Skip to content

Commit 2f8630e

Browse files
committed
refactor: move relay logic to bitcoin crate so it can be shared with
parachain
1 parent 79e1235 commit 2f8630e

15 files changed

Lines changed: 325 additions & 286 deletions

File tree

bitcoin/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ pub enum Error {
7979
AddressError(#[from] AddressError),
8080
#[error("Failed to fetch coinbase tx")]
8181
CoinbaseFetchingFailure,
82+
#[error("Expected a value in a rpc result that is missing")]
83+
MissingValue,
8284
}
8385

8486
impl Error {

bitcoin/src/iter.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
use crate::{BitcoinCoreApi, BitcoinRpcError, Error};
1+
use crate::{BitcoinRpcError, DynBitcoinCoreApi, Error};
22
use bitcoincore_rpc::{
33
bitcoin::{Block, BlockHash, Transaction},
44
jsonrpc::Error as JsonRpcError,
55
Error as BitcoinError,
66
};
77
use futures::{prelude::*, stream::StreamExt};
88
use log::trace;
9-
use std::{iter, sync::Arc};
10-
11-
type DynBitcoinCoreApi = Arc<dyn BitcoinCoreApi + Send + Sync>;
9+
use std::iter;
1210

1311
/// Stream over transactions, starting with this in the mempool and continuing with
1412
/// transactions from previous in-chain block. The stream ends after the block at

bitcoin/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod addr;
1010
mod electrs;
1111
mod error;
1212
mod iter;
13+
pub mod relay;
1314

1415
use async_trait::async_trait;
1516
use backoff::{backoff::Backoff, future::retry, ExponentialBackoff};
@@ -48,6 +49,7 @@ pub use electrs::{ElectrsClient, Error as ElectrsError};
4849
pub use error::{BitcoinRpcError, ConversionError, Error};
4950
pub use iter::{reverse_stream_transactions, stream_blocks, stream_in_chain_transactions};
5051
use log::{info, trace, warn};
52+
pub use relay::*;
5153
use serde_json::error::Category as SerdeJsonCategory;
5254
pub use sp_core::H256;
5355
use std::{
@@ -101,6 +103,8 @@ const RANDOMIZATION_FACTOR: f64 = 0.25;
101103
const DERIVATION_KEY_LABEL: &str = "derivation-key";
102104
const DEPOSIT_LABEL: &str = "deposit";
103105

106+
pub type DynBitcoinCoreApi = Arc<dyn BitcoinCoreApi + Send + Sync>;
107+
104108
fn get_exponential_backoff() -> ExponentialBackoff {
105109
ExponentialBackoff {
106110
current_interval: INITIAL_INTERVAL,
Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,46 @@
1-
use super::Error;
2-
use crate::service::DynBitcoinCoreApi;
1+
use crate::{serialize, BitcoinCoreApi, DynBitcoinCoreApi, Error as BitcoinError};
32
use async_trait::async_trait;
4-
use bitcoin::{serialize, BitcoinCoreApi, Error as BitcoinError};
53

64
#[async_trait]
75
pub trait Backing {
86
/// Returns the height of the longest chain
9-
async fn get_block_count(&self) -> Result<u32, Error>;
7+
async fn get_block_count(&self) -> Result<u32, BitcoinError>;
108

119
/// Returns the raw header of a block in storage
1210
///
1311
/// # Arguments
1412
///
1513
/// * `height` - The height of the block to fetch
16-
async fn get_block_header(&self, height: u32) -> Result<Option<Vec<u8>>, Error>;
14+
async fn get_block_header(&self, height: u32) -> Result<Option<Vec<u8>>, BitcoinError>;
1715

1816
/// Returns the (little endian) hash of a block
1917
///
2018
/// # Arguments
2119
///
2220
/// * `height` - The height of the block to fetch
23-
async fn get_block_hash(&self, height: u32) -> Result<Vec<u8>, Error>;
21+
async fn get_block_hash(&self, height: u32) -> Result<Vec<u8>, BitcoinError>;
2422
}
2523

2624
#[async_trait]
2725
impl Backing for DynBitcoinCoreApi {
28-
async fn get_block_count(&self) -> Result<u32, Error> {
26+
async fn get_block_count(&self) -> Result<u32, BitcoinError> {
2927
let count = BitcoinCoreApi::get_block_count(&**self).await?;
3028
return Ok(count as u32);
3129
}
3230

33-
async fn get_block_header(&self, height: u32) -> Result<Option<Vec<u8>>, Error> {
31+
async fn get_block_header(&self, height: u32) -> Result<Option<Vec<u8>>, BitcoinError> {
3432
let block_hash = match BitcoinCoreApi::get_block_hash(&**self, height).await {
3533
Ok(h) => h,
3634
Err(BitcoinError::InvalidBitcoinHeight) => {
3735
return Ok(None);
3836
}
39-
Err(err) => return Err(err.into()),
37+
Err(err) => return Err(err),
4038
};
4139
let block_header = BitcoinCoreApi::get_block_header(&**self, &block_hash).await?;
4240
Ok(Some(serialize(&block_header)))
4341
}
4442

45-
async fn get_block_hash(&self, height: u32) -> Result<Vec<u8>, Error> {
43+
async fn get_block_hash(&self, height: u32) -> Result<Vec<u8>, BitcoinError> {
4644
let block_hash = BitcoinCoreApi::get_block_hash(&**self, height)
4745
.await
4846
.map(|hash| serialize(&hash))?;
Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
#![allow(clippy::enum_variant_names)]
22

3-
use bitcoin::Error as BitcoinError;
4-
use runtime::Error as RuntimeError;
3+
use crate::Error as BitcoinError;
54
use thiserror::Error;
65

76
#[cfg(test)]
87
use std::mem::discriminant;
98

109
#[derive(Error, Debug)]
11-
pub enum Error {
10+
pub enum Error<RuntimeError> {
1211
#[error("Client already initialized")]
1312
AlreadyInitialized,
1413
#[error("Client has not been initialized")]
@@ -28,13 +27,7 @@ pub enum Error {
2827

2928
#[error("BitcoinError: {0}")]
3029
BitcoinError(#[from] BitcoinError),
30+
// note: we can't have two #[from]s when one is generic. We'll use map_err for the runtime error
3131
#[error("RuntimeError: {0}")]
32-
RuntimeError(#[from] RuntimeError),
33-
}
34-
35-
#[cfg(test)]
36-
impl PartialEq for Error {
37-
fn eq(&self, other: &Self) -> bool {
38-
discriminant(self) == discriminant(other)
39-
}
32+
RuntimeError(RuntimeError),
4033
}

bitcoin/src/relay/issuing.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use async_trait::async_trait;
2+
use std::{fmt, sync::Arc};
3+
4+
#[async_trait]
5+
pub trait RandomDelay: fmt::Debug {
6+
type Error;
7+
async fn delay(&self, seed_data: &[u8; 32]) -> Result<(), Self::Error>;
8+
}
9+
10+
#[async_trait]
11+
pub trait Issuing {
12+
type Error;
13+
14+
/// Returns true if the light client is initialized
15+
async fn is_initialized(&self) -> Result<bool, Self::Error>;
16+
17+
/// Initialize the light client
18+
///
19+
/// # Arguments
20+
///
21+
/// * `header` - Raw block header
22+
/// * `height` - Starting height
23+
async fn initialize(&self, header: Vec<u8>, height: u32) -> Result<(), Self::Error>;
24+
25+
/// Submit a block header and wait for inclusion
26+
///
27+
/// # Arguments
28+
///
29+
/// * `header` - Raw block header
30+
async fn submit_block_header(
31+
&self,
32+
header: Vec<u8>,
33+
random_delay: Arc<Box<dyn RandomDelay<Error = Self::Error> + Send + Sync>>,
34+
) -> Result<(), Self::Error>;
35+
36+
/// Submit a batch of block headers and wait for inclusion
37+
///
38+
/// # Arguments
39+
///
40+
/// * `headers` - Raw block headers (multiple of 80 bytes)
41+
async fn submit_block_header_batch(&self, headers: Vec<Vec<u8>>) -> Result<(), Self::Error>;
42+
43+
/// Returns the light client's chain tip
44+
async fn get_best_height(&self) -> Result<u32, Self::Error>;
45+
46+
/// Returns the block hash stored at a given height,
47+
/// this is assumed to be in little-endian format
48+
///
49+
/// # Arguments
50+
///
51+
/// * `height` - Height of the block to fetch
52+
async fn get_block_hash(&self, height: u32) -> Result<Vec<u8>, Self::Error>;
53+
54+
/// Returns true if the block described by the hash
55+
/// has been stored in the light client
56+
///
57+
/// # Arguments
58+
///
59+
/// * `hash_le` - Hash (little-endian) of the block
60+
async fn is_block_stored(&self, hash_le: Vec<u8>) -> Result<bool, Self::Error>;
61+
}

0 commit comments

Comments
 (0)