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)
|
systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx)
|
||||||
v := systemInterop.SpawnVM()
|
v := systemInterop.SpawnVM()
|
||||||
v.LoadScriptWithFlags(tx.Script, callflag.All)
|
v.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||||
v.SetPriceGetter(bc.getPrice)
|
v.SetPriceGetter(systemInterop.GetPrice)
|
||||||
v.LoadToken = contract.LoadToken(systemInterop)
|
v.LoadToken = contract.LoadToken(systemInterop)
|
||||||
v.GasLimit = tx.SystemFee
|
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)
|
systemInterop := bc.newInteropContext(trig, cache, block, nil)
|
||||||
v := systemInterop.SpawnVM()
|
v := systemInterop.SpawnVM()
|
||||||
v.LoadScriptWithFlags(script, callflag.WriteStates|callflag.AllowCall)
|
v.LoadScriptWithFlags(script, callflag.WriteStates|callflag.AllowCall)
|
||||||
v.SetPriceGetter(bc.getPrice)
|
v.SetPriceGetter(systemInterop.GetPrice)
|
||||||
if err := v.Run(); err != nil {
|
if err := v.Run(); err != nil {
|
||||||
return nil, fmt.Errorf("VM has failed: %w", err)
|
return nil, fmt.Errorf("VM has failed: %w", err)
|
||||||
} else if _, err := systemInterop.DAO.Persist(); err != nil {
|
} 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
|
d.MPT = nil
|
||||||
systemInterop := bc.newInteropContext(t, d, b, tx)
|
systemInterop := bc.newInteropContext(t, d, b, tx)
|
||||||
vm := systemInterop.SpawnVM()
|
vm := systemInterop.SpawnVM()
|
||||||
vm.SetPriceGetter(bc.getPrice)
|
vm.SetPriceGetter(systemInterop.GetPrice)
|
||||||
vm.LoadToken = contract.LoadToken(systemInterop)
|
vm.LoadToken = contract.LoadToken(systemInterop)
|
||||||
return vm
|
return vm
|
||||||
}
|
}
|
||||||
|
@ -1794,7 +1794,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
|
||||||
}
|
}
|
||||||
|
|
||||||
vm := interopCtx.SpawnVM()
|
vm := interopCtx.SpawnVM()
|
||||||
vm.SetPriceGetter(bc.getPrice)
|
vm.SetPriceGetter(interopCtx.GetPrice)
|
||||||
vm.LoadToken = contract.LoadToken(interopCtx)
|
vm.LoadToken = contract.LoadToken(interopCtx)
|
||||||
vm.GasLimit = gas
|
vm.GasLimit = gas
|
||||||
if err := bc.initVerificationVM(interopCtx, hash, witness); err != nil {
|
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`.
|
// GetBaseExecFee return execution price for `NOP`.
|
||||||
func (bc *Blockchain) GetBaseExecFee() int64 {
|
func (bc *Blockchain) GetBaseExecFee() int64 {
|
||||||
if bc.BlockHeight() == 0 {
|
|
||||||
return interop.DefaultBaseExecFee
|
|
||||||
}
|
|
||||||
return bc.contracts.Policy.GetExecFeeFactorInternal(bc.dao)
|
return bc.contracts.Policy.GetExecFeeFactorInternal(bc.dao)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
package fee
|
package fee
|
||||||
|
|
||||||
import (
|
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/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"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/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"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
|
// Calculate returns network fee for transaction
|
||||||
func Calculate(base int64, script []byte) (int64, int) {
|
func Calculate(base int64, script []byte) (int64, int) {
|
||||||
var (
|
var (
|
||||||
|
@ -16,13 +18,13 @@ func Calculate(base int64, script []byte) (int64, int) {
|
||||||
)
|
)
|
||||||
if vm.IsSignatureContract(script) {
|
if vm.IsSignatureContract(script) {
|
||||||
size += 67 + io.GetVarSize(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 {
|
} else if m, pubs, ok := vm.ParseMultiSigContract(script); ok {
|
||||||
n := len(pubs)
|
n := len(pubs)
|
||||||
sizeInv := 66 * m
|
sizeInv := 66 * m
|
||||||
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
|
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
|
||||||
netFee += calculateMultisig(base, m) + calculateMultisig(base, n)
|
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 {
|
} else {
|
||||||
// We can support more contract types in the future.
|
// 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.
|
// BaseExecFee represents factor to multiply syscall prices with.
|
||||||
func (ic *Context) BaseExecFee() int64 {
|
func (ic *Context) BaseExecFee() int64 {
|
||||||
if ic.Chain == nil {
|
if ic.Chain == nil || (ic.Block != nil && ic.Block.Index == 0) {
|
||||||
return DefaultBaseExecFee
|
return DefaultBaseExecFee
|
||||||
}
|
}
|
||||||
return ic.Chain.GetPolicer().GetBaseExecFee()
|
return ic.Chain.GetPolicer().GetBaseExecFee()
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"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/core/interop"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
|
@ -15,9 +16,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"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.
|
// ECDSASecp256r1Verify checks ECDSA signature using Secp256r1 elliptic curve.
|
||||||
func ECDSASecp256r1Verify(ic *interop.Context) error {
|
func ECDSASecp256r1Verify(ic *interop.Context) error {
|
||||||
return ecdsaVerify(ic, elliptic.P256())
|
return ecdsaVerify(ic, elliptic.P256())
|
||||||
|
@ -69,7 +67,7 @@ func ecdsaCheckMultisig(ic *interop.Context, curve elliptic.Curve) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("wrong parameters: %w", err)
|
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")
|
return errors.New("gas limit exceeded")
|
||||||
}
|
}
|
||||||
sigs, err := ic.VM.Estack().PopSigElements()
|
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/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
"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/interop"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
"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/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("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) {
|
t.Run("gas limit exceeded", func(t *testing.T) {
|
||||||
v := initCHECKMULTISIGVM(t, isR1, 1, []int{0}, []int{0})
|
v := initCHECKMULTISIGVM(t, isR1, 1, []int{0}, []int{0})
|
||||||
v.GasLimit = ECDSAVerifyPrice - 1
|
v.GasLimit = fee.ECDSAVerifyPrice - 1
|
||||||
require.Error(t, v.Run())
|
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 (
|
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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/binary"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/binary"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
|
||||||
|
@ -98,9 +99,9 @@ var systemInterops = []interop.Function{
|
||||||
|
|
||||||
var neoInterops = []interop.Function{
|
var neoInterops = []interop.Function{
|
||||||
{Name: interopnames.NeoCryptoVerifyWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1Verify,
|
{Name: interopnames.NeoCryptoVerifyWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1Verify,
|
||||||
Price: crypto.ECDSAVerifyPrice, ParamCount: 3},
|
Price: fee.ECDSAVerifyPrice, ParamCount: 3},
|
||||||
{Name: interopnames.NeoCryptoVerifyWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1Verify,
|
{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.NeoCryptoCheckMultisigWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 3},
|
||||||
{Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1CheckMultisig, 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},
|
{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/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
"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/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
|
|
@ -65,7 +65,7 @@ type VM struct {
|
||||||
state State
|
state State
|
||||||
|
|
||||||
// callback to get interop price
|
// callback to get interop price
|
||||||
getPrice func(*VM, opcode.Opcode, []byte) int64
|
getPrice func(opcode.Opcode, []byte) int64
|
||||||
|
|
||||||
istack *Stack // invocation stack.
|
istack *Stack // invocation stack.
|
||||||
estack *Stack // execution stack.
|
estack *Stack // execution stack.
|
||||||
|
@ -119,7 +119,7 @@ func (v *VM) newItemStack(n string) *Stack {
|
||||||
|
|
||||||
// SetPriceGetter registers the given PriceGetterFunc in v.
|
// SetPriceGetter registers the given PriceGetterFunc in v.
|
||||||
// f accepts vm's Context, current instruction and instruction parameter.
|
// 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
|
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) {
|
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 {
|
if v.GasLimit >= 0 && v.gasConsumed > v.GasLimit {
|
||||||
panic("gas limit is exceeded")
|
panic("gas limit is exceeded")
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ func TestVM_SetPriceGetter(t *testing.T) {
|
||||||
require.EqualValues(t, 0, v.GasConsumed())
|
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 {
|
if op == opcode.PUSH4 {
|
||||||
return 1
|
return 1
|
||||||
} else if op == opcode.PUSHDATA1 && bytes.Equal(p, []byte{0xCA, 0xFE}) {
|
} else if op == opcode.PUSHDATA1 && bytes.Equal(p, []byte{0xCA, 0xFE}) {
|
||||||
|
|
Loading…
Reference in a new issue