diff --git a/rust/basic_bitcoin/README.md b/rust/basic_bitcoin/README.md index b296d51a3..437a42715 100644 --- a/rust/basic_bitcoin/README.md +++ b/rust/basic_bitcoin/README.md @@ -42,7 +42,7 @@ To clone and build the smart contract in **Rust**: ```bash git clone https://github.com/dfinity/examples cd examples/rust/basic_bitcoin -cargo build --release --target wasm32-unknown unknown +cargo build --release --target wasm32-unknown-unknown ``` ### Acquire cycles to deploy @@ -214,6 +214,21 @@ it sent to the network. You can track the status of this transaction using a transaction has at least one confirmation, you should be able to see it reflected in your current balance. +## Step 6: Retrieving block headers + +You can also get a range of Bitcoin block headers by using the `get_block_headers` +endpoint on your canister. + +Make the call using the command line. Be sure to replace `10` with your desired start height: + +```bash +dfx canister --network=ic call basic_bitcoin get_block_headers "(10: nat32)" +``` +or replace `0` and `11` with your desired start and end height respectively: +```bash +dfx canister --network=ic call basic_bitcoin get_block_headers "(0: nat32, 11: nat32)" +``` + ## Conclusion In this tutorial, you were able to: diff --git a/rust/basic_bitcoin/src/basic_bitcoin/basic_bitcoin.did b/rust/basic_bitcoin/src/basic_bitcoin/basic_bitcoin.did index 097a28e64..3a2871f4a 100644 --- a/rust/basic_bitcoin/src/basic_bitcoin/basic_bitcoin.did +++ b/rust/basic_bitcoin/src/basic_bitcoin/basic_bitcoin.did @@ -32,6 +32,14 @@ type get_utxos_response = record { next_page : opt blob; }; +type block_header = blob; +type block_height = nat32; + +type get_block_headers_response = record { + tip_height : block_height; + block_headers : vec block_header; +}; + service : (network) -> { "get_p2pkh_address" : () -> (bitcoin_address); @@ -43,6 +51,8 @@ service : (network) -> { "get_utxos" : (bitcoin_address) -> (get_utxos_response); + "get_block_headers" : (start_height : block_height, end_height : opt block_height) -> (get_block_headers_response); + "get_current_fee_percentiles" : () -> (vec millisatoshi_per_vbyte); "send_from_p2pkh" : ( diff --git a/rust/basic_bitcoin/src/basic_bitcoin/src/bitcoin_api.rs b/rust/basic_bitcoin/src/basic_bitcoin/src/bitcoin_api.rs index c69c66d20..18ca66ba8 100644 --- a/rust/basic_bitcoin/src/basic_bitcoin/src/bitcoin_api.rs +++ b/rust/basic_bitcoin/src/basic_bitcoin/src/bitcoin_api.rs @@ -1,8 +1,10 @@ +use candid::Principal; use ic_cdk::api::management_canister::bitcoin::{ bitcoin_get_balance, bitcoin_get_current_fee_percentiles, bitcoin_get_utxos, bitcoin_send_transaction, BitcoinNetwork, GetBalanceRequest, GetCurrentFeePercentilesRequest, GetUtxosRequest, GetUtxosResponse, MillisatoshiPerByte, SendTransactionRequest, }; +use crate::{GetBlockHeadersRequest, GetBlockHeadersResponse}; /// Returns the balance of the given bitcoin address. /// @@ -36,6 +38,31 @@ pub async fn get_utxos(network: BitcoinNetwork, address: String) -> GetUtxosResp utxos_res.unwrap().0 } +/// Returns the block headers in the given height range. +pub(crate) async fn get_block_headers(network: BitcoinNetwork, start_height: u32, end_height: Option) -> GetBlockHeadersResponse{ + let cycles = match network { + BitcoinNetwork::Mainnet => 10_000_000_000, + BitcoinNetwork::Testnet => 10_000_000_000, + BitcoinNetwork::Regtest => 0, + }; + + let request = GetBlockHeadersRequest{ + start_height, + end_height, + network + }; + + let res = ic_cdk::api::call::call_with_payment128::<(GetBlockHeadersRequest,), (GetBlockHeadersResponse,)>( + Principal::management_canister(), + "bitcoin_get_block_headers", + (request,), + cycles, + ) + .await; + + res.unwrap().0 +} + /// Returns the 100 fee percentiles measured in millisatoshi/byte. /// Percentiles are computed from the last 10,000 transactions (if available). /// @@ -61,3 +88,4 @@ pub async fn send_transaction(network: BitcoinNetwork, transaction: Vec) { res.unwrap(); } + diff --git a/rust/basic_bitcoin/src/basic_bitcoin/src/lib.rs b/rust/basic_bitcoin/src/basic_bitcoin/src/lib.rs index ec417f99e..004f060b5 100644 --- a/rust/basic_bitcoin/src/basic_bitcoin/src/lib.rs +++ b/rust/basic_bitcoin/src/basic_bitcoin/src/lib.rs @@ -3,6 +3,7 @@ mod bitcoin_wallet; mod ecdsa_api; mod schnorr_api; +use candid::{CandidType, Deserialize}; use ic_cdk::api::management_canister::bitcoin::{ BitcoinNetwork, GetUtxosResponse, MillisatoshiPerByte, }; @@ -52,6 +53,31 @@ pub async fn get_utxos(address: String) -> GetUtxosResponse { bitcoin_api::get_utxos(network, address).await } +pub type Height = u32; +pub type BlockHeader = Vec; + +/// A request for getting the block headers for a given height range. +#[derive(CandidType, Debug, Deserialize, PartialEq, Eq)] +pub struct GetBlockHeadersRequest { + pub start_height: Height, + pub end_height: Option, + pub network: BitcoinNetwork, +} + +/// The response returned for a request for getting the block headers from a given height. +#[derive(CandidType, Debug, Deserialize, PartialEq, Eq, Clone)] +pub struct GetBlockHeadersResponse { + pub tip_height: Height, + pub block_headers: Vec, +} + +/// Returns the block headers in the given height range. +#[update] +pub async fn get_block_headers(start_height: u32, end_height: Option) -> GetBlockHeadersResponse{ + let network = NETWORK.with(|n| n.get()); + bitcoin_api::get_block_headers(network, start_height, end_height).await +} + /// Returns the 100 fee percentiles measured in millisatoshi/byte. /// Percentiles are computed from the last 10,000 transactions (if available). #[update]