Test Batches with Instructions

This commit is contained in:
Luke Parker
2023-07-26 14:02:17 -04:00
parent e00aa3031c
commit 64c309f8db
6 changed files with 74 additions and 14 deletions

View File

@@ -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))
}
}
}

View File

@@ -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());
}
}
});
}