The requireMinimal flag for MakeScriptNum was removed in
84b65d049b but the description was left
in the comment for MakeScriptNum. This removes that part of the docs.
Also expand on range error and fix code reference. In
d8306ee602, the error for out-of-range
changed from ErrNumberTooBig to ErrNumOutOfRange.
This modifies the entire repository to use the new formatting of doc
comments in the upcoming Go 1.19 release.
The primary motivating factors for this are:
- Builds check that files are formatted per gofmt and that will no
longer be true as of Go 1.19 without these changes
- Separating all the updates into a single commit ensures these
documentation only formatting changes do not clutter up diffs that
actually change code
For the most part, the changes are just the automated changes suggested
by the Go 1.19 version of gofmt, but there are also a few cases where
the comments were reworded a bit to play nicely with the new formatting
requirements.
For example, the new version of gofmt reformats and collapses nested
lists where as the existing version does not. Thus, instances of nested
lists have been changed to either eliminate them or use mixed markers
which produce expect results.
This modifies the encoding logic for script numbers to support encoding
min int64s. This was previously not supported since the type was not
public and it is not possible to achieve a min int64 within the context
of the script system itself due to the strict limits it imposes.
However, now that script numbers are exported for external use and
callers are not bound by the aforementioned strictness, it should be
possible to encode the entire range for completeness.
In practice, callers should never realistically need to encode the value
since the purpose of the type is to create encoded numbers for scripts
and the value in question will be rejected upon any attempt to use it as
a number when verifying scripts given it is out of range.
This exports the CsvMaxScriptNumLen constant which defines the maximum
number of bytes data being interpreted as an integer may be for by-time
and by-height locks as interpreted by CHECKSEQUENCEVERIFY.
Among other cases, it can be useful when doing complex script analysis
to ensure consensus semantics are observed by CHECKSEQUENCEVERIFY
invocations in addition to the extra semantics needed by the analysis.
This exports the CltvMaxScriptNumLen constant which defines the maximum
number of bytes data being interpreted as an integer may be for by-time
and by-height locks as interpreted by CHECKLOCKTIMEVERIFY.
Among other cases, it can be useful when doing complex script analysis
to ensure consensus semantics are observed by CHECKLOCKTIMEVERIFY
invocations in addition to the extra semantics needed by the analysis.
This exports the MathOpCodeMaxScriptNumLen constant which defines the
maximum number of bytes data being interpreted as an integer may be for
the majority of op codes.
Among other cases, it can be useful when doing complex script analysis
to ensure consensus semantics are observed in addition to the extra
semantics needed by the analysis.
This exports the ScriptNum type and associated MakeScriptNum constructor
in order to expose the ability to better analyze more complex scripts
while respecting the special handling needed to deal with the subtle
semantics required by consensus.
As is already well commented in the code, the sequence number parameter
of the CHECKSEQUENCEVERIFY opcode requires 5 bytes instead of the
standard 4 bytes allowed by math opcodes. This introduces a constant
for the value instead of hardcoding 5 to increase readability and
potentially allow the value to be exported in the future.
As is already well commented in the code, the locktime parameter of the
CHECKLOCKTIMEVERIFY opcode requires 5 bytes instead of the standard 4
bytes allowed by math opcodes. This introduces a constant for the value
instead of hardcoding 5 to increase readability and potentially allow
the value to be exported in the future.
This removes the flag to require minimal encoding when create script
numbers since since all callers now call the function with true due to
the recent removal of the minimal data script verification flag from the
script engine and updates the tests accordingly.
This converts the majority of script errors from generic errors created
via errors.New and fmt.Errorf to use a concrete type that implements the
error interface with an error code and description.
This allows callers to programmatically detect the type of error via
type assertions and an error code while still allowing the errors to
provide more context.
For example, instead of just having an error the reads "disabled opcode"
as would happen prior to these changes when a disabled opcode is
encountered, the error will now read "attempt to execute disabled opcode
OP_FOO".
While it was previously possible to programmatically detect many errors
due to them being exported, they provided no additional context and
there were also various instances that were just returning errors
created on the spot which callers could not reliably detect without
resorting to looking at the actual error message, which is nearly always
bad practice.
Also, while here, export the MaxStackSize and MaxScriptSize constants
since they can be useful for consumers of the package and perform some
minor cleanup of some of the tests.
This commit implements a new type, named scriptNum, for handling all
numeric values used in scripts and converts the code over to make use of
it. This is being done for a few of reasons.
First, the consensus rules for handling numeric values in the scripts
require special handling with subtle semantics. By encapsulating those
details into a type specifically dedicated to that purpose, it
simplifies the code and generally helps prevent improper usage.
Second, the new type is quite a bit more efficient than big.Ints which
are designed to be arbitrarily large and thus involve a lot of heap
allocations and additional multi-precision bookkeeping. Because this
new type is based on an int64, it allows the numbers to be stack
allocated thereby eliminating a lot of GC and also eliminates the extra
multi-precision arithmetic bookkeeping.
The use of an int64 is possible because the consensus rules dictate that
when data is interpreted as a number, it is limited to an int32 even
though results outside of this range are allowed so long as they are not
interpreted as integers again themselves. Thus, the maximum possible
result comes from multiplying a max int32 by itself which safely fits
into an int64 and can then still appropriately provide the serialization
of the larger number as required by consensus.
Finally, it more closely resembles the implementation used by Bitcoin
Core and thus makes is easier to compare the behavior between the two
implementations.
This commit also includes a full suite of tests with 100% coverage of
the semantics of the new type.