mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +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:
@@ -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],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user