-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an implementation of PSBT version 2 - BOOM! Includes all test vectors from BIP-370. Also includes changes to `v0` to explicitly exclude keys as required by PSBT v2 upgrade.
- Loading branch information
Showing
27 changed files
with
5,568 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
//! PSBT v2 - Creator a PSBT and hand it around to various different entities to add inputs and outputs. | ||
|
||
use psbt::bitcoin::hashes::Hash as _; | ||
use psbt::bitcoin::{Amount, OutPoint, ScriptBuf, TxOut, Txid}; | ||
use psbt::v2::{ | ||
Constructor, Creator, InputBuilder, InputsOnlyModifiable, OutputBuilder, OutputsOnlyModifiable, | ||
Psbt, | ||
}; | ||
|
||
fn main() -> anyhow::Result<()> { | ||
// Create the PSBT. | ||
let created = Creator::new().inputs_modifiable().outputs_modifiable().psbt(); | ||
|
||
let ser = created.serialize(); | ||
|
||
// The first constructor entity receives the PSBT and adds an input. | ||
let psbt = Psbt::deserialize(&ser)?; | ||
let in_0 = dummy_out_point(); | ||
let ser = Constructor::<InputsOnlyModifiable>::new(psbt)? | ||
.input(InputBuilder::new(in_0).build()) | ||
.psbt() | ||
.serialize(); | ||
|
||
// The second constructor entity receives the PSBT with one input and adds a second input. | ||
let psbt = Psbt::deserialize(&ser)?; | ||
let in_1 = dummy_out_point(); | ||
let ser = Constructor::<InputsOnlyModifiable>::new(psbt)? | ||
.input(InputBuilder::new(in_1).build()) | ||
.no_more_inputs() | ||
.psbt() | ||
.serialize(); | ||
|
||
// The third constructor entity receives the PSBT with inputs and adds an output. | ||
let psbt = Psbt::deserialize(&ser)?; | ||
let output = dummy_tx_out(); | ||
let ser = Constructor::<OutputsOnlyModifiable>::new(psbt)? | ||
.output(OutputBuilder::new(output).build()) | ||
.no_more_outputs() | ||
.psbt() | ||
.serialize(); | ||
|
||
// The PSBT is now ready for handling with the updater role. | ||
let _updatable_psbt = Psbt::deserialize(&ser)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
/// A dummy `OutPoint`, this would usually be the unspent transaction that we are spending. | ||
fn dummy_out_point() -> OutPoint { | ||
let txid = Txid::hash(b"some arbitrary bytes"); | ||
let vout = 0x15; | ||
OutPoint { txid, vout } | ||
} | ||
|
||
/// A dummy `TxOut`, this would usually be the output we are creating with this transaction. | ||
fn dummy_tx_out() -> TxOut { | ||
// Arbitrary script, may not even be a valid scriptPubkey. | ||
let script = ScriptBuf::from_hex("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac") | ||
.expect("failed to parse script form hex"); | ||
let value = Amount::from_sat(123_456_789); | ||
TxOut { value, script_pubkey: script } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
//! PSBT v2. | ||
//! | ||
//! An example of using PSBT v2 to spend the multisig created in v0.rs to a p2tr output and a p2wpkh change output. | ||
|
||
use psbt::bitcoin::{absolute, OutPoint, Sequence, TxOut}; | ||
use psbt::v2::{Constructor, InputBuilder, Modifiable, OutputBuilder}; | ||
|
||
fn main() -> anyhow::Result<()> { | ||
let previous_output = unspent_multisig_output(); | ||
let spend = spend_output(); | ||
let change = change_output(); | ||
|
||
let min_required_height = absolute::Height::from_consensus(800_000).expect("valid height"); | ||
|
||
// The constructor role. | ||
|
||
let constructor = Constructor::<Modifiable>::default(); | ||
|
||
let input = InputBuilder::new(previous_output) | ||
.minimum_required_height_based_lock_time(min_required_height) | ||
.build(); | ||
|
||
let psbt = constructor | ||
.input(input) | ||
.output(OutputBuilder::new(spend).build()) | ||
.output(OutputBuilder::new(change).build()) | ||
.psbt(); | ||
|
||
// The updater role. | ||
let _ = psbt.set_sequence(Sequence::ENABLE_LOCKTIME_NO_RBF, 0); | ||
|
||
// TODO: Do updates: | ||
// - add inputs[0].witness_utxo | ||
// - add inputs[0].witness_script | ||
|
||
// Each party signs a copy of the PSBT. | ||
// let signed_by_a = alice.sign(psbt.clone())?; | ||
// let signed_by_b = bob.sign(psbt)?; | ||
|
||
// Combiner combines the two PSBTs (or uses `combine_with` to combine one into the other). | ||
// let signed = psbt::v2::combine(signed_by_a, signed_by_b)?; | ||
|
||
// TODO: Finalize and extract. | ||
|
||
Ok(()) | ||
} | ||
|
||
fn unspent_multisig_output() -> OutPoint { todo!() } | ||
|
||
/// Spend to a p2tr output. | ||
fn spend_output() -> TxOut { todo!() } | ||
|
||
/// Send the change back to us in a p2wpkh output. | ||
fn change_output() -> TxOut { todo!() } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.