16 Commits

Author SHA1 Message Date
Luke Parker
ca93c82156 Remove borsh from dkg
It pulls in a lot of bespoke dependencies for little utility directly present.

Moves the necessary code into the processor.
2025-11-16 18:25:23 -05:00
Luke Parker
5b1875dae6 Update lockfile after recent cherry picks 2025-11-16 18:21:02 -05:00
Luke Parker
bcd68441be Use Alpine to build the runtime
Smaller, works without issue.
2025-11-16 18:21:02 -05:00
Luke Parker
4ebf9ad9c7 Rust 1.91.1 due to the regression re: wasm builds 2025-11-16 18:21:02 -05:00
Luke Parker
807572199c Update misc versions 2025-11-16 18:21:02 -05:00
Luke Parker
3cdc1536c5 Make ethereum-schnorr-contract no-std and no-alloc eligible 2025-11-16 18:21:01 -05:00
Luke Parker
9e13e5ebff Patch from parity-bip39 back to bip39
Per https://github.com/michalkucharczyk/rust-bip39/tree/mku-2.0.1-release,
`parity-bip39` was a fork to publish a release of `bip39` with two specific PRs
merged. Not only have those PRs been merged, yet `bip39` now accepts
`bitcoin_hashes 0.14` (https://github.com/rust-bitcoin/rust-bip39/pull/76),
making this a great time to reconcile (even though it does technically add a
git dependency until the new release is cut...).
2025-11-16 18:21:01 -05:00
Luke Parker
9b2c254eee Patch librocksdb-sys to never enable jemalloc, which conflicts with mimalloc
Allows us to update mimalloc and enable the newly added guard pages.

Conflict identified by @PlasmaPower.
2025-11-16 18:20:55 -05:00
Luke Parker
0883479068 Remove rust-src as a component for WASM
It's unnecessary since `wasm32v1-none`.
2025-11-16 17:57:07 -05:00
Luke Parker
c5480c63be Build and run the message queue over Alpine
We prior stopped doing so for stability reasons, but this _should_ be tried
again.
2025-11-16 17:56:51 -05:00
Luke Parker
4280ee6987 revm 33 2025-11-16 17:54:43 -05:00
Luke Parker
91673d7ae3 Remove std feature from revm
It's unnecessary and bloats the tree decently.
2025-11-16 17:52:58 -05:00
Luke Parker
927f07b62b Move bitcoin-serai to core-json and feature-gate the RPC functionality 2025-11-16 17:52:33 -05:00
Luke Parker
7e774d6d2d Correct when spin::Lazy is exposed as std_shims::sync::LazyLock
It's intended to always be used, even on `std`, when `std::sync::LazyLock` is
not available.
2025-11-16 17:52:26 -05:00
Luke Parker
fccd06b376 Bump revm 2025-11-16 17:52:23 -05:00
Luke Parker
e3edc0a7fc Add patches to remove the unused optional dependencies tracked in tree
Also performs the usual `cargo update`.
2025-11-16 17:51:38 -05:00
71 changed files with 717 additions and 853 deletions

View File

@@ -5,7 +5,7 @@ inputs:
version:
description: "Version to download and run"
required: false
default: "29.1"
default: "30.0"
runs:
using: "composite"

View File

@@ -52,9 +52,9 @@ runs:
- name: Install solc
shell: bash
run: |
cargo +1.90 install svm-rs --version =0.5.19
svm install 0.8.26
svm use 0.8.26
cargo +1.91 install svm-rs --version =0.5.19
svm install 0.8.29
svm use 0.8.29
- name: Remove preinstalled Docker
shell: bash

View File

@@ -5,7 +5,7 @@ inputs:
version:
description: "Version to download and run"
required: false
default: v0.18.3.4
default: v0.18.4.3
runs:
using: "composite"

View File

@@ -5,7 +5,7 @@ inputs:
version:
description: "Version to download and run"
required: false
default: v0.18.3.4
default: v0.18.4.3
runs:
using: "composite"

View File

@@ -5,12 +5,12 @@ inputs:
monero-version:
description: "Monero version to download and run as a regtest node"
required: false
default: v0.18.3.4
default: v0.18.4.3
bitcoin-version:
description: "Bitcoin version to download and run as a regtest node"
required: false
default: "29.1"
default: "30.0"
runs:
using: "composite"

View File

@@ -1 +1 @@
nightly-2025-11-01
nightly-2025-11-11

View File

@@ -18,7 +18,7 @@ jobs:
key: rust-advisory-db
- name: Install cargo deny
run: cargo +1.90 install cargo-deny --version =0.18.4
run: cargo +1.91 install cargo-deny --version =0.18.5
- name: Run cargo deny
run: cargo deny -L error --all-features check --hide-inclusion-graph

View File

@@ -26,7 +26,7 @@ jobs:
uses: ./.github/actions/build-dependencies
- name: Install nightly rust
run: rustup toolchain install ${{ steps.nightly.outputs.version }} --profile minimal -t wasm32v1-none -c rust-src -c clippy
run: rustup toolchain install ${{ steps.nightly.outputs.version }} --profile minimal -t wasm32v1-none -c clippy
- name: Run Clippy
run: cargo +${{ steps.nightly.outputs.version }} clippy --all-features --all-targets -- -D warnings -A clippy::items_after_test_module
@@ -52,7 +52,7 @@ jobs:
key: rust-advisory-db
- name: Install cargo deny
run: cargo +1.90 install cargo-deny --version =0.18.4
run: cargo +1.91 install cargo-deny --version =0.18.5
- name: Run cargo deny
run: cargo deny -L error --all-features check --hide-inclusion-graph
@@ -88,8 +88,8 @@ jobs:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- name: Verify all dependencies are in use
run: |
cargo +1.90 install cargo-machete --version =0.9.1
cargo +1.90 machete
cargo +1.91 install cargo-machete --version =0.9.1
cargo +1.91 machete
msrv:
runs-on: ubuntu-latest
@@ -98,7 +98,7 @@ jobs:
- name: Verify claimed `rust-version`
shell: bash
run: |
cargo +1.90 install cargo-msrv --version =0.18.4
cargo +1.91 install cargo-msrv --version =0.18.4
function check_msrv {
# We `cd` into the directory passed as the first argument, but will return to the
@@ -155,8 +155,6 @@ jobs:
# Correct the last line, which was malleated to "],"
members=$(echo "$members" | sed "$(echo "$members" | wc -l)s/\]\,/\]/")
# Don't check the patches
members=$(echo "$members" | grep -v "patches")
# Don't check the following
# Most of these are binaries, with the exception of the Substrate runtime which has a
# bespoke build pipeline
@@ -192,12 +190,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- name: Build Dependencies
uses: ./.github/actions/build-dependencies
- name: Slither
run: |
python3 -m pip install solc-select
solc-select install 0.8.26
solc-select use 0.8.26
python3 -m pip install slither-analyzer
slither --include-paths ./networks/ethereum/schnorr/contracts/Schnorr.sol

762
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -172,6 +172,12 @@ panic = "unwind"
overflow-checks = true
[patch.crates-io]
# Point to empty crates for unused crates in our tree
ark-ff-3 = { package = "ark-ff", path = "patches/ethereum/ark-ff-0.3" }
ark-ff-4 = { package = "ark-ff", path = "patches/ethereum/ark-ff-0.4" }
c-kzg = { path = "patches/ethereum/c-kzg" }
secp256k1-30 = { package = "secp256k1", path = "patches/ethereum/secp256k1-30" }
# Dependencies from monero-oxide which originate from within our own tree
std-shims = { path = "patches/std-shims" }
simple-request = { path = "patches/simple-request" }
@@ -182,12 +188,16 @@ dalek-ff-group = { path = "patches/dalek-ff-group" }
minimal-ed448 = { path = "crypto/ed448" }
modular-frost = { path = "crypto/frost" }
# This has a non-deprecated `std` alternative since Rust's 2024 edition
home = { path = "patches/home" }
# Updates to the latest version
darling = { path = "patches/darling" }
thiserror = { path = "patches/thiserror" }
# 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" }
# These has an `std` alternative since Rust's 2024 edition
home = { path = "patches/home" }
# directories-next was created because directories was unmaintained
# directories-next is now unmaintained while directories is maintained
# The directories author pulls in ridiculously pointless crates and prefers
@@ -196,10 +206,16 @@ home = { path = "patches/home" }
option-ext = { path = "patches/option-ext" }
directories-next = { path = "patches/directories-next" }
# Patch to include `FromUniformBytes<64>` over Scalar
# Patch from a fork back to upstream
parity-bip39 = { path = "patches/parity-bip39" }
# Patch to include `FromUniformBytes<64>` over `Scalar`
k256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" }
p256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" }
# `jemalloc` conflicts with `mimalloc`, so patch to a `rocksdb` which never uses `jemalloc`
librocksdb-sys = { path = "patches/librocksdb-sys" }
[workspace.lints.clippy]
unwrap_or_default = "allow"
map_unwrap_or = "allow"

View File

@@ -35,6 +35,9 @@ mod mutex_shim {
pub use mutex_shim::{ShimMutex as Mutex, MutexGuard};
#[rustversion::before(1.80)]
pub use spin::Lazy as LazyLock;
#[rustversion::since(1.80)]
#[cfg(not(feature = "std"))]
pub use spin::Lazy as LazyLock;
#[rustversion::since(1.80)]

View File

@@ -103,7 +103,7 @@ mod _internal_db {
// Tributary transactions to publish from the DKG confirmation task
TributaryTransactionsFromDkgConfirmation: (set: ExternalValidatorSet) -> Transaction,
// Participants to remove
RemoveParticipant: (set: ExternalValidatorSet) -> Participant,
RemoveParticipant: (set: ExternalValidatorSet) -> u16,
}
}
}
@@ -139,10 +139,11 @@ impl RemoveParticipant {
pub(crate) fn send(txn: &mut impl DbTxn, set: ExternalValidatorSet, participant: Participant) {
// If this set has yet to be retired, send this transaction
if RetiredTributary::get(txn, set.network).map(|session| session.0) < Some(set.session.0) {
_internal_db::RemoveParticipant::send(txn, set, &participant);
_internal_db::RemoveParticipant::send(txn, set, &u16::from(participant));
}
}
pub(crate) fn try_recv(txn: &mut impl DbTxn, set: ExternalValidatorSet) -> Option<Participant> {
_internal_db::RemoveParticipant::try_recv(txn, set)
.map(|i| Participant::new(i).expect("sent invalid participant index for removal"))
}
}

View File

@@ -23,19 +23,12 @@ thiserror = { version = "2", default-features = false }
std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false, features = ["alloc"] }
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true }
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", default-features = false, features = ["alloc"] }
[features]
std = [
"thiserror/std",
"std-shims/std",
"borsh?/std",
"ciphersuite/std",
]
borsh = ["dep:borsh"]
default = ["std"]

View File

@@ -22,7 +22,6 @@ use ciphersuite::{
/// The ID of a participant, defined as a non-zero u16.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Zeroize)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize))]
pub struct Participant(u16);
impl Participant {
/// Create a new Participant identifier from a u16.
@@ -129,18 +128,8 @@ pub enum DkgError {
NotParticipating,
}
// Manually implements BorshDeserialize so we can enforce it's a valid index
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for Participant {
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
Participant::new(u16::deserialize_reader(reader)?)
.ok_or_else(|| io::Error::other("invalid participant"))
}
}
/// Parameters for a multisig.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize))]
pub struct ThresholdParams {
/// Participants needed to sign on behalf of the group.
t: u16,
@@ -210,16 +199,6 @@ impl ThresholdParams {
}
}
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for ThresholdParams {
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
let t = u16::deserialize_reader(reader)?;
let n = u16::deserialize_reader(reader)?;
let i = Participant::deserialize_reader(reader)?;
ThresholdParams::new(t, n, i).map_err(|e| io::Error::other(format!("{e:?}")))
}
}
/// A method of interpolation.
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
pub enum Interpolation<F: Zeroize + PrimeField> {

View File

@@ -141,5 +141,7 @@ allow-git = [
"https://github.com/kayabaNerve/elliptic-curves",
"https://github.com/monero-oxide/monero-oxide",
"https://github.com/kayabaNerve/monero-oxide",
"https://github.com/rust-bitcoin/rust-bip39",
"https://github.com/rust-rocksdb/rust-rocksdb",
"https://github.com/serai-dex/patch-polkadot-sdk",
]

View File

@@ -30,8 +30,8 @@ k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic"
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.11", default-features = false, features = ["secp256k1"] }
hex = { version = "0.4", default-features = false, optional = true }
serde = { version = "1", default-features = false, features = ["derive"], optional = true }
serde_json = { version = "1", default-features = false, optional = true }
core-json-traits = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
core-json-derive = { version = "0.4", default-features = false, optional = true }
simple-request = { path = "../../common/request", version = "0.3", default-features = false, features = ["tokio", "tls", "basic-auth"], optional = true }
[dev-dependencies]
@@ -52,15 +52,16 @@ std = [
"rand_core/std",
"bitcoin/std",
"bitcoin/serde",
"k256/std",
"frost/std",
]
rpc = [
"std",
"hex/std",
"serde/std",
"serde_json/std",
"core-json-traits",
"core-json-derive",
"simple-request",
]
hazmat = []
default = ["std"]
default = ["std", "rpc"]

View File

@@ -14,7 +14,7 @@ pub(crate) mod crypto;
/// Wallet functionality to create transactions.
pub mod wallet;
/// A minimal asynchronous Bitcoin RPC client.
#[cfg(feature = "std")]
#[cfg(feature = "rpc")]
pub mod rpc;
#[cfg(test)]

View File

@@ -1,11 +1,8 @@
use core::fmt::Debug;
use std::collections::HashSet;
use core::{str::FromStr, fmt::Debug};
use std::{io::Read, collections::HashSet};
use thiserror::Error;
use serde::{Deserialize, de::DeserializeOwned};
use serde_json::json;
use simple_request::{hyper, Request, TokioClient as Client};
use bitcoin::{
@@ -14,19 +11,12 @@ use bitcoin::{
Txid, Transaction, BlockHash, Block,
};
#[derive(Clone, PartialEq, Eq, Debug, Deserialize)]
#[derive(Clone, Debug)]
pub struct Error {
code: isize,
message: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
enum RpcResponse<T> {
Ok { result: T },
Err { error: Error },
}
/// A minimal asynchronous Bitcoin RPC client.
#[derive(Clone, Debug)]
pub struct Rpc {
@@ -34,14 +24,14 @@ pub struct Rpc {
url: String,
}
#[derive(Clone, PartialEq, Eq, Debug, Error)]
#[derive(Clone, Debug, Error)]
pub enum RpcError {
#[error("couldn't connect to node")]
ConnectionError,
#[error("request had an error: {0:?}")]
RequestError(Error),
#[error("node replied with invalid JSON")]
InvalidJson(serde_json::error::Category),
InvalidJson,
#[error("node sent an invalid response ({0})")]
InvalidResponse(&'static str),
#[error("node was missing expected methods")]
@@ -66,7 +56,7 @@ impl Rpc {
Rpc { client: Client::with_connection_pool().map_err(|_| RpcError::ConnectionError)?, url };
// Make an RPC request to verify the node is reachable and sane
let res: String = rpc.rpc_call("help", json!([])).await?;
let res: String = rpc.call("help", "[]").await?;
// Verify all methods we expect are present
// If we had a more expanded RPC, due to differences in RPC versions, it wouldn't make sense to
@@ -103,18 +93,16 @@ impl Rpc {
}
/// Perform an arbitrary RPC call.
pub async fn rpc_call<Response: DeserializeOwned + Debug>(
pub async fn call<Response: 'static + Default + core_json_traits::JsonDeserialize>(
&self,
method: &str,
params: serde_json::Value,
params: &str,
) -> Result<Response, RpcError> {
let mut request = Request::from(
hyper::Request::post(&self.url)
.header("Content-Type", "application/json")
.body(
serde_json::to_vec(&json!({ "jsonrpc": "2.0", "method": method, "params": params }))
.unwrap()
.into(),
format!(r#"{{ "method": "{method}", "params": {params} }}"#).as_bytes().to_vec().into(),
)
.unwrap(),
);
@@ -129,11 +117,52 @@ impl Rpc {
.await
.map_err(|_| RpcError::ConnectionError)?;
let res: RpcResponse<Response> =
serde_json::from_reader(&mut res).map_err(|e| RpcError::InvalidJson(e.classify()))?;
#[derive(Default, core_json_derive::JsonDeserialize)]
struct InternalError {
code: Option<i64>,
message: Option<String>,
}
#[derive(core_json_derive::JsonDeserialize)]
struct RpcResponse<T: core_json_traits::JsonDeserialize> {
result: Option<T>,
error: Option<InternalError>,
}
impl<T: core_json_traits::JsonDeserialize> Default for RpcResponse<T> {
fn default() -> Self {
Self { result: None, error: None }
}
}
// TODO: `core_json::ReadAdapter`
let mut res_vec = vec![];
res.read_to_end(&mut res_vec).map_err(|_| RpcError::ConnectionError)?;
let res = <RpcResponse<Response> as core_json_traits::JsonStructure>::deserialize_structure::<
_,
core_json_traits::ConstStack<32>,
>(res_vec.as_slice())
.map_err(|_| RpcError::InvalidJson)?;
match res {
RpcResponse::Ok { result } => Ok(result),
RpcResponse::Err { error } => Err(RpcError::RequestError(error)),
RpcResponse { result: Some(result), error: None } => Ok(result),
RpcResponse { result: None, error: Some(error) } => {
let code =
error.code.ok_or_else(|| RpcError::InvalidResponse("error was missing `code`"))?;
let code = isize::try_from(code)
.map_err(|_| RpcError::InvalidResponse("error code exceeded isize::MAX"))?;
let message =
error.message.ok_or_else(|| RpcError::InvalidResponse("error was missing `message`"))?;
Err(RpcError::RequestError(Error { code, message }))
}
// `invalidateblock` yields this edge case
RpcResponse { result: None, error: None } => {
if core::any::TypeId::of::<Response>() == core::any::TypeId::of::<()>() {
Ok(Default::default())
} else {
Err(RpcError::InvalidResponse("response lacked both a result and an error"))
}
}
_ => Err(RpcError::InvalidResponse("response contained both a result and an error")),
}
}
@@ -146,16 +175,17 @@ impl Rpc {
// tip block of the current chain. The "height" of a block is defined as the amount of blocks
// present when the block was created. Accordingly, the genesis block has height 0, and
// getblockcount will return 0 when it's only the only block, despite their being one block.
self.rpc_call("getblockcount", json!([])).await
usize::try_from(self.call::<u64>("getblockcount", "[]").await?)
.map_err(|_| RpcError::InvalidResponse("latest block number exceeded usize::MAX"))
}
/// Get the hash of a block by the block's number.
pub async fn get_block_hash(&self, number: usize) -> Result<[u8; 32], RpcError> {
let mut hash = self
.rpc_call::<BlockHash>("getblockhash", json!([number]))
.await?
.as_raw_hash()
.to_byte_array();
let mut hash =
BlockHash::from_str(&self.call::<String>("getblockhash", &format!("[{number}]")).await?)
.map_err(|_| RpcError::InvalidResponse("block hash was not valid hex"))?
.as_raw_hash()
.to_byte_array();
// bitcoin stores the inner bytes in reverse order.
hash.reverse();
Ok(hash)
@@ -163,16 +193,25 @@ impl Rpc {
/// Get a block's number by its hash.
pub async fn get_block_number(&self, hash: &[u8; 32]) -> Result<usize, RpcError> {
#[derive(Deserialize, Debug)]
#[derive(Default, core_json_derive::JsonDeserialize)]
struct Number {
height: usize,
height: Option<u64>,
}
Ok(self.rpc_call::<Number>("getblockheader", json!([hex::encode(hash)])).await?.height)
usize::try_from(
self
.call::<Number>("getblockheader", &format!(r#"["{}"]"#, hex::encode(hash)))
.await?
.height
.ok_or_else(|| {
RpcError::InvalidResponse("`getblockheader` did not include `height` field")
})?,
)
.map_err(|_| RpcError::InvalidResponse("block number exceeded usize::MAX"))
}
/// Get a block by its hash.
pub async fn get_block(&self, hash: &[u8; 32]) -> Result<Block, RpcError> {
let hex = self.rpc_call::<String>("getblock", json!([hex::encode(hash), 0])).await?;
let hex = self.call::<String>("getblock", &format!(r#"["{}", 0]"#, hex::encode(hash))).await?;
let bytes: Vec<u8> = FromHex::from_hex(&hex)
.map_err(|_| RpcError::InvalidResponse("node didn't use hex to encode the block"))?;
let block: Block = encode::deserialize(&bytes)
@@ -189,8 +228,13 @@ impl Rpc {
/// Publish a transaction.
pub async fn send_raw_transaction(&self, tx: &Transaction) -> Result<Txid, RpcError> {
let txid = match self.rpc_call("sendrawtransaction", json!([encode::serialize_hex(tx)])).await {
Ok(txid) => txid,
let txid = match self
.call::<String>("sendrawtransaction", &format!(r#"["{}"]"#, encode::serialize_hex(tx)))
.await
{
Ok(txid) => {
Txid::from_str(&txid).map_err(|_| RpcError::InvalidResponse("TXID was not valid hex"))?
}
Err(e) => {
// A const from Bitcoin's bitcoin/src/rpc/protocol.h
const RPC_VERIFY_ALREADY_IN_CHAIN: isize = -27;
@@ -211,7 +255,8 @@ impl Rpc {
/// Get a transaction by its hash.
pub async fn get_transaction(&self, hash: &[u8; 32]) -> Result<Transaction, RpcError> {
let hex = self.rpc_call::<String>("getrawtransaction", json!([hex::encode(hash)])).await?;
let hex =
self.call::<String>("getrawtransaction", &format!(r#"["{}"]"#, hex::encode(hash))).await?;
let bytes: Vec<u8> = FromHex::from_hex(&hex)
.map_err(|_| RpcError::InvalidResponse("node didn't use hex to encode the transaction"))?;
let tx: Transaction = encode::deserialize(&bytes)

View File

@@ -14,9 +14,9 @@ pub(crate) async fn rpc() -> Rpc {
// If this node has already been interacted with, clear its chain
if rpc.get_latest_block_number().await.unwrap() > 0 {
rpc
.rpc_call(
.call(
"invalidateblock",
serde_json::json!([hex::encode(rpc.get_block_hash(1).await.unwrap())]),
&format!(r#"["{}"]"#, hex::encode(rpc.get_block_hash(1).await.unwrap())),
)
.await
.unwrap()

View File

@@ -41,21 +41,21 @@ async fn send_and_get_output(rpc: &Rpc, scanner: &Scanner, key: ProjectivePoint)
let block_number = rpc.get_latest_block_number().await.unwrap() + 1;
rpc
.rpc_call::<Vec<String>>(
.call::<Vec<String>>(
"generatetoaddress",
serde_json::json!([
1,
&format!(
r#"[1, "{}"]"#,
Address::from_script(&p2tr_script_buf(key).unwrap(), Network::Regtest).unwrap()
]),
),
)
.await
.unwrap();
// Mine until maturity
rpc
.rpc_call::<Vec<String>>(
.call::<Vec<String>>(
"generatetoaddress",
serde_json::json!([100, Address::p2sh(Script::new(), Network::Regtest).unwrap()]),
&format!(r#"[100, "{}"]"#, Address::p2sh(Script::new(), Network::Regtest).unwrap()),
)
.await
.unwrap();

View File

@@ -6,7 +6,7 @@ use std::{path::PathBuf, fs, process::Command};
/// Build contracts from the specified path, outputting the artifacts to the specified path.
///
/// Requires solc 0.8.26.
/// Requires solc 0.8.29.
pub fn build(
include_paths: &[&str],
contracts_path: &str,
@@ -35,8 +35,8 @@ pub fn build(
if let Some(version) = line.strip_prefix("Version: ") {
let version =
version.split('+').next().ok_or_else(|| "no value present on line".to_string())?;
if version != "0.8.26" {
Err(format!("version was {version}, 0.8.26 required"))?
if version != "0.8.29" {
Err(format!("version was {version}, 0.8.29 required"))?
}
}
}

View File

@@ -16,10 +16,12 @@ rustdoc-args = ["--cfg", "docsrs"]
workspace = true
[dependencies]
subtle = { version = "2", default-features = false, features = ["std"] }
sha3 = { version = "0.10", default-features = false, features = ["std"] }
group = { version = "0.13", default-features = false, features = ["alloc"] }
k256 = { version = "^0.13.1", default-features = false, features = ["std", "arithmetic"] }
std-shims = { path = "../../../common/std-shims", version = "0.1", default-features = false }
subtle = { version = "2", default-features = false }
sha3 = { version = "0.10", default-features = false }
group = { version = "0.13", default-features = false }
k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic"] }
[build-dependencies]
build-solidity-contracts = { path = "../build-contracts", version = "0.1" }
@@ -40,3 +42,8 @@ alloy-provider = { version = "1", default-features = false }
alloy-node-bindings = { version = "1", default-features = false }
tokio = { version = "1", default-features = false, features = ["macros"] }
[features]
alloc = ["std-shims/alloc", "group/alloc"]
std = ["alloc", "std-shims/std", "subtle/std", "sha3/std", "k256/std"]
default = ["std"]

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
/// @title A library for verifying Schnorr signatures
/// @author Luke Parker <lukeparker@serai.exchange>

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
import "../Schnorr.sol";

View File

@@ -2,6 +2,7 @@
#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
#![allow(non_snake_case)]
#![cfg_attr(not(feature = "std"), no_std)]
mod public_key;
pub use public_key::PublicKey;

View File

@@ -1,4 +1,4 @@
use std::io;
use std_shims::io;
use sha3::{Digest, Keccak256};
@@ -77,6 +77,7 @@ impl Signature {
}
/// Write the signature.
#[cfg(feature = "alloc")]
pub fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_all(&self.to_bytes())
}

View File

@@ -1,50 +0,0 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
# This GPG-signed message exists to confirm the SHA256 sums of Monero binaries.
#
# Please verify the signature against the key for binaryFate in the
# source code repository (/utils/gpg_keys).
#
#
## CLI
6122f0bcaca12d5badd92002338847d16032f6d52d86155c203bcb67d4fe1518 monero-android-armv7-v0.18.4.2.tar.bz2
3b248c3201f028205915403b4b2f173df0dd8bf47eeb268fd67a4661251469d3 monero-android-armv8-v0.18.4.2.tar.bz2
b4e2b7de80107a1b4613b878d8e2114244b3fb16397821d69baa72d9b0f8c8d5 monero-freebsd-x64-v0.18.4.2.tar.bz2
ecb2577499a3b0901d731e11d462d3fadcd70095f3ab0def0c27ee64dc56b061 monero-linux-armv7-v0.18.4.2.tar.bz2
a39530054dac348b219f1048a24ca629da26990f72cf9c1f6b6853e3d8c39a79 monero-linux-armv8-v0.18.4.2.tar.bz2
18492ace80bf8ef2f44aa9a99b4f20adf00fd59c675a6a496211a720088d5d1a monero-linux-riscv64-v0.18.4.2.tar.bz2
41d023f2357244ea43ee0a74796f5705ce75ce7373a5865d4959fefa13ecab06 monero-linux-x64-v0.18.4.2.tar.bz2
03e77a4836861a47430664fa703dd149a355b3b214bc400b04ed38eb064a3ef0 monero-linux-x86-v0.18.4.2.tar.bz2
9b98da6911b4769abef229c20e21f29d919b11db156965d6f139d2e1ad6625c2 monero-mac-armv8-v0.18.4.2.tar.bz2
b1b1b580320118d3b6eaa5575fdbd73cf4db90fcc025b7abf875c5e5b4e335c1 monero-mac-x64-v0.18.4.2.tar.bz2
14dd5aa11308f106183dd7834aa200e74ce6f3497103973696b556e893a4fef2 monero-win-x64-v0.18.4.2.zip
934d9dbeb06ff5610d2c96ebe34fa480e74f78eaeb3fa3e47d89b7961c9bc5e0 monero-win-x86-v0.18.4.2.zip
e9ec2062b3547db58f00102e6905621116ab7f56a331e0bc9b9e892607b87d24 monero-source-v0.18.4.2.tar.bz2
#
## GUI
9d6e87add7e3ac006ee34c13c4f629252595395f54421db768f72dc233e94ea8 monero-gui-install-win-x64-v0.18.4.2.exe
e4fcdea3f0ff27c3616a8a75545f42a4e4866ea374fa2eeaa9c87027573358ea monero-gui-linux-x64-v0.18.4.2.tar.bz2
3dfee5c5d8e000c72eb3755bf0eb03ca7c5928b69c3a241e147ad22d144e00a7 monero-gui-mac-armv8-v0.18.4.2.dmg
16abadcbd608d4f7ba20d17a297f2aa2c9066d33f6f22bf3fcdca679ab603990 monero-gui-mac-x64-v0.18.4.2.dmg
4daff8850280173d46464ba9a9de7f712228ad1ef76a1c4954531e4fd2b86d86 monero-gui-win-x64-v0.18.4.2.zip
691085e61ece6c56738431f3cfd395536ca0675214e5991e0dbfab85025e82d7 monero-gui-source-v0.18.4.2.tar.bz2
#
#
# ~binaryFate
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEgaxZH+nEtlxYBq/D8K9NRioL35IFAmitx+kACgkQ8K9NRioL
35J6cQ/7ByvGstg/a5lIYbB+Lz5bNiPozCILD9/offvC7GgOvna9rkHuofuLS+pX
qhYEMrjFjmp03XMY+i68M83qkBEZ+yU5iNDbwRuHUNMMWaaGlhnhm3nyUVtDpjjr
4xwVsee+dzi0JZhVQG7HJFURiP2Ub5Ua6bSaATDoT/aUYdhmrOnQiH2+VxogiCv3
JStDqXq6LpFjzw7UkAfxxu1PW+AQFNBzi3L0qWfzb5WWL7xuK63wXGmEkYBlvult
qt3LUhDUzMrfZ5GiiOYDEw44Y2atD4ibOYtBnllCX9CKNb0o2KKU6Qkj+CYqqtnE
uGNOt1oT09VPOtE7OUkBLVkALjef7ZXRibE7tN4wSnsrG39DP795/52L6CGJbl4n
UDnHzLCUbuvhnoAu5U+rUP5nUEDYS9ANNyj610ogNCo7YjfzLH641WSQ/UnuXKkA
RmK8xIiKoOnUeOanX99zqeXqV7gQdQMlfwLUr3pQzCI2YjdvxdRoedSEi5nX5KvO
Snf3BcCYMBemGYqVMdo95tc0Gmsw12/O8WwrBbTea+PeAXJuLaBxrLNn+RNZLfF/
UJYq2VcEwxG6vXb3cJ5lDKmRDDRI8Fxu6Amdab+6ponhM8Zy3eAynVIO952pLA7N
dtl72RsimM+sgHXP4ERYL4c6WARSHE5sAiog43dr56l3PPmM8pE=
=SoHG
-----END PGP SIGNATURE-----

View File

@@ -0,0 +1,50 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
# This GPG-signed message exists to confirm the SHA256 sums of Monero binaries.
#
# Please verify the signature against the key for binaryFate in the
# source code repository (/utils/gpg_keys).
#
#
## CLI
4e1481835824b9233f204553d4a19645274824f3f6185d8a4b50198470752f54 monero-android-armv7-v0.18.4.3.tar.bz2
1aebd24aaaec3d1e87a64163f2e30ab2cd45f3902a7a859413f6870944775c21 monero-android-armv8-v0.18.4.3.tar.bz2
ff7b9c5cf2cb3d602c3dff1902ac0bc3394768cefc260b6003a9ad4bcfb7c6a4 monero-freebsd-x64-v0.18.4.3.tar.bz2
3ac83049bc565fb5238501f0fa629cdd473bbe94d5fb815088af8e6ff1d761cd monero-linux-armv7-v0.18.4.3.tar.bz2
b1cc5f135de3ba8512d56deb4b536b38c41addde922b2a53bf443aeaf2a5a800 monero-linux-armv8-v0.18.4.3.tar.bz2
95baaa6e8957b92caeaed7fb19b5c2659373df8dd5f4de2601ed3dae7b17ce2f monero-linux-riscv64-v0.18.4.3.tar.bz2
3a7b36ae4da831a4e9913e0a891728f4c43cd320f9b136cdb6686b1d0a33fafa monero-linux-x64-v0.18.4.3.tar.bz2
e0b51ca71934c33cb83cfa8535ffffebf431a2fc9efe3acf2baad96fb6ce21ec monero-linux-x86-v0.18.4.3.tar.bz2
bab9a6d3c2ca519386cff5ff0b5601642a495ed1a209736acaf354468cba1145 monero-mac-armv8-v0.18.4.3.tar.bz2
a8d8273b14f31569f5b7aa3063fbd322e3caec3d63f9f51e287dfc539c7f7d61 monero-mac-x64-v0.18.4.3.tar.bz2
bd9f615657c35d2d7dd9a5168ad54f1547dbf9a335dee7f12fab115f6f394e36 monero-win-x64-v0.18.4.3.zip
e642ed7bbfa34c30b185387fa553aa9c3ea608db1f3fc0e9332afa9b522c9c1a monero-win-x86-v0.18.4.3.zip
6ba5e082c8fa25216aba7aea8198f3e23d4b138df15c512457081e1eb3d03ff6 monero-source-v0.18.4.3.tar.bz2
#
## GUI
7b9255c696a462a00a810d9c8f94e60400a9e7d6438e8d6a8b693e9c13dca9ab monero-gui-install-win-x64-v0.18.4.3.exe
0bd84de0a7c18b2a3ea8e8eff2194ae000cf1060045badfd4ab48674bc1b9325 monero-gui-linux-x64-v0.18.4.3.tar.bz2
68ea30db32efb4a0671ec723297b6629d932fa188edf76edb38a37adaa3528e6 monero-gui-mac-armv8-v0.18.4.3.dmg
27243b01f030fdae68c59cae1daf21f530bbadeaf10579d2908db9a834191cee monero-gui-mac-x64-v0.18.4.3.dmg
dc9531cb4319b37b2c2dea4126e44a0fe6e7b6f34d278ccf5dd9ba693e3031e0 monero-gui-win-x64-v0.18.4.3.zip
0d44687644db9b1824f324416e98f4a46b3bb0a5ed09af54b2835b6facaa0cdd monero-gui-source-v0.18.4.3.tar.bz2
#
#
# ~binaryFate
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEgaxZH+nEtlxYBq/D8K9NRioL35IFAmjntxwACgkQ8K9NRioL
35J57g//dUOY1KAoLNaV7XLJyGbNk1lT6c2+A8h1wkK6iNQhXsmnc6rcigsHXrG0
LQyVUuZJ6ELhNb6BnH5V0zbcB72t8XjkSEqlYhStUfMnaUvj1VdXtL/OnSs3fEvt
Zwz6QBTxIKDDYEYyXrvCK96cYaYlIOgK3IVn/zoHdrHRUqTXqRJkFoTHum5l783y
vr9BwMFFWYePUrilphjIiLyJDl+eB5al8PaJkqK2whxBUHoA2jF1edJOSq2mZajI
+L2fBYClePS8oqwoKGquqCh2RVcmdtXtQTVzRIoNx14qFzP8ymqa+6z1Ygkri7bV
qMCJk7KQ8ND7uU9NShpaCIqrZpr5GZ4Al6SRkcpK/7mipQcy2QpKJR3iOpcfiTX1
YmYGVmLB3zmHu2kiS0kogZv6Ob7+tVFzOQ8NZX4FVnpB0N0phqMfNFOfHzdQZrsZ
qg29HNc9sHlUmsOVmE5w+7Oq+s79yvQB3034XXi/9wQu+f8fKRhqZboe0fe77FLf
QXoAYrZZ7LnGz0Z75Q9O4RB7uxM0Ug5imvyEFus4iuBVyBWjgcfyLnbkKJtbXmfn
BZBbTProhPJfVa/VffBxW9HZB27W7O14oGWVpUkGWnVMZfVY/78XTUHwxaScQsPO
SGawjobQsB3pTMNr/kra1XTjkti70si8Fcs5ueYWGB3yfc6r3hU=
=5HRY
-----END PGP SIGNATURE-----

View File

@@ -1,14 +1,7 @@
# rust:1.89.0-slim-bookworm as of August 1st, 2025 (GMT)
FROM --platform=linux/amd64 rust@sha256:703cfb0f80db8eb8a3452bf5151162472039c1b37fe4fb2957b495a6f0104ae7 AS deterministic
# rust:1.91.1-alpine as of November 11th, 2025 (GMT)
FROM --platform=linux/amd64 rust@sha256:700c0959b23445f69c82676b72caa97ca4359decd075dca55b13339df27dc4d3 AS deterministic
# Move to a Debian package snapshot
RUN rm -rf /etc/apt/sources.list.d/debian.sources && \
rm -rf /var/lib/apt/lists/* && \
echo "deb [arch=amd64] http://snapshot.debian.org/archive/debian/20250801T000000Z bookworm main" > /etc/apt/sources.list && \
apt update
# Install dependencies
RUN apt update -y && apt upgrade -y && apt install -y clang
RUN apk add musl-dev=1.2.5-r10
# Add the wasm toolchain
RUN rustup target add wasm32v1-none
@@ -35,6 +28,7 @@ ADD AGPL-3.0 /serai
WORKDIR /serai
# Build the runtime, copying it to the volume if it exists
ENV RUSTFLAGS="-Ctarget-feature=-crt-static"
CMD cargo build --release -p serai-runtime && \
mkdir -p /volume && \
cp /serai/target/release/wbuild/serai-runtime/serai_runtime.wasm /volume/serai.wasm

View File

@@ -19,6 +19,7 @@ pub fn coordinator(
let setup = mimalloc(Os::Debian).to_string() +
&build_serai_service(
"",
Os::Debian,
network.release(),
&format!("{db} {longer_reattempts}"),
"serai-coordinator",

View File

@@ -4,7 +4,13 @@ use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
pub fn ethereum_relayer(orchestration_path: &Path, network: Network) {
let setup = mimalloc(Os::Debian).to_string() +
&build_serai_service("", network.release(), network.db(), "serai-ethereum-relayer");
&build_serai_service(
"",
Os::Debian,
network.release(),
network.db(),
"serai-ethereum-relayer",
);
let env_vars = [
("DB_PATH", "/volume/ethereum-relayer-db".to_string()),

View File

@@ -143,13 +143,20 @@ WORKDIR /home/{user}
}
}
fn build_serai_service(prelude: &str, release: bool, features: &str, package: &str) -> String {
fn build_serai_service(
prelude: &str,
os: Os,
release: bool,
features: &str,
package: &str,
) -> String {
let profile = if release { "release" } else { "debug" };
let profile_flag = if release { "--release" } else { "" };
format!(
r#"
FROM rust:1.90-slim-trixie AS builder
(match os {
Os::Debian => {
r#"
FROM rust:1.91-slim-trixie AS builder
COPY --from=mimalloc-debian libmimalloc.so /usr/lib
RUN echo "/usr/lib/libmimalloc.so" >> /etc/ld.so.preload
@@ -161,7 +168,25 @@ RUN apt install -y pkg-config libclang-dev clang
# Dependencies for the Serai node
RUN apt install -y make protobuf-compiler
"#
}
Os::Alpine => {
r#"
FROM rust:1.91-alpine AS builder
COPY --from=mimalloc-alpine libmimalloc.so /usr/lib
ENV LD_PRELOAD=libmimalloc.so
RUN apk update && apk upgrade
# Add dev dependencies
RUN apk add clang-dev
"#
}
})
.to_owned() +
&format!(
r#"
# Add the wasm toolchain
RUN rustup target add wasm32v1-none
@@ -195,7 +220,7 @@ RUN --mount=type=cache,target=/root/.cargo \
cargo build {profile_flag} --features "{features}" -p {package} && \
mv /serai/target/{profile}/{package} /serai/bin
"#
)
)
}
pub fn write_dockerfile(path: PathBuf, dockerfile: &str) {

View File

@@ -13,8 +13,8 @@ pub fn message_queue(
ethereum_key: <Ristretto as WrappedGroup>::G,
monero_key: <Ristretto as WrappedGroup>::G,
) {
let setup = mimalloc(Os::Debian).to_string() +
&build_serai_service("", network.release(), network.db(), "serai-message-queue");
let setup = mimalloc(Os::Alpine).to_string() +
&build_serai_service("", Os::Alpine, network.release(), network.db(), "serai-message-queue");
let env_vars = [
("COORDINATOR_KEY", hex::encode(coordinator_key.to_bytes())),
@@ -41,7 +41,7 @@ CMD {env_vars_str} serai-message-queue
"#
);
let run = os(Os::Debian, "", "messagequeue") + &run_message_queue;
let run = os(Os::Alpine, "", "messagequeue") + &run_message_queue;
let res = setup + &run;
let mut message_queue_path = orchestration_path.to_path_buf();

View File

@@ -7,10 +7,10 @@ FROM alpine:latest AS mimalloc-alpine
RUN apk update && apk upgrade && apk --no-cache add gcc g++ libc-dev make cmake git
RUN git clone https://github.com/microsoft/mimalloc && \
cd mimalloc && \
git checkout 43ce4bd7fd34bcc730c1c7471c99995597415488 && \
git checkout fbd8b99c2b828428947d70fdc046bb55609be93e && \
mkdir -p out/secure && \
cd out/secure && \
cmake -DMI_SECURE=ON ../.. && \
cmake -DMI_SECURE=ON -DMI_GUARDED=on ../.. && \
make && \
cp ./libmimalloc-secure.so ../../../libmimalloc.so
"#;
@@ -21,10 +21,10 @@ FROM debian:trixie-slim AS mimalloc-debian
RUN apt update && apt upgrade -y && apt install -y gcc g++ make cmake git
RUN git clone https://github.com/microsoft/mimalloc && \
cd mimalloc && \
git checkout 43ce4bd7fd34bcc730c1c7471c99995597415488 && \
git checkout fbd8b99c2b828428947d70fdc046bb55609be93e && \
mkdir -p out/secure && \
cd out/secure && \
cmake -DMI_SECURE=ON ../.. && \
cmake -DMI_SECURE=ON -DMI_GUARDED=on ../.. && \
make && \
cp ./libmimalloc-secure.so ../../../libmimalloc.so
"#;

View File

@@ -7,7 +7,7 @@ pub fn bitcoin(orchestration_path: &Path, network: Network) {
const DOWNLOAD_BITCOIN: &str = r#"
FROM alpine:latest AS bitcoin
ENV BITCOIN_VERSION=29.1
ENV BITCOIN_VERSION=30.0
RUN apk --no-cache add wget git gnupg

View File

@@ -10,7 +10,7 @@ fn monero_internal(
monero_binary: &str,
ports: &str,
) {
const MONERO_VERSION: &str = "0.18.4.2";
const MONERO_VERSION: &str = "0.18.4.3";
let arch = match std::env::consts::ARCH {
// We probably would run this without issues yet it's not worth needing to provide support for

View File

@@ -22,12 +22,13 @@ pub fn processor(
if coin == "ethereum" {
r#"
RUN cargo install svm-rs
RUN svm install 0.8.26
RUN svm use 0.8.26
RUN svm install 0.8.29
RUN svm use 0.8.29
"#
} else {
""
},
Os::Debian,
network.release(),
&format!("binaries {} {coin}", network.db()),
"serai-processor",

View File

@@ -12,9 +12,10 @@ pub fn serai(
serai_key: &Zeroizing<<Ristretto as WrappedGroup>::F>,
) {
// Always builds in release for performance reasons
let setup = mimalloc(Os::Debian).to_string() + &build_serai_service("", true, "", "serai-node");
let setup_fast_epoch =
mimalloc(Os::Debian).to_string() + &build_serai_service("", true, "fast-epoch", "serai-node");
let setup =
mimalloc(Os::Debian).to_string() + &build_serai_service("", Os::Debian, true, "", "serai-node");
let setup_fast_epoch = mimalloc(Os::Debian).to_string() +
&build_serai_service("", Os::Debian, true, "fast-epoch", "serai-node");
let env_vars = [("KEY", hex::encode(serai_key.to_repr()))];
let mut env_vars_str = String::new();

View File

@@ -0,0 +1,16 @@
[package]
name = "darling"
version = "0.20.99"
description = "Patch to the latest version"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/darling"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
darling = { version = "0.21" }

View File

@@ -0,0 +1 @@
pub use darling::*;

View File

@@ -0,0 +1,16 @@
[package]
name = "ark-ff"
version = "0.3.99"
description = "Patch to an empty crate"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/ark-ff-0.3"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[features]
std = []

View File

@@ -0,0 +1 @@
const _NEVER_COMPILED: [(); 0 - 1] = [(); 0 - 1];

View File

@@ -0,0 +1,16 @@
[package]
name = "ark-ff"
version = "0.4.99"
description = "Patch to an empty crate"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/ark-ff-0.4"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[features]
std = []

View File

@@ -0,0 +1 @@
const _NEVER_COMPILED: [(); 0 - 1] = [(); 0 - 1];

View File

@@ -0,0 +1,18 @@
[package]
name = "c-kzg"
version = "2.99.99"
description = "Patch to an empty crate"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/c-kzg"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[features]
std = []
serde = []
ethereum_kzg_settings = []

View File

@@ -0,0 +1 @@
const _NEVER_COMPILED: [(); 0 - 1] = [(); 0 - 1];

View File

@@ -0,0 +1,21 @@
[package]
name = "secp256k1"
version = "0.30.99"
description = "Patch to an empty crate"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/secp256k1-30"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[features]
alloc = []
std = []
rand = []
serde = []
global-context = []
recovery = []

View File

@@ -0,0 +1 @@
const _NEVER_COMPILED: [(); 0 - 1] = [(); 0 - 1];

View File

@@ -0,0 +1,35 @@
[package]
name = "librocksdb-sys"
version = "0.17.99"
description = "Replacement for `librocksdb-sys` which removes the `jemalloc` feature"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/librocksdb-sys"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2018"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[workspace]
[dependencies]
# librocksdb-sys 0.17.3+10.4.2, with the commit provided by crates.io in `cargo_vcs_info.json`
librocksdb-sys = { git = "https://github.com/rust-rocksdb/rust-rocksdb", commit = "bb7d2168eab1bc7849f23adbcb825e3aba1bd2f4", default-features = false }
[features]
default = ["librocksdb-sys/default"]
jemalloc = []
static = ["librocksdb-sys/static"]
bindgen-runtime = ["librocksdb-sys/bindgen-runtime"]
bindgen-static = ["librocksdb-sys/bindgen-static"]
mt_static = ["librocksdb-sys/mt_static"]
io-uring = ["librocksdb-sys/io-uring"]
snappy = ["librocksdb-sys/snappy"]
lz4 = ["librocksdb-sys/lz4"]
zstd = ["librocksdb-sys/zstd"]
zlib = ["librocksdb-sys/zlib"]
bzip2 = ["librocksdb-sys/bzip2"]
rtti = ["librocksdb-sys/rtti"]
lto = ["librocksdb-sys/lto"]

View File

@@ -0,0 +1 @@
pub use librocksdb_sys::*;

View File

@@ -0,0 +1,30 @@
[package]
name = "parity-bip39"
version = "2.99.99"
description = "Patch back to the upstream library"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/parity-bip39"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[workspace]
[dependencies]
bip39 = { git = "https://github.com/rust-bitcoin/rust-bip39", commit = "f735e2559f30049f6738d1bf68c69a0b7bd7b858", default-features = false }
[features]
default = ["bip39/default"]
alloc = ["bip39/alloc"]
std = ["bip39/std"]
unicode-normalization = ["bip39/unicode-normalization"]
all-languages = ["bip39/all-languages"]
zeroize = ["bip39/zeroize"]
rand_core = ["bip39/rand_core"]
rand = ["bip39/rand"]

View File

@@ -0,0 +1,3 @@
#![cfg_attr(not(feature = "std"), no_std)]
pub use bip39::*;

View File

@@ -0,0 +1,16 @@
[package]
name = "thiserror"
version = "1.99.99"
description = "Patch to the latest version"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/thiserror"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
thiserror = { version = "2", features = ["std"] }

View File

@@ -0,0 +1 @@
pub use thiserror::*;

View File

@@ -29,7 +29,7 @@ dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features =
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false }
secp256k1 = { version = "0.29", default-features = false, features = ["std", "global-context", "rand-std"] }
bitcoin-serai = { path = "../../networks/bitcoin", default-features = false, features = ["std"] }
bitcoin-serai = { path = "../../networks/bitcoin", default-features = false, features = ["std", "rpc"] }
serai-client = { path = "../../substrate/client", default-features = false, features = ["bitcoin"] }

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
/*
The expected deployment process of Serai's Router is as follows:

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: CC0
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);

View File

@@ -33,9 +33,9 @@ alloy-rpc-types-eth = { version = "1", default-features = false }
alloy-transport = { version = "1", default-features = false }
alloy-provider = { version = "1", default-features = false }
revm = { version = "29", default-features = false, features = ["std"] }
revm = { version = "33", default-features = false }
ethereum-schnorr = { package = "ethereum-schnorr-contract", path = "../../../networks/ethereum/schnorr", default-features = false }
ethereum-schnorr = { package = "ethereum-schnorr-contract", path = "../../../networks/ethereum/schnorr", default-features = false, features = ["std"] }
ethereum-primitives = { package = "serai-processor-ethereum-primitives", path = "../primitives", default-features = false }
ethereum-deployer = { package = "serai-processor-ethereum-deployer", path = "../deployer", default-features = false }

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
/// @title Serai Router (without functions overriden by selector collisions)
/// @author Luke Parker <lukeparker@serai.exchange>

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
import "IERC20.sol";
@@ -223,7 +223,7 @@ contract Router is IRouterWithoutCollisions {
/*
Advance the message past the function selector, enabling decoding the arguments. Ideally, we'd
also advance past the signature (to simplify decoding arguments and save some memory). This
would transfrom message from:
would transform message from:
message (pointer)
v

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
import "Router.sol";

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
contract TestERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.26;
pragma solidity ^0.8.29;
import "Router.sol";

View File

@@ -31,7 +31,15 @@ struct RawParams {
#[derive(BorshSerialize, BorshDeserialize)]
pub(crate) struct Participations {
#[borsh(
serialize_with = "messages::borsh_serialize_participant_map",
deserialize_with = "messages::borsh_deserialize_participant_map"
)]
pub(crate) substrate_participations: HashMap<Participant, Vec<u8>>,
#[borsh(
serialize_with = "messages::borsh_serialize_participant_map",
deserialize_with = "messages::borsh_deserialize_participant_map"
)]
pub(crate) network_participations: HashMap<Participant, Vec<u8>>,
}

View File

@@ -23,7 +23,7 @@ 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"] }
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "borsh"] }
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std"] }
serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std", "borsh"] }
in-instructions-primitives = { package = "serai-in-instructions-primitives", path = "../../substrate/in-instructions/primitives", default-features = false, features = ["std", "borsh"] }

View File

@@ -21,6 +21,44 @@ pub struct SubstrateContext {
pub network_latest_finalized_block: BlockHash,
}
pub fn borsh_serialize_participant<W: borsh::io::Write>(
value: &Participant,
writer: &mut W,
) -> borsh::io::Result<()> {
u16::from(*value).serialize(writer)
}
pub fn borsh_deserialize_participant<R: borsh::io::Read>(
reader: &mut R,
) -> borsh::io::Result<Participant> {
u16::deserialize_reader(reader).and_then(|p| {
Participant::new(p)
.ok_or_else(|| borsh::io::Error::other("invalid `Participant` despite valid `u16`"))
})
}
pub fn borsh_serialize_participant_map<W: borsh::io::Write>(
value: &HashMap<Participant, Vec<u8>>,
writer: &mut W,
) -> borsh::io::Result<()> {
value
.iter()
.map(|(key, value)| (u16::from(*key), value))
.collect::<HashMap<u16, &Vec<u8>>>()
.serialize(writer)
}
pub fn borsh_deserialize_participant_map<R: borsh::io::Read>(
reader: &mut R,
) -> borsh::io::Result<HashMap<Participant, Vec<u8>>> {
HashMap::<u16, Vec<u8>>::deserialize_reader(reader)?
.into_iter()
.map(|(key, value)| {
Participant::new(key)
.ok_or_else(|| borsh::io::Error::other("invalid `Participant` despite valid `u16` in map"))
.map(|key| (key, value))
})
.collect()
}
pub mod key_gen {
use super::*;
@@ -33,7 +71,15 @@ pub mod key_gen {
/// Received participations for the specified key generation protocol.
///
/// This is sent by the Coordinator's Tributary scanner.
Participation { session: Session, participant: Participant, participation: Vec<u8> },
Participation {
session: Session,
#[borsh(
serialize_with = "borsh_serialize_participant",
deserialize_with = "borsh_deserialize_participant"
)]
participant: Participant,
participation: Vec<u8>,
},
}
impl core::fmt::Debug for CoordinatorMessage {
@@ -58,11 +104,25 @@ pub mod key_gen {
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub enum ProcessorMessage {
// Participated in the specified key generation protocol.
Participation { session: Session, participation: Vec<u8> },
Participation {
session: Session,
participation: Vec<u8>,
},
// Resulting keys from the specified key generation protocol.
GeneratedKeyPair { session: Session, substrate_key: [u8; 32], network_key: Vec<u8> },
GeneratedKeyPair {
session: Session,
substrate_key: [u8; 32],
network_key: Vec<u8>,
},
// Blame this participant.
Blame { session: Session, participant: Participant },
Blame {
session: Session,
#[borsh(
serialize_with = "borsh_serialize_participant",
deserialize_with = "borsh_deserialize_participant"
)]
participant: Participant,
},
}
impl core::fmt::Debug for ProcessorMessage {
@@ -127,11 +187,25 @@ pub mod sign {
/// Received preprocesses for the specified signing protocol.
///
/// This is sent by the Coordinator's Tributary scanner.
Preprocesses { id: SignId, preprocesses: HashMap<Participant, Vec<u8>> },
Preprocesses {
id: SignId,
#[borsh(
serialize_with = "borsh_serialize_participant_map",
deserialize_with = "borsh_deserialize_participant_map"
)]
preprocesses: HashMap<Participant, Vec<u8>>,
},
// Received shares for the specified signing protocol.
///
/// This is sent by the Coordinator's Tributary scanner.
Shares { id: SignId, shares: HashMap<Participant, Vec<u8>> },
Shares {
id: SignId,
#[borsh(
serialize_with = "borsh_serialize_participant_map",
deserialize_with = "borsh_deserialize_participant_map"
)]
shares: HashMap<Participant, Vec<u8>>,
},
// Re-attempt a signing protocol.
///
/// This is sent by the Coordinator's Tributary re-attempt scheduling logic.
@@ -152,11 +226,24 @@ pub mod sign {
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
pub enum ProcessorMessage {
// Participant sent an invalid message during the sign protocol.
InvalidParticipant { session: Session, participant: Participant },
InvalidParticipant {
session: Session,
#[borsh(
serialize_with = "borsh_serialize_participant",
deserialize_with = "borsh_deserialize_participant"
)]
participant: Participant,
},
// Created preprocesses for the specified signing protocol.
Preprocesses { id: SignId, preprocesses: Vec<Vec<u8>> },
Preprocesses {
id: SignId,
preprocesses: Vec<Vec<u8>>,
},
// Signed shares for the specified signing protocol.
Shares { id: SignId, shares: Vec<Vec<u8>> },
Shares {
id: SignId,
shares: Vec<Vec<u8>>,
},
}
}
@@ -301,7 +388,7 @@ impl CoordinatorMessage {
}
// Unique since one participation per participant per session
key_gen::CoordinatorMessage::Participation { session, participant, .. } => {
(1, borsh::to_vec(&(session, participant)).unwrap())
(1, borsh::to_vec(&(session, u16::from(*participant))).unwrap())
}
};
@@ -372,7 +459,7 @@ impl ProcessorMessage {
}
// Unique since we only blame a participant once (as this is fatal)
key_gen::ProcessorMessage::Blame { session, participant } => {
(2, borsh::to_vec(&(session, participant)).unwrap())
(2, borsh::to_vec(&(session, u16::from(*participant))).unwrap())
}
};

View File

@@ -1,5 +1,5 @@
[toolchain]
channel = "1.90"
channel = "1.91.1"
targets = ["wasm32v1-none"]
profile = "minimal"
components = ["rust-src", "rustfmt", "clippy"]
components = ["rustfmt", "clippy"]

View File

@@ -36,8 +36,8 @@ rustup target add wasm32v1-none --toolchain nightly
```
cargo install svm-rs
svm install 0.8.26
svm use 0.8.26
svm install 0.8.29
svm use 0.8.29
```
### Install foundry (for tests)

View File

@@ -46,6 +46,8 @@ frost-schnorrkel = { path = "../../crypto/schnorrkel", default-features = false,
bitcoin-serai = { path = "../../networks/bitcoin", default-features = false, features = ["hazmat"], optional = true }
ethereum-schnorr-contract = { path = "../../networks/ethereum/schnorr", default-features = false }
[features]
alloc = [
"std-shims/alloc",
@@ -75,4 +77,6 @@ alloc = [
"frost-schnorrkel",
"bitcoin-serai",
"ethereum-schnorr-contract/alloc",
]

View File

@@ -16,6 +16,8 @@ pub use embedwards25519;
pub use schnorr_signatures;
pub use ethereum_schnorr_contract;
#[cfg(feature = "alloc")]
pub mod alloc {
pub use multiexp;

View File

@@ -7,7 +7,7 @@ pub fn reproducibly_builds() {
use dockertest::{PullPolicy, Image, TestBodySpecification, DockerTest};
const RUNS: usize = 3;
const TIMEOUT: u16 = 180 * 60; // 3 hours
const TIMEOUT: u16 = 3 * 60 * 60; // 3 hours
serai_docker_tests::build("runtime".to_string());