mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-22 19:49:22 +00:00
Test Batches with Instructions
This commit is contained in:
parent
e00aa3031c
commit
64c309f8db
6 changed files with 74 additions and 14 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -8849,6 +8849,7 @@ dependencies = [
|
|||
"dockertest",
|
||||
"hex",
|
||||
"monero-serai",
|
||||
"parity-scale-codec",
|
||||
"rand_core 0.6.4",
|
||||
"serai-docker-tests",
|
||||
"serai-in-instructions-primitives",
|
||||
|
|
|
@ -699,6 +699,8 @@ async fn run<C: Coin, D: Db, Co: Coordinator>(mut raw_db: D, coin: C, mut coordi
|
|||
}).collect()
|
||||
};
|
||||
|
||||
info!("created batch {} ({} instructions)", batch.id, batch.instructions.len());
|
||||
|
||||
// Start signing this batch
|
||||
tributary_mutable
|
||||
.substrate_signers
|
||||
|
|
|
@ -162,7 +162,7 @@ impl<D: Db> SubstrateSigner<D> {
|
|||
self.attempt.insert(id, attempt);
|
||||
|
||||
let id = SignId { key: self.keys.group_key().to_bytes().to_vec(), id, attempt };
|
||||
info!("signing batch {} with attempt #{}", hex::encode(id.id), id.attempt);
|
||||
info!("signing batch {}, attempt #{}", hex::encode(id.id), id.attempt);
|
||||
|
||||
// If we reboot mid-sign, the current design has us abort all signs and wait for latter
|
||||
// attempts/new signing protocols
|
||||
|
@ -178,7 +178,7 @@ impl<D: Db> SubstrateSigner<D> {
|
|||
// Only run if this hasn't already been attempted
|
||||
if SubstrateSignerDb::<D>::has_attempt(txn, &id) {
|
||||
warn!(
|
||||
"already attempted {} #{}. this is an error if we didn't reboot",
|
||||
"already attempted batch {}, attempt #{}. this is an error if we didn't reboot",
|
||||
hex::encode(id.id),
|
||||
id.attempt
|
||||
);
|
||||
|
|
|
@ -28,6 +28,7 @@ monero-serai = { path = "../../coins/monero" }
|
|||
|
||||
messages = { package = "serai-processor-messages", path = "../../processor/messages" }
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3" }
|
||||
serai-primitives = { path = "../../substrate/primitives" }
|
||||
serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primitives" }
|
||||
serai-in-instructions-primitives = { path = "../../substrate/in-instructions/primitives" }
|
||||
|
|
|
@ -3,8 +3,11 @@ use std::collections::HashSet;
|
|||
use zeroize::Zeroizing;
|
||||
use rand_core::{RngCore, OsRng};
|
||||
|
||||
use serai_primitives::NetworkId;
|
||||
use scale::Encode;
|
||||
|
||||
use serai_primitives::{NetworkId, Amount};
|
||||
use serai_validator_sets_primitives::ExternalKey;
|
||||
use serai_in_instructions_primitives::{InInstruction, RefundableInInstruction, Shorthand};
|
||||
|
||||
use dockertest::{PullPolicy, Image, StartPolicy, Composition, DockerOperations};
|
||||
|
||||
|
@ -213,7 +216,12 @@ impl Wallet {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn send_to_address(&mut self, ops: &DockerOperations, to: &ExternalKey) -> Vec<u8> {
|
||||
pub async fn send_to_address(
|
||||
&mut self,
|
||||
ops: &DockerOperations,
|
||||
to: &ExternalKey,
|
||||
instruction: Option<InInstruction>,
|
||||
) -> (Vec<u8>, Amount) {
|
||||
match self {
|
||||
Wallet::Bitcoin { private_key, public_key, ref mut input_tx } => {
|
||||
use bitcoin_serai::bitcoin::{
|
||||
|
@ -221,7 +229,7 @@ impl Wallet {
|
|||
key::{XOnlyPublicKey, TweakedPublicKey},
|
||||
consensus::Encodable,
|
||||
sighash::{EcdsaSighashType, SighashCache},
|
||||
script::{PushBytesBuf, Script, Builder},
|
||||
script::{PushBytesBuf, Script, ScriptBuf, Builder},
|
||||
address::Payload,
|
||||
OutPoint, Sequence, Witness, TxIn, TxOut,
|
||||
absolute::LockTime,
|
||||
|
@ -253,6 +261,18 @@ impl Wallet {
|
|||
],
|
||||
};
|
||||
|
||||
if let Some(instruction) = instruction {
|
||||
tx.output.push(TxOut {
|
||||
value: 0,
|
||||
script_pubkey: ScriptBuf::new_op_return(
|
||||
&PushBytesBuf::try_from(
|
||||
Shorthand::Raw(RefundableInInstruction { origin: None, instruction }).encode(),
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
let mut der = SECP256K1
|
||||
.sign_ecdsa_low_r(
|
||||
&Message::from(
|
||||
|
@ -278,7 +298,7 @@ impl Wallet {
|
|||
let mut buf = vec![];
|
||||
tx.consensus_encode(&mut buf).unwrap();
|
||||
*input_tx = tx;
|
||||
buf
|
||||
(buf, Amount(AMOUNT))
|
||||
}
|
||||
|
||||
Wallet::Monero { handle, ref spend_key, ref view_pair, ref mut inputs } => {
|
||||
|
@ -329,13 +349,18 @@ impl Wallet {
|
|||
);
|
||||
|
||||
// Create and sign the TX
|
||||
const AMOUNT: u64 = 1_000_000_000_000;
|
||||
let mut data = vec![];
|
||||
if let Some(instruction) = instruction {
|
||||
data.push(Shorthand::Raw(RefundableInInstruction { origin: None, instruction }).encode());
|
||||
}
|
||||
let tx = SignableTransaction::new(
|
||||
Protocol::v16,
|
||||
None,
|
||||
these_inputs.drain(..).zip(decoys.drain(..)).collect(),
|
||||
vec![(to_addr, 1_000_000_000_000)],
|
||||
vec![(to_addr, AMOUNT)],
|
||||
Some(Change::new(view_pair, false)),
|
||||
vec![],
|
||||
data,
|
||||
rpc.get_fee(Protocol::v16, FeePriority::Low).await.unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
|
@ -351,7 +376,7 @@ impl Wallet {
|
|||
.remove(0),
|
||||
);
|
||||
|
||||
tx.serialize()
|
||||
(tx.serialize(), Amount(AMOUNT))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,12 @@ use dkg::{Participant, tests::clone_without};
|
|||
|
||||
use messages::sign::SignId;
|
||||
|
||||
use serai_primitives::{NetworkId, BlockHash, crypto::RuntimePublic, PublicKey};
|
||||
use serai_in_instructions_primitives::{SignedBatch, batch_message};
|
||||
use serai_primitives::{
|
||||
BlockHash, crypto::RuntimePublic, PublicKey, SeraiAddress, NetworkId, Coin, Balance,
|
||||
};
|
||||
use serai_in_instructions_primitives::{
|
||||
InInstruction, InInstructionWithBalance, SignedBatch, batch_message,
|
||||
};
|
||||
|
||||
use dockertest::DockerTest;
|
||||
|
||||
|
@ -168,9 +172,16 @@ fn batch_test() {
|
|||
}
|
||||
coordinators[0].sync(&ops, &coordinators[1 ..]).await;
|
||||
|
||||
// Run twice, once with an instruction and once without
|
||||
for i in 0 .. 2 {
|
||||
let mut serai_address = [0; 32];
|
||||
OsRng.fill_bytes(&mut serai_address);
|
||||
let instruction =
|
||||
if i == 1 { Some(InInstruction::Transfer(SeraiAddress(serai_address))) } else { None };
|
||||
|
||||
// Send into the processor's wallet
|
||||
let tx = wallet.send_to_address(&ops, &key_pair.1).await;
|
||||
let (tx, amount_sent) =
|
||||
wallet.send_to_address(&ops, &key_pair.1, instruction.clone()).await;
|
||||
for coordinator in &mut coordinators {
|
||||
coordinator.publish_transacton(&ops, &tx).await;
|
||||
}
|
||||
|
@ -215,8 +226,28 @@ fn batch_test() {
|
|||
assert_eq!(batch.batch.network, network);
|
||||
assert_eq!(batch.batch.id, i);
|
||||
assert_eq!(batch.batch.block, BlockHash(block_with_tx.unwrap()));
|
||||
// This shouldn't have an instruction as we didn't add any data into the TX we sent
|
||||
assert!(batch.batch.instructions.is_empty());
|
||||
if let Some(instruction) = instruction {
|
||||
assert_eq!(
|
||||
batch.batch.instructions,
|
||||
vec![InInstructionWithBalance {
|
||||
instruction,
|
||||
balance: Balance {
|
||||
coin: match network {
|
||||
NetworkId::Bitcoin => Coin::Bitcoin,
|
||||
NetworkId::Ethereum => todo!(),
|
||||
NetworkId::Monero => Coin::Monero,
|
||||
NetworkId::Serai => panic!("running processor tests on Serai"),
|
||||
},
|
||||
amount: amount_sent,
|
||||
}
|
||||
}]
|
||||
);
|
||||
} else {
|
||||
// This shouldn't have an instruction as we didn't add any data into the TX we sent
|
||||
// Empty batches remain valuable as they let us achieve consensus on the block and spend
|
||||
// contained outputs
|
||||
assert!(batch.batch.instructions.is_empty());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue