core: redefine opcode prices

Prices are defined in as a coefficients to `BaseExecFee` which
is defined by Policy contract (TBD later).
Native method prices are defined without need to multiply.
This commit is contained in:
Evgenii Stratonikov 2020-12-11 15:22:49 +03:00
parent 44b4c92992
commit 1840c1c80d
22 changed files with 342 additions and 298 deletions

View file

@ -92,7 +92,7 @@ func NewDeployTx(bc blockchainer.Blockchainer, name string, sender util.Uint160,
func SignTx(bc blockchainer.Blockchainer, txs ...*transaction.Transaction) error { func SignTx(bc blockchainer.Blockchainer, txs ...*transaction.Transaction) error {
for _, tx := range txs { for _, tx := range txs {
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(ownerScript) netFee, sizeDelta := fee.Calculate(bc.GetPolicer().GetBaseExecFee(), ownerScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
tx.NetworkFee += int64(size) * bc.FeePerByte() tx.NetworkFee += int64(size) * bc.FeePerByte()

View file

@ -11,6 +11,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"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" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/core/fee" "github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
@ -32,7 +33,7 @@ func TestNewService(t *testing.T) {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 100000) tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 100000)
tx.ValidUntilBlock = 1 tx.ValidUntilBlock = 1
addSender(t, tx) addSender(t, tx)
signTx(t, srv.Chain.FeePerByte(), tx) signTx(t, srv.Chain, tx)
require.NoError(t, srv.Chain.PoolTx(tx)) require.NoError(t, srv.Chain.PoolTx(tx))
var txx []block.Transaction var txx []block.Transaction
@ -170,7 +171,7 @@ func TestService_GetVerified(t *testing.T) {
txs = append(txs, tx) txs = append(txs, tx)
} }
addSender(t, txs...) addSender(t, txs...)
signTx(t, srv.Chain.FeePerByte(), txs...) signTx(t, srv.Chain, txs...)
require.NoError(t, srv.Chain.PoolTx(txs[3])) require.NoError(t, srv.Chain.PoolTx(txs[3]))
hashes := []util.Uint256{txs[0].Hash(), txs[1].Hash(), txs[2].Hash()} hashes := []util.Uint256{txs[0].Hash(), txs[1].Hash(), txs[2].Hash()}
@ -257,7 +258,7 @@ func TestService_getTx(t *testing.T) {
tx.Nonce = 1234 tx.Nonce = 1234
tx.ValidUntilBlock = 1 tx.ValidUntilBlock = 1
addSender(t, tx) addSender(t, tx)
signTx(t, srv.Chain.FeePerByte(), tx) signTx(t, srv.Chain, tx)
h := tx.Hash() h := tx.Hash()
require.Equal(t, nil, srv.getTx(h)) require.Equal(t, nil, srv.getTx(h))
@ -351,7 +352,7 @@ func TestVerifyBlock(t *testing.T) {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 100000) tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 100000)
tx.ValidUntilBlock = 1 tx.ValidUntilBlock = 1
addSender(t, tx) addSender(t, tx)
signTx(t, srv.Chain.FeePerByte(), tx) signTx(t, srv.Chain, tx)
require.NoError(t, srv.Chain.PoolTx(tx)) require.NoError(t, srv.Chain.PoolTx(tx))
b := testchain.NewBlock(t, srv.Chain, 1, 0, tx) b := testchain.NewBlock(t, srv.Chain, 1, 0, tx)
require.True(t, srv.verifyBlock(&neoBlock{Block: *b})) require.True(t, srv.verifyBlock(&neoBlock{Block: *b}))
@ -360,7 +361,7 @@ func TestVerifyBlock(t *testing.T) {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 100000) tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 100000)
tx.ValidUntilBlock = 1 tx.ValidUntilBlock = 1
addSender(t, tx) addSender(t, tx)
signTx(t, srv.Chain.FeePerByte(), tx) signTx(t, srv.Chain, tx)
b := testchain.NewBlock(t, srv.Chain, 1, 0, tx) b := testchain.NewBlock(t, srv.Chain, 1, 0, tx)
require.True(t, srv.verifyBlock(&neoBlock{Block: *b})) require.True(t, srv.verifyBlock(&neoBlock{Block: *b}))
}) })
@ -369,12 +370,12 @@ func TestVerifyBlock(t *testing.T) {
tx1.NetworkFee = 20_000_000 * native.GASFactor tx1.NetworkFee = 20_000_000 * native.GASFactor
tx1.ValidUntilBlock = 1 tx1.ValidUntilBlock = 1
addSender(t, tx1) addSender(t, tx1)
signTx(t, srv.Chain.FeePerByte(), tx1) signTx(t, srv.Chain, tx1)
tx2 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 100000) tx2 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 100000)
tx2.NetworkFee = 20_000_000 * native.GASFactor tx2.NetworkFee = 20_000_000 * native.GASFactor
tx2.ValidUntilBlock = 1 tx2.ValidUntilBlock = 1
addSender(t, tx2) addSender(t, tx2)
signTx(t, srv.Chain.FeePerByte(), tx2) signTx(t, srv.Chain, tx2)
require.NoError(t, srv.Chain.PoolTx(tx1)) require.NoError(t, srv.Chain.PoolTx(tx1))
require.Error(t, srv.Chain.PoolTx(tx2)) require.Error(t, srv.Chain.PoolTx(tx2))
b := testchain.NewBlock(t, srv.Chain, 1, 0, tx2) b := testchain.NewBlock(t, srv.Chain, 1, 0, tx2)
@ -391,7 +392,7 @@ func TestVerifyBlock(t *testing.T) {
tx := transaction.New(netmode.UnitTestNet, script, 100000) tx := transaction.New(netmode.UnitTestNet, script, 100000)
tx.ValidUntilBlock = 1 tx.ValidUntilBlock = 1
addSender(t, tx) addSender(t, tx)
signTx(t, srv.Chain.FeePerByte(), tx) signTx(t, srv.Chain, tx)
b := testchain.NewBlock(t, srv.Chain, 1, 0, tx) b := testchain.NewBlock(t, srv.Chain, 1, 0, tx)
require.False(t, srv.verifyBlock(&neoBlock{Block: *b})) require.False(t, srv.verifyBlock(&neoBlock{Block: *b}))
}) })
@ -399,7 +400,7 @@ func TestVerifyBlock(t *testing.T) {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 100000) tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 100000)
tx.ValidUntilBlock = 1 tx.ValidUntilBlock = 1
addSender(t, tx) addSender(t, tx)
signTx(t, srv.Chain.FeePerByte(), tx) signTx(t, srv.Chain, tx)
tx.Scripts[0].InvocationScript[16] = ^tx.Scripts[0].InvocationScript[16] tx.Scripts[0].InvocationScript[16] = ^tx.Scripts[0].InvocationScript[16]
b := testchain.NewBlock(t, srv.Chain, 1, 0, tx) b := testchain.NewBlock(t, srv.Chain, 1, 0, tx)
require.False(t, srv.verifyBlock(&neoBlock{Block: *b})) require.False(t, srv.verifyBlock(&neoBlock{Block: *b}))
@ -410,7 +411,7 @@ func TestVerifyBlock(t *testing.T) {
txes[i] = transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, srv.Chain.GetPolicer().GetMaxBlockSystemFee()/2+1) txes[i] = transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, srv.Chain.GetPolicer().GetMaxBlockSystemFee()/2+1)
txes[i].ValidUntilBlock = 1 txes[i].ValidUntilBlock = 1
addSender(t, txes[i]) addSender(t, txes[i])
signTx(t, srv.Chain.FeePerByte(), txes[i]) signTx(t, srv.Chain, txes[i])
} }
b := testchain.NewBlock(t, srv.Chain, 1, 0, txes...) b := testchain.NewBlock(t, srv.Chain, 1, 0, txes...)
require.False(t, srv.verifyBlock(&neoBlock{Block: *b})) require.False(t, srv.verifyBlock(&neoBlock{Block: *b}))
@ -500,7 +501,7 @@ func addSender(t *testing.T, txs ...*transaction.Transaction) {
} }
} }
func signTx(t *testing.T, feePerByte int64, txs ...*transaction.Transaction) { func signTx(t *testing.T, bc blockchainer.Blockchainer, txs ...*transaction.Transaction) {
validators := make([]*keys.PublicKey, 4) validators := make([]*keys.PublicKey, 4)
privNetKeys := make([]*keys.PrivateKey, 4) privNetKeys := make([]*keys.PrivateKey, 4)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
@ -512,10 +513,10 @@ func signTx(t *testing.T, feePerByte int64, txs ...*transaction.Transaction) {
require.NoError(t, err) require.NoError(t, err)
for _, tx := range txs { for _, tx := range txs {
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(rawScript) netFee, sizeDelta := fee.Calculate(bc.GetPolicer().GetBaseExecFee(), rawScript)
tx.NetworkFee += +netFee tx.NetworkFee += +netFee
size += sizeDelta size += sizeDelta
tx.NetworkFee += int64(size) * feePerByte tx.NetworkFee += int64(size) * bc.FeePerByte()
data := tx.GetSignedPart() data := tx.GetSignedPart()
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()

View file

@ -620,7 +620,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, smartcontract.All) v.LoadScriptWithFlags(tx.Script, smartcontract.All)
v.SetPriceGetter(getPrice) v.SetPriceGetter(bc.getPrice)
v.GasLimit = tx.SystemFee v.GasLimit = tx.SystemFee
err := v.Run() err := v.Run()
@ -753,7 +753,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, smartcontract.WriteStates|smartcontract.AllowCall) v.LoadScriptWithFlags(script, smartcontract.WriteStates|smartcontract.AllowCall)
v.SetPriceGetter(getPrice) v.SetPriceGetter(bc.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 {
@ -1622,7 +1622,7 @@ func (bc *Blockchain) GetTestVM(tx *transaction.Transaction, b *block.Block) *vm
d.MPT = nil d.MPT = nil
systemInterop := bc.newInteropContext(trigger.Application, d, b, tx) systemInterop := bc.newInteropContext(trigger.Application, d, b, tx)
vm := systemInterop.SpawnVM() vm := systemInterop.SpawnVM()
vm.SetPriceGetter(getPrice) vm.SetPriceGetter(bc.getPrice)
return vm return vm
} }
@ -1692,7 +1692,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
} }
vm := interopCtx.SpawnVM() vm := interopCtx.SpawnVM()
vm.SetPriceGetter(getPrice) vm.SetPriceGetter(bc.getPrice)
vm.GasLimit = gas vm.GasLimit = gas
if err := bc.initVerificationVM(interopCtx, hash, witness); err != nil { if err := bc.initVerificationVM(interopCtx, hash, witness); err != nil {
return 0, err return 0, err
@ -1813,6 +1813,11 @@ func (bc *Blockchain) GetPolicer() blockchainer.Policer {
return bc return bc
} }
// GetBaseExecFee return execution price for `NOP`.
func (bc *Blockchain) GetBaseExecFee() int64 {
return interop.DefaultBaseExecFee
}
// GetMaxBlockSize returns maximum allowed block size from native Policy contract. // GetMaxBlockSize returns maximum allowed block size from native Policy contract.
func (bc *Blockchain) GetMaxBlockSize() uint32 { func (bc *Blockchain) GetMaxBlockSize() uint32 {
return bc.contracts.Policy.GetMaxBlockSizeInternal(bc.dao) return bc.contracts.Policy.GetMaxBlockSizeInternal(bc.dao)

View file

@ -338,7 +338,7 @@ func TestVerifyTx(t *testing.T) {
}) })
t.Run("AlmostEnoughNetworkFee", func(t *testing.T) { t.Run("AlmostEnoughNetworkFee", func(t *testing.T) {
tx := bc.newTestTx(h, testScript) tx := bc.newTestTx(h, testScript)
verificationNetFee, calcultedScriptSize := fee.Calculate(accs[0].Contract.Script) verificationNetFee, calcultedScriptSize := fee.Calculate(bc.GetBaseExecFee(), accs[0].Contract.Script)
expectedSize := io.GetVarSize(tx) + calcultedScriptSize expectedSize := io.GetVarSize(tx) + calcultedScriptSize
calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
tx.NetworkFee = calculatedNetFee - 1 tx.NetworkFee = calculatedNetFee - 1
@ -348,7 +348,7 @@ func TestVerifyTx(t *testing.T) {
}) })
t.Run("EnoughNetworkFee", func(t *testing.T) { t.Run("EnoughNetworkFee", func(t *testing.T) {
tx := bc.newTestTx(h, testScript) tx := bc.newTestTx(h, testScript)
verificationNetFee, calcultedScriptSize := fee.Calculate(accs[0].Contract.Script) verificationNetFee, calcultedScriptSize := fee.Calculate(bc.GetBaseExecFee(), accs[0].Contract.Script)
expectedSize := io.GetVarSize(tx) + calcultedScriptSize expectedSize := io.GetVarSize(tx) + calcultedScriptSize
calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
tx.NetworkFee = calculatedNetFee tx.NetworkFee = calculatedNetFee
@ -359,7 +359,7 @@ func TestVerifyTx(t *testing.T) {
t.Run("CalculateNetworkFee, signature script", func(t *testing.T) { t.Run("CalculateNetworkFee, signature script", func(t *testing.T) {
tx := bc.newTestTx(h, testScript) tx := bc.newTestTx(h, testScript)
expectedSize := io.GetVarSize(tx) expectedSize := io.GetVarSize(tx)
verificationNetFee, calculatedScriptSize := fee.Calculate(accs[0].Contract.Script) verificationNetFee, calculatedScriptSize := fee.Calculate(bc.GetBaseExecFee(), accs[0].Contract.Script)
expectedSize += calculatedScriptSize expectedSize += calculatedScriptSize
expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
tx.NetworkFee = expectedNetFee tx.NetworkFee = expectedNetFee
@ -378,7 +378,7 @@ func TestVerifyTx(t *testing.T) {
require.NoError(t, multisigAcc.ConvertMultisig(1, pKeys)) require.NoError(t, multisigAcc.ConvertMultisig(1, pKeys))
multisigHash := hash.Hash160(multisigAcc.Contract.Script) multisigHash := hash.Hash160(multisigAcc.Contract.Script)
tx := bc.newTestTx(multisigHash, testScript) tx := bc.newTestTx(multisigHash, testScript)
verificationNetFee, calculatedScriptSize := fee.Calculate(multisigAcc.Contract.Script) verificationNetFee, calculatedScriptSize := fee.Calculate(bc.GetBaseExecFee(), multisigAcc.Contract.Script)
expectedSize := io.GetVarSize(tx) + calculatedScriptSize expectedSize := io.GetVarSize(tx) + calculatedScriptSize
expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte() expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
tx.NetworkFee = expectedNetFee tx.NetworkFee = expectedNetFee
@ -478,7 +478,7 @@ func TestVerifyTx(t *testing.T) {
rawScript := testchain.CommitteeVerificationScript() rawScript := testchain.CommitteeVerificationScript()
require.NoError(t, err) require.NoError(t, err)
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(rawScript) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
data := tx.GetSignedPart() data := tx.GetSignedPart()
@ -517,7 +517,7 @@ func TestVerifyTx(t *testing.T) {
Scopes: transaction.None, Scopes: transaction.None,
}} }}
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(oracleScript) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), oracleScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
return tx return tx
@ -614,7 +614,7 @@ func TestVerifyTx(t *testing.T) {
rawScript := testchain.CommitteeVerificationScript() rawScript := testchain.CommitteeVerificationScript()
require.NoError(t, err) require.NoError(t, err)
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(rawScript) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
data := tx.GetSignedPart() data := tx.GetSignedPart()
@ -652,7 +652,7 @@ func TestVerifyTx(t *testing.T) {
rawScript := testchain.CommitteeVerificationScript() rawScript := testchain.CommitteeVerificationScript()
require.NoError(t, err) require.NoError(t, err)
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(rawScript) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
data := tx.GetSignedPart() data := tx.GetSignedPart()
@ -692,7 +692,7 @@ func TestVerifyTx(t *testing.T) {
rawScript := testchain.CommitteeVerificationScript() rawScript := testchain.CommitteeVerificationScript()
require.NoError(t, err) require.NoError(t, err)
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(rawScript) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
data := tx.GetSignedPart() data := tx.GetSignedPart()
@ -772,7 +772,7 @@ func TestVerifyTx(t *testing.T) {
} }
rawScript := testchain.CommitteeVerificationScript() rawScript := testchain.CommitteeVerificationScript()
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(rawScript) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript)
tx.NetworkFee += netFee tx.NetworkFee += netFee
tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte() tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
data := tx.GetSignedPart() data := tx.GetSignedPart()
@ -964,14 +964,14 @@ func TestVerifyTx(t *testing.T) {
}, },
} }
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(testchain.MultisigVerificationScript()) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), testchain.MultisigVerificationScript())
tx.NetworkFee = netFee + // multisig witness verification price tx.NetworkFee = netFee + // multisig witness verification price
int64(size)*bc.FeePerByte() + // fee for unsigned size int64(size)*bc.FeePerByte() + // fee for unsigned size
int64(sizeDelta)*bc.FeePerByte() + //fee for multisig size int64(sizeDelta)*bc.FeePerByte() + //fee for multisig size
66*bc.FeePerByte() + // fee for Notary signature size (66 bytes for Invocation script and 0 bytes for Verification script) 66*bc.FeePerByte() + // fee for Notary signature size (66 bytes for Invocation script and 0 bytes for Verification script)
2*bc.FeePerByte() + // fee for the length of each script in Notary witness (they are nil, so we did not take them into account during `size` calculation) 2*bc.FeePerByte() + // fee for the length of each script in Notary witness (they are nil, so we did not take them into account during `size` calculation)
transaction.NotaryServiceFeePerKey + // fee for Notary attribute transaction.NotaryServiceFeePerKey + // fee for Notary attribute
fee.Opcode( // Notary verification script fee.Opcode(bc.GetBaseExecFee(), // Notary verification script
opcode.PUSHDATA1, opcode.RET, // invocation script opcode.PUSHDATA1, opcode.RET, // invocation script
opcode.DEPTH, opcode.PACK, opcode.PUSHDATA1, opcode.RET, // arguments for native verification call opcode.DEPTH, opcode.PACK, opcode.PUSHDATA1, opcode.RET, // arguments for native verification call
opcode.PUSHDATA1, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call opcode.PUSHDATA1, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call

View file

@ -2,6 +2,7 @@ package blockchainer
// Policer is an interface that abstracts the implementation of policy methods. // Policer is an interface that abstracts the implementation of policy methods.
type Policer interface { type Policer interface {
GetBaseExecFee() int64
GetMaxBlockSize() uint32 GetMaxBlockSize() uint32
GetMaxBlockSystemFee() int64 GetMaxBlockSystemFee() int64
GetMaxVerificationGAS() int64 GetMaxVerificationGAS() int64

View file

@ -9,31 +9,31 @@ import (
) )
// Calculate returns network fee for transaction // Calculate returns network fee for transaction
func Calculate(script []byte) (int64, int) { func Calculate(base int64, script []byte) (int64, int) {
var ( var (
netFee int64 netFee int64
size int size int
) )
if vm.IsSignatureContract(script) { if vm.IsSignatureContract(script) {
size += 67 + io.GetVarSize(script) size += 67 + io.GetVarSize(script)
netFee += Opcode(opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + crypto.ECDSAVerifyPrice netFee += Opcode(base, opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + base*crypto.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(m) + calculateMultisig(n) netFee += calculateMultisig(base, m) + calculateMultisig(base, n)
netFee += Opcode(opcode.PUSHNULL) + crypto.ECDSAVerifyPrice*int64(n) netFee += Opcode(base, opcode.PUSHNULL) + base*crypto.ECDSAVerifyPrice*int64(n)
} else { } else {
// We can support more contract types in the future. // We can support more contract types in the future.
} }
return netFee, size return netFee, size
} }
func calculateMultisig(n int) int64 { func calculateMultisig(base int64, n int) int64 {
result := Opcode(opcode.PUSHDATA1) * int64(n) result := Opcode(base, opcode.PUSHDATA1) * int64(n)
bw := io.NewBufBinWriter() bw := io.NewBufBinWriter()
emit.Int(bw.BinWriter, int64(n)) emit.Int(bw.BinWriter, int64(n))
// it's a hack because prices of small PUSH* opcodes are equal // it's a hack because coefficients of small PUSH* opcodes are equal
result += Opcode(opcode.Opcode(bw.Bytes()[0])) result += Opcode(base, opcode.Opcode(bw.Bytes()[0]))
return result return result
} }

View file

@ -1,199 +1,201 @@
package fee package fee
import "github.com/nspcc-dev/neo-go/pkg/vm/opcode" import (
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
)
// Opcode returns the deployment prices of specified opcodes. // Opcode returns the deployment coefficients of specified opcodes.
func Opcode(opcodes ...opcode.Opcode) int64 { func Opcode(base int64, opcodes ...opcode.Opcode) int64 {
var result int64 var result int64
for _, op := range opcodes { for _, op := range opcodes {
result += prices[op] result += coefficients[op]
} }
return result return result * base
} }
var prices = map[opcode.Opcode]int64{ var coefficients = map[opcode.Opcode]int64{
opcode.PUSHINT8: 30, opcode.PUSHINT8: 1 << 0,
opcode.PUSHINT32: 30, opcode.PUSHINT16: 1 << 0,
opcode.PUSHINT64: 30, opcode.PUSHINT32: 1 << 0,
opcode.PUSHINT16: 30, opcode.PUSHINT64: 1 << 0,
opcode.PUSHINT128: 120, opcode.PUSHINT128: 1 << 2,
opcode.PUSHINT256: 120, opcode.PUSHINT256: 1 << 2,
opcode.PUSHA: 120, opcode.PUSHA: 1 << 2,
opcode.PUSHNULL: 30, opcode.PUSHNULL: 1 << 0,
opcode.PUSHDATA1: 180, opcode.PUSHDATA1: 1 << 3,
opcode.PUSHDATA2: 13000, opcode.PUSHDATA2: 1 << 9,
opcode.PUSHDATA4: 110000, opcode.PUSHDATA4: 1 << 12,
opcode.PUSHM1: 30, opcode.PUSHM1: 1 << 0,
opcode.PUSH0: 30, opcode.PUSH0: 1 << 0,
opcode.PUSH1: 30, opcode.PUSH1: 1 << 0,
opcode.PUSH2: 30, opcode.PUSH2: 1 << 0,
opcode.PUSH3: 30, opcode.PUSH3: 1 << 0,
opcode.PUSH4: 30, opcode.PUSH4: 1 << 0,
opcode.PUSH5: 30, opcode.PUSH5: 1 << 0,
opcode.PUSH6: 30, opcode.PUSH6: 1 << 0,
opcode.PUSH7: 30, opcode.PUSH7: 1 << 0,
opcode.PUSH8: 30, opcode.PUSH8: 1 << 0,
opcode.PUSH9: 30, opcode.PUSH9: 1 << 0,
opcode.PUSH10: 30, opcode.PUSH10: 1 << 0,
opcode.PUSH11: 30, opcode.PUSH11: 1 << 0,
opcode.PUSH12: 30, opcode.PUSH12: 1 << 0,
opcode.PUSH13: 30, opcode.PUSH13: 1 << 0,
opcode.PUSH14: 30, opcode.PUSH14: 1 << 0,
opcode.PUSH15: 30, opcode.PUSH15: 1 << 0,
opcode.PUSH16: 30, opcode.PUSH16: 1 << 0,
opcode.NOP: 30, opcode.NOP: 1 << 0,
opcode.JMP: 70, opcode.JMP: 1 << 1,
opcode.JMPL: 70, opcode.JMPL: 1 << 1,
opcode.JMPIF: 70, opcode.JMPIF: 1 << 1,
opcode.JMPIFL: 70, opcode.JMPIFL: 1 << 1,
opcode.JMPIFNOT: 70, opcode.JMPIFNOT: 1 << 1,
opcode.JMPIFNOTL: 70, opcode.JMPIFNOTL: 1 << 1,
opcode.JMPEQ: 70, opcode.JMPEQ: 1 << 1,
opcode.JMPEQL: 70, opcode.JMPEQL: 1 << 1,
opcode.JMPNE: 70, opcode.JMPNE: 1 << 1,
opcode.JMPNEL: 70, opcode.JMPNEL: 1 << 1,
opcode.JMPGT: 70, opcode.JMPGT: 1 << 1,
opcode.JMPGTL: 70, opcode.JMPGTL: 1 << 1,
opcode.JMPGE: 70, opcode.JMPGE: 1 << 1,
opcode.JMPGEL: 70, opcode.JMPGEL: 1 << 1,
opcode.JMPLT: 70, opcode.JMPLT: 1 << 1,
opcode.JMPLTL: 70, opcode.JMPLTL: 1 << 1,
opcode.JMPLE: 70, opcode.JMPLE: 1 << 1,
opcode.JMPLEL: 70, opcode.JMPLEL: 1 << 1,
opcode.CALL: 22000, opcode.CALL: 1 << 9,
opcode.CALLL: 22000, opcode.CALLL: 1 << 9,
opcode.CALLA: 22000, opcode.CALLA: 1 << 9,
opcode.ABORT: 30, opcode.ABORT: 0,
opcode.ASSERT: 30, opcode.ASSERT: 1 << 0,
opcode.THROW: 22000, opcode.THROW: 1 << 9,
opcode.TRY: 100, opcode.TRY: 1 << 2,
opcode.TRYL: 100, opcode.TRYL: 1 << 2,
opcode.ENDTRY: 100, opcode.ENDTRY: 1 << 2,
opcode.ENDTRYL: 100, opcode.ENDTRYL: 1 << 2,
opcode.ENDFINALLY: 100, opcode.ENDFINALLY: 1 << 2,
opcode.RET: 0, opcode.RET: 0,
opcode.SYSCALL: 0, opcode.SYSCALL: 0,
opcode.DEPTH: 60, opcode.DEPTH: 1 << 1,
opcode.DROP: 60, opcode.DROP: 1 << 1,
opcode.NIP: 60, opcode.NIP: 1 << 1,
opcode.XDROP: 400, opcode.XDROP: 1 << 4,
opcode.CLEAR: 400, opcode.CLEAR: 1 << 4,
opcode.DUP: 60, opcode.DUP: 1 << 1,
opcode.OVER: 60, opcode.OVER: 1 << 1,
opcode.PICK: 60, opcode.PICK: 1 << 1,
opcode.TUCK: 60, opcode.TUCK: 1 << 1,
opcode.SWAP: 60, opcode.SWAP: 1 << 1,
opcode.ROT: 60, opcode.ROT: 1 << 1,
opcode.ROLL: 400, opcode.ROLL: 1 << 4,
opcode.REVERSE3: 60, opcode.REVERSE3: 1 << 1,
opcode.REVERSE4: 60, opcode.REVERSE4: 1 << 1,
opcode.REVERSEN: 400, opcode.REVERSEN: 1 << 4,
opcode.INITSSLOT: 400, opcode.INITSSLOT: 1 << 4,
opcode.INITSLOT: 1600, opcode.INITSLOT: 1 << 6,
opcode.LDSFLD0: 60, opcode.LDSFLD0: 1 << 1,
opcode.LDSFLD1: 60, opcode.LDSFLD1: 1 << 1,
opcode.LDSFLD2: 60, opcode.LDSFLD2: 1 << 1,
opcode.LDSFLD3: 60, opcode.LDSFLD3: 1 << 1,
opcode.LDSFLD4: 60, opcode.LDSFLD4: 1 << 1,
opcode.LDSFLD5: 60, opcode.LDSFLD5: 1 << 1,
opcode.LDSFLD6: 60, opcode.LDSFLD6: 1 << 1,
opcode.LDSFLD: 60, opcode.LDSFLD: 1 << 1,
opcode.STSFLD0: 60, opcode.STSFLD0: 1 << 1,
opcode.STSFLD1: 60, opcode.STSFLD1: 1 << 1,
opcode.STSFLD2: 60, opcode.STSFLD2: 1 << 1,
opcode.STSFLD3: 60, opcode.STSFLD3: 1 << 1,
opcode.STSFLD4: 60, opcode.STSFLD4: 1 << 1,
opcode.STSFLD5: 60, opcode.STSFLD5: 1 << 1,
opcode.STSFLD6: 60, opcode.STSFLD6: 1 << 1,
opcode.STSFLD: 60, opcode.STSFLD: 1 << 1,
opcode.LDLOC0: 60, opcode.LDLOC0: 1 << 1,
opcode.LDLOC1: 60, opcode.LDLOC1: 1 << 1,
opcode.LDLOC2: 60, opcode.LDLOC2: 1 << 1,
opcode.LDLOC3: 60, opcode.LDLOC3: 1 << 1,
opcode.LDLOC4: 60, opcode.LDLOC4: 1 << 1,
opcode.LDLOC5: 60, opcode.LDLOC5: 1 << 1,
opcode.LDLOC6: 60, opcode.LDLOC6: 1 << 1,
opcode.LDLOC: 60, opcode.LDLOC: 1 << 1,
opcode.STLOC0: 60, opcode.STLOC0: 1 << 1,
opcode.STLOC1: 60, opcode.STLOC1: 1 << 1,
opcode.STLOC2: 60, opcode.STLOC2: 1 << 1,
opcode.STLOC3: 60, opcode.STLOC3: 1 << 1,
opcode.STLOC4: 60, opcode.STLOC4: 1 << 1,
opcode.STLOC5: 60, opcode.STLOC5: 1 << 1,
opcode.STLOC6: 60, opcode.STLOC6: 1 << 1,
opcode.STLOC: 60, opcode.STLOC: 1 << 1,
opcode.LDARG0: 60, opcode.LDARG0: 1 << 1,
opcode.LDARG1: 60, opcode.LDARG1: 1 << 1,
opcode.LDARG2: 60, opcode.LDARG2: 1 << 1,
opcode.LDARG3: 60, opcode.LDARG3: 1 << 1,
opcode.LDARG4: 60, opcode.LDARG4: 1 << 1,
opcode.LDARG5: 60, opcode.LDARG5: 1 << 1,
opcode.LDARG6: 60, opcode.LDARG6: 1 << 1,
opcode.LDARG: 60, opcode.LDARG: 1 << 1,
opcode.STARG0: 60, opcode.STARG0: 1 << 1,
opcode.STARG1: 60, opcode.STARG1: 1 << 1,
opcode.STARG2: 60, opcode.STARG2: 1 << 1,
opcode.STARG3: 60, opcode.STARG3: 1 << 1,
opcode.STARG4: 60, opcode.STARG4: 1 << 1,
opcode.STARG5: 60, opcode.STARG5: 1 << 1,
opcode.STARG6: 60, opcode.STARG6: 1 << 1,
opcode.STARG: 60, opcode.STARG: 1 << 1,
opcode.NEWBUFFER: 80000, opcode.NEWBUFFER: 1 << 8,
opcode.MEMCPY: 80000, opcode.MEMCPY: 1 << 11,
opcode.CAT: 80000, opcode.CAT: 1 << 11,
opcode.SUBSTR: 80000, opcode.SUBSTR: 1 << 11,
opcode.LEFT: 80000, opcode.LEFT: 1 << 11,
opcode.RIGHT: 80000, opcode.RIGHT: 1 << 11,
opcode.INVERT: 100, opcode.INVERT: 1 << 2,
opcode.AND: 200, opcode.AND: 1 << 3,
opcode.OR: 200, opcode.OR: 1 << 3,
opcode.XOR: 200, opcode.XOR: 1 << 3,
opcode.EQUAL: 1000, opcode.EQUAL: 1 << 5,
opcode.NOTEQUAL: 1000, opcode.NOTEQUAL: 1 << 5,
opcode.SIGN: 100, opcode.SIGN: 1 << 2,
opcode.ABS: 100, opcode.ABS: 1 << 2,
opcode.NEGATE: 100, opcode.NEGATE: 1 << 2,
opcode.INC: 100, opcode.INC: 1 << 2,
opcode.DEC: 100, opcode.DEC: 1 << 2,
opcode.ADD: 200, opcode.ADD: 1 << 3,
opcode.SUB: 200, opcode.SUB: 1 << 3,
opcode.MUL: 300, opcode.MUL: 1 << 3,
opcode.DIV: 300, opcode.DIV: 1 << 3,
opcode.MOD: 300, opcode.MOD: 1 << 3,
opcode.SHL: 300, opcode.SHL: 1 << 3,
opcode.SHR: 300, opcode.SHR: 1 << 3,
opcode.NOT: 100, opcode.NOT: 1 << 2,
opcode.BOOLAND: 200, opcode.BOOLAND: 1 << 3,
opcode.BOOLOR: 200, opcode.BOOLOR: 1 << 3,
opcode.NZ: 100, opcode.NZ: 1 << 2,
opcode.NUMEQUAL: 200, opcode.NUMEQUAL: 1 << 3,
opcode.NUMNOTEQUAL: 200, opcode.NUMNOTEQUAL: 1 << 3,
opcode.LT: 200, opcode.LT: 1 << 3,
opcode.LTE: 200, opcode.LTE: 1 << 3,
opcode.GT: 200, opcode.GT: 1 << 3,
opcode.GTE: 200, opcode.GTE: 1 << 3,
opcode.MIN: 200, opcode.MIN: 1 << 3,
opcode.MAX: 200, opcode.MAX: 1 << 3,
opcode.WITHIN: 200, opcode.WITHIN: 1 << 3,
opcode.PACK: 15000, opcode.PACK: 1 << 9,
opcode.UNPACK: 15000, opcode.UNPACK: 1 << 9,
opcode.NEWARRAY0: 400, opcode.NEWARRAY0: 1 << 4,
opcode.NEWARRAY: 15000, opcode.NEWARRAY: 1 << 9,
opcode.NEWARRAYT: 15000, opcode.NEWARRAYT: 1 << 9,
opcode.NEWSTRUCT0: 400, opcode.NEWSTRUCT0: 1 << 4,
opcode.NEWSTRUCT: 15000, opcode.NEWSTRUCT: 1 << 9,
opcode.NEWMAP: 200, opcode.NEWMAP: 1 << 3,
opcode.SIZE: 150, opcode.SIZE: 1 << 2,
opcode.HASKEY: 270000, opcode.HASKEY: 1 << 6,
opcode.KEYS: 500, opcode.KEYS: 1 << 4,
opcode.VALUES: 270000, opcode.VALUES: 1 << 13,
opcode.PICKITEM: 270000, opcode.PICKITEM: 1 << 6,
opcode.APPEND: 270000, opcode.APPEND: 1 << 13,
opcode.SETITEM: 270000, opcode.SETITEM: 1 << 13,
opcode.REVERSEITEMS: 270000, opcode.REVERSEITEMS: 1 << 13,
opcode.REMOVE: 500, opcode.REMOVE: 1 << 4,
opcode.CLEARITEMS: 400, opcode.CLEARITEMS: 1 << 4,
opcode.ISNULL: 60, opcode.ISNULL: 1 << 1,
opcode.ISTYPE: 60, opcode.ISTYPE: 1 << 1,
opcode.CONVERT: 80000, opcode.CONVERT: 1 << 11,
} }

View file

@ -7,6 +7,6 @@ import (
) )
// getPrice returns a price for executing op with the provided parameter. // getPrice returns a price for executing op with the provided parameter.
func getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) int64 { func (bc *Blockchain) getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) int64 {
return fee.Opcode(op) return fee.Opcode(bc.GetBaseExecFee(), op)
} }

View file

@ -398,13 +398,13 @@ func addSigners(txs ...*transaction.Transaction) {
func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.Account) error { func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.Account) error {
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(sender.Contract.Script) netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), sender.Contract.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
for _, cosigner := range tx.Signers { for _, cosigner := range tx.Signers {
contract := bc.GetContractState(cosigner.Account) contract := bc.GetContractState(cosigner.Account)
if contract != nil { if contract != nil {
netFee, sizeDelta = fee.Calculate(contract.Script) netFee, sizeDelta = fee.Calculate(bc.GetBaseExecFee(), contract.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
} }

View file

@ -20,6 +20,11 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
const (
// DefaultBaseExecFee specifies default multiplier for opcode and syscall prices.
DefaultBaseExecFee = 30
)
// Context represents context in which interops are executed. // Context represents context in which interops are executed.
type Context struct { type Context struct {
Chain blockchainer.Blockchainer Chain blockchainer.Blockchainer
@ -155,6 +160,14 @@ func (ic *Context) GetFunction(id uint32) *Function {
return nil return nil
} }
// BaseExecFee represents factor to multiply syscall prices with.
func (ic *Context) BaseExecFee() int64 {
if ic.Chain == nil {
return DefaultBaseExecFee
}
return ic.Chain.GetPolicer().GetBaseExecFee()
}
// SyscallHandler handles syscall with id. // SyscallHandler handles syscall with id.
func (ic *Context) SyscallHandler(_ *vm.VM, id uint32) error { func (ic *Context) SyscallHandler(_ *vm.VM, id uint32) error {
f := ic.GetFunction(id) f := ic.GetFunction(id)
@ -165,7 +178,7 @@ func (ic *Context) SyscallHandler(_ *vm.VM, id uint32) error {
if !cf.Has(f.RequiredFlags) { if !cf.Has(f.RequiredFlags) {
return fmt.Errorf("missing call flags: %05b vs %05b", cf, f.RequiredFlags) return fmt.Errorf("missing call flags: %05b vs %05b", cf, f.RequiredFlags)
} }
if !ic.VM.AddGas(f.Price) { if !ic.VM.AddGas(f.Price * ic.BaseExecFee()) {
return errors.New("insufficient amount of gas") return errors.New("insufficient amount of gas")
} }
return f.Func(ic) return f.Func(ic)

View file

@ -16,7 +16,7 @@ import (
) )
// ECDSAVerifyPrice is a gas price of a single verification. // ECDSAVerifyPrice is a gas price of a single verification.
const ECDSAVerifyPrice = 1000000 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 {
@ -69,7 +69,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(ECDSAVerifyPrice * int64(len(pkeys))) { if !ic.VM.AddGas(ic.BaseExecFee() * 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()

View file

@ -201,6 +201,7 @@ func storageDelete(ic *interop.Context) error {
if stc.ReadOnly { if stc.ReadOnly {
return errors.New("StorageContext is read only") return errors.New("StorageContext is read only")
} }
ic.VM.AddGas(native.StoragePrice)
key := ic.VM.Estack().Pop().Bytes() key := ic.VM.Estack().Pop().Bytes()
si := ic.DAO.GetStorageItem(stc.ID, key) si := ic.DAO.GetStorageItem(stc.ID, key)
if si != nil && si.IsConst { if si != nil && si.IsConst {

View file

@ -33,80 +33,80 @@ func SpawnVM(ic *interop.Context) *vm.VM {
// All lists are sorted, keep 'em this way, please. // All lists are sorted, keep 'em this way, please.
var systemInterops = []interop.Function{ var systemInterops = []interop.Function{
{Name: interopnames.SystemBinaryAtoi, Func: binary.Atoi, Price: 100000, ParamCount: 2}, {Name: interopnames.SystemBinaryAtoi, Func: binary.Atoi, Price: 1 << 12, ParamCount: 2},
{Name: interopnames.SystemBinaryBase58Decode, Func: binary.DecodeBase58, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBinaryBase58Decode, Func: binary.DecodeBase58, Price: 1 << 12, ParamCount: 1},
{Name: interopnames.SystemBinaryBase58Encode, Func: binary.EncodeBase58, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBinaryBase58Encode, Func: binary.EncodeBase58, Price: 1 << 12, ParamCount: 1},
{Name: interopnames.SystemBinaryBase64Decode, Func: binary.DecodeBase64, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBinaryBase64Decode, Func: binary.DecodeBase64, Price: 1 << 12, ParamCount: 1},
{Name: interopnames.SystemBinaryBase64Encode, Func: binary.EncodeBase64, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBinaryBase64Encode, Func: binary.EncodeBase64, Price: 1 << 12, ParamCount: 1},
{Name: interopnames.SystemBinaryDeserialize, Func: binary.Deserialize, Price: 500000, ParamCount: 1}, {Name: interopnames.SystemBinaryDeserialize, Func: binary.Deserialize, Price: 1 << 14, ParamCount: 1},
{Name: interopnames.SystemBinaryItoa, Func: binary.Itoa, Price: 100000, ParamCount: 2}, {Name: interopnames.SystemBinaryItoa, Func: binary.Itoa, Price: 1 << 12, ParamCount: 2},
{Name: interopnames.SystemBinarySerialize, Func: binary.Serialize, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemBinarySerialize, Func: binary.Serialize, Price: 1 << 12, ParamCount: 1},
{Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 2500000, {Name: interopnames.SystemBlockchainGetBlock, Func: bcGetBlock, Price: 1 << 16,
RequiredFlags: smartcontract.ReadStates, ParamCount: 1}, RequiredFlags: smartcontract.ReadStates, ParamCount: 1},
{Name: interopnames.SystemBlockchainGetHeight, Func: bcGetHeight, Price: 400, {Name: interopnames.SystemBlockchainGetHeight, Func: bcGetHeight, Price: 1 << 4,
RequiredFlags: smartcontract.ReadStates}, RequiredFlags: smartcontract.ReadStates},
{Name: interopnames.SystemBlockchainGetTransaction, Func: bcGetTransaction, Price: 1000000, {Name: interopnames.SystemBlockchainGetTransaction, Func: bcGetTransaction, Price: 1 << 15,
RequiredFlags: smartcontract.ReadStates, ParamCount: 1}, RequiredFlags: smartcontract.ReadStates, ParamCount: 1},
{Name: interopnames.SystemBlockchainGetTransactionFromBlock, Func: bcGetTransactionFromBlock, Price: 1000000, {Name: interopnames.SystemBlockchainGetTransactionFromBlock, Func: bcGetTransactionFromBlock, Price: 1 << 15,
RequiredFlags: smartcontract.ReadStates, ParamCount: 2}, RequiredFlags: smartcontract.ReadStates, ParamCount: 2},
{Name: interopnames.SystemBlockchainGetTransactionHeight, Func: bcGetTransactionHeight, Price: 1000000, {Name: interopnames.SystemBlockchainGetTransactionHeight, Func: bcGetTransactionHeight, Price: 1 << 15,
RequiredFlags: smartcontract.ReadStates, ParamCount: 1}, RequiredFlags: smartcontract.ReadStates, ParamCount: 1},
{Name: interopnames.SystemCallbackCreate, Func: callback.Create, Price: 400, ParamCount: 3, DisallowCallback: true}, {Name: interopnames.SystemCallbackCreate, Func: callback.Create, Price: 1 << 4, ParamCount: 3, DisallowCallback: true},
{Name: interopnames.SystemCallbackCreateFromMethod, Func: callback.CreateFromMethod, Price: 1000000, RequiredFlags: smartcontract.ReadStates, ParamCount: 2, DisallowCallback: true}, {Name: interopnames.SystemCallbackCreateFromMethod, Func: callback.CreateFromMethod, Price: 1 << 15, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemCallbackCreateFromSyscall, Func: callback.CreateFromSyscall, Price: 400, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemCallbackCreateFromSyscall, Func: callback.CreateFromSyscall, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemCallbackInvoke, Func: callback.Invoke, Price: 1000000, RequiredFlags: smartcontract.AllowCall, ParamCount: 2, DisallowCallback: true}, {Name: interopnames.SystemCallbackInvoke, Func: callback.Invoke, Price: 1 << 15, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1000000, {Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1 << 15,
RequiredFlags: smartcontract.AllowCall, ParamCount: 3, DisallowCallback: true}, RequiredFlags: smartcontract.AllowCall, ParamCount: 3, DisallowCallback: true},
{Name: interopnames.SystemContractCallEx, Func: contract.CallEx, Price: 1000000, {Name: interopnames.SystemContractCallEx, Func: contract.CallEx, Price: 1 << 15,
RequiredFlags: smartcontract.AllowCall, ParamCount: 4, DisallowCallback: true}, RequiredFlags: smartcontract.AllowCall, ParamCount: 4, DisallowCallback: true},
{Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemContractCreateStandardAccount, Func: contractCreateStandardAccount, Price: 10000, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemContractCreateStandardAccount, Func: contractCreateStandardAccount, Price: 1 << 8, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemContractIsStandard, Func: contractIsStandard, Price: 30000, RequiredFlags: smartcontract.ReadStates, ParamCount: 1}, {Name: interopnames.SystemContractIsStandard, Func: contractIsStandard, Price: 1 << 10, RequiredFlags: smartcontract.ReadStates, ParamCount: 1},
{Name: interopnames.SystemContractGetCallFlags, Func: contractGetCallFlags, Price: 30000, DisallowCallback: true}, {Name: interopnames.SystemContractGetCallFlags, Func: contractGetCallFlags, Price: 1 << 10, DisallowCallback: true},
{Name: interopnames.SystemContractNativeOnPersist, Func: native.OnPersist, Price: 0, RequiredFlags: smartcontract.WriteStates, DisallowCallback: true}, {Name: interopnames.SystemContractNativeOnPersist, Func: native.OnPersist, Price: 0, RequiredFlags: smartcontract.WriteStates, DisallowCallback: true},
{Name: interopnames.SystemContractNativePostPersist, Func: native.PostPersist, Price: 0, RequiredFlags: smartcontract.WriteStates, DisallowCallback: true}, {Name: interopnames.SystemContractNativePostPersist, Func: native.PostPersist, Price: 0, RequiredFlags: smartcontract.WriteStates, DisallowCallback: true},
{Name: interopnames.SystemEnumeratorConcat, Func: enumerator.Concat, Price: 400, ParamCount: 2, DisallowCallback: true}, {Name: interopnames.SystemEnumeratorConcat, Func: enumerator.Concat, Price: 1 << 4, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemEnumeratorCreate, Func: enumerator.Create, Price: 400, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemEnumeratorCreate, Func: enumerator.Create, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemEnumeratorNext, Func: enumerator.Next, Price: 1000000, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemEnumeratorNext, Func: enumerator.Next, Price: 1 << 15, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemEnumeratorValue, Func: enumerator.Value, Price: 400, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemEnumeratorValue, Func: enumerator.Value, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemIteratorConcat, Func: iterator.Concat, Price: 400, ParamCount: 2, DisallowCallback: true}, {Name: interopnames.SystemIteratorConcat, Func: iterator.Concat, Price: 1 << 4, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemIteratorCreate, Func: iterator.Create, Price: 400, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemIteratorCreate, Func: iterator.Create, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemIteratorKey, Func: iterator.Key, Price: 400, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemIteratorKey, Func: iterator.Key, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemIteratorKeys, Func: iterator.Keys, Price: 400, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemIteratorKeys, Func: iterator.Keys, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemIteratorValues, Func: iterator.Values, Price: 400, ParamCount: 1, DisallowCallback: true}, {Name: interopnames.SystemIteratorValues, Func: iterator.Values, Price: 1 << 4, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemJSONDeserialize, Func: json.Deserialize, Price: 500000, ParamCount: 1}, {Name: interopnames.SystemJSONDeserialize, Func: json.Deserialize, Price: 1 << 14, ParamCount: 1},
{Name: interopnames.SystemJSONSerialize, Func: json.Serialize, Price: 100000, ParamCount: 1}, {Name: interopnames.SystemJSONSerialize, Func: json.Serialize, Price: 1 << 12, ParamCount: 1},
{Name: interopnames.SystemRuntimeCheckWitness, Func: runtime.CheckWitness, Price: 30000, {Name: interopnames.SystemRuntimeCheckWitness, Func: runtime.CheckWitness, Price: 1 << 10,
RequiredFlags: smartcontract.NoneFlag, ParamCount: 1}, RequiredFlags: smartcontract.NoneFlag, ParamCount: 1},
{Name: interopnames.SystemRuntimeGasLeft, Func: runtime.GasLeft, Price: 400}, {Name: interopnames.SystemRuntimeGasLeft, Func: runtime.GasLeft, Price: 1 << 4},
{Name: interopnames.SystemRuntimeGetCallingScriptHash, Func: runtime.GetCallingScriptHash, Price: 400}, {Name: interopnames.SystemRuntimeGetCallingScriptHash, Func: runtime.GetCallingScriptHash, Price: 1 << 4},
{Name: interopnames.SystemRuntimeGetEntryScriptHash, Func: runtime.GetEntryScriptHash, Price: 400}, {Name: interopnames.SystemRuntimeGetEntryScriptHash, Func: runtime.GetEntryScriptHash, Price: 1 << 4},
{Name: interopnames.SystemRuntimeGetExecutingScriptHash, Func: runtime.GetExecutingScriptHash, Price: 400}, {Name: interopnames.SystemRuntimeGetExecutingScriptHash, Func: runtime.GetExecutingScriptHash, Price: 1 << 4},
{Name: interopnames.SystemRuntimeGetInvocationCounter, Func: runtime.GetInvocationCounter, Price: 400}, {Name: interopnames.SystemRuntimeGetInvocationCounter, Func: runtime.GetInvocationCounter, Price: 1 << 4},
{Name: interopnames.SystemRuntimeGetNotifications, Func: runtime.GetNotifications, Price: 10000, ParamCount: 1}, {Name: interopnames.SystemRuntimeGetNotifications, Func: runtime.GetNotifications, Price: 1 << 8, ParamCount: 1},
{Name: interopnames.SystemRuntimeGetScriptContainer, Func: engineGetScriptContainer, Price: 250}, {Name: interopnames.SystemRuntimeGetScriptContainer, Func: engineGetScriptContainer, Price: 1 << 3},
{Name: interopnames.SystemRuntimeGetTime, Func: runtime.GetTime, Price: 250}, {Name: interopnames.SystemRuntimeGetTime, Func: runtime.GetTime, Price: 1 << 3, RequiredFlags: smartcontract.ReadStates},
{Name: interopnames.SystemRuntimeGetTrigger, Func: runtime.GetTrigger, Price: 250}, {Name: interopnames.SystemRuntimeGetTrigger, Func: runtime.GetTrigger, Price: 1 << 3},
{Name: interopnames.SystemRuntimeLog, Func: runtime.Log, Price: 1000000, RequiredFlags: smartcontract.AllowNotify, {Name: interopnames.SystemRuntimeLog, Func: runtime.Log, Price: 1 << 15, RequiredFlags: smartcontract.AllowNotify,
ParamCount: 1, DisallowCallback: true}, ParamCount: 1, DisallowCallback: true},
{Name: interopnames.SystemRuntimeNotify, Func: runtime.Notify, Price: 1000000, RequiredFlags: smartcontract.AllowNotify, {Name: interopnames.SystemRuntimeNotify, Func: runtime.Notify, Price: 1 << 15, RequiredFlags: smartcontract.AllowNotify,
ParamCount: 2, DisallowCallback: true}, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemRuntimePlatform, Func: runtime.Platform, Price: 250}, {Name: interopnames.SystemRuntimePlatform, Func: runtime.Platform, Price: 1 << 3},
{Name: interopnames.SystemStorageDelete, Func: storageDelete, Price: native.StoragePrice, {Name: interopnames.SystemStorageDelete, Func: storageDelete, Price: 0,
RequiredFlags: smartcontract.WriteStates, ParamCount: 2, DisallowCallback: true}, RequiredFlags: smartcontract.WriteStates, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemStorageFind, Func: storageFind, Price: 1000000, RequiredFlags: smartcontract.ReadStates, {Name: interopnames.SystemStorageFind, Func: storageFind, Price: 1 << 15, RequiredFlags: smartcontract.ReadStates,
ParamCount: 2, DisallowCallback: true}, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemStorageGet, Func: storageGet, Price: 1000000, RequiredFlags: smartcontract.ReadStates, {Name: interopnames.SystemStorageGet, Func: storageGet, Price: 1 << 15, RequiredFlags: smartcontract.ReadStates,
ParamCount: 2, DisallowCallback: true}, ParamCount: 2, DisallowCallback: true},
{Name: interopnames.SystemStorageGetContext, Func: storageGetContext, Price: 400, {Name: interopnames.SystemStorageGetContext, Func: storageGetContext, Price: 1 << 4,
RequiredFlags: smartcontract.ReadStates, DisallowCallback: true}, RequiredFlags: smartcontract.ReadStates, DisallowCallback: true},
{Name: interopnames.SystemStorageGetReadOnlyContext, Func: storageGetReadOnlyContext, Price: 400, {Name: interopnames.SystemStorageGetReadOnlyContext, Func: storageGetReadOnlyContext, Price: 1 << 4,
RequiredFlags: smartcontract.ReadStates, DisallowCallback: true}, RequiredFlags: smartcontract.ReadStates, DisallowCallback: true},
{Name: interopnames.SystemStoragePut, Func: storagePut, Price: 0, RequiredFlags: smartcontract.WriteStates, {Name: interopnames.SystemStoragePut, Func: storagePut, Price: 0, RequiredFlags: smartcontract.WriteStates,
ParamCount: 3, DisallowCallback: true}, // These don't have static price in C# code. ParamCount: 3, DisallowCallback: true}, // These don't have static price in C# code.
{Name: interopnames.SystemStoragePutEx, Func: storagePutEx, Price: 0, RequiredFlags: smartcontract.WriteStates, {Name: interopnames.SystemStoragePutEx, Func: storagePutEx, Price: 0, RequiredFlags: smartcontract.WriteStates,
ParamCount: 4, DisallowCallback: true}, ParamCount: 4, DisallowCallback: true},
{Name: interopnames.SystemStorageAsReadOnly, Func: storageContextAsReadOnly, Price: 400, {Name: interopnames.SystemStorageAsReadOnly, Func: storageContextAsReadOnly, Price: 1 << 4,
RequiredFlags: smartcontract.ReadStates, ParamCount: 1, DisallowCallback: true}, RequiredFlags: smartcontract.ReadStates, ParamCount: 1, DisallowCallback: true},
} }
@ -117,8 +117,8 @@ var neoInterops = []interop.Function{
Price: crypto.ECDSAVerifyPrice, ParamCount: 3}, Price: crypto.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: 1000000, ParamCount: 1}, {Name: interopnames.NeoCryptoSHA256, Func: crypto.Sha256, Price: 1 << 15, ParamCount: 1},
{Name: interopnames.NeoCryptoRIPEMD160, Func: crypto.RipeMD160, Price: 1000000, ParamCount: 1}, {Name: interopnames.NeoCryptoRIPEMD160, Func: crypto.RipeMD160, Price: 1 << 15, ParamCount: 1},
} }
// initIDinInteropsSlice initializes IDs from names in one given // initIDinInteropsSlice initializes IDs from names in one given

View file

@ -24,6 +24,10 @@ type FeerStub struct {
balance int64 balance int64
} }
func (fs *FeerStub) GetBaseExecFee() int64 {
return 30
}
func (fs *FeerStub) FeePerByte() int64 { func (fs *FeerStub) FeePerByte() int64 {
return fs.feePerByte return fs.feePerByte
} }

View file

@ -35,6 +35,7 @@ func Call(ic *interop.Context) error {
if !ic.VM.Context().GetCallFlags().Has(m.RequiredFlags) { if !ic.VM.Context().GetCallFlags().Has(m.RequiredFlags) {
return fmt.Errorf("missing call flags for native %s `%s` operation call: %05b vs %05b", name, operation, ic.VM.Context().GetCallFlags(), m.RequiredFlags) return fmt.Errorf("missing call flags for native %s `%s` operation call: %05b vs %05b", name, operation, ic.VM.Context().GetCallFlags(), m.RequiredFlags)
} }
// Native contract prices are not multiplied by `BaseExecFee`.
if !ic.VM.AddGas(m.Price) { if !ic.VM.AddGas(m.Price) {
return errors.New("gas limit exceeded") return errors.New("gas limit exceeded")
} }

View file

@ -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/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
@ -17,6 +18,7 @@ import (
"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"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -54,7 +56,7 @@ func (bc *Blockchain) registerNative(c interop.Contract) {
bc.contracts.Contracts = append(bc.contracts.Contracts, c) bc.contracts.Contracts = append(bc.contracts.Contracts, c)
} }
const testSumPrice = 1000000 const testSumPrice = 1 << 15 * interop.DefaultBaseExecFee // same as contract.Call
func newTestNative() *testNative { func newTestNative() *testNative {
tn := &testNative{ tn := &testNative{
@ -176,8 +178,12 @@ func TestNativeContract_Invoke(t *testing.T) {
}) })
require.NoError(t, err) require.NoError(t, err)
// System.Contract.Call + "sum" itself + opcodes for pushing arguments (PACK is 15000) // System.Contract.Call + "sum" itself + opcodes for pushing arguments.
res, err := invokeContractMethod(chain, testSumPrice*2+18000, tn.Metadata().Hash, "sum", int64(14), int64(28)) price := int64(testSumPrice * 2)
price += 3 * fee.Opcode(chain.GetBaseExecFee(), opcode.PUSHINT8, opcode.PUSHDATA1)
price += 2 * fee.Opcode(chain.GetBaseExecFee(), opcode.SYSCALL)
price += fee.Opcode(chain.GetBaseExecFee(), opcode.PACK)
res, err := invokeContractMethod(chain, price, tn.Metadata().Hash, "sum", int64(14), int64(28))
require.NoError(t, err) require.NoError(t, err)
checkResult(t, res, stackitem.Make(42)) checkResult(t, res, stackitem.Make(42))
require.NoError(t, chain.persist()) require.NoError(t, chain.persist())
@ -190,10 +196,9 @@ func TestNativeContract_Invoke(t *testing.T) {
} }
// Enough for Call and other opcodes, but not enough for "sum" call. // Enough for Call and other opcodes, but not enough for "sum" call.
res, err = invokeContractMethod(chain, testSumPrice*2+8000, tn.Metadata().Hash, "sum", int64(14), int64(28)) res, err = invokeContractMethod(chain, price-1, tn.Metadata().Hash, "sum", int64(14), int64(28))
require.NoError(t, err) require.NoError(t, err)
checkFAULTState(t, res) checkFAULTState(t, res)
} }
func TestNativeContract_InvokeInternal(t *testing.T) { func TestNativeContract_InvokeInternal(t *testing.T) {

View file

@ -14,6 +14,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/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer" "github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/mempool" "github.com/nspcc-dev/neo-go/pkg/core/mempool"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -101,7 +102,9 @@ func (chain *testChain) GetNotaryBalance(acc util.Uint160) *big.Int {
func (chain *testChain) GetPolicer() blockchainer.Policer { func (chain *testChain) GetPolicer() blockchainer.Policer {
return chain return chain
} }
func (chain *testChain) GetBaseExecFee() int64 {
return interop.DefaultBaseExecFee
}
func (chain *testChain) GetMaxVerificationGAS() int64 { func (chain *testChain) GetMaxVerificationGAS() int64 {
if chain.maxVerificationGAS != 0 { if chain.maxVerificationGAS != 0 {
return chain.maxVerificationGAS return chain.maxVerificationGAS

View file

@ -15,6 +15,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/consensus" "github.com/nspcc-dev/neo-go/pkg/consensus"
"github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/network/capability" "github.com/nspcc-dev/neo-go/pkg/network/capability"
"github.com/nspcc-dev/neo-go/pkg/network/payload" "github.com/nspcc-dev/neo-go/pkg/network/payload"
@ -798,6 +799,7 @@ func (f feerStub) FeePerByte() int64 { return 1 }
func (f feerStub) GetUtilityTokenBalance(util.Uint160) *big.Int { return big.NewInt(100000000) } func (f feerStub) GetUtilityTokenBalance(util.Uint160) *big.Int { return big.NewInt(100000000) }
func (f feerStub) BlockHeight() uint32 { return f.blockHeight } func (f feerStub) BlockHeight() uint32 { return f.blockHeight }
func (f feerStub) P2PSigExtensionsEnabled() bool { return false } func (f feerStub) P2PSigExtensionsEnabled() bool { return false }
func (f feerStub) GetBaseExecFee() int64 { return interop.DefaultBaseExecFee }
func TestMemPool(t *testing.T) { func TestMemPool(t *testing.T) {
s, shutdown := startTestServer(t) s, shutdown := startTestServer(t)

View file

@ -9,6 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/fee" "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/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -589,7 +590,7 @@ func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, accs
size += io.GetVarSize([]byte{}) * 2 // both scripts are empty size += io.GetVarSize([]byte{}) * 2 // both scripts are empty
continue continue
} }
netFee, sizeDelta := fee.Calculate(accs[i].Contract.Script) netFee, sizeDelta := fee.Calculate(interop.DefaultBaseExecFee, accs[i].Contract.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
} }

View file

@ -102,7 +102,7 @@ func TestAddNetworkFee(t *testing.T) {
}} }}
require.NoError(t, c.AddNetworkFee(tx, 10, accs[0])) require.NoError(t, c.AddNetworkFee(tx, 10, accs[0]))
require.NoError(t, accs[0].SignTx(tx)) require.NoError(t, accs[0].SignTx(tx))
cFee, _ := fee.Calculate(accs[0].Contract.Script) cFee, _ := fee.Calculate(chain.GetBaseExecFee(), accs[0].Contract.Script)
require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+10, tx.NetworkFee) require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+10, tx.NetworkFee)
}) })
@ -126,8 +126,8 @@ func TestAddNetworkFee(t *testing.T) {
require.NoError(t, accs[0].SignTx(tx)) require.NoError(t, accs[0].SignTx(tx))
require.NoError(t, accs[1].SignTx(tx)) require.NoError(t, accs[1].SignTx(tx))
require.NoError(t, accs[2].SignTx(tx)) require.NoError(t, accs[2].SignTx(tx))
cFee, _ := fee.Calculate(accs[0].Contract.Script) cFee, _ := fee.Calculate(chain.GetBaseExecFee(), accs[0].Contract.Script)
cFeeM, _ := fee.Calculate(accs[1].Contract.Script) cFeeM, _ := fee.Calculate(chain.GetBaseExecFee(), accs[1].Contract.Script)
require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+cFeeM+10, tx.NetworkFee) require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+cFeeM+10, tx.NetworkFee)
}) })
t.Run("Contract", func(t *testing.T) { t.Run("Contract", func(t *testing.T) {

View file

@ -11,6 +11,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" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
"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/io" "github.com/nspcc-dev/neo-go/pkg/io"
@ -102,3 +103,7 @@ func (fs *FeerStub) GetUtilityTokenBalance(acc util.Uint160) *big.Int {
func (fs FeerStub) P2PSigExtensionsEnabled() bool { func (fs FeerStub) P2PSigExtensionsEnabled() bool {
return false return false
} }
func (fs FeerStub) GetBaseExecFee() int64 {
return interop.DefaultBaseExecFee
}

View file

@ -1003,7 +1003,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
addNetworkFee := func(tx *transaction.Transaction) { addNetworkFee := func(tx *transaction.Transaction) {
size := io.GetVarSize(tx) size := io.GetVarSize(tx)
netFee, sizeDelta := fee.Calculate(acc0.Contract.Script) netFee, sizeDelta := fee.Calculate(chain.GetBaseExecFee(), acc0.Contract.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
tx.NetworkFee += int64(size) * chain.FeePerByte() tx.NetworkFee += int64(size) * chain.FeePerByte()