From e8cf4d96cef7f25ae3c18418ac7fbedc20b6dba6 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 13 Aug 2020 13:42:21 +0300 Subject: [PATCH 1/4] core: add tests for (*Blockchain).verifyTx --- pkg/core/blockchain.go | 36 +++++++--- pkg/core/blockchain_test.go | 129 ++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 10 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 183fdbc8e..386d24dab 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1192,11 +1192,21 @@ func (bc *Blockchain) verifyHeader(currHeader, prevHeader *block.Header) error { return bc.verifyHeaderWitnesses(currHeader, prevHeader) } +// Various errors that could be returned upon verification. +var ( + ErrTxExpired = errors.New("transaction has expired") + ErrInsufficientFunds = errors.New("insufficient funds") + ErrTxSmallNetworkFee = errors.New("too small network fee") + ErrTxTooBig = errors.New("too big transaction") + ErrMemPoolConflict = errors.New("invalid transaction due to conflicts with the memory pool") + ErrTxInvalidWitnessNum = errors.New("number of signers doesn't match witnesses") +) + // verifyTx verifies whether a transaction is bonafide or not. func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) error { height := bc.BlockHeight() if t.ValidUntilBlock <= height || t.ValidUntilBlock > height+transaction.MaxValidUntilBlockIncrement { - return fmt.Errorf("transaction has expired. ValidUntilBlock = %d, current height = %d", t.ValidUntilBlock, height) + return fmt.Errorf("%w: ValidUntilBlock = %d, current height = %d", ErrTxExpired, t.ValidUntilBlock, height) } // Policying. if err := bc.contracts.Policy.CheckPolicy(bc.dao, t); err != nil { @@ -1206,20 +1216,20 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e balance := bc.GetUtilityTokenBalance(t.Sender()) need := t.SystemFee + t.NetworkFee if balance.Cmp(big.NewInt(need)) < 0 { - return fmt.Errorf("insufficient funds: balance is %v, need: %v", balance, need) + return fmt.Errorf("%w: balance is %v, need: %v", ErrInsufficientFunds, balance, need) } size := io.GetVarSize(t) if size > transaction.MaxTransactionSize { - return fmt.Errorf("too big transaction (%d > MaxTransactionSize %d)", size, transaction.MaxTransactionSize) + return fmt.Errorf("%w: (%d > MaxTransactionSize %d)", ErrTxTooBig, size, transaction.MaxTransactionSize) } needNetworkFee := int64(size) * bc.FeePerByte() netFee := t.NetworkFee - needNetworkFee if netFee < 0 { - return fmt.Errorf("insufficient funds: net fee is %v, need %v", t.NetworkFee, needNetworkFee) + return fmt.Errorf("%w: net fee is %v, need %v", ErrTxSmallNetworkFee, t.NetworkFee, needNetworkFee) } if block == nil { if ok := bc.memPool.Verify(t, bc); !ok { - return errors.New("invalid transaction due to conflicts with the memory pool") + return ErrMemPoolConflict } } @@ -1405,12 +1415,18 @@ func ScriptFromWitness(hash util.Uint160, witness *transaction.Witness) ([]byte, emit.AppCall(bb.BinWriter, hash) verification = bb.Bytes() } else if h := witness.ScriptHash(); hash != h { - return nil, errors.New("witness hash mismatch") + return nil, ErrWitnessHashMismatch } return verification, nil } +// Various witness verification errors. +var ( + ErrWitnessHashMismatch = errors.New("witness hash mismatch") + ErrVerificationFailed = errors.New("signature check failed") +) + // verifyHashAgainstScript verifies given hash against the given witness. func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, interopCtx *interop.Context, useKeys bool, gas int64) error { verification, err := ScriptFromWitness(hash, witness) @@ -1437,12 +1453,12 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa } err = vm.Run() if vm.HasFailed() { - return fmt.Errorf("vm execution has failed: %w", err) + return fmt.Errorf("%w: vm execution has failed: %v", ErrVerificationFailed, err) } resEl := vm.Estack().Pop() if resEl != nil { if !resEl.Bool() { - return fmt.Errorf("signature check failed") + return fmt.Errorf("%w: invalid signature", ErrVerificationFailed) } if useKeys { bc.keyCacheLock.RLock() @@ -1455,7 +1471,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa } } } else { - return fmt.Errorf("no result returned from the script") + return fmt.Errorf("%w: no result returned from the script", ErrVerificationFailed) } return nil } @@ -1468,7 +1484,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa // Golang implementation of VerifyWitnesses method in C# (https://github.com/neo-project/neo/blob/master/neo/SmartContract/Helper.cs#L87). func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block.Block) error { if len(t.Signers) != len(t.Scripts) { - return fmt.Errorf("number of signers doesn't match witnesses (%d vs %d)", len(t.Signers), len(t.Scripts)) + return fmt.Errorf("%w: %d vs %d", ErrTxInvalidWitnessNum, len(t.Signers), len(t.Scripts)) } interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, block, t) for i := range t.Signers { diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 7883ced7f..655831d8c 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -1,7 +1,10 @@ package core import ( + "errors" + "fmt" "math/big" + "math/rand" "testing" "time" @@ -11,11 +14,14 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" + "github.com/nspcc-dev/neo-go/pkg/internal/testchain" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/opcode" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -144,6 +150,129 @@ func TestGetBlock(t *testing.T) { } } +func (bc *Blockchain) newTestTx(h util.Uint160, script []byte) *transaction.Transaction { + tx := transaction.New(testchain.Network(), script, 1_000_000) + tx.Nonce = rand.Uint32() + tx.ValidUntilBlock = 100 + tx.Signers = []transaction.Signer{{ + Account: h, + Scopes: transaction.CalledByEntry, + }} + tx.NetworkFee = int64(io.GetVarSize(tx)+200 /* witness */) * bc.FeePerByte() + tx.NetworkFee += 1_000_000 // verification cost + return tx +} + +func TestVerifyTx(t *testing.T) { + bc := newTestChain(t) + defer bc.Close() + + accs := make([]*wallet.Account, 2) + for i := range accs { + var err error + accs[i], err = wallet.NewAccount() + require.NoError(t, err) + } + + neoHash := bc.contracts.NEO.Hash + gasHash := bc.contracts.GAS.Hash + w := io.NewBufBinWriter() + for _, sc := range []util.Uint160{neoHash, gasHash} { + for _, a := range accs { + amount := int64(1_000_000) + if sc.Equals(gasHash) { + amount = 1_000_000_000 + } + emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", + neoOwner, a.PrivateKey().GetScriptHash(), amount) + emit.Opcode(w.BinWriter, opcode.ASSERT) + } + } + require.NoError(t, w.Err) + + txMove := bc.newTestTx(neoOwner, w.Bytes()) + txMove.SystemFee = 1_000_000_000 + require.NoError(t, signTx(bc, txMove)) + b := bc.newBlock(txMove) + require.NoError(t, bc.AddBlock(b)) + + aer, err := bc.GetAppExecResult(txMove.Hash()) + require.NoError(t, err) + require.Equal(t, aer.VMState, vm.HaltState) + + res, err := invokeNativePolicyMethod(bc, "blockAccount", accs[1].PrivateKey().GetScriptHash().BytesBE()) + require.NoError(t, err) + checkResult(t, res, stackitem.NewBool(true)) + + checkErr := func(t *testing.T, expectedErr error, tx *transaction.Transaction) { + err := bc.verifyTx(tx, nil) + fmt.Println(err) + require.True(t, errors.Is(err, expectedErr)) + } + + testScript := []byte{byte(opcode.PUSH1)} + h := accs[0].PrivateKey().GetScriptHash() + t.Run("Expired", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + tx.ValidUntilBlock = 1 + require.NoError(t, accs[0].SignTx(tx)) + checkErr(t, ErrTxExpired, tx) + }) + t.Run("BlockedAccount", func(t *testing.T) { + tx := bc.newTestTx(accs[1].PrivateKey().GetScriptHash(), testScript) + require.NoError(t, accs[1].SignTx(tx)) + err := bc.verifyTx(tx, nil) + require.True(t, errors.Is(err, ErrPolicy)) + }) + t.Run("InsufficientGas", func(t *testing.T) { + balance := bc.GetUtilityTokenBalance(h) + tx := bc.newTestTx(h, testScript) + tx.SystemFee = balance.Int64() + 1 + require.NoError(t, accs[0].SignTx(tx)) + checkErr(t, ErrInsufficientFunds, tx) + }) + t.Run("TooBigTx", func(t *testing.T) { + script := make([]byte, transaction.MaxTransactionSize) + tx := bc.newTestTx(h, script) + require.NoError(t, accs[0].SignTx(tx)) + checkErr(t, ErrTxTooBig, tx) + }) + t.Run("SmallNetworkFee", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + tx.NetworkFee = 1 + require.NoError(t, accs[0].SignTx(tx)) + checkErr(t, ErrTxSmallNetworkFee, tx) + }) + t.Run("Conflict", func(t *testing.T) { + balance := bc.GetUtilityTokenBalance(h).Int64() + tx := bc.newTestTx(h, testScript) + tx.NetworkFee = balance / 2 + require.NoError(t, accs[0].SignTx(tx)) + checkErr(t, nil, tx) + + tx2 := bc.newTestTx(h, testScript) + tx2.NetworkFee = balance / 2 + require.NoError(t, bc.memPool.Add(tx2, bc)) + checkErr(t, ErrMemPoolConflict, tx) + }) + t.Run("NotEnoughWitnesses", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + checkErr(t, ErrTxInvalidWitnessNum, tx) + }) + t.Run("InvalidWitnessHash", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + require.NoError(t, accs[0].SignTx(tx)) + tx.Scripts[0].VerificationScript = []byte{byte(opcode.PUSHT)} + checkErr(t, ErrWitnessHashMismatch, tx) + }) + t.Run("InvalidWitnessSignature", func(t *testing.T) { + tx := bc.newTestTx(h, testScript) + require.NoError(t, accs[0].SignTx(tx)) + tx.Scripts[0].InvocationScript[10] = ^tx.Scripts[0].InvocationScript[10] + checkErr(t, ErrVerificationFailed, tx) + }) +} + func TestHasBlock(t *testing.T) { bc := newTestChain(t) blocks, err := bc.genBlocks(50) From 7f2a931fb6206cdfc47c5cceb857964ed6dff34c Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 13 Aug 2020 13:57:30 +0300 Subject: [PATCH 2/4] core: add tests for (*Blockchain).verifyHeader --- pkg/core/blockchain.go | 13 ++++++++++--- pkg/core/blockchain_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 386d24dab..14353cdff 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1179,15 +1179,22 @@ func (bc *Blockchain) ApplyPolicyToTxSet(txes []*transaction.Transaction) []*tra return txes } +// Various errors that could be returns upon header verification. +var ( + ErrHdrHashMismatch = errors.New("previous header hash doesn't match") + ErrHdrIndexMismatch = errors.New("previous header index doesn't match") + ErrHdrInvalidTimestamp = errors.New("block is not newer than the previous one") +) + func (bc *Blockchain) verifyHeader(currHeader, prevHeader *block.Header) error { if prevHeader.Hash() != currHeader.PrevHash { - return errors.New("previous header hash doesn't match") + return ErrHdrHashMismatch } if prevHeader.Index+1 != currHeader.Index { - return errors.New("previous header index doesn't match") + return ErrHdrIndexMismatch } if prevHeader.Timestamp >= currHeader.Timestamp { - return errors.New("block is not newer than the previous one") + return ErrHdrInvalidTimestamp } return bc.verifyHeaderWitnesses(currHeader, prevHeader) } diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 655831d8c..eaebeb630 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -26,6 +26,33 @@ import ( "github.com/stretchr/testify/require" ) +func TestVerifyHeader(t *testing.T) { + bc := newTestChain(t) + defer bc.Close() + prev := bc.topBlock.Load().(*block.Block).Header() + t.Run("Invalid", func(t *testing.T) { + t.Run("Hash", func(t *testing.T) { + h := prev.Hash() + h[0] = ^h[0] + hdr := newBlock(bc.config, 1, h).Header() + require.True(t, errors.Is(bc.verifyHeader(hdr, prev), ErrHdrHashMismatch)) + }) + t.Run("Index", func(t *testing.T) { + hdr := newBlock(bc.config, 3, prev.Hash()).Header() + require.True(t, errors.Is(bc.verifyHeader(hdr, prev), ErrHdrIndexMismatch)) + }) + t.Run("Timestamp", func(t *testing.T) { + hdr := newBlock(bc.config, 1, prev.Hash()).Header() + hdr.Timestamp = 0 + require.True(t, errors.Is(bc.verifyHeader(hdr, prev), ErrHdrInvalidTimestamp)) + }) + }) + t.Run("Valid", func(t *testing.T) { + hdr := newBlock(bc.config, 1, prev.Hash()).Header() + require.NoError(t, bc.verifyHeader(hdr, prev)) + }) +} + func TestAddHeaders(t *testing.T) { bc := newTestChain(t) defer bc.Close() From 1eb9a4c6c6be3e87d5f8a34178231c729e04332b Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 13 Aug 2020 18:42:53 +0300 Subject: [PATCH 3/4] core: allow to use verification contracts In NEO3 we can't just appcall hash, as verification script has no access to state. Instead we use `verify` method of an arbitrary contract. --- pkg/core/blockchain.go | 35 +++++++++++++++++++----- pkg/core/blockchain_test.go | 37 ++++++++++++++++++++++++++ pkg/core/interop_system_test.go | 6 +++++ pkg/smartcontract/manifest/manifest.go | 3 +++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 14353cdff..59c499726 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -22,6 +22,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" @@ -1430,15 +1431,33 @@ func ScriptFromWitness(hash util.Uint160, witness *transaction.Witness) ([]byte, // Various witness verification errors. var ( - ErrWitnessHashMismatch = errors.New("witness hash mismatch") - ErrVerificationFailed = errors.New("signature check failed") + ErrWitnessHashMismatch = errors.New("witness hash mismatch") + ErrVerificationFailed = errors.New("signature check failed") + ErrUnknownVerificationContract = errors.New("unknown verification contract") + ErrInvalidVerificationContract = errors.New("verification contract is missing `verify` method") ) // verifyHashAgainstScript verifies given hash against the given witness. func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, interopCtx *interop.Context, useKeys bool, gas int64) error { - verification, err := ScriptFromWitness(hash, witness) - if err != nil { - return err + var offset int + var initMD *manifest.Method + verification := witness.VerificationScript + if len(verification) != 0 { + if witness.ScriptHash() != hash { + return ErrWitnessHashMismatch + } + } else { + cs, err := interopCtx.DAO.GetContractState(hash) + if err != nil { + return ErrUnknownVerificationContract + } + md := cs.Manifest.ABI.GetMethod(manifest.MethodVerify) + if md == nil { + return ErrInvalidVerificationContract + } + verification = cs.Script + offset = md.Offset + initMD = cs.Manifest.ABI.GetMethod(manifest.MethodInit) } gasPolicy := bc.contracts.Policy.GetMaxVerificationGas(interopCtx.DAO) @@ -1450,6 +1469,10 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa vm.SetPriceGetter(getPrice) vm.GasLimit = gas vm.LoadScriptWithFlags(verification, smartcontract.NoneFlag) + vm.Jump(vm.Context(), offset) + if initMD != nil { + vm.Call(vm.Context(), initMD.Offset) + } vm.LoadScript(witness.InvocationScript) if useKeys { bc.keyCacheLock.RLock() @@ -1458,7 +1481,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa } bc.keyCacheLock.RUnlock() } - err = vm.Run() + err := vm.Run() if vm.HasFailed() { return fmt.Errorf("%w: vm execution has failed: %v", ErrVerificationFailed, err) } diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index eaebeb630..bee28a2b2 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -16,6 +16,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/internal/testchain" "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm/emit" @@ -300,6 +301,42 @@ func TestVerifyTx(t *testing.T) { }) } +func TestVerifyHashAgainstScript(t *testing.T) { + bc := newTestChain(t) + defer bc.Close() + + cs, csInvalid := getTestContractState() + ic := bc.newInteropContext(trigger.Verification, bc.dao, nil, nil) + require.NoError(t, ic.DAO.PutContractState(cs)) + require.NoError(t, ic.DAO.PutContractState(csInvalid)) + + gas := bc.contracts.Policy.GetMaxVerificationGas(ic.DAO) + t.Run("Contract", func(t *testing.T) { + t.Run("Missing", func(t *testing.T) { + newH := cs.ScriptHash() + newH[0] = ^newH[0] + w := &transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH4)}} + err := bc.verifyHashAgainstScript(newH, w, ic, false, gas) + require.True(t, errors.Is(err, ErrUnknownVerificationContract)) + }) + t.Run("Invalid", func(t *testing.T) { + w := &transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH4)}} + err := bc.verifyHashAgainstScript(csInvalid.ScriptHash(), w, ic, false, gas) + require.True(t, errors.Is(err, ErrInvalidVerificationContract)) + }) + t.Run("ValidSignature", func(t *testing.T) { + w := &transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH4)}} + err := bc.verifyHashAgainstScript(cs.ScriptHash(), w, ic, false, gas) + require.NoError(t, err) + }) + t.Run("InvalidSignature", func(t *testing.T) { + w := &transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH3)}} + err := bc.verifyHashAgainstScript(cs.ScriptHash(), w, ic, false, gas) + require.True(t, errors.Is(err, ErrVerificationFailed)) + }) + }) +} + func TestHasBlock(t *testing.T) { bc := newTestChain(t) blocks, err := bc.genBlocks(50) diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go index 29e1ddcbc..33686d75a 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -337,6 +337,7 @@ func getTestContractState() (*state.Contract, *state.Contract) { byte(opcode.LDSFLD0), byte(opcode.ADD), byte(opcode.RET), byte(opcode.PUSH1), byte(opcode.PUSH2), byte(opcode.RET), byte(opcode.RET), + byte(opcode.LDSFLD0), byte(opcode.SUB), byte(opcode.CONVERT), byte(stackitem.BooleanT), byte(opcode.RET), } h := hash.Hash160(script) m := manifest.NewManifest(h) @@ -384,6 +385,11 @@ func getTestContractState() (*state.Contract, *state.Contract) { Offset: 18, ReturnType: smartcontract.IntegerType, }, + { + Name: manifest.MethodVerify, + Offset: 19, + ReturnType: smartcontract.BoolType, + }, } cs := &state.Contract{ Script: script, diff --git a/pkg/smartcontract/manifest/manifest.go b/pkg/smartcontract/manifest/manifest.go index 1d528eec8..f2b76e9d7 100644 --- a/pkg/smartcontract/manifest/manifest.go +++ b/pkg/smartcontract/manifest/manifest.go @@ -15,6 +15,9 @@ const ( // MethodInit is a name for default initialization method. MethodInit = "_initialize" + // MethodVerify is a name for default verification method. + MethodVerify = "verify" + // NEP5StandardName represents the name of NEP5 smartcontract standard. NEP5StandardName = "NEP-5" // NEP10StandardName represents the name of NEP10 smartcontract standard. From cadebdfc196071c3ec3f75377496b8fef83dbaec Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 13 Aug 2020 18:53:41 +0300 Subject: [PATCH 4/4] core: add tests for (*Blockchain).verifyHashAgainstScript --- pkg/core/blockchain_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index bee28a2b2..f7ff28ace 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -335,6 +335,24 @@ func TestVerifyHashAgainstScript(t *testing.T) { require.True(t, errors.Is(err, ErrVerificationFailed)) }) }) + t.Run("NotEnoughGas", func(t *testing.T) { + verif := []byte{byte(opcode.PUSH1)} + w := &transaction.Witness{ + InvocationScript: []byte{byte(opcode.NOP)}, + VerificationScript: verif, + } + err := bc.verifyHashAgainstScript(hash.Hash160(verif), w, ic, false, 1) + require.True(t, errors.Is(err, ErrVerificationFailed)) + }) + t.Run("NoResult", func(t *testing.T) { + verif := []byte{byte(opcode.DROP)} + w := &transaction.Witness{ + InvocationScript: []byte{byte(opcode.PUSH1)}, + VerificationScript: verif, + } + err := bc.verifyHashAgainstScript(hash.Hash160(verif), w, ic, false, gas) + require.True(t, errors.Is(err, ErrVerificationFailed)) + }) } func TestHasBlock(t *testing.T) {