-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested witness signing #1304
base: master
Are you sure you want to change the base?
Nested witness signing #1304
Conversation
fbef308
to
96b8929
Compare
@jcvernaleo (as per #1530)
|
any progress on this? |
@sunsiansong It seems the PR was lost in the backlog. I've added this to our internal review board to prioritize this. In the meantime, if you can help with reviewing and testing out this PR, that'd be very helpful! |
@afk11 If you could rebase your branch on the current master to run the CI checks and fix the outdated Glide stuff, that'd really get the ball rolling. |
Hi all Thanks for the ping. I know most apps got by without this feature, but did think it was worthwhile to bring everything up to date. I'll try rebase this in the next day or so. Re tests, I covered most nested forms of P2PK/P2PKH/multisig in P2SH, P2WSH, and nested P2WSH in P2SH with the results of each verified by the script interpreter. So I'm pretty confident it was working :) https://github.com/btcsuite/btcd/pull/1304/files#diff-c4fcde2c18ebe144b7b71b53efb1021c7bb089a8c02602134402999ca9fa1417R1436 I'll check in more depth later and report back |
7e89ed2
to
b6bcef2
Compare
Pull Request Test Coverage Report for Build 343822214
💛 - Coveralls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me but could you squash it to one commit please? That way you can give one coherent commit message (rather than if I squash from the github interface). But otherwise, great work.
b6bcef2
to
3aef94d
Compare
Squashed @jcvernaleo |
3aef94d
to
fb7974d
Compare
txscript/sign.go
Outdated
ScriptClass, []btcutil.Address, int, error) { | ||
// sign supports returning the scripts for script-hash types, as well | ||
// as returning a signature stack if the script was P2PK|P2PKH|multisig | ||
// P2WPKH is not handled here, but instead hints by the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: finish this comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated comment when squashing
builder.AddData(script) | ||
finalScript, _ := builder.Script() | ||
return finalScript | ||
return nil, errors.New("cannot merge " + ScriptHashTy.String() + " type") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should review the history behind this and see why so much was taken out
OK - mergeScripts is now used differently which explains it. It doesn't handle P2SH, or P2WSH because the caller adjusts their parameters based on the case.
I think a follow up PR could remove mergeScripts and just call mergeMultiSig directly if the default case isn't taken - it might not need to be there
if err != nil { | ||
return fmt.Errorf("failed to verify output %s: %v", msg, err) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding this section tests SignTxWitness in all the old tests (non-segwit cases)
@jcvernaleo @onyb anything else you'd like done on this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really good work on this!
I am submitting my first set of review comments. I haven't reviewed the unit-tests yet and would like to do another pass on SignTxWitness
.
In addition to my review comments, I have a general remark regarding your choice of using raw stacks instead of the script builder that we already have. I realize that it does give you some convenience in a few places, but it reduces readability and a bit unsafe (due to lack of validation, prone to programmer errors, etc.).
To understand the tradeoffs better, can you please add some GitHub review comments to SignTxWitness
function indicating the places where you felt that using the script builder was too inconvenient? Perhaps we can brainstorm together to come up with some helpers that make using script-builder less cumbersome?
subscript []byte, hashType SigHashType, | ||
privKey *btcec.PrivateKey, compress bool) (wire.TxWitness, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The wrapping is a bit weird. Line 50 is over 80 characters, so amt int64
could be moved to the next line.
// a nil pointer dereference. We require compress here to ensure segwit public | ||
// key encoding policy is followed | ||
func makeSignature(tx *wire.MsgTx, sigHashes *TxSigHashes, idx int, | ||
amt int64, subscript []byte, sigVersion int, hashType SigHashType, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we introduce an enum for sigVersion
? Here is the reference from Bitcoin Core.
// slices here, rather than a single byte slice. | ||
return wire.TxWitness{sig, pkData}, nil | ||
return wire.TxWitness(stack), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simply doing this should work too:
return wire.TxWitness(stack), nil | |
return stack, nil |
} | ||
return RawTxInWitnessSignature(tx, sigHashes, idx, amt, subscript, hashType, privKey) | ||
} | ||
return RawTxInSignature(tx, idx, subscript, hashType, privKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about wrapping this call around an if sigVersion == 0 {...}
, and returning an error for other values of sigVersion
.
stack := make([][]byte, 1) | ||
stack[0] = sig |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
stack := make([][]byte, 1) | |
stack[0] = sig | |
stack := [][]byte{sig} |
for i := 0; i < len(scriptStack); i++ { | ||
builder.AddData(scriptStack[i]) | ||
} | ||
if redeemScript != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: do not cuddle with the previous block
} | ||
|
||
// Build final scriptSig and witness | ||
builder := NewScriptBuilder() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: add new line after this statement
if redeemScript != nil { | ||
builder.AddData(redeemScript) | ||
} | ||
scriptSig, err := builder.Script() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: do not cuddle with the previous block
if err != nil { | ||
return nil, nil, err | ||
} | ||
if witnessScript != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: do not cuddle with the previous block
sigVersion = 1 | ||
witnessScript = stack[0] | ||
pkScript = stack[0] | ||
stack, class, addresses, nrequired, err = sign(chainParams, tx, sigHashes, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use a different variable instead of class
. Perhaps innerClass
?
This PR adds SignTxWitness which handles signing normal outputs + any that use segwit. It will return a signature script and witness structure after signing whatever it can and merging signatures. The function is a superset of what SignTxOutput supports. I left SignTxOutput's intact to preserve BC, though SignTxWitness also works with old outputs and should probably be used going forward for easy segwit support.
I went with using [][]byte to pass around input script data because it's easily converted back to a pushonly scriptSig, or can be used as a witness if called for.
Also added test cases comparable to SignTxOutput: