mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
This refactors the consensus code which extracts the null data from the coinbase from txscript.ExtractCoinbaseNullData so that it is performed directly in the validation code where it more properly belongs. The only reason the extraction was previously done in txscript is because it was not possible to parse scripts outside of it, but that is no longer the case now that txscript offers an exported tokenizer for that purpose. The extraction code is ever so slightly more efficient now that it no longer needs to be as generic since it now has direct knowledge of the conditions that need to be handled. Great care was taken to ensure the semantics are not changed while refactoring the code and no additional tests are added in this commit because all of the conditions and code paths are covered by the tests recently added to the full block tests. While here, also perform some related code cleanup in the function and improve the error messages . Since the txscript.ExtractCoinbaseNullData is no longer necessary, this deprecates the function and releated error code and constant so they can be removed in the next major version of txscript. Finally, since this relies on the script tokenizer which is not yet in a released version of the txscript module, bump the requirement to include an as yet unreleased version of txscript to ensure the next time the blockchain module is released, it will require a newer version of txscript to be released first.
68 lines
2.6 KiB
Go
68 lines
2.6 KiB
Go
// Copyright (c) 2015-2016 The btcsuite developers
|
|
// Copyright (c) 2015-2019 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package txscript
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
const (
|
|
// LockTimeThreshold is the number below which a lock time is
|
|
// interpreted to be a block number. Since an average of one block
|
|
// is generated per 10 minutes, this allows blocks for about 9,512
|
|
// years.
|
|
LockTimeThreshold = 5e8 // Tue Nov 5 00:53:20 1985 UTC
|
|
|
|
// maxUniqueCoinbaseNullDataSize is the maximum number of bytes allowed
|
|
// in the pushed data output of the coinbase output that is used to
|
|
// ensure the coinbase has a unique hash.
|
|
//
|
|
// Deprecated: This will be removed in the next major version bump.
|
|
maxUniqueCoinbaseNullDataSize = 256
|
|
)
|
|
|
|
// ExtractCoinbaseNullData ensures the passed script is a nulldata script as
|
|
// required by the consensus rules for the coinbase output that is used to
|
|
// ensure the coinbase has a unique hash and returns the data it pushes.
|
|
//
|
|
// 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.
|
|
//
|
|
// Deprecated: This will be removed in the next major version bump.
|
|
func ExtractCoinbaseNullData(pkScript []byte) ([]byte, error) {
|
|
// The nulldata in the coinbase must be a single OP_RETURN followed by a
|
|
// data push up to maxUniqueCoinbaseNullDataSize bytes.
|
|
//
|
|
// NOTE: This is intentionally not using GetScriptClass and the related
|
|
// functions because those are specifically for standardness checks which
|
|
// can change over time and this function is specifically intended to be
|
|
// used by the consensus rules.
|
|
//
|
|
// Also of note is that technically normal nulldata scripts support encoding
|
|
// numbers via small opcodes, however the consensus rules require the block
|
|
// height to be encoded as a 4-byte little-endian uint32 pushed via a normal
|
|
// data push, as opposed to using the normal number handling semantics of
|
|
// scripts, so this is specialized to accommodate that.
|
|
const scriptVersion = 0
|
|
if len(pkScript) == 1 && pkScript[0] == OP_RETURN {
|
|
return nil, nil
|
|
}
|
|
if len(pkScript) > 1 && pkScript[0] == OP_RETURN {
|
|
tokenizer := MakeScriptTokenizer(scriptVersion, pkScript[1:])
|
|
if tokenizer.Next() && tokenizer.Done() &&
|
|
tokenizer.Opcode() <= OP_PUSHDATA4 &&
|
|
len(tokenizer.Data()) <= maxUniqueCoinbaseNullDataSize {
|
|
|
|
return tokenizer.Data(), nil
|
|
}
|
|
}
|
|
|
|
str := fmt.Sprintf("script %x is not well-formed coinbase nulldata",
|
|
pkScript)
|
|
return nil, scriptError(ErrMalformedCoinbaseNullData, str)
|
|
}
|