Skip to content

Commit

Permalink
feat: Use the burn cycles API in the Bitcoin canister (#268)
Browse files Browse the repository at this point in the history
Co-authored-by: Islam El-Ashi <islam.elashi@dfinity.org>
  • Loading branch information
dragoljub-duric and ielashi authored Nov 22, 2023
1 parent 5696340 commit be7cf3b
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 28 deletions.
35 changes: 34 additions & 1 deletion .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI Checks

env:
RUST_VERSION: 1.68.0
DFX_VERSION: 0.13.1
DFX_VERSION: 0.15.2-beta.0

on:
push:
Expand Down Expand Up @@ -353,6 +353,38 @@ jobs:
run: |
bash e2e-tests/set_config.sh
cycles_burn:
runs-on: ubuntu-20.04
needs: cargo-build

steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-1

- name: Install Rust
run: |
rustup update ${{ matrix.rust }} --no-self-update
rustup default ${{ matrix.rust }}
rustup target add wasm32-unknown-unknown
- name: Install DFX
run: |
wget --output-document install-dfx.sh "https://internetcomputer.org/install.sh"
bash install-dfx.sh < <(yes Y)
rm install-dfx.sh
dfx cache install
echo "$HOME/bin" >> $GITHUB_PATH
- name: Run cycles_burn test
run: |
bash e2e-tests/cycles_burn.sh
benchmark:
runs-on: ubuntu-20.04
needs: cargo-build
Expand Down Expand Up @@ -529,6 +561,7 @@ jobs:
- charge-cycles-on-reject
- upgradability
- set_config
- cycles_burn
- benchmark
- watchdog_health_status
- watchdog_get_config
Expand Down
52 changes: 36 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ ic-btc-interface = { path = "./interface" }
ic-btc-types = { path = "./types" }
ic-btc-test-utils = { path = "./test-utils" }
ic-btc-validation = { path = "./validation" }
ic-cdk = "0.10.0"
ic-cdk = "0.11.2"
ic-cdk-macros = "0.7.0"
ic-http = { path = "./ic-http" }
ic-metrics-encoder = "1.0.0"
Expand All @@ -45,4 +45,4 @@ lazy_static = "1.4.0"
serde = "1.0.171"
serde_bytes = "0.11"
serde_json = "1.0.94"
tokio = { version = "1.29.1", features = [ "full" ] }
tokio = { version = "1.29.1", features = ["full"] }
6 changes: 6 additions & 0 deletions canister/src/api/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ fn encode_metrics(w: &mut MetricsEncoder<Vec<u8>>) -> std::io::Result<()> {
"The total number of (valid) requests to the send_transaction endpoint.",
)?;

w.encode_gauge(
"cycles_burnt",
state.metrics.cycles_burnt.unwrap_or_default() as f64,
"The total number of cycles burnt.",
)?;

w.encode_gauge(
"cycles_balance",
ic_cdk::api::canister_balance() as f64,
Expand Down
17 changes: 16 additions & 1 deletion canister/src/heartbeat.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
runtime::{call_get_successors, print},
runtime::{call_get_successors, cycles_burn, print},
state::{self, ResponseToProcess},
types::{
GetSuccessorsCompleteResponse, GetSuccessorsRequest, GetSuccessorsRequestInitial,
Expand All @@ -17,6 +17,11 @@ use ic_btc_types::{Block, BlockHash};
/// The heartbeat fetches new blocks from the bitcoin network and inserts them into the state.
pub async fn heartbeat() {
print("Starting heartbeat...");

// Burn any cycles in the canister's balance (to count towards the IC's cycles burn rate)
let cycles_burnt = cycles_burn();
add_cycles_burnt_to_metric(cycles_burnt);

if ingest_stable_blocks_into_utxoset() {
// Exit the heartbeat if stable blocks had been ingested.
// This is a precaution to not exceed the instructions limit.
Expand Down Expand Up @@ -228,6 +233,16 @@ fn maybe_get_successors_request() -> Option<GetSuccessorsRequest> {
})
}

fn add_cycles_burnt_to_metric(cycles_burnt: u128) {
with_state_mut(|s| {
if let Some(metric_cycles_burnt) = &mut s.metrics.cycles_burnt {
*metric_cycles_burnt += cycles_burnt;
} else {
s.metrics.cycles_burnt = Some(cycles_burnt);
}
});
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
5 changes: 5 additions & 0 deletions canister/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ pub struct Metrics {

/// Instructions needed to insert a block into the pool of unstable blocks.
pub block_insertion: InstructionHistogram,

/// The total number of cycles burnt.
pub cycles_burnt: Option<u128>,
}

impl Default for Metrics {
Expand Down Expand Up @@ -66,6 +69,8 @@ impl Default for Metrics {
"ins_block_insertion",
"Instructions needed to insert a block into the pool of unstable blocks.",
),

cycles_burnt: Some(0),
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions canister/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,13 @@ pub fn time() -> u64 {
.unwrap()
.as_secs()
}

#[cfg(target_arch = "wasm32")]
pub fn cycles_burn() -> u128 {
ic_cdk::api::cycles_burn(ic_cdk::api::canister_balance128())
}

#[cfg(not(target_arch = "wasm32"))]
pub fn cycles_burn() -> u128 {
1_000_000
}
32 changes: 32 additions & 0 deletions canister/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,3 +716,35 @@ async fn test_syncing_with_next_block_headers() {

assert!(catch_unwind(verify_synced).is_err());
}

#[async_std::test]
async fn cycles_burnt_are_tracked_in_metrics() {
crate::init(crate::Config::default());

let cycles_burnt_0 = crate::with_state(|state| state.metrics.cycles_burnt);

assert_eq!(cycles_burnt_0, Some(0));

let burn_amount = 1_000_000;

// Burn cycles.
heartbeat().await;

let cycles_burnt_1 = crate::with_state(|state| state.metrics.cycles_burnt);

assert_eq!(cycles_burnt_1, Some(burn_amount));

// Burn cycles.
heartbeat().await;

let cycles_burnt_2 = crate::with_state(|state| state.metrics.cycles_burnt);

assert_eq!(cycles_burnt_2, Some(2 * burn_amount));

// Burn cycles.
heartbeat().await;

let cycles_burnt_3 = crate::with_state(|state| state.metrics.cycles_burnt);

assert_eq!(cycles_burnt_3, Some(3 * burn_amount));
}
8 changes: 5 additions & 3 deletions dfx.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dfx": "0.13.1",
"dfx": "0.15.2-beta.0",
"canisters": {
"bitcoin": {
"type": "custom",
Expand Down Expand Up @@ -78,9 +78,11 @@
}
},
"testnet": {
"providers": ["http://[2a00:fb01:400:42:5000:aaff:fea4:ae46]:8080"],
"providers": [
"http://[2a00:fb01:400:42:5000:aaff:fea4:ae46]:8080"
],
"type": "persistent"
}
},
"version": 1
}
}
Loading

0 comments on commit be7cf3b

Please sign in to comment.