mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 13:39:25 +00:00
Compare commits
48 Commits
next
...
1b755a5d48
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b755a5d48 | ||
|
|
e5efcd56ba | ||
|
|
5d60b3c2ae | ||
|
|
ae923b24ff | ||
|
|
d304cd97e1 | ||
|
|
2b56dcdf3f | ||
|
|
90804c4c30 | ||
|
|
46caca2f51 | ||
|
|
2077e485bb | ||
|
|
28dbef8a1c | ||
|
|
3541197aa5 | ||
|
|
a2209dd6ff | ||
|
|
2032cf355f | ||
|
|
fe41b09fd4 | ||
|
|
74bad049a7 | ||
|
|
72fefb3d85 | ||
|
|
200c1530a4 | ||
|
|
5736b87b57 | ||
|
|
ada94e8c5d | ||
|
|
75240ed327 | ||
|
|
6177cf5c07 | ||
|
|
0d38dc96b6 | ||
|
|
e8094523ff | ||
|
|
53a64bc7e2 | ||
|
|
3c6e889732 | ||
|
|
354efc0192 | ||
|
|
e20058feae | ||
|
|
09f0714894 | ||
|
|
d3d539553c | ||
|
|
b08ae8e6a7 | ||
|
|
35db2924b4 | ||
|
|
bfff823bf7 | ||
|
|
352af85498 | ||
|
|
ecad89b269 | ||
|
|
48f5ed71d7 | ||
|
|
ed9cbdd8e0 | ||
|
|
0ac11defcc | ||
|
|
24e89316d5 | ||
|
|
3f03dac050 | ||
|
|
820b710928 | ||
|
|
88c7ae3e7d | ||
|
|
dd5e43760d | ||
|
|
776e417fd2 | ||
|
|
2f8ce15a92 | ||
|
|
af56304676 | ||
|
|
62a2c4f20e | ||
|
|
c69841710a | ||
|
|
3158590675 |
14
.github/workflows/lint.yml
vendored
14
.github/workflows/lint.yml
vendored
@@ -144,14 +144,15 @@ jobs:
|
|||||||
function check_workspace {
|
function check_workspace {
|
||||||
# Get the members array from the workspace's `Cargo.toml`
|
# Get the members array from the workspace's `Cargo.toml`
|
||||||
cargo_toml_lines=$(cat ./Cargo.toml | wc -l)
|
cargo_toml_lines=$(cat ./Cargo.toml | wc -l)
|
||||||
|
# Keep all lines after the start of the array, then keep all lines before the next "]"
|
||||||
members=$(cat Cargo.toml | grep "members\ \=\ \[" -m1 -A$cargo_toml_lines | grep "]" -m1 -B$cargo_toml_lines)
|
members=$(cat Cargo.toml | grep "members\ \=\ \[" -m1 -A$cargo_toml_lines | grep "]" -m1 -B$cargo_toml_lines)
|
||||||
# Parse out any comments, including comments post-fixed on the same line as an entry
|
|
||||||
members=$(echo "$members" | grep -Ev "^[[:space:]]+#" | grep -Ev "^[[:space:]]?$" | awk -F',' '{print $1","}')
|
|
||||||
# Prune `members = [` to `[` by replacing the first line with just `[`
|
# Prune `members = [` to `[` by replacing the first line with just `[`
|
||||||
members=$(echo "$members" | sed "1s/.*/\[/")
|
members=$(echo "$members" | sed "1s/.*/\[/")
|
||||||
# Remove the trailing comma by replacing the last line's "," with ""
|
|
||||||
members=$(echo "$members" | sed "$(($(echo "$members" | wc -l) - 1))s/\,//")
|
# Parse out any comments, whitespace, including comments post-fixed on the same line as an entry
|
||||||
# Correct the last line, which was malleated to "]," when pruning comments
|
# We accomplish the latter by pruning all characters after the entry's ","
|
||||||
|
members=$(echo "$members" | grep -Ev "^[[:space:]]*(#|$)" | awk -F',' '{print $1","}')
|
||||||
|
# Correct the last line, which was malleated to "],"
|
||||||
members=$(echo "$members" | sed "$(echo "$members" | wc -l)s/\]\,/\]/")
|
members=$(echo "$members" | sed "$(echo "$members" | wc -l)s/\]\,/\]/")
|
||||||
|
|
||||||
# Don't check the patches
|
# Don't check the patches
|
||||||
@@ -174,6 +175,9 @@ jobs:
|
|||||||
members=$(echo "$members" | grep -v "mini\"")
|
members=$(echo "$members" | grep -v "mini\"")
|
||||||
members=$(echo "$members" | grep -v "tests/")
|
members=$(echo "$members" | grep -v "tests/")
|
||||||
|
|
||||||
|
# Remove the trailing comma by replacing the last line's "," with ""
|
||||||
|
members=$(echo "$members" | sed "$(($(echo "$members" | wc -l) - 1))s/\,//")
|
||||||
|
|
||||||
echo $members | jq -r ".[]" | while read -r member; do
|
echo $members | jq -r ".[]" | while read -r member; do
|
||||||
check_msrv $member
|
check_msrv $member
|
||||||
correct=$?
|
correct=$?
|
||||||
|
|||||||
2
.github/workflows/pages.yml
vendored
2
.github/workflows/pages.yml
vendored
@@ -69,7 +69,7 @@ jobs:
|
|||||||
uses: ./.github/actions/build-dependencies
|
uses: ./.github/actions/build-dependencies
|
||||||
- name: Buld Rust docs
|
- name: Buld Rust docs
|
||||||
run: |
|
run: |
|
||||||
rustup toolchain install ${{ steps.nightly.outputs.version }} --profile minimal -t wasm32v1-none -c rust-docs
|
rustup toolchain install ${{ steps.nightly.outputs.version }} --profile minimal -t wasm32v1-none -c rust-docs -c rust-src
|
||||||
RUSTDOCFLAGS="--cfg docsrs" cargo +${{ steps.nightly.outputs.version }} doc --workspace --all-features
|
RUSTDOCFLAGS="--cfg docsrs" cargo +${{ steps.nightly.outputs.version }} doc --workspace --all-features
|
||||||
mv target/doc docs/_site/rust
|
mv target/doc docs/_site/rust
|
||||||
|
|
||||||
|
|||||||
1
.github/workflows/tests.yml
vendored
1
.github/workflows/tests.yml
vendored
@@ -61,6 +61,7 @@ jobs:
|
|||||||
-p serai-monero-processor \
|
-p serai-monero-processor \
|
||||||
-p tendermint-machine \
|
-p tendermint-machine \
|
||||||
-p tributary-sdk \
|
-p tributary-sdk \
|
||||||
|
-p serai-cosign-types \
|
||||||
-p serai-cosign \
|
-p serai-cosign \
|
||||||
-p serai-coordinator-substrate \
|
-p serai-coordinator-substrate \
|
||||||
-p serai-coordinator-tributary \
|
-p serai-coordinator-tributary \
|
||||||
|
|||||||
4760
Cargo.lock
generated
4760
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
60
Cargo.toml
60
Cargo.toml
@@ -1,15 +1,6 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
# Version patches
|
|
||||||
"patches/parking_lot",
|
|
||||||
"patches/zstd",
|
|
||||||
"patches/rocksdb",
|
|
||||||
|
|
||||||
# std patches
|
|
||||||
"patches/matches",
|
|
||||||
"patches/is-terminal",
|
|
||||||
|
|
||||||
# Rewrites/redirects
|
# Rewrites/redirects
|
||||||
"patches/option-ext",
|
"patches/option-ext",
|
||||||
"patches/directories-next",
|
"patches/directories-next",
|
||||||
@@ -89,6 +80,7 @@ members = [
|
|||||||
|
|
||||||
"coordinator/tributary-sdk/tendermint",
|
"coordinator/tributary-sdk/tendermint",
|
||||||
"coordinator/tributary-sdk",
|
"coordinator/tributary-sdk",
|
||||||
|
"coordinator/cosign/types",
|
||||||
"coordinator/cosign",
|
"coordinator/cosign",
|
||||||
"coordinator/substrate",
|
"coordinator/substrate",
|
||||||
"coordinator/tributary",
|
"coordinator/tributary",
|
||||||
@@ -97,31 +89,17 @@ members = [
|
|||||||
"coordinator",
|
"coordinator",
|
||||||
|
|
||||||
"substrate/primitives",
|
"substrate/primitives",
|
||||||
|
|
||||||
"substrate/coins/primitives",
|
|
||||||
"substrate/coins/pallet",
|
|
||||||
|
|
||||||
"substrate/dex/pallet",
|
|
||||||
|
|
||||||
"substrate/validator-sets/primitives",
|
|
||||||
"substrate/validator-sets/pallet",
|
|
||||||
|
|
||||||
"substrate/genesis-liquidity/primitives",
|
|
||||||
"substrate/genesis-liquidity/pallet",
|
|
||||||
|
|
||||||
"substrate/emissions/primitives",
|
|
||||||
"substrate/emissions/pallet",
|
|
||||||
|
|
||||||
"substrate/economic-security/pallet",
|
|
||||||
|
|
||||||
"substrate/in-instructions/primitives",
|
|
||||||
"substrate/in-instructions/pallet",
|
|
||||||
|
|
||||||
"substrate/signals/primitives",
|
|
||||||
"substrate/signals/pallet",
|
|
||||||
|
|
||||||
"substrate/abi",
|
"substrate/abi",
|
||||||
|
|
||||||
|
"substrate/coins",
|
||||||
|
"substrate/validator-sets",
|
||||||
|
"substrate/signals",
|
||||||
|
"substrate/dex",
|
||||||
|
"substrate/genesis-liquidity",
|
||||||
|
"substrate/economic-security",
|
||||||
|
"substrate/emissions",
|
||||||
|
"substrate/in-instructions",
|
||||||
|
|
||||||
"substrate/runtime",
|
"substrate/runtime",
|
||||||
"substrate/node",
|
"substrate/node",
|
||||||
|
|
||||||
@@ -205,17 +183,6 @@ modular-frost = { path = "crypto/frost" }
|
|||||||
# https://github.com/rust-lang-nursery/lazy-static.rs/issues/201
|
# https://github.com/rust-lang-nursery/lazy-static.rs/issues/201
|
||||||
lazy_static = { git = "https://github.com/rust-lang-nursery/lazy-static.rs", rev = "5735630d46572f1e5377c8f2ba0f79d18f53b10c" }
|
lazy_static = { git = "https://github.com/rust-lang-nursery/lazy-static.rs", rev = "5735630d46572f1e5377c8f2ba0f79d18f53b10c" }
|
||||||
|
|
||||||
parking_lot = { path = "patches/parking_lot" }
|
|
||||||
# wasmtime pulls in an old version for this
|
|
||||||
zstd = { path = "patches/zstd" }
|
|
||||||
# Needed for WAL compression
|
|
||||||
rocksdb = { path = "patches/rocksdb" }
|
|
||||||
|
|
||||||
# is-terminal now has an std-based solution with an equivalent API
|
|
||||||
is-terminal = { path = "patches/is-terminal" }
|
|
||||||
# So does matches
|
|
||||||
matches = { path = "patches/matches" }
|
|
||||||
|
|
||||||
# directories-next was created because directories was unmaintained
|
# directories-next was created because directories was unmaintained
|
||||||
# directories-next is now unmaintained while directories is maintained
|
# directories-next is now unmaintained while directories is maintained
|
||||||
# The directories author pulls in ridiculously pointless crates and prefers
|
# The directories author pulls in ridiculously pointless crates and prefers
|
||||||
@@ -228,12 +195,15 @@ directories-next = { path = "patches/directories-next" }
|
|||||||
k256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" }
|
k256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" }
|
||||||
p256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" }
|
p256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" }
|
||||||
|
|
||||||
|
# Patch due to `std` now including the required functionality
|
||||||
|
is_terminal_polyfill = { path = "./patches/is_terminal_polyfill" }
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
|
incompatible_msrv = "allow" # Manually verified with a GitHub workflow
|
||||||
|
manual_is_multiple_of = "allow"
|
||||||
unwrap_or_default = "allow"
|
unwrap_or_default = "allow"
|
||||||
map_unwrap_or = "allow"
|
map_unwrap_or = "allow"
|
||||||
needless_continue = "allow"
|
needless_continue = "allow"
|
||||||
manual_is_multiple_of = "allow"
|
|
||||||
incompatible_msrv = "allow" # Manually verified with a GitHub workflow
|
|
||||||
borrow_as_ptr = "deny"
|
borrow_as_ptr = "deny"
|
||||||
cast_lossless = "deny"
|
cast_lossless = "deny"
|
||||||
cast_possible_truncation = "deny"
|
cast_possible_truncation = "deny"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-db = { version = "0.4", default-features = false, optional = true }
|
parity-db = { version = "0.5", default-features = false, features = ["arc"], optional = true }
|
||||||
rocksdb = { version = "0.24", default-features = false, features = ["zstd"], optional = true }
|
rocksdb = { version = "0.24", default-features = false, features = ["zstd"], optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub fn serai_db_key(
|
|||||||
///
|
///
|
||||||
/// Creates a unit struct and a default implementation for the `key`, `get`, and `set`. The macro
|
/// Creates a unit struct and a default implementation for the `key`, `get`, and `set`. The macro
|
||||||
/// uses a syntax similar to defining a function. Parameters are concatenated to produce a key,
|
/// uses a syntax similar to defining a function. Parameters are concatenated to produce a key,
|
||||||
/// they must be `scale` encodable. The return type is used to auto encode and decode the database
|
/// they must be `borsh` serializable. The return type is used to auto (de)serialize the database
|
||||||
/// value bytes using `borsh`.
|
/// value bytes using `borsh`.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@@ -54,11 +54,10 @@ macro_rules! create_db {
|
|||||||
)?;
|
)?;
|
||||||
impl$(<$($generic_name: $generic_type),+>)? $field_name$(<$($generic_name),+>)? {
|
impl$(<$($generic_name: $generic_type),+>)? $field_name$(<$($generic_name),+>)? {
|
||||||
pub(crate) fn key($($arg: $arg_type),*) -> Vec<u8> {
|
pub(crate) fn key($($arg: $arg_type),*) -> Vec<u8> {
|
||||||
use scale::Encode;
|
|
||||||
$crate::serai_db_key(
|
$crate::serai_db_key(
|
||||||
stringify!($db_name).as_bytes(),
|
stringify!($db_name).as_bytes(),
|
||||||
stringify!($field_name).as_bytes(),
|
stringify!($field_name).as_bytes(),
|
||||||
($($arg),*).encode()
|
&borsh::to_vec(&($($arg),*)).unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub(crate) fn set(
|
pub(crate) fn set(
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
rustversion = { version = "1", default-features = false }
|
rustversion = { version = "1", default-features = false }
|
||||||
spin = { version = "0.10", default-features = false, features = ["use_ticket_mutex", "once", "lazy"] }
|
spin = { version = "0.10", default-features = false, features = ["use_ticket_mutex", "once", "lazy"] }
|
||||||
hashbrown = { version = "0.15", default-features = false, features = ["default-hasher", "inline-more"] }
|
hashbrown = { version = "0.16", default-features = false, features = ["default-hasher", "inline-more"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = []
|
std = []
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ frost = { package = "modular-frost", path = "../crypto/frost" }
|
|||||||
frost-schnorrkel = { path = "../crypto/schnorrkel" }
|
frost-schnorrkel = { path = "../crypto/schnorrkel" }
|
||||||
|
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std", "derive", "bit-vec"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
zalloc = { path = "../common/zalloc" }
|
zalloc = { path = "../common/zalloc" }
|
||||||
@@ -43,7 +42,7 @@ messages = { package = "serai-processor-messages", path = "../processor/messages
|
|||||||
message-queue = { package = "serai-message-queue", path = "../message-queue" }
|
message-queue = { package = "serai-message-queue", path = "../message-queue" }
|
||||||
tributary-sdk = { path = "./tributary-sdk" }
|
tributary-sdk = { path = "./tributary-sdk" }
|
||||||
|
|
||||||
serai-client = { path = "../substrate/client", default-features = false, features = ["serai", "borsh"] }
|
serai-client = { path = "../substrate/client", default-features = false, features = ["serai"] }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
env_logger = { version = "0.10", default-features = false, features = ["humantime"] }
|
env_logger = { version = "0.10", default-features = false, features = ["humantime"] }
|
||||||
|
|||||||
@@ -21,9 +21,8 @@ workspace = true
|
|||||||
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
||||||
schnorrkel = { version = "0.11", default-features = false, features = ["std"] }
|
schnorrkel = { version = "0.11", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std", "derive"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
serai-client = { path = "../../substrate/client", default-features = false, features = ["serai", "borsh"] }
|
serai-client = { path = "../../substrate/client", default-features = false, features = ["serai"] }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
@@ -31,3 +30,5 @@ tokio = { version = "1", default-features = false }
|
|||||||
|
|
||||||
serai-db = { path = "../../common/db", version = "0.1.1" }
|
serai-db = { path = "../../common/db", version = "0.1.1" }
|
||||||
serai-task = { path = "../../common/task", version = "0.1" }
|
serai-task = { path = "../../common/task", version = "0.1" }
|
||||||
|
|
||||||
|
serai-cosign-types = { path = "./types" }
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use std::{sync::Arc, collections::HashMap, time::Instant};
|
|||||||
|
|
||||||
use blake2::{Digest, Blake2s256};
|
use blake2::{Digest, Blake2s256};
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
@@ -19,6 +18,8 @@ use serai_client::{
|
|||||||
use serai_db::*;
|
use serai_db::*;
|
||||||
use serai_task::*;
|
use serai_task::*;
|
||||||
|
|
||||||
|
use serai_cosign_types::*;
|
||||||
|
|
||||||
/// The cosigns which are intended to be performed.
|
/// The cosigns which are intended to be performed.
|
||||||
mod intend;
|
mod intend;
|
||||||
/// The evaluator of the cosigns.
|
/// The evaluator of the cosigns.
|
||||||
@@ -78,68 +79,6 @@ enum HasEvents {
|
|||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An intended cosign.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
|
||||||
pub struct CosignIntent {
|
|
||||||
/// The global session this cosign is being performed under.
|
|
||||||
pub global_session: [u8; 32],
|
|
||||||
/// The number of the block to cosign.
|
|
||||||
pub block_number: u64,
|
|
||||||
/// The hash of the block to cosign.
|
|
||||||
pub block_hash: [u8; 32],
|
|
||||||
/// If this cosign must be handled before further cosigns are.
|
|
||||||
pub notable: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A cosign.
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, BorshSerialize, BorshDeserialize)]
|
|
||||||
pub struct Cosign {
|
|
||||||
/// The global session this cosign is being performed under.
|
|
||||||
pub global_session: [u8; 32],
|
|
||||||
/// The number of the block to cosign.
|
|
||||||
pub block_number: u64,
|
|
||||||
/// The hash of the block to cosign.
|
|
||||||
pub block_hash: [u8; 32],
|
|
||||||
/// The actual cosigner.
|
|
||||||
pub cosigner: ExternalNetworkId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CosignIntent {
|
|
||||||
/// Convert this into a `Cosign`.
|
|
||||||
pub fn into_cosign(self, cosigner: ExternalNetworkId) -> Cosign {
|
|
||||||
let CosignIntent { global_session, block_number, block_hash, notable: _ } = self;
|
|
||||||
Cosign { global_session, block_number, block_hash, cosigner }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cosign {
|
|
||||||
/// The message to sign to sign this cosign.
|
|
||||||
///
|
|
||||||
/// This must be signed with schnorrkel, the context set to `COSIGN_CONTEXT`.
|
|
||||||
pub fn signature_message(&self) -> Vec<u8> {
|
|
||||||
// We use a schnorrkel context to domain-separate this
|
|
||||||
self.encode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A signed cosign.
|
|
||||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
|
|
||||||
pub struct SignedCosign {
|
|
||||||
/// The cosign.
|
|
||||||
pub cosign: Cosign,
|
|
||||||
/// The signature for the cosign.
|
|
||||||
pub signature: [u8; 64],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SignedCosign {
|
|
||||||
fn verify_signature(&self, signer: serai_client::Public) -> bool {
|
|
||||||
let Ok(signer) = schnorrkel::PublicKey::from_bytes(&signer.0) else { return false };
|
|
||||||
let Ok(signature) = schnorrkel::Signature::from_bytes(&self.signature) else { return false };
|
|
||||||
|
|
||||||
signer.verify_simple(COSIGN_CONTEXT, &self.cosign.signature_message(), &signature).is_ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
create_db! {
|
create_db! {
|
||||||
Cosign {
|
Cosign {
|
||||||
// The following are populated by the intend task and used throughout the library
|
// The following are populated by the intend task and used throughout the library
|
||||||
|
|||||||
25
coordinator/cosign/types/Cargo.toml
Normal file
25
coordinator/cosign/types/Cargo.toml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "serai-cosign-types"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Evaluator of cosigns for the Serai network"
|
||||||
|
license = "AGPL-3.0-only"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/coordinator/cosign"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
keywords = []
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
rust-version = "1.85"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
schnorrkel = { version = "0.11", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
|
serai-primitives = { path = "../../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
72
coordinator/cosign/types/src/lib.rs
Normal file
72
coordinator/cosign/types/src/lib.rs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
//! Types used when cosigning Serai. For more info, please see `serai-cosign`.
|
||||||
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
|
use serai_primitives::{crypto::Public, network_id::ExternalNetworkId};
|
||||||
|
|
||||||
|
/// The schnorrkel context to used when signing a cosign.
|
||||||
|
pub const COSIGN_CONTEXT: &[u8] = b"/serai/coordinator/cosign";
|
||||||
|
|
||||||
|
/// An intended cosign.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct CosignIntent {
|
||||||
|
/// The global session this cosign is being performed under.
|
||||||
|
pub global_session: [u8; 32],
|
||||||
|
/// The number of the block to cosign.
|
||||||
|
pub block_number: u64,
|
||||||
|
/// The hash of the block to cosign.
|
||||||
|
pub block_hash: [u8; 32],
|
||||||
|
/// If this cosign must be handled before further cosigns are.
|
||||||
|
pub notable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A cosign.
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct Cosign {
|
||||||
|
/// The global session this cosign is being performed under.
|
||||||
|
pub global_session: [u8; 32],
|
||||||
|
/// The number of the block to cosign.
|
||||||
|
pub block_number: u64,
|
||||||
|
/// The hash of the block to cosign.
|
||||||
|
pub block_hash: [u8; 32],
|
||||||
|
/// The actual cosigner.
|
||||||
|
pub cosigner: ExternalNetworkId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CosignIntent {
|
||||||
|
/// Convert this into a `Cosign`.
|
||||||
|
pub fn into_cosign(self, cosigner: ExternalNetworkId) -> Cosign {
|
||||||
|
let CosignIntent { global_session, block_number, block_hash, notable: _ } = self;
|
||||||
|
Cosign { global_session, block_number, block_hash, cosigner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cosign {
|
||||||
|
/// The message to sign to sign this cosign.
|
||||||
|
///
|
||||||
|
/// This must be signed with schnorrkel, the context set to `COSIGN_CONTEXT`.
|
||||||
|
pub fn signature_message(&self) -> Vec<u8> {
|
||||||
|
// We use a schnorrkel context to domain-separate this
|
||||||
|
borsh::to_vec(self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A signed cosign.
|
||||||
|
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct SignedCosign {
|
||||||
|
/// The cosign.
|
||||||
|
pub cosign: Cosign,
|
||||||
|
/// The signature for the cosign.
|
||||||
|
pub signature: [u8; 64],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SignedCosign {
|
||||||
|
/// Verify a cosign's signature.
|
||||||
|
pub fn verify_signature(&self, signer: Public) -> bool {
|
||||||
|
let Ok(signer) = schnorrkel::PublicKey::from_bytes(&signer.0) else { return false };
|
||||||
|
let Ok(signature) = schnorrkel::Signature::from_bytes(&self.signature) else { return false };
|
||||||
|
|
||||||
|
signer.verify_simple(COSIGN_CONTEXT, &self.cosign.signature_message(), &signature).is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ borsh = { version = "1", default-features = false, features = ["std", "derive",
|
|||||||
|
|
||||||
serai-db = { path = "../../common/db", version = "0.1" }
|
serai-db = { path = "../../common/db", version = "0.1" }
|
||||||
|
|
||||||
serai-client = { path = "../../substrate/client", default-features = false, features = ["serai", "borsh"] }
|
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
serai-cosign = { path = "../cosign" }
|
serai-cosign = { path = "../cosign" }
|
||||||
tributary-sdk = { path = "../tributary-sdk" }
|
tributary-sdk = { path = "../tributary-sdk" }
|
||||||
|
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ schnorrkel = { version = "0.11", default-features = false, features = ["std"] }
|
|||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
serai-client = { path = "../../../substrate/client", default-features = false, features = ["serai", "borsh"] }
|
serai-client = { path = "../../../substrate/client", default-features = false, features = ["serai"] }
|
||||||
serai-cosign = { path = "../../cosign" }
|
serai-cosign = { path = "../../cosign" }
|
||||||
tributary-sdk = { path = "../../tributary-sdk" }
|
tributary-sdk = { path = "../../tributary-sdk" }
|
||||||
|
|
||||||
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
||||||
tokio = { version = "1", default-features = false, features = ["sync"] }
|
tokio = { version = "1", default-features = false, features = ["sync"] }
|
||||||
libp2p = { version = "0.54", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "ping", "request-response", "gossipsub", "macros"] }
|
libp2p = { version = "0.56", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "ping", "request-response", "gossipsub", "macros"] }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
serai-task = { path = "../../../common/task", version = "0.1" }
|
serai-task = { path = "../../../common/task", version = "0.1" }
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use serai_client::validator_sets::primitives::{MAX_KEY_SHARES_PER_SET, ExternalValidatorSet};
|
use serai_primitives::{MAX_KEY_SHARES_PER_SET, ExternalValidatorSet};
|
||||||
|
|
||||||
use futures_lite::FutureExt;
|
use futures_lite::FutureExt;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_client::{primitives::ExternalNetworkId, validator_sets::primitives::ExternalValidatorSet};
|
use serai_primitives::{network_id::ExternalNetworkId, validator_sets::ExternalValidatorSet};
|
||||||
|
|
||||||
use serai_db::Db;
|
use serai_db::Db;
|
||||||
use tributary_sdk::{ReadWrite, TransactionTrait, Tributary, TributaryReader};
|
use tributary_sdk::{ReadWrite, TransactionTrait, Tributary, TributaryReader};
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use tokio::sync::mpsc;
|
|||||||
|
|
||||||
use serai_db::{Get, DbTxn, Db as DbTrait, create_db, db_channel};
|
use serai_db::{Get, DbTxn, Db as DbTrait, create_db, db_channel};
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
use serai_client::validator_sets::primitives::ExternalValidatorSet;
|
use serai_client::validator_sets::primitives::ExternalValidatorSet;
|
||||||
|
|
||||||
use tributary_sdk::{TransactionKind, TransactionError, ProvidedError, TransactionTrait, Tributary};
|
use tributary_sdk::{TransactionKind, TransactionError, ProvidedError, TransactionTrait, Tributary};
|
||||||
@@ -479,7 +478,8 @@ pub(crate) async fn spawn_tributary<P: P2p>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let genesis = <[u8; 32]>::from(Blake2s::<U32>::digest((set.serai_block, set.set).encode()));
|
let genesis =
|
||||||
|
<[u8; 32]>::from(Blake2s::<U32>::digest(borsh::to_vec(&(set.serai_block, set.set)).unwrap()));
|
||||||
|
|
||||||
// Since the Serai block will be finalized, then cosigned, before we handle this, this time will
|
// Since the Serai block will be finalized, then cosigned, before we handle this, this time will
|
||||||
// be a couple of minutes stale. While the Tributary will still function with a start time in the
|
// be a couple of minutes stale. While the Tributary will still function with a start time in the
|
||||||
|
|||||||
@@ -20,12 +20,11 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bitvec = { version = "1", default-features = false, features = ["std"] }
|
bitvec = { version = "1", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std", "derive", "bit-vec"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std"] }
|
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
serai-client = { path = "../../substrate/client", version = "0.1", default-features = false, features = ["serai", "borsh"] }
|
serai-client = { path = "../../substrate/client", version = "0.1", default-features = false, features = ["serai"] }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use dkg::Participant;
|
use dkg::Participant;
|
||||||
@@ -178,14 +177,13 @@ impl Keys {
|
|||||||
signature_participants,
|
signature_participants,
|
||||||
signature,
|
signature,
|
||||||
);
|
);
|
||||||
_public_db::Keys::set(txn, set.network, &(set.session, tx.encode()));
|
_public_db::Keys::set(txn, set.network, &(set.session, tx));
|
||||||
}
|
}
|
||||||
pub(crate) fn take(
|
pub(crate) fn take(
|
||||||
txn: &mut impl DbTxn,
|
txn: &mut impl DbTxn,
|
||||||
network: ExternalNetworkId,
|
network: ExternalNetworkId,
|
||||||
) -> Option<(Session, Transaction)> {
|
) -> Option<(Session, Transaction)> {
|
||||||
let (session, tx) = _public_db::Keys::take(txn, network)?;
|
_public_db::Keys::take(txn, network)
|
||||||
Some((session, <_>::decode(&mut tx.as_slice()).unwrap()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,13 +224,12 @@ impl SlashReports {
|
|||||||
slash_report,
|
slash_report,
|
||||||
signature,
|
signature,
|
||||||
);
|
);
|
||||||
_public_db::SlashReports::set(txn, set.network, &(set.session, tx.encode()));
|
_public_db::SlashReports::set(txn, set.network, &(set.session, tx));
|
||||||
}
|
}
|
||||||
pub(crate) fn take(
|
pub(crate) fn take(
|
||||||
txn: &mut impl DbTxn,
|
txn: &mut impl DbTxn,
|
||||||
network: ExternalNetworkId,
|
network: ExternalNetworkId,
|
||||||
) -> Option<(Session, Transaction)> {
|
) -> Option<(Session, Transaction)> {
|
||||||
let (session, tx) = _public_db::SlashReports::take(txn, network)?;
|
_public_db::SlashReports::take(txn, network)
|
||||||
Some((session, <_>::decode(&mut tx.as_slice()).unwrap()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ log = { version = "0.4", default-features = false, features = ["std"] }
|
|||||||
|
|
||||||
serai-db = { path = "../../common/db", version = "0.1" }
|
serai-db = { path = "../../common/db", version = "0.1" }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std", "derive"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
futures-util = { version = "0.3", default-features = false, features = ["std", "sink", "channel"] }
|
futures-util = { version = "0.3", default-features = false, features = ["std", "sink", "channel"] }
|
||||||
futures-channel = { version = "0.3", default-features = false, features = ["std", "sink"] }
|
futures-channel = { version = "0.3", default-features = false, features = ["std", "sink"] }
|
||||||
tendermint = { package = "tendermint-machine", path = "./tendermint", version = "0.2" }
|
tendermint = { package = "tendermint-machine", path = "./tendermint", version = "0.2" }
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use ciphersuite::{group::GroupEncoding, *};
|
|||||||
|
|
||||||
use serai_db::{Get, DbTxn, Db};
|
use serai_db::{Get, DbTxn, Db};
|
||||||
|
|
||||||
use scale::Decode;
|
use borsh::BorshDeserialize;
|
||||||
|
|
||||||
use tendermint::ext::{Network, Commit};
|
use tendermint::ext::{Network, Commit};
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ impl<D: Db, T: TransactionTrait> Blockchain<D, T> {
|
|||||||
D::key(
|
D::key(
|
||||||
b"tributary_blockchain",
|
b"tributary_blockchain",
|
||||||
b"next_nonce",
|
b"next_nonce",
|
||||||
[genesis.as_ref(), signer.to_bytes().as_ref(), order].concat(),
|
[genesis.as_slice(), signer.to_bytes().as_slice(), order].concat(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ impl<D: Db, T: TransactionTrait> Blockchain<D, T> {
|
|||||||
|
|
||||||
pub(crate) fn block_from_db(db: &D, genesis: [u8; 32], block: &[u8; 32]) -> Option<Block<T>> {
|
pub(crate) fn block_from_db(db: &D, genesis: [u8; 32], block: &[u8; 32]) -> Option<Block<T>> {
|
||||||
db.get(Self::block_key(&genesis, block))
|
db.get(Self::block_key(&genesis, block))
|
||||||
.map(|bytes| Block::<T>::read::<&[u8]>(&mut bytes.as_ref()).unwrap())
|
.map(|bytes| Block::<T>::read::<&[u8]>(&mut bytes.as_slice()).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn commit_from_db(db: &D, genesis: [u8; 32], block: &[u8; 32]) -> Option<Vec<u8>> {
|
pub(crate) fn commit_from_db(db: &D, genesis: [u8; 32], block: &[u8; 32]) -> Option<Vec<u8>> {
|
||||||
@@ -169,7 +169,7 @@ impl<D: Db, T: TransactionTrait> Blockchain<D, T> {
|
|||||||
// we must have a commit per valid hash
|
// we must have a commit per valid hash
|
||||||
let commit = Self::commit_from_db(db, genesis, &hash).unwrap();
|
let commit = Self::commit_from_db(db, genesis, &hash).unwrap();
|
||||||
// commit has to be valid if it is coming from our db
|
// commit has to be valid if it is coming from our db
|
||||||
Some(Commit::<N::SignatureScheme>::decode(&mut commit.as_ref()).unwrap())
|
Some(Commit::<N::SignatureScheme>::deserialize_reader(&mut commit.as_slice()).unwrap())
|
||||||
};
|
};
|
||||||
let unsigned_in_chain =
|
let unsigned_in_chain =
|
||||||
|hash: [u8; 32]| db.get(Self::unsigned_included_key(&self.genesis, &hash)).is_some();
|
|hash: [u8; 32]| db.get(Self::unsigned_included_key(&self.genesis, &hash)).is_some();
|
||||||
@@ -244,7 +244,7 @@ impl<D: Db, T: TransactionTrait> Blockchain<D, T> {
|
|||||||
let commit = |block: u64| -> Option<Commit<N::SignatureScheme>> {
|
let commit = |block: u64| -> Option<Commit<N::SignatureScheme>> {
|
||||||
let commit = self.commit_by_block_number(block)?;
|
let commit = self.commit_by_block_number(block)?;
|
||||||
// commit has to be valid if it is coming from our db
|
// commit has to be valid if it is coming from our db
|
||||||
Some(Commit::<N::SignatureScheme>::decode(&mut commit.as_ref()).unwrap())
|
Some(Commit::<N::SignatureScheme>::deserialize_reader(&mut commit.as_slice()).unwrap())
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut txn_db = db.clone();
|
let mut txn_db = db.clone();
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ use std::{sync::Arc, io};
|
|||||||
|
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
|
use borsh::BorshDeserialize;
|
||||||
|
|
||||||
use ciphersuite::*;
|
use ciphersuite::*;
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
|
|
||||||
use scale::Decode;
|
|
||||||
use futures_channel::mpsc::UnboundedReceiver;
|
use futures_channel::mpsc::UnboundedReceiver;
|
||||||
use futures_util::{StreamExt, SinkExt};
|
use futures_util::{StreamExt, SinkExt};
|
||||||
use ::tendermint::{
|
use ::tendermint::{
|
||||||
@@ -177,7 +178,7 @@ impl<D: Db, T: TransactionTrait, P: P2p> Tributary<D, T, P> {
|
|||||||
let block_number = BlockNumber(blockchain.block_number());
|
let block_number = BlockNumber(blockchain.block_number());
|
||||||
|
|
||||||
let start_time = if let Some(commit) = blockchain.commit(&blockchain.tip()) {
|
let start_time = if let Some(commit) = blockchain.commit(&blockchain.tip()) {
|
||||||
Commit::<Validators>::decode(&mut commit.as_ref()).unwrap().end_time
|
Commit::<Validators>::deserialize_reader(&mut commit.as_slice()).unwrap().end_time
|
||||||
} else {
|
} else {
|
||||||
start_time
|
start_time
|
||||||
};
|
};
|
||||||
@@ -276,8 +277,8 @@ impl<D: Db, T: TransactionTrait, P: P2p> Tributary<D, T, P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let block = TendermintBlock(block.serialize());
|
let block = TendermintBlock(block.serialize());
|
||||||
let mut commit_ref = commit.as_ref();
|
let mut commit_ref = commit.as_slice();
|
||||||
let Ok(commit) = Commit::<Arc<Validators>>::decode(&mut commit_ref) else {
|
let Ok(commit) = Commit::<Arc<Validators>>::deserialize_reader(&mut commit_ref) else {
|
||||||
log::error!("sent an invalidly serialized commit");
|
log::error!("sent an invalidly serialized commit");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -327,7 +328,7 @@ impl<D: Db, T: TransactionTrait, P: P2p> Tributary<D, T, P> {
|
|||||||
|
|
||||||
Some(&TENDERMINT_MESSAGE) => {
|
Some(&TENDERMINT_MESSAGE) => {
|
||||||
let Ok(msg) =
|
let Ok(msg) =
|
||||||
SignedMessageFor::<TendermintNetwork<D, T, P>>::decode::<&[u8]>(&mut &msg[1 ..])
|
SignedMessageFor::<TendermintNetwork<D, T, P>>::deserialize_reader(&mut &msg[1 ..])
|
||||||
else {
|
else {
|
||||||
log::error!("received invalid tendermint message");
|
log::error!("received invalid tendermint message");
|
||||||
return false;
|
return false;
|
||||||
@@ -367,15 +368,17 @@ impl<D: Db, T: TransactionTrait> TributaryReader<D, T> {
|
|||||||
Blockchain::<D, T>::commit_from_db(&self.0, self.1, hash)
|
Blockchain::<D, T>::commit_from_db(&self.0, self.1, hash)
|
||||||
}
|
}
|
||||||
pub fn parsed_commit(&self, hash: &[u8; 32]) -> Option<Commit<Validators>> {
|
pub fn parsed_commit(&self, hash: &[u8; 32]) -> Option<Commit<Validators>> {
|
||||||
self.commit(hash).map(|commit| Commit::<Validators>::decode(&mut commit.as_ref()).unwrap())
|
self
|
||||||
|
.commit(hash)
|
||||||
|
.map(|commit| Commit::<Validators>::deserialize_reader(&mut commit.as_slice()).unwrap())
|
||||||
}
|
}
|
||||||
pub fn block_after(&self, hash: &[u8; 32]) -> Option<[u8; 32]> {
|
pub fn block_after(&self, hash: &[u8; 32]) -> Option<[u8; 32]> {
|
||||||
Blockchain::<D, T>::block_after(&self.0, self.1, hash)
|
Blockchain::<D, T>::block_after(&self.0, self.1, hash)
|
||||||
}
|
}
|
||||||
pub fn time_of_block(&self, hash: &[u8; 32]) -> Option<u64> {
|
pub fn time_of_block(&self, hash: &[u8; 32]) -> Option<u64> {
|
||||||
self
|
self.commit(hash).map(|commit| {
|
||||||
.commit(hash)
|
Commit::<Validators>::deserialize_reader(&mut commit.as_slice()).unwrap().end_time
|
||||||
.map(|commit| Commit::<Validators>::decode(&mut commit.as_ref()).unwrap().end_time)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn locally_provided_txs_in_block(&self, hash: &[u8; 32], order: &str) -> bool {
|
pub fn locally_provided_txs_in_block(&self, hash: &[u8; 32], order: &str) -> bool {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use schnorr::{
|
|||||||
|
|
||||||
use serai_db::Db;
|
use serai_db::Db;
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use tendermint::{
|
use tendermint::{
|
||||||
SignedMessageFor,
|
SignedMessageFor,
|
||||||
ext::{
|
ext::{
|
||||||
@@ -248,7 +248,7 @@ impl Weights for Validators {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct TendermintBlock(pub Vec<u8>);
|
pub struct TendermintBlock(pub Vec<u8>);
|
||||||
impl BlockTrait for TendermintBlock {
|
impl BlockTrait for TendermintBlock {
|
||||||
type Id = [u8; 32];
|
type Id = [u8; 32];
|
||||||
@@ -300,7 +300,7 @@ impl<D: Db, T: TransactionTrait, P: P2p> Network for TendermintNetwork<D, T, P>
|
|||||||
fn broadcast(&mut self, msg: SignedMessageFor<Self>) -> impl Send + Future<Output = ()> {
|
fn broadcast(&mut self, msg: SignedMessageFor<Self>) -> impl Send + Future<Output = ()> {
|
||||||
async move {
|
async move {
|
||||||
let mut to_broadcast = vec![TENDERMINT_MESSAGE];
|
let mut to_broadcast = vec![TENDERMINT_MESSAGE];
|
||||||
to_broadcast.extend(msg.encode());
|
msg.serialize(&mut to_broadcast).unwrap();
|
||||||
self.p2p.broadcast(self.genesis, to_broadcast).await
|
self.p2p.broadcast(self.genesis, to_broadcast).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,7 +390,7 @@ impl<D: Db, T: TransactionTrait, P: P2p> Network for TendermintNetwork<D, T, P>
|
|||||||
return invalid_block();
|
return invalid_block();
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoded_commit = commit.encode();
|
let encoded_commit = borsh::to_vec(&commit).unwrap();
|
||||||
loop {
|
loop {
|
||||||
let block_res = self.blockchain.write().await.add_block::<Self>(
|
let block_res = self.blockchain.write().await.add_block::<Self>(
|
||||||
&block,
|
&block,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use scale::{Encode, Decode, IoReader};
|
use borsh::BorshDeserialize;
|
||||||
|
|
||||||
use blake2::{Digest, Blake2s256};
|
use blake2::{Digest, Blake2s256};
|
||||||
|
|
||||||
@@ -27,14 +27,14 @@ pub enum TendermintTx {
|
|||||||
|
|
||||||
impl ReadWrite for TendermintTx {
|
impl ReadWrite for TendermintTx {
|
||||||
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
||||||
Evidence::decode(&mut IoReader(reader))
|
Evidence::deserialize_reader(reader)
|
||||||
.map(TendermintTx::SlashEvidence)
|
.map(TendermintTx::SlashEvidence)
|
||||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid evidence format"))
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid evidence format"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
TendermintTx::SlashEvidence(ev) => writer.write_all(&ev.encode()),
|
TendermintTx::SlashEvidence(ev) => writer.write_all(&borsh::to_vec(&ev).unwrap()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ use dalek_ff_group::Ristretto;
|
|||||||
use ciphersuite::{group::Group, *};
|
use ciphersuite::{group::Group, *};
|
||||||
use schnorr::SchnorrSignature;
|
use schnorr::SchnorrSignature;
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
|
|
||||||
use ::tendermint::{
|
use ::tendermint::{
|
||||||
ext::{Network, Signer as SignerTrait, SignatureScheme, BlockNumber, RoundNumber},
|
ext::{Network, Signer as SignerTrait, SignatureScheme, BlockNumber, RoundNumber},
|
||||||
SignedMessageFor, DataFor, Message, SignedMessage, Data, Evidence,
|
SignedMessageFor, DataFor, Message, SignedMessage, Data, Evidence,
|
||||||
@@ -200,7 +198,7 @@ pub async fn signed_from_data<N: Network>(
|
|||||||
round: RoundNumber(round_number),
|
round: RoundNumber(round_number),
|
||||||
data,
|
data,
|
||||||
};
|
};
|
||||||
let sig = signer.sign(&msg.encode()).await;
|
let sig = signer.sign(&borsh::to_vec(&msg).unwrap()).await;
|
||||||
SignedMessage { msg, sig }
|
SignedMessage { msg, sig }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,5 +211,5 @@ pub async fn random_evidence_tx<N: Network>(
|
|||||||
let data = Data::Proposal(Some(RoundNumber(0)), b);
|
let data = Data::Proposal(Some(RoundNumber(0)), b);
|
||||||
let signer_id = signer.validator_id().await.unwrap();
|
let signer_id = signer.validator_id().await.unwrap();
|
||||||
let signed = signed_from_data::<N>(signer, signer_id, 0, 0, data).await;
|
let signed = signed_from_data::<N>(signer, signer_id, 0, 0, data).await;
|
||||||
TendermintTx::SlashEvidence(Evidence::InvalidValidRound(signed.encode()))
|
TendermintTx::SlashEvidence(Evidence::InvalidValidRound(borsh::to_vec(&signed).unwrap()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ use rand::{RngCore, rngs::OsRng};
|
|||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::*;
|
use ciphersuite::*;
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
|
|
||||||
use tendermint::{
|
use tendermint::{
|
||||||
time::CanonicalInstant,
|
time::CanonicalInstant,
|
||||||
round::RoundData,
|
round::RoundData,
|
||||||
@@ -52,7 +50,10 @@ async fn invalid_valid_round() {
|
|||||||
async move {
|
async move {
|
||||||
let data = Data::Proposal(valid_round, TendermintBlock(vec![]));
|
let data = Data::Proposal(valid_round, TendermintBlock(vec![]));
|
||||||
let signed = signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, data).await;
|
let signed = signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, data).await;
|
||||||
(signed.clone(), TendermintTx::SlashEvidence(Evidence::InvalidValidRound(signed.encode())))
|
(
|
||||||
|
signed.clone(),
|
||||||
|
TendermintTx::SlashEvidence(Evidence::InvalidValidRound(borsh::to_vec(&signed).unwrap())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,7 +71,8 @@ async fn invalid_valid_round() {
|
|||||||
let mut random_sig = [0u8; 64];
|
let mut random_sig = [0u8; 64];
|
||||||
OsRng.fill_bytes(&mut random_sig);
|
OsRng.fill_bytes(&mut random_sig);
|
||||||
signed.sig = random_sig;
|
signed.sig = random_sig;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::InvalidValidRound(signed.encode()));
|
let tx =
|
||||||
|
TendermintTx::SlashEvidence(Evidence::InvalidValidRound(borsh::to_vec(&signed).unwrap()));
|
||||||
|
|
||||||
// should fail
|
// should fail
|
||||||
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
||||||
@@ -90,7 +92,10 @@ async fn invalid_precommit_signature() {
|
|||||||
let signed =
|
let signed =
|
||||||
signed_from_data::<N>(signer.clone().into(), signer_id, 1, 0, Data::Precommit(precommit))
|
signed_from_data::<N>(signer.clone().into(), signer_id, 1, 0, Data::Precommit(precommit))
|
||||||
.await;
|
.await;
|
||||||
(signed.clone(), TendermintTx::SlashEvidence(Evidence::InvalidPrecommit(signed.encode())))
|
(
|
||||||
|
signed.clone(),
|
||||||
|
TendermintTx::SlashEvidence(Evidence::InvalidPrecommit(borsh::to_vec(&signed).unwrap())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -120,7 +125,8 @@ async fn invalid_precommit_signature() {
|
|||||||
let mut random_sig = [0u8; 64];
|
let mut random_sig = [0u8; 64];
|
||||||
OsRng.fill_bytes(&mut random_sig);
|
OsRng.fill_bytes(&mut random_sig);
|
||||||
signed.sig = random_sig;
|
signed.sig = random_sig;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::InvalidPrecommit(signed.encode()));
|
let tx =
|
||||||
|
TendermintTx::SlashEvidence(Evidence::InvalidPrecommit(borsh::to_vec(&signed).unwrap()));
|
||||||
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,24 +144,32 @@ async fn evidence_with_prevote() {
|
|||||||
// it should fail for all reasons.
|
// it should fail for all reasons.
|
||||||
let mut txs = vec![];
|
let mut txs = vec![];
|
||||||
txs.push(TendermintTx::SlashEvidence(Evidence::InvalidPrecommit(
|
txs.push(TendermintTx::SlashEvidence(Evidence::InvalidPrecommit(
|
||||||
signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, Data::Prevote(block_id))
|
borsh::to_vec(
|
||||||
.await
|
&&signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, Data::Prevote(block_id))
|
||||||
.encode(),
|
.await,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
)));
|
)));
|
||||||
txs.push(TendermintTx::SlashEvidence(Evidence::InvalidValidRound(
|
txs.push(TendermintTx::SlashEvidence(Evidence::InvalidValidRound(
|
||||||
signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, Data::Prevote(block_id))
|
borsh::to_vec(
|
||||||
.await
|
&signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, Data::Prevote(block_id))
|
||||||
.encode(),
|
.await,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
)));
|
)));
|
||||||
// Since these require a second message, provide this one again
|
// Since these require a second message, provide this one again
|
||||||
// ConflictingMessages can be fired for actually conflicting Prevotes however
|
// ConflictingMessages can be fired for actually conflicting Prevotes however
|
||||||
txs.push(TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
txs.push(TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, Data::Prevote(block_id))
|
borsh::to_vec(
|
||||||
.await
|
&signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, Data::Prevote(block_id))
|
||||||
.encode(),
|
.await,
|
||||||
signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, Data::Prevote(block_id))
|
)
|
||||||
.await
|
.unwrap(),
|
||||||
.encode(),
|
borsh::to_vec(
|
||||||
|
&signed_from_data::<N>(signer.clone().into(), signer_id, 0, 0, Data::Prevote(block_id))
|
||||||
|
.await,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
)));
|
)));
|
||||||
txs
|
txs
|
||||||
}
|
}
|
||||||
@@ -189,16 +203,16 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
// non-conflicting data should fail
|
// non-conflicting data should fail
|
||||||
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x11]))).await;
|
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x11]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
));
|
));
|
||||||
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
||||||
|
|
||||||
// conflicting data should pass
|
// conflicting data should pass
|
||||||
let signed_2 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
|
let signed_2 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_2.encode(),
|
borsh::to_vec(&signed_2).unwrap(),
|
||||||
));
|
));
|
||||||
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap();
|
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap();
|
||||||
|
|
||||||
@@ -206,16 +220,16 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
// (except for Precommit)
|
// (except for Precommit)
|
||||||
let signed_2 = signed_for_b_r(0, 1, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
|
let signed_2 = signed_for_b_r(0, 1, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_2.encode(),
|
borsh::to_vec(&signed_2).unwrap(),
|
||||||
));
|
));
|
||||||
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap_err();
|
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap_err();
|
||||||
|
|
||||||
// Proposals for different block numbers should also fail as evidence
|
// Proposals for different block numbers should also fail as evidence
|
||||||
let signed_2 = signed_for_b_r(1, 0, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
|
let signed_2 = signed_for_b_r(1, 0, Data::Proposal(None, TendermintBlock(vec![0x22]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_2.encode(),
|
borsh::to_vec(&signed_2).unwrap(),
|
||||||
));
|
));
|
||||||
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap_err();
|
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap_err();
|
||||||
}
|
}
|
||||||
@@ -225,16 +239,16 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
// non-conflicting data should fail
|
// non-conflicting data should fail
|
||||||
let signed_1 = signed_for_b_r(0, 0, Data::Prevote(Some([0x11; 32]))).await;
|
let signed_1 = signed_for_b_r(0, 0, Data::Prevote(Some([0x11; 32]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
));
|
));
|
||||||
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
||||||
|
|
||||||
// conflicting data should pass
|
// conflicting data should pass
|
||||||
let signed_2 = signed_for_b_r(0, 0, Data::Prevote(Some([0x22; 32]))).await;
|
let signed_2 = signed_for_b_r(0, 0, Data::Prevote(Some([0x22; 32]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_2.encode(),
|
borsh::to_vec(&signed_2).unwrap(),
|
||||||
));
|
));
|
||||||
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap();
|
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap();
|
||||||
|
|
||||||
@@ -242,16 +256,16 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
// (except for Precommit)
|
// (except for Precommit)
|
||||||
let signed_2 = signed_for_b_r(0, 1, Data::Prevote(Some([0x22; 32]))).await;
|
let signed_2 = signed_for_b_r(0, 1, Data::Prevote(Some([0x22; 32]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_2.encode(),
|
borsh::to_vec(&signed_2).unwrap(),
|
||||||
));
|
));
|
||||||
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap_err();
|
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap_err();
|
||||||
|
|
||||||
// Proposals for different block numbers should also fail as evidence
|
// Proposals for different block numbers should also fail as evidence
|
||||||
let signed_2 = signed_for_b_r(1, 0, Data::Prevote(Some([0x22; 32]))).await;
|
let signed_2 = signed_for_b_r(1, 0, Data::Prevote(Some([0x22; 32]))).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_2.encode(),
|
borsh::to_vec(&signed_2).unwrap(),
|
||||||
));
|
));
|
||||||
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap_err();
|
verify_tendermint_tx::<N>(&tx, &validators, commit).unwrap_err();
|
||||||
}
|
}
|
||||||
@@ -273,8 +287,8 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_2.encode(),
|
borsh::to_vec(&signed_2).unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
// update schema so that we don't fail due to invalid signature
|
// update schema so that we don't fail due to invalid signature
|
||||||
@@ -292,8 +306,8 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![]))).await;
|
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![]))).await;
|
||||||
let signed_2 = signed_for_b_r(0, 0, Data::Prevote(None)).await;
|
let signed_2 = signed_for_b_r(0, 0, Data::Prevote(None)).await;
|
||||||
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
let tx = TendermintTx::SlashEvidence(Evidence::ConflictingMessages(
|
||||||
signed_1.encode(),
|
borsh::to_vec(&signed_1).unwrap(),
|
||||||
signed_2.encode(),
|
borsh::to_vec(&signed_2).unwrap(),
|
||||||
));
|
));
|
||||||
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
assert!(verify_tendermint_tx::<N>(&tx, &validators, commit).is_err());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ thiserror = { version = "2", default-features = false, features = ["std"] }
|
|||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
parity-scale-codec = { version = "3", default-features = false, features = ["std", "derive"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
futures-util = { version = "0.3", default-features = false, features = ["std", "async-await-macro", "sink", "channel"] }
|
futures-util = { version = "0.3", default-features = false, features = ["std", "async-await-macro", "sink", "channel"] }
|
||||||
futures-channel = { version = "0.3", default-features = false, features = ["std", "sink"] }
|
futures-channel = { version = "0.3", default-features = false, features = ["std", "sink"] }
|
||||||
|
|||||||
@@ -3,33 +3,41 @@ use std::{sync::Arc, collections::HashSet};
|
|||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use parity_scale_codec::{Encode, Decode};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use crate::{SignedMessageFor, SlashEvent, commit_msg};
|
use crate::{SignedMessageFor, SlashEvent, commit_msg};
|
||||||
|
|
||||||
/// An alias for a series of traits required for a type to be usable as a validator ID,
|
/// An alias for a series of traits required for a type to be usable as a validator ID,
|
||||||
/// automatically implemented for all types satisfying those traits.
|
/// automatically implemented for all types satisfying those traits.
|
||||||
pub trait ValidatorId:
|
pub trait ValidatorId:
|
||||||
Send + Sync + Clone + Copy + PartialEq + Eq + Hash + Debug + Encode + Decode
|
Send + Sync + Clone + Copy + PartialEq + Eq + Hash + Debug + BorshSerialize + BorshDeserialize
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
impl<V: Send + Sync + Clone + Copy + PartialEq + Eq + Hash + Debug + Encode + Decode> ValidatorId
|
#[rustfmt::skip]
|
||||||
for V
|
impl<
|
||||||
|
V: Send + Sync + Clone + Copy + PartialEq + Eq + Hash + Debug + BorshSerialize + BorshDeserialize,
|
||||||
|
> ValidatorId for V
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An alias for a series of traits required for a type to be usable as a signature,
|
/// An alias for a series of traits required for a type to be usable as a signature,
|
||||||
/// automatically implemented for all types satisfying those traits.
|
/// automatically implemented for all types satisfying those traits.
|
||||||
pub trait Signature: Send + Sync + Clone + PartialEq + Eq + Debug + Encode + Decode {}
|
pub trait Signature:
|
||||||
impl<S: Send + Sync + Clone + PartialEq + Eq + Debug + Encode + Decode> Signature for S {}
|
Send + Sync + Clone + PartialEq + Eq + Debug + BorshSerialize + BorshDeserialize
|
||||||
|
{
|
||||||
|
}
|
||||||
|
impl<S: Send + Sync + Clone + PartialEq + Eq + Debug + BorshSerialize + BorshDeserialize> Signature
|
||||||
|
for S
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Type aliases which are distinct according to the type system
|
// Type aliases which are distinct according to the type system
|
||||||
|
|
||||||
/// A struct containing a Block Number, wrapped to have a distinct type.
|
/// A struct containing a Block Number, wrapped to have a distinct type.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct BlockNumber(pub u64);
|
pub struct BlockNumber(pub u64);
|
||||||
/// A struct containing a round number, wrapped to have a distinct type.
|
/// A struct containing a round number, wrapped to have a distinct type.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct RoundNumber(pub u32);
|
pub struct RoundNumber(pub u32);
|
||||||
|
|
||||||
/// A signer for a validator.
|
/// A signer for a validator.
|
||||||
@@ -127,7 +135,7 @@ impl<S: SignatureScheme> SignatureScheme for Arc<S> {
|
|||||||
/// A commit for a specific block.
|
/// A commit for a specific block.
|
||||||
///
|
///
|
||||||
/// The list of validators have weight exceeding the threshold for a valid commit.
|
/// The list of validators have weight exceeding the threshold for a valid commit.
|
||||||
#[derive(PartialEq, Debug, Encode, Decode)]
|
#[derive(PartialEq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct Commit<S: SignatureScheme> {
|
pub struct Commit<S: SignatureScheme> {
|
||||||
/// End time of the round which created this commit, used as the start time of the next block.
|
/// End time of the round which created this commit, used as the start time of the next block.
|
||||||
pub end_time: u64,
|
pub end_time: u64,
|
||||||
@@ -185,7 +193,7 @@ impl<W: Weights> Weights for Arc<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Simplified error enum representing a block's validity.
|
/// Simplified error enum representing a block's validity.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Error, Encode, Decode)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Error, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum BlockError {
|
pub enum BlockError {
|
||||||
/// Malformed block which is wholly invalid.
|
/// Malformed block which is wholly invalid.
|
||||||
#[error("invalid block")]
|
#[error("invalid block")]
|
||||||
@@ -197,9 +205,20 @@ pub enum BlockError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Trait representing a Block.
|
/// Trait representing a Block.
|
||||||
pub trait Block: Send + Sync + Clone + PartialEq + Eq + Debug + Encode + Decode {
|
pub trait Block:
|
||||||
|
Send + Sync + Clone + PartialEq + Eq + Debug + BorshSerialize + BorshDeserialize
|
||||||
|
{
|
||||||
// Type used to identify blocks. Presumably a cryptographic hash of the block.
|
// Type used to identify blocks. Presumably a cryptographic hash of the block.
|
||||||
type Id: Send + Sync + Copy + Clone + PartialEq + Eq + AsRef<[u8]> + Debug + Encode + Decode;
|
type Id: Send
|
||||||
|
+ Sync
|
||||||
|
+ Copy
|
||||||
|
+ Clone
|
||||||
|
+ PartialEq
|
||||||
|
+ Eq
|
||||||
|
+ AsRef<[u8]>
|
||||||
|
+ Debug
|
||||||
|
+ BorshSerialize
|
||||||
|
+ BorshDeserialize;
|
||||||
|
|
||||||
/// Return the deterministic, unique ID for this block.
|
/// Return the deterministic, unique ID for this block.
|
||||||
fn id(&self) -> Self::Id;
|
fn id(&self) -> Self::Id;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::{
|
|||||||
collections::{VecDeque, HashMap},
|
collections::{VecDeque, HashMap},
|
||||||
};
|
};
|
||||||
|
|
||||||
use parity_scale_codec::{Encode, Decode, IoReader};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use futures_channel::mpsc;
|
use futures_channel::mpsc;
|
||||||
use futures_util::{
|
use futures_util::{
|
||||||
@@ -41,14 +41,14 @@ pub fn commit_msg(end_time: u64, id: &[u8]) -> Vec<u8> {
|
|||||||
[&end_time.to_le_bytes(), id].concat()
|
[&end_time.to_le_bytes(), id].concat()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum Step {
|
pub enum Step {
|
||||||
Propose,
|
Propose,
|
||||||
Prevote,
|
Prevote,
|
||||||
Precommit,
|
Precommit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum Data<B: Block, S: Signature> {
|
pub enum Data<B: Block, S: Signature> {
|
||||||
Proposal(Option<RoundNumber>, B),
|
Proposal(Option<RoundNumber>, B),
|
||||||
Prevote(Option<B::Id>),
|
Prevote(Option<B::Id>),
|
||||||
@@ -90,7 +90,7 @@ impl<B: Block, S: Signature> Data<B, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct Message<V: ValidatorId, B: Block, S: Signature> {
|
pub struct Message<V: ValidatorId, B: Block, S: Signature> {
|
||||||
pub sender: V,
|
pub sender: V,
|
||||||
pub block: BlockNumber,
|
pub block: BlockNumber,
|
||||||
@@ -100,7 +100,7 @@ pub struct Message<V: ValidatorId, B: Block, S: Signature> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A signed Tendermint consensus message to be broadcast to the other validators.
|
/// A signed Tendermint consensus message to be broadcast to the other validators.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct SignedMessage<V: ValidatorId, B: Block, S: Signature> {
|
pub struct SignedMessage<V: ValidatorId, B: Block, S: Signature> {
|
||||||
pub msg: Message<V, B, S>,
|
pub msg: Message<V, B, S>,
|
||||||
pub sig: S,
|
pub sig: S,
|
||||||
@@ -117,18 +117,18 @@ impl<V: ValidatorId, B: Block, S: Signature> SignedMessage<V, B, S> {
|
|||||||
&self,
|
&self,
|
||||||
signer: &Scheme,
|
signer: &Scheme,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
signer.verify(self.msg.sender, &self.msg.encode(), &self.sig)
|
signer.verify(self.msg.sender, &borsh::to_vec(&self.msg).unwrap(), &self.sig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum SlashReason {
|
pub enum SlashReason {
|
||||||
FailToPropose,
|
FailToPropose,
|
||||||
InvalidBlock,
|
InvalidBlock,
|
||||||
InvalidProposer,
|
InvalidProposer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum Evidence {
|
pub enum Evidence {
|
||||||
ConflictingMessages(Vec<u8>, Vec<u8>),
|
ConflictingMessages(Vec<u8>, Vec<u8>),
|
||||||
InvalidPrecommit(Vec<u8>),
|
InvalidPrecommit(Vec<u8>),
|
||||||
@@ -159,7 +159,7 @@ pub type SignedMessageFor<N> = SignedMessage<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
pub fn decode_signed_message<N: Network>(mut data: &[u8]) -> Option<SignedMessageFor<N>> {
|
pub fn decode_signed_message<N: Network>(mut data: &[u8]) -> Option<SignedMessageFor<N>> {
|
||||||
SignedMessageFor::<N>::decode(&mut data).ok()
|
SignedMessageFor::<N>::deserialize_reader(&mut data).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_and_verify_signed_message<N: Network>(
|
fn decode_and_verify_signed_message<N: Network>(
|
||||||
@@ -339,7 +339,7 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
target: "tendermint",
|
target: "tendermint",
|
||||||
"proposer for block {}, round {round:?} was {} (me: {res})",
|
"proposer for block {}, round {round:?} was {} (me: {res})",
|
||||||
self.block.number.0,
|
self.block.number.0,
|
||||||
hex::encode(proposer.encode()),
|
hex::encode(borsh::to_vec(&proposer).unwrap()),
|
||||||
);
|
);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@@ -420,7 +420,11 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
// TODO: If the new slash event has evidence, emit to prevent a low-importance slash from
|
// TODO: If the new slash event has evidence, emit to prevent a low-importance slash from
|
||||||
// cancelling emission of high-importance slashes
|
// cancelling emission of high-importance slashes
|
||||||
if !self.block.slashes.contains(&validator) {
|
if !self.block.slashes.contains(&validator) {
|
||||||
log::info!(target: "tendermint", "Slashing validator {}", hex::encode(validator.encode()));
|
log::info!(
|
||||||
|
target: "tendermint",
|
||||||
|
"Slashing validator {}",
|
||||||
|
hex::encode(borsh::to_vec(&validator).unwrap()),
|
||||||
|
);
|
||||||
self.block.slashes.insert(validator);
|
self.block.slashes.insert(validator);
|
||||||
self.network.slash(validator, slash_event).await;
|
self.network.slash(validator, slash_event).await;
|
||||||
}
|
}
|
||||||
@@ -670,7 +674,7 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
self
|
self
|
||||||
.slash(
|
.slash(
|
||||||
msg.sender,
|
msg.sender,
|
||||||
SlashEvent::WithEvidence(Evidence::InvalidPrecommit(signed.encode())),
|
SlashEvent::WithEvidence(Evidence::InvalidPrecommit(borsh::to_vec(&signed).unwrap())),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
Err(TendermintError::Malicious)?;
|
Err(TendermintError::Malicious)?;
|
||||||
@@ -741,7 +745,10 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
self.broadcast(Data::Prevote(None));
|
self.broadcast(Data::Prevote(None));
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
.slash(msg.sender, SlashEvent::WithEvidence(Evidence::InvalidValidRound(msg.encode())))
|
.slash(
|
||||||
|
msg.sender,
|
||||||
|
SlashEvent::WithEvidence(Evidence::InvalidValidRound(borsh::to_vec(&msg).unwrap())),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
Err(TendermintError::Malicious)?;
|
Err(TendermintError::Malicious)?;
|
||||||
}
|
}
|
||||||
@@ -1032,7 +1039,7 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
|
|
||||||
while !messages.is_empty() {
|
while !messages.is_empty() {
|
||||||
self.network.broadcast(
|
self.network.broadcast(
|
||||||
SignedMessageFor::<N>::decode(&mut IoReader(&mut messages))
|
SignedMessageFor::<N>::deserialize_reader(&mut messages)
|
||||||
.expect("saved invalid message to DB")
|
.expect("saved invalid message to DB")
|
||||||
).await;
|
).await;
|
||||||
}
|
}
|
||||||
@@ -1057,7 +1064,7 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
} {
|
} {
|
||||||
if our_message {
|
if our_message {
|
||||||
assert!(sig.is_none());
|
assert!(sig.is_none());
|
||||||
sig = Some(self.signer.sign(&msg.encode()).await);
|
sig = Some(self.signer.sign(&borsh::to_vec(&msg).unwrap()).await);
|
||||||
}
|
}
|
||||||
let sig = sig.unwrap();
|
let sig = sig.unwrap();
|
||||||
|
|
||||||
@@ -1077,7 +1084,7 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
let message_tape_key = message_tape_key(self.genesis);
|
let message_tape_key = message_tape_key(self.genesis);
|
||||||
let mut txn = self.db.txn();
|
let mut txn = self.db.txn();
|
||||||
let mut message_tape = txn.get(&message_tape_key).unwrap_or(vec![]);
|
let mut message_tape = txn.get(&message_tape_key).unwrap_or(vec![]);
|
||||||
message_tape.extend(signed_msg.encode());
|
signed_msg.serialize(&mut message_tape).unwrap();
|
||||||
txn.put(&message_tape_key, message_tape);
|
txn.put(&message_tape_key, message_tape);
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use std::{sync::Arc, collections::HashMap};
|
use std::{sync::Arc, collections::HashMap};
|
||||||
|
|
||||||
use parity_scale_codec::Encode;
|
|
||||||
|
|
||||||
use crate::{ext::*, RoundNumber, Step, DataFor, SignedMessageFor, Evidence};
|
use crate::{ext::*, RoundNumber, Step, DataFor, SignedMessageFor, Evidence};
|
||||||
|
|
||||||
type RoundLog<N> = HashMap<<N as Network>::ValidatorId, HashMap<Step, SignedMessageFor<N>>>;
|
type RoundLog<N> = HashMap<<N as Network>::ValidatorId, HashMap<Step, SignedMessageFor<N>>>;
|
||||||
@@ -39,7 +37,10 @@ impl<N: Network> MessageLog<N> {
|
|||||||
target: "tendermint",
|
target: "tendermint",
|
||||||
"Validator sent multiple messages for the same block + round + step"
|
"Validator sent multiple messages for the same block + round + step"
|
||||||
);
|
);
|
||||||
Err(Evidence::ConflictingMessages(existing.encode(), signed.encode()))?;
|
Err(Evidence::ConflictingMessages(
|
||||||
|
borsh::to_vec(&existing).unwrap(),
|
||||||
|
borsh::to_vec(&signed).unwrap(),
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::{
|
|||||||
time::{UNIX_EPOCH, SystemTime, Duration},
|
time::{UNIX_EPOCH, SystemTime, Duration},
|
||||||
};
|
};
|
||||||
|
|
||||||
use parity_scale_codec::{Encode, Decode};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use futures_util::sink::SinkExt;
|
use futures_util::sink::SinkExt;
|
||||||
use tokio::{sync::RwLock, time::sleep};
|
use tokio::{sync::RwLock, time::sleep};
|
||||||
@@ -89,7 +89,7 @@ impl Weights for TestWeights {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
struct TestBlock {
|
struct TestBlock {
|
||||||
id: TestBlockId,
|
id: TestBlockId,
|
||||||
valid: Result<(), BlockError>,
|
valid: Result<(), BlockError>,
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ workspace = true
|
|||||||
zeroize = { version = "^1.5", default-features = false, features = ["std"] }
|
zeroize = { version = "^1.5", default-features = false, features = ["std"] }
|
||||||
rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std", "derive"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
||||||
@@ -30,7 +29,7 @@ dalek-ff-group = { path = "../../crypto/dalek-ff-group", default-features = fals
|
|||||||
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std"] }
|
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std"] }
|
||||||
schnorr = { package = "schnorr-signatures", path = "../../crypto/schnorr", default-features = false, features = ["std"] }
|
schnorr = { package = "schnorr-signatures", path = "../../crypto/schnorr", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
serai-client = { path = "../../substrate/client", default-features = false, features = ["serai", "borsh"] }
|
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
serai-db = { path = "../../common/db" }
|
serai-db = { path = "../../common/db" }
|
||||||
serai-task = { path = "../../common/task", version = "0.1" }
|
serai-task = { path = "../../common/task", version = "0.1" }
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_client::{primitives::SeraiAddress, validator_sets::primitives::ExternalValidatorSet};
|
use serai_primitives::{address::SeraiAddress, validator_sets::primitives::ExternalValidatorSet};
|
||||||
|
|
||||||
use messages::sign::{VariantSignId, SignId};
|
use messages::sign::{VariantSignId, SignId};
|
||||||
|
|
||||||
@@ -14,7 +13,7 @@ use serai_cosign::CosignIntent;
|
|||||||
use crate::transaction::SigningProtocolRound;
|
use crate::transaction::SigningProtocolRound;
|
||||||
|
|
||||||
/// A topic within the database which the group participates in
|
/// A topic within the database which the group participates in
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum Topic {
|
pub enum Topic {
|
||||||
/// Vote to remove a participant
|
/// Vote to remove a participant
|
||||||
RemoveParticipant {
|
RemoveParticipant {
|
||||||
@@ -123,7 +122,7 @@ impl Topic {
|
|||||||
Topic::DkgConfirmation { attempt, round: _ } => Some({
|
Topic::DkgConfirmation { attempt, round: _ } => Some({
|
||||||
let id = {
|
let id = {
|
||||||
let mut id = [0; 32];
|
let mut id = [0; 32];
|
||||||
let encoded_set = set.encode();
|
let encoded_set = borsh::to_vec(set).unwrap();
|
||||||
id[.. encoded_set.len()].copy_from_slice(&encoded_set);
|
id[.. encoded_set.len()].copy_from_slice(&encoded_set);
|
||||||
VariantSignId::Batch(id)
|
VariantSignId::Batch(id)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ use std::collections::HashMap;
|
|||||||
use ciphersuite::group::GroupEncoding;
|
use ciphersuite::group::GroupEncoding;
|
||||||
use dkg::Participant;
|
use dkg::Participant;
|
||||||
|
|
||||||
use serai_client::{
|
use serai_primitives::{
|
||||||
primitives::SeraiAddress,
|
address::SeraiAddress,
|
||||||
validator_sets::primitives::{ExternalValidatorSet, Slash},
|
validator_sets::{ExternalValidatorSet, Slash},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serai_db::*;
|
use serai_db::*;
|
||||||
|
|||||||
@@ -12,10 +12,9 @@ use ciphersuite::{
|
|||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use schnorr::SchnorrSignature;
|
use schnorr::SchnorrSignature;
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_client::{primitives::SeraiAddress, validator_sets::primitives::MAX_KEY_SHARES_PER_SET};
|
use serai_primitives::{addess::SeraiAddress, validator_sets::MAX_KEY_SHARES_PER_SET};
|
||||||
|
|
||||||
use messages::sign::VariantSignId;
|
use messages::sign::VariantSignId;
|
||||||
|
|
||||||
@@ -29,7 +28,7 @@ use tributary_sdk::{
|
|||||||
use crate::db::Topic;
|
use crate::db::Topic;
|
||||||
|
|
||||||
/// The round this data is for, within a signing protocol.
|
/// The round this data is for, within a signing protocol.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum SigningProtocolRound {
|
pub enum SigningProtocolRound {
|
||||||
/// A preprocess.
|
/// A preprocess.
|
||||||
Preprocess,
|
Preprocess,
|
||||||
@@ -242,19 +241,20 @@ impl TransactionTrait for Transaction {
|
|||||||
fn kind(&self) -> TransactionKind {
|
fn kind(&self) -> TransactionKind {
|
||||||
match self {
|
match self {
|
||||||
Transaction::RemoveParticipant { participant, signed } => TransactionKind::Signed(
|
Transaction::RemoveParticipant { participant, signed } => TransactionKind::Signed(
|
||||||
(b"RemoveParticipant", participant).encode(),
|
borsh::to_vec(&(b"RemoveParticipant".as_slice(), participant)).unwrap(),
|
||||||
signed.to_tributary_signed(0),
|
signed.to_tributary_signed(0),
|
||||||
),
|
),
|
||||||
|
|
||||||
Transaction::DkgParticipation { signed, .. } => {
|
Transaction::DkgParticipation { signed, .. } => TransactionKind::Signed(
|
||||||
TransactionKind::Signed(b"DkgParticipation".encode(), signed.to_tributary_signed(0))
|
borsh::to_vec(b"DkgParticipation".as_slice()).unwrap(),
|
||||||
}
|
signed.to_tributary_signed(0),
|
||||||
|
),
|
||||||
Transaction::DkgConfirmationPreprocess { attempt, signed, .. } => TransactionKind::Signed(
|
Transaction::DkgConfirmationPreprocess { attempt, signed, .. } => TransactionKind::Signed(
|
||||||
(b"DkgConfirmation", attempt).encode(),
|
borsh::to_vec(b"DkgConfirmation".as_slice(), attempt).unwrap(),
|
||||||
signed.to_tributary_signed(0),
|
signed.to_tributary_signed(0),
|
||||||
),
|
),
|
||||||
Transaction::DkgConfirmationShare { attempt, signed, .. } => TransactionKind::Signed(
|
Transaction::DkgConfirmationShare { attempt, signed, .. } => TransactionKind::Signed(
|
||||||
(b"DkgConfirmation", attempt).encode(),
|
borsh::to_vec(b"DkgConfirmation".as_slice(), attempt).unwrap(),
|
||||||
signed.to_tributary_signed(1),
|
signed.to_tributary_signed(1),
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -264,13 +264,14 @@ impl TransactionTrait for Transaction {
|
|||||||
Transaction::Batch { .. } => TransactionKind::Provided("Batch"),
|
Transaction::Batch { .. } => TransactionKind::Provided("Batch"),
|
||||||
|
|
||||||
Transaction::Sign { id, attempt, round, signed, .. } => TransactionKind::Signed(
|
Transaction::Sign { id, attempt, round, signed, .. } => TransactionKind::Signed(
|
||||||
(b"Sign", id, attempt).encode(),
|
borsh::to_vec(b"Sign".as_slice(), id, attempt).unwrap(),
|
||||||
signed.to_tributary_signed(round.nonce()),
|
signed.to_tributary_signed(round.nonce()),
|
||||||
),
|
),
|
||||||
|
|
||||||
Transaction::SlashReport { signed, .. } => {
|
Transaction::SlashReport { signed, .. } => TransactionKind::Signed(
|
||||||
TransactionKind::Signed(b"SlashReport".encode(), signed.to_tributary_signed(0))
|
borsh::to_vec(b"SlashReport".as_slice()).unwrap(),
|
||||||
}
|
signed.to_tributary_signed(0),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
deny.toml
14
deny.toml
@@ -7,11 +7,9 @@ db-urls = ["https://github.com/rustsec/advisory-db"]
|
|||||||
yanked = "deny"
|
yanked = "deny"
|
||||||
|
|
||||||
ignore = [
|
ignore = [
|
||||||
"RUSTSEC-2020-0168", # mach is unmaintained
|
|
||||||
"RUSTSEC-2021-0139", # https://github.com/serai-dex/serai/228
|
|
||||||
"RUSTSEC-2022-0061", # https://github.com/serai-dex/serai/227
|
"RUSTSEC-2022-0061", # https://github.com/serai-dex/serai/227
|
||||||
"RUSTSEC-2024-0370", # proc-macro-error is unmaintained
|
"RUSTSEC-2024-0370", # proc-macro-error is unmaintained
|
||||||
"RUSTSEC-2024-0384", # instant is unmaintained
|
"RUSTSEC-2024-0436", # paste is unmaintained
|
||||||
]
|
]
|
||||||
|
|
||||||
[licenses]
|
[licenses]
|
||||||
@@ -30,10 +28,10 @@ allow = [
|
|||||||
"ISC",
|
"ISC",
|
||||||
"Zlib",
|
"Zlib",
|
||||||
"Unicode-3.0",
|
"Unicode-3.0",
|
||||||
"OpenSSL",
|
"CDLA-Permissive-2.0",
|
||||||
|
|
||||||
# Non-invasive copyleft
|
# Non-invasive copyleft
|
||||||
"MPL-2.0",
|
# "MPL-2.0", # Commented as it's not currently in-use within the Serai tree
|
||||||
"Apache-2.0",
|
"Apache-2.0",
|
||||||
"Apache-2.0 WITH LLVM-exception",
|
"Apache-2.0 WITH LLVM-exception",
|
||||||
"GPL-3.0 WITH Classpath-exception-2.0",
|
"GPL-3.0 WITH Classpath-exception-2.0",
|
||||||
@@ -73,6 +71,7 @@ exceptions = [
|
|||||||
{ allow = ["AGPL-3.0"], name = "serai-monero-processor" },
|
{ allow = ["AGPL-3.0"], name = "serai-monero-processor" },
|
||||||
|
|
||||||
{ allow = ["AGPL-3.0"], name = "tributary-sdk" },
|
{ allow = ["AGPL-3.0"], name = "tributary-sdk" },
|
||||||
|
{ allow = ["AGPL-3.0"], name = "serai-cosign-types" },
|
||||||
{ allow = ["AGPL-3.0"], name = "serai-cosign" },
|
{ allow = ["AGPL-3.0"], name = "serai-cosign" },
|
||||||
{ allow = ["AGPL-3.0"], name = "serai-coordinator-substrate" },
|
{ allow = ["AGPL-3.0"], name = "serai-coordinator-substrate" },
|
||||||
{ allow = ["AGPL-3.0"], name = "serai-coordinator-tributary" },
|
{ allow = ["AGPL-3.0"], name = "serai-coordinator-tributary" },
|
||||||
@@ -124,6 +123,8 @@ highlight = "all"
|
|||||||
deny = [
|
deny = [
|
||||||
{ name = "serde_derive", version = ">=1.0.172, <1.0.185" },
|
{ name = "serde_derive", version = ">=1.0.172, <1.0.185" },
|
||||||
{ name = "hashbrown", version = "=0.15.0" },
|
{ name = "hashbrown", version = "=0.15.0" },
|
||||||
|
# Legacy which _no one_ should use anymore
|
||||||
|
{ name = "is-terminal", version = "*" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[sources]
|
[sources]
|
||||||
@@ -132,10 +133,7 @@ unknown-git = "deny"
|
|||||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||||
allow-git = [
|
allow-git = [
|
||||||
"https://github.com/rust-lang-nursery/lazy-static.rs",
|
"https://github.com/rust-lang-nursery/lazy-static.rs",
|
||||||
"https://github.com/kayabaNerve/hybrid-array",
|
|
||||||
"https://github.com/kayabaNerve/elliptic-curves",
|
"https://github.com/kayabaNerve/elliptic-curves",
|
||||||
"https://github.com/monero-oxide/monero-oxide",
|
"https://github.com/monero-oxide/monero-oxide",
|
||||||
"https://github.com/serai-dex/substrate-bip39",
|
|
||||||
"https://github.com/serai-dex/substrate",
|
|
||||||
"https://github.com/serai-dex/patch-polkadot-sdk",
|
"https://github.com/serai-dex/patch-polkadot-sdk",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ serai-db = { path = "../common/db", optional = true }
|
|||||||
|
|
||||||
serai-env = { path = "../common/env" }
|
serai-env = { path = "../common/env" }
|
||||||
|
|
||||||
serai-primitives = { path = "../substrate/primitives", features = ["borsh"] }
|
serai-primitives = { path = "../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
parity-db = ["serai-db/parity-db"]
|
parity-db = ["serai-db/parity-db"]
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use dalek_ff_group::Ristretto;
|
|||||||
pub(crate) use ciphersuite::{group::GroupEncoding, WrappedGroup, GroupCanonicalEncoding};
|
pub(crate) use ciphersuite::{group::GroupEncoding, WrappedGroup, GroupCanonicalEncoding};
|
||||||
pub(crate) use schnorr_signatures::SchnorrSignature;
|
pub(crate) use schnorr_signatures::SchnorrSignature;
|
||||||
|
|
||||||
pub(crate) use serai_primitives::ExternalNetworkId;
|
pub(crate) use serai_primitives::network_id::ExternalNetworkId;
|
||||||
|
|
||||||
pub(crate) use tokio::{
|
pub(crate) use tokio::{
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
@@ -198,7 +198,7 @@ async fn main() {
|
|||||||
KEYS.write().unwrap().insert(service, key);
|
KEYS.write().unwrap().insert(service, key);
|
||||||
let mut queues = QUEUES.write().unwrap();
|
let mut queues = QUEUES.write().unwrap();
|
||||||
if service == Service::Coordinator {
|
if service == Service::Coordinator {
|
||||||
for network in serai_primitives::EXTERNAL_NETWORKS {
|
for network in ExternalNetworkId::all() {
|
||||||
queues.insert(
|
queues.insert(
|
||||||
(service, Service::Processor(network)),
|
(service, Service::Processor(network)),
|
||||||
RwLock::new(Queue(db.clone(), service, Service::Processor(network))),
|
RwLock::new(Queue(db.clone(), service, Service::Processor(network))),
|
||||||
@@ -213,12 +213,13 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Make queues for each ExternalNetworkId
|
// Make queues for each ExternalNetworkId
|
||||||
for network in serai_primitives::EXTERNAL_NETWORKS {
|
for network in ExternalNetworkId::all() {
|
||||||
// Use a match so we error if the list of NetworkIds changes
|
// Use a match so we error if the list of NetworkIds changes
|
||||||
let Some(key) = read_key(match network {
|
let Some(key) = read_key(match network {
|
||||||
ExternalNetworkId::Bitcoin => "BITCOIN_KEY",
|
ExternalNetworkId::Bitcoin => "BITCOIN_KEY",
|
||||||
ExternalNetworkId::Ethereum => "ETHEREUM_KEY",
|
ExternalNetworkId::Ethereum => "ETHEREUM_KEY",
|
||||||
ExternalNetworkId::Monero => "MONERO_KEY",
|
ExternalNetworkId::Monero => "MONERO_KEY",
|
||||||
|
_ => panic!("unrecognized network"),
|
||||||
}) else {
|
}) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use ciphersuite::{group::GroupEncoding, FromUniformBytes, WrappedGroup, WithPref
|
|||||||
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_primitives::ExternalNetworkId;
|
use serai_primitives::network_id::ExternalNetworkId;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum Service {
|
pub enum Service {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ RUN rm -rf /etc/apt/sources.list.d/debian.sources && \
|
|||||||
RUN apt update -y && apt upgrade -y && apt install -y clang
|
RUN apt update -y && apt upgrade -y && apt install -y clang
|
||||||
|
|
||||||
# Add the wasm toolchain
|
# Add the wasm toolchain
|
||||||
|
RUN rustup component add rust-src
|
||||||
RUN rustup target add wasm32v1-none
|
RUN rustup target add wasm32v1-none
|
||||||
|
|
||||||
FROM deterministic
|
FROM deterministic
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ RUN apt install -y pkg-config clang
|
|||||||
RUN apt install -y make protobuf-compiler
|
RUN apt install -y make protobuf-compiler
|
||||||
|
|
||||||
# Add the wasm toolchain
|
# Add the wasm toolchain
|
||||||
|
RUN rustup component add rust-src
|
||||||
RUN rustup target add wasm32v1-none
|
RUN rustup target add wasm32v1-none
|
||||||
|
|
||||||
{prelude}
|
{prelude}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "directories-next"
|
name = "directories-next"
|
||||||
version = "2.0.0"
|
version = "2.0.99"
|
||||||
description = "Patch from directories-next back to directories"
|
description = "Patch from directories-next back to directories"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/patches/directories-next"
|
repository = "https://github.com/serai-dex/serai/tree/develop/patches/directories-next"
|
||||||
@@ -13,4 +13,4 @@ all-features = true
|
|||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
directories = "5"
|
directories = "6"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "is-terminal"
|
name = "is_terminal_polyfill"
|
||||||
version = "0.4.10"
|
version = "1.70.1"
|
||||||
description = "is-terminal written around std::io::IsTerminal"
|
description = "is_terminal_polyfill written around std::io::IsTerminal"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/patches/is-terminal"
|
repository = "https://github.com/serai-dex/serai/tree/develop/patches/is_terminal_polyfill"
|
||||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
keywords = []
|
keywords = []
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "matches"
|
|
||||||
version = "0.1.10"
|
|
||||||
description = "Replacement for the matches polyfill which uses the std impl"
|
|
||||||
license = "MIT"
|
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/patches/matches"
|
|
||||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
|
||||||
keywords = []
|
|
||||||
edition = "2018"
|
|
||||||
rust-version = "1.42"
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub use std::matches;
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.11.2"
|
|
||||||
description = "parking_lot which patches to the latest update"
|
|
||||||
license = "MIT"
|
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/patches/parking_lot"
|
|
||||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
|
||||||
keywords = []
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
parking_lot = "0.12"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub use parking_lot::*;
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "rocksdb"
|
|
||||||
version = "0.21.0"
|
|
||||||
description = "rocksdb which patches to the latest update"
|
|
||||||
license = "MIT"
|
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/patches/rocksdb"
|
|
||||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
|
||||||
keywords = []
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
rocksdb = { version = "0.24", default-features = false, features = ["bindgen-runtime"] }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
jemalloc = [] # Dropped as this causes a compilation failure on windows
|
|
||||||
snappy = ["rocksdb/snappy"]
|
|
||||||
lz4 = ["rocksdb/lz4"]
|
|
||||||
zstd = ["rocksdb/zstd"]
|
|
||||||
zlib = ["rocksdb/zlib"]
|
|
||||||
bzip2 = ["rocksdb/bzip2"]
|
|
||||||
default = ["snappy", "lz4", "zstd", "zlib", "bzip2"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub use rocksdb::*;
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "zstd"
|
|
||||||
version = "0.11.2+zstd.1.5.2"
|
|
||||||
description = "zstd which patches to the latest update"
|
|
||||||
license = "MIT"
|
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/patches/zstd"
|
|
||||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
|
||||||
keywords = []
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
zstd = "0.13"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub use zstd::*;
|
|
||||||
@@ -20,14 +20,13 @@ workspace = true
|
|||||||
zeroize = { version = "1", default-features = false, features = ["std"] }
|
zeroize = { version = "1", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||||
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std"] }
|
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
serai-client = { path = "../../substrate/client", default-features = false }
|
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
serai-cosign = { path = "../../coordinator/cosign" }
|
serai-cosign = { package = "serai-cosign-types", path = "../../coordinator/cosign/types" }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
env_logger = { version = "0.10", default-features = false, features = ["humantime"] }
|
env_logger = { version = "0.10", default-features = false, features = ["humantime"] }
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ use std::sync::{LazyLock, Arc, Mutex};
|
|||||||
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
use serai_client::{
|
use serai_primitives::{
|
||||||
primitives::Signature,
|
crypto::Signature,
|
||||||
validator_sets::primitives::{Session, SlashReport},
|
validator_sets::{Session, SlashReport},
|
||||||
in_instructions::primitives::SignedBatch,
|
instructions::SignedBatch,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serai_cosign::SignedCosign;
|
use serai_cosign::SignedCosign;
|
||||||
@@ -34,7 +34,7 @@ static SEND_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
|
|||||||
|
|
||||||
db_channel! {
|
db_channel! {
|
||||||
ProcessorBinCoordinator {
|
ProcessorBinCoordinator {
|
||||||
SentCoordinatorMessages: () -> Vec<u8>,
|
SentCoordinatorMessages: () -> messages::ProcessorMessage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ impl CoordinatorSend {
|
|||||||
fn send(&mut self, msg: &messages::ProcessorMessage) {
|
fn send(&mut self, msg: &messages::ProcessorMessage) {
|
||||||
let _lock = SEND_LOCK.lock().unwrap();
|
let _lock = SEND_LOCK.lock().unwrap();
|
||||||
let mut txn = self.db.txn();
|
let mut txn = self.db.txn();
|
||||||
SentCoordinatorMessages::send(&mut txn, &borsh::to_vec(msg).unwrap());
|
SentCoordinatorMessages::send(&mut txn, msg);
|
||||||
txn.commit();
|
txn.commit();
|
||||||
self
|
self
|
||||||
.sent_message
|
.sent_message
|
||||||
@@ -114,12 +114,9 @@ impl Coordinator {
|
|||||||
let mut txn = db.txn();
|
let mut txn = db.txn();
|
||||||
match SentCoordinatorMessages::try_recv(&mut txn) {
|
match SentCoordinatorMessages::try_recv(&mut txn) {
|
||||||
Some(msg) => {
|
Some(msg) => {
|
||||||
let metadata = Metadata {
|
let metadata =
|
||||||
from: service,
|
Metadata { from: service, to: Service::Coordinator, intent: msg.intent() };
|
||||||
to: Service::Coordinator,
|
message_queue.queue_with_retry(metadata, borsh::to_vec(&msg).unwrap()).await;
|
||||||
intent: borsh::from_slice::<messages::ProcessorMessage>(&msg).unwrap().intent(),
|
|
||||||
};
|
|
||||||
message_queue.queue_with_retry(metadata, msg).await;
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use ciphersuite::{
|
|||||||
};
|
};
|
||||||
use dkg::Curves;
|
use dkg::Curves;
|
||||||
|
|
||||||
use serai_client::validator_sets::primitives::Session;
|
use serai_primitives::validator_sets::Session;
|
||||||
|
|
||||||
use serai_env as env;
|
use serai_env as env;
|
||||||
use serai_db::{Get, DbTxn, Db as DbTrait, create_db, db_channel};
|
use serai_db::{Get, DbTxn, Db as DbTrait, create_db, db_channel};
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ workspace = true
|
|||||||
rand_core = { version = "0.6", default-features = false }
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -10,12 +10,15 @@ use bitcoin_serai::{
|
|||||||
wallet::ReceivedOutput as WalletOutput,
|
wallet::ReceivedOutput as WalletOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
use scale::{Encode, Decode, IoReader};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use serai_db::Get;
|
use serai_db::Get;
|
||||||
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
primitives::{ExternalCoin, Amount, ExternalBalance, ExternalAddress},
|
primitives::{
|
||||||
|
coin::ExternalCoin,
|
||||||
|
balance::{Amount, ExternalBalance},
|
||||||
|
address::ExternalAddress,
|
||||||
|
},
|
||||||
networks::bitcoin::Address,
|
networks::bitcoin::Address,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -26,7 +29,7 @@ use crate::{
|
|||||||
scan::{offsets_for_key, presumed_origin, extract_serai_data},
|
scan::{offsets_for_key, presumed_origin, extract_serai_data},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Encode, Decode, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub(crate) struct OutputId([u8; 36]);
|
pub(crate) struct OutputId([u8; 36]);
|
||||||
impl Default for OutputId {
|
impl Default for OutputId {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@@ -139,7 +142,7 @@ impl ReceivedOutput<<Secp256k1 as WrappedGroup>::G, Address> for Output {
|
|||||||
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||||
self.kind.write(writer)?;
|
self.kind.write(writer)?;
|
||||||
let presumed_origin: Option<ExternalAddress> = self.presumed_origin.clone().map(Into::into);
|
let presumed_origin: Option<ExternalAddress> = self.presumed_origin.clone().map(Into::into);
|
||||||
writer.write_all(&presumed_origin.encode())?;
|
presumed_origin.serialize(writer)?;
|
||||||
self.output.write(writer)?;
|
self.output.write(writer)?;
|
||||||
writer.write_all(&u16::try_from(self.data.len()).unwrap().to_le_bytes())?;
|
writer.write_all(&u16::try_from(self.data.len()).unwrap().to_le_bytes())?;
|
||||||
writer.write_all(&self.data)
|
writer.write_all(&self.data)
|
||||||
@@ -149,7 +152,7 @@ impl ReceivedOutput<<Secp256k1 as WrappedGroup>::G, Address> for Output {
|
|||||||
Ok(Output {
|
Ok(Output {
|
||||||
kind: OutputType::read(reader)?,
|
kind: OutputType::read(reader)?,
|
||||||
presumed_origin: {
|
presumed_origin: {
|
||||||
Option::<ExternalAddress>::decode(&mut IoReader(&mut reader))
|
Option::<ExternalAddress>::deserialize_reader(&mut reader)
|
||||||
.map_err(|e| io::Error::other(format!("couldn't decode ExternalAddress: {e:?}")))?
|
.map_err(|e| io::Error::other(format!("couldn't decode ExternalAddress: {e:?}")))?
|
||||||
.map(|address| {
|
.map(|address| {
|
||||||
Address::try_from(address)
|
Address::try_from(address)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use core::future::Future;
|
|||||||
|
|
||||||
use bitcoin_serai::rpc::{RpcError, Rpc as BRpc};
|
use bitcoin_serai::rpc::{RpcError, Rpc as BRpc};
|
||||||
|
|
||||||
use serai_client::primitives::{ExternalNetworkId, ExternalCoin, Amount};
|
use serai_client::primitives::{network_id::ExternalNetworkId, coin::ExternalCoin, balance::Amount};
|
||||||
|
|
||||||
use serai_db::Db;
|
use serai_db::Db;
|
||||||
use scanner::ScannerFeed;
|
use scanner::ScannerFeed;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use bitcoin_serai::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
primitives::{ExternalCoin, Amount},
|
primitives::{coin::ExternalCoin, balance::Amount},
|
||||||
networks::bitcoin::Address,
|
networks::bitcoin::Address,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ rand_core = { version = "0.6", default-features = false }
|
|||||||
|
|
||||||
const-hex = { version = "1", default-features = false, features = ["std"] }
|
const-hex = { version = "1", default-features = false, features = ["std"] }
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ ethereum-primitives = { package = "serai-processor-ethereum-primitives", path =
|
|||||||
ethereum-deployer = { package = "serai-processor-ethereum-deployer", path = "../deployer", default-features = false }
|
ethereum-deployer = { package = "serai-processor-ethereum-deployer", path = "../deployer", default-features = false }
|
||||||
erc20 = { package = "serai-processor-ethereum-erc20", path = "../erc20", default-features = false }
|
erc20 = { package = "serai-processor-ethereum-erc20", path = "../erc20", default-features = false }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
serai-client = { path = "../../../substrate/client", default-features = false, features = ["ethereum"] }
|
serai-client = { path = "../../../substrate/client", default-features = false, features = ["ethereum"] }
|
||||||
|
|
||||||
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ interface IRouterWithoutCollisions {
|
|||||||
/// @param from The address which called `inInstruction` and caused this event to be emitted
|
/// @param from The address which called `inInstruction` and caused this event to be emitted
|
||||||
/// @param coin The coin transferred in
|
/// @param coin The coin transferred in
|
||||||
/// @param amount The amount of the coin transferred in
|
/// @param amount The amount of the coin transferred in
|
||||||
/// @param instruction The Shorthand-encoded InInstruction for Serai to decode and handle
|
/// @param instruction The encoded `RefundableInInstruction` for Serai to decode and handle
|
||||||
event InInstruction(
|
event InInstruction(
|
||||||
address indexed from, address indexed coin, uint256 amount, bytes instruction
|
address indexed from, address indexed coin, uint256 amount, bytes instruction
|
||||||
);
|
);
|
||||||
@@ -81,8 +81,8 @@ interface IRouterWithoutCollisions {
|
|||||||
/// @param coin The coin to transfer in (address(0) if Ether)
|
/// @param coin The coin to transfer in (address(0) if Ether)
|
||||||
/// @param amount The amount to transfer in (msg.value if Ether)
|
/// @param amount The amount to transfer in (msg.value if Ether)
|
||||||
/**
|
/**
|
||||||
* @param instruction The Shorthand-encoded InInstruction for Serai to associate with this
|
* @param instruction The encoded `RefundableInInstruction` for Serai to associate with this
|
||||||
* transfer in
|
* transfer in
|
||||||
*/
|
*/
|
||||||
// Re-entrancy doesn't bork this function
|
// Re-entrancy doesn't bork this function
|
||||||
// slither-disable-next-line reentrancy-events
|
// slither-disable-next-line reentrancy-events
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ contract Router is IRouterWithoutCollisions {
|
|||||||
/// @param coin The coin to transfer in (address(0) if Ether)
|
/// @param coin The coin to transfer in (address(0) if Ether)
|
||||||
/// @param amount The amount to transfer in (msg.value if Ether)
|
/// @param amount The amount to transfer in (msg.value if Ether)
|
||||||
/**
|
/**
|
||||||
* @param instruction The Shorthand-encoded InInstruction for Serai to associate with this
|
* @param instruction The encoded `RefundableInInstruction` for Serai to associate with this
|
||||||
* transfer in
|
* transfer in
|
||||||
*/
|
*/
|
||||||
// This function doesn't require nonReentrant as re-entrancy isn't an issue with this function
|
// This function doesn't require nonReentrant as re-entrancy isn't an issue with this function
|
||||||
|
|||||||
@@ -21,9 +21,8 @@ use alloy_rpc_types_eth::{BlockId, Log, Filter, TransactionInput, TransactionReq
|
|||||||
use alloy_transport::{TransportErrorKind, RpcError};
|
use alloy_transport::{TransportErrorKind, RpcError};
|
||||||
use alloy_provider::{Provider, RootProvider};
|
use alloy_provider::{Provider, RootProvider};
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
in_instructions::primitives::Shorthand, networks::ethereum::Address as SeraiAddress,
|
primitives::instructions::RefundableInInstruction, networks::ethereum::Address as SeraiAddress,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethereum_primitives::LogIndex;
|
use ethereum_primitives::LogIndex;
|
||||||
@@ -351,20 +350,29 @@ impl Router {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a transaction to send coins with an InInstruction to Serai.
|
/// Construct a transaction to send coins with an `InInstruction` to Serai.
|
||||||
///
|
///
|
||||||
/// If coin is an ERC20, this will not create a transaction calling the Router but will create a
|
/// If coin is an ERC20, this will not create a transaction calling the Router but will create a
|
||||||
/// top-level transfer of the ERC20 to the Router. This avoids needing to call `approve` before
|
/// top-level transfer of the ERC20 to the Router. This avoids needing to call `approve` before
|
||||||
/// publishing the transaction calling the Router.
|
/// publishing the transaction calling the Router.
|
||||||
///
|
///
|
||||||
/// The gas limit and gas price are not set and are left to the caller.
|
/// The gas limit and gas price are not set and are left to the caller.
|
||||||
pub fn in_instruction(&self, coin: Coin, amount: U256, in_instruction: &Shorthand) -> TxLegacy {
|
pub fn in_instruction(
|
||||||
|
&self,
|
||||||
|
coin: Coin,
|
||||||
|
amount: U256,
|
||||||
|
in_instruction: &RefundableInInstruction,
|
||||||
|
) -> TxLegacy {
|
||||||
match coin {
|
match coin {
|
||||||
Coin::Ether => TxLegacy {
|
Coin::Ether => TxLegacy {
|
||||||
to: self.address.into(),
|
to: self.address.into(),
|
||||||
input: abi::inInstructionCall::new((coin.into(), amount, in_instruction.encode().into()))
|
input: abi::inInstructionCall::new((
|
||||||
.abi_encode()
|
coin.into(),
|
||||||
.into(),
|
amount,
|
||||||
|
borsh::to_vec(&in_instruction).unwrap().into(),
|
||||||
|
))
|
||||||
|
.abi_encode()
|
||||||
|
.into(),
|
||||||
value: amount,
|
value: amount,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
@@ -373,7 +381,7 @@ impl Router {
|
|||||||
input: erc20::transferWithInInstructionCall::new((
|
input: erc20::transferWithInInstructionCall::new((
|
||||||
self.address,
|
self.address,
|
||||||
amount,
|
amount,
|
||||||
in_instruction.encode().into(),
|
borsh::to_vec(&in_instruction).unwrap().into(),
|
||||||
))
|
))
|
||||||
.abi_encode()
|
.abi_encode()
|
||||||
.into(),
|
.into(),
|
||||||
|
|||||||
@@ -5,12 +5,9 @@ use alloy_sol_types::SolCall;
|
|||||||
|
|
||||||
use alloy_consensus::{TxLegacy, Signed};
|
use alloy_consensus::{TxLegacy, Signed};
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
primitives::SeraiAddress,
|
primitives::SeraiAddress,
|
||||||
in_instructions::primitives::{
|
primitives::instructions::{InInstruction as SeraiInInstruction, RefundableInInstruction},
|
||||||
InInstruction as SeraiInInstruction, RefundableInInstruction, Shorthand,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethereum_primitives::LogIndex;
|
use ethereum_primitives::LogIndex;
|
||||||
@@ -18,14 +15,14 @@ use ethereum_primitives::LogIndex;
|
|||||||
use crate::{InInstruction, tests::*};
|
use crate::{InInstruction, tests::*};
|
||||||
|
|
||||||
impl Test {
|
impl Test {
|
||||||
pub(crate) fn in_instruction() -> Shorthand {
|
pub(crate) fn in_instruction() -> RefundableInInstruction {
|
||||||
Shorthand::Raw(RefundableInInstruction {
|
RefundableInInstruction {
|
||||||
origin: None,
|
origin: None,
|
||||||
instruction: SeraiInInstruction::Transfer(SeraiAddress([0xff; 32])),
|
instruction: SeraiInInstruction::Transfer(SeraiAddress([0xff; 32])),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eth_in_instruction_tx(&self) -> (Coin, U256, Shorthand, TxLegacy) {
|
pub(crate) fn eth_in_instruction_tx(&self) -> (Coin, U256, RefundableInInstruction, TxLegacy) {
|
||||||
let coin = Coin::Ether;
|
let coin = Coin::Ether;
|
||||||
let amount = U256::from(1);
|
let amount = U256::from(1);
|
||||||
let shorthand = Self::in_instruction();
|
let shorthand = Self::in_instruction();
|
||||||
@@ -42,7 +39,7 @@ impl Test {
|
|||||||
tx: Signed<TxLegacy>,
|
tx: Signed<TxLegacy>,
|
||||||
coin: Coin,
|
coin: Coin,
|
||||||
amount: U256,
|
amount: U256,
|
||||||
shorthand: &Shorthand,
|
shorthand: &RefundableInInstruction,
|
||||||
) {
|
) {
|
||||||
let receipt = ethereum_test_primitives::publish_tx(&self.provider, tx.clone()).await;
|
let receipt = ethereum_test_primitives::publish_tx(&self.provider, tx.clone()).await;
|
||||||
assert!(receipt.status());
|
assert!(receipt.status());
|
||||||
@@ -81,7 +78,7 @@ impl Test {
|
|||||||
from: tx.recover_signer().unwrap(),
|
from: tx.recover_signer().unwrap(),
|
||||||
coin,
|
coin,
|
||||||
amount,
|
amount,
|
||||||
data: shorthand.encode(),
|
data: borsh::to_vec(&shorthand).unwrap(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -140,9 +137,13 @@ async fn test_erc20_router_in_instruction() {
|
|||||||
gas_limit: 1_000_000,
|
gas_limit: 1_000_000,
|
||||||
to: test.router.address().into(),
|
to: test.router.address().into(),
|
||||||
value: U256::ZERO,
|
value: U256::ZERO,
|
||||||
input: crate::abi::inInstructionCall::new((coin.into(), amount, shorthand.encode().into()))
|
input: crate::abi::inInstructionCall::new((
|
||||||
.abi_encode()
|
coin.into(),
|
||||||
.into(),
|
amount,
|
||||||
|
borsh::to_vec(shorthand).unwrap().into(),
|
||||||
|
))
|
||||||
|
.abi_encode()
|
||||||
|
.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// If no `approve` was granted, this should fail
|
// If no `approve` was granted, this should fail
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use alloy_simple_request_transport::SimpleRequest;
|
|||||||
use alloy_rpc_client::ClientBuilder;
|
use alloy_rpc_client::ClientBuilder;
|
||||||
use alloy_provider::{Provider, RootProvider};
|
use alloy_provider::{Provider, RootProvider};
|
||||||
|
|
||||||
use serai_client::validator_sets::primitives::Session;
|
use serai_client::primitives::validator_sets::Session;
|
||||||
|
|
||||||
use serai_env as env;
|
use serai_env as env;
|
||||||
use serai_db::{Get, DbTxn, create_db};
|
use serai_db::{Get, DbTxn, create_db};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use alloy_core::primitives::{FixedBytes, Address};
|
use alloy_core::primitives::{FixedBytes, Address};
|
||||||
|
|
||||||
use serai_client::primitives::Amount;
|
use serai_client::primitives::balance::Amount;
|
||||||
|
|
||||||
pub(crate) mod output;
|
pub(crate) mod output;
|
||||||
pub(crate) mod transaction;
|
pub(crate) mod transaction;
|
||||||
|
|||||||
@@ -5,11 +5,14 @@ use ciphersuite_kp256::Secp256k1;
|
|||||||
|
|
||||||
use alloy_core::primitives::U256;
|
use alloy_core::primitives::U256;
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
primitives::{ExternalNetworkId, ExternalCoin, Amount, ExternalBalance},
|
primitives::{
|
||||||
|
network_id::ExternalNetworkId,
|
||||||
|
coin::ExternalCoin,
|
||||||
|
balance::{Amount, ExternalBalance},
|
||||||
|
},
|
||||||
networks::ethereum::Address,
|
networks::ethereum::Address,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,9 +42,7 @@ fn amount_to_serai_amount(coin: ExternalCoin, amount: U256) -> Amount {
|
|||||||
Amount(u64::try_from(amount / divisor).unwrap())
|
Amount(u64::try_from(amount / divisor).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, BorshSerialize, BorshDeserialize,
|
|
||||||
)]
|
|
||||||
pub(crate) struct OutputId(pub(crate) [u8; 40]);
|
pub(crate) struct OutputId(pub(crate) [u8; 40]);
|
||||||
impl Default for OutputId {
|
impl Default for OutputId {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use alloy_rpc_types_eth::{Header, BlockNumberOrTag};
|
|||||||
use alloy_transport::{RpcError, TransportErrorKind};
|
use alloy_transport::{RpcError, TransportErrorKind};
|
||||||
use alloy_provider::{Provider, RootProvider};
|
use alloy_provider::{Provider, RootProvider};
|
||||||
|
|
||||||
use serai_client::primitives::{ExternalNetworkId, ExternalCoin, Amount};
|
use serai_client::primitives::{network_id::ExternalNetworkId, coin::ExternalCoin, balance::Amount};
|
||||||
|
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||||||
use alloy_core::primitives::U256;
|
use alloy_core::primitives::U256;
|
||||||
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
primitives::{ExternalNetworkId, ExternalCoin, ExternalBalance},
|
primitives::{network_id::ExternalNetworkId, coin::ExternalCoin, balance::ExternalBalance},
|
||||||
networks::ethereum::Address,
|
networks::ethereum::Address,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ all-features = true
|
|||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[package.metadata.cargo-machete]
|
[package.metadata.cargo-machete]
|
||||||
ignored = ["borsh", "scale"]
|
ignored = ["borsh"]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
@@ -25,11 +25,10 @@ rand_core = { version = "0.6", default-features = false, features = ["std", "get
|
|||||||
|
|
||||||
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false }
|
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false }
|
||||||
|
|
||||||
serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std"] }
|
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
serai-db = { path = "../../common/db" }
|
serai-db = { path = "../../common/db" }
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use frost::{
|
|||||||
sign::{Writable, PreprocessMachine, SignMachine, SignatureMachine},
|
sign::{Writable, PreprocessMachine, SignMachine, SignatureMachine},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_primitives::validator_sets::Session;
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, Db, create_db};
|
use serai_db::{Get, DbTxn, Db, create_db};
|
||||||
use messages::sign::{VariantSignId, SignId, ProcessorMessage};
|
use messages::sign::{VariantSignId, SignId, ProcessorMessage};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use frost::{Participant, sign::PreprocessMachine};
|
use frost::{Participant, sign::PreprocessMachine};
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_primitives::validator_sets::Session;
|
||||||
|
|
||||||
use serai_db::{DbTxn, Db};
|
use serai_db::{DbTxn, Db};
|
||||||
use messages::sign::{VariantSignId, ProcessorMessage, CoordinatorMessage};
|
use messages::sign::{VariantSignId, ProcessorMessage, CoordinatorMessage};
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ rust-version = "1.89"
|
|||||||
all-features = true
|
all-features = true
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[package.metadata.cargo-machete]
|
|
||||||
ignored = ["scale"]
|
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
@@ -37,10 +34,9 @@ dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features =
|
|||||||
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false, features = ["ristretto"] }
|
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false, features = ["ristretto"] }
|
||||||
|
|
||||||
# Substrate
|
# Substrate
|
||||||
serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std"] }
|
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
# Encoders
|
# Encoders
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
# Application
|
# Application
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use zeroize::Zeroizing;
|
|||||||
use ciphersuite::{group::GroupEncoding, *};
|
use ciphersuite::{group::GroupEncoding, *};
|
||||||
use dkg::*;
|
use dkg::*;
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_primitives::validator_sets::Session;
|
||||||
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use serai_db::{Get, DbTxn};
|
use serai_db::{Get, DbTxn};
|
||||||
@@ -36,7 +36,7 @@ pub(crate) struct Participations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod _db {
|
mod _db {
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_primitives::validator_sets::Session;
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, create_db};
|
use serai_db::{Get, DbTxn, create_db};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::{
|
|||||||
|
|
||||||
use dkg::*;
|
use dkg::*;
|
||||||
|
|
||||||
use serai_validator_sets_primitives::MAX_KEY_SHARES_PER_SET;
|
use serai_primitives::constants::MAX_KEY_SHARES_PER_SET;
|
||||||
|
|
||||||
/// A cache of the generators used by the eVRF DKG.
|
/// A cache of the generators used by the eVRF DKG.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use ciphersuite::{
|
|||||||
};
|
};
|
||||||
use dkg::*;
|
use dkg::*;
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_primitives::validator_sets::Session;
|
||||||
use messages::key_gen::*;
|
use messages::key_gen::*;
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn};
|
use serai_db::{Get, DbTxn};
|
||||||
|
|||||||
@@ -20,14 +20,10 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "borsh"] }
|
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "borsh"] }
|
||||||
|
|
||||||
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std", "borsh"] }
|
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
in-instructions-primitives = { package = "serai-in-instructions-primitives", path = "../../substrate/in-instructions/primitives", default-features = false, features = ["std", "borsh"] }
|
|
||||||
coins-primitives = { package = "serai-coins-primitives", path = "../../substrate/coins/primitives", default-features = false, features = ["std", "borsh"] }
|
|
||||||
validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std", "borsh"] }
|
|
||||||
|
|
||||||
serai-cosign = { path = "../../coordinator/cosign", default-features = false }
|
serai-cosign = { package = "serai-cosign-types", path = "../../coordinator/cosign/types" }
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use dkg::Participant;
|
use dkg::Participant;
|
||||||
|
|
||||||
use serai_primitives::BlockHash;
|
use serai_primitives::{
|
||||||
use validator_sets_primitives::{Session, KeyPair, SlashReport};
|
BlockHash,
|
||||||
use coins_primitives::OutInstructionWithBalance;
|
crypto::KeyPair,
|
||||||
use in_instructions_primitives::SignedBatch;
|
validator_sets::{Session, SlashReport},
|
||||||
|
instructions::{SignedBatch, OutInstructionWithBalance},
|
||||||
|
};
|
||||||
|
|
||||||
use serai_cosign::{Cosign, SignedCosign};
|
use serai_cosign::{Cosign, SignedCosign};
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ pub mod key_gen {
|
|||||||
pub mod sign {
|
pub mod sign {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encode, Decode, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, BorshSerialize, BorshDeserialize)]
|
||||||
pub enum VariantSignId {
|
pub enum VariantSignId {
|
||||||
Cosign(u64),
|
Cosign(u64),
|
||||||
Batch([u8; 32]),
|
Batch([u8; 32]),
|
||||||
@@ -111,9 +112,7 @@ pub mod sign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, BorshSerialize, BorshDeserialize,
|
|
||||||
)]
|
|
||||||
pub struct SignId {
|
pub struct SignId {
|
||||||
pub session: Session,
|
pub session: Session,
|
||||||
pub id: VariantSignId,
|
pub id: VariantSignId,
|
||||||
@@ -295,7 +294,7 @@ impl CoordinatorMessage {
|
|||||||
let (sub, id) = match msg {
|
let (sub, id) = match msg {
|
||||||
// Unique since we only have one attempt per session
|
// Unique since we only have one attempt per session
|
||||||
key_gen::CoordinatorMessage::GenerateKey { session, .. } => {
|
key_gen::CoordinatorMessage::GenerateKey { session, .. } => {
|
||||||
(0, borsh::to_vec(session).unwrap())
|
(0, borsh::to_vec(&session).unwrap())
|
||||||
}
|
}
|
||||||
// Unique since one participation per participant per session
|
// Unique since one participation per participant per session
|
||||||
key_gen::CoordinatorMessage::Participation { session, participant, .. } => {
|
key_gen::CoordinatorMessage::Participation { session, participant, .. } => {
|
||||||
@@ -316,17 +315,19 @@ impl CoordinatorMessage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut res = vec![COORDINATOR_UID, TYPE_SIGN_UID, sub];
|
let mut res = vec![COORDINATOR_UID, TYPE_SIGN_UID, sub];
|
||||||
res.extend(id.encode());
|
res.extend(borsh::to_vec(&id).unwrap());
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
CoordinatorMessage::Coordinator(msg) => {
|
CoordinatorMessage::Coordinator(msg) => {
|
||||||
let (sub, id) = match msg {
|
let (sub, id) = match msg {
|
||||||
// We only cosign a block once, and Reattempt is a separate message
|
// We only cosign a block once, and Reattempt is a separate message
|
||||||
coordinator::CoordinatorMessage::CosignSubstrateBlock { cosign, .. } => {
|
coordinator::CoordinatorMessage::CosignSubstrateBlock { cosign, .. } => {
|
||||||
(0, cosign.block_number.encode())
|
(0, borsh::to_vec(&cosign.block_number).unwrap())
|
||||||
}
|
}
|
||||||
// We only sign one slash report, and Reattempt is a separate message
|
// We only sign one slash report, and Reattempt is a separate message
|
||||||
coordinator::CoordinatorMessage::SignSlashReport { session, .. } => (1, session.encode()),
|
coordinator::CoordinatorMessage::SignSlashReport { session, .. } => {
|
||||||
|
(1, borsh::to_vec(&session).unwrap())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = vec![COORDINATOR_UID, TYPE_COORDINATOR_UID, sub];
|
let mut res = vec![COORDINATOR_UID, TYPE_COORDINATOR_UID, sub];
|
||||||
@@ -335,10 +336,14 @@ impl CoordinatorMessage {
|
|||||||
}
|
}
|
||||||
CoordinatorMessage::Substrate(msg) => {
|
CoordinatorMessage::Substrate(msg) => {
|
||||||
let (sub, id) = match msg {
|
let (sub, id) = match msg {
|
||||||
substrate::CoordinatorMessage::SetKeys { session, .. } => (0, session.encode()),
|
substrate::CoordinatorMessage::SetKeys { session, .. } => {
|
||||||
substrate::CoordinatorMessage::SlashesReported { session } => (1, session.encode()),
|
(0, borsh::to_vec(&session).unwrap())
|
||||||
|
}
|
||||||
|
substrate::CoordinatorMessage::SlashesReported { session } => {
|
||||||
|
(1, borsh::to_vec(&session).unwrap())
|
||||||
|
}
|
||||||
substrate::CoordinatorMessage::Block { serai_block_number, .. } => {
|
substrate::CoordinatorMessage::Block { serai_block_number, .. } => {
|
||||||
(2, serai_block_number.encode())
|
(2, borsh::to_vec(&serai_block_number).unwrap())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -363,10 +368,10 @@ impl ProcessorMessage {
|
|||||||
let (sub, id) = match msg {
|
let (sub, id) = match msg {
|
||||||
// Unique since we only have one participation per session (due to no re-attempts)
|
// Unique since we only have one participation per session (due to no re-attempts)
|
||||||
key_gen::ProcessorMessage::Participation { session, .. } => {
|
key_gen::ProcessorMessage::Participation { session, .. } => {
|
||||||
(0, borsh::to_vec(session).unwrap())
|
(0, borsh::to_vec(&session).unwrap())
|
||||||
}
|
}
|
||||||
key_gen::ProcessorMessage::GeneratedKeyPair { session, .. } => {
|
key_gen::ProcessorMessage::GeneratedKeyPair { session, .. } => {
|
||||||
(1, borsh::to_vec(session).unwrap())
|
(1, borsh::to_vec(&session).unwrap())
|
||||||
}
|
}
|
||||||
// Unique since we only blame a participant once (as this is fatal)
|
// Unique since we only blame a participant once (as this is fatal)
|
||||||
key_gen::ProcessorMessage::Blame { session, participant } => {
|
key_gen::ProcessorMessage::Blame { session, participant } => {
|
||||||
@@ -382,11 +387,11 @@ impl ProcessorMessage {
|
|||||||
let (sub, id) = match msg {
|
let (sub, id) = match msg {
|
||||||
// Unique since we'll only fatally slash a a participant once
|
// Unique since we'll only fatally slash a a participant once
|
||||||
sign::ProcessorMessage::InvalidParticipant { session, participant } => {
|
sign::ProcessorMessage::InvalidParticipant { session, participant } => {
|
||||||
(0, (session, u16::from(*participant)).encode())
|
(0, borsh::to_vec(&(session, u16::from(*participant))).unwrap())
|
||||||
}
|
}
|
||||||
// Unique since SignId
|
// Unique since SignId
|
||||||
sign::ProcessorMessage::Preprocesses { id, .. } => (1, id.encode()),
|
sign::ProcessorMessage::Preprocesses { id, .. } => (1, borsh::to_vec(&id).unwrap()),
|
||||||
sign::ProcessorMessage::Shares { id, .. } => (2, id.encode()),
|
sign::ProcessorMessage::Shares { id, .. } => (2, borsh::to_vec(&id).unwrap()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = vec![PROCESSOR_UID, TYPE_SIGN_UID, sub];
|
let mut res = vec![PROCESSOR_UID, TYPE_SIGN_UID, sub];
|
||||||
@@ -396,10 +401,14 @@ impl ProcessorMessage {
|
|||||||
ProcessorMessage::Coordinator(msg) => {
|
ProcessorMessage::Coordinator(msg) => {
|
||||||
let (sub, id) = match msg {
|
let (sub, id) = match msg {
|
||||||
coordinator::ProcessorMessage::CosignedBlock { cosign } => {
|
coordinator::ProcessorMessage::CosignedBlock { cosign } => {
|
||||||
(0, cosign.cosign.block_hash.encode())
|
(0, borsh::to_vec(&cosign.cosign.block_hash).unwrap())
|
||||||
|
}
|
||||||
|
coordinator::ProcessorMessage::SignedBatch { batch, .. } => {
|
||||||
|
(1, borsh::to_vec(&batch.batch.id()).unwrap())
|
||||||
|
}
|
||||||
|
coordinator::ProcessorMessage::SignedSlashReport { session, .. } => {
|
||||||
|
(2, borsh::to_vec(&session).unwrap())
|
||||||
}
|
}
|
||||||
coordinator::ProcessorMessage::SignedBatch { batch, .. } => (1, batch.batch.id.encode()),
|
|
||||||
coordinator::ProcessorMessage::SignedSlashReport { session, .. } => (2, session.encode()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = vec![PROCESSOR_UID, TYPE_COORDINATOR_UID, sub];
|
let mut res = vec![PROCESSOR_UID, TYPE_COORDINATOR_UID, sub];
|
||||||
@@ -408,7 +417,9 @@ impl ProcessorMessage {
|
|||||||
}
|
}
|
||||||
ProcessorMessage::Substrate(msg) => {
|
ProcessorMessage::Substrate(msg) => {
|
||||||
let (sub, id) = match msg {
|
let (sub, id) = match msg {
|
||||||
substrate::ProcessorMessage::SubstrateBlockAck { block, .. } => (0, block.encode()),
|
substrate::ProcessorMessage::SubstrateBlockAck { block, .. } => {
|
||||||
|
(0, borsh::to_vec(&block).unwrap())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = vec![PROCESSOR_UID, TYPE_SUBSTRATE_UID, sub];
|
let mut res = vec![PROCESSOR_UID, TYPE_SUBSTRATE_UID, sub];
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ rand_core = { version = "0.6", default-features = false }
|
|||||||
rand_chacha = { version = "0.3", default-features = false, features = ["std"] }
|
rand_chacha = { version = "0.3", default-features = false, features = ["std"] }
|
||||||
zeroize = { version = "1", default-features = false, features = ["std"] }
|
zeroize = { version = "1", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ use dalek_ff_group::Ed25519;
|
|||||||
|
|
||||||
use monero_wallet::WalletOutput;
|
use monero_wallet::WalletOutput;
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
primitives::{ExternalCoin, Amount, ExternalBalance},
|
primitives::{
|
||||||
|
coin::ExternalCoin,
|
||||||
|
balance::{Amount, ExternalBalance},
|
||||||
|
},
|
||||||
networks::monero::Address,
|
networks::monero::Address,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -17,10 +19,7 @@ use primitives::{OutputType, ReceivedOutput};
|
|||||||
|
|
||||||
use crate::{EXTERNAL_SUBADDRESS, BRANCH_SUBADDRESS, CHANGE_SUBADDRESS, FORWARDED_SUBADDRESS};
|
use crate::{EXTERNAL_SUBADDRESS, BRANCH_SUBADDRESS, CHANGE_SUBADDRESS, FORWARDED_SUBADDRESS};
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[derive(Clone, Copy, PartialEq, Eq, Default, Hash, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
#[derive(
|
|
||||||
Clone, Copy, PartialEq, Eq, Default, Hash, Debug, Encode, Decode, BorshSerialize, BorshDeserialize,
|
|
||||||
)]
|
|
||||||
pub(crate) struct OutputId(pub(crate) [u8; 32]);
|
pub(crate) struct OutputId(pub(crate) [u8; 32]);
|
||||||
impl AsRef<[u8]> for OutputId {
|
impl AsRef<[u8]> for OutputId {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use core::future::Future;
|
|||||||
use monero_wallet::rpc::{RpcError, Rpc as RpcTrait};
|
use monero_wallet::rpc::{RpcError, Rpc as RpcTrait};
|
||||||
use monero_simple_request_rpc::SimpleRequestRpc;
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
|
|
||||||
use serai_client::primitives::{ExternalNetworkId, ExternalCoin, Amount};
|
use serai_client::primitives::{network_id::ExternalNetworkId, coin::ExternalCoin, balance::Amount};
|
||||||
|
|
||||||
use scanner::ScannerFeed;
|
use scanner::ScannerFeed;
|
||||||
use signers::TransactionPublisher;
|
use signers::TransactionPublisher;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use dalek_ff_group::Ed25519;
|
|||||||
use monero_wallet::rpc::{FeeRate, RpcError};
|
use monero_wallet::rpc::{FeeRate, RpcError};
|
||||||
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
primitives::{ExternalCoin, Amount},
|
primitives::{coin::ExternalCoin, balance::Amount},
|
||||||
networks::monero::Address,
|
networks::monero::Address,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,8 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
group = { version = "0.13", default-features = false }
|
group = { version = "0.13", default-features = false }
|
||||||
|
|
||||||
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std", "borsh"] }
|
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
serai-coins-primitives = { path = "../../substrate/coins/primitives", default-features = false, features = ["std", "borsh"] }
|
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use core::{hash::Hash, fmt::Debug};
|
|||||||
|
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
/// A module for task-related structs and functionality.
|
/// A module for task-related structs and functionality.
|
||||||
@@ -40,8 +39,6 @@ pub trait Id:
|
|||||||
+ AsRef<[u8]>
|
+ AsRef<[u8]>
|
||||||
+ AsMut<[u8]>
|
+ AsMut<[u8]>
|
||||||
+ Debug
|
+ Debug
|
||||||
+ Encode
|
|
||||||
+ Decode
|
|
||||||
+ BorshSerialize
|
+ BorshSerialize
|
||||||
+ BorshDeserialize
|
+ BorshDeserialize
|
||||||
{
|
{
|
||||||
@@ -57,22 +54,15 @@ impl<
|
|||||||
+ AsRef<[u8]>
|
+ AsRef<[u8]>
|
||||||
+ AsMut<[u8]>
|
+ AsMut<[u8]>
|
||||||
+ Debug
|
+ Debug
|
||||||
+ Encode
|
|
||||||
+ Decode
|
|
||||||
+ BorshSerialize
|
+ BorshSerialize
|
||||||
+ BorshDeserialize,
|
+ BorshDeserialize,
|
||||||
> Id for I
|
> Id for I
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper for a group element which implements the scale/borsh traits.
|
/// A wrapper for a group element which implements the `borsh` traits.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub struct EncodableG<G: GroupEncoding>(pub G);
|
pub struct EncodableG<G: GroupEncoding>(pub G);
|
||||||
impl<G: GroupEncoding> Encode for EncodableG<G> {
|
|
||||||
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
|
||||||
f(self.0.to_bytes().as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<G: GroupEncoding> BorshSerialize for EncodableG<G> {
|
impl<G: GroupEncoding> BorshSerialize for EncodableG<G> {
|
||||||
fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> borsh::io::Result<()> {
|
fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> borsh::io::Result<()> {
|
||||||
writer.write_all(self.0.to_bytes().as_ref())
|
writer.write_all(self.0.to_bytes().as_ref())
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use group::GroupEncoding;
|
|||||||
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_primitives::{ExternalAddress, ExternalBalance};
|
use serai_primitives::{address::ExternalAddress, balance::ExternalBalance};
|
||||||
|
|
||||||
use crate::Id;
|
use crate::Id;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use scale::{Encode, Decode, IoReader};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
use serai_primitives::ExternalBalance;
|
use serai_primitives::{
|
||||||
use serai_coins_primitives::OutInstructionWithBalance;
|
balance::ExternalBalance,
|
||||||
|
instructions::{OutInstruction, OutInstructionWithBalance},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::Address;
|
use crate::Address;
|
||||||
|
|
||||||
@@ -18,9 +19,11 @@ pub struct Payment<A: Address> {
|
|||||||
impl<A: Address> TryFrom<OutInstructionWithBalance> for Payment<A> {
|
impl<A: Address> TryFrom<OutInstructionWithBalance> for Payment<A> {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
fn try_from(out_instruction_with_balance: OutInstructionWithBalance) -> Result<Self, ()> {
|
fn try_from(out_instruction_with_balance: OutInstructionWithBalance) -> Result<Self, ()> {
|
||||||
Ok(Payment {
|
Ok(match out_instruction_with_balance.instruction {
|
||||||
address: out_instruction_with_balance.instruction.address.try_into().map_err(|_| ())?,
|
OutInstruction::Transfer(address) => Payment {
|
||||||
balance: out_instruction_with_balance.balance,
|
address: address.try_into().map_err(|_| ())?,
|
||||||
|
balance: out_instruction_with_balance.balance,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,14 +46,12 @@ impl<A: Address> Payment<A> {
|
|||||||
/// Read a Payment.
|
/// Read a Payment.
|
||||||
pub fn read(reader: &mut impl io::Read) -> io::Result<Self> {
|
pub fn read(reader: &mut impl io::Read) -> io::Result<Self> {
|
||||||
let address = A::deserialize_reader(reader)?;
|
let address = A::deserialize_reader(reader)?;
|
||||||
let reader = &mut IoReader(reader);
|
let balance = ExternalBalance::deserialize_reader(reader).map_err(io::Error::other)?;
|
||||||
let balance = ExternalBalance::decode(reader).map_err(io::Error::other)?;
|
|
||||||
Ok(Self { address, balance })
|
Ok(Self { address, balance })
|
||||||
}
|
}
|
||||||
/// Write the Payment.
|
/// Write the Payment.
|
||||||
pub fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
|
pub fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
|
||||||
self.address.serialize(writer)?;
|
self.address.serialize(writer)?;
|
||||||
self.balance.encode_to(writer);
|
self.balance.serialize(writer)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
# Encoders
|
# Encoders
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] }
|
|
||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
# Cryptography
|
# Cryptography
|
||||||
@@ -36,9 +35,6 @@ serai-db = { path = "../../common/db" }
|
|||||||
messages = { package = "serai-processor-messages", path = "../messages" }
|
messages = { package = "serai-processor-messages", path = "../messages" }
|
||||||
|
|
||||||
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] }
|
||||||
serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std", "borsh"] }
|
|
||||||
serai-in-instructions-primitives = { path = "../../substrate/in-instructions/primitives", default-features = false, features = ["std", "borsh"] }
|
|
||||||
serai-coins-primitives = { path = "../../substrate/coins/primitives", default-features = false, features = ["std", "borsh"] }
|
|
||||||
|
|
||||||
primitives = { package = "serai-processor-primitives", path = "../primitives" }
|
primitives = { package = "serai-processor-primitives", path = "../primitives" }
|
||||||
scheduler-primitives = { package = "serai-processor-scheduler-primitives", path = "../scheduler/primitives" }
|
scheduler-primitives = { package = "serai-processor-scheduler-primitives", path = "../scheduler/primitives" }
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ use std::io::{Read, Write};
|
|||||||
|
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
|
|
||||||
use scale::{Encode, Decode, IoReader};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use serai_db::{Get, DbTxn, create_db};
|
use serai_db::{Get, DbTxn, create_db};
|
||||||
|
|
||||||
use serai_primitives::ExternalBalance;
|
use serai_primitives::{balance::ExternalBalance, validator_sets::Session};
|
||||||
use serai_validator_sets_primitives::Session;
|
|
||||||
|
|
||||||
use primitives::EncodableG;
|
use primitives::EncodableG;
|
||||||
use crate::{ScannerFeed, KeyFor, AddressFor};
|
use crate::{ScannerFeed, KeyFor, AddressFor};
|
||||||
@@ -94,7 +92,7 @@ impl<S: ScannerFeed> BatchDb<S> {
|
|||||||
if let Some(ReturnInformation { address, balance }) = return_information {
|
if let Some(ReturnInformation { address, balance }) = return_information {
|
||||||
buf.write_all(&[1]).unwrap();
|
buf.write_all(&[1]).unwrap();
|
||||||
address.serialize(&mut buf).unwrap();
|
address.serialize(&mut buf).unwrap();
|
||||||
balance.encode_to(&mut buf);
|
balance.serialize(&mut buf).unwrap();
|
||||||
} else {
|
} else {
|
||||||
buf.write_all(&[0]).unwrap();
|
buf.write_all(&[0]).unwrap();
|
||||||
}
|
}
|
||||||
@@ -116,7 +114,7 @@ impl<S: ScannerFeed> BatchDb<S> {
|
|||||||
|
|
||||||
res.push((opt[0] == 1).then(|| {
|
res.push((opt[0] == 1).then(|| {
|
||||||
let address = AddressFor::<S>::deserialize_reader(&mut buf).unwrap();
|
let address = AddressFor::<S>::deserialize_reader(&mut buf).unwrap();
|
||||||
let balance = ExternalBalance::decode(&mut IoReader(&mut buf)).unwrap();
|
let balance = ExternalBalance::deserialize_reader(&mut buf).unwrap();
|
||||||
ReturnInformation { address, balance }
|
ReturnInformation { address, balance }
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ use core::{marker::PhantomData, future::Future};
|
|||||||
|
|
||||||
use blake2::{digest::typenum::U32, Digest, Blake2b};
|
use blake2::{digest::typenum::U32, Digest, Blake2b};
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
use serai_db::{DbTxn, Db};
|
use serai_db::{DbTxn, Db};
|
||||||
|
|
||||||
use serai_primitives::BlockHash;
|
use serai_primitives::{BlockHash, instructions::Batch};
|
||||||
use serai_in_instructions_primitives::{MAX_BATCH_SIZE, Batch};
|
|
||||||
|
|
||||||
use primitives::{
|
use primitives::{
|
||||||
EncodableG,
|
EncodableG,
|
||||||
@@ -111,12 +109,7 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for BatchTask<D, S> {
|
|||||||
let mut batch_id = BatchDb::<S>::acquire_batch_id(&mut txn);
|
let mut batch_id = BatchDb::<S>::acquire_batch_id(&mut txn);
|
||||||
|
|
||||||
// start with empty batch
|
// start with empty batch
|
||||||
let mut batches = vec![Batch {
|
let mut batches = vec![Batch::new(network, batch_id, external_network_block_hash)];
|
||||||
network,
|
|
||||||
id: batch_id,
|
|
||||||
external_network_block_hash,
|
|
||||||
instructions: vec![],
|
|
||||||
}];
|
|
||||||
// We also track the return information for the InInstructions within a Batch in case
|
// We also track the return information for the InInstructions within a Batch in case
|
||||||
// they error
|
// they error
|
||||||
let mut return_information = vec![vec![]];
|
let mut return_information = vec![vec![]];
|
||||||
@@ -125,23 +118,19 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for BatchTask<D, S> {
|
|||||||
let balance = in_instruction.balance;
|
let balance = in_instruction.balance;
|
||||||
|
|
||||||
let batch = batches.last_mut().unwrap();
|
let batch = batches.last_mut().unwrap();
|
||||||
batch.instructions.push(in_instruction);
|
|
||||||
|
|
||||||
// check if batch is over-size
|
// check if batch is over-size
|
||||||
if batch.encode().len() > MAX_BATCH_SIZE {
|
if batch.push_instruction(in_instruction.clone()).is_err() {
|
||||||
// pop the last instruction so it's back in size
|
|
||||||
let in_instruction = batch.instructions.pop().unwrap();
|
|
||||||
|
|
||||||
// bump the id for the new batch
|
// bump the id for the new batch
|
||||||
batch_id = BatchDb::<S>::acquire_batch_id(&mut txn);
|
batch_id = BatchDb::<S>::acquire_batch_id(&mut txn);
|
||||||
|
|
||||||
// make a new batch with this instruction included
|
// make a new batch with this instruction included
|
||||||
batches.push(Batch {
|
let mut batch = Batch::new(network, batch_id, external_network_block_hash);
|
||||||
network,
|
batch
|
||||||
id: batch_id,
|
.push_instruction(in_instruction)
|
||||||
external_network_block_hash,
|
.expect("single InInstruction exceeded Batch size limit");
|
||||||
instructions: vec![in_instruction],
|
batches.push(batch);
|
||||||
});
|
|
||||||
// Since we're allocating a new batch, allocate a new set of return addresses for it
|
// Since we're allocating a new batch, allocate a new set of return addresses for it
|
||||||
return_information.push(vec![]);
|
return_information.push(vec![]);
|
||||||
}
|
}
|
||||||
@@ -157,16 +146,16 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for BatchTask<D, S> {
|
|||||||
// Now that we've finalized the Batches, save the information for each to the database
|
// Now that we've finalized the Batches, save the information for each to the database
|
||||||
assert_eq!(batches.len(), return_information.len());
|
assert_eq!(batches.len(), return_information.len());
|
||||||
for (batch, return_information) in batches.iter().zip(&return_information) {
|
for (batch, return_information) in batches.iter().zip(&return_information) {
|
||||||
assert_eq!(batch.instructions.len(), return_information.len());
|
assert_eq!(batch.instructions().len(), return_information.len());
|
||||||
BatchDb::<S>::save_batch_info(
|
BatchDb::<S>::save_batch_info(
|
||||||
&mut txn,
|
&mut txn,
|
||||||
batch.id,
|
batch.id(),
|
||||||
block_number,
|
block_number,
|
||||||
session_to_sign_batch,
|
session_to_sign_batch,
|
||||||
external_key_for_session_to_sign_batch,
|
external_key_for_session_to_sign_batch,
|
||||||
Blake2b::<U32>::digest(batch.instructions.encode()).into(),
|
Blake2b::<U32>::digest(borsh::to_vec(&batch.instructions()).unwrap()).into(),
|
||||||
);
|
);
|
||||||
BatchDb::<S>::save_return_information(&mut txn, batch.id, return_information);
|
BatchDb::<S>::save_return_information(&mut txn, batch.id(), return_information);
|
||||||
}
|
}
|
||||||
|
|
||||||
for batch in batches {
|
for batch in batches {
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ use std::io::{self, Read, Write};
|
|||||||
|
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
|
|
||||||
use scale::{Encode, Decode, IoReader};
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use serai_db::{Get, DbTxn, create_db, db_channel};
|
use serai_db::{Get, DbTxn, create_db, db_channel};
|
||||||
|
|
||||||
use serai_coins_primitives::OutInstructionWithBalance;
|
use serai_primitives::{
|
||||||
use serai_validator_sets_primitives::Session;
|
validator_sets::Session,
|
||||||
use serai_in_instructions_primitives::{InInstructionWithBalance, Batch};
|
instructions::{InInstructionWithBalance, Batch, OutInstructionWithBalance},
|
||||||
|
};
|
||||||
|
|
||||||
use primitives::{EncodableG, ReceivedOutput};
|
use primitives::{EncodableG, ReceivedOutput};
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ impl<S: ScannerFeed> OutputWithInInstruction<S> {
|
|||||||
(opt[0] == 1).then(|| AddressFor::<S>::deserialize_reader(reader)).transpose()?
|
(opt[0] == 1).then(|| AddressFor::<S>::deserialize_reader(reader)).transpose()?
|
||||||
};
|
};
|
||||||
let in_instruction =
|
let in_instruction =
|
||||||
InInstructionWithBalance::decode(&mut IoReader(reader)).map_err(io::Error::other)?;
|
InInstructionWithBalance::deserialize_reader(reader).map_err(io::Error::other)?;
|
||||||
Ok(Self { output, return_address, in_instruction })
|
Ok(Self { output, return_address, in_instruction })
|
||||||
}
|
}
|
||||||
pub(crate) fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
|
pub(crate) fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
|
||||||
@@ -67,7 +67,7 @@ impl<S: ScannerFeed> OutputWithInInstruction<S> {
|
|||||||
} else {
|
} else {
|
||||||
writer.write_all(&[0])?;
|
writer.write_all(&[0])?;
|
||||||
}
|
}
|
||||||
self.in_instruction.encode_to(writer);
|
self.in_instruction.serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,10 +76,10 @@ create_db!(
|
|||||||
ScannerGlobal {
|
ScannerGlobal {
|
||||||
StartBlock: () -> u64,
|
StartBlock: () -> u64,
|
||||||
|
|
||||||
QueuedKey: <K: Encode>(key: K) -> (),
|
QueuedKey: <K: BorshSerialize>(key: K) -> (),
|
||||||
|
|
||||||
ActiveKeys: <K: Borshy>() -> Vec<SeraiKeyDbEntry<K>>,
|
ActiveKeys: <K: Borshy>() -> Vec<SeraiKeyDbEntry<K>>,
|
||||||
RetireAt: <K: Encode>(key: K) -> u64,
|
RetireAt: <K: BorshSerialize>(key: K) -> u64,
|
||||||
|
|
||||||
// Highest acknowledged block
|
// Highest acknowledged block
|
||||||
HighestAcknowledgedBlock: () -> u64,
|
HighestAcknowledgedBlock: () -> u64,
|
||||||
@@ -294,7 +294,7 @@ impl<S: ScannerFeed> ScannerGlobalDb<S> {
|
|||||||
assert!((opt[0] == 0) || (opt[0] == 1));
|
assert!((opt[0] == 0) || (opt[0] == 1));
|
||||||
|
|
||||||
let address = (opt[0] == 1).then(|| AddressFor::<S>::deserialize_reader(&mut buf).unwrap());
|
let address = (opt[0] == 1).then(|| AddressFor::<S>::deserialize_reader(&mut buf).unwrap());
|
||||||
Some((address, InInstructionWithBalance::decode(&mut IoReader(buf)).unwrap()))
|
Some((address, InInstructionWithBalance::deserialize_reader(&mut buf).unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +357,7 @@ impl<S: ScannerFeed> ScanToEventualityDb<S> {
|
|||||||
} else {
|
} else {
|
||||||
buf.write_all(&[0]).unwrap();
|
buf.write_all(&[0]).unwrap();
|
||||||
}
|
}
|
||||||
forward.in_instruction.encode_to(&mut buf);
|
forward.in_instruction.serialize(&mut buf).unwrap();
|
||||||
|
|
||||||
SerializedForwardedOutput::set(txn, forward.output.id().as_ref(), &buf);
|
SerializedForwardedOutput::set(txn, forward.output.id().as_ref(), &buf);
|
||||||
}
|
}
|
||||||
@@ -454,7 +454,7 @@ impl<S: ScannerFeed> Returnable<S> {
|
|||||||
(opt[0] == 1).then(|| AddressFor::<S>::deserialize_reader(reader)).transpose()?;
|
(opt[0] == 1).then(|| AddressFor::<S>::deserialize_reader(reader)).transpose()?;
|
||||||
|
|
||||||
let in_instruction =
|
let in_instruction =
|
||||||
InInstructionWithBalance::decode(&mut IoReader(reader)).map_err(io::Error::other)?;
|
InInstructionWithBalance::deserialize_reader(reader).map_err(io::Error::other)?;
|
||||||
Ok(Returnable { return_address, in_instruction })
|
Ok(Returnable { return_address, in_instruction })
|
||||||
}
|
}
|
||||||
fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
|
fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
|
||||||
@@ -464,7 +464,7 @@ impl<S: ScannerFeed> Returnable<S> {
|
|||||||
} else {
|
} else {
|
||||||
writer.write_all(&[0])?;
|
writer.write_all(&[0])?;
|
||||||
}
|
}
|
||||||
self.in_instruction.encode_to(writer);
|
self.in_instruction.serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,7 +494,7 @@ impl<S: ScannerFeed> ScanToBatchDb<S> {
|
|||||||
block_number: u64,
|
block_number: u64,
|
||||||
data: &InInstructionData<S>,
|
data: &InInstructionData<S>,
|
||||||
) {
|
) {
|
||||||
let mut buf = data.session_to_sign_batch.encode();
|
let mut buf = borsh::to_vec(&data.session_to_sign_batch).unwrap();
|
||||||
buf.extend(data.external_key_for_session_to_sign_batch.to_bytes().as_ref());
|
buf.extend(data.external_key_for_session_to_sign_batch.to_bytes().as_ref());
|
||||||
for returnable_in_instruction in &data.returnable_in_instructions {
|
for returnable_in_instruction in &data.returnable_in_instructions {
|
||||||
returnable_in_instruction.write(&mut buf).unwrap();
|
returnable_in_instruction.write(&mut buf).unwrap();
|
||||||
@@ -517,7 +517,7 @@ impl<S: ScannerFeed> ScanToBatchDb<S> {
|
|||||||
);
|
);
|
||||||
let mut buf = data.returnable_in_instructions.as_slice();
|
let mut buf = data.returnable_in_instructions.as_slice();
|
||||||
|
|
||||||
let session_to_sign_batch = Session::decode(&mut buf).unwrap();
|
let session_to_sign_batch = Session::deserialize_reader(&mut buf).unwrap();
|
||||||
let external_key_for_session_to_sign_batch = {
|
let external_key_for_session_to_sign_batch = {
|
||||||
let mut external_key_for_session_to_sign_batch =
|
let mut external_key_for_session_to_sign_batch =
|
||||||
<KeyFor<S> as GroupEncoding>::Repr::default();
|
<KeyFor<S> as GroupEncoding>::Repr::default();
|
||||||
@@ -595,7 +595,7 @@ impl SubstrateToEventualityDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod _public_db {
|
mod _public_db {
|
||||||
use serai_in_instructions_primitives::Batch;
|
use serai_primitives::instructions::Batch;
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, create_db, db_channel};
|
use serai_db::{Get, DbTxn, create_db, db_channel};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use scale::Encode;
|
use borsh::BorshSerialize;
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, create_db};
|
use serai_db::{Get, DbTxn, create_db};
|
||||||
|
|
||||||
use primitives::{EncodableG, ReceivedOutput, Eventuality, EventualityTracker};
|
use primitives::{EncodableG, ReceivedOutput, Eventuality, EventualityTracker};
|
||||||
@@ -14,7 +15,7 @@ create_db!(
|
|||||||
// The latest block this task has handled which was notable
|
// The latest block this task has handled which was notable
|
||||||
LatestHandledNotableBlock: () -> u64,
|
LatestHandledNotableBlock: () -> u64,
|
||||||
|
|
||||||
SerializedEventualities: <K: Encode>(key: K) -> Vec<u8>,
|
SerializedEventualities: <K: BorshSerialize>(key: K) -> Vec<u8>,
|
||||||
|
|
||||||
AccumulatedOutput: (id: &[u8]) -> (),
|
AccumulatedOutput: (id: &[u8]) -> (),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ use group::GroupEncoding;
|
|||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use serai_db::{Get, DbTxn, Db};
|
use serai_db::{Get, DbTxn, Db};
|
||||||
|
|
||||||
use serai_primitives::{ExternalNetworkId, ExternalCoin, Amount};
|
use serai_primitives::{
|
||||||
use serai_coins_primitives::OutInstructionWithBalance;
|
network_id::ExternalNetworkId, coin::ExternalCoin, balance::Amount,
|
||||||
|
instructions::OutInstructionWithBalance,
|
||||||
|
};
|
||||||
|
|
||||||
use messages::substrate::ExecutedBatch;
|
use messages::substrate::ExecutedBatch;
|
||||||
use primitives::{task::*, Address, ReceivedOutput, Block, Payment};
|
use primitives::{task::*, Address, ReceivedOutput, Block, Payment};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use serai_db::{Get, DbTxn, create_db};
|
use serai_db::{Get, DbTxn, create_db};
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_primitives::validator_sets::Session;
|
||||||
|
|
||||||
create_db!(
|
create_db!(
|
||||||
ScannerBatch {
|
ScannerBatch {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use core::{marker::PhantomData, future::Future};
|
|||||||
|
|
||||||
use serai_db::{DbTxn, Db};
|
use serai_db::{DbTxn, Db};
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_primitives::validator_sets::Session;
|
||||||
|
|
||||||
use primitives::task::{DoesNotError, ContinuallyRan};
|
use primitives::task::{DoesNotError, ContinuallyRan};
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -70,12 +70,12 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for ReportTask<D, S> {
|
|||||||
// Because this boolean was expanded, we lose short-circuiting. That's fine
|
// Because this boolean was expanded, we lose short-circuiting. That's fine
|
||||||
let handover_batch = last_session != session_to_sign_batch;
|
let handover_batch = last_session != session_to_sign_batch;
|
||||||
let batch_after_handover_batch =
|
let batch_after_handover_batch =
|
||||||
(last_session == session_to_sign_batch) && ((first_batch + 1) == batch.id);
|
(last_session == session_to_sign_batch) && ((first_batch + 1) == batch.id());
|
||||||
if handover_batch || batch_after_handover_batch {
|
if handover_batch || batch_after_handover_batch {
|
||||||
let verified_prior_batch = substrate::last_acknowledged_batch::<S>(&txn)
|
let verified_prior_batch = substrate::last_acknowledged_batch::<S>(&txn)
|
||||||
// Since `batch.id = 0` in the Session(0)-never-published-a-Batch case, we don't
|
// Since `batch.id() = 0` in the Session(0)-never-published-a-Batch case, we don't
|
||||||
// check `last_acknowledged_batch >= (batch.id - 1)` but instead this
|
// check `last_acknowledged_batch >= (batch.id() - 1)` but instead this
|
||||||
.map(|last_acknowledged_batch| (last_acknowledged_batch + 1) >= batch.id)
|
.map(|last_acknowledged_batch| (last_acknowledged_batch + 1) >= batch.id())
|
||||||
// We've never verified any Batches
|
// We've never verified any Batches
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if !verified_prior_batch {
|
if !verified_prior_batch {
|
||||||
@@ -90,7 +90,7 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for ReportTask<D, S> {
|
|||||||
BatchDb::set_last_session_to_sign_batch_and_first_batch(
|
BatchDb::set_last_session_to_sign_batch_and_first_batch(
|
||||||
&mut txn,
|
&mut txn,
|
||||||
session_to_sign_batch,
|
session_to_sign_batch,
|
||||||
batch.id,
|
batch.id(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use scale::Decode;
|
use borsh::BorshDeserialize;
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, Db};
|
use serai_db::{Get, DbTxn, Db};
|
||||||
|
|
||||||
use serai_in_instructions_primitives::{
|
#[rustfmt::skip]
|
||||||
Shorthand, RefundableInInstruction, InInstruction, InInstructionWithBalance,
|
use serai_primitives::instructions::{RefundableInInstruction, InInstruction, InInstructionWithBalance};
|
||||||
};
|
|
||||||
|
|
||||||
use primitives::{task::ContinuallyRan, OutputType, ReceivedOutput, Block};
|
use primitives::{task::ContinuallyRan, OutputType, ReceivedOutput, Block};
|
||||||
|
|
||||||
@@ -55,26 +55,22 @@ fn in_instruction_from_output<S: ScannerFeed>(
|
|||||||
let presumed_origin = output.presumed_origin();
|
let presumed_origin = output.presumed_origin();
|
||||||
|
|
||||||
let mut data = output.data();
|
let mut data = output.data();
|
||||||
let shorthand = match Shorthand::decode(&mut data) {
|
let instruction = match RefundableInInstruction::deserialize_reader(&mut data) {
|
||||||
Ok(shorthand) => shorthand,
|
|
||||||
Err(e) => {
|
|
||||||
log::info!("data in output {} wasn't valid shorthand: {e:?}", hex::encode(output.id()));
|
|
||||||
return (presumed_origin, None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let instruction = match RefundableInInstruction::try_from(shorthand) {
|
|
||||||
Ok(instruction) => instruction,
|
Ok(instruction) => instruction,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::info!(
|
log::info!(
|
||||||
"shorthand in output {} wasn't convertible to a RefundableInInstruction: {e:?}",
|
"data in output {} wasn't a valid `RefundableInInstruction`: {e:?}",
|
||||||
hex::encode(output.id())
|
hex::encode(output.id()),
|
||||||
);
|
);
|
||||||
return (presumed_origin, None);
|
return (presumed_origin, None);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
instruction.origin.and_then(|addr| AddressFor::<S>::try_from(addr).ok()).or(presumed_origin),
|
instruction
|
||||||
|
.return_address
|
||||||
|
.and_then(|addr| AddressFor::<S>::try_from(addr).ok())
|
||||||
|
.or(presumed_origin),
|
||||||
Some(instruction.instruction),
|
Some(instruction.instruction),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use group::GroupEncoding;
|
|||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use serai_db::{Get, DbTxn, create_db, db_channel};
|
use serai_db::{Get, DbTxn, create_db, db_channel};
|
||||||
|
|
||||||
use serai_coins_primitives::OutInstructionWithBalance;
|
use serai_primitives::instructions::OutInstructionWithBalance;
|
||||||
|
|
||||||
use messages::substrate::ExecutedBatch;
|
use messages::substrate::ExecutedBatch;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use core::{marker::PhantomData, future::Future};
|
|||||||
|
|
||||||
use serai_db::{Get, DbTxn, Db};
|
use serai_db::{Get, DbTxn, Db};
|
||||||
|
|
||||||
use serai_coins_primitives::{OutInstruction, OutInstructionWithBalance};
|
use serai_primitives::instructions::{OutInstruction, OutInstructionWithBalance};
|
||||||
|
|
||||||
use messages::substrate::ExecutedBatch;
|
use messages::substrate::ExecutedBatch;
|
||||||
use primitives::task::{DoesNotError, ContinuallyRan};
|
use primitives::task::{DoesNotError, ContinuallyRan};
|
||||||
@@ -150,7 +150,7 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for SubstrateTask<D, S> {
|
|||||||
|
|
||||||
if let Some(batch::ReturnInformation { address, balance }) = return_information {
|
if let Some(batch::ReturnInformation { address, balance }) = return_information {
|
||||||
burns.push(OutInstructionWithBalance {
|
burns.push(OutInstructionWithBalance {
|
||||||
instruction: OutInstruction { address: address.into() },
|
instruction: OutInstruction::Transfer(address.into()),
|
||||||
balance,
|
balance,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user