From 6a4e312eac8db705630fded7d262b3d0e70cdf47 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 5 Feb 2021 11:25:22 +0300 Subject: [PATCH] core: move GetPrice from `core` to `interop` We have additional logic for getting BaseExecFee policy value. This logic should be moved to interop context instead of being in Policer, because Policer is just an interface over Policy contract. After moving this logic to interop context, we need to use it to define BaseExecFee instead of (Policer).BaseExecFee. Thus, moving (*Blockchain).GetPrice to (*Context).GetPrice is necessary. --- pkg/core/blockchain.go | 11 ++++------- pkg/core/fee/calculate.go | 8 +++++--- pkg/core/gas_price.go | 12 ------------ pkg/core/interop/context.go | 2 +- pkg/core/interop/crypto/ecdsa.go | 6 ++---- pkg/core/interop/crypto/ecdsa_test.go | 3 ++- pkg/core/interop/gas_price.go | 11 +++++++++++ pkg/core/interops.go | 5 +++-- pkg/rpc/server/server_test.go | 2 +- pkg/vm/vm.go | 6 +++--- pkg/vm/vm_test.go | 2 +- 11 files changed, 33 insertions(+), 35 deletions(-) delete mode 100644 pkg/core/gas_price.go create mode 100644 pkg/core/interop/gas_price.go diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 93000f95f..b516e1ff4 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -641,7 +641,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx) v := systemInterop.SpawnVM() v.LoadScriptWithFlags(tx.Script, callflag.All) - v.SetPriceGetter(bc.getPrice) + v.SetPriceGetter(systemInterop.GetPrice) v.LoadToken = contract.LoadToken(systemInterop) v.GasLimit = tx.SystemFee @@ -849,7 +849,7 @@ func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.C systemInterop := bc.newInteropContext(trig, cache, block, nil) v := systemInterop.SpawnVM() v.LoadScriptWithFlags(script, callflag.WriteStates|callflag.AllowCall) - v.SetPriceGetter(bc.getPrice) + v.SetPriceGetter(systemInterop.GetPrice) if err := v.Run(); err != nil { return nil, fmt.Errorf("VM has failed: %w", err) } else if _, err := systemInterop.DAO.Persist(); err != nil { @@ -1718,7 +1718,7 @@ func (bc *Blockchain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b * d.MPT = nil systemInterop := bc.newInteropContext(t, d, b, tx) vm := systemInterop.SpawnVM() - vm.SetPriceGetter(bc.getPrice) + vm.SetPriceGetter(systemInterop.GetPrice) vm.LoadToken = contract.LoadToken(systemInterop) return vm } @@ -1794,7 +1794,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa } vm := interopCtx.SpawnVM() - vm.SetPriceGetter(bc.getPrice) + vm.SetPriceGetter(interopCtx.GetPrice) vm.LoadToken = contract.LoadToken(interopCtx) vm.GasLimit = gas if err := bc.initVerificationVM(interopCtx, hash, witness); err != nil { @@ -1918,9 +1918,6 @@ func (bc *Blockchain) GetPolicer() blockchainer.Policer { // GetBaseExecFee return execution price for `NOP`. func (bc *Blockchain) GetBaseExecFee() int64 { - if bc.BlockHeight() == 0 { - return interop.DefaultBaseExecFee - } return bc.contracts.Policy.GetExecFeeFactorInternal(bc.dao) } diff --git a/pkg/core/fee/calculate.go b/pkg/core/fee/calculate.go index 0cf4e6383..4966ad4f5 100644 --- a/pkg/core/fee/calculate.go +++ b/pkg/core/fee/calculate.go @@ -1,13 +1,15 @@ package fee import ( - "github.com/nspcc-dev/neo-go/pkg/core/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/io" "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" ) +// ECDSAVerifyPrice is a gas price of a single verification. +const ECDSAVerifyPrice = 1 << 15 + // Calculate returns network fee for transaction func Calculate(base int64, script []byte) (int64, int) { var ( @@ -16,13 +18,13 @@ func Calculate(base int64, script []byte) (int64, int) { ) if vm.IsSignatureContract(script) { size += 67 + io.GetVarSize(script) - netFee += Opcode(base, opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + base*crypto.ECDSAVerifyPrice + netFee += Opcode(base, opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + base*ECDSAVerifyPrice } else if m, pubs, ok := vm.ParseMultiSigContract(script); ok { n := len(pubs) sizeInv := 66 * m size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script) netFee += calculateMultisig(base, m) + calculateMultisig(base, n) - netFee += Opcode(base, opcode.PUSHNULL) + base*crypto.ECDSAVerifyPrice*int64(n) + netFee += Opcode(base, opcode.PUSHNULL) + base*ECDSAVerifyPrice*int64(n) } else { // We can support more contract types in the future. } diff --git a/pkg/core/gas_price.go b/pkg/core/gas_price.go deleted file mode 100644 index 406e1e65a..000000000 --- a/pkg/core/gas_price.go +++ /dev/null @@ -1,12 +0,0 @@ -package core - -import ( - "github.com/nspcc-dev/neo-go/pkg/core/fee" - "github.com/nspcc-dev/neo-go/pkg/vm" - "github.com/nspcc-dev/neo-go/pkg/vm/opcode" -) - -// getPrice returns a price for executing op with the provided parameter. -func (bc *Blockchain) getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) int64 { - return fee.Opcode(bc.GetBaseExecFee(), op) -} diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index 5cd231150..0d00d3e10 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -199,7 +199,7 @@ func (ic *Context) GetFunction(id uint32) *Function { // BaseExecFee represents factor to multiply syscall prices with. func (ic *Context) BaseExecFee() int64 { - if ic.Chain == nil { + if ic.Chain == nil || (ic.Block != nil && ic.Block.Index == 0) { return DefaultBaseExecFee } return ic.Chain.GetPolicer().GetBaseExecFee() diff --git a/pkg/core/interop/crypto/ecdsa.go b/pkg/core/interop/crypto/ecdsa.go index 3e27810af..a31ca3e70 100644 --- a/pkg/core/interop/crypto/ecdsa.go +++ b/pkg/core/interop/crypto/ecdsa.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/btcsuite/btcd/btcec" + "github.com/nspcc-dev/neo-go/pkg/core/fee" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/crypto" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" @@ -15,9 +16,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) -// ECDSAVerifyPrice is a gas price of a single verification. -const ECDSAVerifyPrice = 1 << 15 - // ECDSASecp256r1Verify checks ECDSA signature using Secp256r1 elliptic curve. func ECDSASecp256r1Verify(ic *interop.Context) error { return ecdsaVerify(ic, elliptic.P256()) @@ -69,7 +67,7 @@ func ecdsaCheckMultisig(ic *interop.Context, curve elliptic.Curve) error { if err != nil { return fmt.Errorf("wrong parameters: %w", err) } - if !ic.VM.AddGas(ic.BaseExecFee() * ECDSAVerifyPrice * int64(len(pkeys))) { + if !ic.VM.AddGas(ic.BaseExecFee() * fee.ECDSAVerifyPrice * int64(len(pkeys))) { return errors.New("gas limit exceeded") } sigs, err := ic.VM.Estack().PopSigElements() diff --git a/pkg/core/interop/crypto/ecdsa_test.go b/pkg/core/interop/crypto/ecdsa_test.go index 58fab77d6..1939514f2 100644 --- a/pkg/core/interop/crypto/ecdsa_test.go +++ b/pkg/core/interop/crypto/ecdsa_test.go @@ -7,6 +7,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/dao" + "github.com/nspcc-dev/neo-go/pkg/core/fee" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -247,7 +248,7 @@ func testCurveCHECKMULTISIGBad(t *testing.T, isR1 bool) { t.Run("1_2 too many signatures", func(t *testing.T) { testCHECKMULTISIGBad(t, isR1, true, 2, []int{0}, []int{0, 1}) }) t.Run("gas limit exceeded", func(t *testing.T) { v := initCHECKMULTISIGVM(t, isR1, 1, []int{0}, []int{0}) - v.GasLimit = ECDSAVerifyPrice - 1 + v.GasLimit = fee.ECDSAVerifyPrice - 1 require.Error(t, v.Run()) }) diff --git a/pkg/core/interop/gas_price.go b/pkg/core/interop/gas_price.go new file mode 100644 index 000000000..c72671411 --- /dev/null +++ b/pkg/core/interop/gas_price.go @@ -0,0 +1,11 @@ +package interop + +import ( + "github.com/nspcc-dev/neo-go/pkg/core/fee" + "github.com/nspcc-dev/neo-go/pkg/vm/opcode" +) + +// GetPrice returns a price for executing op with the provided parameter. +func (ic *Context) GetPrice(op opcode.Opcode, parameter []byte) int64 { + return fee.Opcode(ic.BaseExecFee(), op) +} diff --git a/pkg/core/interops.go b/pkg/core/interops.go index 08dccd64d..d210ca97b 100644 --- a/pkg/core/interops.go +++ b/pkg/core/interops.go @@ -8,6 +8,7 @@ package core */ import ( + "github.com/nspcc-dev/neo-go/pkg/core/fee" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop/binary" "github.com/nspcc-dev/neo-go/pkg/core/interop/contract" @@ -98,9 +99,9 @@ var systemInterops = []interop.Function{ var neoInterops = []interop.Function{ {Name: interopnames.NeoCryptoVerifyWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1Verify, - Price: crypto.ECDSAVerifyPrice, ParamCount: 3}, + Price: fee.ECDSAVerifyPrice, ParamCount: 3}, {Name: interopnames.NeoCryptoVerifyWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1Verify, - Price: crypto.ECDSAVerifyPrice, ParamCount: 3}, + Price: fee.ECDSAVerifyPrice, ParamCount: 3}, {Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 3}, {Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1CheckMultisig, Price: 0, ParamCount: 3}, {Name: interopnames.NeoCryptoSHA256, Func: crypto.Sha256, Price: 1 << 15, ParamCount: 1}, diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index a2da8e512..efe2a5f89 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -28,9 +28,9 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/io" - rpc2 "github.com/nspcc-dev/neo-go/pkg/services/oracle/broadcaster" "github.com/nspcc-dev/neo-go/pkg/rpc/response" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result" + rpc2 "github.com/nspcc-dev/neo-go/pkg/services/oracle/broadcaster" "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" diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index a1112a7b4..67f3b1f0c 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -65,7 +65,7 @@ type VM struct { state State // callback to get interop price - getPrice func(*VM, opcode.Opcode, []byte) int64 + getPrice func(opcode.Opcode, []byte) int64 istack *Stack // invocation stack. estack *Stack // execution stack. @@ -119,7 +119,7 @@ func (v *VM) newItemStack(n string) *Stack { // SetPriceGetter registers the given PriceGetterFunc in v. // f accepts vm's Context, current instruction and instruction parameter. -func (v *VM) SetPriceGetter(f func(*VM, opcode.Opcode, []byte) int64) { +func (v *VM) SetPriceGetter(f func(opcode.Opcode, []byte) int64) { v.getPrice = f } @@ -528,7 +528,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) + v.gasConsumed += v.getPrice(op, parameter) 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 3dcf0d652..281441f1c 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -62,7 +62,7 @@ func TestVM_SetPriceGetter(t *testing.T) { require.EqualValues(t, 0, v.GasConsumed()) }) - v.SetPriceGetter(func(_ *VM, op opcode.Opcode, p []byte) int64 { + v.SetPriceGetter(func(op opcode.Opcode, p []byte) int64 { if op == opcode.PUSH4 { return 1 } else if op == opcode.PUSHDATA1 && bytes.Equal(p, []byte{0xCA, 0xFE}) {