Skip to content
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

txscript: backport tokenizer from dcrd #1684

Conversation

cfromknecht
Copy link
Contributor

@cfromknecht cfromknecht commented Feb 1, 2021

Dusting off this old branch... IIRC it should be mostly complete, there were a few edge cases around multisig parsing that I wanted to revisit. Happy to finish it up if people are interested in it.

This is a backport of decred/dcrd#1656 by @davecgh which converts
all script handling to use a combination of raw script analysis and a zero-allocation script tokenizer.
This vastly reduces the amount of memory and number of allocations performed during IBD, see
the original PR for the performance gains realized in dcrd. As a result, dcrd saw a 15% improvement
in IBD due to the reduction in CPU cycles spent performing GC.

TODO:

  • gather IBD profiles comparing master and this branch

Before and after benchmarks for various methods after converting to the
combination of raw script analysis + script tokenizer:

    benchmark                                       old ns/op     new ns/op     delta
    BenchmarkIsPayToScriptHash-8                    62393         0.51          -100.00%
    BenchmarkIsPubKeyHashScript-8                   62228         0.56          -100.00%
    BenchmarkGetSigOpCount-8                        61051         658           -98.92%
    BenchmarkExtractPkScriptAddrsLarge-8            60713         17.2          -99.97%
    BenchmarkExtractPkScriptAddrs-8                 289           17.9          -93.81%
    BenchmarkIsWitnessPubKeyHash-8                  61688         0.42          -100.00%
    BenchmarkIsUnspendable-8                        656           520           -20.73%
    BenchmarkExtractAtomicSwapDataPushesLarge-8     61332         44.0          -99.93%
    BenchmarkExtractAtomicSwapDataPushes-8          990           260           -73.74%
    BenchmarkDisasmString-8                         102902        39754         -61.37%
    BenchmarkGetPreciseSigOpCount-8                 130223        715           -99.45%
    BenchmarkScriptParsing-8                        63464         681           -98.93%
    BenchmarkIsMultisigScriptLarge-8                64166         5.83          -99.99%
    BenchmarkIsMultisigScript-8                     630           58.5          -90.71%
    BenchmarkPushedData-8                           64837         1779          -97.26%
    BenchmarkCalcSigHash-8                          3627895       3605459       -0.62%
    BenchmarkIsPubKeyScript-8                       62323         2.83          -100.00%
    BenchmarkIsPushOnlyScript-8                     62412         569           -99.09%
    BenchmarkIsWitnessScriptHash-8                  61243         0.56          -100.00%
    BenchmarkGetScriptClass-8                       61515         16.4          -99.97%
    BenchmarkIsNullDataScript-8                     62495         2.53          -100.00%
    BenchmarkIsMultisigSigScriptLarge-8             69328         2.52          -100.00%
    BenchmarkIsMultisigSigScript-8                  2375          141           -94.06%
    BenchmarkGetWitnessSigOpCountP2WKH-8            504           72.0          -85.71%
    BenchmarkGetWitnessSigOpCountNested-8           1158          136           -88.26%
    BenchmarkIsWitnessPubKeyHash-8                  68927         0.53          -100.00%
    BenchmarkIsWitnessScriptHash-8                  62774         0.63          -100.00%

    benchmark                                       old allocs     new allocs     delta
    BenchmarkIsPayToScriptHash-8                    1              0              -100.00%
    BenchmarkIsPubKeyHashScript-8                   1              0              -100.00%
    BenchmarkGetSigOpCount-8                        1              0              -100.00%
    BenchmarkExtractPkScriptAddrsLarge-8            1              0              -100.00%
    BenchmarkExtractPkScriptAddrs-8                 1              0              -100.00%
    BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
    BenchmarkIsUnspendable-8                        1              0              -100.00%
    BenchmarkExtractAtomicSwapDataPushesLarge-8     1              0              -100.00%
    BenchmarkExtractAtomicSwapDataPushes-8          2              1              -50.00%
    BenchmarkDisasmString-8                         46             51             +10.87%
    BenchmarkGetPreciseSigOpCount-8                 3              0              -100.00%
    BenchmarkScriptParsing-8                        1              0              -100.00%
    BenchmarkIsMultisigScriptLarge-8                1              0              -100.00%
    BenchmarkIsMultisigScript-8                     1              0              -100.00%
    BenchmarkPushedData-8                           7              6              -14.29%
    BenchmarkCalcSigHash-8                          1335           712            -46.67%
    BenchmarkIsPubKeyScript-8                       1              0              -100.00%
    BenchmarkIsPushOnlyScript-8                     1              0              -100.00%
    BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%
    BenchmarkGetScriptClass-8                       1              0              -100.00%
    BenchmarkIsNullDataScript-8                     1              0              -100.00%
    BenchmarkIsMultisigSigScriptLarge-8             5              0              -100.00%
    BenchmarkIsMultisigSigScript-8                  3              0              -100.00%
    BenchmarkGetWitnessSigOpCountP2WKH-8            2              0              -100.00%
    BenchmarkGetWitnessSigOpCountNested-8           4              0              -100.00%
    BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
    BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%

    benchmark                                       old bytes     new bytes     delta
    BenchmarkIsPayToScriptHash-8                    311299        0             -100.00%
    BenchmarkIsPubKeyHashScript-8                   311299        0             -100.00%
    BenchmarkGetSigOpCount-8                        311299        0             -100.00%
    BenchmarkExtractPkScriptAddrsLarge-8            311299        0             -100.00%
    BenchmarkExtractPkScriptAddrs-8                 768           0             -100.00%
    BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
    BenchmarkIsUnspendable-8                        1             0             -100.00%
    BenchmarkExtractAtomicSwapDataPushesLarge-8     311299        0             -100.00%
    BenchmarkExtractAtomicSwapDataPushes-8          3168          96            -96.97%
    BenchmarkDisasmString-8                         389324        130552        -66.47%
    BenchmarkGetPreciseSigOpCount-8                 623367        0             -100.00%
    BenchmarkScriptParsing-8                        311299        0             -100.00%
    BenchmarkIsMultisigScriptLarge-8                311299        0             -100.00%
    BenchmarkIsMultisigScript-8                     2304          0             -100.00%
    BenchmarkPushedData-8                           312816        1520          -99.51%
    BenchmarkCalcSigHash-8                          1373812       1290507       -6.06%
    BenchmarkIsPubKeyScript-8                       311299        0             -100.00%
    BenchmarkIsPushOnlyScript-8                     311299        0             -100.00%
    BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
    BenchmarkGetScriptClass-8                       311299        0             -100.00%
    BenchmarkIsNullDataScript-8                     311299        0             -100.00%
    BenchmarkIsMultisigSigScriptLarge-8             330035        0             -100.00%
    BenchmarkIsMultisigSigScript-8                  9472          0             -100.00%
    BenchmarkGetWitnessSigOpCountP2WKH-8            1408          0             -100.00%
    BenchmarkGetWitnessSigOpCountNested-8           3200          0             -100.00%
    BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
    BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%

Depends on #1689

@kcalvinalvin
Copy link
Collaborator

I... wish I saw this when I was working on #1685

@onyb
Copy link
Collaborator

onyb commented Feb 2, 2021

@cfromknecht Thanks for your PR! We recently merged #1615, which introduced some merge conflicts. Can you please resolve them and fix the edge cases around multisig parsing, so we're closer to having this merged?

@jcvernaleo
Copy link
Member

Generally speaking, we are super happy for decred backports! As the person who did most of the initial backporting of btcd stuff into decred (times really have changed now that backports got he other way :) ), I know how much of a pain it can be but it is super worth it to get those improvements.

@cfromknecht cfromknecht force-pushed the txscript_zero_alloc_optimization_refactor branch 2 times, most recently from f038748 to e4f8c4d Compare February 2, 2021 16:17
@cfromknecht
Copy link
Contributor Author

cfromknecht commented Feb 2, 2021

@onyb @jcvernaleo i've rebased on master to remove the merge conflicts. i'm currently going through each commit to check for compilation and resolve the remaining issues to make it ready for review

I... wish I saw this when I was working on #1685

@kcalvinalvin Haha yeah that's totally my fault for not pushing this up sooner and letting it sit on my fork... I have ~5 or so other optimization branches I should push up so they can at least be tracked

cfromknecht added a commit to cfromknecht/btcd that referenced this pull request Feb 2, 2021
TestHashCacheAddContainsHashes flakes fairly regularly when rebasing
PR btcsuite#1684 with:
    txid <txid> wasn't inserted into cache but was found.

With probabilty 1/10^2 there will be no inputs on the transaction. This
reduces the entropy in the txid, and I belive is the primary cause of
the flake.
@cfromknecht cfromknecht force-pushed the txscript_zero_alloc_optimization_refactor branch from e4f8c4d to 8db2852 Compare February 2, 2021 21:39
@cfromknecht
Copy link
Contributor Author

@onyb @jcvernaleo I went back and touched up all the commits so that each compiles and passes the unit test suite, here's the output:
https://paste.ubuntu.com/p/BRCBVnf2Qk/

In the process I kept hitting a flake in txscript/hashcache_test.go, so I opened #1689 to fix (and are now the first two commits of this PR).

In the meantime I'll start going through the commits again myself and double checking everything.

@cfromknecht
Copy link
Contributor Author

Also not noted here, but I already did ~10 or so sync tests on mainnet using this branch back in 2019. @Roasbeef and I will probably run a few more and gather some final benchmarks.

@coveralls
Copy link

coveralls commented Feb 3, 2021

Pull Request Test Coverage Report for Build 553429087

  • 904 of 1093 (82.71%) changed or added relevant lines in 8 files are covered.
  • 1877 unchanged lines in 12 files lost coverage.
  • Overall coverage decreased (-0.6%) to 52.81%

Changes Missing Coverage Covered Lines Changed/Added Lines %
txscript/tokenizer.go 82 87 94.25%
txscript/sign.go 59 67 88.06%
txscript/script.go 160 184 86.96%
txscript/engine.go 195 248 78.63%
txscript/standard.go 295 394 74.87%
Files with Coverage Reduction New Missed Lines %
connmgr/connmanager.go 1 86.79%
txscript/sign.go 1 74.73%
peer/peer.go 2 76.18%
txscript/pkscript.go 3 80.0%
txscript/script.go 6 88.82%
txscript/standard.go 7 78.05%
btcjson/jsonrpc.go 17 84.96%
btcec/signature.go 23 92.76%
integration/rpctest/rpc_harness.go 42 73.36%
rpcclient/infrastructure.go 430 0%
Totals Coverage Status
Change from base Build 535940167: -0.6%
Covered Lines: 20984
Relevant Lines: 39735

💛 - Coveralls

@cfromknecht cfromknecht force-pushed the txscript_zero_alloc_optimization_refactor branch from 8db2852 to 827c3d7 Compare February 3, 2021 03:09
@cfromknecht
Copy link
Contributor Author

cfromknecht commented Feb 3, 2021

I went through each commit and reran the before and after benchmarks where applicable, as well as adding a total comparison in the final commit message showing the difference between when the benchmark was added and the final commit. I updated the PR body with the current benchmarks

@Roasbeef
Copy link
Member

Roasbeef commented Feb 4, 2021

@Roasbeef and I will probably run a few more and gather some final benchmarks.

Yep, I'm switching over one of my mainnet nodes to run this patch now.

@onyb
Copy link
Collaborator

onyb commented Feb 4, 2021

Not a blocker, but #1304 is touching the txscript/sign.go file. Although I don't think the other PR will make it to master before this one.

@onyb
Copy link
Collaborator

onyb commented Feb 5, 2021

Review progress tracker

▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 100 %

  • c5a193f txscript: Add benchmark for CalcSignatureHash
  • d683492 txscript: Add benchmark for CalcWitnessSigHash
  • a93ee39 txscript: Add benchmark for script parsing.
  • fff82cf txscript: Introduce zero-alloc script tokenizer.
  • cce880c txscript: Add benchmark for DisasmString.
  • 1762107 txscript: Optimize script disasm.
  • 04ed404 txscript: Introduce raw script sighash calc func.
  • bcbf950 txscript: Optimize CalcSignatureHash.
  • 54fda7d txscript/reference_test: Convert sighash calc test
  • b4abc15 txscript: Make isSmallInt accept raw opcode.
  • cd6f1f9 txscript: Make asSmallInt accept raw opcode.
  • 9846914 txscript: Add benchmark for IsPayToPubKey
  • 8ceea24 txscript: Optimize IsPayToPubKey
  • dff834b txscript: Add benchmark for IsPayToPubKeyHash
  • e51d50a txscript: Optimize IsPayToPubKeyHash
  • f75b1e2 txscript: Add benchmark for IsPayToScriptHash.
  • ff0fc4c txscript: Optimize IsPayToScriptHash.
  • 086b4f1 txscript: Add benchmarks for IsMutlsigScript.
  • e0b8ade txscript: Optimize IsMultisigScript.
  • d64dbbb txscript: Add benchmarks for IsMutlsigSigScript.
  • 3cfdeca txscript: Optimize IsMultisigSigScript.
  • 1f2afc1 txscript: Add benchmark for IsPushOnlyScript.
  • 29dcb83 txscript: Optimize IsPushOnlyScript.
  • c1d1b0e txscript: Add benchmark IsPayToWitnessPubkeyHash
  • 344636f txscript: Optimize IsPayToWitnessPubKeyHash
  • 58a2fa9 txscript: Add benchmark for IsPayToWitnessScriptHash
  • 5b69223 txscript: Optimize IsPayToWitnessScriptHash
  • 0ccd702 txscript: Add benchmark for IsNullData
  • eda642a txscript: Optimize IsNullData
  • 75b614c txscript: Add benchmark for IsUnspendable.
  • 6635382 txscript: Optimize IsUnspendable.
  • e726274 txscript/engine: Optimize new engine push only script
  • 2f4de13 txscript/engine: Use optimized IsPushOnlyScript
  • f676d32 txscript/engine: Use optimized isScriptHashScript
  • 3d352cd txscript/engine: Check ps2h push before parsing script
  • 564681c txscript: Add benchmark for GetSigOpCount.
  • 43624d9 txscript: Optimize GetSigOpCount.
  • 86f5907 txscript: Add benchmark for GetPreciseSigOpCount.
  • c747cc5 txscript: Optimize GetPreciseSigOpCount.
  • 931aab2 txscript: add GetWitnessSigOpCountBenchmarks
  • f3185ee txscript: Optimize GetWitnessSigOpCount
  • ca395fe txscript: Add benchmark for GetScriptClass.
  • e9d7686 txscript: Make typeOfScript accept raw script.
  • 5161238 txscript: Optimize typeOfScript pay-to-script-hash.
  • f4b4bfa txscript: Remove unused isScriptHash function.
  • b1a191a txscript: Optimize typeOfScript multisig.
  • b76572d txscript: Remove unused isMultiSig function.
  • d8e3a4a txscript: Optimze typeOfScript pay-to-pubkey
  • d165f48 txscript: Remove unused isPubkey function.
  • fe80899 txscript: Optimize typeOfScript pay-to-pubkey-hash.
  • bf287f5 txscript: Remove unused isPubkeyHash function.
  • 612f05c txscript: Optimize typeOfScript for null data scripts
  • ddffa50 txscript: Remove unused isNullData function.
  • 7a471e0 txscript: Optimize typeOfScript witness-pubkey-hash
  • 7f10c29 txscript: Optimize typeOfScript for witness-script-hash
  • 7032bd5 txscript: Remove unused isWitnessScriptHash
  • 5c97e22 txscript: Convert CalcScriptInfo.
  • b933306 txscript: Remove unused isPushOnly function.
  • fae615d txscript: Remove unused getSigOpCount function.
  • 1df85f4 txscript: Optimize CalcMultiSigStats.
  • 5079460 txscript: Add benchmark for PushedData.
  • d88103e txscript: Optimize PushedData.
  • be38621 txscript: Make canonicalPush accept raw opcode.
  • 7e6b84c txscript: Add ExtractAtomicSwapDataPushes benches.
  • ba0c48b txscript/scriptnum: add maxscriptnum and maxcltvlength
  • bf39ad7 txscript: Optimize ExtractAtomicSwapDataPushes.
  • 3b8712d txscript: Add ExtractPkScriptAddrs benchmarks.
  • 1adafa3 txscript: Optimize ExtractPkScriptAddrs scripthash.
  • 7aaa28a txscript: Optimize ExtractPkScriptAddrs pubkeyhash.
  • 76a2d2b txscript: Optimize ExtractPkScriptAddrs pubkey.
  • 05388db txscript: Optimize ExtractPkScriptAddrs multisig.
  • 5f9581d txscript: Optimize ExtractPkScriptAddrs nulldata.
  • 57bef04 txscript: Optimize ExtractPkScriptAddrs witness pubkey hash
  • d17add5 txscript: Optimize ExtractPkScriptAddrs witness script hash
  • c1f8d30 txscript: Optimize ExtractPkScriptAddr assume non-standard if no success
  • cbc3a2e txscript: Optimize IsWitnessProgram
  • 6702a2b txscript: Return witness version and program in one pass
  • f0b3095 txscript: Use internal analysis methods for GetWitnessSigOpCount
  • 5c56138 txscript: Optimize ExtractWitnessProgramInfo
  • 8170896 txscript: mergeMultiSig function def order cleanup.
  • b280be1 txscript: Introduce calcWitnessSignatureHashRaw
  • bfc2a3e txscript: Remove unused isWitnessPubKeyHash
  • 5aa00f7 txscript: Use optimized calcWitnessSignatureHashRaw w/o parsing
  • 01f8aec txscript: Use raw scripts in SignTxOutput.
  • 1200b05 txscript: Implement efficient opcode data removal.
  • 897c0ec txscript: Optimize removeOpcodeRaw
  • 3337741 txscript: Remove unused removeOpcode
  • 9351643 txscript: Use removeOpcodeRaw for CODESEP in calcSigHash
  • a3d3df3 txscript: Make isDisabled accept raw opcode.
  • 6bdd5c0 txscript: Make alwaysIllegal accept raw opcode.
  • 84bf89a txscript: Make isConditional accept raw opcode.
  • f2ab844 txscript: Make min push accept raw opcode and data.
  • 2258e94 txscript: Convert to use non-parsed opcode disasm.
  • 3f1788f txscript: Refactor engine to use raw scripts.
  • 215269d txscript: Remove unused calcSignatureHash
  • 4091cd0 txscript: Remove unused isWitnessProgram
  • 79d106e txscript: Remove unused removeOpcodeByData func.
  • afa1d5a txscript: Rename removeOpcodeByDataRaw func.
  • 97a1f61 txscript: Rename calcSignatureHashRaw
  • 1442714 txscript/sign: Use calcWitnessSigHashRaw for witness sigs
  • 83375f1 txscript/pkscript: Use finalOpcodeData to extract redeem script
  • 1b571f6 txscript: Remove unused parseScript func.
  • 11f1857 txscript: Remove unused calcWitnessSignatureHash
  • d16fd9f txscript: Remove unused unparseScript func.
  • f535e04 txscript: Remove unused parsedOpcode.bytes func.
  • 56c26d1 txscript: Remove unused parseScriptTemplate func.
  • 1cdaaf3 txscript: Make executeOpcode take opcode and data.
  • 398da74 txscript: Make op callbacks take opcode and data.

Note: Using this mostly for my own reference, but also gives a good idea to others how the review is progressing.

@cfromknecht
Copy link
Contributor Author

cfromknecht commented Feb 5, 2021

Thanks @onyb! I’m currently working on restructuring some of the commits, e.g. some of the witness related refactoring can be moved into more logical spots. So some of the commits in the latter half might get split/moved up. I think reviewers will find it easier to digest that way. Pretty close to finishing that as well as adding some more benchmarks.

If you give me until tomorrow I can get it to a place where (I hope) is more stable for review. The contents of the commits shouldn’t change to much though if you want to familiarize yourself with the diffs :)

@onyb
Copy link
Collaborator

onyb commented Feb 5, 2021

@cfromknecht No worries, you can go ahead with the refactoring. It seems there won't be too many logical changes to do anyway. 👍

I'm looking forward to your benchmarks. Something like the graphs in decred/dcrd#1656 would be pretty cool. I am currently syncing testnet3 with this branch. Will report back the IBD time once finished.

@onyb
Copy link
Collaborator

onyb commented Feb 5, 2021

I'm seeing a ~20% speedup in IBD on testnet3.

Benchmark

Branch IBD time
master 7h 18m
#1684 5h 53m

System specifications

Component Info
OS Mac OS BigSur
Processor 2.7 GHz Quad-Core Intel Core i7
Memory 16 GB 2133 MHz LPDDR3
Disk SSD (NVMe)
Internet connection 70 Mbps

davecgh and others added 6 commits February 5, 2021 01:47
This implements an efficient and zero-allocation script tokenizer that
is exported to both provide a new capability to tokenize scripts to
external consumers of the API as well as to serve as a base for
refactoring the existing highly inefficient internal code.

It is important to note that this tokenizer is intended to be used in
consensus critical code in the future, so it must exactly follow the
existing semantics.

The current script parsing mechanism used throughout the txscript module
is to fully tokenize the scripts into an array of internal parsed
opcodes which are then examined and passed around in order to implement
virtually everything related to scripts.

While that approach does simplify the analysis of certain scripts and
thus provide some nice properties in that regard, it is both extremely
inefficient in many cases, and makes it impossible for external
consumers of the API to implement any form of custom script analysis
without manually implementing a bunch of error prone tokenizing code or,
alternatively, the script engine exposing internal structures.

For example, as shown by profiling the total memory allocations of an
initial sync, the existing script parsing code allocates a total of
around 295.12GB, which equates to around 50% of all allocations
performed.  The zero-alloc tokenizer this introduces will allow that to
be reduced to virtually zero.

The following is a before and after comparison of tokenizing a large
script with a high opcode count using the existing code versus the
tokenizer this introduces for both speed and memory allocations:

benchmark                    old ns/op     new ns/op     delta
BenchmarkScriptParsing-8     63464         677           -98.93%

benchmark                    old allocs     new allocs     delta
BenchmarkScriptParsing-8     1              0              -100.00%

benchmark                    old bytes     new bytes     delta
BenchmarkScriptParsing-8     311299        0             -100.00%

The following is an overview of the changes:

- Introduce new error code ErrUnsupportedScriptVersion
- Implement zero-allocation script tokenizer
- Add a full suite of tests to ensure the tokenizer works as intended
  and follows the required consensus semantics
- Add an example of using the new tokenizer to count the number of
  opcodes in a script
- Update README.md to include the new example
- Update script parsing benchmark to use the new tokenizer
This converts the DisasmString function to make use of the new
zero-allocation script tokenizer instead of the far less efficient
parseScript thereby significantly optimizing the function.

In order to facilitate this, the opcode disassembly functionality is
split into a separate function called disasmOpcode that accepts the
opcode struct and data independently as opposed to requiring a parsed
opcode.  The new function also accepts a pointer to a string builder so
the disassembly can be more efficiently be built.

While here, the comment is modified to explicitly call out the script
version semantics.

The following is a before and after comparison of a large script:

benchmark                   old ns/op     new ns/op     delta
BenchmarkDisasmString-8     102902        40124         -61.01%

benchmark                   old allocs     new allocs     delta
BenchmarkDisasmString-8     46             51             +10.87%

benchmark                   old bytes     new bytes     delta
BenchmarkDisasmString-8     389324        130552        -66.47%
Also remove tests associated with the func accordingly.
This converts the executeOpcode function defined on the engine to accept
an opcode and data slice instead of a parsed opcode as a step towards
removing the parsed opcode struct and associated supporting code altogether.

It also updates all callers accordingly.
@cfromknecht cfromknecht force-pushed the txscript_zero_alloc_optimization_refactor branch from 827c3d7 to 3b37866 Compare February 5, 2021 17:58
This converts the callback function defined on the internal opcode
struct to accept the opcode and data slice instead of a parsed opcode as
the final step towards removing the parsed opcode struct and associated
supporting code altogether.

It also updates all of the callbacks and tests accordingly and finally
removes the now unused parsedOpcode struct.

The final results for the raw script analysis and tokenizer
optimizations are as follows:

benchmark                                       old ns/op     new ns/op     delta
BenchmarkIsPayToScriptHash-8                    62393         0.51          -100.00%
BenchmarkIsPubKeyHashScript-8                   62228         0.56          -100.00%
BenchmarkGetSigOpCount-8                        61051         658           -98.92%
BenchmarkExtractPkScriptAddrsLarge-8            60713         17.2          -99.97%
BenchmarkExtractPkScriptAddrs-8                 289           17.9          -93.81%
BenchmarkIsWitnessPubKeyHash-8                  61688         0.42          -100.00%
BenchmarkIsUnspendable-8                        656           520           -20.73%
BenchmarkExtractAtomicSwapDataPushesLarge-8     61332         44.0          -99.93%
BenchmarkExtractAtomicSwapDataPushes-8          990           260           -73.74%
BenchmarkDisasmString-8                         102902        39754         -61.37%
BenchmarkGetPreciseSigOpCount-8                 130223        715           -99.45%
BenchmarkScriptParsing-8                        63464         681           -98.93%
BenchmarkIsMultisigScriptLarge-8                64166         5.83          -99.99%
BenchmarkIsMultisigScript-8                     630           58.5          -90.71%
BenchmarkPushedData-8                           64837         1779          -97.26%
BenchmarkCalcSigHash-8                          3627895       3605459       -0.62%
BenchmarkIsPubKeyScript-8                       62323         2.83          -100.00%
BenchmarkIsPushOnlyScript-8                     62412         569           -99.09%
BenchmarkIsWitnessScriptHash-8                  61243         0.56          -100.00%
BenchmarkGetScriptClass-8                       61515         16.4          -99.97%
BenchmarkIsNullDataScript-8                     62495         2.53          -100.00%
BenchmarkIsMultisigSigScriptLarge-8             69328         2.52          -100.00%
BenchmarkIsMultisigSigScript-8                  2375          141           -94.06%
BenchmarkGetWitnessSigOpCountP2WKH-8            504           72.0          -85.71%
BenchmarkGetWitnessSigOpCountNested-8           1158          136           -88.26%
BenchmarkIsWitnessPubKeyHash-8                  68927         0.53          -100.00%
BenchmarkIsWitnessScriptHash-8                  62774         0.63          -100.00%

benchmark                                       old allocs     new allocs     delta
BenchmarkIsPayToScriptHash-8                    1              0              -100.00%
BenchmarkIsPubKeyHashScript-8                   1              0              -100.00%
BenchmarkGetSigOpCount-8                        1              0              -100.00%
BenchmarkExtractPkScriptAddrsLarge-8            1              0              -100.00%
BenchmarkExtractPkScriptAddrs-8                 1              0              -100.00%
BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
BenchmarkIsUnspendable-8                        1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushesLarge-8     1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          2              1              -50.00%
BenchmarkDisasmString-8                         46             51             +10.87%
BenchmarkGetPreciseSigOpCount-8                 3              0              -100.00%
BenchmarkScriptParsing-8                        1              0              -100.00%
BenchmarkIsMultisigScriptLarge-8                1              0              -100.00%
BenchmarkIsMultisigScript-8                     1              0              -100.00%
BenchmarkPushedData-8                           7              6              -14.29%
BenchmarkCalcSigHash-8                          1335           712            -46.67%
BenchmarkIsPubKeyScript-8                       1              0              -100.00%
BenchmarkIsPushOnlyScript-8                     1              0              -100.00%
BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%
BenchmarkGetScriptClass-8                       1              0              -100.00%
BenchmarkIsNullDataScript-8                     1              0              -100.00%
BenchmarkIsMultisigSigScriptLarge-8             5              0              -100.00%
BenchmarkIsMultisigSigScript-8                  3              0              -100.00%
BenchmarkGetWitnessSigOpCountP2WKH-8            2              0              -100.00%
BenchmarkGetWitnessSigOpCountNested-8           4              0              -100.00%
BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%

benchmark                                       old bytes     new bytes     delta
BenchmarkIsPayToScriptHash-8                    311299        0             -100.00%
BenchmarkIsPubKeyHashScript-8                   311299        0             -100.00%
BenchmarkGetSigOpCount-8                        311299        0             -100.00%
BenchmarkExtractPkScriptAddrsLarge-8            311299        0             -100.00%
BenchmarkExtractPkScriptAddrs-8                 768           0             -100.00%
BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
BenchmarkIsUnspendable-8                        1             0             -100.00%
BenchmarkExtractAtomicSwapDataPushesLarge-8     311299        0             -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          3168          96            -96.97%
BenchmarkDisasmString-8                         389324        130552        -66.47%
BenchmarkGetPreciseSigOpCount-8                 623367        0             -100.00%
BenchmarkScriptParsing-8                        311299        0             -100.00%
BenchmarkIsMultisigScriptLarge-8                311299        0             -100.00%
BenchmarkIsMultisigScript-8                     2304          0             -100.00%
BenchmarkPushedData-8                           312816        1520          -99.51%
BenchmarkCalcSigHash-8                          1373812       1290507       -6.06%
BenchmarkIsPubKeyScript-8                       311299        0             -100.00%
BenchmarkIsPushOnlyScript-8                     311299        0             -100.00%
BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
BenchmarkGetScriptClass-8                       311299        0             -100.00%
BenchmarkIsNullDataScript-8                     311299        0             -100.00%
BenchmarkIsMultisigSigScriptLarge-8             330035        0             -100.00%
BenchmarkIsMultisigSigScript-8                  9472          0             -100.00%
BenchmarkGetWitnessSigOpCountP2WKH-8            1408          0             -100.00%
BenchmarkGetWitnessSigOpCountNested-8           3200          0             -100.00%
BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
@cfromknecht cfromknecht force-pushed the txscript_zero_alloc_optimization_refactor branch from 3b37866 to 398da74 Compare February 5, 2021 17:58
@cfromknecht
Copy link
Contributor Author

@onyb new version is up, the commits should be more coherent/uniform now.

I also added a few benchmarks for: BenchmarkGetWitnessSigOpCountP2WKH, BenchmarkGetWitnessSigOpCountNested, BenchmarkIsWitnessPubKeyHash, and BenchmarkIsWitnessScriptHash. The WitnessSigOpCount benchmarks are slightly underrepresentative, since by the time the benchmark is added they are already using optimized variants of IsPushOnlyScript, IsPayToWitnessPubKeyHash, and IsPayToWitnessScriptHash. However it should be easy to move that commit up and capture a better view of the total performance gain down the road.

Log of all commits passing the test suite: https://paste.ubuntu.com/p/qdYwDHpb3p/

Copy link
Collaborator

@onyb onyb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have covered 60% of the commits in my review. Submitting whatever comments I have so far.

txscript/script.go Outdated Show resolved Hide resolved
txscript/reference_test.go Outdated Show resolved Hide resolved
pops, _ := parseScript(scriptPubKey)

// Treat non P2SH transactions as normal.
if !(bip16 && isScriptHash(pops)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs an explanation somewhere why bip16 is not used anymore.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were no prior instances where GetPreciseSigOpCount was called with the final argument being false. The new diff now checks isScriptHashScript directly. If it's p2sh, then we'll also examine the sigScript for the final push which contains the script itself.

}
return script, nil
return tokenizer.Err() == nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider an empty script as push-only?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this retains the existing behavior in isPushOnly. You can see similar behavior enforced in bitcoind here: https://github.com/bitcoin/bitcoin/blob/4a540683ec40393d6369da1a9e02e45614db936d/src/script/script.cpp#L250

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is usually used to enforce that the sigScript for a p2sh or nested p2wsh only contains push data op codes. If a sigScript attempts to spend one of these outputs with a blank script, then execution should fail in both scenarios, but it wouldn't explicitly violate the push only requirement.

txscript/standard.go Outdated Show resolved Hide resolved
txscript/standard.go Show resolved Hide resolved
txscript/standard.go Show resolved Hide resolved
txscript/standard.go Show resolved Hide resolved
if len(script) == 35 &&
script[34] == OP_CHECKSIG &&
script[0] == OP_DATA_33 &&
(script[1] == 0x02 || script[1] == 0x03) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great that the new version of the parser is a lot stricter than the one in isPubkey. Not for this PR, but we should think about unit-tests to exercise all these conditions.

// versions.
//
// The error is DEPRECATED and will be removed in the major version bump.
func IsMultisigScript(script []byte) (bool, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test for the "zero pubkeys" case? You can add it to the existing benchmark test, or create a new unit test function.

@onyb
Copy link
Collaborator

onyb commented Feb 6, 2021

@cfromknecht IBD benchmark with #1426:

ibd

@onyb onyb added this to Pending reviews in btcd-dev Feb 9, 2021
@cfromknecht
Copy link
Contributor Author

@onyb great comments, I pushed fixups for most of them. The ones left are:

Needs an explanation somewhere why bip16 is not used anymore.

I think perhaps this is a bug, but I will need to go through the call sites to be sure.

Should we consider an empty script as push-only?

I believe we do in this case, this also matches the behavior in the prior isPushOnly function removed in b933306.

It's great that the new version of the parser is a lot stricter than the one in isPubkey. Not for this PR, but we should think about unit-tests to exercise all these conditions.

Certainly, I'd be happy to do so!

Can you add a test for the "zero pubkeys" case? You can add it to the existing benchmark test, or create a new unit test function.

Sure thing I will have that up in the next set of fixups!

Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checkpointing my review here at: 3f1788f

Amazing work with this monster of a back port!

txscript/README.md Show resolved Hide resolved
const scriptVersion = 0
tokenizer := MakeScriptTokenizer(scriptVersion, sigScript)
var prevOffset int32
for tokenizer.Next() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self to verify this change independently on my end.

}
return script, nil
return tokenizer.Err() == nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this retains the existing behavior in isPushOnly. You can see similar behavior enforced in bitcoind here: https://github.com/bitcoin/bitcoin/blob/4a540683ec40393d6369da1a9e02e45614db936d/src/script/script.cpp#L250

}
return script, nil
return tokenizer.Err() == nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is usually used to enforce that the sigScript for a p2sh or nested p2wsh only contains push data op codes. If a sigScript attempts to spend one of these outputs with a blank script, then execution should fail in both scenarios, but it wouldn't explicitly violate the push only requirement.

pops, _ := parseScript(scriptPubKey)

// Treat non P2SH transactions as normal.
if !(bip16 && isScriptHash(pops)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were no prior instances where GetPreciseSigOpCount was called with the final argument being false. The new diff now checks isScriptHashScript directly. If it's p2sh, then we'll also examine the sigScript for the final push which contains the script itself.

txscript/script.go Show resolved Hide resolved
txscript/script.go Show resolved Hide resolved
txscript/script.go Show resolved Hide resolved
@Roasbeef
Copy link
Member

Kicking off a mainnet sync with this branch later today.

Copy link
Collaborator

@onyb onyb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally had the chance to come back to this PR and finish reviewing it. I've added some last comments, but apart from that, it looks ready to go in! Going to pre-approve this PR, since the outstanding review comments are minor. 🚀

@Roasbeef There are two commits that'd particularly benefit from a careful pass by you since it's consensus critical code:

  • the zero-alloc tokenizer itself ➞ fff82cf
  • changes to the txscript engine ➞ 3f1788f

As previously mentioned, I've already tested this PR against testnet3 and noticed a 20% speedup with no stability issues. I'm going to do the same for mainnet, but it might take me a while to obtain the results. Should be fine; I got 5G. 😎

txscript/script.go Show resolved Hide resolved
Comment on lines +919 to +942
// Check for pay-to-pubkey script.
if data := extractPubKey(pkScript); data != nil {
var addrs []btcutil.Address
addr, err := btcutil.NewAddressPubKey(data, chainParams)
if err == nil {
addrs = append(addrs, addr)
}
return PubKeyTy, addrs, 1, nil
}

case PubKeyTy:
// A pay-to-pubkey script is of the form:
// <pubkey> OP_CHECKSIG
// Therefore the pubkey is the first item on the stack.
// Skip the pubkey if it's invalid for some reason.
requiredSigs = 1
addr, err := btcutil.NewAddressPubKey(pops[0].data, chainParams)
if err == nil {
addrs = append(addrs, addr)
// Check for multi-signature script.
const scriptVersion = 0
details := extractMultisigScriptDetails(scriptVersion, pkScript, true)
if details.valid {
// Convert the public keys while skipping any that are invalid.
addrs := make([]btcutil.Address, 0, len(details.pubKeys))
for _, pubkey := range details.pubKeys {
addr, err := btcutil.NewAddressPubKey(pubkey, chainParams)
if err == nil {
addrs = append(addrs, addr)
}
}
return MultiSigTy, addrs, details.requiredSigs, nil
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if it makes sense to have a function like pubKeyToAddrs, just like pubKeyHashToAddrs, and scriptHashToAddrs. It could also be reused for the multi-sig part.

Comment on lines +931 to +932
details := extractMultisigScriptDetails(scriptVersion, pkScript, true)
if details.valid {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: could be a one-line:

Suggested change
details := extractMultisigScriptDetails(scriptVersion, pkScript, true)
if details.valid {
if details := extractMultisigScriptDetails(scriptVersion, pkScript, true); details.valid {

txscript/standard.go Show resolved Hide resolved
txscript/engine.go Show resolved Hide resolved
txscript/script.go Show resolved Hide resolved
return nil
}

// Ensure all executed data push opcodes use the minimal encoding when
// the minimal data verification flag is set.
if vm.dstack.verifyMinimalData && vm.isBranchExecuting() &&
pop.opcode.value >= 0 && pop.opcode.value <= OP_PUSHDATA4 {
op.value >= 0 && op.value <= OP_PUSHDATA4 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two remarks:

  • Perhaps it's better to use op.value >= OP_0 instead of op.value >= 0.
  • Isn't op.value always >= 0, by virtue of being a byte?

// covering 1 through 16 pubkeys, which means this will count any
// more than that value (e.g. 17, 18 19) as the maximum number of
// allowed pubkeys. This is, unfortunately, now part of
// the Bitcion consensus rules, due to historical
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Suggested change
// the Bitcion consensus rules, due to historical
// the Bitcoin consensus rules, due to historical

@onyb
Copy link
Collaborator

onyb commented Jun 2, 2021

@cfromknecht Just checking if you got the chance to finish up the last few things in this PR. Is there anything I can help you with?

marni pushed a commit to decfi/btcd that referenced this pull request Oct 5, 2021
* Improve error message about non-active segwit on simnet

I started playing with simnet and was confronted with error message:

```
[ERR] FNDG: Unable to broadcast funding tx for ChannelPoint(<point>:0):
-22: TX rejected: transaction <tx> has witness data, but segwit isn't active yet
```

I wasn't aware of the activation period so I got quite puzzled.
Google helped. But I think the message could mention likely cause.

Newly it optionally prints something like:

```
(The threshold for segwit activation is 300 blocks on simnet, current best height is 113)
```

* btcctl: add regtest mode to btcctl

* build: replace travis-ci with github actions.

test go 1.14
use golangci-lint

* build: update deps

* build: clean linter warnings

* btcjson: change getblock default verbosity to 1

This change makes btcd's getblock command match bitcoind's. Previously
the default verbosity was 0, which caused errors when using the
rpcclient library to connect to a bitcoind node - getblock would
unmarshall incorrectly since it didn't expect a verbosity=1 result when
it did not specify verbosity.

* rpcclient: send legacy GetBlock request for backwards compatibility

Without this, users of this library wouldn't be able to issue GetBlock
requests to nodes which haven't updated to support the latest request
format, namely the use of a single `int` parameter to denote verbosity
instead of two `bool`s.

* rpcclient: Add cookie auth

Based on Hugo Landau's cookie auth implementation for Namecoin's ncdns.

Fixes btcsuite#1054

* rpcclient: Refactor cookie caching

* rpcclient: Try user+pass auth before cookie auth

* rpcclient: Read first line of cookie instead of trimming space

* rpcclient: serialize nil inputs to empty list

* Improve chain state init efficiency

Remove unnecessary slice of all block indexes and
remove DB iteration over all block indexes that
used to determined the size of the slice.

* Add blockchain.NewUtxoEntry() to directly create entries for UtxoViewpoint

The current methods to add to a UtxoViewpoint don't allow for a situation where
we have only UTXO data but not a whole transaction.  This commit allows
contstruction of a UtxoEntry without requiring a full MsgTx.

AddTxOut() and AddTxOuts() both require a whole transaction, including the inputs,
which are only used in order to calculate the txid.  In some situations, such as
with use of the utreexo accumulator, we only have the utxo data but not the
transaction which created it.

For reference, utreexo's initial usage of the blockchain.NewUtxoEntry() function is at
https://github.com/mit-dci/utreexo/pull/135/files#diff-3f7b8f9991ea957f1f4ad9f5a95415f0R96

* Add getchaintxstats JSON-RPC client command

* Add fundrawtransaction RPC call

* Add getbalances RPC client command

* rpcclient: Add GetTransactionWatchOnly method

* peer: knownInventory, sentNonces - use generic lru

While here, also rename and generalize limitMap and apply to
other maps which need to be bounded.

* btcec: Avoid panic in fieldVal.SetByteSlice for large inputs

The implementation has been adapted from the dcrec module in dcrd. The
bug was initially fixed in decred/dcrd@3d9cda1 while transitioning to a
constant time algorithm. A large set of test vectors were subsequently
added in decred/dcrd@8c6b52d.

The function signature has been preserved for backwards compatibility.
This means that returning whether the value has overflowed, and the
corresponding test vectors have not been backported.

This fixes btcsuite#1170 and closes a previous attempt to fix the bug in btcsuite#1178.

* config+service_windows: add flag to disable win service

To run integration tests with btcd on Windows in non-interactive
environments (such as the Travis build with Windows machines), we
need to make sure we can still spawn a child process instead of only a
windows background service.

* updated docs for getblock-verbosity fixes

* Update json_rpc_api.md

Corrections suggested by @onyb btcsuite#1608 (comment)

* netsync: handle notfound messages from peers

backport from decred/dcrd#2253

When a peer sends a notfound message, remove the hash from requested
map.  Also increase notfound ban score and return early if it
disconnects the peer.

* release: update release script path

* release: remove old scripts and update process doc

- remove prep_release.sh and notes.sample
- update license in release.sh
- add notes for maintainers on the release process
- mention CHANGES file modifications

* Update CHANGES file for 0.21.0 release

Also updated changes for 0.20.1, and added a small note about changes
since 0.12.0.

* btcd: bump version to v0.21.0-beta

* blockchain: remove unknown block version warning

* Add rpclient implementation of getdescriptorinfo RPC

* peer: prevent last block height going backwards

This modifies the UpdateLastBlockHeight function to ensure the new
height is after the existing height before updating it in order to
prevent it from going backwards so it properly matches the intent of the
function which is to report the latest known block height for the peer.

Without this change, the value will properly start out at the latest
known block height reported by the peer during version negotiation,
however, it will be set to lower values when syncing from the peer due
to requesting old blocks and blindly updating the height.

It also adds a test to ensure proper functionality.

This is a backport of decred/dcrd#1747

* Fix monetary unit

* rpcserver: add parity with bitcoind for validateaddress

Updated the rpcserver handler for validateaddress JSON-RPC command to
have parity with the bitcoind 0.20.0 interface.

The new fields included are - isscript, iswitness, witness_version, and
witness_program. The scriptPubKey field has been left out since it
requires wallet access.

This update has no impact on the rpcclient.ValidateAddress method,
which uses the btcjson.ValidateAddressWalletResult type for modelling
the response from bitcoind.

* Add getblockfilter JSON-RPC client command

Add type for second getblockfilter param

* Implement signmessagewithprivkey JSON-RPC command

Reuse the Bitcoin message signature header const
also in verifymessage.

* rpcclient: Implement importmulti JSON-RPC client command

* Add Dockerfile to build and run btcd on Docker.

* btcd: fix conversion of int to string failing in Go 1.15

* btcjson,wire: fix invalid use of string(x) to convert byte value

* Major rework on documentation to make it compatible to readthedocs.org

* Added symlink to index.md for github readme preview.

* btcd+netsync: support witness tx and block in notfound msg

* btcec: set curve name in CurveParams

Set curve name(secp256k1) in KoblitzCurve.CurveParams

Fixes btcsuite#1564

* btcec: add a comment indicating where curve name taken from

Related with btcsuite#1565

* rpcclient: support listtransactions RPC with watchonly argument

Co-authored-by: Gert-Jaap Glasbergen <gertjaap@decoscrypto.com>

* blockchain: Remove unnecessary tx hash

* btcjson: update ListTransactionsResult for Bitcoin 0.20.0

This only adds new fields as optional, in order to make this change
backwards compatible with older versions of Bitcoin Core.

* chaincfg: Add RegisterHDKeyID func to populate HD key ID pairs

Currently, the only way to register HD version bytes is by initializing
chaincfg.Params struct, and registering it during package init.
RegisterHDKeyID provides a way to populate custom HD version bytes,
without having to create new chaincfg.Params instances. This is useful
for library packages who want to use non-standard version bytes for
serializing extended keys, such as the ones documented in SLIP-0132.

This function is complementary to HDPrivateKeyToPublicKeyID, which is
used to lookup previously registered key IDs.

* Nullable optional JSON-RPC parameters

Fix command marshalling dropping params following params with nil value.

btcsuite#1591 Allow specifying null parameter value from command line.

* GitHub Actions: Enable Go Race detector and code coverage

This modifies the goclean.sh script to run tests with the
race detector enabled. It also enables code coverage, and
uploads the results to coveralls.io.

Running tests with -race and -cover flags was disabled in
6487ba1 and 6788df7 respectively, due to some limits on
time/goroutines being hit on Travis CI. Since we have
migrated to GitHub Actions, it is desirable to bring them
back.

* rpc: Add getnodeaddresses JSON-RPC support

Add NodeAddresses function to rpcserverConnManager
interface for fetching known node addresses.

* btcjson,rpcclient: add support for PSBT commands to rpcclient

* Added ListSinceBlockMinConfWatchOnly method.

* wire: add proper types for flag field and improve docs

Summary of changes:

- Add a new const TxFlagMarker to indicate the flag prefix byte.
- Add a new TxFlag type to enumerate the flags supported by the
  tx parser.

  This allows us to avoid hardcoded magics, and will make it easier
  to support new flags in future.
- Improve code comments.

Closes btcsuite#1598.

* removed unnecessary GOMAXPROCS function calls

* rpcclient: add deriveaddresses RPC command

* ci: add go 1.15 to tests

* sample-btcd.conf: fix typo

* btcjson: add test for null params in searchrawtransactions

Closes PR btcsuite#1476.

* GetBlockTemplate RPC client implementation (btcsuite#1629)

* GetBlockTemplate RPC client implementation

* Txid added to the getblocktemplate result

* Omitempty for TxID and improved comment for GetBlockTemplate 'rules' field

* rpcclient: implement getaddressinfo command

Fields such as label, and labelspurpose are not included, since they
are deprecated, and will be removed in Bitcoin Core 0.21.

* Fix link to using bootstrap.dat

* rpcclient: implement getwalletinfo command

* rpcserver: add txid to getblocktemplate response

* rpc: add signrawtransactionwithwallet interface

Adds interface for issuing a signrawtransactionwithwallet command.
Note that this does not add functionality for the btcd rpc server
itself, it simply assumes that the RPC client has this ability and gives
an API for interacting with the RPC client.

rpc: add signrawtransactionwithwallet interface

* rpcclient: implement gettxoutsetinfo command

* Unmarshal hashes/second as float in GetMiningInfoResult

* rpcclient: add more wallet commands

Implement backupwallet, dumpwallet, loadwallet and unloadwallet.

* btcjson: add new JSON-RPC errors and document them

* rpcclient: implement createwallet with functional options

* rpcclient: fix documentation typos

* integration: allow setting custom btcd exe path

To allow using a custom btcd executable, we allow specifying a path to a
file. If the path is empty, the harness will fall back to compiling one
from scratch.

* integration: allow overwriting address generator

* integration: allow specifying connection behavior

* integration/rpctest: randomizes port in rpctest.New to reduce collisions

* btcjson+rpcserverhelp: restore bitcoind compatibility

The PR btcsuite#1594 introduced a change that made the order of parameters
relevant, if one of them is nil. This makes it harder to be backward
compatible with the same JSON message if an existing parameter in
bitcoind was re-purposed to have a different meaning.

* simplify s[:] to s where s is a slice

Found using https://go-critic.github.io/overview#unslice-ref

* rpcclient: add ExtraHeaders in ConnConfig

* Add support for receiving sendaddrv2 message from a peer

* fixed broken link

* Add support for arm32v7 in Dockerfile

* Fixes btcsuite#1653

* btcjson: Update fields in GetBlockChainInfoResult

Update the fields of GetBlockChainInfoResult to reflect the current state of
the RPC returned by other full-node implementations.

 * InitialBlockDownload - Node is in Initial Block Download mode if True.
 * SizeOnDisk - The estimated size of the block and undo files on disk.

* txscript: add benchmark for IsUnspendable

 - create benchmarks to measure allocations
 - add test for benchmark input
 - create a low alloc parseScriptTemplate
 - refactor parsing logic for a single opcode

* txscript/hashcache_test: always add inputs during getTxn

TestHashCacheAddContainsHashes flakes fairly regularly when rebasing
PR btcsuite#1684 with:
    txid <txid> wasn't inserted into cache but was found.

With probabilty 1/10^2 there will be no inputs on the transaction. This
reduces the entropy in the txid, and I belive is the primary cause of
the flake.

* txscript/hashcache_test: call rand.Seed once in init

This resolves the more fundamental flake in the unit tests noted in the
prior commit.

Because multiple unit tests call rand.Seed in parallel, it's possible
they can be executed with the same unix timestamp (in seconds). If the
second call happens between generating the hash cache and checking that
the cache doesn't contain a random txn, the random transaction is in
fact a duplicate of one generated earlier since the RNG state was reset.

To remedy, we initialize rand.Seed once in the init function.

* btcec: validate R and S signature components in RecoverCompact

* Add Batch JSON-RPC support (rpc client & server)

* Fix error message returned by EstimateFee

When you provide an argument to EstimateFee(numblocks uint32) that exceeds the estimateFeeDepth (which is set to 25), you get an error message that says "can only estimate fees for up to 100 blocks from now".  The variable used in the if condition and the variable used for creating the error message should be the same.

* docs: update shields

* rpcserver: Fix Error message returned by processRequest

When processRequest can't find a rpc command, standardCmdResult returns
a `btcjson.ErrRPCMethodNotFound` but it gets ignored and a
`btcjson.ErrRPCInvalidRequest` is returned instead.

This makes processRequest return the right error message.

* peer: allow external testing of peer.Peer

The previous use of allowSelfConns prevented this, as users aren't able
to invoke peer.TstAllowSelfConns themselves due to being part of a test
file, which aren't exported at the library level, leading to a
"disconnecting peer connected to self" error upon establishing a mock
connection between two peers. By including the option at the config
level instead (false by default, prevents connections to self) we enable
users of the peer library to properly test the behavior of the peer.Peer
struct externally.

* addrmgr: Use RLock/RUnlock when possible

* build: update btcutil dependency

* rpcclient: fix documentation typo

* btcjson: Updated TxRawResult.Version from int32 to uint32

* wire+chaincfg: add signet params

This commit adds all necessary chain parameters for connecting to the
public signet network.
Reference: bitcoin/bitcoin#18267

* config+params: add signet config option

This commit adds the --signet command line flag (or signet config
option) for starting btcd in signet mode.

* rpcserver: add taproot deployment to getblockchaininfo

* btcctl: add signet param

This commit adds the --signet command line flag to the btcctl utility.

* mining: extract witness commitment add into method

* rpctest: add witness commitment when calling CreateBlock

If we tried to include transactions having witnesses, the block would be
invalid since the witness commitment was not added.

* Don't reference the readme that we don't produce

* chaincfg: fix deployment bit numbers

On signet all previous soft forks and also taproot are always activated,
meaning the version is always 0x20000000 for all blocks. To make sure
they activate properly in `btcd` we therefore need to use the correct
bit to mask the version.
This means that on any custom signet there would need to be 2016 blocks
mined before SegWit or Taproot can be used.

* mempool: add additional test case for inherited RBF replacement

In this commit, we add an additional test case for inherited RBF
replacement. This test case asserts that if a parent is marked as being
replaceable, but the child isn't, then the child can still be replaced
as according to BIP 125 it shoudl _inhreit_ the replaceability of its
parent.

The addition of this test case was prompted by the recently discovered
Bitcoin Core "CVE" [1]. It turns out that bitcoind doesn't properly
implement BIP 125. Namely it fails to allow a child to "inherit"
replaceability if its parent is also replaceable. Our implementation
makes this trait rather explicit due to its recursive implementation.
Kudos to the original implementer @wpaulino for getting this correct.

[1]: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-May/018893.html.

* Update CHANGES file for 0.22.0 release

* btcd: bump version to v0.22.0-beta

* Update release date for v0.22.0-beta in CHANGES file

* remove duplicate command

Co-authored-by: Antonin Hildebrand <antonin@hildebrand.cz>
Co-authored-by: Dan Cline <kidscline01@gmail.com>
Co-authored-by: David Hill <dhill@mindcry.org>
Co-authored-by: Henry <henry.wfisher@gmail.com>
Co-authored-by: Wilmer Paulino <wilmer.paulino@gmail.com>
Co-authored-by: Olaoluwa Osuntokun <laolu32@gmail.com>
Co-authored-by: JeremyRand <jeremyrand@airmail.cc>
Co-authored-by: Torkel Rogstad <torkel@rogstad.io>
Co-authored-by: Mikael Lindlof <mikuz.dev@gmail.com>
Co-authored-by: adiabat <rx@awsomnet.org>
Co-authored-by: Federico Bond <federicobond@gmail.com>
Co-authored-by: Anirudha Bose <anirudha.bose@ledger.fr>
Co-authored-by: Javed Khan <tuxcanfly@gmail.com>
Co-authored-by: Anirudha Bose <anirudha.bose@alumni.cern>
Co-authored-by: Oliver Gugger <gugger@gmail.com>
Co-authored-by: qqjettkgjzhxmwj <37233887+JettScythe@users.noreply.github.com>
Co-authored-by: Dan Cline <dan@dancline.net>
Co-authored-by: John C. Vernaleo <jcv@netpurgatory.com>
Co-authored-by: wakiyamap <wakiyamap@gmail.com>
Co-authored-by: Christian Lehmann <info@legacycode.org>
Co-authored-by: yyforyongyu <yy2452@columbia.edu>
Co-authored-by: Hanjun Kim <hallazzang@gmail.com>
Co-authored-by: Gert-Jaap Glasbergen <gertjaap@decoscrypto.com>
Co-authored-by: Calvin Kim <calvin@kcalvinalvin.info>
Co-authored-by: Andrew Tugarinov <nalcheg@gmail.com>
Co-authored-by: ipriver <g1ran1q@gmail.com>
Co-authored-by: Jake Sylvestre <jakesyl@gmail.com>
Co-authored-by: Tristyn <tristynstimpson@gmail.com>
Co-authored-by: Elliott Minns <elliott.minns@me.com>
Co-authored-by: Friedger Müffke <friedger@gmail.com>
Co-authored-by: David Mazary <dmaz@vt.edu>
Co-authored-by: Armando Ochoa <armando.o.j@gmail.com>
Co-authored-by: Liran Sharir <lsharir@paxos.com>
Co-authored-by: Iskander Sharipov <quasilyte@gmail.com>
Co-authored-by: 10gic <2391796+10gic@users.noreply.github.com>
Co-authored-by: Yaacov Akiba Slama <ya@slamail.org>
Co-authored-by: ebiiim <mail@ebiiim.com>
Co-authored-by: Victor Lavaud <victor.lavaud@gmail.com>
Co-authored-by: Vinayak Borkar <vinayakb@gmail.com>
Co-authored-by: Steven Kreuzer <skreuzer@FreeBSD.org>
Co-authored-by: Conner Fromknecht <conner@lightning.engineering>
Co-authored-by: Appelberg-s <Appelberg-s@users.noreply.github.com>
Co-authored-by: Gustavo Chain <gchain@pm.me>
Co-authored-by: Aurèle Oulès <aurele@oules.com>
Co-authored-by: Johan T. Halseth <johanth@gmail.com>
@Roasbeef
Copy link
Member

Replaced by #1769

@Roasbeef Roasbeef closed this Nov 10, 2021
btcd-dev automation moved this from Pending reviews to Done Nov 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
btcd-dev
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

7 participants