mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
This converts the ExtractCoinbaseNullData function to make use of the new tokenizer instead of the far less efficient parseScript thereby significantly optimizing the function. The following is a before and after comparison of analyzing a typical coinbase script: benchmark old ns/op new ns/op delta ------------------------------------------------------------------- BenchmarkExactCoinbaseNullData 227 31.0 -86.34% benchmark old allocs new allocs delta ------------------------------------------------------------------- BenchmarkExactCoinbaseNullData 1 0 -100.00% benchmark old bytes new bytes delta ------------------------------------------------------------------- BenchmarkExactCoinbaseNullData 448 0 -100.00%
64 lines
2.4 KiB
Go
64 lines
2.4 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.
|
|
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.
|
|
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)
|
|
}
|