Closed calldata closed 5 years ago
@jayphbee What is your concrete usecase?
@thomaseizinger i'd like to sign a transaction offline use Transaction
object, but i found it is not convenient to accomplish. I have to construct ScriptSig myself and set it back to Transaction.TxIn.script, then serialize it.
@thomaseizinger i'd like to sign a transaction offline use
Transaction
object, but i found it is not convenient to accomplish. I have to construct ScriptSig myself and set it back to Transaction.TxIn.script, then serialize it.
@jayphbee Unfortunately, that is a very generic description and I can't help much with that :(
The reason I was asking was because we currently don't have any examples (examples/
folder) that explain how to do certain things with the library. I was gonna add some but without a concrete usecase, it is hard to guess what you are looking for. There is many different aspects when it comes to constructing a Transaction
:
The current interface allows for all of this and hence, can't be really opinionated towards a single one (it sounds like you are asking for a specific usecase since you mentioned lack of convenience).
What you described sounds right. If you want to manually sign a transaction, you need to set the inputs + outputs, serialize it and add the correct signature (from the input you are spending).
This is my way to build a p2pkh transaction with 2 inputs and 2 outputs
let raw_tx = Transaction {
version: 1,
lock_time: 0,
input: vec![TxIn {
previous_output: OutPoint::from_str("964b06c7d65bc2966ffc089be06469cf3961fdae4253cb51fe158bf1696882a1:1").unwrap(),
script_sig: Script::new(),
sequence: 0,
witness: vec![],
}, TxIn {
previous_output: OutPoint::from_str("6c1fd83338c12326e9160d57a95198937a228b6c4f55e882792be19fe2038da5:1").unwrap(),
script_sig: Script::new(),
sequence: 0,
witness: vec![],
}],
output: vec![TxOut {
value: 81243807,
script_pubkey: Script::from(decode("76a9145477d7bfe9bdf17cea9f5b2ecacc7a2577723c7488ac").unwrap()),
}, TxOut {
value: 100000,
script_pubkey: Script::from(decode("76a91402245e1265ca65f5ab6d70289f7bcfed6204810588ac").unwrap()),
}],
};
let sig_hash = raw_tx.signature_hash(0, &Script::from(decode("76a9145477d7bfe9bdf17cea9f5b2ecacc7a2577723c7488ac").unwrap()), 1);
let secp = Secp256k1::new();
let msg = Message::from_slice(&sig_hash.into_inner()).unwrap();
let sk = PrivateKey::from_wif("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").unwrap();
let pk = sk.public_key(&secp);
let mut sig = secp.sign(&msg, &sk.key).serialize_der();
sig.push(1); // sign hash type
let builder1 = Builder::new()
.push_slice(&sig)
.push_key(&pk);
// set the first input signature
raw_tx.input[0].script_sig = builder1.into_script();
let sig_hash2 = raw_tx.signature_hash(1, &Script::from(decode("76a9145477d7bfe9bdf17cea9f5b2ecacc7a2577723c7488ac").unwrap()), 1);
let msg2 = Message::from_slice(&sig_hash2.into_inner()).unwrap();
let mut sig2 = secp.sign(&msg2, &sk.key).serialize_der();
sig2.push(1); // sign hash type
println!("sig2: {:?}", encode(&sig2));
let builder2 = Builder::new()
.push_slice(&sig2)
.push_key(&pk);
// set the second input signature
raw_tx.input[1].script_sig = builder2.into_script();
let serialized = raw_tx.serialize();
println!("serialized: {:?}", serialized);
println!("txHash: {:?}", raw_tx.txid());
Is there a more high level api to do this ?
I'm thinking it might be worth it to have signing logic on the PSBT types. Like a single method try_sign
or something that takes a set of private keys (or hashmap of pubkey->privkey) and goes over all the psbt inputs signing if it can sign them.
But it's certainly worth it to wait for rust-miniscript to stabilize so that we can use miniscript for that. (@apoelstra)
Yeah, miniscript is the tool for this.
rust-miniscript will also have PSBT support
good to know that. Close this issue
Yeah, miniscript is the tool for this.
I needed to sign some transactions to send to a regtest bitcoind node for testing, and found this issue. Is rust-miniscript
the right approach for quick-and-dirty testing as well?
If you know the exact shape of your scriptSig
(or more likely, your witnessScript
) then you can just hack it together manually. The PSBT API in rust-bitcoin is much nicer now than when this issue was opened. In particular #957 will make your life easier.
But rust-miniscript is probably the easist thing to use in any case because it can produce generic witnesses, even for complex scripts, and will figure out the background "is this segwit or legacy or taproot or what" questions.
Just pushed some code I had laying around to GitHub for you :)
Tx creation: https://github.com/stevenroose/rust-bitcoin-wallet/blob/dcc4fc49225a4fd7fea1181a26cf2da0e78c83a8/src/wallet.rs#L268
Signing code in another project: https://github.com/Blockstream/gdk_rpc/blob/9dec80995c170d7fcd5a2aa875609b2e118f9cbc/src/wallet.rs#L361
(only does p2wpkh, but p2pkh is also possible)