reduce duplication of transaction-building code

This commit is contained in:
conduition
2024-03-20 21:44:35 +00:00
parent 8e337ccb8b
commit 4e1eb8eeee

View File

@@ -6,7 +6,7 @@ use bitcoincore_rpc::{jsonrpc::serde_json, Auth, Client as BitcoinClient, RpcApi
use serial_test::serial; use serial_test::serial;
use bitcoin::{ use bitcoin::{
blockdata::transaction::predict_weight, blockdata::transaction::{predict_weight, InputWeightPrediction},
hashes::Hash, hashes::Hash,
key::TweakedPublicKey, key::TweakedPublicKey,
locktime::absolute::LockTime, locktime::absolute::LockTime,
@@ -19,8 +19,6 @@ use secp::{MaybeScalar, Point, Scalar};
use std::collections::BTreeMap; use std::collections::BTreeMap;
const P2TR_SCRIPT_PUBKEY_SIZE: usize = 34;
/// Generate a P2TR address which pays to the given pubkey (no tweak added). /// Generate a P2TR address which pays to the given pubkey (no tweak added).
fn p2tr_address(pubkey: Point) -> Address { fn p2tr_address(pubkey: Point) -> Address {
let (xonly, _) = pubkey.into(); let (xonly, _) = pubkey.into();
@@ -35,6 +33,28 @@ fn p2tr_script_pubkey(pubkey: Point) -> ScriptBuf {
ScriptBuf::new_p2tr_tweaked(tweaked) ScriptBuf::new_p2tr_tweaked(tweaked)
} }
fn simple_sweep_tx(
destination_pubkey: Point,
input: TxIn,
input_weight: InputWeightPrediction,
prevout_value: Amount,
) -> Transaction {
let script_pubkey = p2tr_script_pubkey(destination_pubkey);
Transaction {
version: bitcoin::transaction::Version::TWO,
lock_time: LockTime::ZERO,
input: vec![input],
output: vec![TxOut {
value: {
let tx_weight = predict_weight([input_weight], [script_pubkey.len()]);
let fee = tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
prevout_value - fee
},
script_pubkey,
}],
}
}
/// Build a bitcoind RPC client for regtest. Expects the following environment variables /// Build a bitcoind RPC client for regtest. Expects the following environment variables
/// to be defined: /// to be defined:
/// ///
@@ -456,10 +476,6 @@ impl SimulationManager {
mine_blocks(&self.rpc, (expiry_height - block_height) as u16) mine_blocks(&self.rpc, (expiry_height - block_height) as u16)
} }
fn script_pubkey_market_maker(&self) -> ScriptBuf {
p2tr_script_pubkey(self.contract.params().market_maker.pubkey)
}
} }
#[test] #[test]
@@ -535,22 +551,12 @@ fn ticketed_dlc_with_on_chain_resolutions() {
.split_sellback_tx_input_and_prevout(&alice_win_cond) .split_sellback_tx_input_and_prevout(&alice_win_cond)
.unwrap(); .unwrap();
let mut sellback_tx = Transaction { let mut sellback_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.contract.params().market_maker.pubkey,
lock_time: LockTime::ZERO, alice_split_input,
input: vec![alice_split_input], manager.contract.split_sellback_tx_input_weight(),
output: vec![TxOut { alice_split_prevout.value,
script_pubkey: p2tr_script_pubkey(manager.alice.player.pubkey),
value: {
let sellback_tx_weight = predict_weight(
[manager.contract.split_sellback_tx_input_weight()],
[P2TR_SCRIPT_PUBKEY_SIZE],
); );
let fee = sellback_tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
alice_split_prevout.value - fee
},
}],
};
manager manager
.contract .contract
@@ -581,22 +587,12 @@ fn ticketed_dlc_with_on_chain_resolutions() {
.split_win_tx_input_and_prevout(&bob_win_cond) .split_win_tx_input_and_prevout(&bob_win_cond)
.unwrap(); .unwrap();
let mut bob_win_tx = Transaction { let mut bob_win_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.bob.player.pubkey,
lock_time: LockTime::ZERO, bob_split_input,
input: vec![bob_split_input], manager.contract.split_win_tx_input_weight(),
output: vec![TxOut { bob_split_prevout.value,
script_pubkey: p2tr_script_pubkey(manager.bob.player.pubkey),
value: {
let win_tx_weight = predict_weight(
[manager.contract.split_win_tx_input_weight()],
[P2TR_SCRIPT_PUBKEY_SIZE],
); );
let fee = win_tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
bob_split_prevout.value - fee
},
}],
};
// Ensure Bob cannot broadcast a win TX early. OP_CSV should // Ensure Bob cannot broadcast a win TX early. OP_CSV should
// enforce the relative locktime. // enforce the relative locktime.
@@ -660,22 +656,12 @@ fn ticketed_dlc_with_on_chain_resolutions() {
.split_reclaim_tx_input_and_prevout(&carol_win_cond) .split_reclaim_tx_input_and_prevout(&carol_win_cond)
.unwrap(); .unwrap();
let mut reclaim_tx = Transaction { let mut reclaim_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.contract.params().market_maker.pubkey,
lock_time: LockTime::ZERO, carol_split_input,
input: vec![carol_split_input], manager.contract.split_reclaim_tx_input_weight(),
output: vec![TxOut { carol_split_prevout.value,
script_pubkey: manager.script_pubkey_market_maker(),
value: {
let reclaim_tx_weight = predict_weight(
[manager.contract.split_reclaim_tx_input_weight()],
[P2TR_SCRIPT_PUBKEY_SIZE],
); );
let fee = reclaim_tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
carol_split_prevout.value - fee
},
}],
};
// Ensure the Market Maker cannot broadcast a split reclaim TX early. OP_CSV // Ensure the Market Maker cannot broadcast a split reclaim TX early. OP_CSV
// should enforce the relative locktime. // should enforce the relative locktime.
@@ -772,22 +758,12 @@ fn ticketed_dlc_individual_sellback() {
.contract .contract
.split_close_tx_input_and_prevout(&bob_win_cond) .split_close_tx_input_and_prevout(&bob_win_cond)
.expect("error computing split close TX prevouts"); .expect("error computing split close TX prevouts");
let mut close_tx = Transaction { let mut close_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.contract.params().market_maker.pubkey,
lock_time: LockTime::ZERO, close_tx_input,
input: vec![close_tx_input], manager.contract.close_tx_input_weight(),
output: vec![TxOut { close_tx_prevout.value,
script_pubkey: manager.script_pubkey_market_maker(),
value: {
let close_tx_weight = predict_weight(
[manager.contract.close_tx_input_weight()],
[P2TR_SCRIPT_PUBKEY_SIZE],
); );
let fee = close_tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
close_tx_prevout.value - fee
},
}],
};
manager manager
.contract .contract
@@ -837,22 +813,12 @@ fn ticketed_dlc_all_winners_cooperate() {
.contract .contract
.outcome_close_tx_input_and_prevout(&outcome) .outcome_close_tx_input_and_prevout(&outcome)
.expect("error constructing outcome close TX prevouts"); .expect("error constructing outcome close TX prevouts");
let mut close_tx = Transaction { let mut close_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.contract.params().market_maker.pubkey,
lock_time: LockTime::ZERO, close_tx_input,
input: vec![close_tx_input], manager.contract.close_tx_input_weight(),
output: vec![TxOut { close_tx_prevout.value,
script_pubkey: manager.script_pubkey_market_maker(),
value: {
let close_tx_weight = predict_weight(
[manager.contract.close_tx_input_weight()],
[P2TR_SCRIPT_PUBKEY_SIZE],
); );
let fee = close_tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
close_tx_prevout.value - fee
},
}],
};
manager manager
.contract .contract
@@ -901,23 +867,15 @@ fn ticketed_dlc_market_maker_reclaims_outcome_tx() {
.contract .contract
.outcome_reclaim_tx_input_and_prevout(&outcome) .outcome_reclaim_tx_input_and_prevout(&outcome)
.expect("error constructing outcome reclaim TX prevouts"); .expect("error constructing outcome reclaim TX prevouts");
let mut reclaim_tx = Transaction { let mut reclaim_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.contract.params().market_maker.pubkey,
lock_time: LockTime::ZERO, reclaim_tx_input,
input: vec![reclaim_tx_input], manager
output: vec![TxOut {
script_pubkey: manager.script_pubkey_market_maker(),
value: {
let input_weight = manager
.contract .contract
.outcome_reclaim_tx_input_weight(&outcome) .outcome_reclaim_tx_input_weight(&outcome)
.unwrap(); .unwrap(),
let reclaim_tx_weight = predict_weight([input_weight], [P2TR_SCRIPT_PUBKEY_SIZE]); reclaim_tx_prevout.value,
let fee = reclaim_tx_weight * FeeRate::from_sat_per_vb_unchecked(20); );
reclaim_tx_prevout.value - fee
},
}],
};
// Ensure the Market Maker cannot broadcast an outcome reclaim TX early. OP_CSV // Ensure the Market Maker cannot broadcast an outcome reclaim TX early. OP_CSV
// should enforce the relative locktime. // should enforce the relative locktime.
@@ -1050,22 +1008,12 @@ fn ticketed_dlc_contract_expiry_on_chain_resolution() {
.split_win_tx_input_and_prevout(&dave_win_cond) .split_win_tx_input_and_prevout(&dave_win_cond)
.unwrap(); .unwrap();
let mut dave_win_tx = Transaction { let mut dave_win_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.dave.player.pubkey,
lock_time: LockTime::ZERO, dave_split_input,
input: vec![dave_split_input], manager.contract.split_win_tx_input_weight(),
output: vec![TxOut { dave_split_prevout.value,
script_pubkey: p2tr_script_pubkey(manager.dave.player.pubkey),
value: {
let win_tx_weight = predict_weight(
[manager.contract.split_win_tx_input_weight()],
[P2TR_SCRIPT_PUBKEY_SIZE],
); );
let fee = win_tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
dave_split_prevout.value - fee
},
}],
};
// Ensure Dave cannot broadcast the win TX early. OP_CSV should // Ensure Dave cannot broadcast the win TX early. OP_CSV should
// enforce the relative locktime. // enforce the relative locktime.
@@ -1155,22 +1103,12 @@ fn ticketed_dlc_contract_expiry_all_winners_cooperate() {
.contract .contract
.outcome_close_tx_input_and_prevout(&outcome) .outcome_close_tx_input_and_prevout(&outcome)
.expect("error constructing outcome close TX prevouts"); .expect("error constructing outcome close TX prevouts");
let mut close_tx = Transaction { let mut close_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.contract.params().market_maker.pubkey,
lock_time: LockTime::ZERO, close_tx_input,
input: vec![close_tx_input], manager.contract.close_tx_input_weight(),
output: vec![TxOut { close_tx_prevout.value,
script_pubkey: manager.script_pubkey_market_maker(),
value: {
let close_tx_weight = predict_weight(
[manager.contract.close_tx_input_weight()],
[P2TR_SCRIPT_PUBKEY_SIZE],
); );
let fee = close_tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
close_tx_prevout.value - fee
},
}],
};
manager manager
.contract .contract
@@ -1209,22 +1147,12 @@ fn ticketed_dlc_all_players_cooperate() {
// double spends the funding TX, but even if the split TX is confirmed, // double spends the funding TX, but even if the split TX is confirmed,
// the market maker can then immediately sweep the output of the split TX anyway. // the market maker can then immediately sweep the output of the split TX anyway.
let (close_tx_input, close_tx_prevout) = manager.contract.funding_close_tx_input_and_prevout(); let (close_tx_input, close_tx_prevout) = manager.contract.funding_close_tx_input_and_prevout();
let mut close_tx = Transaction { let mut close_tx = simple_sweep_tx(
version: bitcoin::transaction::Version::TWO, manager.contract.params().market_maker.pubkey,
lock_time: LockTime::ZERO, close_tx_input,
input: vec![close_tx_input], manager.contract.close_tx_input_weight(),
output: vec![TxOut { close_tx_prevout.value,
script_pubkey: manager.script_pubkey_market_maker(),
value: {
let close_tx_weight = predict_weight(
[manager.contract.close_tx_input_weight()],
[P2TR_SCRIPT_PUBKEY_SIZE],
); );
let fee = close_tx_weight * FeeRate::from_sat_per_vb_unchecked(20);
close_tx_prevout.value - fee
},
}],
};
manager manager
.contract .contract