mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Compare commits
7 Commits
a793aa18ef
...
46b1f1b7ec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46b1f1b7ec | ||
|
|
09113201e7 | ||
|
|
556d294157 | ||
|
|
82ca889ed3 | ||
|
|
cde0f753c2 | ||
|
|
6ff0ef7aa6 | ||
|
|
f9e3d1b142 |
@@ -6,7 +6,7 @@ license = "MIT"
|
|||||||
repository = "https://github.com/serai-dex/serai/tree/develop/networks/bitcoin"
|
repository = "https://github.com/serai-dex/serai/tree/develop/networks/bitcoin"
|
||||||
authors = ["Luke Parker <lukeparker5132@gmail.com>", "Vrx <vrx00@proton.me>"]
|
authors = ["Luke Parker <lukeparker5132@gmail.com>", "Vrx <vrx00@proton.me>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.85"
|
rust-version = "1.89"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ impl Rpc {
|
|||||||
Err(RpcError::RequestError(Error { code, message }))
|
Err(RpcError::RequestError(Error { code, message }))
|
||||||
}
|
}
|
||||||
// `invalidateblock` yields this edge case
|
// `invalidateblock` yields this edge case
|
||||||
|
// TODO: https://github.com/core-json/core-json/issues/18
|
||||||
RpcResponse { result: None, error: None } => {
|
RpcResponse { result: None, error: None } => {
|
||||||
if core::any::TypeId::of::<Response>() == core::any::TypeId::of::<()>() {
|
if core::any::TypeId::of::<Response>() == core::any::TypeId::of::<()>() {
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ workspace = true
|
|||||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
||||||
|
|
||||||
bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
serde = { version = "1", default-features = false, features = ["derive"], optional = true }
|
serde = { version = "1", default-features = false, features = ["derive"], optional = true }
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"], optional = true }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"], optional = true }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false, features = ["serde"], optional = true }
|
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false, features = ["serde"], optional = true }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false, optional = true }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false, optional = true }
|
||||||
|
|
||||||
serai-primitives = { path = "../primitives", version = "0.1", default-features = false }
|
serai-primitives = { path = "../primitives", version = "0.1", default-features = false }
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,26 @@ use crate::{
|
|||||||
Transaction,
|
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.
|
/// 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;
|
pub const TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG: u8 = 4;
|
||||||
/// The tag for the branch hashes of transaction events.
|
/// The tag for the branch hashes of the Merkle tree for a transaction's events.
|
||||||
pub const TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG: u8 = 1;
|
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
|
/// 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.
|
/// Merkle tree which is the events' commitment.
|
||||||
pub const EVENTS_COMMITMENT_LEAF_TAG: u8 = 2;
|
pub const EVENTS_COMMITMENT_LEAF_TAG: u8 = 6;
|
||||||
/// The tag for for the branch hashes of the Merkle tree which is the events commitments.
|
/// The tag for branch hashes in the events' commitment.
|
||||||
pub const EVENTS_COMMITMENT_BRANCH_TAG: u8 = 3;
|
pub const EVENTS_COMMITMENT_BRANCH_TAG: u8 = 7;
|
||||||
|
|
||||||
/// A V1 header for a block.
|
/// A V1 header for a block.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
@@ -38,7 +49,8 @@ pub struct HeaderV1 {
|
|||||||
pub builds_upon: UnbalancedMerkleTree,
|
pub builds_upon: UnbalancedMerkleTree,
|
||||||
/// The UNIX time in milliseconds this block was created at.
|
/// The UNIX time in milliseconds this block was created at.
|
||||||
pub unix_time_in_millis: u64,
|
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,
|
pub transactions_commitment: UnbalancedMerkleTree,
|
||||||
/// The commitment to the events within this block.
|
/// The commitment to the events within this block.
|
||||||
///
|
///
|
||||||
@@ -147,6 +159,29 @@ mod substrate {
|
|||||||
pub unix_time_in_millis: u64,
|
pub unix_time_in_millis: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SeraiPreExecutionDigest {
|
||||||
|
/// The consensus ID for a Serai pre-execution digest.
|
||||||
|
pub const CONSENSUS_ID: [u8; 4] = *b"SRIP";
|
||||||
|
|
||||||
|
/// Find the pre-execution digest within a `Digest`.
|
||||||
|
///
|
||||||
|
/// This will panic if the digest either isn't found or is invalid.
|
||||||
|
pub fn find(digest: &Digest) -> Self {
|
||||||
|
for log in digest.logs() {
|
||||||
|
match log {
|
||||||
|
DigestItem::PreRuntime(consensus, encoded)
|
||||||
|
if *consensus == SeraiPreExecutionDigest::CONSENSUS_ID =>
|
||||||
|
{
|
||||||
|
return <_>::deserialize_reader(&mut encoded.as_slice())
|
||||||
|
.expect("invalid `SeraiPreExecutionDigest`");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("missing `SeraiPreExecutionDigest`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The digest for all of the Serai-specific header fields determined during execution of the
|
/// The digest for all of the Serai-specific header fields determined during execution of the
|
||||||
/// block.
|
/// block.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||||
@@ -159,11 +194,6 @@ mod substrate {
|
|||||||
pub events_commitment: UnbalancedMerkleTree,
|
pub events_commitment: UnbalancedMerkleTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SeraiPreExecutionDigest {
|
|
||||||
/// The consensus ID for a Serai pre-execution digest.
|
|
||||||
pub const CONSENSUS_ID: [u8; 4] = *b"SRIP";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SeraiExecutionDigest {
|
impl SeraiExecutionDigest {
|
||||||
/// The consensus ID for a Serai execution digest.
|
/// The consensus ID for a Serai execution digest.
|
||||||
pub const CONSENSUS_ID: [u8; 4] = *b"SRIE";
|
pub const CONSENSUS_ID: [u8; 4] = *b"SRIE";
|
||||||
@@ -241,7 +271,7 @@ mod substrate {
|
|||||||
for log in header.consensus.digest.logs() {
|
for log in header.consensus.digest.logs() {
|
||||||
match log {
|
match log {
|
||||||
DigestItem::PreRuntime(consensus, encoded)
|
DigestItem::PreRuntime(consensus, encoded)
|
||||||
if *consensus == SeraiExecutionDigest::CONSENSUS_ID =>
|
if *consensus == SeraiPreExecutionDigest::CONSENSUS_ID =>
|
||||||
{
|
{
|
||||||
pre_execution_digest =
|
pre_execution_digest =
|
||||||
SeraiPreExecutionDigest::deserialize_reader(&mut encoded.as_slice()).ok();
|
SeraiPreExecutionDigest::deserialize_reader(&mut encoded.as_slice()).ok();
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ serde_json = { version = "1", optional = true }
|
|||||||
serai-abi = { path = "../abi", version = "0.1" }
|
serai-abi = { path = "../abi", version = "0.1" }
|
||||||
|
|
||||||
multiaddr = { version = "0.18", optional = true }
|
multiaddr = { version = "0.18", optional = true }
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", optional = true }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", optional = true }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", optional = true }
|
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", optional = true }
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", optional = true }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", optional = true }
|
||||||
|
|
||||||
async-lock = "3"
|
async-lock = "3"
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/substrate/client/s
|
|||||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
keywords = ["serai"]
|
keywords = ["serai"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.85"
|
rust-version = "1.89"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
@@ -29,6 +29,8 @@ serai-abi = { path = "../../abi", version = "0.1" }
|
|||||||
async-lock = "3"
|
async-lock = "3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
blake2 = { version = "0.11.0-rc.3", default-features = false }
|
||||||
|
|
||||||
tokio = { version = "1", default-features = false, features = ["rt", "macros"] }
|
tokio = { version = "1", default-features = false, features = ["rt", "macros"] }
|
||||||
dockertest = "0.5"
|
dockertest = "0.5"
|
||||||
serai-docker-tests = { path = "../../../tests/docker" }
|
serai-docker-tests = { path = "../../../tests/docker" }
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ pub struct Serai {
|
|||||||
pub struct TemporalSerai<'a> {
|
pub struct TemporalSerai<'a> {
|
||||||
serai: &'a Serai,
|
serai: &'a Serai,
|
||||||
block: BlockHash,
|
block: BlockHash,
|
||||||
events: Arc<RwLock<Option<Vec<Event>>>>,
|
events: Arc<RwLock<Option<Vec<Vec<Event>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serai {
|
impl Serai {
|
||||||
@@ -109,10 +109,10 @@ impl Serai {
|
|||||||
Response { result: None, error: Some(error) } => {
|
Response { result: None, error: Some(error) } => {
|
||||||
Err(RpcError::ErrorInResponse(error.message))
|
Err(RpcError::ErrorInResponse(error.message))
|
||||||
}
|
}
|
||||||
Response { result: Some(_), error: Some(_) } | Response { result: None, error: None } => {
|
// TODO: https://github.com/core-json/core-json/issues/18
|
||||||
Err(RpcError::InvalidNode(
|
Response { result: None, error: None } => Ok(Default::default()),
|
||||||
"node didn't exclusively provide either `result` or `error`".to_string(),
|
Response { result: Some(_), error: Some(_) } => {
|
||||||
))
|
Err(RpcError::InvalidNode("node didn't provided both `result` and `error`".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,12 +125,12 @@ impl Serai {
|
|||||||
|
|
||||||
/// Fetch the latest finalized block number.
|
/// Fetch the latest finalized block number.
|
||||||
pub async fn latest_finalized_block_number(&self) -> Result<u64, RpcError> {
|
pub async fn latest_finalized_block_number(&self) -> Result<u64, RpcError> {
|
||||||
self.call("serai_latestFinalizedBlockNumber", "[]").await
|
self.call("blockchain/latest_finalized_block_number", "[]").await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch if a block is finalized.
|
/// Fetch if a block is finalized.
|
||||||
pub async fn finalized(&self, block: BlockHash) -> Result<bool, RpcError> {
|
pub async fn finalized(&self, block: BlockHash) -> Result<bool, RpcError> {
|
||||||
self.call("serai_isFinalized", &format!(r#"["{block}"]"#)).await
|
self.call("blockchain/is_finalized", &format!(r#"{{ "block": "{block}" }}"#)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn block_internal(
|
async fn block_internal(
|
||||||
@@ -147,12 +147,13 @@ impl Serai {
|
|||||||
|
|
||||||
/// Fetch a block from the Serai blockchain.
|
/// Fetch a block from the Serai blockchain.
|
||||||
pub async fn block(&self, block: BlockHash) -> Result<Block, RpcError> {
|
pub async fn block(&self, block: BlockHash) -> Result<Block, RpcError> {
|
||||||
Self::block_internal(self.call("serai_block", &format!(r#"["{block}"]"#))).await
|
Self::block_internal(self.call("blockchain/block", &format!(r#"{{ "block": "{block}" }}"#)))
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch a block from the Serai blockchain by its number.
|
/// Fetch a block from the Serai blockchain by its number.
|
||||||
pub async fn block_by_number(&self, block: u64) -> Result<Block, RpcError> {
|
pub async fn block_by_number(&self, block: u64) -> Result<Block, RpcError> {
|
||||||
Self::block_internal(self.call("serai_block", &format!("[{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.
|
/// Scope this RPC client to the state as of a specific block.
|
||||||
@@ -183,10 +184,20 @@ impl Serai {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TemporalSerai<'a> {
|
impl<'a> TemporalSerai<'a> {
|
||||||
|
async fn call<ResponseValue: Default + JsonDeserialize>(
|
||||||
|
&self,
|
||||||
|
method: &str,
|
||||||
|
params: &str,
|
||||||
|
) -> Result<ResponseValue, RpcError> {
|
||||||
|
self.serai.call(method, &format!(r#"{{ "block": "{}" {params} }}"#, self.block)).await
|
||||||
|
}
|
||||||
|
|
||||||
/// Fetch the events for this block.
|
/// Fetch the events for this block.
|
||||||
///
|
///
|
||||||
/// The returned `Option` will always be `Some(_)`.
|
/// The returned `Option` will always be `Some(_)`.
|
||||||
async fn events(&self) -> Result<async_lock::RwLockReadGuard<'_, Option<Vec<Event>>>, RpcError> {
|
async fn events_borrowed(
|
||||||
|
&self,
|
||||||
|
) -> Result<async_lock::RwLockReadGuard<'_, Option<Vec<Vec<Event>>>>, RpcError> {
|
||||||
let mut events = self.events.read().await;
|
let mut events = self.events.read().await;
|
||||||
if events.is_none() {
|
if events.is_none() {
|
||||||
drop(events);
|
drop(events);
|
||||||
@@ -195,21 +206,25 @@ impl<'a> TemporalSerai<'a> {
|
|||||||
if events_mut.is_none() {
|
if events_mut.is_none() {
|
||||||
*events_mut = Some(
|
*events_mut = Some(
|
||||||
self
|
self
|
||||||
.serai
|
.call::<Vec<Vec<String>>>("blockchain/events", "")
|
||||||
.call::<Vec<String>>("serai_events", &format!(r#"["{}"]"#, self.block))
|
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|event| {
|
.map(|events_per_tx| {
|
||||||
Event::deserialize(
|
events_per_tx
|
||||||
&mut hex::decode(&event)
|
.into_iter()
|
||||||
.map_err(|_| {
|
.map(|event| {
|
||||||
RpcError::InvalidNode("node returned non-hex-encoded event".to_string())
|
Event::deserialize(
|
||||||
})?
|
&mut hex::decode(&event)
|
||||||
.as_slice(),
|
.map_err(|_| {
|
||||||
)
|
RpcError::InvalidNode("node returned non-hex-encoded event".to_string())
|
||||||
.map_err(|_| RpcError::InvalidNode("node returned invalid event".to_string()))
|
})?
|
||||||
|
.as_slice(),
|
||||||
|
)
|
||||||
|
.map_err(|_| RpcError::InvalidNode("node returned invalid event".to_string()))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,6 +233,14 @@ impl<'a> TemporalSerai<'a> {
|
|||||||
Ok(events)
|
Ok(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch the events for this block.
|
||||||
|
///
|
||||||
|
/// These will be grouped by the transactions which emitted them, including the inherent
|
||||||
|
/// transactions at the start and end of every block.
|
||||||
|
pub async fn events(&self) -> Result<Vec<Vec<Event>>, RpcError> {
|
||||||
|
Ok(self.events_borrowed().await?.clone().expect("`TemporalSerai::events` returned None"))
|
||||||
|
}
|
||||||
|
|
||||||
/// Scope to the validator sets module.
|
/// Scope to the validator sets module.
|
||||||
pub fn validator_sets(&self) -> ValidatorSets<'_> {
|
pub fn validator_sets(&self) -> ValidatorSets<'_> {
|
||||||
ValidatorSets(self)
|
ValidatorSets(self)
|
||||||
|
|||||||
@@ -1,6 +1,27 @@
|
|||||||
pub use serai_abi::validator_sets::Event;
|
use borsh::BorshDeserialize;
|
||||||
|
|
||||||
|
pub use serai_abi::{
|
||||||
|
primitives::{
|
||||||
|
crypto::KeyPair,
|
||||||
|
network_id::{ExternalNetworkId, NetworkId},
|
||||||
|
validator_sets::{Session, ExternalValidatorSet, ValidatorSet},
|
||||||
|
balance::Amount,
|
||||||
|
},
|
||||||
|
validator_sets::Event,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{RpcError, TemporalSerai};
|
use crate::{RpcError, TemporalSerai};
|
||||||
|
|
||||||
|
fn rpc_network(network: impl Into<NetworkId>) -> Result<&'static str, RpcError> {
|
||||||
|
Ok(match network.into() {
|
||||||
|
NetworkId::Serai => r#""serai""#,
|
||||||
|
NetworkId::External(ExternalNetworkId::Bitcoin) => r#""bitcoin""#,
|
||||||
|
NetworkId::External(ExternalNetworkId::Ethereum) => r#""ethereum""#,
|
||||||
|
NetworkId::External(ExternalNetworkId::Monero) => r#""monero""#,
|
||||||
|
_ => Err(RpcError::InternalError("unrecognized network ID".to_string()))?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// A `TemporalSerai` scoped to the validator sets module.
|
/// A `TemporalSerai` scoped to the validator sets module.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ValidatorSets<'a>(pub(super) &'a TemporalSerai<'a>);
|
pub struct ValidatorSets<'a>(pub(super) &'a TemporalSerai<'a>);
|
||||||
@@ -11,11 +32,12 @@ impl<'a> ValidatorSets<'a> {
|
|||||||
Ok(
|
Ok(
|
||||||
self
|
self
|
||||||
.0
|
.0
|
||||||
.events()
|
.events_borrowed()
|
||||||
.await?
|
.await?
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("`TemporalSerai::events` returned None")
|
.expect("`TemporalSerai::events` returned None")
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(IntoIterator::into_iter)
|
||||||
.filter_map(|event| match event {
|
.filter_map(|event| match event {
|
||||||
serai_abi::Event::ValidatorSets(event) => Some(event.clone()),
|
serai_abi::Event::ValidatorSets(event) => Some(event.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -36,6 +58,18 @@ impl<'a> ValidatorSets<'a> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The `SetKeys` events from the validator sets module.
|
||||||
|
pub async fn set_keys_events(&self) -> Result<Vec<Event>, RpcError> {
|
||||||
|
Ok(
|
||||||
|
self
|
||||||
|
.events()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.filter(|event| matches!(event, Event::SetKeys { .. }))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// The `AcceptedHandover` events from the validator sets module.
|
/// The `AcceptedHandover` events from the validator sets module.
|
||||||
pub async fn accepted_handover_events(&self) -> Result<Vec<Event>, RpcError> {
|
pub async fn accepted_handover_events(&self) -> Result<Vec<Event>, RpcError> {
|
||||||
Ok(
|
Ok(
|
||||||
@@ -47,4 +81,65 @@ impl<'a> ValidatorSets<'a> {
|
|||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The `SlashReport` events from the validator sets module.
|
||||||
|
pub async fn slash_report_events(&self) -> Result<Vec<Event>, RpcError> {
|
||||||
|
Ok(
|
||||||
|
self
|
||||||
|
.events()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.filter(|event| matches!(event, Event::SlashReport { .. }))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The current session for the specified network.
|
||||||
|
pub async fn current_session(&self, network: NetworkId) -> Result<Option<Session>, RpcError> {
|
||||||
|
Ok(
|
||||||
|
self
|
||||||
|
.0
|
||||||
|
.call::<Option<_>>(
|
||||||
|
"validator-sets/current_session",
|
||||||
|
&format!(r#", "network": {} "#, rpc_network(network)?),
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.map(Session),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The stake for the current validators for specified network.
|
||||||
|
pub async fn current_stake(&self, network: NetworkId) -> Result<Option<Amount>, RpcError> {
|
||||||
|
Ok(
|
||||||
|
self
|
||||||
|
.0
|
||||||
|
.call::<Option<_>>(
|
||||||
|
"validator-sets/current_stake",
|
||||||
|
&format!(r#", "network": {} "#, rpc_network(network)?),
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.map(Amount),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The keys for the specified validator set.
|
||||||
|
pub async fn keys(&self, set: ExternalValidatorSet) -> Result<Option<KeyPair>, RpcError> {
|
||||||
|
let Some(key_pair) = self
|
||||||
|
.0
|
||||||
|
.call::<Option<String>>(
|
||||||
|
"validator-sets/keys",
|
||||||
|
&format!(r#", "network": {}, "session": {} "#, rpc_network(set.network)?, set.session.0),
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
KeyPair::deserialize(
|
||||||
|
&mut hex::decode(key_pair)
|
||||||
|
.map_err(|_| RpcError::InvalidNode("validator set's keys weren't valid hex".to_string()))?
|
||||||
|
.as_slice(),
|
||||||
|
)
|
||||||
|
.map(Some)
|
||||||
|
.map_err(|_| RpcError::InvalidNode("validator set's keys weren't a valid key pair".to_string()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use blake2::{Digest, Blake2b256};
|
||||||
|
|
||||||
|
use serai_abi::{
|
||||||
|
primitives::merkle::UnbalancedMerkleTree, BLOCK_HEADER_LEAF_TAG, BLOCK_HEADER_BRANCH_TAG,
|
||||||
|
TRANSACTION_COMMITMENT_LEAF_TAG, TRANSACTION_COMMITMENT_BRANCH_TAG,
|
||||||
|
TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG, TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG,
|
||||||
|
EVENTS_COMMITMENT_LEAF_TAG, EVENTS_COMMITMENT_BRANCH_TAG,
|
||||||
|
};
|
||||||
|
|
||||||
use serai_client_serai::*;
|
use serai_client_serai::*;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -91,6 +102,99 @@ async fn blockchain() {
|
|||||||
test_finalized_block(next_finalized).await;
|
test_finalized_block(next_finalized).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the blocks have the expected headers
|
||||||
|
{
|
||||||
|
let mut last_block_number = serai.latest_finalized_block_number().await.unwrap();
|
||||||
|
let mut observed_consensus_commitments = HashSet::new();
|
||||||
|
let mut tagged_block_hashes = vec![];
|
||||||
|
for i in 0 ..= last_block_number {
|
||||||
|
let block = serai.block_by_number(i).await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(block.header.number(), i);
|
||||||
|
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
UnbalancedMerkleTree::new(BLOCK_HEADER_BRANCH_TAG, tagged_block_hashes.clone()).root,
|
||||||
|
block.header.builds_upon().root,
|
||||||
|
);
|
||||||
|
tagged_block_hashes.push({
|
||||||
|
let mut tagged = vec![BLOCK_HEADER_LEAF_TAG];
|
||||||
|
tagged.extend(&block.header.hash().0);
|
||||||
|
Blake2b256::digest(tagged).into()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut start_transaction = [0; 32];
|
||||||
|
start_transaction[24 ..].copy_from_slice(&i.to_be_bytes());
|
||||||
|
let mut end_transaction = start_transaction;
|
||||||
|
end_transaction[.. 16].copy_from_slice(&[0xff; 16]);
|
||||||
|
let transactions_iter = core::iter::once(start_transaction)
|
||||||
|
.chain(block.transactions.iter().map(serai_abi::Transaction::hash))
|
||||||
|
.chain(core::iter::once(end_transaction));
|
||||||
|
|
||||||
|
let events = serai.as_of(block.header.hash()).await.unwrap().events().await.unwrap();
|
||||||
|
assert_eq!(events.len(), 2 + block.transactions.len());
|
||||||
|
|
||||||
|
let mut transaction_leaves = vec![];
|
||||||
|
let mut events_leaves = vec![];
|
||||||
|
for (transaction, events) in transactions_iter.zip(events) {
|
||||||
|
{
|
||||||
|
let mut tagged = vec![TRANSACTION_COMMITMENT_LEAF_TAG];
|
||||||
|
tagged.extend(&transaction);
|
||||||
|
transaction_leaves.push(Blake2b256::digest(tagged).into());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let events = UnbalancedMerkleTree::new(
|
||||||
|
TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG,
|
||||||
|
events
|
||||||
|
.into_iter()
|
||||||
|
.map(|event| {
|
||||||
|
let mut tagged = vec![TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG];
|
||||||
|
tagged.extend(&borsh::to_vec(&event).unwrap());
|
||||||
|
Blake2b256::digest(tagged).into()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.root;
|
||||||
|
|
||||||
|
let mut tagged = vec![EVENTS_COMMITMENT_LEAF_TAG];
|
||||||
|
tagged.extend(&transaction);
|
||||||
|
tagged.extend(&events);
|
||||||
|
events_leaves.push(Blake2b256::digest(tagged).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
UnbalancedMerkleTree::new(TRANSACTION_COMMITMENT_BRANCH_TAG, transaction_leaves).root,
|
||||||
|
block.header.transactions_commitment().root
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
UnbalancedMerkleTree::new(EVENTS_COMMITMENT_BRANCH_TAG, events_leaves).root,
|
||||||
|
block.header.events_commitment().root
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match block.header {
|
||||||
|
serai_abi::Header::V1(serai_abi::HeaderV1 {
|
||||||
|
unix_time_in_millis,
|
||||||
|
consensus_commitment,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
if i == 0 {
|
||||||
|
assert_eq!(unix_time_in_millis, 0);
|
||||||
|
} else {
|
||||||
|
assert!(unix_time_in_millis != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We treat the `consensus_commitment` as opaque, but we do want to make sure it's set
|
||||||
|
// This check practically ensures it's being properly defined for each block
|
||||||
|
assert!(!observed_consensus_commitments.contains(&consensus_commitment));
|
||||||
|
observed_consensus_commitments.insert(consensus_commitment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
println!("Finished `serai-client/blockchain` test");
|
println!("Finished `serai-client/blockchain` test");
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use serai_abi::{
|
use serai_abi::{
|
||||||
primitives::{
|
primitives::{
|
||||||
network_id::{ExternalNetworkId, NetworkId},
|
network_id::{ExternalNetworkId, NetworkId},
|
||||||
validator_sets::{Session, ValidatorSet},
|
balance::Amount,
|
||||||
|
validator_sets::{Session, ExternalValidatorSet, ValidatorSet},
|
||||||
},
|
},
|
||||||
validator_sets::Event,
|
validator_sets::Event,
|
||||||
};
|
};
|
||||||
@@ -125,7 +126,32 @@ async fn validator_sets() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Finished `serai-client/blockchain` test");
|
{
|
||||||
|
let serai =
|
||||||
|
serai.as_of(serai.block_by_number(0).await.unwrap().header.hash()).await.unwrap();
|
||||||
|
let serai = serai.validator_sets();
|
||||||
|
for network in NetworkId::all() {
|
||||||
|
match network {
|
||||||
|
NetworkId::Serai => {
|
||||||
|
assert_eq!(serai.current_session(network).await.unwrap(), Some(Session(0)));
|
||||||
|
assert_eq!(serai.current_stake(network).await.unwrap(), Some(Amount(0)));
|
||||||
|
}
|
||||||
|
NetworkId::External(external) => {
|
||||||
|
assert!(serai.current_session(network).await.unwrap().is_none());
|
||||||
|
assert!(serai.current_stake(network).await.unwrap().is_none());
|
||||||
|
assert_eq!(
|
||||||
|
serai
|
||||||
|
.keys(ExternalValidatorSet { network: external, session: Session(0) })
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Finished `serai-client/validator_sets` test");
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||||
serai-core-pallet = { path = "../core", default-features = false }
|
serai-core-pallet = { path = "../core", default-features = false }
|
||||||
@@ -29,7 +29,9 @@ serai-core-pallet = { path = "../core", default-features = false }
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false, features = ["std"] }
|
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
|
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = [
|
std = [
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ construct_runtime!(
|
|||||||
pub enum Test
|
pub enum Test
|
||||||
{
|
{
|
||||||
System: frame_system,
|
System: frame_system,
|
||||||
|
Timestamp: pallet_timestamp,
|
||||||
Core: serai_core_pallet,
|
Core: serai_core_pallet,
|
||||||
Coins: coins::<CoinsInstance>,
|
Coins: coins::<CoinsInstance>,
|
||||||
}
|
}
|
||||||
@@ -22,6 +23,9 @@ impl frame_system::Config for Test {
|
|||||||
type Block = frame_system::mocking::MockBlock<Test>;
|
type Block = frame_system::mocking::MockBlock<Test>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)]
|
||||||
|
impl pallet_timestamp::Config for Test {}
|
||||||
|
|
||||||
impl serai_core_pallet::Config for Test {}
|
impl serai_core_pallet::Config for Test {}
|
||||||
|
|
||||||
impl crate::Config<CoinsInstance> for Test {
|
impl crate::Config<CoinsInstance> for Test {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ fn mint() {
|
|||||||
// test events
|
// test events
|
||||||
let mint_events = Core::events()
|
let mint_events = Core::events()
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(IntoIterator::into_iter)
|
||||||
.map(|event| borsh::from_slice::<serai_abi::Event>(event.as_slice()).unwrap())
|
.map(|event| borsh::from_slice::<serai_abi::Event>(event.as_slice()).unwrap())
|
||||||
.filter_map(|event| {
|
.filter_map(|event| {
|
||||||
if let serai_abi::Event::Coins(e) = &event {
|
if let serai_abi::Event::Coins(e) = &event {
|
||||||
@@ -83,6 +84,7 @@ fn burn_with_instruction() {
|
|||||||
|
|
||||||
let burn_events = Core::events()
|
let burn_events = Core::events()
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(IntoIterator::into_iter)
|
||||||
.map(|event| borsh::from_slice::<serai_abi::Event>(event.as_slice()).unwrap())
|
.map(|event| borsh::from_slice::<serai_abi::Event>(event.as_slice()).unwrap())
|
||||||
.filter_map(|event| {
|
.filter_map(|event| {
|
||||||
if let serai_abi::Event::Coins(e) = &event {
|
if let serai_abi::Event::Coins(e) = &event {
|
||||||
|
|||||||
@@ -20,10 +20,12 @@ borsh = { version = "1", default-features = false, features = ["derive", "de_str
|
|||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
|
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||||
|
|
||||||
@@ -37,14 +39,17 @@ std = [
|
|||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
|
|
||||||
|
"pallet-timestamp/std",
|
||||||
|
|
||||||
"serai-abi/std",
|
"serai-abi/std",
|
||||||
]
|
]
|
||||||
|
|
||||||
runtime-benchmarks = [
|
runtime-benchmarks = [
|
||||||
"frame-system/runtime-benchmarks",
|
"frame-system/runtime-benchmarks",
|
||||||
"frame-support/runtime-benchmarks",
|
"frame-support/runtime-benchmarks",
|
||||||
|
"pallet-timestamp/runtime-benchmarks",
|
||||||
]
|
]
|
||||||
|
|
||||||
try-runtime = ["serai-abi/try-runtime"]
|
try-runtime = ["pallet-timestamp/try-runtime", "serai-abi/try-runtime"]
|
||||||
|
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use serai_abi::primitives::merkle::{UnbalancedMerkleTree, IncrementalUnbalancedM
|
|||||||
/// `IncrementalUnbalancedMerkleTree`.
|
/// `IncrementalUnbalancedMerkleTree`.
|
||||||
pub struct IncrementalUnbalancedMerkleTree<
|
pub struct IncrementalUnbalancedMerkleTree<
|
||||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||||
const BRANCH_TAG: u8 = 1,
|
const BRANCH_TAG: u8,
|
||||||
const LEAF_TAG: u8 = 0,
|
const LEAF_TAG: u8,
|
||||||
>(PhantomData<T>);
|
>(PhantomData<T>);
|
||||||
impl<
|
impl<
|
||||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||||
|
|||||||
@@ -4,18 +4,22 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
use frame_support::traits::{PreInherents, PostTransactions};
|
||||||
|
|
||||||
mod iumt;
|
mod iumt;
|
||||||
pub use iumt::*;
|
pub use iumt::*;
|
||||||
|
|
||||||
#[expect(clippy::cast_possible_truncation)]
|
#[expect(clippy::cast_possible_truncation)]
|
||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
use alloc::vec::Vec;
|
use alloc::{vec::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};
|
use serai_abi::primitives::{prelude::*, merkle::IncrementalUnbalancedMerkleTree as Iumt};
|
||||||
|
|
||||||
@@ -28,14 +32,21 @@ pub mod pallet {
|
|||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
#[pallet::unbounded]
|
#[pallet::unbounded]
|
||||||
pub(super) type BlocksCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
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.
|
/// The Merkle tree of all transactions within the current block.
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
#[pallet::unbounded]
|
#[pallet::unbounded]
|
||||||
pub(super) type BlockTransactionsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
pub(super) type BlockTransactionsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||||
pub(super) type BlockTransactionsCommitmentMerkle<T> =
|
pub(super) type BlockTransactionsCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||||
IncrementalUnbalancedMerkleTree<BlockTransactionsCommitment<T>>;
|
BlockTransactionsCommitment<T>,
|
||||||
|
{ serai_abi::TRANSACTION_COMMITMENT_BRANCH_TAG },
|
||||||
|
{ serai_abi::TRANSACTION_COMMITMENT_LEAF_TAG },
|
||||||
|
>;
|
||||||
|
|
||||||
/// The hashes of events caused by the current transaction.
|
/// The hashes of events caused by the current transaction.
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
@@ -64,12 +75,17 @@ pub mod pallet {
|
|||||||
#[pallet::event]
|
#[pallet::event]
|
||||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||||
pub enum Event<T: Config> {
|
pub enum Event<T: Config> {
|
||||||
|
/// A transaction begun.
|
||||||
|
BeginTransaction,
|
||||||
/// An event from Serai.
|
/// An event from Serai.
|
||||||
Event(Vec<u8>),
|
Event(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::config]
|
#[pallet::config]
|
||||||
pub trait Config: frame_system::Config<Hash: Into<[u8; 32]>> {}
|
pub trait Config:
|
||||||
|
frame_system::Config<Hash: Into<[u8; 32]>> + pallet_timestamp::Config<Moment = u64>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
pub struct Pallet<T>(_);
|
pub struct Pallet<T>(_);
|
||||||
@@ -99,10 +115,16 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The code to run on genesis.
|
/// The code to run on genesis.
|
||||||
pub fn genesis() {
|
pub fn genesis(config: &impl frame_support::traits::BuildGenesisConfig) {
|
||||||
BlocksCommitmentMerkle::<T>::new_expecting_none();
|
BlocksCommitmentMerkle::<T>::new_expecting_none();
|
||||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||||
BlockEventsCommitmentMerkle::<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.
|
/// The code to run when beginning execution of a transaction.
|
||||||
@@ -110,6 +132,7 @@ pub mod pallet {
|
|||||||
/// The caller MUST ensure two transactions aren't simultaneously started.
|
/// The caller MUST ensure two transactions aren't simultaneously started.
|
||||||
pub fn start_transaction() {
|
pub fn start_transaction() {
|
||||||
TransactionEventsMerkle::<T>::new_expecting_none();
|
TransactionEventsMerkle::<T>::new_expecting_none();
|
||||||
|
Self::deposit_event(Event::BeginTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit an event.
|
/// Emit an event.
|
||||||
@@ -130,19 +153,24 @@ pub mod pallet {
|
|||||||
BlockEventsCommitmentMerkle::<T>::append(&(&transaction_hash, &transaction_events_root));
|
BlockEventsCommitmentMerkle::<T>::append(&(&transaction_hash, &transaction_events_root));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch all of Serai's events.
|
/// Fetch all of Serai's events for each transaction.
|
||||||
///
|
///
|
||||||
/// This MUST NOT be called during a transaction/block's execution.
|
/// This MUST NOT be called during a transaction/block's execution.
|
||||||
pub fn events() -> Vec<Vec<u8>>
|
pub fn events() -> Vec<Vec<Vec<u8>>>
|
||||||
where
|
where
|
||||||
T::RuntimeEvent: TryInto<Event<T>>,
|
T::RuntimeEvent: TryInto<Event<T>>,
|
||||||
{
|
{
|
||||||
frame_system::Pallet::<T>::read_events_no_consensus()
|
let mut result = vec![];
|
||||||
.filter_map(|e| match e.event.try_into() {
|
for event in frame_system::Pallet::<T>::read_events_no_consensus() {
|
||||||
Ok(Event::Event(bytes)) => Some(bytes),
|
match event.event.try_into() {
|
||||||
_ => None,
|
Ok(Event::BeginTransaction) => result.push(vec![]),
|
||||||
})
|
Ok(Event::Event(bytes)) => {
|
||||||
.collect()
|
result.last_mut().expect("Serai event outside of a transaction").push(bytes)
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,7 +178,7 @@ pub use pallet::*;
|
|||||||
|
|
||||||
/// The code to run at the start of a block for this pallet.
|
/// The code to run at the start of a block for this pallet.
|
||||||
pub struct StartOfBlock<T: Config>(PhantomData<T>);
|
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() {
|
fn pre_inherents() {
|
||||||
use frame_support::pallet_prelude::Zero;
|
use frame_support::pallet_prelude::Zero;
|
||||||
// `Pallet::genesis` is expected to be used for the genesis block
|
// `Pallet::genesis` is expected to be used for the genesis block
|
||||||
@@ -163,13 +191,44 @@ impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
|
|||||||
|
|
||||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||||
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
||||||
|
|
||||||
|
Pallet::<T>::start_transaction();
|
||||||
|
|
||||||
|
// Handle the `SeraiPreExecutionDigest`
|
||||||
|
/*
|
||||||
|
These calls panic but this is desired behavior. All blocks, except the genesis, should have
|
||||||
|
this and the timestamp should be valid.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
let digest = serai_abi::SeraiPreExecutionDigest::find(&frame_system::Pallet::<T>::digest());
|
||||||
|
pallet_timestamp::Pallet::<T>::set(
|
||||||
|
frame_system::RawOrigin::None.into(),
|
||||||
|
digest.unix_time_in_millis,
|
||||||
|
)
|
||||||
|
.expect("failed to set timestamp");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
/// The code to run at the end of a block for this pallet.
|
||||||
pub struct EndOfBlock<T: Config>(PhantomData<T>);
|
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() {
|
fn post_transactions() {
|
||||||
|
Pallet::<T>::start_transaction();
|
||||||
|
|
||||||
|
// Other modules' `PostTransactions`
|
||||||
|
|
||||||
|
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;
|
use serai_abi::SeraiExecutionDigest;
|
||||||
frame_system::Pallet::<T>::deposit_log(
|
frame_system::Pallet::<T>::deposit_log(
|
||||||
frame_support::sp_runtime::generic::DigestItem::Consensus(
|
frame_support::sp_runtime::generic::DigestItem::Consensus(
|
||||||
|
|||||||
@@ -21,15 +21,15 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scale = { package = "parity-scale-codec", version = "3.6.1", default-features = false }
|
scale = { package = "parity-scale-codec", version = "3.6.1", default-features = false }
|
||||||
|
|
||||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false, optional = true }
|
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false, optional = true }
|
||||||
|
|
||||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
dex-pallet = { package = "serai-dex-pallet", path = "../dex", default-features = false }
|
dex-pallet = { package = "serai-dex-pallet", path = "../dex", default-features = false }
|
||||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||||
@@ -30,16 +30,16 @@ coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-feat
|
|||||||
serai-primitives = { path = "../primitives", default-features = false }
|
serai-primitives = { path = "../primitives", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets", default-features = false }
|
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets", default-features = false }
|
||||||
|
|
||||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = [
|
std = [
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||||
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets", default-features = false }
|
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets", default-features = false }
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
dex-pallet = { package = "serai-dex-pallet", path = "../dex", default-features = false }
|
dex-pallet = { package = "serai-dex-pallet", path = "../dex", default-features = false }
|
||||||
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-features = false }
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
|||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] }
|
||||||
|
|
||||||
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-std = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
serai-primitives = { path = "../primitives", default-features = false }
|
serai-primitives = { path = "../primitives", default-features = false }
|
||||||
|
|
||||||
@@ -42,9 +42,9 @@ genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path =
|
|||||||
emissions-pallet = { package = "serai-emissions-pallet", path = "../emissions", default-features = false }
|
emissions-pallet = { package = "serai-emissions-pallet", path = "../emissions", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
economic-security-pallet = { package = "serai-economic-security-pallet", path = "../economic-security", default-features = false }
|
economic-security-pallet = { package = "serai-economic-security-pallet", path = "../economic-security", default-features = false }
|
||||||
|
|
||||||
|
|||||||
@@ -34,20 +34,20 @@ secq256k1 = { path = "../../crypto/secq256k1" }
|
|||||||
|
|
||||||
libp2p = "0.56"
|
libp2p = "0.56"
|
||||||
|
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-inherents = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-inherents = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-blockchain = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-blockchain = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-consensus = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-consensus = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-state-machine = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-state-machine = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-keystore = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-keystore = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-block-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-block-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
|
|
||||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
|
|
||||||
serai-abi = { path = "../abi", features = ["std", "substrate"] }
|
serai-abi = { path = "../abi", features = ["std", "substrate"] }
|
||||||
serai-runtime = { path = "../runtime", features = ["std"] }
|
serai-runtime = { path = "../runtime", features = ["std"] }
|
||||||
@@ -59,23 +59,24 @@ futures-util = "0.3"
|
|||||||
tokio = { version = "1", features = ["sync", "rt-multi-thread"] }
|
tokio = { version = "1", features = ["sync", "rt-multi-thread"] }
|
||||||
jsonrpsee = { version = "0.24", features = ["server"] }
|
jsonrpsee = { version = "0.24", features = ["server"] }
|
||||||
|
|
||||||
sc-transaction-pool = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-transaction-pool = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-transaction-pool-api = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-basic-authorship = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-basic-authorship = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-executor = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-client-db = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-service = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-executor = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-client-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-service = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-network = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-client-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
|
sc-network = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
|
|
||||||
sc-consensus = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-consensus = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-consensus-slots = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-consensus-slots = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-consensus-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-consensus-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-authority-discovery = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-authority-discovery = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
|
|
||||||
sc-telemetry = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-telemetry = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-chain-spec = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-chain-spec = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
sc-cli = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
sc-cli = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
|
|
||||||
serai-env = { path = "../../common/env" }
|
serai-env = { path = "../../common/env" }
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
use core::marker::PhantomData;
|
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 sc_service::ChainType;
|
||||||
|
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
@@ -201,3 +209,45 @@ pub fn bootnode_multiaddrs(id: &str) -> Vec<libp2p::Multiaddr> {
|
|||||||
_ => panic!("unrecognized network ID"),
|
_ => 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,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,46 +15,7 @@ use serai_runtime::SeraiApi;
|
|||||||
|
|
||||||
use jsonrpsee::RpcModule;
|
use jsonrpsee::RpcModule;
|
||||||
|
|
||||||
fn block_hash<
|
use super::utils::{Error, block_hash};
|
||||||
C: HeaderMetadata<Block, Error = BlockchainError>
|
|
||||||
+ HeaderBackend<Block>
|
|
||||||
+ BlockBackend<Block>
|
|
||||||
+ ProvideRuntimeApi<Block>,
|
|
||||||
>(
|
|
||||||
client: &C,
|
|
||||||
params: &jsonrpsee::types::params::Params,
|
|
||||||
) -> Result<<Block as sp_runtime::traits::Block>::Hash, jsonrpsee::types::error::ErrorObjectOwned> {
|
|
||||||
Ok(if let Ok(block_hash) = params.sequence().next::<String>() {
|
|
||||||
let Some(block_hash) = hex::decode(&block_hash).ok().and_then(|bytes| {
|
|
||||||
<[u8; 32]>::try_from(bytes.as_slice())
|
|
||||||
.map(<Block as sp_runtime::traits::Block>::Hash::from)
|
|
||||||
.ok()
|
|
||||||
}) else {
|
|
||||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
|
||||||
-1,
|
|
||||||
"requested block hash wasn't a valid hash",
|
|
||||||
Option::<()>::None,
|
|
||||||
));
|
|
||||||
};
|
|
||||||
block_hash
|
|
||||||
} else {
|
|
||||||
let Ok(block_number) = params.sequence().next::<u64>() else {
|
|
||||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
|
||||||
-1,
|
|
||||||
"requested block wasn't a valid hash nor number",
|
|
||||||
Option::<()>::None,
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Ok(Some(block_hash)) = client.block_hash(block_number) else {
|
|
||||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
|
||||||
-2,
|
|
||||||
"couldn't find requested block's hash",
|
|
||||||
Option::<()>::None,
|
|
||||||
));
|
|
||||||
};
|
|
||||||
block_hash
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn module<
|
pub(crate) fn module<
|
||||||
C: 'static
|
C: 'static
|
||||||
@@ -69,56 +30,48 @@ pub(crate) fn module<
|
|||||||
) -> Result<RpcModule<impl 'static + Send + Sync>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<RpcModule<impl 'static + Send + Sync>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut module = RpcModule::new(client);
|
let mut module = RpcModule::new(client);
|
||||||
|
|
||||||
module.register_method("serai_latestFinalizedBlockNumber", |_params, client, _ext| {
|
module.register_method("blockchain/latest_finalized_block_number", |_params, client, _ext| {
|
||||||
client.info().finalized_number
|
client.info().finalized_number
|
||||||
});
|
});
|
||||||
|
|
||||||
module.register_method("serai_isFinalized", |params, client, _ext| {
|
module.register_method(
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
"blockchain/is_finalized",
|
||||||
let finalized = client.info().finalized_number;
|
|params, client, _ext| -> Result<_, Error> {
|
||||||
let Ok(Some(number)) = client.number(block_hash) else {
|
let block_hash = block_hash(&**client, ¶ms)?;
|
||||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
let finalized = client.info().finalized_number;
|
||||||
-2,
|
let Ok(Some(number)) = client.number(block_hash) else {
|
||||||
"failed to fetch block's number",
|
Err(Error::Missing("failed to fetch block's number"))?
|
||||||
Option::<()>::None,
|
};
|
||||||
));
|
let Ok(status) = client.block_status(block_hash) else {
|
||||||
};
|
Err(Error::Internal("failed to fetch block's status"))?
|
||||||
let Ok(status) = client.block_status(block_hash) else {
|
};
|
||||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
Ok(
|
||||||
-3,
|
matches!(status, BlockStatus::InChainWithState | BlockStatus::InChainPruned) &&
|
||||||
"failed to fetch block's status",
|
(number <= finalized),
|
||||||
Option::<()>::None,
|
)
|
||||||
));
|
},
|
||||||
};
|
)?;
|
||||||
Ok(
|
|
||||||
matches!(status, BlockStatus::InChainWithState | BlockStatus::InChainPruned) &&
|
|
||||||
(number <= finalized),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
module.register_method("serai_block", |params, client, _ext| {
|
module.register_method("blockchain/block", |params, client, _ext| -> Result<_, Error> {
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
let block_hash = block_hash(&**client, ¶ms)?;
|
||||||
let Ok(Some(block)) = client.block(block_hash) else {
|
let Ok(Some(block)) = client.block(block_hash) else {
|
||||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
Err(Error::Missing("couldn't find requested block"))?
|
||||||
-2,
|
|
||||||
"couldn't find requested block",
|
|
||||||
Option::<()>::None,
|
|
||||||
));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(hex::encode(borsh::to_vec(&serai_abi::Block::from(block.block)).unwrap()))
|
Ok(hex::encode(borsh::to_vec(&serai_abi::Block::from(block.block)).unwrap()))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
module.register_method("serai_events", |params, client, _ext| {
|
module.register_method("blockchain/events", |params, client, _ext| -> Result<_, Error> {
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
let block_hash = block_hash(&**client, ¶ms)?;
|
||||||
let Ok(events) = client.runtime_api().events(block_hash) else {
|
let Ok(events) = client.runtime_api().events(block_hash) else {
|
||||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
Err(Error::Missing("couldn't fetch the events for the requested block"))?
|
||||||
-2,
|
|
||||||
"couldn't fetch the events for the requested block",
|
|
||||||
Option::<()>::None,
|
|
||||||
));
|
|
||||||
};
|
};
|
||||||
Ok(events.into_iter().map(hex::encode).collect::<Vec<String>>())
|
Ok(
|
||||||
|
events
|
||||||
|
.into_iter()
|
||||||
|
.map(|events_per_tx| events_per_tx.into_iter().map(hex::encode).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(module)
|
Ok(module)
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ use jsonrpsee::RpcModule;
|
|||||||
use sc_client_api::BlockBackend;
|
use sc_client_api::BlockBackend;
|
||||||
use sc_transaction_pool_api::TransactionPool;
|
use sc_transaction_pool_api::TransactionPool;
|
||||||
|
|
||||||
|
mod utils;
|
||||||
mod blockchain;
|
mod blockchain;
|
||||||
|
mod validator_sets;
|
||||||
mod p2p_validators;
|
mod p2p_validators;
|
||||||
|
|
||||||
pub struct FullDeps<C, P> {
|
pub struct FullDeps<C, P> {
|
||||||
@@ -42,6 +44,7 @@ pub fn create_full<
|
|||||||
|
|
||||||
let mut root = RpcModule::new(());
|
let mut root = RpcModule::new(());
|
||||||
root.merge(blockchain::module(client.clone())?)?;
|
root.merge(blockchain::module(client.clone())?)?;
|
||||||
|
root.merge(validator_sets::module(client.clone()))?;
|
||||||
if let Some(authority_discovery) = authority_discovery {
|
if let Some(authority_discovery) = authority_discovery {
|
||||||
root.merge(p2p_validators::module(id, client, authority_discovery)?)?;
|
root.merge(p2p_validators::module(id, client, authority_discovery)?)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ use tokio::sync::RwLock;
|
|||||||
|
|
||||||
use jsonrpsee::RpcModule;
|
use jsonrpsee::RpcModule;
|
||||||
|
|
||||||
|
use super::utils::Error;
|
||||||
|
|
||||||
pub(crate) fn module<
|
pub(crate) fn module<
|
||||||
C: 'static + Send + Sync + HeaderBackend<Block> + ProvideRuntimeApi<Block, Api: SeraiApi<Block>>,
|
C: 'static + Send + Sync + HeaderBackend<Block> + ProvideRuntimeApi<Block, Api: SeraiApi<Block>>,
|
||||||
>(
|
>(
|
||||||
@@ -22,34 +24,28 @@ pub(crate) fn module<
|
|||||||
) -> Result<RpcModule<impl 'static + Send + Sync>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<RpcModule<impl 'static + Send + Sync>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut module = RpcModule::new((id, client, RwLock::new(authority_discovery)));
|
let mut module = RpcModule::new((id, client, RwLock::new(authority_discovery)));
|
||||||
module.register_async_method("p2p_validators", |params, context, _ext| async move {
|
module.register_async_method("p2p_validators", |params, context, _ext| async move {
|
||||||
let [network]: [String; 1] = params.parse()?;
|
let network = match params.parse::<[String; 1]>() {
|
||||||
|
Ok([network]) => network,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
|
|
||||||
let network = match network.to_lowercase().as_str() {
|
let network = match network.to_lowercase().as_str() {
|
||||||
"serai" => NetworkId::Serai,
|
"serai" => NetworkId::Serai,
|
||||||
"bitcoin" => ExternalNetworkId::Bitcoin.into(),
|
"bitcoin" => ExternalNetworkId::Bitcoin.into(),
|
||||||
"ethereum" => ExternalNetworkId::Ethereum.into(),
|
"ethereum" => ExternalNetworkId::Ethereum.into(),
|
||||||
"monero" => ExternalNetworkId::Monero.into(),
|
"monero" => ExternalNetworkId::Monero.into(),
|
||||||
_ => Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
_ => Err(Error::InvalidRequest("network to fetch the `p2p_validators` of was unrecognized"))?,
|
||||||
-1,
|
|
||||||
"network to fetch the `p2p_validators` of was unrecognized".to_string(),
|
|
||||||
Option::<()>::None,
|
|
||||||
))?,
|
|
||||||
};
|
};
|
||||||
let (id, client, authority_discovery) = &*context;
|
let (id, client, authority_discovery) = &*context;
|
||||||
let latest_block = client.info().best_hash;
|
let latest_block = client.info().best_hash;
|
||||||
|
|
||||||
let validators = client.runtime_api().validators(latest_block, network).map_err(|_| {
|
let validators = client
|
||||||
jsonrpsee::types::error::ErrorObjectOwned::owned(
|
.runtime_api()
|
||||||
-2,
|
.validators(latest_block, network)
|
||||||
format!(
|
.map_err(|_| Error::Internal("couldn't get validators from the latest block"));
|
||||||
"couldn't get validators from the latest block, which is likely a fatal bug. {}",
|
|
||||||
"please report this at https://github.com/serai-dex/serai",
|
|
||||||
),
|
|
||||||
Option::<()>::None,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let validators = match validators {
|
let validators = match validators {
|
||||||
Ok(validators) => validators,
|
Ok(validators) => validators,
|
||||||
Err(e) => return Err(e),
|
Err(e) => Err(e)?,
|
||||||
};
|
};
|
||||||
// Always return the protocol's bootnodes
|
// Always return the protocol's bootnodes
|
||||||
let mut all_p2p_addresses = crate::chain_spec::bootnode_multiaddrs(id);
|
let mut all_p2p_addresses = crate::chain_spec::bootnode_multiaddrs(id);
|
||||||
|
|||||||
63
substrate/node/src/rpc/utils.rs
Normal file
63
substrate/node/src/rpc/utils.rs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
use sp_blockchain::{Error as BlockchainError, HeaderMetadata, HeaderBackend};
|
||||||
|
use sc_client_api::BlockBackend;
|
||||||
|
|
||||||
|
use serai_abi::{primitives::prelude::*, SubstrateBlock as Block};
|
||||||
|
|
||||||
|
pub(super) enum Error {
|
||||||
|
Internal(&'static str),
|
||||||
|
InvalidRequest(&'static str),
|
||||||
|
Missing(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for jsonrpsee::types::error::ErrorObjectOwned {
|
||||||
|
fn from(error: Error) -> Self {
|
||||||
|
match error {
|
||||||
|
Error::Internal(str) => {
|
||||||
|
jsonrpsee::types::error::ErrorObjectOwned::owned(-1, str, Option::<()>::None)
|
||||||
|
}
|
||||||
|
Error::InvalidRequest(str) => {
|
||||||
|
jsonrpsee::types::error::ErrorObjectOwned::owned(-2, str, Option::<()>::None)
|
||||||
|
}
|
||||||
|
Error::Missing(str) => {
|
||||||
|
jsonrpsee::types::error::ErrorObjectOwned::owned(-3, str, Option::<()>::None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn block_hash<
|
||||||
|
C: HeaderMetadata<Block, Error = BlockchainError> + HeaderBackend<Block> + BlockBackend<Block>,
|
||||||
|
>(
|
||||||
|
client: &C,
|
||||||
|
params: &jsonrpsee::types::params::Params,
|
||||||
|
) -> Result<<Block as sp_runtime::traits::Block>::Hash, Error> {
|
||||||
|
#[derive(sp_core::serde::Deserialize)]
|
||||||
|
#[serde(crate = "sp_core::serde")]
|
||||||
|
struct BlockByHash {
|
||||||
|
block: String,
|
||||||
|
};
|
||||||
|
#[derive(sp_core::serde::Deserialize)]
|
||||||
|
#[serde(crate = "sp_core::serde")]
|
||||||
|
struct BlockByNumber {
|
||||||
|
block: u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(if let Ok(block_hash) = params.parse::<BlockByHash>() {
|
||||||
|
let Some(block_hash) = hex::decode(&block_hash.block).ok().and_then(|bytes| {
|
||||||
|
<[u8; 32]>::try_from(bytes.as_slice())
|
||||||
|
.map(<Block as sp_runtime::traits::Block>::Hash::from)
|
||||||
|
.ok()
|
||||||
|
}) else {
|
||||||
|
return Err(Error::InvalidRequest("requested block hash wasn't a valid hash"));
|
||||||
|
};
|
||||||
|
block_hash
|
||||||
|
} else {
|
||||||
|
let Ok(block_number) = params.parse::<BlockByNumber>() else {
|
||||||
|
return Err(Error::InvalidRequest("requested block wasn't a valid hash nor number"));
|
||||||
|
};
|
||||||
|
let Ok(Some(block_hash)) = client.block_hash(block_number.block) else {
|
||||||
|
return Err(Error::Missing("no block hash for that block number"));
|
||||||
|
};
|
||||||
|
block_hash
|
||||||
|
})
|
||||||
|
}
|
||||||
109
substrate/node/src/rpc/validator_sets.rs
Normal file
109
substrate/node/src/rpc/validator_sets.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
use std::{sync::Arc, ops::Deref, convert::AsRef, collections::HashSet};
|
||||||
|
|
||||||
|
use rand_core::{RngCore, OsRng};
|
||||||
|
|
||||||
|
use sp_core::Encode;
|
||||||
|
use sp_blockchain::{Error as BlockchainError, HeaderMetadata, HeaderBackend};
|
||||||
|
use sp_consensus::BlockStatus;
|
||||||
|
use sp_block_builder::BlockBuilder;
|
||||||
|
use sp_api::ProvideRuntimeApi;
|
||||||
|
use sc_client_api::BlockBackend;
|
||||||
|
|
||||||
|
use serai_abi::{primitives::prelude::*, SubstrateBlock as Block};
|
||||||
|
|
||||||
|
use serai_runtime::SeraiApi;
|
||||||
|
|
||||||
|
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")]
|
||||||
|
struct Network {
|
||||||
|
network: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(network) = params.parse::<Network>() else {
|
||||||
|
Err(Error::InvalidRequest(r#"missing `string` "network" field"#))?
|
||||||
|
};
|
||||||
|
|
||||||
|
network_from_str(network.network)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn set(params: &jsonrpsee::types::params::Params) -> Result<ValidatorSet, Error> {
|
||||||
|
#[derive(sp_core::serde::Deserialize)]
|
||||||
|
#[serde(crate = "sp_core::serde")]
|
||||||
|
struct Set {
|
||||||
|
network: String,
|
||||||
|
session: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(set) = params.parse::<Set>() else {
|
||||||
|
Err(Error::InvalidRequest(r#"missing `object` "set" field"#))?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ValidatorSet { network: network_from_str(set.network)?, session: Session(set.session) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn module<
|
||||||
|
C: 'static
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ HeaderMetadata<Block, Error = BlockchainError>
|
||||||
|
+ HeaderBackend<Block>
|
||||||
|
+ BlockBackend<Block>
|
||||||
|
+ ProvideRuntimeApi<Block, Api: SeraiApi<Block>>,
|
||||||
|
>(
|
||||||
|
client: Arc<C>,
|
||||||
|
) -> RpcModule<impl 'static + Send + Sync> {
|
||||||
|
let mut module = RpcModule::new(client);
|
||||||
|
|
||||||
|
module.register_method(
|
||||||
|
"validator-sets/current_session",
|
||||||
|
|params, client, _ext| -> Result<_, Error> {
|
||||||
|
let block_hash = block_hash(&**client, ¶ms)?;
|
||||||
|
let network = network(¶ms)?;
|
||||||
|
let Ok(session) = client.runtime_api().current_session(block_hash, network) else {
|
||||||
|
Err(Error::Internal("couldn't fetch the session for the requested network"))?
|
||||||
|
};
|
||||||
|
Ok(session.map(|session| session.0))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
module.register_method(
|
||||||
|
"validator-sets/current_stake",
|
||||||
|
|params, client, _ext| -> Result<_, Error> {
|
||||||
|
let block_hash = block_hash(&**client, ¶ms)?;
|
||||||
|
let network = network(¶ms)?;
|
||||||
|
let Ok(stake) = client.runtime_api().current_stake(block_hash, network) else {
|
||||||
|
Err(Error::Internal("couldn't fetch the total allocated stake for the requested network"))?
|
||||||
|
};
|
||||||
|
Ok(stake.map(|stake| stake.0))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
module.register_method("validator-sets/keys", |params, client, _ext| -> Result<_, Error> {
|
||||||
|
let block_hash = block_hash(&**client, ¶ms)?;
|
||||||
|
let set = set(¶ms)?;
|
||||||
|
let Ok(set) = ExternalValidatorSet::try_from(set) else {
|
||||||
|
Err(Error::InvalidRequest("requested keys for a non-external validator set"))?
|
||||||
|
};
|
||||||
|
let Ok(key_pair) = client.runtime_api().keys(block_hash, set) else {
|
||||||
|
Err(Error::Internal("couldn't fetch the keys for the requested validator set"))?
|
||||||
|
};
|
||||||
|
Ok(key_pair.map(|key_pair| hex::encode(borsh::to_vec(&key_pair).unwrap())))
|
||||||
|
});
|
||||||
|
|
||||||
|
module
|
||||||
|
}
|
||||||
@@ -22,6 +22,8 @@ use serai_runtime::RuntimeApi;
|
|||||||
use sc_consensus_babe::{self, SlotProportion};
|
use sc_consensus_babe::{self, SlotProportion};
|
||||||
use sc_consensus_grandpa as grandpa;
|
use sc_consensus_grandpa as grandpa;
|
||||||
|
|
||||||
|
mod proposer;
|
||||||
|
|
||||||
#[cfg(not(feature = "runtime-benchmarks"))]
|
#[cfg(not(feature = "runtime-benchmarks"))]
|
||||||
pub type Executor = WasmExecutor<ExtendedHostFunctions<SubstrateHostFunctions, ()>>;
|
pub type Executor = WasmExecutor<ExtendedHostFunctions<SubstrateHostFunctions, ()>>;
|
||||||
#[cfg(feature = "runtime-benchmarks")]
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
@@ -32,6 +34,8 @@ pub type Executor = WasmExecutor<
|
|||||||
type FullBackend = sc_service::TFullBackend<Block>;
|
type FullBackend = sc_service::TFullBackend<Block>;
|
||||||
pub type FullClient = TFullClient<Block, RuntimeApi, Executor>;
|
pub type FullClient = TFullClient<Block, RuntimeApi, Executor>;
|
||||||
|
|
||||||
|
pub type TransactionPool = sc_transaction_pool::TransactionPoolWrapper<Block, FullClient>;
|
||||||
|
|
||||||
type SelectChain = sc_consensus::LongestChain<FullBackend, Block>;
|
type SelectChain = sc_consensus::LongestChain<FullBackend, Block>;
|
||||||
type GrandpaBlockImport = grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, SelectChain>;
|
type GrandpaBlockImport = grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, SelectChain>;
|
||||||
type BabeBlockImport<CIDP> =
|
type BabeBlockImport<CIDP> =
|
||||||
@@ -42,7 +46,7 @@ type PartialComponents<CIDP> = sc_service::PartialComponents<
|
|||||||
FullBackend,
|
FullBackend,
|
||||||
SelectChain,
|
SelectChain,
|
||||||
sc_consensus::DefaultImportQueue<Block>,
|
sc_consensus::DefaultImportQueue<Block>,
|
||||||
sc_transaction_pool::TransactionPoolWrapper<Block, FullClient>,
|
TransactionPool,
|
||||||
(
|
(
|
||||||
BabeBlockImport<CIDP>,
|
BabeBlockImport<CIDP>,
|
||||||
sc_consensus_babe::BabeLink<Block>,
|
sc_consensus_babe::BabeLink<Block>,
|
||||||
@@ -95,12 +99,19 @@ pub fn new_partial(
|
|||||||
config.executor.runtime_cache_size,
|
config.executor.runtime_cache_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (client, backend, keystore_container, task_manager) =
|
let (client, backend, keystore_container, task_manager) = {
|
||||||
sc_service::new_full_parts::<Block, RuntimeApi, _>(
|
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,
|
config,
|
||||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
telemetry,
|
||||||
executor,
|
executor.clone(),
|
||||||
)?;
|
backend.clone(),
|
||||||
|
super::chain_spec::genesis_block(&*config.chain_spec, backend, executor)?,
|
||||||
|
false,
|
||||||
|
)?
|
||||||
|
};
|
||||||
let client = Arc::new(client);
|
let client = Arc::new(client);
|
||||||
|
|
||||||
let keystore: Arc<dyn sp_keystore::Keystore> =
|
let keystore: Arc<dyn sp_keystore::Keystore> =
|
||||||
@@ -384,13 +395,13 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
|||||||
keystore: keystore.clone(),
|
keystore: keystore.clone(),
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
select_chain,
|
select_chain,
|
||||||
env: sc_basic_authorship::ProposerFactory::new(
|
env: proposer::ProposerFactory(sc_basic_authorship::ProposerFactory::new(
|
||||||
task_manager.spawn_handle(),
|
task_manager.spawn_handle(),
|
||||||
client,
|
client,
|
||||||
transaction_pool.clone(),
|
transaction_pool.clone(),
|
||||||
prometheus_registry.as_ref(),
|
prometheus_registry.as_ref(),
|
||||||
telemetry.as_ref().map(Telemetry::handle),
|
telemetry.as_ref().map(Telemetry::handle),
|
||||||
),
|
)),
|
||||||
block_import,
|
block_import,
|
||||||
sync_oracle: sync_service.clone(),
|
sync_oracle: sync_service.clone(),
|
||||||
justification_sync_link: sync_service.clone(),
|
justification_sync_link: sync_service.clone(),
|
||||||
56
substrate/node/src/service/proposer.rs
Normal file
56
substrate/node/src/service/proposer.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use sp_runtime::Digest;
|
||||||
|
use sp_consensus::{InherentData, DisableProofRecording};
|
||||||
|
|
||||||
|
use serai_abi::{SeraiPreExecutionDigest, SubstrateHeader as Header, SubstrateBlock as Block};
|
||||||
|
|
||||||
|
use super::{FullClient, TransactionPool};
|
||||||
|
|
||||||
|
type UnderlyingProposer =
|
||||||
|
sc_basic_authorship::Proposer<Block, FullClient, TransactionPool, DisableProofRecording>;
|
||||||
|
pub struct Proposer(UnderlyingProposer);
|
||||||
|
impl sp_consensus::Proposer<Block> for Proposer {
|
||||||
|
type Error = <UnderlyingProposer as sp_consensus::Proposer<Block>>::Error;
|
||||||
|
type Proposal = <UnderlyingProposer as sp_consensus::Proposer<Block>>::Proposal;
|
||||||
|
type ProofRecording = DisableProofRecording;
|
||||||
|
type Proof = ();
|
||||||
|
|
||||||
|
fn propose(
|
||||||
|
self,
|
||||||
|
inherent_data: InherentData,
|
||||||
|
mut inherent_digests: Digest,
|
||||||
|
max_duration: Duration,
|
||||||
|
block_size_limit: Option<usize>,
|
||||||
|
) -> Self::Proposal {
|
||||||
|
Box::pin(async move {
|
||||||
|
// Insert our expected digest
|
||||||
|
inherent_digests.logs.push(sp_runtime::generic::DigestItem::PreRuntime(
|
||||||
|
SeraiPreExecutionDigest::CONSENSUS_ID,
|
||||||
|
borsh::to_vec(&SeraiPreExecutionDigest {
|
||||||
|
unix_time_in_millis: inherent_data
|
||||||
|
.get_data::<sp_timestamp::Timestamp>(&sp_timestamp::INHERENT_IDENTIFIER)
|
||||||
|
.map_err(|err| sp_blockchain::Error::Application(err.into()))?
|
||||||
|
.ok_or(sp_blockchain::Error::Application("missing timestamp inherent".into()))?
|
||||||
|
.as_millis(),
|
||||||
|
})
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Call the underlying propose function
|
||||||
|
self.0.propose(inherent_data, inherent_digests, max_duration, block_size_limit).await
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnderlyingFactory =
|
||||||
|
sc_basic_authorship::ProposerFactory<TransactionPool, FullClient, DisableProofRecording>;
|
||||||
|
pub struct ProposerFactory(pub UnderlyingFactory);
|
||||||
|
impl sp_consensus::Environment<Block> for ProposerFactory {
|
||||||
|
type CreateProposer = core::future::Ready<Result<Proposer, Self::Error>>;
|
||||||
|
type Proposer = Proposer;
|
||||||
|
type Error = <UnderlyingFactory as sp_consensus::Environment<Block>>::Error;
|
||||||
|
fn init(&mut self, parent_header: &Header) -> Self::CreateProposer {
|
||||||
|
core::future::ready(self.0.init(parent_header).into_inner().map(Proposer))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ borsh = { version = "1", default-features = false, features = ["derive", "de_str
|
|||||||
|
|
||||||
bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"], optional = true }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"], optional = true }
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["alloc"] }
|
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["alloc"] }
|
||||||
schnorr-signatures = { path = "../../crypto/schnorr", default-features = false }
|
schnorr-signatures = { path = "../../crypto/schnorr", default-features = false }
|
||||||
|
|||||||
@@ -20,31 +20,34 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
sp-version = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-version = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-transaction-pool = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-transaction-pool = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-inherents = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-inherents = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-block-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-block-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-consensus-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-consensus-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-authority-discovery = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-authority-discovery = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||||
|
|
||||||
[target.'cfg(target_family = "wasm")'.dependencies]
|
[target.'cfg(target_family = "wasm")'.dependencies]
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
borsh = { version = "1", default-features = false }
|
||||||
sp-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-executive = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-executive = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
|
||||||
|
pallet-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
serai-core-pallet = { path = "../core", default-features = false }
|
serai-core-pallet = { path = "../core", default-features = false }
|
||||||
serai-coins-pallet = { path = "../coins", default-features = false }
|
serai-coins-pallet = { path = "../coins", default-features = false }
|
||||||
@@ -52,11 +55,12 @@ serai-validator-sets-pallet = { path = "../validator-sets", default-features = f
|
|||||||
serai-signals-pallet = { path = "../signals", default-features = false }
|
serai-signals-pallet = { path = "../signals", default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = [
|
std = [
|
||||||
"scale/std",
|
"scale/std",
|
||||||
|
"borsh/std",
|
||||||
|
|
||||||
"sp-core/std",
|
"sp-core/std",
|
||||||
"sp-session/std",
|
"sp-session/std",
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ extern crate alloc;
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use serai_abi::{
|
use serai_abi::{
|
||||||
primitives::{
|
primitives::{
|
||||||
crypto::{Public, SignedEmbeddedEllipticCurveKeys},
|
crypto::{Public, SignedEmbeddedEllipticCurveKeys, KeyPair},
|
||||||
network_id::NetworkId,
|
network_id::NetworkId,
|
||||||
balance::Balance,
|
validator_sets::{Session, ExternalValidatorSet, ValidatorSet},
|
||||||
|
balance::{Amount, Balance},
|
||||||
},
|
},
|
||||||
Event,
|
Event,
|
||||||
};
|
};
|
||||||
@@ -33,8 +34,11 @@ sp_api::decl_runtime_apis! {
|
|||||||
fn build(genesis: GenesisConfig);
|
fn build(genesis: GenesisConfig);
|
||||||
}
|
}
|
||||||
pub trait SeraiApi {
|
pub trait SeraiApi {
|
||||||
fn events() -> Vec<Vec<u8>>;
|
fn events() -> Vec<Vec<Vec<u8>>>;
|
||||||
fn validators(network_id: NetworkId) -> Vec<Public>;
|
fn validators(network: NetworkId) -> Vec<Public>;
|
||||||
|
fn current_session(network: NetworkId) -> Option<Session>;
|
||||||
|
fn current_stake(network: NetworkId) -> Option<Amount>;
|
||||||
|
fn keys(set: ExternalValidatorSet) -> Option<KeyPair>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +48,8 @@ mod apis {
|
|||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
use serai_abi::{SubstrateHeader as Header, SubstrateBlock as Block};
|
use serai_abi::{SubstrateHeader as Header, SubstrateBlock as Block};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[sp_version::runtime_version]
|
#[sp_version::runtime_version]
|
||||||
pub const VERSION: sp_version::RuntimeVersion = sp_version::RuntimeVersion {
|
pub const VERSION: sp_version::RuntimeVersion = sp_version::RuntimeVersion {
|
||||||
spec_name: Cow::Borrowed("serai"),
|
spec_name: Cow::Borrowed("serai"),
|
||||||
@@ -173,7 +179,7 @@ mod apis {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl crate::SeraiApi<Block> for Runtime {
|
impl crate::SeraiApi<Block> for Runtime {
|
||||||
fn events() -> Vec<Vec<u8>> {
|
fn events() -> Vec<Vec<Vec<u8>>> {
|
||||||
unimplemented!("runtime is only implemented when WASM")
|
unimplemented!("runtime is only implemented when WASM")
|
||||||
}
|
}
|
||||||
fn validators(
|
fn validators(
|
||||||
@@ -181,6 +187,15 @@ mod apis {
|
|||||||
) -> Vec<serai_abi::primitives::crypto::Public> {
|
) -> Vec<serai_abi::primitives::crypto::Public> {
|
||||||
unimplemented!("runtime is only implemented when WASM")
|
unimplemented!("runtime is only implemented when WASM")
|
||||||
}
|
}
|
||||||
|
fn current_session(network: NetworkId) -> Option<Session> {
|
||||||
|
unimplemented!("runtime is only implemented when WASM")
|
||||||
|
}
|
||||||
|
fn current_stake(network: NetworkId) -> Option<Amount> {
|
||||||
|
unimplemented!("runtime is only implemented when WASM")
|
||||||
|
}
|
||||||
|
fn keys(set: ExternalValidatorSet) -> Option<KeyPair> {
|
||||||
|
unimplemented!("runtime is only implemented when WASM")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,23 +2,24 @@ use core::marker::PhantomData;
|
|||||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
use alloc::{borrow::Cow, vec, vec::Vec};
|
||||||
|
|
||||||
use sp_core::{ConstU32, ConstU64, sr25519::Public};
|
use sp_core::{ConstU32, ConstU64, sr25519::Public};
|
||||||
use sp_runtime::{Perbill, Weight};
|
use sp_runtime::{
|
||||||
|
Perbill, Weight,
|
||||||
|
traits::{Header as _, Block as _},
|
||||||
|
};
|
||||||
use sp_version::RuntimeVersion;
|
use sp_version::RuntimeVersion;
|
||||||
|
|
||||||
use serai_abi::{
|
use serai_abi::{
|
||||||
primitives::{
|
primitives::{
|
||||||
network_id::{ExternalNetworkId, NetworkId},
|
network_id::{ExternalNetworkId, NetworkId},
|
||||||
balance::{Amount, ExternalBalance},
|
balance::{Amount, ExternalBalance},
|
||||||
validator_sets::ValidatorSet,
|
validator_sets::{Session, ExternalValidatorSet, ValidatorSet},
|
||||||
address::SeraiAddress,
|
address::SeraiAddress,
|
||||||
},
|
},
|
||||||
SubstrateHeader as Header, SubstrateBlock,
|
SubstrateHeader as Header, SubstrateBlock as Block,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serai_coins_pallet::{CoinsInstance, LiquidityTokensInstance};
|
use serai_coins_pallet::{CoinsInstance, LiquidityTokensInstance};
|
||||||
|
|
||||||
type Block = SubstrateBlock;
|
|
||||||
|
|
||||||
/// The lookup for a SeraiAddress -> Public.
|
/// The lookup for a SeraiAddress -> Public.
|
||||||
pub struct Lookup;
|
pub struct Lookup;
|
||||||
impl sp_runtime::traits::StaticLookup for Lookup {
|
impl sp_runtime::traits::StaticLookup for Lookup {
|
||||||
@@ -91,6 +92,10 @@ mod runtime {
|
|||||||
#[runtime::pallet_index(5)]
|
#[runtime::pallet_index(5)]
|
||||||
pub type LiquidityTokens = serai_coins_pallet::Pallet<Runtime, LiquidityTokensInstance>;
|
pub type LiquidityTokens = serai_coins_pallet::Pallet<Runtime, LiquidityTokensInstance>;
|
||||||
|
|
||||||
|
#[runtime::pallet_index(0xfd)]
|
||||||
|
#[runtime::disable_inherent]
|
||||||
|
pub type Timestamp = pallet_timestamp::Pallet<Runtime>;
|
||||||
|
|
||||||
#[runtime::pallet_index(0xfe)]
|
#[runtime::pallet_index(0xfe)]
|
||||||
pub type Babe = pallet_babe::Pallet<Runtime>;
|
pub type Babe = pallet_babe::Pallet<Runtime>;
|
||||||
|
|
||||||
@@ -166,13 +171,6 @@ impl serai_coins_pallet::Config<LiquidityTokensInstance> for Runtime {
|
|||||||
type AllowMint = serai_coins_pallet::AlwaysAllowMint;
|
type AllowMint = serai_coins_pallet::AlwaysAllowMint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
`pallet-babe` requires we implement `pallet-timestamp` for the associated constants. It does not
|
|
||||||
actually require we offer the timestamp pallet however, and we don't as we follow our methodology
|
|
||||||
(using the block header for timestamps, not an inherent transaction).
|
|
||||||
|
|
||||||
TODO: Set timestamp when executing a block.
|
|
||||||
*/
|
|
||||||
impl pallet_timestamp::Config for Runtime {
|
impl pallet_timestamp::Config for Runtime {
|
||||||
type Moment = u64;
|
type Moment = u64;
|
||||||
type OnTimestampSet = Babe;
|
type OnTimestampSet = Babe;
|
||||||
@@ -181,6 +179,8 @@ impl pallet_timestamp::Config for Runtime {
|
|||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pallet-babe requires `pallet-session` for `GetCurrentSessionForSubstrate` but not it itself
|
||||||
|
// We ensure this by having patched `pallet-session` to omit the pallet
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct GetCurrentSessionForSubstrate;
|
pub struct GetCurrentSessionForSubstrate;
|
||||||
impl pallet_session::GetCurrentSessionForSubstrate for GetCurrentSessionForSubstrate {
|
impl pallet_session::GetCurrentSessionForSubstrate for GetCurrentSessionForSubstrate {
|
||||||
@@ -356,14 +356,7 @@ sp_api::impl_runtime_apis! {
|
|||||||
grandpa: GrandpaConfig { authorities: vec![], _config: PhantomData },
|
grandpa: GrandpaConfig { authorities: vec![], _config: PhantomData },
|
||||||
};
|
};
|
||||||
|
|
||||||
Core::genesis();
|
Core::genesis(&config);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +393,59 @@ sp_api::impl_runtime_apis! {
|
|||||||
block: Block,
|
block: Block,
|
||||||
data: sp_inherents::InherentData,
|
data: sp_inherents::InherentData,
|
||||||
) -> sp_inherents::CheckInherentsResult {
|
) -> sp_inherents::CheckInherentsResult {
|
||||||
data.check_extrinsics(&block)
|
let mut result = data.check_extrinsics(&block);
|
||||||
|
|
||||||
|
// Handle the `SeraiPreExecutionDigest`
|
||||||
|
'outer: {
|
||||||
|
use serai_abi::SeraiPreExecutionDigest;
|
||||||
|
|
||||||
|
const INHERENT_ID: [u8; 8] = [
|
||||||
|
SeraiPreExecutionDigest::CONSENSUS_ID[0],
|
||||||
|
SeraiPreExecutionDigest::CONSENSUS_ID[1],
|
||||||
|
SeraiPreExecutionDigest::CONSENSUS_ID[2],
|
||||||
|
SeraiPreExecutionDigest::CONSENSUS_ID[3],
|
||||||
|
0, 0, 0, 0
|
||||||
|
];
|
||||||
|
|
||||||
|
for log in block.header().digest().logs() {
|
||||||
|
match log {
|
||||||
|
sp_runtime::DigestItem::PreRuntime(consensus, encoded)
|
||||||
|
if *consensus == SeraiPreExecutionDigest::CONSENSUS_ID =>
|
||||||
|
{
|
||||||
|
let Ok(SeraiPreExecutionDigest { unix_time_in_millis }) =
|
||||||
|
<_ as borsh::BorshDeserialize>::deserialize_reader(&mut encoded.as_slice()) else {
|
||||||
|
// We don't handle this error as we can't in this position
|
||||||
|
let _ = result.put_error(
|
||||||
|
INHERENT_ID,
|
||||||
|
&sp_inherents::MakeFatalError::from("invalid `SeraiPreExecutionDigest`"),
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
use frame_support::inherent::ProvideInherent;
|
||||||
|
match pallet_timestamp::Pallet::<Runtime>::check_inherent(
|
||||||
|
&pallet_timestamp::Call::<Runtime>::set { now: unix_time_in_millis },
|
||||||
|
&data
|
||||||
|
) {
|
||||||
|
Ok(()) => {},
|
||||||
|
Err(e) => {
|
||||||
|
let _ = result.put_error(sp_timestamp::INHERENT_IDENTIFIER, &e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = result.put_error(
|
||||||
|
INHERENT_ID,
|
||||||
|
&sp_inherents::MakeFatalError::from("missing `SeraiPreExecutionDigest`")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +550,7 @@ sp_api::impl_runtime_apis! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl crate::SeraiApi<Block> for Runtime {
|
impl crate::SeraiApi<Block> for Runtime {
|
||||||
fn events() -> Vec<Vec<u8>> {
|
fn events() -> Vec<Vec<Vec<u8>>> {
|
||||||
Core::events()
|
Core::events()
|
||||||
}
|
}
|
||||||
fn validators(network: NetworkId) -> Vec<serai_abi::primitives::crypto::Public> {
|
fn validators(network: NetworkId) -> Vec<serai_abi::primitives::crypto::Public> {
|
||||||
@@ -522,6 +567,21 @@ sp_api::impl_runtime_apis! {
|
|||||||
.map(|validator| validator.0.into())
|
.map(|validator| validator.0.into())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
fn current_session(network: NetworkId) -> Option<Session> {
|
||||||
|
ValidatorSets::current_session(network)
|
||||||
|
}
|
||||||
|
fn current_stake(network: NetworkId) -> Option<Amount> {
|
||||||
|
ValidatorSets::stake_for_current_validator_set(network)
|
||||||
|
}
|
||||||
|
fn keys(set: ExternalValidatorSet) -> Option<serai_abi::primitives::crypto::KeyPair> {
|
||||||
|
ValidatorSets::oraclization_key(set)
|
||||||
|
.and_then(|oraclization_key| {
|
||||||
|
ValidatorSets::external_key(set)
|
||||||
|
.map(|external_key| {
|
||||||
|
serai_abi::primitives::crypto::KeyPair(oraclization_key.into(), external_key)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,8 +764,6 @@ mod benches {
|
|||||||
|
|
||||||
[system, SystemBench::<Runtime>]
|
[system, SystemBench::<Runtime>]
|
||||||
|
|
||||||
[pallet_timestamp, Timestamp]
|
|
||||||
|
|
||||||
[balances, Balances]
|
[balances, Balances]
|
||||||
|
|
||||||
[babe, Babe]
|
[babe, Babe]
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||||
|
|
||||||
|
|||||||
@@ -20,17 +20,17 @@ bitvec = { version = "1", default-features = false, features = ["alloc", "serde"
|
|||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "bit-vec"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "bit-vec"] }
|
||||||
|
|
||||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-application-crypto = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
pallet-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||||
|
|
||||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ pub(crate) trait Keys {
|
|||||||
|
|
||||||
/// The oraclization key for a validator set.
|
/// The oraclization key for a validator set.
|
||||||
fn oraclization_key(set: ExternalValidatorSet) -> Option<Public>;
|
fn oraclization_key(set: ExternalValidatorSet) -> Option<Public>;
|
||||||
|
|
||||||
|
/// The external key for a validator set.
|
||||||
|
fn external_key(set: ExternalValidatorSet) -> Option<ExternalKey>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: KeysStorage> Keys for S {
|
impl<S: KeysStorage> Keys for S {
|
||||||
@@ -53,4 +56,8 @@ impl<S: KeysStorage> Keys for S {
|
|||||||
fn oraclization_key(set: ExternalValidatorSet) -> Option<Public> {
|
fn oraclization_key(set: ExternalValidatorSet) -> Option<Public> {
|
||||||
S::OraclizationKeys::get(set)
|
S::OraclizationKeys::get(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn external_key(set: ExternalValidatorSet) -> Option<ExternalKey> {
|
||||||
|
S::ExternalKeys::get(set)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,6 +307,14 @@ mod pallet {
|
|||||||
Abstractions::<T>::selected_validators(set)
|
Abstractions::<T>::selected_validators(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn oraclization_key(set: ExternalValidatorSet) -> Option<Public> {
|
||||||
|
Abstractions::<T>::oraclization_key(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn external_key(set: ExternalValidatorSet) -> Option<ExternalKey> {
|
||||||
|
Abstractions::<T>::external_key(set)
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
pub fn distribute_block_rewards(
|
pub fn distribute_block_rewards(
|
||||||
network: NetworkId,
|
network: NetworkId,
|
||||||
|
|||||||
Reference in New Issue
Block a user