mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-22 19:19:09 +00:00
Merge pull request #2543 from nspcc-dev/perf-new
Minor allocation improvements
This commit is contained in:
commit
8673d2a79c
9 changed files with 118 additions and 63 deletions
|
@ -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()))
|
||||||
|
|
|
@ -1095,7 +1095,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
||||||
close(aerdone)
|
close(aerdone)
|
||||||
}()
|
}()
|
||||||
_ = cache.GetItemCtx() // Prime serialization context cache (it'll be reused by upper layer DAOs).
|
_ = cache.GetItemCtx() // Prime serialization context cache (it'll be reused by upper layer DAOs).
|
||||||
aer, err := bc.runPersist(bc.contracts.GetPersistScript(), block, cache, trigger.OnPersist)
|
aer, v, err := bc.runPersist(bc.contracts.GetPersistScript(), block, cache, trigger.OnPersist, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Release goroutines, don't care about errors, we already have one.
|
// Release goroutines, don't care about errors, we already have one.
|
||||||
close(aerchan)
|
close(aerchan)
|
||||||
|
@ -1107,10 +1107,8 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
||||||
|
|
||||||
for _, tx := range block.Transactions {
|
for _, tx := range block.Transactions {
|
||||||
systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx)
|
systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx)
|
||||||
v := systemInterop.SpawnVM()
|
systemInterop.ReuseVM(v)
|
||||||
v.LoadScriptWithFlags(tx.Script, callflag.All)
|
v.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||||
v.SetPriceGetter(systemInterop.GetPrice)
|
|
||||||
v.LoadToken = contract.LoadToken(systemInterop)
|
|
||||||
v.GasLimit = tx.SystemFee
|
v.GasLimit = tx.SystemFee
|
||||||
|
|
||||||
err := systemInterop.Exec()
|
err := systemInterop.Exec()
|
||||||
|
@ -1145,7 +1143,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
||||||
aerchan <- aer
|
aerchan <- aer
|
||||||
}
|
}
|
||||||
|
|
||||||
aer, err = bc.runPersist(bc.contracts.GetPostPersistScript(), block, cache, trigger.PostPersist)
|
aer, _, err = bc.runPersist(bc.contracts.GetPostPersistScript(), block, cache, trigger.PostPersist, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Release goroutines, don't care about errors, we already have one.
|
// Release goroutines, don't care about errors, we already have one.
|
||||||
close(aerchan)
|
close(aerchan)
|
||||||
|
@ -1280,15 +1278,18 @@ func (bc *Blockchain) IsExtensibleAllowed(u util.Uint160) bool {
|
||||||
return n < len(us)
|
return n < len(us)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.Simple, trig trigger.Type) (*state.AppExecResult, error) {
|
func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.Simple, trig trigger.Type, v *vm.VM) (*state.AppExecResult, *vm.VM, error) {
|
||||||
systemInterop := bc.newInteropContext(trig, cache, block, nil)
|
systemInterop := bc.newInteropContext(trig, cache, block, nil)
|
||||||
v := systemInterop.SpawnVM()
|
if v == nil {
|
||||||
|
v = systemInterop.SpawnVM()
|
||||||
|
} else {
|
||||||
|
systemInterop.ReuseVM(v)
|
||||||
|
}
|
||||||
v.LoadScriptWithFlags(script, callflag.All)
|
v.LoadScriptWithFlags(script, callflag.All)
|
||||||
v.SetPriceGetter(systemInterop.GetPrice)
|
|
||||||
if err := systemInterop.Exec(); err != nil {
|
if err := systemInterop.Exec(); err != nil {
|
||||||
return nil, fmt.Errorf("VM has failed: %w", err)
|
return nil, v, fmt.Errorf("VM has failed: %w", err)
|
||||||
} else if _, err := systemInterop.DAO.Persist(); err != nil {
|
} else if _, err := systemInterop.DAO.Persist(); err != nil {
|
||||||
return nil, fmt.Errorf("can't save changes: %w", err)
|
return nil, v, fmt.Errorf("can't save changes: %w", err)
|
||||||
}
|
}
|
||||||
return &state.AppExecResult{
|
return &state.AppExecResult{
|
||||||
Container: block.Hash(), // application logs can be retrieved by block hash
|
Container: block.Hash(), // application logs can be retrieved by block hash
|
||||||
|
@ -1299,7 +1300,7 @@ func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.S
|
||||||
Stack: v.Estack().ToArray(),
|
Stack: v.Estack().ToArray(),
|
||||||
Events: systemInterop.Notifications,
|
Events: systemInterop.Notifications,
|
||||||
},
|
},
|
||||||
}, nil
|
}, v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.Simple,
|
func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.Simple,
|
||||||
|
@ -1365,6 +1366,7 @@ func (bc *Blockchain) processTokenTransfer(cache *dao.Simple, transCache map[uti
|
||||||
if !isNEP11 {
|
if !isNEP11 {
|
||||||
nep17xfer = &state.NEP17Transfer{
|
nep17xfer = &state.NEP17Transfer{
|
||||||
Asset: id,
|
Asset: id,
|
||||||
|
Amount: *amount,
|
||||||
From: from,
|
From: from,
|
||||||
To: to,
|
To: to,
|
||||||
Block: b.Index,
|
Block: b.Index,
|
||||||
|
@ -1376,6 +1378,7 @@ func (bc *Blockchain) processTokenTransfer(cache *dao.Simple, transCache map[uti
|
||||||
nep11xfer := &state.NEP11Transfer{
|
nep11xfer := &state.NEP11Transfer{
|
||||||
NEP17Transfer: state.NEP17Transfer{
|
NEP17Transfer: state.NEP17Transfer{
|
||||||
Asset: id,
|
Asset: id,
|
||||||
|
Amount: *amount,
|
||||||
From: from,
|
From: from,
|
||||||
To: to,
|
To: to,
|
||||||
Block: b.Index,
|
Block: b.Index,
|
||||||
|
@ -1388,13 +1391,14 @@ func (bc *Blockchain) processTokenTransfer(cache *dao.Simple, transCache map[uti
|
||||||
nep17xfer = &nep11xfer.NEP17Transfer
|
nep17xfer = &nep11xfer.NEP17Transfer
|
||||||
}
|
}
|
||||||
if !from.Equals(util.Uint160{}) {
|
if !from.Equals(util.Uint160{}) {
|
||||||
_ = nep17xfer.Amount.Neg(amount) // We already have the Int.
|
_ = nep17xfer.Amount.Neg(&nep17xfer.Amount)
|
||||||
if appendTokenTransfer(cache, transCache, from, transfer, id, b.Index, b.Timestamp, isNEP11) != nil {
|
err := appendTokenTransfer(cache, transCache, from, transfer, id, b.Index, b.Timestamp, isNEP11)
|
||||||
|
_ = nep17xfer.Amount.Neg(&nep17xfer.Amount)
|
||||||
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !to.Equals(util.Uint160{}) {
|
if !to.Equals(util.Uint160{}) {
|
||||||
_ = nep17xfer.Amount.Set(amount) // We already have the Int.
|
|
||||||
_ = appendTokenTransfer(cache, transCache, to, transfer, id, b.Index, b.Timestamp, isNEP11) // Nothing useful we can do.
|
_ = appendTokenTransfer(cache, transCache, to, transfer, id, b.Index, b.Timestamp, isNEP11) // Nothing useful we can do.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1451,7 +1455,7 @@ func appendTokenTransfer(cache *dao.Simple, transCache map[util.Uint160]transfer
|
||||||
*nextBatch++
|
*nextBatch++
|
||||||
*currTimestamp = bTimestamp
|
*currTimestamp = bTimestamp
|
||||||
// Put makes a copy of it anyway.
|
// Put makes a copy of it anyway.
|
||||||
log.Raw = log.Raw[:0]
|
log.Reset()
|
||||||
}
|
}
|
||||||
transCache[addr] = transferData
|
transCache[addr] = transferData
|
||||||
return nil
|
return nil
|
||||||
|
@ -2164,9 +2168,7 @@ func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) {
|
||||||
// GetTestVM returns an interop context with VM set up for a test run.
|
// GetTestVM returns an interop context with VM set up for a test run.
|
||||||
func (bc *Blockchain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) *interop.Context {
|
func (bc *Blockchain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) *interop.Context {
|
||||||
systemInterop := bc.newInteropContext(t, bc.dao, b, tx)
|
systemInterop := bc.newInteropContext(t, bc.dao, b, tx)
|
||||||
vm := systemInterop.SpawnVM()
|
_ = systemInterop.SpawnVM() // All the other code suppose that the VM is ready.
|
||||||
vm.SetPriceGetter(systemInterop.GetPrice)
|
|
||||||
vm.LoadToken = contract.LoadToken(systemInterop)
|
|
||||||
return systemInterop
|
return systemInterop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2199,9 +2201,7 @@ func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transact
|
||||||
return nil, fmt.Errorf("failed to initialize native cache backed by historic DAO: %w", err)
|
return nil, fmt.Errorf("failed to initialize native cache backed by historic DAO: %w", err)
|
||||||
}
|
}
|
||||||
systemInterop := bc.newInteropContext(t, dTrie, b, tx)
|
systemInterop := bc.newInteropContext(t, dTrie, b, tx)
|
||||||
vm := systemInterop.SpawnVM()
|
_ = systemInterop.SpawnVM() // All the other code suppose that the VM is ready.
|
||||||
vm.SetPriceGetter(systemInterop.GetPrice)
|
|
||||||
vm.LoadToken = contract.LoadToken(systemInterop)
|
|
||||||
return systemInterop, nil
|
return systemInterop, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2276,8 +2276,6 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
|
||||||
}
|
}
|
||||||
|
|
||||||
vm := interopCtx.SpawnVM()
|
vm := interopCtx.SpawnVM()
|
||||||
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
|
||||||
|
@ -2373,7 +2371,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:
|
||||||
|
|
|
@ -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,10 +326,22 @@ 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)
|
||||||
|
ic.initVM(v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ic *Context) initVM(v *vm.VM) {
|
||||||
|
v.LoadToken = ic.LoadToken
|
||||||
v.GasLimit = -1
|
v.GasLimit = -1
|
||||||
v.SyscallHandler = ic.SyscallHandler
|
v.SyscallHandler = ic.SyscallHandler
|
||||||
|
v.SetPriceGetter(ic.GetPrice)
|
||||||
ic.VM = v
|
ic.VM = v
|
||||||
return v
|
}
|
||||||
|
|
||||||
|
// ReuseVM resets given VM and allows to reuse it in the current context.
|
||||||
|
func (ic *Context) ReuseVM(v *vm.VM) {
|
||||||
|
v.Reset(ic.Trigger)
|
||||||
|
ic.initVM(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterCancelFunc adds the given function to the list of functions to be called after the VM
|
// RegisterCancelFunc adds the given function to the list of functions to be called after the VM
|
||||||
|
|
|
@ -22,26 +22,24 @@ 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")
|
|
||||||
}
|
|
||||||
tok := ctx.NEF.Tokens[id]
|
|
||||||
if int(tok.ParamCount) > ctx.Estack().Len() {
|
|
||||||
return errors.New("stack is too small")
|
|
||||||
}
|
|
||||||
args := make([]stackitem.Item, tok.ParamCount)
|
|
||||||
for i := range args {
|
|
||||||
args[i] = ic.VM.Estack().Pop().Item()
|
|
||||||
}
|
|
||||||
cs, err := ic.GetContract(tok.Hash)
|
|
||||||
if err != nil {
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
tok := ctx.NEF.Tokens[id]
|
||||||
|
if int(tok.ParamCount) > ctx.Estack().Len() {
|
||||||
|
return errors.New("stack is too small")
|
||||||
|
}
|
||||||
|
args := make([]stackitem.Item, tok.ParamCount)
|
||||||
|
for i := range args {
|
||||||
|
args[i] = ic.VM.Estack().Pop().Item()
|
||||||
|
}
|
||||||
|
cs, err := ic.GetContract(tok.Hash)
|
||||||
|
if err != nil {
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call calls a contract with flags.
|
// Call calls a contract with flags.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -16,6 +16,8 @@ const TokenTransferBatchSize = 128
|
||||||
// TokenTransferLog is a serialized log of token transfers.
|
// TokenTransferLog is a serialized log of token transfers.
|
||||||
type TokenTransferLog struct {
|
type TokenTransferLog struct {
|
||||||
Raw []byte
|
Raw []byte
|
||||||
|
buf *bytes.Buffer
|
||||||
|
iow *io.BinWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEP17Transfer represents a single NEP-17 Transfer event.
|
// NEP17Transfer represents a single NEP-17 Transfer event.
|
||||||
|
@ -111,18 +113,30 @@ func (lg *TokenTransferLog) Append(tr io.Serializable) error {
|
||||||
lg.Raw = append(lg.Raw, 0)
|
lg.Raw = append(lg.Raw, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
b := bytes.NewBuffer(lg.Raw)
|
if lg.buf == nil {
|
||||||
w := io.NewBinWriterFromIO(b)
|
lg.buf = bytes.NewBuffer(lg.Raw)
|
||||||
|
|
||||||
tr.EncodeBinary(w)
|
|
||||||
if w.Err != nil {
|
|
||||||
return w.Err
|
|
||||||
}
|
}
|
||||||
lg.Raw = b.Bytes()
|
if lg.iow == nil {
|
||||||
|
lg.iow = io.NewBinWriterFromIO(lg.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.EncodeBinary(lg.iow)
|
||||||
|
if lg.iow.Err != nil {
|
||||||
|
return lg.iow.Err
|
||||||
|
}
|
||||||
|
lg.Raw = lg.buf.Bytes()
|
||||||
lg.Raw[0]++
|
lg.Raw[0]++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset resets the state of the log, clearing all entries, but keeping existing
|
||||||
|
// buffer for future writes.
|
||||||
|
func (lg *TokenTransferLog) Reset() {
|
||||||
|
lg.Raw = lg.Raw[:0]
|
||||||
|
lg.buf = nil
|
||||||
|
lg.iow = nil
|
||||||
|
}
|
||||||
|
|
||||||
// ForEachNEP11 iterates over a transfer log returning on the first error.
|
// ForEachNEP11 iterates over a transfer log returning on the first error.
|
||||||
func (lg *TokenTransferLog) ForEachNEP11(f func(*NEP11Transfer) (bool, error)) (bool, error) {
|
func (lg *TokenTransferLog) ForEachNEP11(f func(*NEP11Transfer) (bool, error)) (bool, error) {
|
||||||
if lg == nil || len(lg.Raw) == 0 {
|
if lg == nil || len(lg.Raw) == 0 {
|
||||||
|
|
|
@ -48,3 +48,12 @@ func BenchmarkScriptPushPop(t *testing.B) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkIsSignatureContract(t *testing.B) {
|
||||||
|
b64script := "DCED2eixa9myLTNF1tTN4xvhw+HRYVMuPQzOy5Xs4utYM25BVuezJw=="
|
||||||
|
script, err := base64.StdEncoding.DecodeString(b64script)
|
||||||
|
require.NoError(t, err)
|
||||||
|
for n := 0; n < t.N; n++ {
|
||||||
|
_ = IsSignatureContract(script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -118,17 +118,14 @@ func ParseSignatureContract(script []byte) ([]byte, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := NewContext(script)
|
// We don't use Context for this simple case, it's more efficient this way.
|
||||||
instr, param, err := ctx.Next()
|
if script[0] == byte(opcode.PUSHDATA1) && // PUSHDATA1
|
||||||
if err != nil || instr != opcode.PUSHDATA1 || len(param) != 33 {
|
script[1] == 33 && // with a public key parameter
|
||||||
return nil, false
|
script[35] == byte(opcode.SYSCALL) && // and a CheckSig SYSCALL.
|
||||||
|
binary.LittleEndian.Uint32(script[36:]) == verifyInteropID {
|
||||||
|
return script[2:35], true
|
||||||
}
|
}
|
||||||
pub := param
|
return nil, false
|
||||||
instr, param, err = ctx.Next()
|
|
||||||
if err != nil || instr != opcode.SYSCALL || binary.LittleEndian.Uint32(param) != verifyInteropID {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
return pub, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsStandardContract checks whether the passed script is a signature or
|
// IsStandardContract checks whether the passed script is a signature or
|
||||||
|
|
18
pkg/vm/vm.go
18
pkg/vm/vm.go
|
@ -122,6 +122,24 @@ func (v *VM) SetPriceGetter(f func(opcode.Opcode, []byte) int64) {
|
||||||
v.getPrice = f
|
v.getPrice = f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset allows to reuse existing VM for subsequent executions making them somewhat
|
||||||
|
// more efficient. It reuses invocation and evaluation stacks as well as VM structure
|
||||||
|
// itself.
|
||||||
|
func (v *VM) Reset(t trigger.Type) {
|
||||||
|
v.state = NoneState
|
||||||
|
v.getPrice = nil
|
||||||
|
v.istack.elems = v.istack.elems[:0]
|
||||||
|
v.estack.elems = v.estack.elems[:0]
|
||||||
|
v.uncaughtException = nil
|
||||||
|
v.refs = 0
|
||||||
|
v.gasConsumed = 0
|
||||||
|
v.GasLimit = 0
|
||||||
|
v.SyscallHandler = nil
|
||||||
|
v.LoadToken = nil
|
||||||
|
v.trigger = t
|
||||||
|
v.invTree = nil
|
||||||
|
}
|
||||||
|
|
||||||
// GasConsumed returns the amount of GAS consumed during execution.
|
// GasConsumed returns the amount of GAS consumed during execution.
|
||||||
func (v *VM) GasConsumed() int64 {
|
func (v *VM) GasConsumed() int64 {
|
||||||
return v.gasConsumed
|
return v.gasConsumed
|
||||||
|
|
Loading…
Reference in a new issue