mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 18:41:03 +00:00
Merge commit 'e5bed7ac380b6adb54b60a2a72a2a8f07f50d6c1' as 'bridges'
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::rpc::Ethereum;
|
||||
use crate::types::{
|
||||
Address, Bytes, CallRequest, Header, HeaderWithTransactions, Receipt, SignedRawTx, SyncState, Transaction,
|
||||
TransactionHash, H256, U256,
|
||||
};
|
||||
use crate::{ConnectionParams, Error, Result};
|
||||
|
||||
use jsonrpsee_ws_client::{WsClient as RpcClient, WsClientBuilder as RpcClientBuilder};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Number of headers missing from the Ethereum node for us to consider node not synced.
|
||||
const MAJOR_SYNC_BLOCKS: u64 = 5;
|
||||
|
||||
/// The client used to interact with an Ethereum node through RPC.
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
params: ConnectionParams,
|
||||
client: Arc<RpcClient>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Create a new Ethereum RPC Client.
|
||||
pub async fn new(params: ConnectionParams) -> Result<Self> {
|
||||
Ok(Self {
|
||||
client: Self::build_client(¶ms).await?,
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
/// Build client to use in connection.
|
||||
async fn build_client(params: &ConnectionParams) -> Result<Arc<RpcClient>> {
|
||||
let uri = format!("ws://{}:{}", params.host, params.port);
|
||||
let client = RpcClientBuilder::default().build(&uri).await?;
|
||||
Ok(Arc::new(client))
|
||||
}
|
||||
|
||||
/// Reopen client connection.
|
||||
pub async fn reconnect(&mut self) -> Result<()> {
|
||||
self.client = Self::build_client(&self.params).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Returns true if client is connected to at least one peer and is in synced state.
|
||||
pub async fn ensure_synced(&self) -> Result<()> {
|
||||
match Ethereum::syncing(&*self.client).await? {
|
||||
SyncState::NotSyncing => Ok(()),
|
||||
SyncState::Syncing(syncing) => {
|
||||
let missing_headers = syncing.highest_block.saturating_sub(syncing.current_block);
|
||||
if missing_headers > MAJOR_SYNC_BLOCKS.into() {
|
||||
return Err(Error::ClientNotSynced(missing_headers));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Estimate gas usage for the given call.
|
||||
pub async fn estimate_gas(&self, call_request: CallRequest) -> Result<U256> {
|
||||
Ok(Ethereum::estimate_gas(&*self.client, call_request).await?)
|
||||
}
|
||||
|
||||
/// Retrieve number of the best known block from the Ethereum node.
|
||||
pub async fn best_block_number(&self) -> Result<u64> {
|
||||
Ok(Ethereum::block_number(&*self.client).await?.as_u64())
|
||||
}
|
||||
|
||||
/// Retrieve number of the best known block from the Ethereum node.
|
||||
pub async fn header_by_number(&self, block_number: u64) -> Result<Header> {
|
||||
let get_full_tx_objects = false;
|
||||
let header = Ethereum::get_block_by_number(&*self.client, block_number, get_full_tx_objects).await?;
|
||||
match header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some() {
|
||||
true => Ok(header),
|
||||
false => Err(Error::IncompleteHeader),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve block header by its hash from Ethereum node.
|
||||
pub async fn header_by_hash(&self, hash: H256) -> Result<Header> {
|
||||
let get_full_tx_objects = false;
|
||||
let header = Ethereum::get_block_by_hash(&*self.client, hash, get_full_tx_objects).await?;
|
||||
match header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some() {
|
||||
true => Ok(header),
|
||||
false => Err(Error::IncompleteHeader),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve block header and its transactions by its number from Ethereum node.
|
||||
pub async fn header_by_number_with_transactions(&self, number: u64) -> Result<HeaderWithTransactions> {
|
||||
let get_full_tx_objects = true;
|
||||
let header =
|
||||
Ethereum::get_block_by_number_with_transactions(&*self.client, number, get_full_tx_objects).await?;
|
||||
|
||||
let is_complete_header = header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some();
|
||||
if !is_complete_header {
|
||||
return Err(Error::IncompleteHeader);
|
||||
}
|
||||
|
||||
let is_complete_transactions = header.transactions.iter().all(|tx| tx.raw.is_some());
|
||||
if !is_complete_transactions {
|
||||
return Err(Error::IncompleteTransaction);
|
||||
}
|
||||
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
/// Retrieve block header and its transactions by its hash from Ethereum node.
|
||||
pub async fn header_by_hash_with_transactions(&self, hash: H256) -> Result<HeaderWithTransactions> {
|
||||
let get_full_tx_objects = true;
|
||||
let header = Ethereum::get_block_by_hash_with_transactions(&*self.client, hash, get_full_tx_objects).await?;
|
||||
|
||||
let is_complete_header = header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some();
|
||||
if !is_complete_header {
|
||||
return Err(Error::IncompleteHeader);
|
||||
}
|
||||
|
||||
let is_complete_transactions = header.transactions.iter().all(|tx| tx.raw.is_some());
|
||||
if !is_complete_transactions {
|
||||
return Err(Error::IncompleteTransaction);
|
||||
}
|
||||
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
/// Retrieve transaction by its hash from Ethereum node.
|
||||
pub async fn transaction_by_hash(&self, hash: H256) -> Result<Option<Transaction>> {
|
||||
Ok(Ethereum::transaction_by_hash(&*self.client, hash).await?)
|
||||
}
|
||||
|
||||
/// Retrieve transaction receipt by transaction hash.
|
||||
pub async fn transaction_receipt(&self, transaction_hash: H256) -> Result<Receipt> {
|
||||
Ok(Ethereum::get_transaction_receipt(&*self.client, transaction_hash).await?)
|
||||
}
|
||||
|
||||
/// Get the nonce of the given account.
|
||||
pub async fn account_nonce(&self, address: Address) -> Result<U256> {
|
||||
Ok(Ethereum::get_transaction_count(&*self.client, address).await?)
|
||||
}
|
||||
|
||||
/// Submit an Ethereum transaction.
|
||||
///
|
||||
/// The transaction must already be signed before sending it through this method.
|
||||
pub async fn submit_transaction(&self, signed_raw_tx: SignedRawTx) -> Result<TransactionHash> {
|
||||
let transaction = Bytes(signed_raw_tx);
|
||||
let tx_hash = Ethereum::submit_transaction(&*self.client, transaction).await?;
|
||||
log::trace!(target: "bridge", "Sent transaction to Ethereum node: {:?}", tx_hash);
|
||||
Ok(tx_hash)
|
||||
}
|
||||
|
||||
/// Call Ethereum smart contract.
|
||||
pub async fn eth_call(&self, call_transaction: CallRequest) -> Result<Bytes> {
|
||||
Ok(Ethereum::call(&*self.client, call_transaction).await?)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Ethereum node RPC errors.
|
||||
|
||||
use crate::types::U256;
|
||||
|
||||
use jsonrpsee_ws_client::Error as RpcError;
|
||||
use relay_utils::MaybeConnectionError;
|
||||
|
||||
/// Result type used by Ethereum client.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// Errors that can occur only when interacting with
|
||||
/// an Ethereum node through RPC.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// An error that can occur when making an HTTP request to
|
||||
/// an JSON-RPC client.
|
||||
RpcError(RpcError),
|
||||
/// Failed to parse response.
|
||||
ResponseParseFailed(String),
|
||||
/// We have received a header with missing fields.
|
||||
IncompleteHeader,
|
||||
/// We have received a transaction missing a `raw` field.
|
||||
IncompleteTransaction,
|
||||
/// An invalid Substrate block number was received from
|
||||
/// an Ethereum node.
|
||||
InvalidSubstrateBlockNumber,
|
||||
/// An invalid index has been received from an Ethereum node.
|
||||
InvalidIncompleteIndex,
|
||||
/// The client we're connected to is not synced, so we can't rely on its state. Contains
|
||||
/// number of unsynced headers.
|
||||
ClientNotSynced(U256),
|
||||
}
|
||||
|
||||
impl From<RpcError> for Error {
|
||||
fn from(error: RpcError) -> Self {
|
||||
Error::RpcError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl MaybeConnectionError for Error {
|
||||
fn is_connection_error(&self) -> bool {
|
||||
matches!(
|
||||
*self,
|
||||
Error::RpcError(RpcError::TransportError(_))
|
||||
// right now if connection to the ws server is dropped (after it is already established),
|
||||
// we're getting this error
|
||||
| Error::RpcError(RpcError::Internal(_))
|
||||
| Error::ClientNotSynced(_),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Error {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::RpcError(e) => e.to_string(),
|
||||
Self::ResponseParseFailed(e) => e.to_string(),
|
||||
Self::IncompleteHeader => {
|
||||
"Incomplete Ethereum Header Received (missing some of required fields - hash, number, logs_bloom)"
|
||||
.to_string()
|
||||
}
|
||||
Self::IncompleteTransaction => "Incomplete Ethereum Transaction (missing required field - raw)".to_string(),
|
||||
Self::InvalidSubstrateBlockNumber => "Received an invalid Substrate block from Ethereum Node".to_string(),
|
||||
Self::InvalidIncompleteIndex => "Received an invalid incomplete index from Ethereum Node".to_string(),
|
||||
Self::ClientNotSynced(missing_headers) => {
|
||||
format!("Ethereum client is not synced: syncing {} headers", missing_headers)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Tools to interact with (Open) Ethereum node using RPC methods.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
mod client;
|
||||
mod error;
|
||||
mod rpc;
|
||||
mod sign;
|
||||
|
||||
pub use crate::client::Client;
|
||||
pub use crate::error::{Error, Result};
|
||||
pub use crate::sign::{sign_and_submit_transaction, SigningParams};
|
||||
|
||||
pub mod types;
|
||||
|
||||
/// Ethereum-over-websocket connection params.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConnectionParams {
|
||||
/// Websocket server hostname.
|
||||
pub host: String,
|
||||
/// Websocket server TCP port.
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
impl Default for ConnectionParams {
|
||||
fn default() -> Self {
|
||||
ConnectionParams {
|
||||
host: "localhost".into(),
|
||||
port: 8546,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Ethereum node RPC interface.
|
||||
|
||||
use crate::types::{
|
||||
Address, Bytes, CallRequest, Header, HeaderWithTransactions, Receipt, SyncState, Transaction, TransactionHash,
|
||||
H256, U256, U64,
|
||||
};
|
||||
|
||||
jsonrpsee_proc_macros::rpc_client_api! {
|
||||
pub(crate) Ethereum {
|
||||
#[rpc(method = "eth_syncing", positional_params)]
|
||||
fn syncing() -> SyncState;
|
||||
#[rpc(method = "eth_estimateGas", positional_params)]
|
||||
fn estimate_gas(call_request: CallRequest) -> U256;
|
||||
#[rpc(method = "eth_blockNumber", positional_params)]
|
||||
fn block_number() -> U64;
|
||||
#[rpc(method = "eth_getBlockByNumber", positional_params)]
|
||||
fn get_block_by_number(block_number: U64, full_tx_objs: bool) -> Header;
|
||||
#[rpc(method = "eth_getBlockByHash", positional_params)]
|
||||
fn get_block_by_hash(hash: H256, full_tx_objs: bool) -> Header;
|
||||
#[rpc(method = "eth_getBlockByNumber", positional_params)]
|
||||
fn get_block_by_number_with_transactions(number: U64, full_tx_objs: bool) -> HeaderWithTransactions;
|
||||
#[rpc(method = "eth_getBlockByHash", positional_params)]
|
||||
fn get_block_by_hash_with_transactions(hash: H256, full_tx_objs: bool) -> HeaderWithTransactions;
|
||||
#[rpc(method = "eth_getTransactionByHash", positional_params)]
|
||||
fn transaction_by_hash(hash: H256) -> Option<Transaction>;
|
||||
#[rpc(method = "eth_getTransactionReceipt", positional_params)]
|
||||
fn get_transaction_receipt(transaction_hash: H256) -> Receipt;
|
||||
#[rpc(method = "eth_getTransactionCount", positional_params)]
|
||||
fn get_transaction_count(address: Address) -> U256;
|
||||
#[rpc(method = "eth_submitTransaction", positional_params)]
|
||||
fn submit_transaction(transaction: Bytes) -> TransactionHash;
|
||||
#[rpc(method = "eth_call", positional_params)]
|
||||
fn call(transaction_call: CallRequest) -> Bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::types::{Address, CallRequest, U256};
|
||||
use crate::{Client, Result};
|
||||
use bp_eth_poa::signatures::{secret_to_address, SignTransaction};
|
||||
use hex_literal::hex;
|
||||
use secp256k1::SecretKey;
|
||||
|
||||
/// Ethereum signing params.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SigningParams {
|
||||
/// Ethereum chain id.
|
||||
pub chain_id: u64,
|
||||
/// Ethereum transactions signer.
|
||||
pub signer: SecretKey,
|
||||
/// Gas price we agree to pay.
|
||||
pub gas_price: U256,
|
||||
}
|
||||
|
||||
impl Default for SigningParams {
|
||||
fn default() -> Self {
|
||||
SigningParams {
|
||||
chain_id: 0x11, // Parity dev chain
|
||||
// account that has a lot of ether when we run instant seal engine
|
||||
// address: 0x00a329c0648769a73afac7f9381e08fb43dbea72
|
||||
// secret: 0x4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7
|
||||
signer: SecretKey::parse(&hex!(
|
||||
"4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7"
|
||||
))
|
||||
.expect("secret is hardcoded, thus valid; qed"),
|
||||
gas_price: 8_000_000_000u64.into(), // 8 Gwei
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sign and submit tranaction using given Ethereum client.
|
||||
pub async fn sign_and_submit_transaction(
|
||||
client: &Client,
|
||||
params: &SigningParams,
|
||||
contract_address: Option<Address>,
|
||||
nonce: Option<U256>,
|
||||
double_gas: bool,
|
||||
encoded_call: Vec<u8>,
|
||||
) -> Result<()> {
|
||||
let nonce = if let Some(n) = nonce {
|
||||
n
|
||||
} else {
|
||||
let address: Address = secret_to_address(¶ms.signer);
|
||||
client.account_nonce(address).await?
|
||||
};
|
||||
|
||||
let call_request = CallRequest {
|
||||
to: contract_address,
|
||||
data: Some(encoded_call.clone().into()),
|
||||
..Default::default()
|
||||
};
|
||||
let gas = client.estimate_gas(call_request).await?;
|
||||
|
||||
let raw_transaction = bp_eth_poa::UnsignedTransaction {
|
||||
nonce,
|
||||
to: contract_address,
|
||||
value: U256::zero(),
|
||||
gas: if double_gas { gas.saturating_mul(2.into()) } else { gas },
|
||||
gas_price: params.gas_price,
|
||||
payload: encoded_call,
|
||||
}
|
||||
.sign_by(¶ms.signer, Some(params.chain_id));
|
||||
|
||||
let _ = client.submit_transaction(raw_transaction).await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Common types that are used in relay <-> Ethereum node communications.
|
||||
|
||||
use headers_relay::sync_types::SourceHeader;
|
||||
|
||||
pub use web3::types::{Address, Bytes, CallRequest, SyncState, H256, U128, U256, U64};
|
||||
|
||||
/// When header is just received from the Ethereum node, we check that it has
|
||||
/// both number and hash fields filled.
|
||||
pub const HEADER_ID_PROOF: &str = "checked on retrieval; qed";
|
||||
|
||||
/// Ethereum transaction hash type.
|
||||
pub type HeaderHash = H256;
|
||||
|
||||
/// Ethereum transaction hash type.
|
||||
pub type TransactionHash = H256;
|
||||
|
||||
/// Ethereum transaction type.
|
||||
pub type Transaction = web3::types::Transaction;
|
||||
|
||||
/// Ethereum header type.
|
||||
pub type Header = web3::types::Block<H256>;
|
||||
|
||||
/// Ethereum header type used in headers sync.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SyncHeader(Header);
|
||||
|
||||
impl std::ops::Deref for SyncHeader {
|
||||
type Target = Header;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Ethereum header with transactions type.
|
||||
pub type HeaderWithTransactions = web3::types::Block<Transaction>;
|
||||
|
||||
/// Ethereum transaction receipt type.
|
||||
pub type Receipt = web3::types::TransactionReceipt;
|
||||
|
||||
/// Ethereum header ID.
|
||||
pub type HeaderId = relay_utils::HeaderId<H256, u64>;
|
||||
|
||||
/// A raw Ethereum transaction that's been signed.
|
||||
pub type SignedRawTx = Vec<u8>;
|
||||
|
||||
impl From<Header> for SyncHeader {
|
||||
fn from(header: Header) -> Self {
|
||||
Self(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceHeader<H256, u64> for SyncHeader {
|
||||
fn id(&self) -> HeaderId {
|
||||
relay_utils::HeaderId(
|
||||
self.number.expect(HEADER_ID_PROOF).as_u64(),
|
||||
self.hash.expect(HEADER_ID_PROOF),
|
||||
)
|
||||
}
|
||||
|
||||
fn parent_id(&self) -> HeaderId {
|
||||
relay_utils::HeaderId(self.number.expect(HEADER_ID_PROOF).as_u64() - 1, self.parent_hash)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user