Skip to content

Commit

Permalink
start handling todos in utils.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
lamafab committed Sep 19, 2023
1 parent 4c84a49 commit 6fa15fc
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 28 deletions.
22 changes: 13 additions & 9 deletions rust/tw_bitcoin/src/modules/plan_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl BitcoinPlanBuilder {
proto
.tagged_output
.ok_or_else(|| Error::from(Proto::Error::Error_missing_tagged_output))?,
);
)?;

// First, we create the reveal transaction in order to calculate its input requirement (fee + dust limit).

Expand Down Expand Up @@ -121,6 +121,13 @@ impl BitcoinPlanBuilder {

let brc20_output_value = brc20_output.value;

// Clone the change output, if provided.
let change_output = if let Some(change) = proto.change_output {
Some(super::utils::hard_clone_proto_output(change)?)
} else {
None
};

// Create the full COMMIT transaction with the appropriately selected inputs.
let commit_signing = Proto::SigningInput {
private_key: proto.private_key.to_vec().into(),
Expand All @@ -129,13 +136,10 @@ impl BitcoinPlanBuilder {
.iter()
.cloned()
.map(super::utils::hard_clone_proto_input)
.collect(),
.collect::<Result<_>>()?,
outputs: vec![brc20_output],
input_selector: proto.input_selector,
change_output: proto
.change_output
.as_ref()
.map(|output| super::utils::hard_clone_proto_output(output.clone())),
change_output: change_output.clone(),
fee_per_vb: proto.fee_per_vb,
disable_change_output: proto.disable_change_output,
..Default::default()
Expand Down Expand Up @@ -167,7 +171,7 @@ impl BitcoinPlanBuilder {
.into_iter()
.filter(|input| selected_txids.contains(&input.txid))
.map(super::utils::hard_clone_proto_input)
.collect();
.collect::<Result<_>>()?;

commit_signing.inputs = selected_inputs;

Expand All @@ -179,12 +183,12 @@ impl BitcoinPlanBuilder {
.expect("No Utxo outputs generated")
.value;

let mut change_output = proto.change_output.expect("change output expected");
let mut change_output = change_output.expect("change output expected");
change_output.value = change_amount;

commit_signing
.outputs
.push(hard_clone_proto_output(change_output));
.push(hard_clone_proto_output(change_output)?);
}

commit_signing.input_selector = UtxoProto::InputSelector::UseAll;
Expand Down
45 changes: 26 additions & 19 deletions rust/tw_bitcoin/src/modules/utils.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::aliases::*;
use crate::{Error, Result};
use tw_proto::BitcoinV2::Proto;

// Convenience function: our protobuf library wraps certain types (such as
// `bytes`) in `Cow`, but given that calling `clone()` on a `Cow::Borrowed(T)`
// does not actually clone the underlying data (but the smart pointer instead),
// we must hard-clone individual fields manually. This is unfortunately required
// due to how protobuf library works and our use of the 'static constraints.
pub fn hard_clone_proto_input(proto: Proto::Input<'_>) -> Proto::Input<'static> {
pub fn hard_clone_proto_input(proto: Proto::Input<'_>) -> Result<Proto::Input<'static>> {
fn new_builder(variant: ProtoInputBuilder<'static>) -> ProtoInputRecipient<'static> {
ProtoInputRecipient::builder(Proto::mod_Input::InputBuilder { variant })
}
Expand Down Expand Up @@ -54,7 +55,9 @@ pub fn hard_clone_proto_input(proto: Proto::Input<'_>) -> Proto::Input<'static>
payload: ord.payload.to_vec().into(),
}),
),
ProtoInputBuilder::None => todo!(),
ProtoInputBuilder::None => {
return Err(Error::from(Proto::Error::Error_missing_input_builder))
},
},
ProtoInputRecipient::custom_script(custom) => {
ProtoInputRecipient::custom_script(Proto::mod_Input::InputScriptWitness {
Expand All @@ -68,68 +71,72 @@ pub fn hard_clone_proto_input(proto: Proto::Input<'_>) -> Proto::Input<'static>
signing_method: custom.signing_method,
})
},
ProtoInputRecipient::None => todo!(),
ProtoInputRecipient::None => {
return Err(Error::from(Proto::Error::Error_missing_recipient))
},
};

Proto::Input {
Ok(Proto::Input {
private_key: proto.private_key.to_vec().into(),
txid: proto.txid.to_vec().into(),
to_recipient,
..proto
}
})
}

// Convenience function: our protobuf library wraps certain types (such as
// `bytes`) in `Cow`, but given that calling `clone()` on a `Cow::Borrowed(T)`
// does not actually clone the underlying data (but the smart pointer instead),
// we must hard-clone individual fields manually. This is unfortunately required
// due to how protobuf library works and our use of the 'static constraints.
pub fn hard_clone_proto_output(proto: Proto::Output<'_>) -> Proto::Output<'static> {
pub fn hard_clone_proto_output(proto: Proto::Output<'_>) -> Result<Proto::Output<'static>> {
fn new_builder(variant: ProtoOutputBuilder<'static>) -> ProtoOutputRecipient<'static> {
ProtoOutputRecipient::builder(Proto::mod_Output::OutputBuilder { variant })
}

fn new_script_or_hash(
proto: Proto::mod_Output::OutputRedeemScriptOrHash<'_>,
) -> Proto::mod_Output::OutputRedeemScriptOrHash<'static> {
) -> Result<Proto::mod_Output::OutputRedeemScriptOrHash<'static>> {
let variant = match proto.variant {
ProtoOutputRedeemScriptOrHashBuilder::redeem_script(script) => {
ProtoOutputRedeemScriptOrHashBuilder::redeem_script(script.to_vec().into())
},
ProtoOutputRedeemScriptOrHashBuilder::hash(hash) => {
ProtoOutputRedeemScriptOrHashBuilder::hash(hash.to_vec().into())
},
ProtoOutputRedeemScriptOrHashBuilder::None => todo!(),
ProtoOutputRedeemScriptOrHashBuilder::None => {
return Err(Error::from(Proto::Error::Error_missing_recipient))
},
};

Proto::mod_Output::OutputRedeemScriptOrHash { variant }
Ok(Proto::mod_Output::OutputRedeemScriptOrHash { variant })
}

fn new_pubkey_or_hash(
proto: Proto::ToPublicKeyOrHash<'_>,
) -> Proto::ToPublicKeyOrHash<'static> {
) -> Result<Proto::ToPublicKeyOrHash<'static>> {
let to_address = match proto.to_address {
ProtoPubkeyOrHash::pubkey(pubkey) => ProtoPubkeyOrHash::pubkey(pubkey.to_vec().into()),
ProtoPubkeyOrHash::hash(hash) => ProtoPubkeyOrHash::hash(hash.to_vec().into()),
ProtoPubkeyOrHash::None => todo!(),
};

Proto::ToPublicKeyOrHash { to_address }
Ok(Proto::ToPublicKeyOrHash { to_address })
}

let to_recipient = match proto.to_recipient {
ProtoOutputRecipient::builder(builder) => match builder.variant {
ProtoOutputBuilder::p2sh(script_or_hash) => {
new_builder(ProtoOutputBuilder::p2sh(new_script_or_hash(script_or_hash)))
},
ProtoOutputBuilder::p2sh(script_or_hash) => new_builder(ProtoOutputBuilder::p2sh(
new_script_or_hash(script_or_hash)?,
)),
ProtoOutputBuilder::p2pkh(pubkey_or_hash) => new_builder(ProtoOutputBuilder::p2pkh(
new_pubkey_or_hash(pubkey_or_hash),
new_pubkey_or_hash(pubkey_or_hash)?,
)),
ProtoOutputBuilder::p2wsh(script_or_hash) => new_builder(ProtoOutputBuilder::p2wsh(
new_script_or_hash(script_or_hash),
new_script_or_hash(script_or_hash)?,
)),
ProtoOutputBuilder::p2wpkh(pubkey_or_hash) => new_builder(ProtoOutputBuilder::p2wpkh(
new_pubkey_or_hash(pubkey_or_hash),
new_pubkey_or_hash(pubkey_or_hash)?,
)),
ProtoOutputBuilder::p2tr_key_path(pubkey) => {
new_builder(ProtoOutputBuilder::p2tr_key_path(pubkey.to_vec().into()))
Expand Down Expand Up @@ -168,8 +175,8 @@ pub fn hard_clone_proto_output(proto: Proto::Output<'_>) -> Proto::Output<'stati
ProtoOutputRecipient::None => todo!(),
};

Proto::Output {
Ok(Proto::Output {
value: proto.value,
to_recipient,
}
})
}

0 comments on commit 6fa15fc

Please sign in to comment.