mirror of
https://github.com/serai-dex/serai.git
synced 2024-11-16 17:07:35 +00:00
Ethereum processor docker tests, barring send
We need the TX publication relay thingy for send to work (though that is the point the test fails at).
This commit is contained in:
parent
ae8a27b876
commit
11ec9e3535
20 changed files with 305 additions and 91 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -3706,6 +3706,7 @@ dependencies = [
|
|||
"elliptic-curve",
|
||||
"once_cell",
|
||||
"sha2",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -8070,6 +8071,7 @@ dependencies = [
|
|||
"dockertest",
|
||||
"ethereum-serai",
|
||||
"hex",
|
||||
"k256",
|
||||
"monero-serai",
|
||||
"parity-scale-codec",
|
||||
"rand_core",
|
||||
|
|
|
@ -46,4 +46,4 @@ tokio = { version = "1", features = ["macros"] }
|
|||
alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", rev = "b79db21734cffddc11753fe62ba571565c896f42", default-features = false }
|
||||
|
||||
[features]
|
||||
tests = ["alloy-node-bindings"]
|
||||
tests = ["alloy-node-bindings", "frost/tests"]
|
||||
|
|
|
@ -17,6 +17,7 @@ pub fn coordinator(
|
|||
let longer_reattempts = if network == Network::Dev { "longer-reattempts" } else { "" };
|
||||
let setup = mimalloc(Os::Debian).to_string() +
|
||||
&build_serai_service(
|
||||
"",
|
||||
network.release(),
|
||||
&format!("{db} {longer_reattempts}"),
|
||||
"serai-coordinator",
|
||||
|
|
|
@ -137,7 +137,7 @@ WORKDIR /home/{user}
|
|||
}
|
||||
}
|
||||
|
||||
fn build_serai_service(release: bool, features: &str, package: &str) -> String {
|
||||
fn build_serai_service(prelude: &str, release: bool, features: &str, package: &str) -> String {
|
||||
let profile = if release { "release" } else { "debug" };
|
||||
let profile_flag = if release { "--release" } else { "" };
|
||||
|
||||
|
@ -159,6 +159,8 @@ RUN apt install -y make protobuf-compiler
|
|||
# Add the wasm toolchain
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
|
||||
{prelude}
|
||||
|
||||
# Add files for build
|
||||
ADD patches /serai/patches
|
||||
ADD common /serai/common
|
||||
|
|
|
@ -13,7 +13,7 @@ pub fn message_queue(
|
|||
monero_key: <Ristretto as Ciphersuite>::G,
|
||||
) {
|
||||
let setup = mimalloc(Os::Debian).to_string() +
|
||||
&build_serai_service(network.release(), network.db(), "serai-message-queue");
|
||||
&build_serai_service("", network.release(), network.db(), "serai-message-queue");
|
||||
|
||||
let env_vars = [
|
||||
("COORDINATOR_KEY", hex::encode(coordinator_key.to_bytes())),
|
||||
|
|
|
@ -17,6 +17,15 @@ pub fn processor(
|
|||
) {
|
||||
let setup = mimalloc(Os::Debian).to_string() +
|
||||
&build_serai_service(
|
||||
if coin == "ethereum" {
|
||||
r#"
|
||||
RUN cargo install svm-rs
|
||||
RUN svm install 0.8.25
|
||||
RUN svm use 0.8.25
|
||||
"#
|
||||
} else {
|
||||
""
|
||||
},
|
||||
network.release(),
|
||||
&format!("binaries {} {coin}", network.db()),
|
||||
"serai-processor",
|
||||
|
@ -34,7 +43,7 @@ RUN apt install -y ca-certificates
|
|||
let hostname = format!("serai-{}-{coin}", network.label());
|
||||
let port = match coin {
|
||||
"bitcoin" => 8332,
|
||||
"ethereum" => return, // TODO
|
||||
"ethereum" => 8545,
|
||||
"monero" => 18081,
|
||||
_ => panic!("unrecognized external network"),
|
||||
};
|
||||
|
|
|
@ -11,9 +11,9 @@ pub fn serai(
|
|||
serai_key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
||||
) {
|
||||
// Always builds in release for performance reasons
|
||||
let setup = mimalloc(Os::Debian).to_string() + &build_serai_service(true, "", "serai-node");
|
||||
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");
|
||||
mimalloc(Os::Debian).to_string() + &build_serai_service("", true, "fast-epoch", "serai-node");
|
||||
|
||||
let env_vars = [("KEY", hex::encode(serai_key.to_repr()))];
|
||||
let mut env_vars_str = String::new();
|
||||
|
|
|
@ -512,6 +512,7 @@ impl<N: Network, D: Db> KeyGen<N, D> {
|
|||
ProcessorMessage::GeneratedKeyPair {
|
||||
id,
|
||||
substrate_key: generated_substrate_key.unwrap().to_bytes(),
|
||||
// TODO: This can be made more efficient since tweaked keys may be a subset of keys
|
||||
network_key: generated_network_key.unwrap().to_bytes().as_ref().to_vec(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,9 +63,22 @@ fn instruction_from_output<N: Network>(
|
|||
return (presumed_origin, None);
|
||||
}
|
||||
|
||||
let Ok(shorthand) = Shorthand::decode(&mut data) else { return (presumed_origin, None) };
|
||||
let Ok(instruction) = RefundableInInstruction::try_from(shorthand) else {
|
||||
return (presumed_origin, None);
|
||||
let shorthand = match Shorthand::decode(&mut data) {
|
||||
Ok(shorthand) => shorthand,
|
||||
Err(e) => {
|
||||
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,
|
||||
Err(e) => {
|
||||
info!(
|
||||
"shorthand in output {} wasn't convertible to a RefundableInInstruction: {e:?}",
|
||||
hex::encode(output.id())
|
||||
);
|
||||
return (presumed_origin, None);
|
||||
}
|
||||
};
|
||||
|
||||
let mut balance = output.balance();
|
||||
|
|
|
@ -279,6 +279,8 @@ impl<N: Network, D: Db> ScannerHandle<N, D> {
|
|||
activation_number: usize,
|
||||
key: <N::Curve as Ciphersuite>::G,
|
||||
) {
|
||||
info!("Registering key {} in scanner at {activation_number}", hex::encode(key.to_bytes()));
|
||||
|
||||
let mut scanner_lock = self.scanner.write().await;
|
||||
let scanner = scanner_lock.as_mut().unwrap();
|
||||
assert!(
|
||||
|
@ -286,8 +288,6 @@ impl<N: Network, D: Db> ScannerHandle<N, D> {
|
|||
"activation block of new keys was already scanned",
|
||||
);
|
||||
|
||||
info!("Registering key {} in scanner at {activation_number}", hex::encode(key.to_bytes()));
|
||||
|
||||
if scanner.keys.is_empty() {
|
||||
assert!(scanner.ram_scanned.is_none());
|
||||
scanner.ram_scanned = Some(activation_number);
|
||||
|
|
|
@ -116,7 +116,7 @@ impl<N: Network<Scheduler = Self>> SchedulerTrait<N> for Scheduler<N> {
|
|||
assert!(self.coins.contains(&utxo.balance().coin));
|
||||
}
|
||||
|
||||
let mut nonce = LastNonce::get(txn).map_or(1, |nonce| nonce + 1);
|
||||
let mut nonce = LastNonce::get(txn).unwrap_or(1);
|
||||
let mut plans = vec![];
|
||||
for chunk in payments.as_slice().chunks(N::MAX_OUTPUTS) {
|
||||
// Once we rotate, all further payments should be scheduled via the new multisig
|
||||
|
|
|
@ -432,7 +432,7 @@ impl<N: UtxoNetwork<Scheduler = Self>> Scheduler<N> {
|
|||
}
|
||||
|
||||
// If there's a UTXO to restore, restore it
|
||||
// This is down now as if there is a to_restore output, and it was inserted into self.utxos
|
||||
// This is done now as if there is a to_restore output, and it was inserted into self.utxos
|
||||
// earlier, self.utxos.len() may become `N::MAX_INPUTS + 1`
|
||||
// The prior block requires the len to be `<= N::MAX_INPUTS`
|
||||
if let Some(to_restore) = to_restore {
|
||||
|
@ -442,9 +442,10 @@ impl<N: UtxoNetwork<Scheduler = Self>> Scheduler<N> {
|
|||
txn.put(scheduler_key::<D, _>(&self.key), self.serialize());
|
||||
|
||||
log::info!(
|
||||
"created {} plans containing {} payments to sign",
|
||||
"created {} plans containing {} payments to sign, with {} payments pending scheduling",
|
||||
plans.len(),
|
||||
payments_at_start - self.payments.len(),
|
||||
self.payments.len(),
|
||||
);
|
||||
plans
|
||||
}
|
||||
|
@ -589,7 +590,8 @@ impl<N: UtxoNetwork<Scheduler = Self>> SchedulerTrait<N> for Scheduler<N> {
|
|||
output: N::Output,
|
||||
refund_to: N::Address,
|
||||
) -> Plan<N> {
|
||||
Plan {
|
||||
let output_id = output.id().as_ref().to_vec();
|
||||
let res = Plan {
|
||||
key: output.key(),
|
||||
// Uses a payment as this will still be successfully sent due to fee amortization,
|
||||
// and because change is currently always a Serai key
|
||||
|
@ -597,7 +599,9 @@ impl<N: UtxoNetwork<Scheduler = Self>> SchedulerTrait<N> for Scheduler<N> {
|
|||
inputs: vec![output],
|
||||
change: None,
|
||||
scheduler_addendum: (),
|
||||
}
|
||||
};
|
||||
log::info!("refund plan for {} has ID {}", hex::encode(output_id), hex::encode(res.id()));
|
||||
res
|
||||
}
|
||||
|
||||
fn shim_forward_plan(output: N::Output, to: <N::Curve as Ciphersuite>::G) -> Option<Plan<N>> {
|
||||
|
|
|
@ -426,7 +426,7 @@ impl<D: Db> Network for Ethereum<D> {
|
|||
.get_block(BlockNumberOrTag::Finalized.into(), false)
|
||||
.await
|
||||
.map_err(|_| NetworkError::ConnectionError)?
|
||||
.expect("no blocks were finalized")
|
||||
.ok_or(NetworkError::ConnectionError)?
|
||||
.header
|
||||
.number
|
||||
.unwrap();
|
||||
|
|
|
@ -23,11 +23,14 @@ zeroize = { version = "1", default-features = false }
|
|||
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
|
||||
|
||||
curve25519-dalek = "4"
|
||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["ristretto"] }
|
||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["secp256k1", "ristretto"] }
|
||||
dkg = { path = "../../crypto/dkg", default-features = false, features = ["tests"] }
|
||||
|
||||
bitcoin-serai = { path = "../../coins/bitcoin" }
|
||||
|
||||
k256 = "0.13"
|
||||
ethereum-serai = { path = "../../coins/ethereum" }
|
||||
|
||||
monero-serai = { path = "../../coins/monero" }
|
||||
|
||||
messages = { package = "serai-processor-messages", path = "../../processor/messages" }
|
||||
|
@ -43,7 +46,7 @@ serde_json = { version = "1", default-features = false }
|
|||
|
||||
tokio = { version = "1", features = ["time"] }
|
||||
|
||||
processor = { package = "serai-processor", path = "../../processor", features = ["bitcoin", "monero"] }
|
||||
processor = { package = "serai-processor", path = "../../processor", features = ["bitcoin", "ethereum", "monero"] }
|
||||
|
||||
dockertest = "0.4"
|
||||
serai-docker-tests = { path = "../docker" }
|
||||
|
|
|
@ -61,6 +61,7 @@ pub fn processor_instance(
|
|||
pub type Handles = (String, String, String);
|
||||
pub fn processor_stack(
|
||||
network: NetworkId,
|
||||
network_hostname_override: Option<String>,
|
||||
) -> (Handles, <Ristretto as Ciphersuite>::F, Vec<TestBodySpecification>) {
|
||||
let (network_composition, network_rpc_port) = network_instance(network);
|
||||
|
||||
|
@ -113,7 +114,10 @@ pub fn processor_stack(
|
|||
}
|
||||
|
||||
let processor_composition = compositions.last_mut().unwrap();
|
||||
processor_composition.inject_container_name(handles[0].clone(), "NETWORK_RPC_HOSTNAME");
|
||||
processor_composition.inject_container_name(
|
||||
network_hostname_override.unwrap_or_else(|| handles[0].clone()),
|
||||
"NETWORK_RPC_HOSTNAME",
|
||||
);
|
||||
processor_composition.inject_container_name(handles[1].clone(), "MESSAGE_QUEUE_RPC");
|
||||
|
||||
((handles[0].clone(), handles[1].clone(), handles[2].clone()), coord_key, compositions)
|
||||
|
@ -182,25 +186,52 @@ impl Coordinator {
|
|||
}
|
||||
}
|
||||
NetworkId::Ethereum => {
|
||||
use ethereum_serai::alloy::{
|
||||
simple_request_transport::SimpleRequest,
|
||||
rpc_client::ClientBuilder,
|
||||
provider::{Provider, RootProvider},
|
||||
network::Ethereum,
|
||||
use std::sync::Arc;
|
||||
use ethereum_serai::{
|
||||
alloy::{
|
||||
simple_request_transport::SimpleRequest,
|
||||
rpc_client::ClientBuilder,
|
||||
provider::{Provider, RootProvider},
|
||||
network::Ethereum,
|
||||
},
|
||||
deployer::Deployer,
|
||||
};
|
||||
|
||||
let provider = RootProvider::<_, Ethereum>::new(
|
||||
let provider = Arc::new(RootProvider::<_, Ethereum>::new(
|
||||
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
|
||||
);
|
||||
));
|
||||
|
||||
loop {
|
||||
if handle
|
||||
.block_on(provider.raw_request::<_, ()>("evm_setAutomine".into(), [false]))
|
||||
.is_ok()
|
||||
{
|
||||
break;
|
||||
}
|
||||
handle.block_on(tokio::time::sleep(core::time::Duration::from_secs(1)));
|
||||
if handle
|
||||
.block_on(provider.raw_request::<_, ()>("evm_setAutomine".into(), [false]))
|
||||
.is_ok()
|
||||
{
|
||||
handle.block_on(async {
|
||||
// Deploy the deployer
|
||||
let tx = Deployer::deployment_tx();
|
||||
let signer = tx.recover_signer().unwrap();
|
||||
let (tx, sig, _) = tx.into_parts();
|
||||
|
||||
provider
|
||||
.raw_request::<_, ()>(
|
||||
"anvil_setBalance".into(),
|
||||
[signer.to_string(), (tx.gas_limit * tx.gas_price).to_string()],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut bytes = vec![];
|
||||
tx.encode_with_signature_fields(&sig, &mut bytes);
|
||||
let _ = provider.send_raw_transaction(&bytes).await.unwrap();
|
||||
|
||||
provider.raw_request::<_, ()>("anvil_mine".into(), [96]).await.unwrap();
|
||||
|
||||
let _ = Deployer::new(provider.clone()).await.unwrap().unwrap();
|
||||
|
||||
// Sleep until the actual time is ahead of whatever time is in the epoch we just
|
||||
// mined
|
||||
tokio::time::sleep(core::time::Duration::from_secs(30)).await;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
NetworkId::Monero => {
|
||||
|
@ -371,7 +402,10 @@ impl Coordinator {
|
|||
let rpc = Rpc::new(rpc_url).await.expect("couldn't connect to the Bitcoin RPC");
|
||||
let to = rpc.get_latest_block_number().await.unwrap();
|
||||
for coordinator in others {
|
||||
let from = rpc.get_latest_block_number().await.unwrap() + 1;
|
||||
let other_rpc = Rpc::new(network_rpc(self.network, ops, &coordinator.network_handle))
|
||||
.await
|
||||
.expect("couldn't connect to the Bitcoin RPC");
|
||||
let from = other_rpc.get_latest_block_number().await.unwrap() + 1;
|
||||
|
||||
for b in from ..= to {
|
||||
let mut buf = vec![];
|
||||
|
@ -382,12 +416,10 @@ impl Coordinator {
|
|||
.consensus_encode(&mut buf)
|
||||
.unwrap();
|
||||
|
||||
let rpc_url = network_rpc(coordinator.network, ops, &coordinator.network_handle);
|
||||
let rpc =
|
||||
Rpc::new(rpc_url).await.expect("couldn't connect to the coordinator's Bitcoin RPC");
|
||||
|
||||
let res: Option<String> =
|
||||
rpc.rpc_call("submitblock", serde_json::json!([hex::encode(buf)])).await.unwrap();
|
||||
let res: Option<String> = other_rpc
|
||||
.rpc_call("submitblock", serde_json::json!([hex::encode(buf)]))
|
||||
.await
|
||||
.unwrap();
|
||||
if let Some(err) = res {
|
||||
panic!("submitblock failed: {err}");
|
||||
}
|
||||
|
@ -397,22 +429,52 @@ impl Coordinator {
|
|||
NetworkId::Ethereum => {
|
||||
use ethereum_serai::alloy::{
|
||||
simple_request_transport::SimpleRequest,
|
||||
rpc_types::BlockNumberOrTag,
|
||||
rpc_client::ClientBuilder,
|
||||
provider::{Provider, RootProvider},
|
||||
network::Ethereum,
|
||||
};
|
||||
|
||||
let provider = RootProvider::<_, Ethereum>::new(
|
||||
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
|
||||
);
|
||||
let state = provider.raw_request::<_, String>("anvil_dumpState".into(), ()).await.unwrap();
|
||||
let (expected_number, state) = {
|
||||
let provider = RootProvider::<_, Ethereum>::new(
|
||||
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
|
||||
);
|
||||
|
||||
let expected_number = provider
|
||||
.get_block(BlockNumberOrTag::Latest.into(), false)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.header
|
||||
.number;
|
||||
(
|
||||
expected_number,
|
||||
provider.raw_request::<_, String>("anvil_dumpState".into(), ()).await.unwrap(),
|
||||
)
|
||||
};
|
||||
|
||||
for coordinator in others {
|
||||
let rpc_url = network_rpc(coordinator.network, ops, &coordinator.network_handle);
|
||||
let provider = RootProvider::<_, Ethereum>::new(
|
||||
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
|
||||
);
|
||||
provider.raw_request::<_, ()>("anvil_loadState".into(), &state).await.unwrap();
|
||||
assert!(provider
|
||||
.raw_request::<_, bool>("anvil_loadState".into(), &[&state])
|
||||
.await
|
||||
.unwrap());
|
||||
|
||||
let new_number = provider
|
||||
.get_block(BlockNumberOrTag::Latest.into(), false)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.header
|
||||
.number;
|
||||
|
||||
// TODO: https://github.com/foundry-rs/foundry/issues/7955
|
||||
let _ = expected_number;
|
||||
let _ = new_number;
|
||||
//assert_eq!(expected_number, new_number);
|
||||
}
|
||||
}
|
||||
NetworkId::Monero => {
|
||||
|
@ -421,21 +483,17 @@ impl Coordinator {
|
|||
let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
||||
let to = rpc.get_height().await.unwrap();
|
||||
for coordinator in others {
|
||||
let from = HttpRpc::new(network_rpc(self.network, ops, &coordinator.network_handle))
|
||||
.await
|
||||
.expect("couldn't connect to the Monero RPC")
|
||||
.get_height()
|
||||
.await
|
||||
.unwrap();
|
||||
let other_rpc =
|
||||
HttpRpc::new(network_rpc(coordinator.network, ops, &coordinator.network_handle))
|
||||
.await
|
||||
.expect("couldn't connect to the Monero RPC");
|
||||
|
||||
let from = other_rpc.get_height().await.unwrap();
|
||||
for b in from .. to {
|
||||
let block =
|
||||
rpc.get_block(rpc.get_block_hash(b).await.unwrap()).await.unwrap().serialize();
|
||||
|
||||
let rpc_url = network_rpc(coordinator.network, ops, &coordinator.network_handle);
|
||||
let rpc = HttpRpc::new(rpc_url)
|
||||
.await
|
||||
.expect("couldn't connect to the coordinator's Monero RPC");
|
||||
let res: serde_json::Value = rpc
|
||||
let res: serde_json::Value = other_rpc
|
||||
.json_rpc_call("submit_block", Some(serde_json::json!([hex::encode(block)])))
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
|
@ -96,6 +96,7 @@ pub enum Wallet {
|
|||
input_tx: bitcoin_serai::bitcoin::Transaction,
|
||||
},
|
||||
Ethereum {
|
||||
rpc_url: String,
|
||||
key: <ciphersuite::Secp256k1 as Ciphersuite>::F,
|
||||
nonce: u64,
|
||||
},
|
||||
|
@ -155,7 +156,7 @@ impl Wallet {
|
|||
}
|
||||
|
||||
NetworkId::Ethereum => {
|
||||
use ciphersuite::{group::ff::Field, Ciphersuite, Secp256k1};
|
||||
use ciphersuite::{group::ff::Field, Secp256k1};
|
||||
use ethereum_serai::alloy::{
|
||||
primitives::{U256, Address},
|
||||
simple_request_transport::SimpleRequest,
|
||||
|
@ -183,7 +184,7 @@ impl Wallet {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
Wallet::Ethereum { key, nonce: 0 }
|
||||
Wallet::Ethereum { rpc_url: rpc_url.clone(), key, nonce: 0 }
|
||||
}
|
||||
|
||||
NetworkId::Monero => {
|
||||
|
@ -328,22 +329,107 @@ impl Wallet {
|
|||
(buf, Balance { coin: Coin::Bitcoin, amount: Amount(AMOUNT) })
|
||||
}
|
||||
|
||||
Wallet::Ethereum { key, ref mut nonce } => {
|
||||
/*
|
||||
use ethereum_serai::alloy::primitives::U256;
|
||||
Wallet::Ethereum { rpc_url, key, ref mut nonce } => {
|
||||
use std::sync::Arc;
|
||||
use ethereum_serai::{
|
||||
alloy::{
|
||||
primitives::{U256, TxKind},
|
||||
sol_types::SolCall,
|
||||
simple_request_transport::SimpleRequest,
|
||||
consensus::{TxLegacy, SignableTransaction},
|
||||
rpc_client::ClientBuilder,
|
||||
provider::{Provider, RootProvider},
|
||||
network::Ethereum,
|
||||
},
|
||||
crypto::PublicKey,
|
||||
deployer::Deployer,
|
||||
};
|
||||
|
||||
let eight_decimals = U256::from(100_000_000u64);
|
||||
let nine_decimals = eight_decimals * U256::from(10u64);
|
||||
let eighteen_decimals = nine_decimals * nine_decimals;
|
||||
let one_eth = eighteen_decimals;
|
||||
|
||||
let tx = todo!("send to router");
|
||||
let provider = Arc::new(RootProvider::<_, Ethereum>::new(
|
||||
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
|
||||
));
|
||||
|
||||
let to_as_key = PublicKey::new(
|
||||
<ciphersuite::Secp256k1 as Ciphersuite>::read_G(&mut to.as_slice()).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let router_addr = {
|
||||
// Find the deployer
|
||||
let deployer = Deployer::new(provider.clone()).await.unwrap().unwrap();
|
||||
|
||||
// Find the router, deploying if non-existent
|
||||
let router = if let Some(router) =
|
||||
deployer.find_router(provider.clone(), &to_as_key).await.unwrap()
|
||||
{
|
||||
router
|
||||
} else {
|
||||
let mut tx = deployer.deploy_router(&to_as_key);
|
||||
tx.gas_price = 1_000_000_000u64.into();
|
||||
let tx = ethereum_serai::crypto::deterministically_sign(&tx);
|
||||
let signer = tx.recover_signer().unwrap();
|
||||
let (tx, sig, _) = tx.into_parts();
|
||||
|
||||
provider
|
||||
.raw_request::<_, ()>(
|
||||
"anvil_setBalance".into(),
|
||||
[signer.to_string(), (tx.gas_limit * tx.gas_price).to_string()],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut bytes = vec![];
|
||||
tx.encode_with_signature_fields(&sig, &mut bytes);
|
||||
let _ = provider.send_raw_transaction(&bytes).await.unwrap();
|
||||
|
||||
provider.raw_request::<_, ()>("anvil_mine".into(), [96]).await.unwrap();
|
||||
|
||||
deployer.find_router(provider.clone(), &to_as_key).await.unwrap().unwrap()
|
||||
};
|
||||
|
||||
router.address()
|
||||
};
|
||||
|
||||
let tx = TxLegacy {
|
||||
chain_id: None,
|
||||
nonce: *nonce,
|
||||
gas_price: 1_000_000_000u128,
|
||||
gas_limit: 200_000u128,
|
||||
to: TxKind::Call(router_addr.into()),
|
||||
// 1 ETH
|
||||
value: one_eth,
|
||||
input: ethereum_serai::router::abi::inInstructionCall::new((
|
||||
[0; 20].into(),
|
||||
one_eth,
|
||||
if let Some(instruction) = instruction {
|
||||
Shorthand::Raw(RefundableInInstruction { origin: None, instruction }).encode().into()
|
||||
} else {
|
||||
vec![].into()
|
||||
},
|
||||
))
|
||||
.abi_encode()
|
||||
.into(),
|
||||
};
|
||||
|
||||
*nonce += 1;
|
||||
(tx, Balance { coin: Coin::Ether, amount: Amount(u64::try_from(eight_decimals).unwrap()) })
|
||||
*/
|
||||
let _ = key;
|
||||
let _ = nonce;
|
||||
todo!()
|
||||
|
||||
let sig =
|
||||
k256::ecdsa::SigningKey::from(k256::elliptic_curve::NonZeroScalar::new(*key).unwrap())
|
||||
.sign_prehash_recoverable(tx.signature_hash().as_ref())
|
||||
.unwrap();
|
||||
|
||||
let mut bytes = vec![];
|
||||
tx.encode_with_signature_fields(&sig.into(), &mut bytes);
|
||||
|
||||
// We drop the bottom 10 decimals
|
||||
(
|
||||
bytes,
|
||||
Balance { coin: Coin::Ether, amount: Amount(u64::try_from(eight_decimals).unwrap()) },
|
||||
)
|
||||
}
|
||||
|
||||
Wallet::Monero { handle, ref spend_key, ref view_pair, ref mut inputs } => {
|
||||
|
@ -438,13 +524,10 @@ impl Wallet {
|
|||
)
|
||||
.unwrap()
|
||||
}
|
||||
Wallet::Ethereum { key, .. } => {
|
||||
use ciphersuite::{Ciphersuite, Secp256k1};
|
||||
ExternalAddress::new(
|
||||
ethereum_serai::crypto::address(&(Secp256k1::generator() * key)).into(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
Wallet::Ethereum { key, .. } => ExternalAddress::new(
|
||||
ethereum_serai::crypto::address(&(ciphersuite::Secp256k1::generator() * key)).into(),
|
||||
)
|
||||
.unwrap(),
|
||||
Wallet::Monero { view_pair, .. } => {
|
||||
use monero_serai::wallet::address::{Network, AddressSpec};
|
||||
ExternalAddress::new(
|
||||
|
|
|
@ -17,7 +17,8 @@ use serai_client::{
|
|||
validator_sets::primitives::Session,
|
||||
};
|
||||
|
||||
use processor::networks::{Network, Bitcoin, Monero};
|
||||
use serai_db::MemDb;
|
||||
use processor::networks::{Network, Bitcoin, Ethereum, Monero};
|
||||
|
||||
use crate::{*, tests::*};
|
||||
|
||||
|
@ -188,7 +189,7 @@ pub(crate) async fn substrate_block(
|
|||
|
||||
#[test]
|
||||
fn batch_test() {
|
||||
for network in [NetworkId::Bitcoin, NetworkId::Monero] {
|
||||
for network in [NetworkId::Bitcoin, NetworkId::Ethereum, NetworkId::Monero] {
|
||||
let (coordinators, test) = new_test(network);
|
||||
|
||||
test.run(|ops| async move {
|
||||
|
@ -245,6 +246,8 @@ fn batch_test() {
|
|||
// The scanner works on a 5s interval, so this leaves a few s for any processing/latency
|
||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||
|
||||
println!("sent in transaction. with in instruction: {}", instruction.is_some());
|
||||
|
||||
let expected_batch = Batch {
|
||||
network,
|
||||
id: i,
|
||||
|
@ -256,10 +259,11 @@ fn batch_test() {
|
|||
coin: balance_sent.coin,
|
||||
amount: Amount(
|
||||
balance_sent.amount.0 -
|
||||
(2 * if network == NetworkId::Bitcoin {
|
||||
Bitcoin::COST_TO_AGGREGATE
|
||||
} else {
|
||||
Monero::COST_TO_AGGREGATE
|
||||
(2 * match network {
|
||||
NetworkId::Bitcoin => Bitcoin::COST_TO_AGGREGATE,
|
||||
NetworkId::Ethereum => Ethereum::<MemDb>::COST_TO_AGGREGATE,
|
||||
NetworkId::Monero => Monero::COST_TO_AGGREGATE,
|
||||
NetworkId::Serai => panic!("minted for Serai?"),
|
||||
}),
|
||||
),
|
||||
},
|
||||
|
@ -272,6 +276,8 @@ fn batch_test() {
|
|||
},
|
||||
};
|
||||
|
||||
println!("receiving batch preprocesses...");
|
||||
|
||||
// Make sure the processors picked it up by checking they're trying to sign a batch for it
|
||||
let (mut id, mut preprocesses) =
|
||||
recv_batch_preprocesses(&mut coordinators, Session(0), &expected_batch, 0).await;
|
||||
|
@ -291,6 +297,8 @@ fn batch_test() {
|
|||
recv_batch_preprocesses(&mut coordinators, Session(0), &expected_batch, attempt).await;
|
||||
}
|
||||
|
||||
println!("signing batch...");
|
||||
|
||||
// Continue with signing the batch
|
||||
let batch = sign_batch(&mut coordinators, key_pair.0 .0, id, preprocesses).await;
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ pub(crate) async fn key_gen(coordinators: &mut [Coordinator]) -> KeyPair {
|
|||
|
||||
#[test]
|
||||
fn key_gen_test() {
|
||||
for network in [NetworkId::Bitcoin, NetworkId::Monero] {
|
||||
for network in [NetworkId::Bitcoin, NetworkId::Ethereum, NetworkId::Monero] {
|
||||
let (coordinators, test) = new_test(network);
|
||||
|
||||
test.run(|ops| async move {
|
||||
|
|
|
@ -20,8 +20,14 @@ pub(crate) const THRESHOLD: usize = ((COORDINATORS * 2) / 3) + 1;
|
|||
fn new_test(network: NetworkId) -> (Vec<(Handles, <Ristretto as Ciphersuite>::F)>, DockerTest) {
|
||||
let mut coordinators = vec![];
|
||||
let mut test = DockerTest::new().with_network(dockertest::Network::Isolated);
|
||||
let mut eth_handle = None;
|
||||
for _ in 0 .. COORDINATORS {
|
||||
let (handles, coord_key, compositions) = processor_stack(network);
|
||||
let (handles, coord_key, compositions) = processor_stack(network, eth_handle.clone());
|
||||
// TODO: Remove this once https://github.com/foundry-rs/foundry/issues/7955
|
||||
// This has all processors share an Ethereum node until we can sync controlled nodes
|
||||
if network == NetworkId::Ethereum {
|
||||
eth_handle = eth_handle.or_else(|| Some(handles.0.clone()));
|
||||
}
|
||||
coordinators.push((handles, coord_key));
|
||||
for composition in compositions {
|
||||
test.provide_container(composition);
|
||||
|
|
|
@ -8,12 +8,15 @@ use dkg::{Participant, tests::clone_without};
|
|||
use messages::{sign::SignId, SubstrateContext};
|
||||
|
||||
use serai_client::{
|
||||
primitives::{BlockHash, NetworkId},
|
||||
primitives::{BlockHash, NetworkId, Amount, Balance, SeraiAddress},
|
||||
coins::primitives::{OutInstruction, OutInstructionWithBalance},
|
||||
in_instructions::primitives::Batch,
|
||||
in_instructions::primitives::{InInstruction, InInstructionWithBalance, Batch},
|
||||
validator_sets::primitives::Session,
|
||||
};
|
||||
|
||||
use serai_db::MemDb;
|
||||
use processor::networks::{Network, Bitcoin, Ethereum, Monero};
|
||||
|
||||
use crate::{*, tests::*};
|
||||
|
||||
#[allow(unused)]
|
||||
|
@ -144,7 +147,7 @@ pub(crate) async fn sign_tx(
|
|||
|
||||
#[test]
|
||||
fn send_test() {
|
||||
for network in [NetworkId::Bitcoin, NetworkId::Monero] {
|
||||
for network in [NetworkId::Bitcoin, /* TODO NetworkId::Ethereum, */ NetworkId::Monero] {
|
||||
let (coordinators, test) = new_test(network);
|
||||
|
||||
test.run(|ops| async move {
|
||||
|
@ -173,7 +176,11 @@ fn send_test() {
|
|||
coordinators[0].sync(&ops, &coordinators[1 ..]).await;
|
||||
|
||||
// Send into the processor's wallet
|
||||
let (tx, balance_sent) = wallet.send_to_address(&ops, &key_pair.1, None).await;
|
||||
let mut serai_address = [0; 32];
|
||||
OsRng.fill_bytes(&mut serai_address);
|
||||
let instruction = InInstruction::Transfer(SeraiAddress(serai_address));
|
||||
let (tx, balance_sent) =
|
||||
wallet.send_to_address(&ops, &key_pair.1, Some(instruction.clone())).await;
|
||||
for coordinator in &mut coordinators {
|
||||
coordinator.publish_transacton(&ops, &tx).await;
|
||||
}
|
||||
|
@ -192,8 +199,25 @@ fn send_test() {
|
|||
// The scanner works on a 5s interval, so this leaves a few s for any processing/latency
|
||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||
|
||||
let expected_batch =
|
||||
Batch { network, id: 0, block: BlockHash(block_with_tx.unwrap()), instructions: vec![] };
|
||||
let amount_minted = Amount(
|
||||
balance_sent.amount.0 -
|
||||
(2 * match network {
|
||||
NetworkId::Bitcoin => Bitcoin::COST_TO_AGGREGATE,
|
||||
NetworkId::Ethereum => Ethereum::<MemDb>::COST_TO_AGGREGATE,
|
||||
NetworkId::Monero => Monero::COST_TO_AGGREGATE,
|
||||
NetworkId::Serai => panic!("minted for Serai?"),
|
||||
}),
|
||||
);
|
||||
|
||||
let expected_batch = Batch {
|
||||
network,
|
||||
id: 0,
|
||||
block: BlockHash(block_with_tx.unwrap()),
|
||||
instructions: vec![InInstructionWithBalance {
|
||||
instruction,
|
||||
balance: Balance { coin: balance_sent.coin, amount: amount_minted },
|
||||
}],
|
||||
};
|
||||
|
||||
// Make sure the proceessors picked it up by checking they're trying to sign a batch for it
|
||||
let (id, preprocesses) =
|
||||
|
@ -221,7 +245,7 @@ fn send_test() {
|
|||
block: substrate_block_num,
|
||||
burns: vec![OutInstructionWithBalance {
|
||||
instruction: OutInstruction { address: wallet.address(), data: None },
|
||||
balance: balance_sent,
|
||||
balance: Balance { coin: balance_sent.coin, amount: amount_minted },
|
||||
}],
|
||||
batches: vec![batch.batch.id],
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue