interop: wrap contract.LoadToken in context.LoadToken

Creating a closure in runtime is a relatively costly thing, but it can easily
be avoided.
This commit is contained in:
Roman Khimov 2022-06-06 21:53:03 +03:00
parent 799394192b
commit 638b04b29a
5 changed files with 30 additions and 26 deletions

View file

@ -202,7 +202,7 @@ func TestAppCall(t *testing.T) {
fc := fakechain.NewFakeChain() fc := fakechain.NewFakeChain()
ic := interop.NewContext(trigger.Application, fc, dao.NewSimple(storage.NewMemoryStore(), false, false), ic := interop.NewContext(trigger.Application, fc, dao.NewSimple(storage.NewMemoryStore(), false, false),
interop.DefaultBaseExecFee, native.DefaultStoragePrice, contractGetter, nil, nil, nil, zaptest.NewLogger(t)) interop.DefaultBaseExecFee, native.DefaultStoragePrice, contractGetter, nil, nil, nil, nil, zaptest.NewLogger(t))
t.Run("valid script", func(t *testing.T) { t.Run("valid script", func(t *testing.T) {
src := getAppCallScript(fmt.Sprintf("%#v", ih.BytesBE())) src := getAppCallScript(fmt.Sprintf("%#v", ih.BytesBE()))

View file

@ -1110,7 +1110,6 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
v := systemInterop.SpawnVM() v := systemInterop.SpawnVM()
v.LoadScriptWithFlags(tx.Script, callflag.All) v.LoadScriptWithFlags(tx.Script, callflag.All)
v.SetPriceGetter(systemInterop.GetPrice) v.SetPriceGetter(systemInterop.GetPrice)
v.LoadToken = contract.LoadToken(systemInterop)
v.GasLimit = tx.SystemFee v.GasLimit = tx.SystemFee
err := systemInterop.Exec() err := systemInterop.Exec()
@ -2169,7 +2168,6 @@ func (bc *Blockchain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *
systemInterop := bc.newInteropContext(t, bc.dao, b, tx) systemInterop := bc.newInteropContext(t, bc.dao, b, tx)
vm := systemInterop.SpawnVM() vm := systemInterop.SpawnVM()
vm.SetPriceGetter(systemInterop.GetPrice) vm.SetPriceGetter(systemInterop.GetPrice)
vm.LoadToken = contract.LoadToken(systemInterop)
return systemInterop return systemInterop
} }
@ -2204,7 +2202,6 @@ func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transact
systemInterop := bc.newInteropContext(t, dTrie, b, tx) systemInterop := bc.newInteropContext(t, dTrie, b, tx)
vm := systemInterop.SpawnVM() vm := systemInterop.SpawnVM()
vm.SetPriceGetter(systemInterop.GetPrice) vm.SetPriceGetter(systemInterop.GetPrice)
vm.LoadToken = contract.LoadToken(systemInterop)
return systemInterop, nil return systemInterop, nil
} }
@ -2280,7 +2277,6 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
vm := interopCtx.SpawnVM() vm := interopCtx.SpawnVM()
vm.SetPriceGetter(interopCtx.GetPrice) vm.SetPriceGetter(interopCtx.GetPrice)
vm.LoadToken = contract.LoadToken(interopCtx)
vm.GasLimit = gas vm.GasLimit = gas
if err := bc.InitVerificationContext(interopCtx, hash, witness); err != nil { if err := bc.InitVerificationContext(interopCtx, hash, witness); err != nil {
return 0, err return 0, err
@ -2376,7 +2372,7 @@ func (bc *Blockchain) newInteropContext(trigger trigger.Type, d *dao.Simple, blo
// changes that were not yet persisted to Blockchain's dao. // changes that were not yet persisted to Blockchain's dao.
baseStorageFee = bc.contracts.Policy.GetStoragePriceInternal(d) 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 := interop.NewContext(trigger, bc, d, baseExecFee, baseStorageFee, bc.contracts.Management.GetContract, bc.contracts.Contracts, contract.LoadToken, block, tx, bc.log)
ic.Functions = systemInterops ic.Functions = systemInterops
switch { switch {
case tx != nil: case tx != nil:

View file

@ -64,6 +64,7 @@ type Context struct {
getContract func(*dao.Simple, util.Uint160) (*state.Contract, error) getContract func(*dao.Simple, util.Uint160) (*state.Contract, error)
baseExecFee int64 baseExecFee int64
baseStorageFee int64 baseStorageFee int64
loadToken func(ic *Context, id int32) error
GetRandomCounter uint32 GetRandomCounter uint32
signers []transaction.Signer signers []transaction.Signer
} }
@ -71,6 +72,7 @@ type Context struct {
// NewContext returns new interop context. // NewContext returns new interop context.
func NewContext(trigger trigger.Type, bc Ledger, d *dao.Simple, baseExecFee, baseStorageFee 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, getContract func(*dao.Simple, util.Uint160) (*state.Contract, error), natives []Contract,
loadTokenFunc func(ic *Context, id int32) error,
block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context { block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
dao := d.GetPrivate() dao := d.GetPrivate()
cfg := bc.GetConfig() cfg := bc.GetConfig()
@ -88,6 +90,7 @@ func NewContext(trigger trigger.Type, bc Ledger, d *dao.Simple, baseExecFee, bas
getContract: getContract, getContract: getContract,
baseExecFee: baseExecFee, baseExecFee: baseExecFee,
baseStorageFee: baseStorageFee, baseStorageFee: baseStorageFee,
loadToken: loadTokenFunc,
} }
} }
@ -298,6 +301,12 @@ func (ic *Context) BaseStorageFee() int64 {
return ic.baseStorageFee return ic.baseStorageFee
} }
// LoadToken wraps externally provided load-token loading function providing it with context,
// this function can then be easily used by VM.
func (ic *Context) LoadToken(id int32) error {
return ic.loadToken(ic, id)
}
// 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)
@ -317,6 +326,7 @@ func (ic *Context) SyscallHandler(_ *vm.VM, id uint32) error {
// SpawnVM spawns a new VM with the specified gas limit and set context.VM field. // SpawnVM spawns a new VM with the specified gas limit and set context.VM field.
func (ic *Context) SpawnVM() *vm.VM { func (ic *Context) SpawnVM() *vm.VM {
v := vm.NewWithTrigger(ic.Trigger) v := vm.NewWithTrigger(ic.Trigger)
v.LoadToken = ic.LoadToken
v.GasLimit = -1 v.GasLimit = -1
v.SyscallHandler = ic.SyscallHandler v.SyscallHandler = ic.SyscallHandler
ic.VM = v ic.VM = v

View file

@ -22,8 +22,7 @@ type policyChecker interface {
} }
// LoadToken calls method specified by the token id. // LoadToken calls method specified by the token id.
func LoadToken(ic *interop.Context) func(id int32) error { func LoadToken(ic *interop.Context, id int32) error {
return func(id int32) error {
ctx := ic.VM.Context() ctx := ic.VM.Context()
if !ctx.GetCallFlags().Has(callflag.ReadStates | callflag.AllowCall) { if !ctx.GetCallFlags().Has(callflag.ReadStates | callflag.AllowCall) {
return errors.New("invalid call flags") return errors.New("invalid call flags")
@ -41,7 +40,6 @@ func LoadToken(ic *interop.Context) func(id int32) error {
return fmt.Errorf("token contract %s not found: %w", tok.Hash.StringLE(), err) return fmt.Errorf("token contract %s not found: %w", tok.Hash.StringLE(), err)
} }
return callInternal(ic, cs, tok.Method, tok.CallFlag, tok.HasReturn, args, false) return callInternal(ic, cs, tok.Method, tok.CallFlag, tok.HasReturn, args, false)
}
} }
// Call calls a contract with flags. // Call calls a contract with flags.

View file

@ -73,7 +73,7 @@ func initCheckMultisigVMNoArgs(container *transaction.Transaction) *vm.VM {
trigger.Verification, trigger.Verification,
fakechain.NewFakeChain(), fakechain.NewFakeChain(),
dao.NewSimple(storage.NewMemoryStore(), false, false), dao.NewSimple(storage.NewMemoryStore(), false, false),
interop.DefaultBaseExecFee, native.DefaultStoragePrice, nil, nil, nil, interop.DefaultBaseExecFee, native.DefaultStoragePrice, nil, nil, nil, nil,
container, container,
nil) nil)
ic.Container = container ic.Container = container