In this commit, we turn the package into a new Go module (version 2),
and then port over the current set of types and functions to mainly
alias to the more optimized and maintained dcrec variant.
Taking a look at the benchmarks, most operations other than
normalization (which IIRC is a bit slower now due to constant time
fixes) enjoy some nice speeds up:
```
benchcmp is deprecated in favor of benchstat: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat
benchmark old ns/op new ns/op delta
BenchmarkAddJacobian-8 464 328 -29.20%
BenchmarkAddJacobianNotZOne-8 1138 372 -67.27%
BenchmarkScalarBaseMult-8 47336 31531 -33.39%
BenchmarkScalarBaseMultLarge-8 42465 32057 -24.51%
BenchmarkScalarMult-8 123355 117579 -4.68%
BenchmarkNAF-8 582 168 -71.12%
BenchmarkSigVerify-8 175414 120794 -31.14%
BenchmarkFieldNormalize-8 23.8 24.4 +2.39%
BenchmarkParseCompressedPubKey-8 24282 10907 -55.08%
```
In this commit, we extract the BIP 9 state transition logic from the
thresholdState method into a new thresholdStateTransition function that
allows us to test all the defined state transitions, including the
modified "speedy trial" logic.
In this commit, we extend the existing version bits state machine to add
support for the new minimum activation height and custom block threshold
for activation. We then extend the existing BIP 9 tests (tho this isn't
really BIP 9 anymore...) to exercise the new min activation height
logic.
In this commit, we add a new "dummy" deployment that adds the new params
used to activate taproot. We chose to add a new deployment as unlike the
bitcoind codebase, we don't currently "bury" soft forks that have
happened in the past (hard code an activation height).
The old taproot deployment has been removed as with the way the array
works, a deployment needs to be defined for _all_ networks.
In this commit, we update our version bits logic to use the newly added
HasStarted and HasEnded methods for consensus deployments. Along the
way, wee modify the thresholdConditionChecker` interface to be based off
the new chaincfg interfaces. In addition, we add a new method
`PastMedianTime`, in order to allow the chain itself to be used as a
`chaincfg.BlockClock`.
This serves to make the logic more generic in order to support both
block height and time based soft fork timeouts.
In this commit, we utilize the recently added ConsensusDeploymentStarter
and ConsensusDeploymentEnder interfaces. Concrete implementations of
this interface based on the median time past comparison are used now in
the ConsensusDeployment struct instead of hard coded start/end times.
Along the way, we had to switch to using the "zero time": time.Time{},
in place of 0 and math.MaxInt64 as comparison (After/Before) seems to be
broken in the Go stdlib for times very far in the future. It appears Go
isn't ready to handle the heat death of the universe.
In this commit, we create a series of new interfaces that'll allow us to
abstract "when" exactly a deployment starts and ends. As is, all
deployments start/end based on a unix timestamp, which is compared
against the MTP of a given block to determine if a new deployment has
started or ended. This works fine for BIP 9 which uses time based
timeouts, but not so much for BIP 8. In order to prep a future refactor
that allows our version bits implementation to support both time and
block based start/end times, this new abstraction has been introduced.
Now that the new `btcutil/v1.0.0` tag has been pushed, we update the new
internal modules to point to the top-level `btcd` repo via replace
directives.
In this commit, we adapt the Makefile that was being used for the
btcutil project to work for btcd as well. The Makefile is pretty simple,
and is just a series of templated commands. Overtime, we can pull in
some of the `lnd` additions as well, which we use to handle our
reproducible build and verification system.
In this commit, we update all the btcutil imports to point to the new
sub-module.
In the same commit, we also modify the recently added `btcutil/go.mod`
file as we need to continue pointing to the _old_ version of btcd, until
we merge this PR and push a new tag.
Goleveldb recently had a PR in where memory allocation was reduced
drastically (github.com/syndtr/goleveldb/pull/367). Update goleveldb
to use that PR.
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.
This refactors the script engine to store and step through raw scripts
by making using of the new zero-allocation script tokenizer as opposed
to the less efficient method of storing and stepping through parsed
opcodes. It also improves several aspects while refactoring such as
optimizing the disassembly trace, showing all scripts in the trace in
the case of execution failure, and providing additional comments
describing the purpose of each field in the engine.
It should be noted that this is a step towards removing the parsed
opcode struct and associated supporting code altogether, however, in
order to ease the review process, this retains the struct and all
function signatures for opcode execution which make use of an individual
parsed opcode. Those will be updated in future commits.
The following is an overview of the changes:
- Modify internal engine scripts slice to use raw scripts instead of
parsed opcodes
- Introduce a tokenizer to the engine to track the current script
- Remove no longer needed script offset parameter from the engine since
that is tracked by the tokenizer
- Add an opcode index counter for disassembly purposes to the engine
- Update check for valid program counter to only consider the script
index
- Update tests for bad program counter accordingly
- Rework the NewEngine function
- Store the raw scripts
- Setup the initial tokenizer
- Explicitly check against version 0 instead of DefaultScriptVersion
which would break consensus if changed
- Check the scripts parse according to version 0 semantics to retain
current consensus rules
- Improve comments throughout
- Rework the Step function
- Use the tokenizer and raw scripts
- Create a parsed opcode on the fly for now to retain existing
opcode execution function signatures
- Improve comments throughout
- Update the Execute function
- Explicitly check against version 0 instead of DefaultScriptVersion
which would break consensus if changed
- Improve the disassembly tracing in the case of error
- Update the CheckErrorCondition function
- Modify clean stack error message to make sense in all cases
- Improve the comments
- Update the DisasmPC and DisasmScript functions on the engine
- Use the tokenizer
- Optimize construction via the use of strings.Builder
- Modify the subScript function to return the raw script bytes since the
parsed opcodes are no longer stored
- Update the various signature checking opcodes to use the raw opcode
data removal and signature hash calculation functions since the
subscript is now a raw script
- opcodeCheckSig
- opcodeCheckMultiSig
- opcodeCheckSigAlt
This converts the engine's current program counter disasembly to make
use of the standalone disassembly function to remove the dependency on
the parsed opcode struct.
It also updates the tests accordingly.
This converts the checkMinimalDataPush function defined on a parsed
opcode to a standalone function which accepts an opcode and data slice
instead in order to make it more flexible for raw script analysis.
It also updates all callers accordingly.
This converts the isConditional function defined on a parsed opcode to a
standalone function named isOpcodeConditional which accepts an opcode as
a byte instead in order to make it more flexible for raw script
analysis.
It also updates all callers accordingly.
This converts the alwaysIllegal function defined on a parsed opcode to a
standalone function named isOpcodeAlwaysIllegal which accepts an opcode
as a byte instead in order to make it more flexible for raw script
analysis.
It also updates all callers accordingly.
This converts the isDisabled function defined on a parsed opcode to a
standalone function which accepts an opcode as a byte instead in order
to make it more flexible for raw script analysis.
It also updates all callers accordingly.
This introduces a new function named removeOpcodeByDataRaw which accepts
the raw scripts and data to remove versus requiring the parsed opcodes
to both significantly optimize it as well as make it more flexible for
working with raw scripts.
There are several places in the rest of the code that currently only
have access to the parsed opcodes, so this only introduces the function
for use in the future and deprecates the existing one.
Note that, in practice, the script will never actually contain the data
that is intended to be removed since the function is only used during
signature verification to remove the signature itself which would
require some incredibly non-standard code to create.
Thus, as an optimization, it avoids allocating a new script unless there
is actually a match that needs to be removed.
Finally, it updates the tests to use the new function.
This converts SignTxOutput and supporting funcs, namely sign,
mergeScripts and mergeMultiSig, to make use of the new tokenizer as well
as some recently added funcs that deal with raw scripts in order to
remove the reliance on parsed opcodes as a step towards utlimately
removing them altogether and updates the comments to explicitly call out
the script version semantics.
It is worth noting that this has the side effect of optimizing the
function as well, however, since this change is not focused on the
optimization aspects, no benchmarks are provided.
This moves the function definition for mergeMultiSig so it is more
consistent with the preferred order used through the codebase. In
particular, the functions are defined before they're first used and
generally as close as possible to the first use when they're defined in
the same file.