mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-04 05:06:43 +00:00
[DEV-98] Move script flags from relay rules to consensus (#49)
* [DEV-98] Move script flags from relay rules to consensus * [DEV-98] remove flags from script_tests.json * [DEV-98] fix multisig and remove test that assume no minimal data rule * [DEV-98] rename bip16 bool to isP2sh * [DEV-98] add sighash type to overly long signature in script_tests.json * [DEV-98] add test for NUMEQUAL for non equal numbers script_tests.json * [DEV-98] remove debugging if * [DEV-98] remove ErrCleanStack from EVAL_FALSE * [DEV-98] change isP2sh to isP2SH to comply with Go style * [DEV-98] add ScriptNoFlags to explictly indicate for empty ScriptFlags * [DEV-98] rename ErrPubKeyType -> ErrPubKeyFormat * [DEV-98] rename PUBKEYTYPE -> PUBKEYFORMAT
This commit is contained in:
parent
c65d9aa168
commit
b4b71eec01
@ -40,7 +40,7 @@ func TestCheckBlockScripts(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
scriptFlags := txscript.ScriptBip16
|
||||
scriptFlags := txscript.ScriptNoFlags
|
||||
err = checkBlockScripts(blocks[0], view, scriptFlags, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Transaction script validation failed: %v\n", err)
|
||||
|
@ -955,12 +955,6 @@ func (dag *BlockDAG) checkConnectBlock(node *blockNode, block *util.Block, view
|
||||
return err
|
||||
}
|
||||
|
||||
// BIP0016 describes a pay-to-script-hash type that is considered a
|
||||
// "standard" type. The rules for this BIP only apply to transactions
|
||||
// after the timestamp defined by txscript.Bip16Activation. See
|
||||
// https://en.bitcoin.it/wiki/BIP_0016 for more details.
|
||||
enforceBIP0016 := node.timestamp >= txscript.Bip16Activation.Unix()
|
||||
|
||||
// The number of signature operations must be less than the maximum
|
||||
// allowed per block. Note that the preliminary sanity checks on a
|
||||
// block also include a check similar to this one, but this check
|
||||
@ -971,19 +965,17 @@ func (dag *BlockDAG) checkConnectBlock(node *blockNode, block *util.Block, view
|
||||
totalSigOps := 0
|
||||
for i, tx := range transactions {
|
||||
numsigOps := CountSigOps(tx)
|
||||
if enforceBIP0016 {
|
||||
// Since the first (and only the first) transaction has
|
||||
// already been verified to be a coinbase transaction,
|
||||
// use i == 0 as an optimization for the flag to
|
||||
// countP2SHSigOps for whether or not the transaction is
|
||||
// a coinbase transaction rather than having to do a
|
||||
// full coinbase check again.
|
||||
numP2SHSigOps, err := CountP2SHSigOps(tx, i == 0, view)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
numsigOps += numP2SHSigOps
|
||||
// Since the first (and only the first) transaction has
|
||||
// already been verified to be a coinbase transaction,
|
||||
// use i == 0 as an optimization for the flag to
|
||||
// countP2SHSigOps for whether or not the transaction is
|
||||
// a coinbase transaction rather than having to do a
|
||||
// full coinbase check again.
|
||||
numP2SHSigOps, err := CountP2SHSigOps(tx, i == 0, view)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
numsigOps += numP2SHSigOps
|
||||
|
||||
// Check for overflow or going over the limits. We have to do
|
||||
// this on every loop iteration to avoid overflow.
|
||||
@ -1065,12 +1057,7 @@ func (dag *BlockDAG) checkConnectBlock(node *blockNode, block *util.Block, view
|
||||
runScripts = false
|
||||
}
|
||||
|
||||
// Blocks created after the BIP0016 activation time need to have the
|
||||
// pay-to-script-hash checks enabled.
|
||||
var scriptFlags txscript.ScriptFlags
|
||||
if enforceBIP0016 {
|
||||
scriptFlags |= txscript.ScriptBip16
|
||||
}
|
||||
scriptFlags := txscript.ScriptNoFlags
|
||||
|
||||
// We obtain the MTP of the *previous* block in order to
|
||||
// determine if transactions in the current block are final.
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
|
||||
"github.com/daglabs/btcd/blockdag"
|
||||
"github.com/daglabs/btcd/txscript"
|
||||
"github.com/daglabs/btcd/wire"
|
||||
"github.com/daglabs/btcd/util"
|
||||
"github.com/daglabs/btcd/wire"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -84,12 +84,7 @@ func calcMinRequiredTxRelayFee(serializedSize int64, minRelayTxFee util.Amount)
|
||||
// to ensure they are "standard". A standard transaction input within the
|
||||
// context of this function is one whose referenced public key script is of a
|
||||
// standard form and, for pay-to-script-hash, does not have more than
|
||||
// maxStandardP2SHSigOps signature operations. However, it should also be noted
|
||||
// that standard inputs also are those which have a clean stack after execution
|
||||
// and only contain pushed data in their signature scripts. This function does
|
||||
// not perform those checks because the script engine already does this more
|
||||
// accurately and concisely via the txscript.ScriptVerifyCleanStack and
|
||||
// txscript.ScriptVerifySigPushOnly flags.
|
||||
// maxStandardP2SHSigOps signature operations.
|
||||
func checkInputsStandard(tx *util.Tx, utxoView *blockdag.UtxoViewpoint) error {
|
||||
// NOTE: The reference implementation also does a coinbase check here,
|
||||
// but coinbases have already been rejected prior to calling this
|
||||
|
File diff suppressed because one or more lines are too long
@ -17,9 +17,9 @@ import (
|
||||
type ScriptFlags uint32
|
||||
|
||||
const (
|
||||
// ScriptBip16 defines whether the bip16 threshold has passed and thus
|
||||
// pay-to-script hash transactions will be fully validated.
|
||||
ScriptBip16 ScriptFlags = 1 << iota
|
||||
|
||||
// ScriptNoFlags is used when you want to use ScriptFlags without raising any flags
|
||||
ScriptNoFlags ScriptFlags = 0
|
||||
|
||||
// ScriptDiscourageUpgradableNops defines whether to verify that
|
||||
// NOP1 through NOP10 are reserved for future soft-fork upgrades. This
|
||||
@ -27,40 +27,13 @@ const (
|
||||
// blocks as this flag is only for stricter standard transaction
|
||||
// checks. This flag is only applied when the above opcodes are
|
||||
// executed.
|
||||
ScriptDiscourageUpgradableNops
|
||||
|
||||
// ScriptVerifyCleanStack defines that the stack must contain only
|
||||
// one stack element after evaluation and that the element must be
|
||||
// true if interpreted as a boolean. This is rule 6 of BIP0062.
|
||||
// This flag should never be used without the ScriptBip16 flag.
|
||||
ScriptVerifyCleanStack
|
||||
|
||||
// ScriptVerifyLowS defines that signtures are required to comply with
|
||||
// the DER format and whose S value is <= order / 2. This is rule 5
|
||||
// of BIP0062.
|
||||
ScriptVerifyLowS
|
||||
|
||||
// ScriptVerifyMinimalData defines that signatures must use the smallest
|
||||
// push operator. This is both rules 3 and 4 of BIP0062.
|
||||
ScriptVerifyMinimalData
|
||||
|
||||
// ScriptVerifyNullFail defines that signatures must be empty if
|
||||
// a CHECKSIG or CHECKMULTISIG operation fails.
|
||||
ScriptVerifyNullFail
|
||||
|
||||
// ScriptVerifySigPushOnly defines that signature scripts must contain
|
||||
// only pushed data. This is rule 2 of BIP0062.
|
||||
ScriptVerifySigPushOnly
|
||||
|
||||
// ScriptVerifyStrictEncoding defines that signature scripts and
|
||||
// public keys must follow the strict encoding requirements.
|
||||
ScriptVerifyStrictEncoding
|
||||
ScriptDiscourageUpgradableNops ScriptFlags = 1 << iota
|
||||
)
|
||||
|
||||
const (
|
||||
// MaxStackSize is the maximum combined height of stack and alt stack
|
||||
// during execution.
|
||||
MaxStackSize = 1000
|
||||
MaxStackSize = 244
|
||||
|
||||
// MaxScriptSize is the maximum allowed length of a raw script.
|
||||
MaxScriptSize = 10000
|
||||
@ -82,8 +55,8 @@ type Engine struct {
|
||||
numOps int
|
||||
flags ScriptFlags
|
||||
sigCache *SigCache
|
||||
bip16 bool // treat execution as pay-to-script-hash
|
||||
savedFirstStack [][]byte // stack from first script for bip16 scripts
|
||||
isP2SH bool // treat execution as pay-to-script-hash
|
||||
savedFirstStack [][]byte // stack from first script for ps2h scripts
|
||||
}
|
||||
|
||||
// hasFlag returns whether the script engine instance has the passed flag set.
|
||||
@ -143,7 +116,7 @@ func (vm *Engine) executeOpcode(pop *parsedOpcode) error {
|
||||
|
||||
// Ensure all executed data push opcodes use the minimal encoding when
|
||||
// the minimal data verification flag is set.
|
||||
if vm.dstack.verifyMinimalData && vm.isBranchExecuting() &&
|
||||
if vm.isBranchExecuting() &&
|
||||
pop.opcode.value >= 0 && pop.opcode.value <= OpPushData4 {
|
||||
|
||||
if err := pop.checkMinimalDataPush(); err != nil {
|
||||
@ -228,15 +201,16 @@ func (vm *Engine) CheckErrorCondition(finalScript bool) error {
|
||||
"error check when script unfinished")
|
||||
}
|
||||
|
||||
if finalScript && vm.hasFlag(ScriptVerifyCleanStack) &&
|
||||
vm.dstack.Depth() != 1 {
|
||||
if finalScript {
|
||||
if vm.dstack.Depth() > 1 {
|
||||
|
||||
str := fmt.Sprintf("stack contains %d unexpected items",
|
||||
vm.dstack.Depth()-1)
|
||||
return scriptError(ErrCleanStack, str)
|
||||
} else if vm.dstack.Depth() < 1 {
|
||||
return scriptError(ErrEmptyStack,
|
||||
"stack empty at end of script execution")
|
||||
str := fmt.Sprintf("stack contains %d unexpected items",
|
||||
vm.dstack.Depth()-1)
|
||||
return scriptError(ErrCleanStack, str)
|
||||
} else if vm.dstack.Depth() < 1 {
|
||||
return scriptError(ErrEmptyStack,
|
||||
"stack empty at end of script execution")
|
||||
}
|
||||
}
|
||||
|
||||
v, err := vm.dstack.PopBool()
|
||||
@ -302,10 +276,10 @@ func (vm *Engine) Step() (done bool, err error) {
|
||||
|
||||
vm.numOps = 0 // number of ops is per script.
|
||||
vm.scriptOff = 0
|
||||
if vm.scriptIdx == 0 && vm.bip16 {
|
||||
if vm.scriptIdx == 0 && vm.isP2SH {
|
||||
vm.scriptIdx++
|
||||
vm.savedFirstStack = vm.GetStack()
|
||||
} else if vm.scriptIdx == 1 && vm.bip16 {
|
||||
} else if vm.scriptIdx == 1 && vm.isP2SH {
|
||||
// Put us past the end for CheckErrorCondition()
|
||||
vm.scriptIdx++
|
||||
// Check script ran successfully and pull the script
|
||||
@ -382,10 +356,6 @@ func (vm *Engine) currentScript() []parsedOpcode {
|
||||
// checkHashTypeEncoding returns whether or not the passed hashtype adheres to
|
||||
// the strict encoding requirements if enabled.
|
||||
func (vm *Engine) checkHashTypeEncoding(hashType SigHashType) error {
|
||||
if !vm.hasFlag(ScriptVerifyStrictEncoding) {
|
||||
return nil
|
||||
}
|
||||
|
||||
sigHashType := hashType & ^SigHashAnyOneCanPay
|
||||
if sigHashType < SigHashAll || sigHashType > SigHashSingle {
|
||||
str := fmt.Sprintf("invalid hash type 0x%x", hashType)
|
||||
@ -397,10 +367,6 @@ func (vm *Engine) checkHashTypeEncoding(hashType SigHashType) error {
|
||||
// checkPubKeyEncoding returns whether or not the passed public key adheres to
|
||||
// the strict encoding requirements if enabled.
|
||||
func (vm *Engine) checkPubKeyEncoding(pubKey []byte) error {
|
||||
if !vm.hasFlag(ScriptVerifyStrictEncoding) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(pubKey) == 33 && (pubKey[0] == 0x02 || pubKey[0] == 0x03) {
|
||||
// Compressed
|
||||
return nil
|
||||
@ -410,7 +376,7 @@ func (vm *Engine) checkPubKeyEncoding(pubKey []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return scriptError(ErrPubKeyType, "unsupported public key type")
|
||||
return scriptError(ErrPubKeyFormat, "unsupported public key type")
|
||||
}
|
||||
|
||||
// checkSignatureEncoding returns whether or not the passed signature adheres to
|
||||
@ -542,13 +508,11 @@ func (vm *Engine) checkSignatureEncoding(sig []byte) error {
|
||||
// valid transaction with the complement while still being a valid
|
||||
// signature that verifies. This would result in changing the
|
||||
// transaction hash and thus is source of malleability.
|
||||
if vm.hasFlag(ScriptVerifyLowS) {
|
||||
sValue := new(big.Int).SetBytes(sig[rLen+6 : rLen+6+sLen])
|
||||
if sValue.Cmp(halfOrder) > 0 {
|
||||
return scriptError(ErrSigHighS,
|
||||
"signature is not canonical due to "+
|
||||
"unnecessarily high S value")
|
||||
}
|
||||
sValue := new(big.Int).SetBytes(sig[rLen+6 : rLen+6+sLen])
|
||||
if sValue.Cmp(halfOrder) > 0 {
|
||||
return scriptError(ErrSigHighS,
|
||||
"signature is not canonical due to "+
|
||||
"unnecessarily high S value")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -622,64 +586,43 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags
|
||||
"false stack entry at end of script execution")
|
||||
}
|
||||
|
||||
// The clean stack flag (ScriptVerifyCleanStack) is not allowed without
|
||||
// the pay-to-script-hash (P2SH) evaluation (ScriptBip16) flag.
|
||||
//
|
||||
// Recall that evaluating a P2SH script without the flag set results in
|
||||
// non-P2SH evaluation which leaves the P2SH inputs on the stack. Thus,
|
||||
// allowing the clean stack flag without the P2SH flag would make it
|
||||
// possible to have a situation where P2SH would not be a soft fork when
|
||||
// it should be.
|
||||
vm := Engine{flags: flags, sigCache: sigCache}
|
||||
if vm.hasFlag(ScriptVerifyCleanStack) && !vm.hasFlag(ScriptBip16) {
|
||||
return nil, scriptError(ErrInvalidFlags,
|
||||
"invalid flags combination")
|
||||
}
|
||||
|
||||
// The signature script must only contain data pushes when the
|
||||
// associated flag is set.
|
||||
if vm.hasFlag(ScriptVerifySigPushOnly) && !IsPushOnlyScript(scriptSig) {
|
||||
parsedScriptSig, err := parseScriptAndVerifySize(scriptSig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The signature script must only contain data pushes
|
||||
if !isPushOnly(parsedScriptSig) {
|
||||
return nil, scriptError(ErrNotPushOnly,
|
||||
"signature script is not push only")
|
||||
}
|
||||
|
||||
parsedScriptPubKey, err := parseScriptAndVerifySize(scriptPubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The engine stores the scripts in parsed form using a slice. This
|
||||
// allows multiple scripts to be executed in sequence. For example,
|
||||
// with a pay-to-script-hash transaction, there will be ultimately be
|
||||
// a third script to execute.
|
||||
scripts := [][]byte{scriptSig, scriptPubKey}
|
||||
vm.scripts = make([][]parsedOpcode, len(scripts))
|
||||
for i, scr := range scripts {
|
||||
if len(scr) > MaxScriptSize {
|
||||
str := fmt.Sprintf("script size %d is larger than max "+
|
||||
"allowed size %d", len(scr), MaxScriptSize)
|
||||
return nil, scriptError(ErrScriptTooBig, str)
|
||||
}
|
||||
var err error
|
||||
vm.scripts[i], err = parseScript(scr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
vm.scripts = [][]parsedOpcode{parsedScriptSig, parsedScriptPubKey}
|
||||
|
||||
// Advance the program counter to the public key script if the signature
|
||||
// script is empty since there is nothing to execute for it in that
|
||||
// case.
|
||||
if len(scripts[0]) == 0 {
|
||||
if len(scriptSig) == 0 {
|
||||
vm.scriptIdx++
|
||||
}
|
||||
|
||||
if vm.hasFlag(ScriptBip16) && isScriptHash(vm.scripts[1]) {
|
||||
if isScriptHash(vm.scripts[1]) {
|
||||
// Only accept input scripts that push data for P2SH.
|
||||
if !isPushOnly(vm.scripts[0]) {
|
||||
return nil, scriptError(ErrNotPushOnly,
|
||||
"pay to script hash is not push only")
|
||||
}
|
||||
vm.bip16 = true
|
||||
}
|
||||
if vm.hasFlag(ScriptVerifyMinimalData) {
|
||||
vm.dstack.verifyMinimalData = true
|
||||
vm.astack.verifyMinimalData = true
|
||||
vm.isP2SH = true
|
||||
}
|
||||
|
||||
vm.tx = *tx
|
||||
@ -687,3 +630,12 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags
|
||||
|
||||
return &vm, nil
|
||||
}
|
||||
|
||||
func parseScriptAndVerifySize(script []byte) ([]parsedOpcode, error) {
|
||||
if len(script) > MaxScriptSize {
|
||||
str := fmt.Sprintf("script size %d is larger than max "+
|
||||
"allowed size %d", len(script), MaxScriptSize)
|
||||
return nil, scriptError(ErrScriptTooBig, str)
|
||||
}
|
||||
return parseScript(script)
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ func TestBadPC(t *testing.T) {
|
||||
}),
|
||||
Index: 0,
|
||||
},
|
||||
SignatureScript: mustParseShortForm("NOP"),
|
||||
SignatureScript: mustParseShortForm(""),
|
||||
Sequence: 4294967295,
|
||||
},
|
||||
},
|
||||
@ -145,56 +145,6 @@ func TestCheckErrorCondition(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestInvalidFlagCombinations ensures the script engine returns the expected
|
||||
// error when disallowed flag combinations are specified.
|
||||
func TestInvalidFlagCombinations(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []ScriptFlags{
|
||||
ScriptVerifyCleanStack,
|
||||
}
|
||||
|
||||
// tx with almost empty scripts.
|
||||
tx := &wire.MsgTx{
|
||||
Version: 1,
|
||||
TxIn: []*wire.TxIn{
|
||||
{
|
||||
PreviousOutPoint: wire.OutPoint{
|
||||
Hash: daghash.Hash([32]byte{
|
||||
0xc9, 0x97, 0xa5, 0xe5,
|
||||
0x6e, 0x10, 0x41, 0x02,
|
||||
0xfa, 0x20, 0x9c, 0x6a,
|
||||
0x85, 0x2d, 0xd9, 0x06,
|
||||
0x60, 0xa2, 0x0b, 0x2d,
|
||||
0x9c, 0x35, 0x24, 0x23,
|
||||
0xed, 0xce, 0x25, 0x85,
|
||||
0x7f, 0xcd, 0x37, 0x04,
|
||||
}),
|
||||
Index: 0,
|
||||
},
|
||||
SignatureScript: []uint8{OpNop},
|
||||
Sequence: 4294967295,
|
||||
},
|
||||
},
|
||||
TxOut: []*wire.TxOut{
|
||||
{
|
||||
Value: 1000000000,
|
||||
PkScript: nil,
|
||||
},
|
||||
},
|
||||
LockTime: 0,
|
||||
}
|
||||
pkScript := []byte{OpNop}
|
||||
|
||||
for i, test := range tests {
|
||||
_, err := NewEngine(pkScript, tx, 0, test, nil)
|
||||
if !IsErrorCode(err, ErrInvalidFlags) {
|
||||
t.Fatalf("TestInvalidFlagCombinations #%d unexpected "+
|
||||
"error: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckPubKeyEncoding ensures the internal checkPubKeyEncoding function
|
||||
// works as expected.
|
||||
func TestCheckPubKeyEncoding(t *testing.T) {
|
||||
@ -240,7 +190,7 @@ func TestCheckPubKeyEncoding(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
vm := Engine{flags: ScriptVerifyStrictEncoding}
|
||||
vm := Engine{}
|
||||
for _, test := range tests {
|
||||
err := vm.checkPubKeyEncoding(test.key)
|
||||
if err != nil && test.isValid {
|
||||
@ -412,7 +362,7 @@ func TestCheckSignatureEncoding(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
vm := Engine{flags: ScriptVerifyStrictEncoding}
|
||||
vm := Engine{}
|
||||
for _, test := range tests {
|
||||
err := vm.checkSignatureEncoding(test.sig)
|
||||
if err != nil && test.isValid {
|
||||
|
@ -166,9 +166,8 @@ const (
|
||||
// Failures related to malleability.
|
||||
// ---------------------------------
|
||||
|
||||
// ErrMinimalData is returned when the ScriptVerifyMinimalData flag
|
||||
// is set and the script contains push operations that do not use
|
||||
// the minimal opcode required.
|
||||
// ErrMinimalData is returned when the script contains
|
||||
// push operations that do not use the minimal opcode required.
|
||||
ErrMinimalData
|
||||
|
||||
// ErrInvalidSigHashType is returned when a signature hash type is not
|
||||
@ -189,23 +188,20 @@ const (
|
||||
ErrSigHighS
|
||||
|
||||
// ErrNotPushOnly is returned when a script that is required to only
|
||||
// push data to the stack performs other operations. A couple of cases
|
||||
// where this applies is for a pay-to-script-hash signature script when
|
||||
// bip16 is active and when the ScriptVerifySigPushOnly flag is set.
|
||||
// push data to the stack performs other operations.
|
||||
ErrNotPushOnly
|
||||
|
||||
// ErrPubKeyType is returned when the ScriptVerifyStrictEncoding
|
||||
// flag is set and the script contains invalid public keys.
|
||||
ErrPubKeyType
|
||||
// ErrPubKeyFormat is returned when the script contains invalid public keys.
|
||||
// A valid pubkey should be in uncompressed format as a 64 byte string prefixed with 0x04,
|
||||
// or to be in compressed format as a 32 byte string prefixed with 0x02 or 0x03 to signal oddness.
|
||||
ErrPubKeyFormat
|
||||
|
||||
// ErrCleanStack is returned when the ScriptVerifyCleanStack flag
|
||||
// is set, and after evalution, the stack does not contain only a
|
||||
// single element.
|
||||
// ErrCleanStack is returned when after evalution, the stack
|
||||
// contains more than one element.
|
||||
ErrCleanStack
|
||||
|
||||
// ErrNullFail is returned when the ScriptVerifyNullFail flag is
|
||||
// set and signatures are not empty on failed checksig or checkmultisig
|
||||
// operations.
|
||||
// ErrNullFail is returned when signatures are not empty
|
||||
// on failed checksig or checkmultisig operations.
|
||||
ErrNullFail
|
||||
|
||||
// -------------------------------
|
||||
@ -268,7 +264,7 @@ var errorCodeStrings = map[ErrorCode]string{
|
||||
ErrSigDER: "ErrSigDER",
|
||||
ErrSigHighS: "ErrSigHighS",
|
||||
ErrNotPushOnly: "ErrNotPushOnly",
|
||||
ErrPubKeyType: "ErrPubKeyType",
|
||||
ErrPubKeyFormat: "ErrPubKeyFormat",
|
||||
ErrCleanStack: "ErrCleanStack",
|
||||
ErrNullFail: "ErrNullFail",
|
||||
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
|
||||
|
@ -51,7 +51,7 @@ func TestErrorCodeStringer(t *testing.T) {
|
||||
{ErrSigDER, "ErrSigDER"},
|
||||
{ErrSigHighS, "ErrSigHighS"},
|
||||
{ErrNotPushOnly, "ErrNotPushOnly"},
|
||||
{ErrPubKeyType, "ErrPubKeyType"},
|
||||
{ErrPubKeyFormat, "ErrPubKeyFormat"},
|
||||
{ErrCleanStack, "ErrCleanStack"},
|
||||
{ErrNullFail, "ErrNullFail"},
|
||||
{ErrDiscourageUpgradableNOPs, "ErrDiscourageUpgradableNOPs"},
|
||||
|
@ -162,8 +162,7 @@ func ExampleSignTxOutput() {
|
||||
|
||||
// Prove that the transaction has been validly signed by executing the
|
||||
// script pair.
|
||||
flags := txscript.ScriptBip16 |
|
||||
txscript.ScriptDiscourageUpgradableNops
|
||||
flags := txscript.ScriptDiscourageUpgradableNops
|
||||
vm, err := txscript.NewEngine(originTx.TxOut[0].PkScript, redeemTx, 0, flags, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
@ -1101,7 +1101,7 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lockTime, err := makeScriptNum(so, vm.dstack.verifyMinimalData, 5)
|
||||
lockTime, err := makeScriptNum(so, 5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1164,7 +1164,7 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stackSequence, err := makeScriptNum(so, vm.dstack.verifyMinimalData, 5)
|
||||
stackSequence, err := makeScriptNum(so, 5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -2043,7 +2043,7 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
|
||||
valid = signature.Verify(hash, pubKey)
|
||||
}
|
||||
|
||||
if !valid && vm.hasFlag(ScriptVerifyNullFail) && len(sigBytes) > 0 {
|
||||
if !valid && len(sigBytes) > 0 {
|
||||
str := "signature not empty on failed checksig"
|
||||
return scriptError(ErrNullFail, str)
|
||||
}
|
||||
@ -2248,7 +2248,7 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
|
||||
}
|
||||
}
|
||||
|
||||
if !success && vm.hasFlag(ScriptVerifyNullFail) {
|
||||
if !success {
|
||||
for _, sig := range signatures {
|
||||
if len(sig.signature) > 0 {
|
||||
str := "not all signatures empty on failed checkmultisig"
|
||||
|
@ -133,24 +133,8 @@ func parseScriptFlags(flagStr string) (ScriptFlags, error) {
|
||||
switch flag {
|
||||
case "":
|
||||
// Nothing.
|
||||
case "CLEANSTACK":
|
||||
flags |= ScriptVerifyCleanStack
|
||||
case "DISCOURAGE_UPGRADABLE_NOPS":
|
||||
flags |= ScriptDiscourageUpgradableNops
|
||||
case "LOW_S":
|
||||
flags |= ScriptVerifyLowS
|
||||
case "MINIMALDATA":
|
||||
flags |= ScriptVerifyMinimalData
|
||||
case "NONE":
|
||||
// Nothing.
|
||||
case "NULLFAIL":
|
||||
flags |= ScriptVerifyNullFail
|
||||
case "P2SH":
|
||||
flags |= ScriptBip16
|
||||
case "SIGPUSHONLY":
|
||||
flags |= ScriptVerifySigPushOnly
|
||||
case "STRICTENC":
|
||||
flags |= ScriptVerifyStrictEncoding
|
||||
default:
|
||||
return flags, fmt.Errorf("invalid flag: %s", flag)
|
||||
}
|
||||
@ -167,12 +151,14 @@ func parseExpectedResult(expected string) ([]ErrorCode, error) {
|
||||
return nil, nil
|
||||
case "UNKNOWN_ERROR":
|
||||
return []ErrorCode{ErrNumberTooBig, ErrMinimalData}, nil
|
||||
case "PUBKEYTYPE":
|
||||
return []ErrorCode{ErrPubKeyType}, nil
|
||||
case "PUBKEYFORMAT":
|
||||
return []ErrorCode{ErrPubKeyFormat}, nil
|
||||
case "SIG_DER":
|
||||
return []ErrorCode{ErrSigDER, ErrInvalidSigHashType}, nil
|
||||
case "EVAL_FALSE":
|
||||
return []ErrorCode{ErrEvalFalse, ErrEmptyStack}, nil
|
||||
case "EMPTY_STACK":
|
||||
return []ErrorCode{ErrEmptyStack}, nil
|
||||
case "EQUALVERIFY":
|
||||
return []ErrorCode{ErrEqualVerify}, nil
|
||||
case "NULLFAIL":
|
||||
|
@ -8,17 +8,11 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/daglabs/btcd/dagconfig/daghash"
|
||||
"github.com/daglabs/btcd/wire"
|
||||
)
|
||||
|
||||
// Bip16Activation is the timestamp where BIP0016 is valid to use in the
|
||||
// blockchain. To be used to determine if BIP0016 should be called for or not.
|
||||
// This timestamp corresponds to Sun Apr 1 00:00:00 UTC 2012.
|
||||
var Bip16Activation = time.Unix(1333238400, 0)
|
||||
|
||||
// SigHashType represents hash type bits at the end of a signature.
|
||||
type SigHashType uint32
|
||||
|
||||
@ -424,17 +418,17 @@ func GetSigOpCount(script []byte) int {
|
||||
}
|
||||
|
||||
// GetPreciseSigOpCount returns the number of signature operations in
|
||||
// scriptPubKey. If bip16 is true then scriptSig may be searched for the
|
||||
// scriptPubKey. If p2sh is true then scriptSig may be searched for the
|
||||
// Pay-To-Script-Hash script in order to find the precise number of signature
|
||||
// operations in the transaction. If the script fails to parse, then the count
|
||||
// up to the point of failure is returned.
|
||||
func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int {
|
||||
func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, isP2SH bool) int {
|
||||
// Don't check error since parseScript returns the parsed-up-to-error
|
||||
// list of pops.
|
||||
pops, _ := parseScript(scriptPubKey)
|
||||
|
||||
// Treat non P2SH transactions as normal.
|
||||
if !(bip16 && isScriptHash(pops)) {
|
||||
if !(isP2SH && isScriptHash(pops)) {
|
||||
return getSigOpCount(pops, true)
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,11 @@ type scriptNum int64
|
||||
|
||||
// checkMinimalDataEncoding returns whether or not the passed byte array adheres
|
||||
// to the minimal encoding requirements.
|
||||
// An error will be returned if it will determined that
|
||||
// the encoding is not represented with the smallest possible
|
||||
// number of bytes or is the negative 0 encoding, [0x80]. For example, consider
|
||||
// the number 127. It could be encoded as [0x7f], [0x7f 0x00],
|
||||
// [0x7f 0x00 0x00 ...], etc. All forms except [0x7f] will return an error
|
||||
func checkMinimalDataEncoding(v []byte) error {
|
||||
if len(v) == 0 {
|
||||
return nil
|
||||
@ -167,13 +172,6 @@ func (n scriptNum) Int32() int32 {
|
||||
// bytes and therefore will pass that value to this function resulting in an
|
||||
// allowed range of [-2^31 + 1, 2^31 - 1].
|
||||
//
|
||||
// The requireMinimal flag causes an error to be returned if additional checks
|
||||
// on the encoding determine it is not represented with the smallest possible
|
||||
// number of bytes or is the negative 0 encoding, [0x80]. For example, consider
|
||||
// the number 127. It could be encoded as [0x7f], [0x7f 0x00],
|
||||
// [0x7f 0x00 0x00 ...], etc. All forms except [0x7f] will return an error with
|
||||
// requireMinimal enabled.
|
||||
//
|
||||
// The scriptNumLen is the maximum number of bytes the encoded value can be
|
||||
// before an ErrStackNumberTooBig is returned. This effectively limits the
|
||||
// range of allowed values.
|
||||
@ -182,7 +180,7 @@ func (n scriptNum) Int32() int32 {
|
||||
// overflows.
|
||||
//
|
||||
// See the Bytes function documentation for example encodings.
|
||||
func makeScriptNum(v []byte, requireMinimal bool, scriptNumLen int) (scriptNum, error) {
|
||||
func makeScriptNum(v []byte, scriptNumLen int) (scriptNum, error) {
|
||||
// Interpreting data requires that it is not larger than
|
||||
// the the passed scriptNumLen value.
|
||||
if len(v) > scriptNumLen {
|
||||
@ -192,11 +190,8 @@ func makeScriptNum(v []byte, requireMinimal bool, scriptNumLen int) (scriptNum,
|
||||
return 0, scriptError(ErrNumberTooBig, str)
|
||||
}
|
||||
|
||||
// Enforce minimal encoded if requested.
|
||||
if requireMinimal {
|
||||
if err := checkMinimalDataEncoding(v); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := checkMinimalDataEncoding(v); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Zero is encoded as an empty byte slice.
|
||||
|
@ -97,105 +97,88 @@ func TestMakeScriptNum(t *testing.T) {
|
||||
errMinimalData := scriptError(ErrMinimalData, "")
|
||||
|
||||
tests := []struct {
|
||||
serialized []byte
|
||||
num scriptNum
|
||||
numLen int
|
||||
minimalEncoding bool
|
||||
err error
|
||||
serialized []byte
|
||||
num scriptNum
|
||||
numLen int
|
||||
err error
|
||||
}{
|
||||
// Minimal encoding must reject negative 0.
|
||||
{hexToBytes("80"), 0, defaultScriptNumLen, true, errMinimalData},
|
||||
{hexToBytes("80"), 0, defaultScriptNumLen, errMinimalData},
|
||||
|
||||
// Minimally encoded valid values with minimal encoding flag.
|
||||
// Should not error and return expected integral number.
|
||||
{nil, 0, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("01"), 1, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("81"), -1, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("7f"), 127, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("ff"), -127, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("8000"), 128, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("8080"), -128, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("8100"), 129, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("8180"), -129, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("0001"), 256, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("0081"), -256, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("ff7f"), 32767, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("ffff"), -32767, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("008000"), 32768, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("008080"), -32768, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("ffff00"), 65535, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("ffff80"), -65535, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("000008"), 524288, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("000088"), -524288, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("000070"), 7340032, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("0000f0"), -7340032, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("00008000"), 8388608, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("00008080"), -8388608, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("ffffff7f"), 2147483647, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("ffffffff"), -2147483647, defaultScriptNumLen, true, nil},
|
||||
{hexToBytes("ffffffff7f"), 549755813887, 5, true, nil},
|
||||
{hexToBytes("ffffffffff"), -549755813887, 5, true, nil},
|
||||
{hexToBytes("ffffffffffffff7f"), 9223372036854775807, 8, true, nil},
|
||||
{hexToBytes("ffffffffffffffff"), -9223372036854775807, 8, true, nil},
|
||||
{hexToBytes("ffffffffffffffff7f"), -1, 9, true, nil},
|
||||
{hexToBytes("ffffffffffffffffff"), 1, 9, true, nil},
|
||||
{hexToBytes("ffffffffffffffffff7f"), -1, 10, true, nil},
|
||||
{hexToBytes("ffffffffffffffffffff"), 1, 10, true, nil},
|
||||
{nil, 0, defaultScriptNumLen, nil},
|
||||
{hexToBytes("01"), 1, defaultScriptNumLen, nil},
|
||||
{hexToBytes("81"), -1, defaultScriptNumLen, nil},
|
||||
{hexToBytes("7f"), 127, defaultScriptNumLen, nil},
|
||||
{hexToBytes("ff"), -127, defaultScriptNumLen, nil},
|
||||
{hexToBytes("8000"), 128, defaultScriptNumLen, nil},
|
||||
{hexToBytes("8080"), -128, defaultScriptNumLen, nil},
|
||||
{hexToBytes("8100"), 129, defaultScriptNumLen, nil},
|
||||
{hexToBytes("8180"), -129, defaultScriptNumLen, nil},
|
||||
{hexToBytes("0001"), 256, defaultScriptNumLen, nil},
|
||||
{hexToBytes("0081"), -256, defaultScriptNumLen, nil},
|
||||
{hexToBytes("ff7f"), 32767, defaultScriptNumLen, nil},
|
||||
{hexToBytes("ffff"), -32767, defaultScriptNumLen, nil},
|
||||
{hexToBytes("008000"), 32768, defaultScriptNumLen, nil},
|
||||
{hexToBytes("008080"), -32768, defaultScriptNumLen, nil},
|
||||
{hexToBytes("ffff00"), 65535, defaultScriptNumLen, nil},
|
||||
{hexToBytes("ffff80"), -65535, defaultScriptNumLen, nil},
|
||||
{hexToBytes("000008"), 524288, defaultScriptNumLen, nil},
|
||||
{hexToBytes("000088"), -524288, defaultScriptNumLen, nil},
|
||||
{hexToBytes("000070"), 7340032, defaultScriptNumLen, nil},
|
||||
{hexToBytes("0000f0"), -7340032, defaultScriptNumLen, nil},
|
||||
{hexToBytes("00008000"), 8388608, defaultScriptNumLen, nil},
|
||||
{hexToBytes("00008080"), -8388608, defaultScriptNumLen, nil},
|
||||
{hexToBytes("ffffff7f"), 2147483647, defaultScriptNumLen, nil},
|
||||
{hexToBytes("ffffffff"), -2147483647, defaultScriptNumLen, nil},
|
||||
{hexToBytes("ffffffff7f"), 549755813887, 5, nil},
|
||||
{hexToBytes("ffffffffff"), -549755813887, 5, nil},
|
||||
{hexToBytes("ffffffffffffff7f"), 9223372036854775807, 8, nil},
|
||||
{hexToBytes("ffffffffffffffff"), -9223372036854775807, 8, nil},
|
||||
{hexToBytes("ffffffffffffffff7f"), -1, 9, nil},
|
||||
{hexToBytes("ffffffffffffffffff"), 1, 9, nil},
|
||||
{hexToBytes("ffffffffffffffffff7f"), -1, 10, nil},
|
||||
{hexToBytes("ffffffffffffffffffff"), 1, 10, nil},
|
||||
|
||||
// Minimally encoded values that are out of range for data that
|
||||
// is interpreted as script numbers with the minimal encoding
|
||||
// flag set. Should error and return 0.
|
||||
{hexToBytes("0000008000"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("0000008080"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("0000009000"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("0000009080"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("ffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("ffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("0000000001"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("0000000081"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("ffffffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("ffffffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("ffffffffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("ffffffffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("ffffffffffffff7f"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("ffffffffffffffff"), 0, defaultScriptNumLen, true, errNumTooBig},
|
||||
{hexToBytes("0000008000"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("0000008080"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("0000009000"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("0000009080"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("ffffffff00"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("ffffffff80"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("0000000001"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("0000000081"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("ffffffffffff00"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("ffffffffffff80"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("ffffffffffffff00"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("ffffffffffffff80"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("ffffffffffffff7f"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
{hexToBytes("ffffffffffffffff"), 0, defaultScriptNumLen, errNumTooBig},
|
||||
|
||||
// Non-minimally encoded, but otherwise valid values with
|
||||
// minimal encoding flag. Should error and return 0.
|
||||
{hexToBytes("00"), 0, defaultScriptNumLen, true, errMinimalData}, // 0
|
||||
{hexToBytes("0100"), 0, defaultScriptNumLen, true, errMinimalData}, // 1
|
||||
{hexToBytes("7f00"), 0, defaultScriptNumLen, true, errMinimalData}, // 127
|
||||
{hexToBytes("800000"), 0, defaultScriptNumLen, true, errMinimalData}, // 128
|
||||
{hexToBytes("810000"), 0, defaultScriptNumLen, true, errMinimalData}, // 129
|
||||
{hexToBytes("000100"), 0, defaultScriptNumLen, true, errMinimalData}, // 256
|
||||
{hexToBytes("ff7f00"), 0, defaultScriptNumLen, true, errMinimalData}, // 32767
|
||||
{hexToBytes("00800000"), 0, defaultScriptNumLen, true, errMinimalData}, // 32768
|
||||
{hexToBytes("ffff0000"), 0, defaultScriptNumLen, true, errMinimalData}, // 65535
|
||||
{hexToBytes("00000800"), 0, defaultScriptNumLen, true, errMinimalData}, // 524288
|
||||
{hexToBytes("00007000"), 0, defaultScriptNumLen, true, errMinimalData}, // 7340032
|
||||
{hexToBytes("0009000100"), 0, 5, true, errMinimalData}, // 16779520
|
||||
|
||||
// Non-minimally encoded, but otherwise valid values without
|
||||
// minimal encoding flag. Should not error and return expected
|
||||
// integral number.
|
||||
{hexToBytes("00"), 0, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("0100"), 1, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("7f00"), 127, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("800000"), 128, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("810000"), 129, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("000100"), 256, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("ff7f00"), 32767, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("00800000"), 32768, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("ffff0000"), 65535, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("00000800"), 524288, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("00007000"), 7340032, defaultScriptNumLen, false, nil},
|
||||
{hexToBytes("0009000100"), 16779520, 5, false, nil},
|
||||
{hexToBytes("00"), 0, defaultScriptNumLen, errMinimalData}, // 0
|
||||
{hexToBytes("0100"), 0, defaultScriptNumLen, errMinimalData}, // 1
|
||||
{hexToBytes("7f00"), 0, defaultScriptNumLen, errMinimalData}, // 127
|
||||
{hexToBytes("800000"), 0, defaultScriptNumLen, errMinimalData}, // 128
|
||||
{hexToBytes("810000"), 0, defaultScriptNumLen, errMinimalData}, // 129
|
||||
{hexToBytes("000100"), 0, defaultScriptNumLen, errMinimalData}, // 256
|
||||
{hexToBytes("ff7f00"), 0, defaultScriptNumLen, errMinimalData}, // 32767
|
||||
{hexToBytes("00800000"), 0, defaultScriptNumLen, errMinimalData}, // 32768
|
||||
{hexToBytes("ffff0000"), 0, defaultScriptNumLen, errMinimalData}, // 65535
|
||||
{hexToBytes("00000800"), 0, defaultScriptNumLen, errMinimalData}, // 524288
|
||||
{hexToBytes("00007000"), 0, defaultScriptNumLen, errMinimalData}, // 7340032
|
||||
{hexToBytes("0009000100"), 0, 5, errMinimalData}, // 16779520
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
// Ensure the error code is of the expected type and the error
|
||||
// code matches the value specified in the test instance.
|
||||
gotNum, err := makeScriptNum(test.serialized, test.minimalEncoding,
|
||||
gotNum, err := makeScriptNum(test.serialized,
|
||||
test.numLen)
|
||||
if e := tstCheckScriptError(err, test.err); e != nil {
|
||||
t.Errorf("makeScriptNum(%#x): %v", test.serialized, e)
|
||||
|
@ -314,9 +314,7 @@ sigLoop:
|
||||
}
|
||||
}
|
||||
|
||||
// Extra opcode to handle the extra arg consumed (due to previous bugs
|
||||
// in the reference implementation).
|
||||
builder := NewScriptBuilder().AddOp(OpFalse)
|
||||
builder := NewScriptBuilder()
|
||||
doneSigs := 0
|
||||
// This assumes that addresses are in the same order as in the script.
|
||||
for _, addr := range addresses {
|
||||
|
@ -55,8 +55,9 @@ func mkGetScript(scripts map[string][]byte) ScriptDB {
|
||||
|
||||
func checkScripts(msg string, tx *wire.MsgTx, idx int, sigScript, pkScript []byte) error {
|
||||
tx.TxIn[idx].SignatureScript = sigScript
|
||||
var flags ScriptFlags
|
||||
vm, err := NewEngine(pkScript, tx, idx,
|
||||
ScriptBip16, nil)
|
||||
flags, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to make script engine for %s: %v",
|
||||
msg, err)
|
||||
@ -91,7 +92,6 @@ func TestSignTxOutput(t *testing.T) {
|
||||
// make script based on key.
|
||||
// sign with magic pixie dust.
|
||||
hashTypes := []SigHashType{
|
||||
SigHashOld, // no longer used but should act like all
|
||||
SigHashAll,
|
||||
SigHashNone,
|
||||
SigHashSingle,
|
||||
@ -1498,7 +1498,7 @@ var sigScriptTests = []tstSigScript{
|
||||
scriptAtWrongIndex: false,
|
||||
},
|
||||
{
|
||||
name: "hashType SigHashAnyoneCanPay",
|
||||
name: "hashType SigHashAll | SigHashAnyoneCanPay",
|
||||
inputs: []tstInput{
|
||||
{
|
||||
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
|
||||
@ -1507,17 +1507,31 @@ var sigScriptTests = []tstSigScript{
|
||||
indexOutOfRange: false,
|
||||
},
|
||||
},
|
||||
hashType: SigHashAll | SigHashAnyOneCanPay,
|
||||
compress: false,
|
||||
scriptAtWrongIndex: false,
|
||||
},
|
||||
{
|
||||
name: "hashType SigHashAnyoneCanPay",
|
||||
inputs: []tstInput{
|
||||
{
|
||||
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
|
||||
sigscriptGenerates: true,
|
||||
inputValidates: false,
|
||||
indexOutOfRange: false,
|
||||
},
|
||||
},
|
||||
hashType: SigHashAnyOneCanPay,
|
||||
compress: false,
|
||||
scriptAtWrongIndex: false,
|
||||
},
|
||||
{
|
||||
name: "hashType non-standard",
|
||||
name: "hashType non-exist",
|
||||
inputs: []tstInput{
|
||||
{
|
||||
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
|
||||
sigscriptGenerates: true,
|
||||
inputValidates: true,
|
||||
inputValidates: false,
|
||||
indexOutOfRange: false,
|
||||
},
|
||||
},
|
||||
@ -1658,7 +1672,7 @@ nexttest:
|
||||
}
|
||||
|
||||
// Validate tx input scripts
|
||||
scriptFlags := ScriptBip16
|
||||
var scriptFlags ScriptFlags
|
||||
for j := range tx.TxIn {
|
||||
vm, err := NewEngine(sigScriptTests[i].
|
||||
inputs[j].txout.PkScript, tx, j, scriptFlags, nil)
|
||||
|
@ -36,8 +36,7 @@ func fromBool(v bool) []byte {
|
||||
// changed it *must* be deep-copied first to avoid changing other values on the
|
||||
// stack.
|
||||
type stack struct {
|
||||
stk [][]byte
|
||||
verifyMinimalData bool
|
||||
stk [][]byte
|
||||
}
|
||||
|
||||
// Depth returns the number of items on the stack.
|
||||
@ -86,7 +85,7 @@ func (s *stack) PopInt() (scriptNum, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
|
||||
return makeScriptNum(so, defaultScriptNumLen)
|
||||
}
|
||||
|
||||
// PopBool pops the value off the top of the stack, converts it into a bool, and
|
||||
@ -123,7 +122,7 @@ func (s *stack) PeekInt(idx int32) (scriptNum, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
|
||||
return makeScriptNum(so, defaultScriptNumLen)
|
||||
}
|
||||
|
||||
// PeekBool returns the Nth item on the stack as a bool without removing it.
|
||||
|
@ -186,7 +186,7 @@ func TestStack(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"popInt 0",
|
||||
[][]byte{{0x0}},
|
||||
[][]byte{{}},
|
||||
func(s *stack) error {
|
||||
v, err := s.PopInt()
|
||||
if err != nil {
|
||||
@ -200,22 +200,6 @@ func TestStack(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"popInt -0",
|
||||
[][]byte{{0x80}},
|
||||
func(s *stack) error {
|
||||
v, err := s.PopInt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v != 0 {
|
||||
return errors.New("-0 != 0 on popInt")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"popInt 1",
|
||||
[][]byte{{0x01}},
|
||||
@ -232,23 +216,6 @@ func TestStack(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"popInt 1 leading 0",
|
||||
[][]byte{{0x01, 0x00, 0x00, 0x00}},
|
||||
func(s *stack) error {
|
||||
v, err := s.PopInt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v != 1 {
|
||||
fmt.Printf("%v != %v\n", v, 1)
|
||||
return errors.New("1 != 1 on popInt")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"popInt -1",
|
||||
[][]byte{{0x81}},
|
||||
@ -265,23 +232,6 @@ func TestStack(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"popInt -1 leading 0",
|
||||
[][]byte{{0x01, 0x00, 0x00, 0x80}},
|
||||
func(s *stack) error {
|
||||
v, err := s.PopInt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v != -1 {
|
||||
fmt.Printf("%v != %v\n", v, -1)
|
||||
return errors.New("-1 != -1 on popInt")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
// Triggers the multibyte case in asInt
|
||||
{
|
||||
"popInt -513",
|
||||
@ -300,24 +250,6 @@ func TestStack(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
// Confirm that the asInt code doesn't modify the base data.
|
||||
{
|
||||
"peekint nomodify -1",
|
||||
[][]byte{{0x01, 0x00, 0x00, 0x80}},
|
||||
func(s *stack) error {
|
||||
v, err := s.PeekInt(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v != -1 {
|
||||
fmt.Printf("%v != %v\n", v, -1)
|
||||
return errors.New("-1 != -1 on popInt")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
nil,
|
||||
[][]byte{{0x01, 0x00, 0x00, 0x80}},
|
||||
},
|
||||
{
|
||||
"PushInt 0",
|
||||
nil,
|
||||
@ -852,24 +784,6 @@ func TestStack(t *testing.T) {
|
||||
nil,
|
||||
[][]byte{{1}},
|
||||
},
|
||||
{
|
||||
"Peek int 2",
|
||||
[][]byte{{0}},
|
||||
func(s *stack) error {
|
||||
// Peek int is otherwise pretty well tested,
|
||||
// just check it works.
|
||||
val, err := s.PeekInt(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if val != 0 {
|
||||
return errors.New("invalid result")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
nil,
|
||||
[][]byte{{0}},
|
||||
},
|
||||
{
|
||||
"pop int",
|
||||
nil,
|
||||
|
@ -26,13 +26,7 @@ const (
|
||||
//
|
||||
// TODO: This definition does not belong here. It belongs in a policy
|
||||
// package.
|
||||
StandardVerifyFlags = ScriptBip16 |
|
||||
ScriptVerifyStrictEncoding |
|
||||
ScriptVerifyMinimalData |
|
||||
ScriptDiscourageUpgradableNops |
|
||||
ScriptVerifyCleanStack |
|
||||
ScriptVerifyNullFail |
|
||||
ScriptVerifyLowS
|
||||
StandardVerifyFlags = ScriptDiscourageUpgradableNops
|
||||
)
|
||||
|
||||
// ScriptClass is an enumeration for the list of standard types of script.
|
||||
@ -227,7 +221,7 @@ type ScriptInfo struct {
|
||||
// pair. It will error if the pair is in someway invalid such that they can not
|
||||
// be analysed, i.e. if they do not parse or the pkScript is not a push-only
|
||||
// script
|
||||
func CalcScriptInfo(sigScript, pkScript []byte, bip16 bool) (*ScriptInfo, error) {
|
||||
func CalcScriptInfo(sigScript, pkScript []byte, isP2SH bool) (*ScriptInfo, error) {
|
||||
sigPops, err := parseScript(sigScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -253,7 +247,7 @@ func CalcScriptInfo(sigScript, pkScript []byte, bip16 bool) (*ScriptInfo, error)
|
||||
// All entries pushed to stack (or are OP_RESERVED and exec will fail).
|
||||
si.NumInputs = len(sigPops)
|
||||
|
||||
if si.PkScriptClass == ScriptHashTy && bip16 {
|
||||
if si.PkScriptClass == ScriptHashTy && isP2SH {
|
||||
// The pay-to-hash-script is the final data push of the
|
||||
// signature script.
|
||||
script := sigPops[len(sigPops)-1].data
|
||||
@ -552,7 +546,7 @@ func ExtractAtomicSwapDataPushes(version uint16, pkScript []byte) (*AtomicSwapDa
|
||||
copy(pushes.RecipientHash160[:], pops[9].data)
|
||||
copy(pushes.RefundHash160[:], pops[16].data)
|
||||
if pops[2].data != nil {
|
||||
locktime, err := makeScriptNum(pops[2].data, true, 5)
|
||||
locktime, err := makeScriptNum(pops[2].data, 5)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
@ -563,7 +557,7 @@ func ExtractAtomicSwapDataPushes(version uint16, pkScript []byte) (*AtomicSwapDa
|
||||
return nil, nil
|
||||
}
|
||||
if pops[11].data != nil {
|
||||
locktime, err := makeScriptNum(pops[11].data, true, 5)
|
||||
locktime, err := makeScriptNum(pops[11].data, 5)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
||||
sigScript string
|
||||
pkScript string
|
||||
|
||||
bip16 bool
|
||||
isP2SH bool
|
||||
|
||||
scriptInfo ScriptInfo
|
||||
scriptInfoErr error
|
||||
@ -392,7 +392,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
||||
"SWAP ABS EQUAL",
|
||||
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
||||
"3152205ec4f59c",
|
||||
bip16: true,
|
||||
isP2SH: true,
|
||||
scriptInfoErr: scriptError(ErrMalformedPush, ""),
|
||||
},
|
||||
{
|
||||
@ -402,7 +402,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
||||
"SWAP ABS",
|
||||
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
||||
"3152205ec4f59c74 EQUAL",
|
||||
bip16: true,
|
||||
isP2SH: true,
|
||||
scriptInfoErr: scriptError(ErrMalformedPush, ""),
|
||||
},
|
||||
{
|
||||
@ -413,7 +413,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
||||
"CHECKSIG",
|
||||
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
||||
"3152205ec4f59c74 EQUAL",
|
||||
bip16: true,
|
||||
isP2SH: true,
|
||||
scriptInfo: ScriptInfo{
|
||||
PkScriptClass: ScriptHashTy,
|
||||
NumInputs: 3,
|
||||
@ -429,7 +429,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
||||
"SWAP ABS EQUAL",
|
||||
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
||||
"3152205ec4f59c74 EQUAL",
|
||||
bip16: true,
|
||||
isP2SH: true,
|
||||
scriptInfo: ScriptInfo{
|
||||
PkScriptClass: ScriptHashTy,
|
||||
NumInputs: 3,
|
||||
@ -449,7 +449,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
||||
"161718191a1b1c1d1e1f2021 DATA_33 0x010203040" +
|
||||
"5060708090a0b0c0d0e0f101112131415161718191a1" +
|
||||
"b1c1d1e1f2021 3 CHECKMULTISIG",
|
||||
bip16: true,
|
||||
isP2SH: true,
|
||||
scriptInfo: ScriptInfo{
|
||||
PkScriptClass: MultiSigTy,
|
||||
NumInputs: 4,
|
||||
@ -463,7 +463,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
||||
sigScript := mustParseShortForm(test.sigScript)
|
||||
pkScript := mustParseShortForm(test.pkScript)
|
||||
|
||||
si, err := CalcScriptInfo(sigScript, pkScript, test.bip16)
|
||||
si, err := CalcScriptInfo(sigScript, pkScript, test.isP2SH)
|
||||
if e := tstCheckScriptError(err, test.scriptInfoErr); e != nil {
|
||||
t.Errorf("scriptinfo test %q: %v", test.name, e)
|
||||
continue
|
||||
|
Loading…
x
Reference in New Issue
Block a user