core: return *interop.Context from GetTestVM
Return everything needed, fix #2273.
This commit is contained in:
parent
ab2e60458d
commit
9f9bd7261c
9 changed files with 57 additions and 56 deletions
|
@ -327,7 +327,7 @@ func (chain *FakeChain) GetStorageItem(id int32, key []byte) state.StorageItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTestVM implements Blockchainer interface.
|
// GetTestVM implements Blockchainer interface.
|
||||||
func (chain *FakeChain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*vm.VM, func()) {
|
func (chain *FakeChain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) *interop.Context {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2138,14 +2138,14 @@ func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) {
|
||||||
return bc.contracts.NEO.GetCandidates(bc.dao)
|
return bc.contracts.NEO.GetCandidates(bc.dao)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTestVM returns a VM setup for a test run of some sort of code and finalizer function.
|
// 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) (*vm.VM, func()) {
|
func (bc *Blockchain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) *interop.Context {
|
||||||
d := bc.dao.GetWrapped().(*dao.Simple)
|
d := bc.dao.GetWrapped().(*dao.Simple)
|
||||||
systemInterop := bc.newInteropContext(t, d, b, tx)
|
systemInterop := bc.newInteropContext(t, d, b, tx)
|
||||||
vm := systemInterop.SpawnVM()
|
vm := systemInterop.SpawnVM()
|
||||||
vm.SetPriceGetter(systemInterop.GetPrice)
|
vm.SetPriceGetter(systemInterop.GetPrice)
|
||||||
vm.LoadToken = contract.LoadToken(systemInterop)
|
vm.LoadToken = contract.LoadToken(systemInterop)
|
||||||
return vm, systemInterop.Finalize
|
return systemInterop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Various witness verification errors.
|
// Various witness verification errors.
|
||||||
|
|
|
@ -6,6 +6,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/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer/services"
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer/services"
|
||||||
|
"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"
|
||||||
|
@ -59,7 +60,7 @@ type Blockchainer interface {
|
||||||
GetStateModule() StateRoot
|
GetStateModule() StateRoot
|
||||||
GetStorageItem(id int32, key []byte) state.StorageItem
|
GetStorageItem(id int32, key []byte) state.StorageItem
|
||||||
GetStorageItems(id int32) ([]state.StorageItemWithKey, error)
|
GetStorageItems(id int32) ([]state.StorageItemWithKey, error)
|
||||||
GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*vm.VM, func())
|
GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) *interop.Context
|
||||||
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
||||||
SetOracle(service services.Oracle)
|
SetOracle(service services.Oracle)
|
||||||
mempool.Feer // fee interface
|
mempool.Feer // fee interface
|
||||||
|
|
|
@ -613,12 +613,12 @@ func setTxSystemFee(bc *Blockchain, sysFee int64, tx *transaction.Transaction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ttx := *tx // prevent setting 'hash' field
|
ttx := *tx // prevent setting 'hash' field
|
||||||
v, f := bc.GetTestVM(trigger.Application, &ttx, b)
|
ic := bc.GetTestVM(trigger.Application, &ttx, b)
|
||||||
defer f()
|
defer ic.Finalize()
|
||||||
|
|
||||||
v.LoadWithFlags(tx.Script, callflag.All)
|
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||||
_ = v.Run()
|
_ = ic.VM.Run()
|
||||||
tx.SystemFee = v.GasConsumed()
|
tx.SystemFee = ic.VM.GasConsumed()
|
||||||
}
|
}
|
||||||
|
|
||||||
func signTxWithAccounts(chain *Blockchain, sysFee int64, tx *transaction.Transaction, accs ...*wallet.Account) {
|
func signTxWithAccounts(chain *Blockchain, sysFee int64, tx *transaction.Transaction, accs ...*wallet.Account) {
|
||||||
|
|
|
@ -309,10 +309,10 @@ func TestInvoke(bc blockchainer.Blockchainer, tx *transaction.Transaction) (*vm.
|
||||||
// `GetTestVM` as well as `Run` can use transaction hash which will set cached value.
|
// `GetTestVM` as well as `Run` can use transaction hash which will set cached value.
|
||||||
// This is unwanted behaviour so we explicitly copy transaction to perform execution.
|
// This is unwanted behaviour so we explicitly copy transaction to perform execution.
|
||||||
ttx := *tx
|
ttx := *tx
|
||||||
v, f := bc.GetTestVM(trigger.Application, &ttx, b)
|
ic := bc.GetTestVM(trigger.Application, &ttx, b)
|
||||||
defer f()
|
defer ic.Finalize()
|
||||||
|
|
||||||
v.LoadWithFlags(tx.Script, callflag.All)
|
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||||
err = v.Run()
|
err = ic.VM.Run()
|
||||||
return v, err
|
return ic.VM, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,12 @@ func (e *Executor) CommitteeInvoker(h util.Uint160) *ContractInvoker {
|
||||||
func (c *ContractInvoker) TestInvoke(t *testing.T, method string, args ...interface{}) (*vm.Stack, error) {
|
func (c *ContractInvoker) TestInvoke(t *testing.T, method string, args ...interface{}) (*vm.Stack, error) {
|
||||||
tx := c.PrepareInvokeNoSign(t, method, args...)
|
tx := c.PrepareInvokeNoSign(t, method, args...)
|
||||||
b := c.NewUnsignedBlock(t, tx)
|
b := c.NewUnsignedBlock(t, tx)
|
||||||
v, f := c.Chain.GetTestVM(trigger.Application, tx, b)
|
ic := c.Chain.GetTestVM(trigger.Application, tx, b)
|
||||||
t.Cleanup(f)
|
t.Cleanup(ic.Finalize)
|
||||||
|
|
||||||
v.LoadWithFlags(tx.Script, callflag.All)
|
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||||
err := v.Run()
|
err := ic.VM.Run()
|
||||||
return v.Estack(), err
|
return ic.VM.Estack(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSigners creates new client with the provided signer.
|
// WithSigners creates new client with the provided signer.
|
||||||
|
|
|
@ -715,9 +715,9 @@ func TestCreateNEP17TransferTx(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, acc.SignTx(testchain.Network(), tx))
|
require.NoError(t, acc.SignTx(testchain.Network(), tx))
|
||||||
require.NoError(t, chain.VerifyTx(tx))
|
require.NoError(t, chain.VerifyTx(tx))
|
||||||
v, _ := chain.GetTestVM(trigger.Application, tx, nil)
|
ic := chain.GetTestVM(trigger.Application, tx, nil)
|
||||||
v.LoadScriptWithFlags(tx.Script, callflag.All)
|
ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||||
require.NoError(t, v.Run())
|
require.NoError(t, ic.VM.Run())
|
||||||
})
|
})
|
||||||
t.Run("none scope", func(t *testing.T) {
|
t.Run("none scope", func(t *testing.T) {
|
||||||
_, err := c.CreateNEP17TransferTx(acc, util.Uint160{}, gasContractHash, 1000, 0, nil, []client.SignerAccount{{
|
_, err := c.CreateNEP17TransferTx(acc, util.Uint160{}, gasContractHash, 1000, 0, nil, []client.SignerAccount{{
|
||||||
|
@ -739,9 +739,9 @@ func TestCreateNEP17TransferTx(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, acc.SignTx(testchain.Network(), tx))
|
require.NoError(t, acc.SignTx(testchain.Network(), tx))
|
||||||
require.NoError(t, chain.VerifyTx(tx))
|
require.NoError(t, chain.VerifyTx(tx))
|
||||||
v, _ := chain.GetTestVM(trigger.Application, tx, nil)
|
ic := chain.GetTestVM(trigger.Application, tx, nil)
|
||||||
v.LoadScriptWithFlags(tx.Script, callflag.All)
|
ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||||
require.NoError(t, v.Run())
|
require.NoError(t, ic.VM.Run())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -853,19 +853,19 @@ func (s *Server) invokeReadOnly(bw *io.BufBinWriter, h util.Uint160, method stri
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
v, finalize := s.chain.GetTestVM(trigger.Application, tx, b)
|
ic := s.chain.GetTestVM(trigger.Application, tx, b)
|
||||||
v.GasLimit = core.HeaderVerificationGasLimit
|
ic.VM.GasLimit = core.HeaderVerificationGasLimit
|
||||||
v.LoadScriptWithFlags(script, callflag.All)
|
ic.VM.LoadScriptWithFlags(script, callflag.All)
|
||||||
err = v.Run()
|
err = ic.VM.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
finalize()
|
ic.Finalize()
|
||||||
return nil, nil, fmt.Errorf("failed to run `%s` for %s: %w", method, h.StringLE(), err)
|
return nil, nil, fmt.Errorf("failed to run `%s` for %s: %w", method, h.StringLE(), err)
|
||||||
}
|
}
|
||||||
if v.Estack().Len() != 1 {
|
if ic.VM.Estack().Len() != 1 {
|
||||||
finalize()
|
ic.Finalize()
|
||||||
return nil, nil, fmt.Errorf("invalid `%s` return values count: expected 1, got %d", method, v.Estack().Len())
|
return nil, nil, fmt.Errorf("invalid `%s` return values count: expected 1, got %d", method, ic.VM.Estack().Len())
|
||||||
}
|
}
|
||||||
return v.Estack().Pop().Item(), finalize, nil
|
return ic.VM.Estack().Pop().Item(), ic.Finalize, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getTokenBalance(h util.Uint160, acc util.Uint160, id []byte, bw *io.BufBinWriter) (*big.Int, error) {
|
func (s *Server) getTokenBalance(h util.Uint160, acc util.Uint160, id []byte, bw *io.BufBinWriter) (*big.Int, error) {
|
||||||
|
@ -1690,20 +1690,20 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewInternalServerError("can't create fake block", err)
|
return nil, response.NewInternalServerError("can't create fake block", err)
|
||||||
}
|
}
|
||||||
vm, finalize := s.chain.GetTestVM(t, tx, b)
|
ic := s.chain.GetTestVM(t, tx, b)
|
||||||
if verbose {
|
if verbose {
|
||||||
vm.EnableInvocationTree()
|
ic.VM.EnableInvocationTree()
|
||||||
}
|
}
|
||||||
vm.GasLimit = int64(s.config.MaxGasInvoke)
|
ic.VM.GasLimit = int64(s.config.MaxGasInvoke)
|
||||||
if t == trigger.Verification {
|
if t == trigger.Verification {
|
||||||
// We need this special case because witnesses verification is not the simple System.Contract.Call,
|
// We need this special case because witnesses verification is not the simple System.Contract.Call,
|
||||||
// and we need to define exactly the amount of gas consumed for a contract witness verification.
|
// and we need to define exactly the amount of gas consumed for a contract witness verification.
|
||||||
gasPolicy := s.chain.GetMaxVerificationGAS()
|
gasPolicy := s.chain.GetMaxVerificationGAS()
|
||||||
if vm.GasLimit > gasPolicy {
|
if ic.VM.GasLimit > gasPolicy {
|
||||||
vm.GasLimit = gasPolicy
|
ic.VM.GasLimit = gasPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.chain.InitVerificationVM(vm, func(h util.Uint160) (*state.Contract, error) {
|
err := s.chain.InitVerificationVM(ic.VM, func(h util.Uint160) (*state.Contract, error) {
|
||||||
res := s.chain.GetContractState(h)
|
res := s.chain.GetContractState(h)
|
||||||
if res == nil {
|
if res == nil {
|
||||||
return nil, fmt.Errorf("unknown contract: %s", h.StringBE())
|
return nil, fmt.Errorf("unknown contract: %s", h.StringBE())
|
||||||
|
@ -1714,14 +1714,14 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash
|
||||||
return nil, response.NewInternalServerError("can't prepare verification VM", err)
|
return nil, response.NewInternalServerError("can't prepare verification VM", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vm.LoadScriptWithFlags(script, callflag.All)
|
ic.VM.LoadScriptWithFlags(script, callflag.All)
|
||||||
}
|
}
|
||||||
err = vm.Run()
|
err = ic.VM.Run()
|
||||||
var faultException string
|
var faultException string
|
||||||
if err != nil {
|
if err != nil {
|
||||||
faultException = err.Error()
|
faultException = err.Error()
|
||||||
}
|
}
|
||||||
return result.NewInvoke(vm, finalize, script, faultException, s.config.MaxIteratorResultItems), nil
|
return result.NewInvoke(ic.VM, ic.Finalize, script, faultException, s.config.MaxIteratorResultItems), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// submitBlock broadcasts a raw block over the NEO network.
|
// submitBlock broadcasts a raw block over the NEO network.
|
||||||
|
|
|
@ -6,13 +6,13 @@ import (
|
||||||
gio "io"
|
gio "io"
|
||||||
|
|
||||||
"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/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
"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/vm"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -138,24 +138,24 @@ func (o *Oracle) testVerify(tx *transaction.Transaction) (int64, bool) {
|
||||||
// method caches transaction hash, but tx building is not yet completed and hash will be changed.
|
// method caches transaction hash, but tx building is not yet completed and hash will be changed.
|
||||||
// So make a copy of tx to avoid wrong hash caching.
|
// So make a copy of tx to avoid wrong hash caching.
|
||||||
cp := *tx
|
cp := *tx
|
||||||
v, finalize := o.Chain.GetTestVM(trigger.Verification, &cp, nil)
|
ic := o.Chain.GetTestVM(trigger.Verification, &cp, nil)
|
||||||
v.GasLimit = o.Chain.GetMaxVerificationGAS()
|
ic.VM.GasLimit = o.Chain.GetMaxVerificationGAS()
|
||||||
v.LoadScriptWithHash(o.oracleScript, o.oracleHash, callflag.ReadOnly)
|
ic.VM.LoadScriptWithHash(o.oracleScript, o.oracleHash, callflag.ReadOnly)
|
||||||
v.Context().Jump(o.verifyOffset)
|
ic.VM.Context().Jump(o.verifyOffset)
|
||||||
|
|
||||||
ok := isVerifyOk(v, finalize)
|
ok := isVerifyOk(ic)
|
||||||
return v.GasConsumed(), ok
|
return ic.VM.GasConsumed(), ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func isVerifyOk(v *vm.VM, finalize func()) bool {
|
func isVerifyOk(ic *interop.Context) bool {
|
||||||
defer finalize()
|
defer ic.Finalize()
|
||||||
if err := v.Run(); err != nil {
|
if err := ic.VM.Run(); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if v.Estack().Len() != 1 {
|
if ic.VM.Estack().Len() != 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
ok, err := v.Estack().Pop().Item().TryBool()
|
ok, err := ic.VM.Estack().Pop().Item().TryBool()
|
||||||
return err == nil && ok
|
return err == nil && ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue