Skip to content

Commit

Permalink
txscript: Optimize CalcSignatureHash.
Browse files Browse the repository at this point in the history
This modifies the CalcSignatureHash function to make use of the new
signature hash calculation function that accepts raw scripts without
needing to first parse them.  Consequently, it also doubles as a slight
optimization to the execution time and a significant reduction in the
number of allocations.

In order to convert the CalcScriptHash function and keep the same
semantics, a new function named checkScriptParses is introduced which
will quickly determine if a script can be fully parsed without failure
and return the parse failure in the case it can't.

The following is a before and after comparison of analyzing a large
multiple input transaction:

benchmark              old ns/op    new ns/op   delta
-------------------------------------------------------
BenchmarkCalcSigHash   2792057      2760042     -1.15%

benchmark              old allocs   new allocs  delta
-------------------------------------------------------
BenchmarkCalcSigHash   1691         1068        -36.84%

benchmark              old bytes    new bytes   delta
-------------------------------------------------------
BenchmarkCalcSigHash   521673       438604      -15.92%
  • Loading branch information
davecgh committed Mar 26, 2019
1 parent f306a72 commit c57dc2d
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 3 deletions.
9 changes: 9 additions & 0 deletions txscript/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,15 @@ func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int {
return getSigOpCount(shPops, true)
}

// checkScriptParses returns an error if the provided script fails to parse.
func checkScriptParses(scriptVersion uint16, script []byte) error {
tokenizer := MakeScriptTokenizer(scriptVersion, script)
for tokenizer.Next() {
// Nothing to do.
}
return tokenizer.Err()
}

// IsUnspendable returns whether the passed public key script is unspendable, or
// guaranteed to fail at execution. This allows inputs to be pruned instantly
// when entering the UTXO set. In Decred, all zero value outputs are unspendable.
Expand Down
10 changes: 7 additions & 3 deletions txscript/sighash.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,11 +460,15 @@ func calcSignatureHash(prevOutScript []parsedOpcode, hashType SigHashType, tx *w
// cached prefix parameter allows the caller to optimize the calculation by
// providing the prefix hash to be reused in the case of SigHashAll without the
// SigHashAnyOneCanPay flag set.
//
// NOTE: This function is only valid for version 0 scripts. Since the function
// does not accept a script version, the results are undefined for other script
// versions.
func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx int, cachedPrefix *chainhash.Hash) ([]byte, error) {
pops, err := parseScript(script)
if err != nil {
const scriptVersion = 0
if err := checkScriptParses(scriptVersion, script); err != nil {
return nil, err
}

return calcSignatureHash(pops, hashType, tx, idx, cachedPrefix)
return calcSignatureHashRaw(script, hashType, tx, idx, cachedPrefix)
}

0 comments on commit c57dc2d

Please sign in to comment.