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}) {