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.
This commit is contained in:
parent
260bcd373c
commit
6a4e312eac
11 changed files with 33 additions and 35 deletions
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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())
|
||||
})
|
||||
|
||||
|
|
11
pkg/core/interop/gas_price.go
Normal file
11
pkg/core/interop/gas_price.go
Normal file
|
@ -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)
|
||||
}
|
|
@ -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},
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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}) {
|
||||
|
|
Loading…
Reference in a new issue