Files
serai/substrate/node/src/rpc/mod.rs

152 lines
5.0 KiB
Rust
Raw Normal View History

use std::{sync::Arc, ops::Deref, collections::HashSet};
use rand_core::{RngCore, OsRng};
Move `develop` to `patch-polkadot-sdk` (#678) * Update `build-dependencies` CI action * Update `develop` to `patch-polkadot-sdk` Allows us to finally remove the old `serai-dex/substrate` repository _and_ should have CI pass without issue on `develop` again. The changes made here should be trivial and maintain all prior behavior/functionality. The most notable are to `chain_spec.rs`, in order to still use a SCALE-encoded `GenesisConfig` (avoiding `serde_json`). * CI fixes * Add `/usr/local/opt/llvm/lib` to paths on macOS hosts * Attempt to use `LD_LIBRARY_PATH` in macOS GitHub CI * Use `libp2p 0.56` in `serai-node` * Correct Windows build dependencies * Correct `llvm/lib` path on macOS * Correct how macOS 13 and 14 have different homebrew paths * Use `sw_vers` instead of `uname` on macOS Yields the macOS version instead of the kernel's version. * Replace hard-coded path with the intended env variable to fix macOS 13 * Add `libclang-dev` as dependency to the Debian Dockerfile * Set the `CODE` storage slot * Update to a version of substrate without `wasmtimer` Turns out `wasmtimer` is WASM only. This should restore the node's functioning on non-WASM environments. * Restore `clang` as a dependency due to the Debian Dockerfile as we require a C++ compiler * Move from Debian bookworm to trixie * Restore `chain_getBlockBin` to the RPC * Always generate a new key for the P2P network * Mention every account on-chain before they publish a transaction `CheckNonce` required accounts have a provider in order to even have their nonce considered. This shims that by claiming every account has a provider at the start of a block, if it signs a transaction. The actual execution could presumably diverge between block building (which sets the provider before each transaction) and execution (which sets the providers at the start of the block). It doesn't diverge in our current configuration and it won't be propagated to `next` (which doesn't use `CheckNonce`). Also uses explicit indexes for the `serai_abi::{Call, Event}` `enum`s. * Adopt `patch-polkadot-sdk` with fixed peering * Manually insert the authority discovery key into the keystore I did try pulling in `pallet-authority-discovery` for this, updating `SessionKeys`, but that was insufficient for whatever reason. * Update to latest `substrate-wasm-builder` * Fix timeline for incrementing providers e1671dd71b219bf7439c28f1c5bdf988b1e00ff5 incremented the providers for every single transaction's sender before execution, noting the solution was fragile but it worked for us at this time. It did not work for us at this time. The new solution replaces `inc_providers` with direct access to the `Account` `StorageMap` to increment the providers, achieving the desired goal, _without_ emitting an event (which is ordered, and the disparate order between building and execution was causing mismatches of the state root). This solution is also fragile and may also be insufficient. None of this code exists anymore on `next` however. It just has to work sufficiently for now. * clippy
2025-10-05 10:58:08 -04:00
use sp_core::Encode;
use sp_blockchain::{Error as BlockchainError, HeaderBackend, HeaderMetadata};
use sp_block_builder::BlockBuilder;
use sp_api::ProvideRuntimeApi;
2025-11-05 01:18:21 -05:00
use serai_abi::{primitives::prelude::*, SubstrateBlock as Block};
use tokio::sync::RwLock;
use jsonrpsee::RpcModule;
Move `develop` to `patch-polkadot-sdk` (#678) * Update `build-dependencies` CI action * Update `develop` to `patch-polkadot-sdk` Allows us to finally remove the old `serai-dex/substrate` repository _and_ should have CI pass without issue on `develop` again. The changes made here should be trivial and maintain all prior behavior/functionality. The most notable are to `chain_spec.rs`, in order to still use a SCALE-encoded `GenesisConfig` (avoiding `serde_json`). * CI fixes * Add `/usr/local/opt/llvm/lib` to paths on macOS hosts * Attempt to use `LD_LIBRARY_PATH` in macOS GitHub CI * Use `libp2p 0.56` in `serai-node` * Correct Windows build dependencies * Correct `llvm/lib` path on macOS * Correct how macOS 13 and 14 have different homebrew paths * Use `sw_vers` instead of `uname` on macOS Yields the macOS version instead of the kernel's version. * Replace hard-coded path with the intended env variable to fix macOS 13 * Add `libclang-dev` as dependency to the Debian Dockerfile * Set the `CODE` storage slot * Update to a version of substrate without `wasmtimer` Turns out `wasmtimer` is WASM only. This should restore the node's functioning on non-WASM environments. * Restore `clang` as a dependency due to the Debian Dockerfile as we require a C++ compiler * Move from Debian bookworm to trixie * Restore `chain_getBlockBin` to the RPC * Always generate a new key for the P2P network * Mention every account on-chain before they publish a transaction `CheckNonce` required accounts have a provider in order to even have their nonce considered. This shims that by claiming every account has a provider at the start of a block, if it signs a transaction. The actual execution could presumably diverge between block building (which sets the provider before each transaction) and execution (which sets the providers at the start of the block). It doesn't diverge in our current configuration and it won't be propagated to `next` (which doesn't use `CheckNonce`). Also uses explicit indexes for the `serai_abi::{Call, Event}` `enum`s. * Adopt `patch-polkadot-sdk` with fixed peering * Manually insert the authority discovery key into the keystore I did try pulling in `pallet-authority-discovery` for this, updating `SessionKeys`, but that was insufficient for whatever reason. * Update to latest `substrate-wasm-builder` * Fix timeline for incrementing providers e1671dd71b219bf7439c28f1c5bdf988b1e00ff5 incremented the providers for every single transaction's sender before execution, noting the solution was fragile but it worked for us at this time. It did not work for us at this time. The new solution replaces `inc_providers` with direct access to the `Account` `StorageMap` to increment the providers, achieving the desired goal, _without_ emitting an event (which is ordered, and the disparate order between building and execution was causing mismatches of the state root). This solution is also fragile and may also be insufficient. None of this code exists anymore on `next` however. It just has to work sufficiently for now. * clippy
2025-10-05 10:58:08 -04:00
use sc_client_api::BlockBackend;
Initial In Instructions pallet and Serai client lib (#233) * Initial work on an In Inherents pallet * Add an event for when a batch is executed * Add a dummy provider for InInstructions * Add in-instructions to the node * Add the Serai runtime API to the processor * Move processor tests around * Build a subxt Client around Serai * Successfully get Batch events from Serai Renamed processor/substrate to processor/serai. * Much more robust InInstruction pallet * Implement the workaround from https://github.com/paritytech/subxt/issues/602 * Initial prototype of processor generated InInstructions * Correct PendingCoins data flow for InInstructions * Minor lint to in-instructions * Remove the global Serai connection for a partial re-impl * Correct ID handling of the processor test * Workaround the delay in the subscription * Make an unwrap an if let Some, remove old comments * Lint the processor toml * Rebase and update * Move substrate/in-instructions to substrate/in-instructions/pallet * Start an in-instructions primitives lib * Properly update processor to subxt 0.24 Also corrects failures from the rebase. * in-instructions cargo update * Implement IsFatalError * is_inherent -> true * Rename in-instructions crates and misc cleanup * Update documentation * cargo update * Misc update fixes * Replace height with block_number * Update processor src to latest subxt * Correct pipeline for InInstructions testing * Remove runtime::AccountId for serai_primitives::NativeAddress * Rewrite the in-instructions pallet Complete with respect to the currently written docs. Drops the custom serializer for just using SCALE. Makes slight tweaks as relevant. * Move instructions' InherentDataProvider to a client crate * Correct doc gen * Add serde to in-instructions-primitives * Add in-instructions-primitives to pallet * Heights -> BlockNumbers * Get batch pub test loop working * Update in instructions pallet terminology Removes the ambiguous Coin for Update. Removes pending/artificial latency for furture client work. Also moves to using serai_primitives::Coin. * Add a BlockNumber primitive * Belated cargo fmt * Further document why DifferentBatch isn't fatal * Correct processor sleeps * Remove metadata at compile time, add test framework for Serai nodes * Remove manual RPC client * Simplify update test * Improve re-exporting behavior of serai-runtime It now re-exports all pallets underneath it. * Add a function to get storage values to the Serai RPC * Update substrate/ to latest substrate * Create a dedicated crate for the Serai RPC * Remove unused dependencies in substrate/ * Remove unused dependencies in coins/ Out of scope for this branch, just minor and path of least resistance. * Use substrate/serai/client for the Serai RPC lib It's a bit out of place, since these client folders are intended for the node to access pallets and so on. This is for end-users to access Serai as a whole. In that sense, it made more sense as a top level folder, yet that also felt out of place. * Move InInstructions test to serai-client for now * Final cleanup * Update deny.toml * Cargo.lock update from merging develop * Update nightly Attempt to work around the current CI failure, which is a Rust ICE. We previously didn't upgrade due to clippy 10134, yet that's been reverted. * clippy * clippy * fmt * NativeAddress -> SeraiAddress * Sec fix on non-provided updates and doc fixes * Add Serai as a Coin Necessary in order to swap to Serai. * Add a BlockHash type, used for batch IDs * Remove origin from InInstruction Makes InInstructionTarget. Adds RefundableInInstruction with origin. * Document storage items in in-instructions * Rename serai/client/tests/serai.rs to updates.rs It only tested publishing updates and their successful acceptance.
2023-01-20 11:00:18 -05:00
use sc_transaction_pool_api::TransactionPool;
mod utils;
mod blockchain;
mod validator_sets;
mod p2p_validators;
pub struct FullDeps<C, P> {
pub id: String,
pub client: Arc<C>,
pub pool: Arc<P>,
pub authority_discovery: Option<sc_authority_discovery::Service>,
}
pub fn create_full<
2025-11-05 01:18:21 -05:00
C: 'static
2022-07-15 01:26:07 -04:00
+ Send
+ Sync
2025-11-05 01:18:21 -05:00
+ ProvideRuntimeApi<Block, Api: BlockBuilder<Block> + serai_runtime::SeraiApi<Block>>
+ HeaderBackend<Block>
+ HeaderMetadata<Block, Error = BlockchainError>
+ BlockBackend<Block>,
P: 'static + TransactionPool,
>(
2022-07-15 01:26:07 -04:00
deps: FullDeps<C, P>,
2025-11-05 01:18:21 -05:00
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>> {
Move `develop` to `patch-polkadot-sdk` (#678) * Update `build-dependencies` CI action * Update `develop` to `patch-polkadot-sdk` Allows us to finally remove the old `serai-dex/substrate` repository _and_ should have CI pass without issue on `develop` again. The changes made here should be trivial and maintain all prior behavior/functionality. The most notable are to `chain_spec.rs`, in order to still use a SCALE-encoded `GenesisConfig` (avoiding `serde_json`). * CI fixes * Add `/usr/local/opt/llvm/lib` to paths on macOS hosts * Attempt to use `LD_LIBRARY_PATH` in macOS GitHub CI * Use `libp2p 0.56` in `serai-node` * Correct Windows build dependencies * Correct `llvm/lib` path on macOS * Correct how macOS 13 and 14 have different homebrew paths * Use `sw_vers` instead of `uname` on macOS Yields the macOS version instead of the kernel's version. * Replace hard-coded path with the intended env variable to fix macOS 13 * Add `libclang-dev` as dependency to the Debian Dockerfile * Set the `CODE` storage slot * Update to a version of substrate without `wasmtimer` Turns out `wasmtimer` is WASM only. This should restore the node's functioning on non-WASM environments. * Restore `clang` as a dependency due to the Debian Dockerfile as we require a C++ compiler * Move from Debian bookworm to trixie * Restore `chain_getBlockBin` to the RPC * Always generate a new key for the P2P network * Mention every account on-chain before they publish a transaction `CheckNonce` required accounts have a provider in order to even have their nonce considered. This shims that by claiming every account has a provider at the start of a block, if it signs a transaction. The actual execution could presumably diverge between block building (which sets the provider before each transaction) and execution (which sets the providers at the start of the block). It doesn't diverge in our current configuration and it won't be propagated to `next` (which doesn't use `CheckNonce`). Also uses explicit indexes for the `serai_abi::{Call, Event}` `enum`s. * Adopt `patch-polkadot-sdk` with fixed peering * Manually insert the authority discovery key into the keystore I did try pulling in `pallet-authority-discovery` for this, updating `SessionKeys`, but that was insufficient for whatever reason. * Update to latest `substrate-wasm-builder` * Fix timeline for incrementing providers e1671dd71b219bf7439c28f1c5bdf988b1e00ff5 incremented the providers for every single transaction's sender before execution, noting the solution was fragile but it worked for us at this time. It did not work for us at this time. The new solution replaces `inc_providers` with direct access to the `Account` `StorageMap` to increment the providers, achieving the desired goal, _without_ emitting an event (which is ordered, and the disparate order between building and execution was causing mismatches of the state root). This solution is also fragile and may also be insufficient. None of this code exists anymore on `next` however. It just has to work sufficiently for now. * clippy
2025-10-05 10:58:08 -04:00
let FullDeps { id, client, pool, authority_discovery } = deps;
let mut root = RpcModule::new(());
root.merge(blockchain::module(client.clone())?)?;
root.merge(validator_sets::module(client.clone()))?;
if let Some(authority_discovery) = authority_discovery {
root.merge(p2p_validators::module(id, client, authority_discovery)?)?;
}
Ok(root)
2025-10-05 18:43:53 -04:00
/* TODO
2025-11-05 01:18:21 -05:00
use ciphersuite::{GroupIo, WithPreferredHash};
use ciphersuite_kp256::{k256::elliptic_curve::point::AffineCoordinates, Secp256k1};
use dalek_ff_group::Ed25519;
use bitcoin_serai::bitcoin;
let mut serai_json_module = RpcModule::new(client);
// add network address rpc
serai_json_module.register_async_method(
"external_network_address",
|params, context| async move {
let network: ExternalNetworkId = params.parse()?;
let client = &*context;
let latest_block = client.info().best_hash;
let external_key = client
.runtime_api()
.external_network_key(latest_block, network)
.map_err(|_| Error::Custom("api call error".to_string()))?
.ok_or(Error::Custom("no address for the network".to_string()))?;
match network {
ExternalNetworkId::Bitcoin => {
Smash the singular `Ciphersuite` trait into multiple This helps identify where the various functionalities are used, or rather, not used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating the entire FCMP++ tree, only requires the markers _and_ canonical point decoding. I've opened a PR to upstream such a trait into `group` (https://github.com/zkcrypto/group/pull/68). `WrappedGroup` is still justified for as long as `Group::generator` exists. Moving `::generator()` to its own trait, on an independent structure (upstream) would be massively appreciated. @tarcieri also wanted to update from `fn generator()` to `const GENERATOR`, which would encourage further discussion on https://github.com/zkcrypto/group/issues/32 and https://github.com/zkcrypto/group/issues/45, which have been stagnant. The `Id` trait is occasionally used yet really should be first off the chopping block. Finally, `WithPreferredHash` is only actually used around a third of the time, which more than justifies it being a separate trait. --- Updates `dalek_ff_group::Scalar` to directly re-export `curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint` also could be replaced with an export of `curve25519_dalek::RistrettoPoint`, yet the coordinator relies on how we implemented `Hash` on it for the hell of it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't implement `zeroize`, `subtle` traits within a released, non-yanked version. Relevance to https://github.com/serai-dex/serai/issues/201 and https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746. Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over `SHA2-512`. In order to maintain compliance with FROST's IETF standard, `modular-frost` defines its own ciphersuite for Ristretto which still uses `SHA2-512`.
2025-09-03 12:25:37 -04:00
let key = <Secp256k1 as GroupIo>::read_G::<&[u8]>(&mut external_key.as_slice())
.map_err(|_| Error::Custom("invalid key stored in db".to_string()))?;
let addr = bitcoin::Address::p2tr_tweaked(
2025-08-25 09:17:29 -04:00
bitcoin::key::TweakedPublicKey::dangerous_assume_tweaked(
bitcoin::key::XOnlyPublicKey::from_slice(key.to_affine().x().as_slice()).map_err(
|_| Error::Custom("x-coordinate for Bitcoin key was invalid".to_string()),
)?,
),
bitcoin::address::KnownHrp::Mainnet,
);
Ok(addr.to_string())
}
// We don't know the eth address before the smart contract is deployed.
ExternalNetworkId::Ethereum => Ok(String::new()),
ExternalNetworkId::Monero => {
// TODO: Serai view-key crate
Smash the singular `Ciphersuite` trait into multiple This helps identify where the various functionalities are used, or rather, not used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating the entire FCMP++ tree, only requires the markers _and_ canonical point decoding. I've opened a PR to upstream such a trait into `group` (https://github.com/zkcrypto/group/pull/68). `WrappedGroup` is still justified for as long as `Group::generator` exists. Moving `::generator()` to its own trait, on an independent structure (upstream) would be massively appreciated. @tarcieri also wanted to update from `fn generator()` to `const GENERATOR`, which would encourage further discussion on https://github.com/zkcrypto/group/issues/32 and https://github.com/zkcrypto/group/issues/45, which have been stagnant. The `Id` trait is occasionally used yet really should be first off the chopping block. Finally, `WithPreferredHash` is only actually used around a third of the time, which more than justifies it being a separate trait. --- Updates `dalek_ff_group::Scalar` to directly re-export `curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint` also could be replaced with an export of `curve25519_dalek::RistrettoPoint`, yet the coordinator relies on how we implemented `Hash` on it for the hell of it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't implement `zeroize`, `subtle` traits within a released, non-yanked version. Relevance to https://github.com/serai-dex/serai/issues/201 and https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746. Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over `SHA2-512`. In order to maintain compliance with FROST's IETF standard, `modular-frost` defines its own ciphersuite for Ristretto which still uses `SHA2-512`.
2025-09-03 12:25:37 -04:00
let view_private = zeroize::Zeroizing::new(<Ed25519 as WithPreferredHash>::hash_to_F(
&["Monero".as_bytes(), &0u64.to_le_bytes()].concat(),
));
Smash the singular `Ciphersuite` trait into multiple This helps identify where the various functionalities are used, or rather, not used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating the entire FCMP++ tree, only requires the markers _and_ canonical point decoding. I've opened a PR to upstream such a trait into `group` (https://github.com/zkcrypto/group/pull/68). `WrappedGroup` is still justified for as long as `Group::generator` exists. Moving `::generator()` to its own trait, on an independent structure (upstream) would be massively appreciated. @tarcieri also wanted to update from `fn generator()` to `const GENERATOR`, which would encourage further discussion on https://github.com/zkcrypto/group/issues/32 and https://github.com/zkcrypto/group/issues/45, which have been stagnant. The `Id` trait is occasionally used yet really should be first off the chopping block. Finally, `WithPreferredHash` is only actually used around a third of the time, which more than justifies it being a separate trait. --- Updates `dalek_ff_group::Scalar` to directly re-export `curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint` also could be replaced with an export of `curve25519_dalek::RistrettoPoint`, yet the coordinator relies on how we implemented `Hash` on it for the hell of it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't implement `zeroize`, `subtle` traits within a released, non-yanked version. Relevance to https://github.com/serai-dex/serai/issues/201 and https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746. Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over `SHA2-512`. In order to maintain compliance with FROST's IETF standard, `modular-frost` defines its own ciphersuite for Ristretto which still uses `SHA2-512`.
2025-09-03 12:25:37 -04:00
let spend = <Ed25519 as GroupIo>::read_G::<&[u8]>(&mut external_key.as_slice())
.map_err(|_| Error::Custom("invalid key stored in db".to_string()))?;
let addr = monero_address::MoneroAddress::new(
monero_address::Network::Mainnet,
monero_address::AddressType::Featured {
subaddress: false,
payment_id: None,
guaranteed: true,
},
*spend,
view_private.deref() * curve25519_dalek::constants::ED25519_BASEPOINT_TABLE,
);
Ok(addr.to_string())
}
}
},
)?;
// add shorthand encoding rpc
serai_json_module.register_async_method("encoded_shorthand", |params, _| async move {
// decode using serde and encode back using scale
let shorthand: Shorthand = params.parse()?;
Ok(shorthand.encode())
})?;
// add simulating a swap path rpc
serai_json_module.register_async_method("quote_price", |params, context| async move {
let client = &*context;
let latest_block = client.info().best_hash;
let QuotePriceParams { coin1, coin2, amount, include_fee, exact_in } = params.parse()?;
let amount = if exact_in {
client
.runtime_api()
.quote_price_exact_tokens_for_tokens(latest_block, coin1, coin2, amount, include_fee)
.map_err(|_| Error::Custom("api call error".to_string()))?
.ok_or(Error::Custom("invalid params or empty pool".to_string()))?
} else {
client
.runtime_api()
.quote_price_tokens_for_exact_tokens(latest_block, coin1, coin2, amount, include_fee)
.map_err(|_| Error::Custom("api call error".to_string()))?
.ok_or(Error::Custom("invalid params or empty pool".to_string()))?
};
Ok(amount)
})?;
module.merge(serai_json_module)?;
2025-10-05 18:43:53 -04:00
*/
}