Skip to content

Instantly share code, notes, and snippets.

@stevenroose
Created July 16, 2019 20:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevenroose/e32173d7f4213bf71ccc848431dc5379 to your computer and use it in GitHub Desktop.
Save stevenroose/e32173d7f4213bf71ccc848431dc5379 to your computer and use it in GitHub Desktop.
let mut unsigned_tx: Transaction = deserialize(&funded_result.hex)?;
// Gather the details for the inputs.
let mut input_details = Vec::with_capacity(unsigned_tx.input.len());
for input in &unsigned_tx.input {
let prevout = input.previous_output;
let prevtx = self.rpc.get_transaction(&prevout.txid, Some(true))?;
let details = match prevtx.details.into_iter().find(|d| d.vout == prevout.vout) {
None => bail!("transaction has unknown input: {}", prevout),
Some(det) => det,
};
// If the output is not p2wpkh, we can't spend it for now.
//TODO(stevenroose) implement non-p2wpkh spending
//TODO(stevenroose) make this check better after https://github.com/rust-bitcoin/rust-bitcoin/pull/255
let is_p2wpkh = match details.address.payload {
bitcoin::util::address::Payload::WitnessProgram(ref prog) => {
prog.program().len() == 20
}
_ => false,
};
if !is_p2wpkh {
warn!("Wallet received a tx on a non-p2wpkh address {}: {}", details.address, prevout);
// We lock the unspent so it doesn't get selected anymore.
self.rpc.lock_unspent(&[prevout])?;
continue 'outer;
}
input_details.push(details);
}
debug!("unsigned_tx: {:?}", unsigned_tx);
// Sign the tx.
let sighash_components = bip143::SighashComponents::new(&unsigned_tx);
for (idx, details) in input_details.into_iter().enumerate() {
if details.label.is_none() {
bail!("no label on address {}", details.address);
}
let label = AddressMeta::from_label(details.label.as_ref())?;
let xpriv = if label.fp == self.external_xpriv.as_ref().unwrap().fingerprint(&SECP)
{
self.external_xpriv.as_ref().unwrap()
} else if label.fp == self.internal_xpriv.as_ref().unwrap().fingerprint(&SECP) {
self.internal_xpriv.as_ref().unwrap()
} else {
bail!(
"address is labeled with unknown master xpriv fingerprint: {:?}",
label.fp
)
};
let privkey = xpriv.derive_priv(&SECP, &[label.child])?.private_key;
let pubkey = privkey.public_key(&SECP);
let script_code = bitcoin::Address::p2pkh(&pubkey, privkey.network).script_pubkey();
let sighash = sighash_components.sighash_all(
&unsigned_tx.input[idx],
&script_code,
details.amount.into_inner() as u64,
);
let msg = secp256k1::Message::from_slice(&sighash[..])?;
let mut signature = SECP.sign(&msg, &xpriv.private_key.key).serialize_der();
signature.push(0x01);
unsigned_tx.input[idx].witness = vec![signature, pubkey.to_bytes()];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment