mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-07 19:59:23 +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"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>", "Vrx <vrx00@proton.me>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.85"
|
||||
rust-version = "1.89"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -155,6 +155,7 @@ impl Rpc {
|
||||
Err(RpcError::RequestError(Error { code, message }))
|
||||
}
|
||||
// `invalidateblock` yields this edge case
|
||||
// TODO: https://github.com/core-json/core-json/issues/18
|
||||
RpcResponse { result: None, error: None } => {
|
||||
if core::any::TypeId::of::<Response>() == core::any::TypeId::of::<()>() {
|
||||
Ok(Default::default())
|
||||
|
||||
@@ -22,12 +22,12 @@ workspace = true
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
||||
|
||||
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 }
|
||||
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 }
|
||||
frame-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false, 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false, optional = true }
|
||||
|
||||
serai-primitives = { path = "../primitives", version = "0.1", default-features = false }
|
||||
|
||||
|
||||
@@ -7,15 +7,26 @@ use crate::{
|
||||
Transaction,
|
||||
};
|
||||
|
||||
/// The tag for a block's header, forming a leaf of the Merkle tree which is `builds_upon`.
|
||||
pub const BLOCK_HEADER_LEAF_TAG: u8 = 0;
|
||||
/// The tag for branch hashes in `builds_upon`.
|
||||
pub const BLOCK_HEADER_BRANCH_TAG: u8 = 1;
|
||||
|
||||
/// The tag for a transaction, forming a leaf of the Merkle tree which is the transactions'
|
||||
/// commitment.
|
||||
pub const TRANSACTION_COMMITMENT_LEAF_TAG: u8 = 2;
|
||||
/// The tag for branch hashes in the transactions' commitment.
|
||||
pub const TRANSACTION_COMMITMENT_BRANCH_TAG: u8 = 3;
|
||||
|
||||
/// The tag for the hash of a transaction's event, forming a leaf of the Merkle tree of its events.
|
||||
pub const TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG: u8 = 0;
|
||||
/// The tag for the branch hashes of transaction events.
|
||||
pub const TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG: u8 = 1;
|
||||
pub const TRANSACTION_EVENTS_COMMITMENT_LEAF_TAG: u8 = 4;
|
||||
/// The tag for the branch hashes of the Merkle tree for a transaction's events.
|
||||
pub const TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG: u8 = 5;
|
||||
/// The tag for the hash of a transaction's hash and its events' Merkle root, forming a leaf of the
|
||||
/// Merkle tree which is the events commitment.
|
||||
pub const EVENTS_COMMITMENT_LEAF_TAG: u8 = 2;
|
||||
/// The tag for for the branch hashes of the Merkle tree which is the events commitments.
|
||||
pub const EVENTS_COMMITMENT_BRANCH_TAG: u8 = 3;
|
||||
/// Merkle tree which is the events' commitment.
|
||||
pub const EVENTS_COMMITMENT_LEAF_TAG: u8 = 6;
|
||||
/// The tag for branch hashes in the events' commitment.
|
||||
pub const EVENTS_COMMITMENT_BRANCH_TAG: u8 = 7;
|
||||
|
||||
/// A V1 header for a block.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
@@ -38,7 +49,8 @@ pub struct HeaderV1 {
|
||||
pub builds_upon: UnbalancedMerkleTree,
|
||||
/// The UNIX time in milliseconds this block was created at.
|
||||
pub unix_time_in_millis: u64,
|
||||
/// The commitment to the transactions within this block.
|
||||
/// The commitment to the transactions within this block, including the inherent start/end of
|
||||
/// block transactions.
|
||||
pub transactions_commitment: UnbalancedMerkleTree,
|
||||
/// The commitment to the events within this block.
|
||||
///
|
||||
@@ -147,6 +159,29 @@ mod substrate {
|
||||
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
|
||||
/// block.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
@@ -159,11 +194,6 @@ mod substrate {
|
||||
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 {
|
||||
/// The consensus ID for a Serai execution digest.
|
||||
pub const CONSENSUS_ID: [u8; 4] = *b"SRIE";
|
||||
@@ -241,7 +271,7 @@ mod substrate {
|
||||
for log in header.consensus.digest.logs() {
|
||||
match log {
|
||||
DigestItem::PreRuntime(consensus, encoded)
|
||||
if *consensus == SeraiExecutionDigest::CONSENSUS_ID =>
|
||||
if *consensus == SeraiPreExecutionDigest::CONSENSUS_ID =>
|
||||
{
|
||||
pre_execution_digest =
|
||||
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" }
|
||||
|
||||
multiaddr = { version = "0.18", optional = true }
|
||||
sp-core = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", optional = true }
|
||||
frame-system = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", optional = true }
|
||||
frame-system = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", optional = true }
|
||||
|
||||
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>"]
|
||||
keywords = ["serai"]
|
||||
edition = "2021"
|
||||
rust-version = "1.85"
|
||||
rust-version = "1.89"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
@@ -29,6 +29,8 @@ serai-abi = { path = "../../abi", version = "0.1" }
|
||||
async-lock = "3"
|
||||
|
||||
[dev-dependencies]
|
||||
blake2 = { version = "0.11.0-rc.3", default-features = false }
|
||||
|
||||
tokio = { version = "1", default-features = false, features = ["rt", "macros"] }
|
||||
dockertest = "0.5"
|
||||
serai-docker-tests = { path = "../../../tests/docker" }
|
||||
|
||||
@@ -59,7 +59,7 @@ pub struct Serai {
|
||||
pub struct TemporalSerai<'a> {
|
||||
serai: &'a Serai,
|
||||
block: BlockHash,
|
||||
events: Arc<RwLock<Option<Vec<Event>>>>,
|
||||
events: Arc<RwLock<Option<Vec<Vec<Event>>>>>,
|
||||
}
|
||||
|
||||
impl Serai {
|
||||
@@ -109,10 +109,10 @@ impl Serai {
|
||||
Response { result: None, error: Some(error) } => {
|
||||
Err(RpcError::ErrorInResponse(error.message))
|
||||
}
|
||||
Response { result: Some(_), error: Some(_) } | Response { result: None, error: None } => {
|
||||
Err(RpcError::InvalidNode(
|
||||
"node didn't exclusively provide either `result` or `error`".to_string(),
|
||||
))
|
||||
// TODO: https://github.com/core-json/core-json/issues/18
|
||||
Response { result: None, error: None } => Ok(Default::default()),
|
||||
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.
|
||||
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.
|
||||
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(
|
||||
@@ -147,12 +147,13 @@ impl Serai {
|
||||
|
||||
/// Fetch a block from the Serai blockchain.
|
||||
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.
|
||||
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.
|
||||
@@ -183,10 +184,20 @@ impl Serai {
|
||||
}
|
||||
|
||||
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.
|
||||
///
|
||||
/// 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;
|
||||
if events.is_none() {
|
||||
drop(events);
|
||||
@@ -195,21 +206,25 @@ impl<'a> TemporalSerai<'a> {
|
||||
if events_mut.is_none() {
|
||||
*events_mut = Some(
|
||||
self
|
||||
.serai
|
||||
.call::<Vec<String>>("serai_events", &format!(r#"["{}"]"#, self.block))
|
||||
.call::<Vec<Vec<String>>>("blockchain/events", "")
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|event| {
|
||||
Event::deserialize(
|
||||
&mut hex::decode(&event)
|
||||
.map_err(|_| {
|
||||
RpcError::InvalidNode("node returned non-hex-encoded event".to_string())
|
||||
})?
|
||||
.as_slice(),
|
||||
)
|
||||
.map_err(|_| RpcError::InvalidNode("node returned invalid event".to_string()))
|
||||
.map(|events_per_tx| {
|
||||
events_per_tx
|
||||
.into_iter()
|
||||
.map(|event| {
|
||||
Event::deserialize(
|
||||
&mut hex::decode(&event)
|
||||
.map_err(|_| {
|
||||
RpcError::InvalidNode("node returned non-hex-encoded 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)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn validator_sets(&self) -> ValidatorSets<'_> {
|
||||
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};
|
||||
|
||||
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.
|
||||
#[derive(Clone)]
|
||||
pub struct ValidatorSets<'a>(pub(super) &'a TemporalSerai<'a>);
|
||||
@@ -11,11 +32,12 @@ impl<'a> ValidatorSets<'a> {
|
||||
Ok(
|
||||
self
|
||||
.0
|
||||
.events()
|
||||
.events_borrowed()
|
||||
.await?
|
||||
.as_ref()
|
||||
.expect("`TemporalSerai::events` returned None")
|
||||
.iter()
|
||||
.flat_map(IntoIterator::into_iter)
|
||||
.filter_map(|event| match event {
|
||||
serai_abi::Event::ValidatorSets(event) => Some(event.clone()),
|
||||
_ => 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.
|
||||
pub async fn accepted_handover_events(&self) -> Result<Vec<Event>, RpcError> {
|
||||
Ok(
|
||||
@@ -47,4 +81,65 @@ impl<'a> ValidatorSets<'a> {
|
||||
.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::*;
|
||||
|
||||
#[tokio::test]
|
||||
@@ -91,6 +102,99 @@ async fn blockchain() {
|
||||
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");
|
||||
})
|
||||
.await;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use serai_abi::{
|
||||
primitives::{
|
||||
network_id::{ExternalNetworkId, NetworkId},
|
||||
validator_sets::{Session, ValidatorSet},
|
||||
balance::Amount,
|
||||
validator_sets::{Session, ExternalValidatorSet, ValidatorSet},
|
||||
},
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ workspace = true
|
||||
[dependencies]
|
||||
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-support = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["substrate"] }
|
||||
serai-core-pallet = { path = "../core", default-features = false }
|
||||
@@ -29,7 +29,9 @@ serai-core-pallet = { path = "../core", default-features = false }
|
||||
[dev-dependencies]
|
||||
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]
|
||||
std = [
|
||||
|
||||
@@ -10,6 +10,7 @@ construct_runtime!(
|
||||
pub enum Test
|
||||
{
|
||||
System: frame_system,
|
||||
Timestamp: pallet_timestamp,
|
||||
Core: serai_core_pallet,
|
||||
Coins: coins::<CoinsInstance>,
|
||||
}
|
||||
@@ -22,6 +23,9 @@ impl frame_system::Config for 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 crate::Config<CoinsInstance> for Test {
|
||||
|
||||
@@ -29,6 +29,7 @@ fn mint() {
|
||||
// test events
|
||||
let mint_events = Core::events()
|
||||
.iter()
|
||||
.flat_map(IntoIterator::into_iter)
|
||||
.map(|event| borsh::from_slice::<serai_abi::Event>(event.as_slice()).unwrap())
|
||||
.filter_map(|event| {
|
||||
if let serai_abi::Event::Coins(e) = &event {
|
||||
@@ -83,6 +84,7 @@ fn burn_with_instruction() {
|
||||
|
||||
let burn_events = Core::events()
|
||||
.iter()
|
||||
.flat_map(IntoIterator::into_iter)
|
||||
.map(|event| borsh::from_slice::<serai_abi::Event>(event.as_slice()).unwrap())
|
||||
.filter_map(|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"] }
|
||||
|
||||
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-support = { 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 = "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"] }
|
||||
|
||||
@@ -37,14 +39,17 @@ std = [
|
||||
"frame-system/std",
|
||||
"frame-support/std",
|
||||
|
||||
"pallet-timestamp/std",
|
||||
|
||||
"serai-abi/std",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
"frame-system/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"]
|
||||
|
||||
@@ -8,8 +8,8 @@ use serai_abi::primitives::merkle::{UnbalancedMerkleTree, IncrementalUnbalancedM
|
||||
/// `IncrementalUnbalancedMerkleTree`.
|
||||
pub struct IncrementalUnbalancedMerkleTree<
|
||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||
const BRANCH_TAG: u8 = 1,
|
||||
const LEAF_TAG: u8 = 0,
|
||||
const BRANCH_TAG: u8,
|
||||
const LEAF_TAG: u8,
|
||||
>(PhantomData<T>);
|
||||
impl<
|
||||
T: frame_support::StorageValue<Iumt, Query = Option<Iumt>>,
|
||||
|
||||
@@ -4,18 +4,22 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use frame_support::traits::{PreInherents, PostTransactions};
|
||||
|
||||
mod iumt;
|
||||
pub use iumt::*;
|
||||
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
#[frame_support::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};
|
||||
|
||||
@@ -28,14 +32,21 @@ pub mod pallet {
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlocksCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlocksCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<BlocksCommitment<T>>;
|
||||
pub(super) type BlocksCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||
BlocksCommitment<T>,
|
||||
{ serai_abi::BLOCK_HEADER_BRANCH_TAG },
|
||||
{ serai_abi::BLOCK_HEADER_LEAF_TAG },
|
||||
>;
|
||||
|
||||
/// The Merkle tree of all transactions within the current block.
|
||||
#[pallet::storage]
|
||||
#[pallet::unbounded]
|
||||
pub(super) type BlockTransactionsCommitment<T: Config> = StorageValue<_, Iumt, OptionQuery>;
|
||||
pub(super) type BlockTransactionsCommitmentMerkle<T> =
|
||||
IncrementalUnbalancedMerkleTree<BlockTransactionsCommitment<T>>;
|
||||
pub(super) type BlockTransactionsCommitmentMerkle<T> = IncrementalUnbalancedMerkleTree<
|
||||
BlockTransactionsCommitment<T>,
|
||||
{ serai_abi::TRANSACTION_COMMITMENT_BRANCH_TAG },
|
||||
{ serai_abi::TRANSACTION_COMMITMENT_LEAF_TAG },
|
||||
>;
|
||||
|
||||
/// The hashes of events caused by the current transaction.
|
||||
#[pallet::storage]
|
||||
@@ -64,12 +75,17 @@ pub mod pallet {
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// A transaction begun.
|
||||
BeginTransaction,
|
||||
/// An event from Serai.
|
||||
Event(Vec<u8>),
|
||||
}
|
||||
|
||||
#[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]
|
||||
pub struct Pallet<T>(_);
|
||||
@@ -99,10 +115,16 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
/// The code to run on genesis.
|
||||
pub fn genesis() {
|
||||
pub fn genesis(config: &impl frame_support::traits::BuildGenesisConfig) {
|
||||
BlocksCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockTransactionsCommitmentMerkle::<T>::new_expecting_none();
|
||||
BlockEventsCommitmentMerkle::<T>::new_expecting_none();
|
||||
|
||||
Self::start_transaction();
|
||||
<_>::build(config);
|
||||
Self::end_transaction([0; 32]);
|
||||
|
||||
EndOfBlock::<T>::post_transactions();
|
||||
}
|
||||
|
||||
/// The code to run when beginning execution of a transaction.
|
||||
@@ -110,6 +132,7 @@ pub mod pallet {
|
||||
/// The caller MUST ensure two transactions aren't simultaneously started.
|
||||
pub fn start_transaction() {
|
||||
TransactionEventsMerkle::<T>::new_expecting_none();
|
||||
Self::deposit_event(Event::BeginTransaction);
|
||||
}
|
||||
|
||||
/// Emit an event.
|
||||
@@ -130,19 +153,24 @@ pub mod pallet {
|
||||
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.
|
||||
pub fn events() -> Vec<Vec<u8>>
|
||||
pub fn events() -> Vec<Vec<Vec<u8>>>
|
||||
where
|
||||
T::RuntimeEvent: TryInto<Event<T>>,
|
||||
{
|
||||
frame_system::Pallet::<T>::read_events_no_consensus()
|
||||
.filter_map(|e| match e.event.try_into() {
|
||||
Ok(Event::Event(bytes)) => Some(bytes),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
let mut result = vec![];
|
||||
for event in frame_system::Pallet::<T>::read_events_no_consensus() {
|
||||
match event.event.try_into() {
|
||||
Ok(Event::BeginTransaction) => result.push(vec![]),
|
||||
Ok(Event::Event(bytes)) => {
|
||||
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.
|
||||
pub struct StartOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
|
||||
impl<T: Config> PreInherents for StartOfBlock<T> {
|
||||
fn pre_inherents() {
|
||||
use frame_support::pallet_prelude::Zero;
|
||||
// `Pallet::genesis` is expected to be used for the genesis block
|
||||
@@ -163,13 +191,44 @@ impl<T: Config> frame_support::traits::PreInherents for StartOfBlock<T> {
|
||||
|
||||
BlockTransactionsCommitmentMerkle::<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.
|
||||
pub struct EndOfBlock<T: Config>(PhantomData<T>);
|
||||
impl<T: Config> frame_support::traits::PostTransactions for EndOfBlock<T> {
|
||||
impl<T: Config> PostTransactions for EndOfBlock<T> {
|
||||
fn post_transactions() {
|
||||
Pallet::<T>::start_transaction();
|
||||
|
||||
// Other modules' `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;
|
||||
frame_system::Pallet::<T>::deposit_log(
|
||||
frame_support::sp_runtime::generic::DigestItem::Consensus(
|
||||
|
||||
@@ -21,15 +21,15 @@ workspace = true
|
||||
[dependencies]
|
||||
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-io = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-runtime = { 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 = "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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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-support = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false, optional = true }
|
||||
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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
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 }
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ workspace = true
|
||||
[dependencies]
|
||||
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-support = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 }
|
||||
@@ -30,16 +30,16 @@ coins-pallet = { package = "serai-coins-pallet", path = "../coins", default-feat
|
||||
serai-primitives = { path = "../primitives", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
pallet-babe = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
pallet-timestamp = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 }
|
||||
|
||||
sp-io = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-core = { 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 = "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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
|
||||
@@ -21,11 +21,11 @@ workspace = true
|
||||
[dependencies]
|
||||
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-support = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
|
||||
sp-std = { 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 = "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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 }
|
||||
|
||||
@@ -21,12 +21,12 @@ workspace = true
|
||||
[dependencies]
|
||||
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-support = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
|
||||
sp-std = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-application-crypto = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 }
|
||||
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"] }
|
||||
|
||||
sp-std = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-io = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-core = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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-support = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 }
|
||||
|
||||
[dev-dependencies]
|
||||
pallet-babe = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
pallet-timestamp = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 }
|
||||
|
||||
|
||||
@@ -34,20 +34,20 @@ secq256k1 = { path = "../../crypto/secq256k1" }
|
||||
|
||||
libp2p = "0.56"
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-inherents = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-timestamp = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-blockchain = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-consensus = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-state-machine = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-keystore = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-io = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-block-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sp-consensus-babe = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
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 = "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-runtime = { path = "../runtime", features = ["std"] }
|
||||
@@ -59,23 +59,24 @@ futures-util = "0.3"
|
||||
tokio = { version = "1", features = ["sync", "rt-multi-thread"] }
|
||||
jsonrpsee = { version = "0.24", features = ["server"] }
|
||||
|
||||
sc-transaction-pool = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-transaction-pool-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-basic-authorship = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-executor = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-service = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-client-api = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-network = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
sc-basic-authorship = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
sc-client-db = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
sc-executor = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
sc-service = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
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-slots = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-consensus-babe = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-consensus-grandpa = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-authority-discovery = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
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-chain-spec = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "71fa60b900c8ad068f1b9ce8100508506377fbf5" }
|
||||
sc-cli = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
sc-cli = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84" }
|
||||
|
||||
serai-env = { path = "../../common/env" }
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
use core::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use sp_core::Pair as PairTrait;
|
||||
|
||||
use sp_core::{Decode, storage::Storage, Pair as PairTrait};
|
||||
use sp_runtime::{
|
||||
traits::{Block as _, Header as _},
|
||||
BuildStorage,
|
||||
};
|
||||
use sc_client_db::Backend;
|
||||
use sc_executor::RuntimeVersionOf;
|
||||
use sc_chain_spec::{BuildGenesisBlock, GenesisBlockBuilder, ChainSpec as ChainSpecTrait};
|
||||
use sc_client_api::BlockImportOperation;
|
||||
use sc_service::ChainType;
|
||||
|
||||
use rand_core::OsRng;
|
||||
@@ -201,3 +209,45 @@ pub fn bootnode_multiaddrs(id: &str) -> Vec<libp2p::Multiaddr> {
|
||||
_ => panic!("unrecognized network ID"),
|
||||
}
|
||||
}
|
||||
|
||||
struct GenesisBlock<Executor>(
|
||||
GenesisBlockBuilder<Block, Backend<Block>, Executor>,
|
||||
sp_runtime::Digest,
|
||||
);
|
||||
impl<Executor: RuntimeVersionOf> BuildGenesisBlock<Block> for GenesisBlock<Executor> {
|
||||
type BlockImportOperation = sc_client_db::BlockImportOperation<Block>;
|
||||
|
||||
fn build_genesis_block(self) -> sp_blockchain::Result<(Block, Self::BlockImportOperation)> {
|
||||
let (genesis_block, op) = self.0.build_genesis_block()?;
|
||||
|
||||
let mut header = genesis_block.header().clone();
|
||||
*header.digest_mut() = self.1;
|
||||
let genesis_block = Block::new(header, genesis_block.extrinsics().to_vec());
|
||||
|
||||
Ok((genesis_block, op))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn genesis_block(
|
||||
chain_spec: &dyn ChainSpecTrait,
|
||||
backend: Arc<Backend<Block>>,
|
||||
executor: impl RuntimeVersionOf,
|
||||
) -> Result<
|
||||
impl BuildGenesisBlock<Block, BlockImportOperation = sc_client_db::BlockImportOperation<Block>>,
|
||||
sc_service::error::Error,
|
||||
> {
|
||||
let storage = chain_spec.as_storage_builder().build_storage()?;
|
||||
let digest = {
|
||||
let digest_key = [sp_core::twox_128(b"System"), sp_core::twox_128(b"Digest")].concat();
|
||||
sp_runtime::Digest::decode(
|
||||
&mut storage.top.get(&digest_key).expect("System Digest not set").as_slice(),
|
||||
)
|
||||
.expect("failed to decode System Digest")
|
||||
};
|
||||
|
||||
let commit_genesis_state = true;
|
||||
Ok(GenesisBlock(
|
||||
GenesisBlockBuilder::new_with_storage(storage, commit_genesis_state, backend, executor)?,
|
||||
digest,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -15,46 +15,7 @@ use serai_runtime::SeraiApi;
|
||||
|
||||
use jsonrpsee::RpcModule;
|
||||
|
||||
fn 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
|
||||
})
|
||||
}
|
||||
use super::utils::{Error, block_hash};
|
||||
|
||||
pub(crate) fn module<
|
||||
C: 'static
|
||||
@@ -69,56 +30,48 @@ pub(crate) fn module<
|
||||
) -> Result<RpcModule<impl 'static + Send + Sync>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
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
|
||||
});
|
||||
|
||||
module.register_method("serai_isFinalized", |params, client, _ext| {
|
||||
let block_hash = block_hash(&**client, ¶ms)?;
|
||||
let finalized = client.info().finalized_number;
|
||||
let Ok(Some(number)) = client.number(block_hash) else {
|
||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-2,
|
||||
"failed to fetch block's number",
|
||||
Option::<()>::None,
|
||||
));
|
||||
};
|
||||
let Ok(status) = client.block_status(block_hash) else {
|
||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-3,
|
||||
"failed to fetch block's status",
|
||||
Option::<()>::None,
|
||||
));
|
||||
};
|
||||
Ok(
|
||||
matches!(status, BlockStatus::InChainWithState | BlockStatus::InChainPruned) &&
|
||||
(number <= finalized),
|
||||
)
|
||||
})?;
|
||||
module.register_method(
|
||||
"blockchain/is_finalized",
|
||||
|params, client, _ext| -> Result<_, Error> {
|
||||
let block_hash = block_hash(&**client, ¶ms)?;
|
||||
let finalized = client.info().finalized_number;
|
||||
let Ok(Some(number)) = client.number(block_hash) else {
|
||||
Err(Error::Missing("failed to fetch block's number"))?
|
||||
};
|
||||
let Ok(status) = client.block_status(block_hash) else {
|
||||
Err(Error::Internal("failed to fetch block's status"))?
|
||||
};
|
||||
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 Ok(Some(block)) = client.block(block_hash) else {
|
||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-2,
|
||||
"couldn't find requested block",
|
||||
Option::<()>::None,
|
||||
));
|
||||
Err(Error::Missing("couldn't find requested block"))?
|
||||
};
|
||||
|
||||
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 Ok(events) = client.runtime_api().events(block_hash) else {
|
||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-2,
|
||||
"couldn't fetch the events for the requested block",
|
||||
Option::<()>::None,
|
||||
));
|
||||
Err(Error::Missing("couldn't fetch the events for the requested block"))?
|
||||
};
|
||||
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)
|
||||
|
||||
@@ -16,7 +16,9 @@ use jsonrpsee::RpcModule;
|
||||
use sc_client_api::BlockBackend;
|
||||
use sc_transaction_pool_api::TransactionPool;
|
||||
|
||||
mod utils;
|
||||
mod blockchain;
|
||||
mod validator_sets;
|
||||
mod p2p_validators;
|
||||
|
||||
pub struct FullDeps<C, P> {
|
||||
@@ -42,6 +44,7 @@ pub fn create_full<
|
||||
|
||||
let mut root = RpcModule::new(());
|
||||
root.merge(blockchain::module(client.clone())?)?;
|
||||
root.merge(validator_sets::module(client.clone()))?;
|
||||
if let Some(authority_discovery) = authority_discovery {
|
||||
root.merge(p2p_validators::module(id, client, authority_discovery)?)?;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ use tokio::sync::RwLock;
|
||||
|
||||
use jsonrpsee::RpcModule;
|
||||
|
||||
use super::utils::Error;
|
||||
|
||||
pub(crate) fn module<
|
||||
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>> {
|
||||
let mut module = RpcModule::new((id, client, RwLock::new(authority_discovery)));
|
||||
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() {
|
||||
"serai" => NetworkId::Serai,
|
||||
"bitcoin" => ExternalNetworkId::Bitcoin.into(),
|
||||
"ethereum" => ExternalNetworkId::Ethereum.into(),
|
||||
"monero" => ExternalNetworkId::Monero.into(),
|
||||
_ => Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-1,
|
||||
"network to fetch the `p2p_validators` of was unrecognized".to_string(),
|
||||
Option::<()>::None,
|
||||
))?,
|
||||
_ => Err(Error::InvalidRequest("network to fetch the `p2p_validators` of was unrecognized"))?,
|
||||
};
|
||||
let (id, client, authority_discovery) = &*context;
|
||||
let latest_block = client.info().best_hash;
|
||||
|
||||
let validators = client.runtime_api().validators(latest_block, network).map_err(|_| {
|
||||
jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-2,
|
||||
format!(
|
||||
"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 = client
|
||||
.runtime_api()
|
||||
.validators(latest_block, network)
|
||||
.map_err(|_| Error::Internal("couldn't get validators from the latest block"));
|
||||
let validators = match validators {
|
||||
Ok(validators) => validators,
|
||||
Err(e) => return Err(e),
|
||||
Err(e) => Err(e)?,
|
||||
};
|
||||
// Always return the protocol's bootnodes
|
||||
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_grandpa as grandpa;
|
||||
|
||||
mod proposer;
|
||||
|
||||
#[cfg(not(feature = "runtime-benchmarks"))]
|
||||
pub type Executor = WasmExecutor<ExtendedHostFunctions<SubstrateHostFunctions, ()>>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
@@ -32,6 +34,8 @@ pub type Executor = WasmExecutor<
|
||||
type FullBackend = sc_service::TFullBackend<Block>;
|
||||
pub type FullClient = TFullClient<Block, RuntimeApi, Executor>;
|
||||
|
||||
pub type TransactionPool = sc_transaction_pool::TransactionPoolWrapper<Block, FullClient>;
|
||||
|
||||
type SelectChain = sc_consensus::LongestChain<FullBackend, Block>;
|
||||
type GrandpaBlockImport = grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, SelectChain>;
|
||||
type BabeBlockImport<CIDP> =
|
||||
@@ -42,7 +46,7 @@ type PartialComponents<CIDP> = sc_service::PartialComponents<
|
||||
FullBackend,
|
||||
SelectChain,
|
||||
sc_consensus::DefaultImportQueue<Block>,
|
||||
sc_transaction_pool::TransactionPoolWrapper<Block, FullClient>,
|
||||
TransactionPool,
|
||||
(
|
||||
BabeBlockImport<CIDP>,
|
||||
sc_consensus_babe::BabeLink<Block>,
|
||||
@@ -95,12 +99,19 @@ pub fn new_partial(
|
||||
config.executor.runtime_cache_size,
|
||||
);
|
||||
|
||||
let (client, backend, keystore_container, task_manager) =
|
||||
sc_service::new_full_parts::<Block, RuntimeApi, _>(
|
||||
let (client, backend, keystore_container, task_manager) = {
|
||||
let telemetry = telemetry.as_ref().map(|(_, telemetry)| telemetry.handle());
|
||||
let backend = sc_service::new_db_backend(config.db_config())?;
|
||||
|
||||
sc_service::new_full_parts_with_genesis_builder::<Block, RuntimeApi, _, _>(
|
||||
config,
|
||||
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
|
||||
executor,
|
||||
)?;
|
||||
telemetry,
|
||||
executor.clone(),
|
||||
backend.clone(),
|
||||
super::chain_spec::genesis_block(&*config.chain_spec, backend, executor)?,
|
||||
false,
|
||||
)?
|
||||
};
|
||||
let client = Arc::new(client);
|
||||
|
||||
let keystore: Arc<dyn sp_keystore::Keystore> =
|
||||
@@ -384,13 +395,13 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
||||
keystore: keystore.clone(),
|
||||
client: client.clone(),
|
||||
select_chain,
|
||||
env: sc_basic_authorship::ProposerFactory::new(
|
||||
env: proposer::ProposerFactory(sc_basic_authorship::ProposerFactory::new(
|
||||
task_manager.spawn_handle(),
|
||||
client,
|
||||
transaction_pool.clone(),
|
||||
prometheus_registry.as_ref(),
|
||||
telemetry.as_ref().map(Telemetry::handle),
|
||||
),
|
||||
)),
|
||||
block_import,
|
||||
sync_oracle: 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"] }
|
||||
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"] }
|
||||
schnorr-signatures = { path = "../../crypto/schnorr", default-features = false }
|
||||
|
||||
@@ -20,31 +20,34 @@ workspace = true
|
||||
[dependencies]
|
||||
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-runtime = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
|
||||
sp-api = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-inherents = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-consensus-babe = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-authority-discovery = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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"] }
|
||||
|
||||
[target.'cfg(target_family = "wasm")'.dependencies]
|
||||
sp-core = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
borsh = { version = "1", default-features = false }
|
||||
|
||||
frame-system = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
frame-executive = { 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-session = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 }
|
||||
pallet-session = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
pallet-grandpa = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
frame-executive = { 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 }
|
||||
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-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 }
|
||||
|
||||
[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]
|
||||
std = [
|
||||
"scale/std",
|
||||
"borsh/std",
|
||||
|
||||
"sp-core/std",
|
||||
"sp-session/std",
|
||||
|
||||
@@ -6,9 +6,10 @@ extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
use serai_abi::{
|
||||
primitives::{
|
||||
crypto::{Public, SignedEmbeddedEllipticCurveKeys},
|
||||
crypto::{Public, SignedEmbeddedEllipticCurveKeys, KeyPair},
|
||||
network_id::NetworkId,
|
||||
balance::Balance,
|
||||
validator_sets::{Session, ExternalValidatorSet, ValidatorSet},
|
||||
balance::{Amount, Balance},
|
||||
},
|
||||
Event,
|
||||
};
|
||||
@@ -33,8 +34,11 @@ sp_api::decl_runtime_apis! {
|
||||
fn build(genesis: GenesisConfig);
|
||||
}
|
||||
pub trait SeraiApi {
|
||||
fn events() -> Vec<Vec<u8>>;
|
||||
fn validators(network_id: NetworkId) -> Vec<Public>;
|
||||
fn events() -> Vec<Vec<Vec<u8>>>;
|
||||
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 serai_abi::{SubstrateHeader as Header, SubstrateBlock as Block};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[sp_version::runtime_version]
|
||||
pub const VERSION: sp_version::RuntimeVersion = sp_version::RuntimeVersion {
|
||||
spec_name: Cow::Borrowed("serai"),
|
||||
@@ -173,7 +179,7 @@ mod apis {
|
||||
}
|
||||
|
||||
impl crate::SeraiApi<Block> for Runtime {
|
||||
fn events() -> Vec<Vec<u8>> {
|
||||
fn events() -> Vec<Vec<Vec<u8>>> {
|
||||
unimplemented!("runtime is only implemented when WASM")
|
||||
}
|
||||
fn validators(
|
||||
@@ -181,6 +187,15 @@ mod apis {
|
||||
) -> Vec<serai_abi::primitives::crypto::Public> {
|
||||
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 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 serai_abi::{
|
||||
primitives::{
|
||||
network_id::{ExternalNetworkId, NetworkId},
|
||||
balance::{Amount, ExternalBalance},
|
||||
validator_sets::ValidatorSet,
|
||||
validator_sets::{Session, ExternalValidatorSet, ValidatorSet},
|
||||
address::SeraiAddress,
|
||||
},
|
||||
SubstrateHeader as Header, SubstrateBlock,
|
||||
SubstrateHeader as Header, SubstrateBlock as Block,
|
||||
};
|
||||
|
||||
use serai_coins_pallet::{CoinsInstance, LiquidityTokensInstance};
|
||||
|
||||
type Block = SubstrateBlock;
|
||||
|
||||
/// The lookup for a SeraiAddress -> Public.
|
||||
pub struct Lookup;
|
||||
impl sp_runtime::traits::StaticLookup for Lookup {
|
||||
@@ -91,6 +92,10 @@ mod runtime {
|
||||
#[runtime::pallet_index(5)]
|
||||
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)]
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
`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 {
|
||||
type Moment = u64;
|
||||
type OnTimestampSet = Babe;
|
||||
@@ -181,6 +179,8 @@ impl pallet_timestamp::Config for Runtime {
|
||||
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)]
|
||||
pub struct GetCurrentSessionForSubstrate;
|
||||
impl pallet_session::GetCurrentSessionForSubstrate for GetCurrentSessionForSubstrate {
|
||||
@@ -356,14 +356,7 @@ sp_api::impl_runtime_apis! {
|
||||
grandpa: GrandpaConfig { authorities: vec![], _config: PhantomData },
|
||||
};
|
||||
|
||||
Core::genesis();
|
||||
Core::start_transaction();
|
||||
<RuntimeGenesisConfig as frame_support::traits::BuildGenesisConfig>::build(&config);
|
||||
Core::end_transaction([0; 32]);
|
||||
|
||||
<
|
||||
serai_core_pallet::EndOfBlock<Runtime> as frame_support::traits::PostTransactions
|
||||
>::post_transactions();
|
||||
Core::genesis(&config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +393,59 @@ sp_api::impl_runtime_apis! {
|
||||
block: Block,
|
||||
data: sp_inherents::InherentData,
|
||||
) -> 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 {
|
||||
fn events() -> Vec<Vec<u8>> {
|
||||
fn events() -> Vec<Vec<Vec<u8>>> {
|
||||
Core::events()
|
||||
}
|
||||
fn validators(network: NetworkId) -> Vec<serai_abi::primitives::crypto::Public> {
|
||||
@@ -522,6 +567,21 @@ sp_api::impl_runtime_apis! {
|
||||
.map(|validator| validator.0.into())
|
||||
.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>]
|
||||
|
||||
[pallet_timestamp, Timestamp]
|
||||
|
||||
[balances, Balances]
|
||||
|
||||
[babe, Babe]
|
||||
|
||||
@@ -21,10 +21,10 @@ workspace = true
|
||||
[dependencies]
|
||||
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-support = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
|
||||
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"] }
|
||||
|
||||
sp-core = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
sp-io = { 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 = "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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
|
||||
frame-system = { 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 = "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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", default-features = false }
|
||||
|
||||
pallet-session = { 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 = "71fa60b900c8ad068f1b9ce8100508506377fbf5", default-features = false }
|
||||
pallet-grandpa = { 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 = "e01101b68c5b0f588dd4cdee48f801a2c1f75b84", 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"] }
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@ pub(crate) trait Keys {
|
||||
|
||||
/// The oraclization key for a validator set.
|
||||
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 {
|
||||
@@ -53,4 +56,8 @@ impl<S: KeysStorage> Keys for S {
|
||||
fn oraclization_key(set: ExternalValidatorSet) -> Option<Public> {
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
pub fn distribute_block_rewards(
|
||||
network: NetworkId,
|
||||
|
||||
Reference in New Issue
Block a user