core: use proper storage price within the whole interop context
We shouldn't use StoragePrice from Blockchain because its dao doesn't contain the whole set of changes from previouse transactions in the current block. Instead, we should use an updated storage price for each transaction and retrieve the price from cached DAO.
This commit is contained in:
parent
91a4bc5beb
commit
544f2c2cb2
7 changed files with 51 additions and 38 deletions
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||
"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/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
|
@ -200,7 +201,7 @@ func TestAppCall(t *testing.T) {
|
|||
}
|
||||
|
||||
fc := fakechain.NewFakeChain()
|
||||
ic := interop.NewContext(trigger.Application, fc, dao.NewSimple(storage.NewMemoryStore(), false, false), interop.DefaultBaseExecFee, contractGetter, nil, nil, nil, zaptest.NewLogger(t))
|
||||
ic := interop.NewContext(trigger.Application, fc, dao.NewSimple(storage.NewMemoryStore(), false, false), interop.DefaultBaseExecFee, native.DefaultStoragePrice, contractGetter, nil, nil, nil, zaptest.NewLogger(t))
|
||||
|
||||
t.Run("valid script", func(t *testing.T) {
|
||||
src := getAppCallScript(fmt.Sprintf("%#v", ih.BytesBE()))
|
||||
|
|
|
@ -2305,13 +2305,18 @@ func (bc *Blockchain) ManagementContractHash() util.Uint160 {
|
|||
|
||||
func (bc *Blockchain) newInteropContext(trigger trigger.Type, d *dao.Simple, block *block.Block, tx *transaction.Transaction) *interop.Context {
|
||||
baseExecFee := int64(interop.DefaultBaseExecFee)
|
||||
|
||||
if block == nil || block.Index != 0 {
|
||||
// Use provided dao instead of Blockchain's one to fetch possible ExecFeeFactor
|
||||
// changes that were not yet persisted to Blockchain's dao.
|
||||
baseExecFee = bc.contracts.Policy.GetExecFeeFactorInternal(d)
|
||||
}
|
||||
ic := interop.NewContext(trigger, bc, d, baseExecFee, bc.contracts.Management.GetContract, bc.contracts.Contracts, block, tx, bc.log)
|
||||
baseStorageFee := int64(native.DefaultStoragePrice)
|
||||
if block == nil || block.Index != 0 {
|
||||
// Use provided dao instead of Blockchain's one to fetch possible StoragePrice
|
||||
// changes that were not yet persisted to Blockchain's dao.
|
||||
baseStorageFee = bc.contracts.Policy.GetStoragePriceInternal(d)
|
||||
}
|
||||
ic := interop.NewContext(trigger, bc, d, baseExecFee, baseStorageFee, bc.contracts.Management.GetContract, bc.contracts.Contracts, block, tx, bc.log)
|
||||
ic.Functions = systemInterops
|
||||
switch {
|
||||
case tx != nil:
|
||||
|
|
|
@ -41,48 +41,49 @@ type Ledger interface {
|
|||
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||
GetConfig() config.ProtocolConfiguration
|
||||
GetHeaderHash(int) util.Uint256
|
||||
GetStoragePrice() int64
|
||||
}
|
||||
|
||||
// Context represents context in which interops are executed.
|
||||
type Context struct {
|
||||
Chain Ledger
|
||||
Container hash.Hashable
|
||||
Network uint32
|
||||
Natives []Contract
|
||||
Trigger trigger.Type
|
||||
Block *block.Block
|
||||
NonceData [16]byte
|
||||
Tx *transaction.Transaction
|
||||
DAO *dao.Simple
|
||||
Notifications []state.NotificationEvent
|
||||
Log *zap.Logger
|
||||
VM *vm.VM
|
||||
Functions []Function
|
||||
Invocations map[util.Uint160]int
|
||||
cancelFuncs []context.CancelFunc
|
||||
getContract func(*dao.Simple, util.Uint160) (*state.Contract, error)
|
||||
baseExecFee int64
|
||||
signers []transaction.Signer
|
||||
Chain Ledger
|
||||
Container hash.Hashable
|
||||
Network uint32
|
||||
Natives []Contract
|
||||
Trigger trigger.Type
|
||||
Block *block.Block
|
||||
NonceData [16]byte
|
||||
Tx *transaction.Transaction
|
||||
DAO *dao.Simple
|
||||
Notifications []state.NotificationEvent
|
||||
Log *zap.Logger
|
||||
VM *vm.VM
|
||||
Functions []Function
|
||||
Invocations map[util.Uint160]int
|
||||
cancelFuncs []context.CancelFunc
|
||||
getContract func(*dao.Simple, util.Uint160) (*state.Contract, error)
|
||||
baseExecFee int64
|
||||
baseStorageFee int64
|
||||
signers []transaction.Signer
|
||||
}
|
||||
|
||||
// NewContext returns new interop context.
|
||||
func NewContext(trigger trigger.Type, bc Ledger, d *dao.Simple, baseExecFee int64,
|
||||
func NewContext(trigger trigger.Type, bc Ledger, d *dao.Simple, baseExecFee, baseStorageFee int64,
|
||||
getContract func(*dao.Simple, util.Uint160) (*state.Contract, error), natives []Contract,
|
||||
block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
|
||||
dao := d.GetPrivate()
|
||||
return &Context{
|
||||
Chain: bc,
|
||||
Network: uint32(bc.GetConfig().Magic),
|
||||
Natives: natives,
|
||||
Trigger: trigger,
|
||||
Block: block,
|
||||
Tx: tx,
|
||||
DAO: dao,
|
||||
Log: log,
|
||||
Invocations: make(map[util.Uint160]int),
|
||||
getContract: getContract,
|
||||
baseExecFee: baseExecFee,
|
||||
Chain: bc,
|
||||
Network: uint32(bc.GetConfig().Magic),
|
||||
Natives: natives,
|
||||
Trigger: trigger,
|
||||
Block: block,
|
||||
Tx: tx,
|
||||
DAO: dao,
|
||||
Log: log,
|
||||
Invocations: make(map[util.Uint160]int),
|
||||
getContract: getContract,
|
||||
baseExecFee: baseExecFee,
|
||||
baseStorageFee: baseStorageFee,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,6 +289,11 @@ func (ic *Context) BaseExecFee() int64 {
|
|||
return ic.baseExecFee
|
||||
}
|
||||
|
||||
// BaseStorageFee represents price for storing one byte of data in the contract storage.
|
||||
func (ic *Context) BaseStorageFee() int64 {
|
||||
return ic.baseStorageFee
|
||||
}
|
||||
|
||||
// SyscallHandler handles syscall with id.
|
||||
func (ic *Context) SyscallHandler(_ *vm.VM, id uint32) error {
|
||||
f := ic.GetFunction(id)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"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/native"
|
||||
"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/crypto/hash"
|
||||
|
@ -72,7 +73,7 @@ func initCheckMultisigVMNoArgs(container *transaction.Transaction) *vm.VM {
|
|||
trigger.Verification,
|
||||
fakechain.NewFakeChain(),
|
||||
dao.NewSimple(storage.NewMemoryStore(), false, false),
|
||||
interop.DefaultBaseExecFee, nil, nil, nil,
|
||||
interop.DefaultBaseExecFee, native.DefaultStoragePrice, nil, nil, nil,
|
||||
container,
|
||||
nil)
|
||||
ic.Container = container
|
||||
|
|
|
@ -126,7 +126,7 @@ func putWithContext(ic *interop.Context, stc *StorageContext, key []byte, value
|
|||
sizeInc = (len(si)-1)/4 + 1 + len(value) - len(si)
|
||||
}
|
||||
}
|
||||
if !ic.VM.AddGas(int64(sizeInc) * ic.Chain.GetStoragePrice()) {
|
||||
if !ic.VM.AddGas(int64(sizeInc) * ic.BaseStorageFee()) {
|
||||
return errGasLimitExceeded
|
||||
}
|
||||
ic.DAO.PutStorageItem(stc.ID, key, value)
|
||||
|
|
|
@ -43,7 +43,7 @@ func Call(ic *interop.Context) error {
|
|||
version, m.MD.Name, ic.VM.Context().GetCallFlags(), m.RequiredFlags)
|
||||
}
|
||||
invokeFee := m.CPUFee*ic.Chain.GetBaseExecFee() +
|
||||
m.StorageFee*ic.Chain.GetStoragePrice()
|
||||
m.StorageFee*ic.BaseStorageFee()
|
||||
if !ic.VM.AddGas(invokeFee) {
|
||||
return errors.New("gas limit exceeded")
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ func (m *Management) getNefAndManifestFromItems(ic *interop.Context, args []stac
|
|||
return nil, nil, fmt.Errorf("invalid manifest: %w", err)
|
||||
}
|
||||
|
||||
gas := ic.Chain.GetStoragePrice() * int64(len(nefBytes)+len(manifestBytes))
|
||||
gas := ic.BaseStorageFee() * int64(len(nefBytes)+len(manifestBytes))
|
||||
if isDeploy {
|
||||
fee := m.minimumDeploymentFee(ic.DAO)
|
||||
if fee > gas {
|
||||
|
|
Loading…
Reference in a new issue