mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-05 21:56:50 +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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptFlags := txscript.ScriptBip16
|
scriptFlags := txscript.ScriptNoFlags
|
||||||
err = checkBlockScripts(blocks[0], view, scriptFlags, nil)
|
err = checkBlockScripts(blocks[0], view, scriptFlags, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Transaction script validation failed: %v\n", err)
|
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
|
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
|
// The number of signature operations must be less than the maximum
|
||||||
// allowed per block. Note that the preliminary sanity checks on a
|
// allowed per block. Note that the preliminary sanity checks on a
|
||||||
// block also include a check similar to this one, but this check
|
// 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
|
totalSigOps := 0
|
||||||
for i, tx := range transactions {
|
for i, tx := range transactions {
|
||||||
numsigOps := CountSigOps(tx)
|
numsigOps := CountSigOps(tx)
|
||||||
if enforceBIP0016 {
|
// Since the first (and only the first) transaction has
|
||||||
// Since the first (and only the first) transaction has
|
// already been verified to be a coinbase transaction,
|
||||||
// already been verified to be a coinbase transaction,
|
// use i == 0 as an optimization for the flag to
|
||||||
// use i == 0 as an optimization for the flag to
|
// countP2SHSigOps for whether or not the transaction is
|
||||||
// countP2SHSigOps for whether or not the transaction is
|
// a coinbase transaction rather than having to do a
|
||||||
// a coinbase transaction rather than having to do a
|
// full coinbase check again.
|
||||||
// full coinbase check again.
|
numP2SHSigOps, err := CountP2SHSigOps(tx, i == 0, view)
|
||||||
numP2SHSigOps, err := CountP2SHSigOps(tx, i == 0, view)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
numsigOps += numP2SHSigOps
|
|
||||||
}
|
}
|
||||||
|
numsigOps += numP2SHSigOps
|
||||||
|
|
||||||
// Check for overflow or going over the limits. We have to do
|
// Check for overflow or going over the limits. We have to do
|
||||||
// this on every loop iteration to avoid overflow.
|
// this on every loop iteration to avoid overflow.
|
||||||
@ -1065,12 +1057,7 @@ func (dag *BlockDAG) checkConnectBlock(node *blockNode, block *util.Block, view
|
|||||||
runScripts = false
|
runScripts = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocks created after the BIP0016 activation time need to have the
|
scriptFlags := txscript.ScriptNoFlags
|
||||||
// pay-to-script-hash checks enabled.
|
|
||||||
var scriptFlags txscript.ScriptFlags
|
|
||||||
if enforceBIP0016 {
|
|
||||||
scriptFlags |= txscript.ScriptBip16
|
|
||||||
}
|
|
||||||
|
|
||||||
// We obtain the MTP of the *previous* block in order to
|
// We obtain the MTP of the *previous* block in order to
|
||||||
// determine if transactions in the current block are final.
|
// determine if transactions in the current block are final.
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
"github.com/daglabs/btcd/blockdag"
|
"github.com/daglabs/btcd/blockdag"
|
||||||
"github.com/daglabs/btcd/txscript"
|
"github.com/daglabs/btcd/txscript"
|
||||||
"github.com/daglabs/btcd/wire"
|
|
||||||
"github.com/daglabs/btcd/util"
|
"github.com/daglabs/btcd/util"
|
||||||
|
"github.com/daglabs/btcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -84,12 +84,7 @@ func calcMinRequiredTxRelayFee(serializedSize int64, minRelayTxFee util.Amount)
|
|||||||
// to ensure they are "standard". A standard transaction input within the
|
// 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
|
// 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
|
// standard form and, for pay-to-script-hash, does not have more than
|
||||||
// maxStandardP2SHSigOps signature operations. However, it should also be noted
|
// maxStandardP2SHSigOps signature operations.
|
||||||
// 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.
|
|
||||||
func checkInputsStandard(tx *util.Tx, utxoView *blockdag.UtxoViewpoint) error {
|
func checkInputsStandard(tx *util.Tx, utxoView *blockdag.UtxoViewpoint) error {
|
||||||
// NOTE: The reference implementation also does a coinbase check here,
|
// NOTE: The reference implementation also does a coinbase check here,
|
||||||
// but coinbases have already been rejected prior to calling this
|
// 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
|
type ScriptFlags uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ScriptBip16 defines whether the bip16 threshold has passed and thus
|
|
||||||
// pay-to-script hash transactions will be fully validated.
|
// ScriptNoFlags is used when you want to use ScriptFlags without raising any flags
|
||||||
ScriptBip16 ScriptFlags = 1 << iota
|
ScriptNoFlags ScriptFlags = 0
|
||||||
|
|
||||||
// ScriptDiscourageUpgradableNops defines whether to verify that
|
// ScriptDiscourageUpgradableNops defines whether to verify that
|
||||||
// NOP1 through NOP10 are reserved for future soft-fork upgrades. This
|
// 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
|
// blocks as this flag is only for stricter standard transaction
|
||||||
// checks. This flag is only applied when the above opcodes are
|
// checks. This flag is only applied when the above opcodes are
|
||||||
// executed.
|
// executed.
|
||||||
ScriptDiscourageUpgradableNops
|
ScriptDiscourageUpgradableNops ScriptFlags = 1 << iota
|
||||||
|
|
||||||
// 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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// MaxStackSize is the maximum combined height of stack and alt stack
|
// MaxStackSize is the maximum combined height of stack and alt stack
|
||||||
// during execution.
|
// during execution.
|
||||||
MaxStackSize = 1000
|
MaxStackSize = 244
|
||||||
|
|
||||||
// MaxScriptSize is the maximum allowed length of a raw script.
|
// MaxScriptSize is the maximum allowed length of a raw script.
|
||||||
MaxScriptSize = 10000
|
MaxScriptSize = 10000
|
||||||
@ -82,8 +55,8 @@ type Engine struct {
|
|||||||
numOps int
|
numOps int
|
||||||
flags ScriptFlags
|
flags ScriptFlags
|
||||||
sigCache *SigCache
|
sigCache *SigCache
|
||||||
bip16 bool // treat execution as pay-to-script-hash
|
isP2SH bool // treat execution as pay-to-script-hash
|
||||||
savedFirstStack [][]byte // stack from first script for bip16 scripts
|
savedFirstStack [][]byte // stack from first script for ps2h scripts
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasFlag returns whether the script engine instance has the passed flag set.
|
// 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
|
// Ensure all executed data push opcodes use the minimal encoding when
|
||||||
// the minimal data verification flag is set.
|
// the minimal data verification flag is set.
|
||||||
if vm.dstack.verifyMinimalData && vm.isBranchExecuting() &&
|
if vm.isBranchExecuting() &&
|
||||||
pop.opcode.value >= 0 && pop.opcode.value <= OpPushData4 {
|
pop.opcode.value >= 0 && pop.opcode.value <= OpPushData4 {
|
||||||
|
|
||||||
if err := pop.checkMinimalDataPush(); err != nil {
|
if err := pop.checkMinimalDataPush(); err != nil {
|
||||||
@ -228,15 +201,16 @@ func (vm *Engine) CheckErrorCondition(finalScript bool) error {
|
|||||||
"error check when script unfinished")
|
"error check when script unfinished")
|
||||||
}
|
}
|
||||||
|
|
||||||
if finalScript && vm.hasFlag(ScriptVerifyCleanStack) &&
|
if finalScript {
|
||||||
vm.dstack.Depth() != 1 {
|
if vm.dstack.Depth() > 1 {
|
||||||
|
|
||||||
str := fmt.Sprintf("stack contains %d unexpected items",
|
str := fmt.Sprintf("stack contains %d unexpected items",
|
||||||
vm.dstack.Depth()-1)
|
vm.dstack.Depth()-1)
|
||||||
return scriptError(ErrCleanStack, str)
|
return scriptError(ErrCleanStack, str)
|
||||||
} else if vm.dstack.Depth() < 1 {
|
} else if vm.dstack.Depth() < 1 {
|
||||||
return scriptError(ErrEmptyStack,
|
return scriptError(ErrEmptyStack,
|
||||||
"stack empty at end of script execution")
|
"stack empty at end of script execution")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := vm.dstack.PopBool()
|
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.numOps = 0 // number of ops is per script.
|
||||||
vm.scriptOff = 0
|
vm.scriptOff = 0
|
||||||
if vm.scriptIdx == 0 && vm.bip16 {
|
if vm.scriptIdx == 0 && vm.isP2SH {
|
||||||
vm.scriptIdx++
|
vm.scriptIdx++
|
||||||
vm.savedFirstStack = vm.GetStack()
|
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()
|
// Put us past the end for CheckErrorCondition()
|
||||||
vm.scriptIdx++
|
vm.scriptIdx++
|
||||||
// Check script ran successfully and pull the script
|
// 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
|
// checkHashTypeEncoding returns whether or not the passed hashtype adheres to
|
||||||
// the strict encoding requirements if enabled.
|
// the strict encoding requirements if enabled.
|
||||||
func (vm *Engine) checkHashTypeEncoding(hashType SigHashType) error {
|
func (vm *Engine) checkHashTypeEncoding(hashType SigHashType) error {
|
||||||
if !vm.hasFlag(ScriptVerifyStrictEncoding) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
sigHashType := hashType & ^SigHashAnyOneCanPay
|
sigHashType := hashType & ^SigHashAnyOneCanPay
|
||||||
if sigHashType < SigHashAll || sigHashType > SigHashSingle {
|
if sigHashType < SigHashAll || sigHashType > SigHashSingle {
|
||||||
str := fmt.Sprintf("invalid hash type 0x%x", hashType)
|
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
|
// checkPubKeyEncoding returns whether or not the passed public key adheres to
|
||||||
// the strict encoding requirements if enabled.
|
// the strict encoding requirements if enabled.
|
||||||
func (vm *Engine) checkPubKeyEncoding(pubKey []byte) error {
|
func (vm *Engine) checkPubKeyEncoding(pubKey []byte) error {
|
||||||
if !vm.hasFlag(ScriptVerifyStrictEncoding) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pubKey) == 33 && (pubKey[0] == 0x02 || pubKey[0] == 0x03) {
|
if len(pubKey) == 33 && (pubKey[0] == 0x02 || pubKey[0] == 0x03) {
|
||||||
// Compressed
|
// Compressed
|
||||||
return nil
|
return nil
|
||||||
@ -410,7 +376,7 @@ func (vm *Engine) checkPubKeyEncoding(pubKey []byte) error {
|
|||||||
return nil
|
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
|
// 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
|
// valid transaction with the complement while still being a valid
|
||||||
// signature that verifies. This would result in changing the
|
// signature that verifies. This would result in changing the
|
||||||
// transaction hash and thus is source of malleability.
|
// transaction hash and thus is source of malleability.
|
||||||
if vm.hasFlag(ScriptVerifyLowS) {
|
sValue := new(big.Int).SetBytes(sig[rLen+6 : rLen+6+sLen])
|
||||||
sValue := new(big.Int).SetBytes(sig[rLen+6 : rLen+6+sLen])
|
if sValue.Cmp(halfOrder) > 0 {
|
||||||
if sValue.Cmp(halfOrder) > 0 {
|
return scriptError(ErrSigHighS,
|
||||||
return scriptError(ErrSigHighS,
|
"signature is not canonical due to "+
|
||||||
"signature is not canonical due to "+
|
"unnecessarily high S value")
|
||||||
"unnecessarily high S value")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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")
|
"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}
|
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
|
parsedScriptSig, err := parseScriptAndVerifySize(scriptSig)
|
||||||
// associated flag is set.
|
if err != nil {
|
||||||
if vm.hasFlag(ScriptVerifySigPushOnly) && !IsPushOnlyScript(scriptSig) {
|
return nil, err
|
||||||
|
}
|
||||||
|
// The signature script must only contain data pushes
|
||||||
|
if !isPushOnly(parsedScriptSig) {
|
||||||
return nil, scriptError(ErrNotPushOnly,
|
return nil, scriptError(ErrNotPushOnly,
|
||||||
"signature script is not push only")
|
"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
|
// The engine stores the scripts in parsed form using a slice. This
|
||||||
// allows multiple scripts to be executed in sequence. For example,
|
// allows multiple scripts to be executed in sequence. For example,
|
||||||
// with a pay-to-script-hash transaction, there will be ultimately be
|
// with a pay-to-script-hash transaction, there will be ultimately be
|
||||||
// a third script to execute.
|
// a third script to execute.
|
||||||
scripts := [][]byte{scriptSig, scriptPubKey}
|
vm.scripts = [][]parsedOpcode{parsedScriptSig, parsedScriptPubKey}
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance the program counter to the public key script if the signature
|
// 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
|
// script is empty since there is nothing to execute for it in that
|
||||||
// case.
|
// case.
|
||||||
if len(scripts[0]) == 0 {
|
if len(scriptSig) == 0 {
|
||||||
vm.scriptIdx++
|
vm.scriptIdx++
|
||||||
}
|
}
|
||||||
|
|
||||||
if vm.hasFlag(ScriptBip16) && isScriptHash(vm.scripts[1]) {
|
if isScriptHash(vm.scripts[1]) {
|
||||||
// Only accept input scripts that push data for P2SH.
|
// Only accept input scripts that push data for P2SH.
|
||||||
if !isPushOnly(vm.scripts[0]) {
|
if !isPushOnly(vm.scripts[0]) {
|
||||||
return nil, scriptError(ErrNotPushOnly,
|
return nil, scriptError(ErrNotPushOnly,
|
||||||
"pay to script hash is not push only")
|
"pay to script hash is not push only")
|
||||||
}
|
}
|
||||||
vm.bip16 = true
|
vm.isP2SH = true
|
||||||
}
|
|
||||||
if vm.hasFlag(ScriptVerifyMinimalData) {
|
|
||||||
vm.dstack.verifyMinimalData = true
|
|
||||||
vm.astack.verifyMinimalData = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.tx = *tx
|
vm.tx = *tx
|
||||||
@ -687,3 +630,12 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags
|
|||||||
|
|
||||||
return &vm, nil
|
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,
|
Index: 0,
|
||||||
},
|
},
|
||||||
SignatureScript: mustParseShortForm("NOP"),
|
SignatureScript: mustParseShortForm(""),
|
||||||
Sequence: 4294967295,
|
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
|
// TestCheckPubKeyEncoding ensures the internal checkPubKeyEncoding function
|
||||||
// works as expected.
|
// works as expected.
|
||||||
func TestCheckPubKeyEncoding(t *testing.T) {
|
func TestCheckPubKeyEncoding(t *testing.T) {
|
||||||
@ -240,7 +190,7 @@ func TestCheckPubKeyEncoding(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
vm := Engine{flags: ScriptVerifyStrictEncoding}
|
vm := Engine{}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
err := vm.checkPubKeyEncoding(test.key)
|
err := vm.checkPubKeyEncoding(test.key)
|
||||||
if err != nil && test.isValid {
|
if err != nil && test.isValid {
|
||||||
@ -412,7 +362,7 @@ func TestCheckSignatureEncoding(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
vm := Engine{flags: ScriptVerifyStrictEncoding}
|
vm := Engine{}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
err := vm.checkSignatureEncoding(test.sig)
|
err := vm.checkSignatureEncoding(test.sig)
|
||||||
if err != nil && test.isValid {
|
if err != nil && test.isValid {
|
||||||
|
@ -166,9 +166,8 @@ const (
|
|||||||
// Failures related to malleability.
|
// Failures related to malleability.
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
|
|
||||||
// ErrMinimalData is returned when the ScriptVerifyMinimalData flag
|
// ErrMinimalData is returned when the script contains
|
||||||
// is set and the script contains push operations that do not use
|
// push operations that do not use the minimal opcode required.
|
||||||
// the minimal opcode required.
|
|
||||||
ErrMinimalData
|
ErrMinimalData
|
||||||
|
|
||||||
// ErrInvalidSigHashType is returned when a signature hash type is not
|
// ErrInvalidSigHashType is returned when a signature hash type is not
|
||||||
@ -189,23 +188,20 @@ const (
|
|||||||
ErrSigHighS
|
ErrSigHighS
|
||||||
|
|
||||||
// ErrNotPushOnly is returned when a script that is required to only
|
// ErrNotPushOnly is returned when a script that is required to only
|
||||||
// push data to the stack performs other operations. A couple of cases
|
// push data to the stack performs other operations.
|
||||||
// where this applies is for a pay-to-script-hash signature script when
|
|
||||||
// bip16 is active and when the ScriptVerifySigPushOnly flag is set.
|
|
||||||
ErrNotPushOnly
|
ErrNotPushOnly
|
||||||
|
|
||||||
// ErrPubKeyType is returned when the ScriptVerifyStrictEncoding
|
// ErrPubKeyFormat is returned when the script contains invalid public keys.
|
||||||
// flag is set and the script contains invalid public keys.
|
// A valid pubkey should be in uncompressed format as a 64 byte string prefixed with 0x04,
|
||||||
ErrPubKeyType
|
// 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
|
// ErrCleanStack is returned when after evalution, the stack
|
||||||
// is set, and after evalution, the stack does not contain only a
|
// contains more than one element.
|
||||||
// single element.
|
|
||||||
ErrCleanStack
|
ErrCleanStack
|
||||||
|
|
||||||
// ErrNullFail is returned when the ScriptVerifyNullFail flag is
|
// ErrNullFail is returned when signatures are not empty
|
||||||
// set and signatures are not empty on failed checksig or checkmultisig
|
// on failed checksig or checkmultisig operations.
|
||||||
// operations.
|
|
||||||
ErrNullFail
|
ErrNullFail
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
@ -268,7 +264,7 @@ var errorCodeStrings = map[ErrorCode]string{
|
|||||||
ErrSigDER: "ErrSigDER",
|
ErrSigDER: "ErrSigDER",
|
||||||
ErrSigHighS: "ErrSigHighS",
|
ErrSigHighS: "ErrSigHighS",
|
||||||
ErrNotPushOnly: "ErrNotPushOnly",
|
ErrNotPushOnly: "ErrNotPushOnly",
|
||||||
ErrPubKeyType: "ErrPubKeyType",
|
ErrPubKeyFormat: "ErrPubKeyFormat",
|
||||||
ErrCleanStack: "ErrCleanStack",
|
ErrCleanStack: "ErrCleanStack",
|
||||||
ErrNullFail: "ErrNullFail",
|
ErrNullFail: "ErrNullFail",
|
||||||
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
|
ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs",
|
||||||
|
@ -51,7 +51,7 @@ func TestErrorCodeStringer(t *testing.T) {
|
|||||||
{ErrSigDER, "ErrSigDER"},
|
{ErrSigDER, "ErrSigDER"},
|
||||||
{ErrSigHighS, "ErrSigHighS"},
|
{ErrSigHighS, "ErrSigHighS"},
|
||||||
{ErrNotPushOnly, "ErrNotPushOnly"},
|
{ErrNotPushOnly, "ErrNotPushOnly"},
|
||||||
{ErrPubKeyType, "ErrPubKeyType"},
|
{ErrPubKeyFormat, "ErrPubKeyFormat"},
|
||||||
{ErrCleanStack, "ErrCleanStack"},
|
{ErrCleanStack, "ErrCleanStack"},
|
||||||
{ErrNullFail, "ErrNullFail"},
|
{ErrNullFail, "ErrNullFail"},
|
||||||
{ErrDiscourageUpgradableNOPs, "ErrDiscourageUpgradableNOPs"},
|
{ErrDiscourageUpgradableNOPs, "ErrDiscourageUpgradableNOPs"},
|
||||||
|
@ -162,8 +162,7 @@ func ExampleSignTxOutput() {
|
|||||||
|
|
||||||
// Prove that the transaction has been validly signed by executing the
|
// Prove that the transaction has been validly signed by executing the
|
||||||
// script pair.
|
// script pair.
|
||||||
flags := txscript.ScriptBip16 |
|
flags := txscript.ScriptDiscourageUpgradableNops
|
||||||
txscript.ScriptDiscourageUpgradableNops
|
|
||||||
vm, err := txscript.NewEngine(originTx.TxOut[0].PkScript, redeemTx, 0, flags, nil)
|
vm, err := txscript.NewEngine(originTx.TxOut[0].PkScript, redeemTx, 0, flags, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
@ -1101,7 +1101,7 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
lockTime, err := makeScriptNum(so, vm.dstack.verifyMinimalData, 5)
|
lockTime, err := makeScriptNum(so, 5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1164,7 +1164,7 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stackSequence, err := makeScriptNum(so, vm.dstack.verifyMinimalData, 5)
|
stackSequence, err := makeScriptNum(so, 5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -2043,7 +2043,7 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
|
|||||||
valid = signature.Verify(hash, pubKey)
|
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"
|
str := "signature not empty on failed checksig"
|
||||||
return scriptError(ErrNullFail, str)
|
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 {
|
for _, sig := range signatures {
|
||||||
if len(sig.signature) > 0 {
|
if len(sig.signature) > 0 {
|
||||||
str := "not all signatures empty on failed checkmultisig"
|
str := "not all signatures empty on failed checkmultisig"
|
||||||
|
@ -133,24 +133,8 @@ func parseScriptFlags(flagStr string) (ScriptFlags, error) {
|
|||||||
switch flag {
|
switch flag {
|
||||||
case "":
|
case "":
|
||||||
// Nothing.
|
// Nothing.
|
||||||
case "CLEANSTACK":
|
|
||||||
flags |= ScriptVerifyCleanStack
|
|
||||||
case "DISCOURAGE_UPGRADABLE_NOPS":
|
case "DISCOURAGE_UPGRADABLE_NOPS":
|
||||||
flags |= ScriptDiscourageUpgradableNops
|
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:
|
default:
|
||||||
return flags, fmt.Errorf("invalid flag: %s", flag)
|
return flags, fmt.Errorf("invalid flag: %s", flag)
|
||||||
}
|
}
|
||||||
@ -167,12 +151,14 @@ func parseExpectedResult(expected string) ([]ErrorCode, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
case "UNKNOWN_ERROR":
|
case "UNKNOWN_ERROR":
|
||||||
return []ErrorCode{ErrNumberTooBig, ErrMinimalData}, nil
|
return []ErrorCode{ErrNumberTooBig, ErrMinimalData}, nil
|
||||||
case "PUBKEYTYPE":
|
case "PUBKEYFORMAT":
|
||||||
return []ErrorCode{ErrPubKeyType}, nil
|
return []ErrorCode{ErrPubKeyFormat}, nil
|
||||||
case "SIG_DER":
|
case "SIG_DER":
|
||||||
return []ErrorCode{ErrSigDER, ErrInvalidSigHashType}, nil
|
return []ErrorCode{ErrSigDER, ErrInvalidSigHashType}, nil
|
||||||
case "EVAL_FALSE":
|
case "EVAL_FALSE":
|
||||||
return []ErrorCode{ErrEvalFalse, ErrEmptyStack}, nil
|
return []ErrorCode{ErrEvalFalse, ErrEmptyStack}, nil
|
||||||
|
case "EMPTY_STACK":
|
||||||
|
return []ErrorCode{ErrEmptyStack}, nil
|
||||||
case "EQUALVERIFY":
|
case "EQUALVERIFY":
|
||||||
return []ErrorCode{ErrEqualVerify}, nil
|
return []ErrorCode{ErrEqualVerify}, nil
|
||||||
case "NULLFAIL":
|
case "NULLFAIL":
|
||||||
|
@ -8,17 +8,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/daglabs/btcd/dagconfig/daghash"
|
"github.com/daglabs/btcd/dagconfig/daghash"
|
||||||
"github.com/daglabs/btcd/wire"
|
"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.
|
// SigHashType represents hash type bits at the end of a signature.
|
||||||
type SigHashType uint32
|
type SigHashType uint32
|
||||||
|
|
||||||
@ -424,17 +418,17 @@ func GetSigOpCount(script []byte) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPreciseSigOpCount returns the number of signature operations in
|
// 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
|
// 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
|
// operations in the transaction. If the script fails to parse, then the count
|
||||||
// up to the point of failure is returned.
|
// 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
|
// Don't check error since parseScript returns the parsed-up-to-error
|
||||||
// list of pops.
|
// list of pops.
|
||||||
pops, _ := parseScript(scriptPubKey)
|
pops, _ := parseScript(scriptPubKey)
|
||||||
|
|
||||||
// Treat non P2SH transactions as normal.
|
// Treat non P2SH transactions as normal.
|
||||||
if !(bip16 && isScriptHash(pops)) {
|
if !(isP2SH && isScriptHash(pops)) {
|
||||||
return getSigOpCount(pops, true)
|
return getSigOpCount(pops, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,11 @@ type scriptNum int64
|
|||||||
|
|
||||||
// checkMinimalDataEncoding returns whether or not the passed byte array adheres
|
// checkMinimalDataEncoding returns whether or not the passed byte array adheres
|
||||||
// to the minimal encoding requirements.
|
// 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 {
|
func checkMinimalDataEncoding(v []byte) error {
|
||||||
if len(v) == 0 {
|
if len(v) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -167,13 +172,6 @@ func (n scriptNum) Int32() int32 {
|
|||||||
// bytes and therefore will pass that value to this function resulting in an
|
// bytes and therefore will pass that value to this function resulting in an
|
||||||
// allowed range of [-2^31 + 1, 2^31 - 1].
|
// 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
|
// The scriptNumLen is the maximum number of bytes the encoded value can be
|
||||||
// before an ErrStackNumberTooBig is returned. This effectively limits the
|
// before an ErrStackNumberTooBig is returned. This effectively limits the
|
||||||
// range of allowed values.
|
// range of allowed values.
|
||||||
@ -182,7 +180,7 @@ func (n scriptNum) Int32() int32 {
|
|||||||
// overflows.
|
// overflows.
|
||||||
//
|
//
|
||||||
// See the Bytes function documentation for example encodings.
|
// 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
|
// Interpreting data requires that it is not larger than
|
||||||
// the the passed scriptNumLen value.
|
// the the passed scriptNumLen value.
|
||||||
if len(v) > scriptNumLen {
|
if len(v) > scriptNumLen {
|
||||||
@ -192,11 +190,8 @@ func makeScriptNum(v []byte, requireMinimal bool, scriptNumLen int) (scriptNum,
|
|||||||
return 0, scriptError(ErrNumberTooBig, str)
|
return 0, scriptError(ErrNumberTooBig, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce minimal encoded if requested.
|
if err := checkMinimalDataEncoding(v); err != nil {
|
||||||
if requireMinimal {
|
return 0, err
|
||||||
if err := checkMinimalDataEncoding(v); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero is encoded as an empty byte slice.
|
// Zero is encoded as an empty byte slice.
|
||||||
|
@ -97,105 +97,88 @@ func TestMakeScriptNum(t *testing.T) {
|
|||||||
errMinimalData := scriptError(ErrMinimalData, "")
|
errMinimalData := scriptError(ErrMinimalData, "")
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
serialized []byte
|
serialized []byte
|
||||||
num scriptNum
|
num scriptNum
|
||||||
numLen int
|
numLen int
|
||||||
minimalEncoding bool
|
err error
|
||||||
err error
|
|
||||||
}{
|
}{
|
||||||
// Minimal encoding must reject negative 0.
|
// 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.
|
// Minimally encoded valid values with minimal encoding flag.
|
||||||
// Should not error and return expected integral number.
|
// Should not error and return expected integral number.
|
||||||
{nil, 0, defaultScriptNumLen, true, nil},
|
{nil, 0, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("01"), 1, defaultScriptNumLen, true, nil},
|
{hexToBytes("01"), 1, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("81"), -1, defaultScriptNumLen, true, nil},
|
{hexToBytes("81"), -1, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("7f"), 127, defaultScriptNumLen, true, nil},
|
{hexToBytes("7f"), 127, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("ff"), -127, defaultScriptNumLen, true, nil},
|
{hexToBytes("ff"), -127, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("8000"), 128, defaultScriptNumLen, true, nil},
|
{hexToBytes("8000"), 128, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("8080"), -128, defaultScriptNumLen, true, nil},
|
{hexToBytes("8080"), -128, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("8100"), 129, defaultScriptNumLen, true, nil},
|
{hexToBytes("8100"), 129, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("8180"), -129, defaultScriptNumLen, true, nil},
|
{hexToBytes("8180"), -129, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("0001"), 256, defaultScriptNumLen, true, nil},
|
{hexToBytes("0001"), 256, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("0081"), -256, defaultScriptNumLen, true, nil},
|
{hexToBytes("0081"), -256, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("ff7f"), 32767, defaultScriptNumLen, true, nil},
|
{hexToBytes("ff7f"), 32767, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("ffff"), -32767, defaultScriptNumLen, true, nil},
|
{hexToBytes("ffff"), -32767, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("008000"), 32768, defaultScriptNumLen, true, nil},
|
{hexToBytes("008000"), 32768, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("008080"), -32768, defaultScriptNumLen, true, nil},
|
{hexToBytes("008080"), -32768, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("ffff00"), 65535, defaultScriptNumLen, true, nil},
|
{hexToBytes("ffff00"), 65535, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("ffff80"), -65535, defaultScriptNumLen, true, nil},
|
{hexToBytes("ffff80"), -65535, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("000008"), 524288, defaultScriptNumLen, true, nil},
|
{hexToBytes("000008"), 524288, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("000088"), -524288, defaultScriptNumLen, true, nil},
|
{hexToBytes("000088"), -524288, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("000070"), 7340032, defaultScriptNumLen, true, nil},
|
{hexToBytes("000070"), 7340032, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("0000f0"), -7340032, defaultScriptNumLen, true, nil},
|
{hexToBytes("0000f0"), -7340032, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("00008000"), 8388608, defaultScriptNumLen, true, nil},
|
{hexToBytes("00008000"), 8388608, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("00008080"), -8388608, defaultScriptNumLen, true, nil},
|
{hexToBytes("00008080"), -8388608, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("ffffff7f"), 2147483647, defaultScriptNumLen, true, nil},
|
{hexToBytes("ffffff7f"), 2147483647, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("ffffffff"), -2147483647, defaultScriptNumLen, true, nil},
|
{hexToBytes("ffffffff"), -2147483647, defaultScriptNumLen, nil},
|
||||||
{hexToBytes("ffffffff7f"), 549755813887, 5, true, nil},
|
{hexToBytes("ffffffff7f"), 549755813887, 5, nil},
|
||||||
{hexToBytes("ffffffffff"), -549755813887, 5, true, nil},
|
{hexToBytes("ffffffffff"), -549755813887, 5, nil},
|
||||||
{hexToBytes("ffffffffffffff7f"), 9223372036854775807, 8, true, nil},
|
{hexToBytes("ffffffffffffff7f"), 9223372036854775807, 8, nil},
|
||||||
{hexToBytes("ffffffffffffffff"), -9223372036854775807, 8, true, nil},
|
{hexToBytes("ffffffffffffffff"), -9223372036854775807, 8, nil},
|
||||||
{hexToBytes("ffffffffffffffff7f"), -1, 9, true, nil},
|
{hexToBytes("ffffffffffffffff7f"), -1, 9, nil},
|
||||||
{hexToBytes("ffffffffffffffffff"), 1, 9, true, nil},
|
{hexToBytes("ffffffffffffffffff"), 1, 9, nil},
|
||||||
{hexToBytes("ffffffffffffffffff7f"), -1, 10, true, nil},
|
{hexToBytes("ffffffffffffffffff7f"), -1, 10, nil},
|
||||||
{hexToBytes("ffffffffffffffffffff"), 1, 10, true, nil},
|
{hexToBytes("ffffffffffffffffffff"), 1, 10, nil},
|
||||||
|
|
||||||
// Minimally encoded values that are out of range for data that
|
// Minimally encoded values that are out of range for data that
|
||||||
// is interpreted as script numbers with the minimal encoding
|
// is interpreted as script numbers with the minimal encoding
|
||||||
// flag set. Should error and return 0.
|
// flag set. Should error and return 0.
|
||||||
{hexToBytes("0000008000"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("0000008000"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("0000008080"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("0000008080"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("0000009000"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("0000009000"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("0000009080"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("0000009080"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("ffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("ffffffff00"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("ffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("ffffffff80"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("0000000001"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("0000000001"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("0000000081"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("0000000081"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("ffffffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("ffffffffffff00"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("ffffffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("ffffffffffff80"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("ffffffffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("ffffffffffffff00"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("ffffffffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("ffffffffffffff80"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("ffffffffffffff7f"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("ffffffffffffff7f"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
{hexToBytes("ffffffffffffffff"), 0, defaultScriptNumLen, true, errNumTooBig},
|
{hexToBytes("ffffffffffffffff"), 0, defaultScriptNumLen, errNumTooBig},
|
||||||
|
|
||||||
// Non-minimally encoded, but otherwise valid values with
|
// Non-minimally encoded, but otherwise valid values with
|
||||||
// minimal encoding flag. Should error and return 0.
|
// minimal encoding flag. Should error and return 0.
|
||||||
{hexToBytes("00"), 0, defaultScriptNumLen, true, errMinimalData}, // 0
|
{hexToBytes("00"), 0, defaultScriptNumLen, errMinimalData}, // 0
|
||||||
{hexToBytes("0100"), 0, defaultScriptNumLen, true, errMinimalData}, // 1
|
{hexToBytes("0100"), 0, defaultScriptNumLen, errMinimalData}, // 1
|
||||||
{hexToBytes("7f00"), 0, defaultScriptNumLen, true, errMinimalData}, // 127
|
{hexToBytes("7f00"), 0, defaultScriptNumLen, errMinimalData}, // 127
|
||||||
{hexToBytes("800000"), 0, defaultScriptNumLen, true, errMinimalData}, // 128
|
{hexToBytes("800000"), 0, defaultScriptNumLen, errMinimalData}, // 128
|
||||||
{hexToBytes("810000"), 0, defaultScriptNumLen, true, errMinimalData}, // 129
|
{hexToBytes("810000"), 0, defaultScriptNumLen, errMinimalData}, // 129
|
||||||
{hexToBytes("000100"), 0, defaultScriptNumLen, true, errMinimalData}, // 256
|
{hexToBytes("000100"), 0, defaultScriptNumLen, errMinimalData}, // 256
|
||||||
{hexToBytes("ff7f00"), 0, defaultScriptNumLen, true, errMinimalData}, // 32767
|
{hexToBytes("ff7f00"), 0, defaultScriptNumLen, errMinimalData}, // 32767
|
||||||
{hexToBytes("00800000"), 0, defaultScriptNumLen, true, errMinimalData}, // 32768
|
{hexToBytes("00800000"), 0, defaultScriptNumLen, errMinimalData}, // 32768
|
||||||
{hexToBytes("ffff0000"), 0, defaultScriptNumLen, true, errMinimalData}, // 65535
|
{hexToBytes("ffff0000"), 0, defaultScriptNumLen, errMinimalData}, // 65535
|
||||||
{hexToBytes("00000800"), 0, defaultScriptNumLen, true, errMinimalData}, // 524288
|
{hexToBytes("00000800"), 0, defaultScriptNumLen, errMinimalData}, // 524288
|
||||||
{hexToBytes("00007000"), 0, defaultScriptNumLen, true, errMinimalData}, // 7340032
|
{hexToBytes("00007000"), 0, defaultScriptNumLen, errMinimalData}, // 7340032
|
||||||
{hexToBytes("0009000100"), 0, 5, true, errMinimalData}, // 16779520
|
{hexToBytes("0009000100"), 0, 5, 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},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
// Ensure the error code is of the expected type and the error
|
// Ensure the error code is of the expected type and the error
|
||||||
// code matches the value specified in the test instance.
|
// code matches the value specified in the test instance.
|
||||||
gotNum, err := makeScriptNum(test.serialized, test.minimalEncoding,
|
gotNum, err := makeScriptNum(test.serialized,
|
||||||
test.numLen)
|
test.numLen)
|
||||||
if e := tstCheckScriptError(err, test.err); e != nil {
|
if e := tstCheckScriptError(err, test.err); e != nil {
|
||||||
t.Errorf("makeScriptNum(%#x): %v", test.serialized, e)
|
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
|
builder := NewScriptBuilder()
|
||||||
// in the reference implementation).
|
|
||||||
builder := NewScriptBuilder().AddOp(OpFalse)
|
|
||||||
doneSigs := 0
|
doneSigs := 0
|
||||||
// This assumes that addresses are in the same order as in the script.
|
// This assumes that addresses are in the same order as in the script.
|
||||||
for _, addr := range addresses {
|
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 {
|
func checkScripts(msg string, tx *wire.MsgTx, idx int, sigScript, pkScript []byte) error {
|
||||||
tx.TxIn[idx].SignatureScript = sigScript
|
tx.TxIn[idx].SignatureScript = sigScript
|
||||||
|
var flags ScriptFlags
|
||||||
vm, err := NewEngine(pkScript, tx, idx,
|
vm, err := NewEngine(pkScript, tx, idx,
|
||||||
ScriptBip16, nil)
|
flags, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to make script engine for %s: %v",
|
return fmt.Errorf("failed to make script engine for %s: %v",
|
||||||
msg, err)
|
msg, err)
|
||||||
@ -91,7 +92,6 @@ func TestSignTxOutput(t *testing.T) {
|
|||||||
// make script based on key.
|
// make script based on key.
|
||||||
// sign with magic pixie dust.
|
// sign with magic pixie dust.
|
||||||
hashTypes := []SigHashType{
|
hashTypes := []SigHashType{
|
||||||
SigHashOld, // no longer used but should act like all
|
|
||||||
SigHashAll,
|
SigHashAll,
|
||||||
SigHashNone,
|
SigHashNone,
|
||||||
SigHashSingle,
|
SigHashSingle,
|
||||||
@ -1498,7 +1498,7 @@ var sigScriptTests = []tstSigScript{
|
|||||||
scriptAtWrongIndex: false,
|
scriptAtWrongIndex: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "hashType SigHashAnyoneCanPay",
|
name: "hashType SigHashAll | SigHashAnyoneCanPay",
|
||||||
inputs: []tstInput{
|
inputs: []tstInput{
|
||||||
{
|
{
|
||||||
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
|
||||||
@ -1507,17 +1507,31 @@ var sigScriptTests = []tstSigScript{
|
|||||||
indexOutOfRange: false,
|
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,
|
hashType: SigHashAnyOneCanPay,
|
||||||
compress: false,
|
compress: false,
|
||||||
scriptAtWrongIndex: false,
|
scriptAtWrongIndex: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "hashType non-standard",
|
name: "hashType non-exist",
|
||||||
inputs: []tstInput{
|
inputs: []tstInput{
|
||||||
{
|
{
|
||||||
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
|
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
|
||||||
sigscriptGenerates: true,
|
sigscriptGenerates: true,
|
||||||
inputValidates: true,
|
inputValidates: false,
|
||||||
indexOutOfRange: false,
|
indexOutOfRange: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1658,7 +1672,7 @@ nexttest:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate tx input scripts
|
// Validate tx input scripts
|
||||||
scriptFlags := ScriptBip16
|
var scriptFlags ScriptFlags
|
||||||
for j := range tx.TxIn {
|
for j := range tx.TxIn {
|
||||||
vm, err := NewEngine(sigScriptTests[i].
|
vm, err := NewEngine(sigScriptTests[i].
|
||||||
inputs[j].txout.PkScript, tx, j, scriptFlags, nil)
|
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
|
// changed it *must* be deep-copied first to avoid changing other values on the
|
||||||
// stack.
|
// stack.
|
||||||
type stack struct {
|
type stack struct {
|
||||||
stk [][]byte
|
stk [][]byte
|
||||||
verifyMinimalData bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth returns the number of items on the stack.
|
// Depth returns the number of items on the stack.
|
||||||
@ -86,7 +85,7 @@ func (s *stack) PopInt() (scriptNum, error) {
|
|||||||
return 0, err
|
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
|
// 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 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.
|
// 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",
|
"popInt 0",
|
||||||
[][]byte{{0x0}},
|
[][]byte{{}},
|
||||||
func(s *stack) error {
|
func(s *stack) error {
|
||||||
v, err := s.PopInt()
|
v, err := s.PopInt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -200,22 +200,6 @@ func TestStack(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
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",
|
"popInt 1",
|
||||||
[][]byte{{0x01}},
|
[][]byte{{0x01}},
|
||||||
@ -232,23 +216,6 @@ func TestStack(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
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",
|
"popInt -1",
|
||||||
[][]byte{{0x81}},
|
[][]byte{{0x81}},
|
||||||
@ -265,23 +232,6 @@ func TestStack(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
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
|
// Triggers the multibyte case in asInt
|
||||||
{
|
{
|
||||||
"popInt -513",
|
"popInt -513",
|
||||||
@ -300,24 +250,6 @@ func TestStack(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
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",
|
"PushInt 0",
|
||||||
nil,
|
nil,
|
||||||
@ -852,24 +784,6 @@ func TestStack(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
[][]byte{{1}},
|
[][]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",
|
"pop int",
|
||||||
nil,
|
nil,
|
||||||
|
@ -26,13 +26,7 @@ const (
|
|||||||
//
|
//
|
||||||
// TODO: This definition does not belong here. It belongs in a policy
|
// TODO: This definition does not belong here. It belongs in a policy
|
||||||
// package.
|
// package.
|
||||||
StandardVerifyFlags = ScriptBip16 |
|
StandardVerifyFlags = ScriptDiscourageUpgradableNops
|
||||||
ScriptVerifyStrictEncoding |
|
|
||||||
ScriptVerifyMinimalData |
|
|
||||||
ScriptDiscourageUpgradableNops |
|
|
||||||
ScriptVerifyCleanStack |
|
|
||||||
ScriptVerifyNullFail |
|
|
||||||
ScriptVerifyLowS
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ScriptClass is an enumeration for the list of standard types of script.
|
// 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
|
// 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
|
// be analysed, i.e. if they do not parse or the pkScript is not a push-only
|
||||||
// script
|
// script
|
||||||
func CalcScriptInfo(sigScript, pkScript []byte, bip16 bool) (*ScriptInfo, error) {
|
func CalcScriptInfo(sigScript, pkScript []byte, isP2SH bool) (*ScriptInfo, error) {
|
||||||
sigPops, err := parseScript(sigScript)
|
sigPops, err := parseScript(sigScript)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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).
|
// All entries pushed to stack (or are OP_RESERVED and exec will fail).
|
||||||
si.NumInputs = len(sigPops)
|
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
|
// The pay-to-hash-script is the final data push of the
|
||||||
// signature script.
|
// signature script.
|
||||||
script := sigPops[len(sigPops)-1].data
|
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.RecipientHash160[:], pops[9].data)
|
||||||
copy(pushes.RefundHash160[:], pops[16].data)
|
copy(pushes.RefundHash160[:], pops[16].data)
|
||||||
if pops[2].data != nil {
|
if pops[2].data != nil {
|
||||||
locktime, err := makeScriptNum(pops[2].data, true, 5)
|
locktime, err := makeScriptNum(pops[2].data, 5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -563,7 +557,7 @@ func ExtractAtomicSwapDataPushes(version uint16, pkScript []byte) (*AtomicSwapDa
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if pops[11].data != nil {
|
if pops[11].data != nil {
|
||||||
locktime, err := makeScriptNum(pops[11].data, true, 5)
|
locktime, err := makeScriptNum(pops[11].data, 5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
|||||||
sigScript string
|
sigScript string
|
||||||
pkScript string
|
pkScript string
|
||||||
|
|
||||||
bip16 bool
|
isP2SH bool
|
||||||
|
|
||||||
scriptInfo ScriptInfo
|
scriptInfo ScriptInfo
|
||||||
scriptInfoErr error
|
scriptInfoErr error
|
||||||
@ -392,7 +392,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
|||||||
"SWAP ABS EQUAL",
|
"SWAP ABS EQUAL",
|
||||||
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
||||||
"3152205ec4f59c",
|
"3152205ec4f59c",
|
||||||
bip16: true,
|
isP2SH: true,
|
||||||
scriptInfoErr: scriptError(ErrMalformedPush, ""),
|
scriptInfoErr: scriptError(ErrMalformedPush, ""),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -402,7 +402,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
|||||||
"SWAP ABS",
|
"SWAP ABS",
|
||||||
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
||||||
"3152205ec4f59c74 EQUAL",
|
"3152205ec4f59c74 EQUAL",
|
||||||
bip16: true,
|
isP2SH: true,
|
||||||
scriptInfoErr: scriptError(ErrMalformedPush, ""),
|
scriptInfoErr: scriptError(ErrMalformedPush, ""),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -413,7 +413,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
|||||||
"CHECKSIG",
|
"CHECKSIG",
|
||||||
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
||||||
"3152205ec4f59c74 EQUAL",
|
"3152205ec4f59c74 EQUAL",
|
||||||
bip16: true,
|
isP2SH: true,
|
||||||
scriptInfo: ScriptInfo{
|
scriptInfo: ScriptInfo{
|
||||||
PkScriptClass: ScriptHashTy,
|
PkScriptClass: ScriptHashTy,
|
||||||
NumInputs: 3,
|
NumInputs: 3,
|
||||||
@ -429,7 +429,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
|||||||
"SWAP ABS EQUAL",
|
"SWAP ABS EQUAL",
|
||||||
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" +
|
||||||
"3152205ec4f59c74 EQUAL",
|
"3152205ec4f59c74 EQUAL",
|
||||||
bip16: true,
|
isP2SH: true,
|
||||||
scriptInfo: ScriptInfo{
|
scriptInfo: ScriptInfo{
|
||||||
PkScriptClass: ScriptHashTy,
|
PkScriptClass: ScriptHashTy,
|
||||||
NumInputs: 3,
|
NumInputs: 3,
|
||||||
@ -449,7 +449,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
|||||||
"161718191a1b1c1d1e1f2021 DATA_33 0x010203040" +
|
"161718191a1b1c1d1e1f2021 DATA_33 0x010203040" +
|
||||||
"5060708090a0b0c0d0e0f101112131415161718191a1" +
|
"5060708090a0b0c0d0e0f101112131415161718191a1" +
|
||||||
"b1c1d1e1f2021 3 CHECKMULTISIG",
|
"b1c1d1e1f2021 3 CHECKMULTISIG",
|
||||||
bip16: true,
|
isP2SH: true,
|
||||||
scriptInfo: ScriptInfo{
|
scriptInfo: ScriptInfo{
|
||||||
PkScriptClass: MultiSigTy,
|
PkScriptClass: MultiSigTy,
|
||||||
NumInputs: 4,
|
NumInputs: 4,
|
||||||
@ -463,7 +463,7 @@ func TestCalcScriptInfo(t *testing.T) {
|
|||||||
sigScript := mustParseShortForm(test.sigScript)
|
sigScript := mustParseShortForm(test.sigScript)
|
||||||
pkScript := mustParseShortForm(test.pkScript)
|
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 {
|
if e := tstCheckScriptError(err, test.scriptInfoErr); e != nil {
|
||||||
t.Errorf("scriptinfo test %q: %v", test.name, e)
|
t.Errorf("scriptinfo test %q: %v", test.name, e)
|
||||||
continue
|
continue
|
||||||
|
Loading…
x
Reference in New Issue
Block a user