From afc5ee1ded58a38eef7bba803125f65d54b77c4f Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 13 Jul 2020 18:04:50 +0300 Subject: [PATCH 1/8] core: fix ECDSA verifiation price, it's 1000000 and it's defined in crypto --- pkg/core/util.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pkg/core/util.go b/pkg/core/util.go index 6082ca8e5..792b38a7e 100644 --- a/pkg/core/util.go +++ b/pkg/core/util.go @@ -6,6 +6,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/block" + "github.com/nspcc-dev/neo-go/pkg/core/interop/crypto" "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/crypto/keys" @@ -17,10 +18,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/vm/opcode" ) -// ecdsaVerifyInteropPrice returns the price of Neo.Crypto.ECDsaVerify -// syscall to calculate NetworkFee for transaction -const ecdsaVerifyInteropPrice = 100000 - var ( // governingTokenTX represents transaction that is used to create // governing (NEO) token. It's a part of the genesis block. @@ -138,13 +135,13 @@ func CalculateNetworkFee(script []byte) (int64, int) { ) if vm.IsSignatureContract(script) { size += 67 + io.GetVarSize(script) - netFee += opcodePrice(opcode.PUSHDATA1, opcode.PUSHNULL) + ecdsaVerifyInteropPrice + netFee += opcodePrice(opcode.PUSHDATA1, opcode.PUSHNULL) + crypto.ECDSAVerifyPrice } else if n, pubs, ok := vm.ParseMultiSigContract(script); ok { m := len(pubs) sizeInv := 66 * m size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script) netFee += calculateMultisigFee(m) + calculateMultisigFee(n) - netFee += opcodePrice(opcode.PUSHNULL) + ecdsaVerifyInteropPrice*int64(n) + netFee += opcodePrice(opcode.PUSHNULL) + crypto.ECDSAVerifyPrice*int64(n) } else { // We can support more contract types in the future. } From 3134e364b2c57bb8864a2ba5c257ade8993ad418 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 13 Jul 2020 18:05:46 +0300 Subject: [PATCH 2/8] core: fix CalculateNetworkFee() for multisig contracts We return m from the vm.ParseMultiSigContract and n is the length of pubs, invocation script then pushes m signatures for n keys. --- pkg/core/util.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/core/util.go b/pkg/core/util.go index 792b38a7e..7f1b64d83 100644 --- a/pkg/core/util.go +++ b/pkg/core/util.go @@ -136,8 +136,8 @@ func CalculateNetworkFee(script []byte) (int64, int) { if vm.IsSignatureContract(script) { size += 67 + io.GetVarSize(script) netFee += opcodePrice(opcode.PUSHDATA1, opcode.PUSHNULL) + crypto.ECDSAVerifyPrice - } else if n, pubs, ok := vm.ParseMultiSigContract(script); ok { - m := len(pubs) + } else if m, pubs, ok := vm.ParseMultiSigContract(script); ok { + n := len(pubs) sizeInv := 66 * m size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script) netFee += calculateMultisigFee(m) + calculateMultisigFee(n) From 330e1670d683f630f767877d328f73d64a1d6529 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 13 Jul 2020 18:07:02 +0300 Subject: [PATCH 3/8] consensus: limit payload verification time with GAS Follow C# implementation. --- pkg/consensus/payload.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/consensus/payload.go b/pkg/consensus/payload.go index 80f56f0f7..5bfde2a75 100644 --- a/pkg/consensus/payload.go +++ b/pkg/consensus/payload.go @@ -49,6 +49,8 @@ const ( commitType messageType = 0x30 recoveryRequestType messageType = 0x40 recoveryMessageType messageType = 0x41 + + payloadGasLimit = 2000000 // 0.02 GAS ) // ViewNumber implements payload.ConsensusPayload interface. @@ -221,6 +223,7 @@ func (p *Payload) Verify(scriptHash util.Uint160) bool { } v := vm.New() + v.GasLimit = payloadGasLimit v.RegisterInteropGetter(crypto.GetInterop(&interop.Context{Container: p})) v.LoadScript(verification) v.LoadScript(p.Witness.InvocationScript) From 395f4ea46d037a2d03cc528fcbedf1656301711b Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 13 Jul 2020 18:07:59 +0300 Subject: [PATCH 4/8] consensus: limit the number of signatures used for test transactions We only need 3 out of 4. --- pkg/consensus/consensus_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/consensus/consensus_test.go b/pkg/consensus/consensus_test.go index 902a31546..0ff079a03 100644 --- a/pkg/consensus/consensus_test.go +++ b/pkg/consensus/consensus_test.go @@ -257,6 +257,7 @@ func signTx(t *testing.T, feePerByte int64, txs ...*transaction.Transaction) { privNetKeys[i] = testchain.PrivateKey(i) validators[i] = privNetKeys[i].PublicKey() } + privNetKeys = privNetKeys[:3] rawScript, err := smartcontract.CreateMultiSigRedeemScript(3, validators) require.NoError(t, err) for _, tx := range txs { From 419d68329c1fa31962df2cbe139fa0112619d4ab Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 13 Jul 2020 18:24:58 +0300 Subject: [PATCH 5/8] core: limit GAS available for block verification --- pkg/core/blockchain.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index bbfa38219..866f38a9f 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -35,7 +35,8 @@ const ( headerBatchCount = 2000 version = "0.1.0" - defaultMemPoolSize = 50000 + defaultMemPoolSize = 50000 + verificationGasLimit = 100000000 // 1 GAS ) var ( @@ -1294,13 +1295,15 @@ func ScriptFromWitness(hash util.Uint160, witness *transaction.Witness) ([]byte, } // verifyHashAgainstScript verifies given hash against the given witness. -func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, interopCtx *interop.Context, useKeys bool) error { +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 } vm := SpawnVM(interopCtx) + vm.SetPriceGetter(getPrice) + vm.GasLimit = gas vm.LoadScriptWithFlags(verification, smartcontract.ReadOnly) vm.LoadScript(witness.InvocationScript) if useKeys { @@ -1355,7 +1358,7 @@ func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block sort.Slice(witnesses, func(i, j int) bool { return witnesses[i].ScriptHash().Less(witnesses[j].ScriptHash()) }) interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, block, t) for i := 0; i < len(hashes); i++ { - err := bc.verifyHashAgainstScript(hashes[i], &witnesses[i], interopCtx, false) + err := bc.verifyHashAgainstScript(hashes[i], &witnesses[i], interopCtx, false, 0) if err != nil { numStr := fmt.Sprintf("witness #%d", i) return errors.Wrap(err, numStr) @@ -1375,7 +1378,7 @@ func (bc *Blockchain) verifyHeaderWitnesses(currHeader, prevHeader *block.Header } interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, nil, nil) interopCtx.Container = currHeader - return bc.verifyHashAgainstScript(hash, &currHeader.Script, interopCtx, true) + return bc.verifyHashAgainstScript(hash, &currHeader.Script, interopCtx, true, verificationGasLimit) } // GoverningTokenHash returns the governing token (NEO) native contract hash. From e21a36a7052152aeecfa08b20beae655c51ebd1a Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 13 Jul 2020 20:09:58 +0300 Subject: [PATCH 6/8] config: add MaxGasInvoke to all configuration files Limit the GAS available by default. --- config/protocol.mainnet.yml | 1 + config/protocol.privnet.docker.four.yml | 1 + config/protocol.privnet.docker.one.yml | 1 + config/protocol.privnet.docker.three.yml | 1 + config/protocol.privnet.docker.two.yml | 1 + config/protocol.privnet.yml | 1 + config/protocol.testnet.yml | 1 + config/protocol.unit_testnet.yml | 1 + 8 files changed, 8 insertions(+) diff --git a/config/protocol.mainnet.yml b/config/protocol.mainnet.yml index 1b4e8bada..8c146186a 100644 --- a/config/protocol.mainnet.yml +++ b/config/protocol.mainnet.yml @@ -48,6 +48,7 @@ ApplicationConfiguration: MinPeers: 5 RPC: Enabled: true + MaxGasInvoke: 10 EnableCORSWorkaround: false Port: 10332 TLSConfig: diff --git a/config/protocol.privnet.docker.four.yml b/config/protocol.privnet.docker.four.yml index ea879039f..cd75eb539 100644 --- a/config/protocol.privnet.docker.four.yml +++ b/config/protocol.privnet.docker.four.yml @@ -44,6 +44,7 @@ ApplicationConfiguration: MinPeers: 3 RPC: Enabled: true + MaxGasInvoke: 10 EnableCORSWorkaround: false Port: 30336 Prometheus: diff --git a/config/protocol.privnet.docker.one.yml b/config/protocol.privnet.docker.one.yml index 69e7b9efc..ab1bc4ba0 100644 --- a/config/protocol.privnet.docker.one.yml +++ b/config/protocol.privnet.docker.one.yml @@ -44,6 +44,7 @@ ApplicationConfiguration: MinPeers: 3 RPC: Enabled: true + MaxGasInvoke: 10 EnableCORSWorkaround: false Port: 30333 Prometheus: diff --git a/config/protocol.privnet.docker.three.yml b/config/protocol.privnet.docker.three.yml index 9f4b0da88..74da6f1a1 100644 --- a/config/protocol.privnet.docker.three.yml +++ b/config/protocol.privnet.docker.three.yml @@ -44,6 +44,7 @@ ApplicationConfiguration: MinPeers: 3 RPC: Enabled: true + MaxGasInvoke: 10 EnableCORSWorkaround: false Port: 30335 Prometheus: diff --git a/config/protocol.privnet.docker.two.yml b/config/protocol.privnet.docker.two.yml index cae6428b9..7135bb3df 100644 --- a/config/protocol.privnet.docker.two.yml +++ b/config/protocol.privnet.docker.two.yml @@ -44,6 +44,7 @@ ApplicationConfiguration: MinPeers: 3 RPC: Enabled: true + MaxGasInvoke: 10 EnableCORSWorkaround: false Port: 30334 Prometheus: diff --git a/config/protocol.privnet.yml b/config/protocol.privnet.yml index 7d95a03f3..e17824f13 100644 --- a/config/protocol.privnet.yml +++ b/config/protocol.privnet.yml @@ -44,6 +44,7 @@ ApplicationConfiguration: MinPeers: 3 RPC: Enabled: true + MaxGasInvoke: 10 EnableCORSWorkaround: false Port: 20331 TLSConfig: diff --git a/config/protocol.testnet.yml b/config/protocol.testnet.yml index 2a9c152b3..7463f899b 100644 --- a/config/protocol.testnet.yml +++ b/config/protocol.testnet.yml @@ -48,6 +48,7 @@ ApplicationConfiguration: MinPeers: 5 RPC: Enabled: true + MaxGasInvoke: 10 EnableCORSWorkaround: false Port: 20332 TLSConfig: diff --git a/config/protocol.unit_testnet.yml b/config/protocol.unit_testnet.yml index 23c924c31..26ba3443c 100644 --- a/config/protocol.unit_testnet.yml +++ b/config/protocol.unit_testnet.yml @@ -43,6 +43,7 @@ ApplicationConfiguration: MinPeers: 1 RPC: Address: 127.0.0.1 + MaxGasInvoke: 10 Enabled: true EnableCORSWorkaround: false Port: 0 # let the system choose port dynamically From a5d6c76928d9b485fefbcb24c2a625efa49d5107 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 13 Jul 2020 20:10:27 +0300 Subject: [PATCH 7/8] cli: pay a system fee for the invocation --- cli/smartcontract/smart_contract.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index fe8b15a6c..48560024c 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -460,7 +460,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error { if err != nil { return cli.NewExitError(fmt.Errorf("bad script returned from the RPC node: %v", err), 1) } - txHash, err := c.SignAndPushInvocationTx(script, acc, 0, gas, cosigners) + txHash, err := c.SignAndPushInvocationTx(script, acc, resp.GasConsumed, gas, cosigners) if err != nil { return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %v", err), 1) } From db027ad9c579819159882f62afb14de6f9d64c98 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 13 Jul 2020 20:12:13 +0300 Subject: [PATCH 8/8] vm: zero GAS means no GAS, use fee data to properly limit execution We were accepting transactions with zero system fee, but we shouldn't do that. Also, transaction's verification execution has to be limited by network fee. --- pkg/consensus/consensus_test.go | 4 ++-- pkg/core/blockchain.go | 3 ++- pkg/core/helper_test.go | 6 +++--- pkg/core/interop/crypto/ecdsa_test.go | 1 + pkg/core/native_policy_test.go | 2 +- pkg/rpc/server/server_test.go | 6 +++--- pkg/rpc/server/testdata/testblocks.acc | Bin 6810 -> 6810 bytes pkg/smartcontract/context/context_test.go | 1 + pkg/vm/vm.go | 4 ++-- pkg/vm/vm_test.go | 20 +++++++++++++------- 10 files changed, 28 insertions(+), 19 deletions(-) diff --git a/pkg/consensus/consensus_test.go b/pkg/consensus/consensus_test.go index 0ff079a03..ef5ff98dc 100644 --- a/pkg/consensus/consensus_test.go +++ b/pkg/consensus/consensus_test.go @@ -24,7 +24,7 @@ import ( func TestNewService(t *testing.T) { srv := newTestService(t) - tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0) + tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 100000) tx.ValidUntilBlock = 1 addSender(t, tx) signTx(t, srv.Chain.FeePerByte(), tx) @@ -42,7 +42,7 @@ func TestService_GetVerified(t *testing.T) { srv.dbft.Start() var txs []*transaction.Transaction for i := 0; i < 4; i++ { - tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0) + tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 100000) tx.Nonce = 123 + uint32(i) tx.ValidUntilBlock = 1 txs = append(txs, tx) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 866f38a9f..c8bea038a 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -568,6 +568,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { if block.Index > 0 { systemInterop := bc.newInteropContext(trigger.System, cache, block, nil) v := SpawnVM(systemInterop) + v.GasLimit = -1 v.LoadScriptWithFlags(bc.contracts.GetPersistScript(), smartcontract.AllowModifyStates|smartcontract.AllowCall) v.SetPriceGetter(getPrice) if err := v.Run(); err != nil { @@ -1358,7 +1359,7 @@ func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block sort.Slice(witnesses, func(i, j int) bool { return witnesses[i].ScriptHash().Less(witnesses[j].ScriptHash()) }) interopCtx := bc.newInteropContext(trigger.Verification, bc.dao, block, t) for i := 0; i < len(hashes); i++ { - err := bc.verifyHashAgainstScript(hashes[i], &witnesses[i], interopCtx, false, 0) + err := bc.verifyHashAgainstScript(hashes[i], &witnesses[i], interopCtx, false, t.NetworkFee) if err != nil { numStr := fmt.Sprintf("witness #%d", i) return errors.Wrap(err, numStr) diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index 32ae216de..acd55d969 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -257,7 +257,7 @@ func TestCreateBasicChain(t *testing.T) { script = io.NewBufBinWriter() emit.AppCallWithOperationAndArgs(script.BinWriter, hash.Hash160(avm), "Put", "testkey", "testvalue") - txInv := transaction.New(testchain.Network(), script.Bytes(), 0) + txInv := transaction.New(testchain.Network(), script.Bytes(), 1*native.GASFactor) txInv.Nonce = getNextNonce() txInv.ValidUntilBlock = validUntilBlock txInv.Sender = priv0ScriptHash @@ -288,7 +288,7 @@ func TestCreateBasicChain(t *testing.T) { sh := hash.Hash160(avm) w := io.NewBufBinWriter() emit.AppCallWithOperationAndArgs(w.BinWriter, sh, "init") - initTx := transaction.New(testchain.Network(), w.Bytes(), 0) + initTx := transaction.New(testchain.Network(), w.Bytes(), 1*native.GASFactor) initTx.Nonce = getNextNonce() initTx.ValidUntilBlock = validUntilBlock initTx.Sender = priv0ScriptHash @@ -378,7 +378,7 @@ func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Trans emit.Opcode(w.BinWriter, opcode.ASSERT) script := w.Bytes() - return transaction.New(testchain.Network(), script, 0) + return transaction.New(testchain.Network(), script, 10000000) } func addSender(txs ...*transaction.Transaction) error { diff --git a/pkg/core/interop/crypto/ecdsa_test.go b/pkg/core/interop/crypto/ecdsa_test.go index 8dfa856ef..a628966a9 100644 --- a/pkg/core/interop/crypto/ecdsa_test.go +++ b/pkg/core/interop/crypto/ecdsa_test.go @@ -60,6 +60,7 @@ func initCHECKMULTISIGVM(t *testing.T, n int, ik, is []int) *vm.VM { binary.LittleEndian.PutUint32(buf[1:], ecdsaCheckMultisigID) v := vm.New() + v.GasLimit = -1 ic := &interop.Context{Trigger: trigger.Verification} v.RegisterInteropGetter(GetInterop(ic)) v.LoadScript(buf) diff --git a/pkg/core/native_policy_test.go b/pkg/core/native_policy_test.go index 765f114ec..903af3925 100644 --- a/pkg/core/native_policy_test.go +++ b/pkg/core/native_policy_test.go @@ -227,7 +227,7 @@ func invokeNativePolicyMethod(chain *Blockchain, method string, args ...interfac return nil, w.Err } script := w.Bytes() - tx := transaction.New(chain.GetConfig().Magic, script, 0) + tx := transaction.New(chain.GetConfig().Magic, script, 10000000) validUntil := chain.blockHeight + 1 tx.ValidUntilBlock = validUntil err := addSender(tx) diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 59100f6c3..04ab458b3 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -52,7 +52,7 @@ type rpcTestCase struct { } const testContractHash = "10e262ef80c76bdecca287a2c047841fc02c3129" -const deploymentTxHash = "ad8b149c799d4b2337162b0ad23e0ba8845cddb9cfca8a45587ee207015d2a7c" +const deploymentTxHash = "4843700d16be3e6507a25909d3b2aa1472dcd0526be2520f2bfdd53d768bfebf" var rpcTestCases = map[string][]rpcTestCase{ "getapplicationlog": { @@ -148,7 +148,7 @@ var rpcTestCases = map[string][]rpcTestCase{ }, { Asset: e.chain.UtilityTokenHash(), - Amount: "918.01738700", + Amount: "915.79002700", LastUpdated: 6, }}, Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), @@ -720,7 +720,7 @@ var rpcTestCases = map[string][]rpcTestCase{ "sendrawtransaction": { { name: "positive", - params: `["000a000000316e851039019d39dfc2c37d6c3fee19fd5809870000000000000000f2ad050000000000b00400000001316e851039019d39dfc2c37d6c3fee19fd580987015d0300e87648170000000c1420728274afafc36f43a071d328cfa3e629d9cbb00c14316e851039019d39dfc2c37d6c3fee19fd58098713c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801420c409803db41e66a94e0bd6fdd3d7a7b1e106c1e2281c9782a231f32df036bb80c7f19155cdb9a52a45cf8d93ec9c1e8df69d6ee35625f352d1710c7cc6eee26003c290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b410a906ad4"]`, + params: `["000a000000316e851039019d39dfc2c37d6c3fee19fd58098780969800000000009269130000000000b00400000001316e851039019d39dfc2c37d6c3fee19fd580987015d0300e87648170000000c1420728274afafc36f43a071d328cfa3e629d9cbb00c14316e851039019d39dfc2c37d6c3fee19fd58098713c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801420c4037c8c002c3352329c5f2995567a355d57372447c156ea544844d5f8027babf4cd86142d986681992805e3f62f2625b551f18cf05897e6ea7c135f22537bb740e290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b410a906ad4"]`, result: func(e *executor) interface{} { v := true return &v diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index d1756b35bc17ba6d6c3719166bded1b7af9f17d2..c00d33f9ecfc98f5bb3ec468d57022777fcf098f 100644 GIT binary patch delta 3198 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 b;H*~m*h~a9IHuEWDM=oazSz3GU;O?Dj{D>) diff --git a/pkg/smartcontract/context/context_test.go b/pkg/smartcontract/context/context_test.go index 1971ea88a..5ae5e836d 100644 --- a/pkg/smartcontract/context/context_test.go +++ b/pkg/smartcontract/context/context_test.go @@ -111,6 +111,7 @@ func TestParameterContext_AddSignatureMultisig(t *testing.T) { func newTestVM(w *transaction.Witness, tx *transaction.Transaction) *vm.VM { v := vm.New() + v.GasLimit = -1 v.RegisterInteropGetter(crypto.GetInterop(&interop.Context{Container: tx})) v.LoadScript(w.VerificationScript) v.LoadScript(w.InvocationScript) diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 2105e58e9..630bbfc19 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -133,7 +133,7 @@ func (v *VM) GasConsumed() int64 { // AddGas consumes specified amount of gas. It returns true iff gas limit wasn't exceeded. func (v *VM) AddGas(gas int64) bool { v.gasConsumed += gas - return v.GasLimit == 0 || v.gasConsumed <= v.GasLimit + return v.GasLimit < 0 || v.gasConsumed <= v.GasLimit } // Estack returns the evaluation stack so interop hooks can utilize this. @@ -523,7 +523,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro if v.getPrice != nil && ctx.ip < len(ctx.prog) { v.gasConsumed += v.getPrice(v, op, parameter) - if v.GasLimit > 0 && v.gasConsumed > v.GasLimit { + if v.GasLimit >= 0 && v.gasConsumed > v.GasLimit { panic("gas limit is exceeded") } } diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 35f3b33a8..e076a0f71 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -35,7 +35,7 @@ func fooInteropGetter(id uint32) *InteropFuncPrice { } func TestInteropHook(t *testing.T) { - v := New() + v := newTestVM() v.RegisterInteropGetter(fooInteropGetter) buf := io.NewBufBinWriter() @@ -48,14 +48,14 @@ func TestInteropHook(t *testing.T) { } func TestRegisterInteropGetter(t *testing.T) { - v := New() + v := newTestVM() currRegistered := len(v.getInterop) v.RegisterInteropGetter(fooInteropGetter) assert.Equal(t, currRegistered+1, len(v.getInterop)) } func TestVM_SetPriceGetter(t *testing.T) { - v := New() + v := newTestVM() prog := []byte{ byte(opcode.PUSH4), byte(opcode.PUSH2), byte(opcode.PUSHDATA1), 0x01, 0x01, @@ -103,7 +103,7 @@ func TestVM_SetPriceGetter(t *testing.T) { } func TestAddGas(t *testing.T) { - v := New() + v := newTestVM() v.GasLimit = 10 require.True(t, v.AddGas(5)) require.True(t, v.AddGas(5)) @@ -111,7 +111,7 @@ func TestAddGas(t *testing.T) { } func TestBytesToPublicKey(t *testing.T) { - v := New() + v := newTestVM() cache := v.GetPublicKeys() assert.Equal(t, 0, len(cache)) keyHex := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c" @@ -819,7 +819,7 @@ func TestSerializeInterop(t *testing.T) { func getTestCallFlagsFunc(syscall []byte, flags smartcontract.CallFlag, result interface{}) func(t *testing.T) { return func(t *testing.T) { script := append([]byte{byte(opcode.SYSCALL)}, syscall...) - v := New() + v := newTestVM() v.RegisterInteropGetter(getTestingInterop) v.LoadScriptWithFlags(script, flags) if result == nil { @@ -2518,7 +2518,7 @@ func makeProgram(opcodes ...opcode.Opcode) []byte { } func load(prog []byte) *VM { - vm := New() + vm := newTestVM() if len(prog) != 0 { vm.LoadScript(prog) } @@ -2533,3 +2533,9 @@ func randomBytes(n int) []byte { } return b } + +func newTestVM() *VM { + v := New() + v.GasLimit = -1 + return v +}