mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Correct Serai header on genesis
Includes a couple misc fixes for the RPC as well.
This commit is contained in:
@@ -7,15 +7,26 @@ use crate::{
|
||||
Transaction,
|
||||
};
|
||||
|
||||
/// The tag for a block's header, forming a leaf of the Merkle tree which is `builds_upon`.
|
||||
pub const BLOCK_HEADER_LEAF_TAG: u8 = 0;
|
||||
/// The tag for branch hashes in `builds_upon`.
|
||||
pub const BLOCK_HEADER_BRANCH_TAG: u8 = 1;
|
||||
|
||||
/// The tag for a transaction, forming a leaf of the Merkle tree which is the transactions'
|
||||
/// commitment.
|
||||
pub const TRANSACTION_COMMITMENT_LEAF_TAG: u8 = 2;
|
||||
/// The tag for branch hashes in the transactions' commitment.
|
||||
pub const TRANSACTION_COMMITMENT_BRANCH_TAG: u8 = 3;
|
||||
|
||||
/// The tag for the hash of a transaction's event, forming a leaf of the Merkle tree of its events.
|
||||
pub const TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG: u8 = 0;
|
||||
/// The tag for the branch hashes of transaction events.
|
||||
pub const TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG: u8 = 1;
|
||||
pub const TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG: u8 = 4;
|
||||
/// The tag for the branch hashes of the Merkle tree for a transaction's events.
|
||||
pub const TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG: u8 = 5;
|
||||
/// The tag for the hash of a transaction's hash and its events' Merkle root, forming a leaf of the
|
||||
/// Merkle tree which is the events commitment.
|
||||
pub const EVENTS_COMMITMENT_LEAF_TAG: u8 = 2;
|
||||
/// The tag for for the branch hashes of the Merkle tree which is the events commitments.
|
||||
pub const EVENTS_COMMITMENT_BRANCH_TAG: u8 = 3;
|
||||
/// Merkle tree which is the events' commitment.
|
||||
pub const EVENTS_COMMITMENT_LEAF_TAG: u8 = 6;
|
||||
/// The tag for branch hashes in the events' commitment.
|
||||
pub const EVENTS_COMMITMENT_BRANCH_TAG: u8 = 7;
|
||||
|
||||
/// A V1 header for a block.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
@@ -38,7 +49,8 @@ pub struct HeaderV1 {
|
||||
pub builds_upon: UnbalancedMerkleTree,
|
||||
/// The UNIX time in milliseconds this block was created at.
|
||||
pub unix_time_in_millis: u64,
|
||||
/// The commitment to the transactions within this block.
|
||||
/// The commitment to the transactions within this block, including the inherent start/end of
|
||||
/// block transactions.
|
||||
pub transactions_commitment: UnbalancedMerkleTree,
|
||||
/// The commitment to the events within this block.
|
||||
///
|
||||
|
||||
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/substrate/client/s
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["serai"]
|
||||
edition = "2021"
|
||||
rust-version = "1.85"
|
||||
rust-version = "1.89"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -153,8 +153,7 @@ impl Serai {
|
||||
|
||||
/// Fetch a block from the Serai blockchain by its number.
|
||||
pub async fn block_by_number(&self, block: u64) -> Result<Block, RpcError> {
|
||||
Self::block_internal(self.call("blockchain/block", &format!(r#"{{ "block": "{block}" }}"#)))
|
||||
.await
|
||||
Self::block_internal(self.call("blockchain/block", &format!(r#"{{ "block": {block} }}"#))).await
|
||||
}
|
||||
|
||||
/// Scope this RPC client to the state as of a specific block.
|
||||
|
||||
@@ -100,7 +100,7 @@ impl<'a> ValidatorSets<'a> {
|
||||
.0
|
||||
.call::<Option<_>>(
|
||||
"validator-sets/session",
|
||||
&format!(r#" "network": {} "#, rpc_network(network)?),
|
||||
&format!(r#", "network": {} "#, rpc_network(network)?),
|
||||
)
|
||||
.await?
|
||||
.map(Session),
|
||||
@@ -114,7 +114,7 @@ impl<'a> ValidatorSets<'a> {
|
||||
.0
|
||||
.call::<Option<_>>(
|
||||
"validator-sets/current_stake",
|
||||
&format!(r#" "network": {} "#, rpc_network(network)?),
|
||||
&format!(r#", "network": {} "#, rpc_network(network)?),
|
||||
)
|
||||
.await?
|
||||
.map(Amount),
|
||||
@@ -128,7 +128,7 @@ impl<'a> ValidatorSets<'a> {
|
||||
.call::<Option<String>>(
|
||||
"validator-sets/keys",
|
||||
&format!(
|
||||
r#" "set": {{ "network": {}, "session": {} }} "#,
|
||||
r#", "set": {{ "network": {}, "session": {} }} "#,
|
||||
rpc_network(set.network)?,
|
||||
set.session.0
|
||||
),
|
||||
|
||||
@@ -8,8 +8,8 @@ use serai_abi::primitives::merkle::{UnbalancedMerkleTree, IncrementalUnbalancedM
|
||||
/// `IncrementalUnbalancedMerkleTree`.
|
||||
pub struct IncrementalUnbalancedMerkleTree<
|
||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||
const BRANCH_TAG: u8 = 1,
|
||||
const LEAF_TAG: u8 = 0,
|
||||
const BRANCH_TAG: u8,
|
||||
const LEAF_TAG: u8,
|
||||
>(PhantomData<T>);
|
||||
impl<
|
||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use frame_support::traits::{PreInherents, PostTransactions};
|
||||
|
||||
mod iumt;
|
||||
pub use iumt::*;
|
||||
|
||||
@@ -15,7 +16,10 @@ pub use iumt::*;
|
||||
pub mod pallet {
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_support::{
|
||||
sp_runtime::traits::{Header, Block},
|
||||
pallet_prelude::*,
|
||||
};
|
||||
|
||||
use serai_abi::primitives::{prelude::*, merkle::IncrementalUnbalancedMerkleTree as Iumt};
|
||||
|
||||
@@ -28,14 +32,21 @@ pub mod pallet {
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlocksCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlocksCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<BlocksCommitment<T>>;
|
||||
pub(super) type BlocksCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||
BlocksCommitment<T>,
|
||||
{ serai_abi::BLOCK_HEADER_BRANCH_TAG },
|
||||
{ serai_abi::BLOCK_HEADER_LEAF_TAG },
|
||||
>;
|
||||
|
||||
/// The Merkle tree of all transactions within the current block.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlockTransactionsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlockTransactionsCommitmentMerkle<T> =
|
||||
IncrementalUnbalancedMerkleTree<BlockTransactionsCommitment<T>>;
|
||||
pub(super) type BlockTransactionsCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||
BlockTransactionsCommitment<T>,
|
||||
{ serai_abi::TRANSACTION_COMMITMENT_BRANCH_TAG },
|
||||
{ serai_abi::TRANSACTION_COMMITMENT_LEAF_TAG },
|
||||
>;
|
||||
|
||||
/// The hashes of events caused by the current transaction.
|
||||
#[pallet::storage]
|
||||
@@ -99,10 +110,16 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
/// The code to run on genesis.
|
||||
pub fn genesis() {
|
||||
pub fn genesis(config: &impl frame_support::traits::BuildGenesisConfig) {
|
||||
BlocksCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
||||
|
||||
Self::start_transaction();
|
||||
<_>::build(config);
|
||||
Self::end_transaction([0; 32]);
|
||||
|
||||
EndOfBlock::<T>::post_transactions();
|
||||
}
|
||||
|
||||
/// The code to run when beginning execution of a transaction.
|
||||
@@ -150,7 +167,7 @@ pub use pallet::*;
|
||||
|
||||
/// The code to run at the start of a block for this pallet.
|
||||
pub struct StartOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
|
||||
impl<T: Config> PreInherents for StartOfBlock<T> {
|
||||
fn pre_inherents() {
|
||||
use frame_support::pallet_prelude::Zero;
|
||||
// `Pallet::genesis` is expected to be used for the genesis block
|
||||
@@ -163,13 +180,30 @@ impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
|
||||
|
||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
||||
|
||||
Pallet::<T>::start_transaction();
|
||||
|
||||
// Other modules' `PreInherents`
|
||||
|
||||
let block_number: sp_core::U256 = frame_system::Pallet::<T>::block_number().into();
|
||||
let start_of_block_transaction_hash = block_number.to_big_endian();
|
||||
Pallet::<T>::end_transaction(start_of_block_transaction_hash);
|
||||
}
|
||||
}
|
||||
|
||||
/// The code to run at the end of a block for this pallet.
|
||||
pub struct EndOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> frame_support::traits::PostTransactions for EndOfBlock<T> {
|
||||
impl<T: Config> PostTransactions for EndOfBlock<T> {
|
||||
fn post_transactions() {
|
||||
Pallet::<T>::start_transaction();
|
||||
|
||||
// Other modules' `PostInherents`
|
||||
|
||||
let block_number: sp_core::U256 = frame_system::Pallet::<T>::block_number().into();
|
||||
let mut end_of_block_transaction_hash = block_number.to_big_endian();
|
||||
end_of_block_transaction_hash[.. 16].copy_from_slice(&[0xff; 16]);
|
||||
Pallet::<T>::end_transaction(end_of_block_transaction_hash);
|
||||
|
||||
use serai_abi::SeraiExecutionDigest;
|
||||
frame_system::Pallet::<T>::deposit_log(
|
||||
frame_support::sp_runtime::generic::DigestItem::Consensus(
|
||||
|
||||
@@ -62,6 +62,7 @@ jsonrpsee = { version = "0.24", features = ["server"] }
|
||||
sc-transaction-pool = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-transaction-pool-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-basic-authorship = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-client-db = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-executor = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-service = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-client-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
use core::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use sp_core::Pair as PairTrait;
|
||||
|
||||
use sp_core::{Decode, storage::Storage, Pair as PairTrait};
|
||||
use sp_runtime::{
|
||||
traits::{Block as _, Header as _},
|
||||
BuildStorage,
|
||||
};
|
||||
use sc_client_db::Backend;
|
||||
use sc_executor::RuntimeVersionOf;
|
||||
use sc_chain_spec::{BuildGenesisBlock, GenesisBlockBuilder, ChainSpec as ChainSpecTrait};
|
||||
use sc_client_api::BlockImportOperation;
|
||||
use sc_service::ChainType;
|
||||
|
||||
use rand_core::OsRng;
|
||||
@@ -201,3 +209,45 @@ pub fn bootnode_multiaddrs(id: &str) -> Vec<libp2p::Multiaddr> {
|
||||
_ => panic!("unrecognized network ID"),
|
||||
}
|
||||
}
|
||||
|
||||
struct GenesisBlock<Executor>(
|
||||
GenesisBlockBuilder<Block, Backend<Block>, Executor>,
|
||||
sp_runtime::Digest,
|
||||
);
|
||||
impl<Executor: RuntimeVersionOf> BuildGenesisBlock<Block> for GenesisBlock<Executor> {
|
||||
type BlockImportOperation = sc_client_db::BlockImportOperation<Block>;
|
||||
|
||||
fn build_genesis_block(self) -> sp_blockchain::Result<(Block, Self::BlockImportOperation)> {
|
||||
let (genesis_block, op) = self.0.build_genesis_block()?;
|
||||
|
||||
let mut header = genesis_block.header().clone();
|
||||
*header.digest_mut() = self.1;
|
||||
let genesis_block = Block::new(header, genesis_block.extrinsics().to_vec());
|
||||
|
||||
Ok((genesis_block, op))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn genesis_block(
|
||||
chain_spec: &dyn ChainSpecTrait,
|
||||
backend: Arc<Backend<Block>>,
|
||||
executor: impl RuntimeVersionOf,
|
||||
) -> Result<
|
||||
impl BuildGenesisBlock<Block, BlockImportOperation = sc_client_db::BlockImportOperation<Block>>,
|
||||
sc_service::error::Error,
|
||||
> {
|
||||
let storage = chain_spec.as_storage_builder().build_storage()?;
|
||||
let digest = {
|
||||
let digest_key = [sp_core::twox_128(b"System"), sp_core::twox_128(b"Digest")].concat();
|
||||
sp_runtime::Digest::decode(
|
||||
&mut storage.top.get(&digest_key).expect("System Digest not set").as_slice(),
|
||||
)
|
||||
.expect("failed to decode System Digest")
|
||||
};
|
||||
|
||||
let commit_genesis_state = true;
|
||||
Ok(GenesisBlock(
|
||||
GenesisBlockBuilder::new_with_storage(storage, commit_genesis_state, backend, executor)?,
|
||||
digest,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{sync::Arc, ops::Deref, collections::HashSet};
|
||||
use std::{sync::Arc, ops::Deref, convert::AsRef, collections::HashSet};
|
||||
|
||||
use rand_core::{RngCore, OsRng};
|
||||
|
||||
@@ -17,6 +17,16 @@ use jsonrpsee::RpcModule;
|
||||
|
||||
use super::utils::{Error, block_hash};
|
||||
|
||||
fn network_from_str(network: impl AsRef<str>) -> Result<NetworkId, Error> {
|
||||
Ok(match network.as_ref().to_lowercase().as_str() {
|
||||
"serai" => NetworkId::Serai,
|
||||
"bitcoin" => NetworkId::External(ExternalNetworkId::Bitcoin),
|
||||
"ethereum" => NetworkId::External(ExternalNetworkId::Ethereum),
|
||||
"monero" => NetworkId::External(ExternalNetworkId::Monero),
|
||||
_ => Err(Error::InvalidRequest("unrecognized network requested"))?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn network(params: &jsonrpsee::types::params::Params) -> Result<NetworkId, Error> {
|
||||
#[derive(sp_core::serde::Deserialize)]
|
||||
#[serde(crate = "sp_core::serde")]
|
||||
@@ -28,13 +38,7 @@ pub(super) fn network(params: &jsonrpsee::types::params::Params) -> Result<Netwo
|
||||
Err(Error::InvalidRequest(r#"missing `string` "network" field"#))?
|
||||
};
|
||||
|
||||
Ok(match network.network.to_lowercase().as_str() {
|
||||
"serai" => NetworkId::Serai,
|
||||
"bitcoin" => NetworkId::External(ExternalNetworkId::Bitcoin),
|
||||
"ethereum" => NetworkId::External(ExternalNetworkId::Ethereum),
|
||||
"monero" => NetworkId::External(ExternalNetworkId::Monero),
|
||||
_ => Err(Error::InvalidRequest("unrecognized network requested"))?,
|
||||
})
|
||||
network_from_str(network.network)
|
||||
}
|
||||
|
||||
pub(super) fn set(params: &jsonrpsee::types::params::Params) -> Result<ValidatorSet, Error> {
|
||||
@@ -49,15 +53,7 @@ pub(super) fn set(params: &jsonrpsee::types::params::Params) -> Result<Validator
|
||||
Err(Error::InvalidRequest(r#"missing `object` "set" field"#))?
|
||||
};
|
||||
|
||||
let network = match set.network.to_lowercase().as_str() {
|
||||
"serai" => NetworkId::Serai,
|
||||
"bitcoin" => NetworkId::External(ExternalNetworkId::Bitcoin),
|
||||
"ethereum" => NetworkId::External(ExternalNetworkId::Ethereum),
|
||||
"monero" => NetworkId::External(ExternalNetworkId::Monero),
|
||||
_ => Err(Error::InvalidRequest("unrecognized network requested"))?,
|
||||
};
|
||||
|
||||
Ok(ValidatorSet { network, session: Session(set.session) })
|
||||
Ok(ValidatorSet { network: network_from_str(set.network)?, session: Session(set.session) })
|
||||
}
|
||||
|
||||
pub(crate) fn module<
|
||||
|
||||
@@ -95,12 +95,19 @@ pub fn new_partial(
|
||||
config.executor.runtime_cache_size,
|
||||
);
|
||||
|
||||
let (client, backend, keystore_container, task_manager) =
|
||||
sc_service::new_full_parts::<Block, RuntimeApi, _>(
|
||||
let (client, backend, keystore_container, task_manager) = {
|
||||
let telemetry = telemetry.as_ref().map(|(_, telemetry)| telemetry.handle());
|
||||
let backend = sc_service::new_db_backend(config.db_config())?;
|
||||
|
||||
sc_service::new_full_parts_with_genesis_builder::<Block, RuntimeApi, _, _>(
|
||||
config,
|
||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||
executor,
|
||||
)?;
|
||||
telemetry,
|
||||
executor.clone(),
|
||||
backend.clone(),
|
||||
super::chain_spec::genesis_block(&*config.chain_spec, backend, executor)?,
|
||||
false,
|
||||
)?
|
||||
};
|
||||
let client = Arc::new(client);
|
||||
|
||||
let keystore: Arc<dyn sp_keystore::Keystore> =
|
||||
|
||||
@@ -356,14 +356,7 @@ sp_api::impl_runtime_apis! {
|
||||
grandpa: GrandpaConfig { authorities: vec![], _config: PhantomData },
|
||||
};
|
||||
|
||||
Core::genesis();
|
||||
Core::start_transaction();
|
||||
<RuntimeGenesisConfig as frame_support::traits::BuildGenesisConfig>::build(&config);
|
||||
Core::end_transaction([0; 32]);
|
||||
|
||||
<
|
||||
serai_core_pallet::EndOfBlock<Runtime> as frame_support::traits::PostTransactions
|
||||
>::post_transactions();
|
||||
Core::genesis(&config);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user