Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use the burn cycles API in the Bitcoin canister #268

Merged
Merged
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
16 changes: 15 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,10 @@ 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...");

let cycles_burnt = cycles_burn();
dragoljub-duric marked this conversation as resolved.
Show resolved Hide resolved
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 +232,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 test_cycles_burnt() {
ielashi marked this conversation as resolved.
Show resolved Hide resolved
dragoljub-duric marked this conversation as resolved.
Show resolved Hide resolved
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
Loading