forked from TrueCloudLab/neoneo-go
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.
|
||||
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")
|
||||
}
|
||||
|
||||
|
|
|
@ -2138,14 +2138,14 @@ func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) {
|
|||
return bc.contracts.NEO.GetCandidates(bc.dao)
|
||||
}
|
||||
|
||||
// GetTestVM returns a VM setup for a test run of some sort of code and finalizer function.
|
||||
func (bc *Blockchain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*vm.VM, func()) {
|
||||
// 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 {
|
||||
d := bc.dao.GetWrapped().(*dao.Simple)
|
||||
systemInterop := bc.newInteropContext(t, d, b, tx)
|
||||
vm := systemInterop.SpawnVM()
|
||||
vm.SetPriceGetter(systemInterop.GetPrice)
|
||||
vm.LoadToken = contract.LoadToken(systemInterop)
|
||||
return vm, systemInterop.Finalize
|
||||
return systemInterop
|
||||
}
|
||||
|
||||
// Various witness verification errors.
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"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/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/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
|
@ -59,7 +60,7 @@ type Blockchainer interface {
|
|||
GetStateModule() StateRoot
|
||||
GetStorageItem(id int32, key []byte) state.StorageItem
|
||||
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)
|
||||
SetOracle(service services.Oracle)
|
||||
mempool.Feer // fee interface
|
||||
|
|
|
@ -613,12 +613,12 @@ func setTxSystemFee(bc *Blockchain, sysFee int64, tx *transaction.Transaction) {
|
|||
}
|
||||
|
||||
ttx := *tx // prevent setting 'hash' field
|
||||
v, f := bc.GetTestVM(trigger.Application, &ttx, b)
|
||||
defer f()
|
||||
ic := bc.GetTestVM(trigger.Application, &ttx, b)
|
||||
defer ic.Finalize()
|
||||
|
||||
v.LoadWithFlags(tx.Script, callflag.All)
|
||||
_ = v.Run()
|
||||
tx.SystemFee = v.GasConsumed()
|
||||
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||
_ = ic.VM.Run()
|
||||
tx.SystemFee = ic.VM.GasConsumed()
|
||||
}
|
||||
|
||||
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.
|
||||
// This is unwanted behaviour so we explicitly copy transaction to perform execution.
|
||||
ttx := *tx
|
||||
v, f := bc.GetTestVM(trigger.Application, &ttx, b)
|
||||
defer f()
|
||||
ic := bc.GetTestVM(trigger.Application, &ttx, b)
|
||||
defer ic.Finalize()
|
||||
|
||||
v.LoadWithFlags(tx.Script, callflag.All)
|
||||
err = v.Run()
|
||||
return v, err
|
||||
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||
err = ic.VM.Run()
|
||||
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) {
|
||||
tx := c.PrepareInvokeNoSign(t, method, args...)
|
||||
b := c.NewUnsignedBlock(t, tx)
|
||||
v, f := c.Chain.GetTestVM(trigger.Application, tx, b)
|
||||
t.Cleanup(f)
|
||||
ic := c.Chain.GetTestVM(trigger.Application, tx, b)
|
||||
t.Cleanup(ic.Finalize)
|
||||
|
||||
v.LoadWithFlags(tx.Script, callflag.All)
|
||||
err := v.Run()
|
||||
return v.Estack(), err
|
||||
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||
err := ic.VM.Run()
|
||||
return ic.VM.Estack(), err
|
||||
}
|
||||
|
||||
// WithSigners creates new client with the provided signer.
|
||||
|
|
|
@ -715,9 +715,9 @@ func TestCreateNEP17TransferTx(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, acc.SignTx(testchain.Network(), tx))
|
||||
require.NoError(t, chain.VerifyTx(tx))
|
||||
v, _ := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
v.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||
require.NoError(t, v.Run())
|
||||
ic := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||
require.NoError(t, ic.VM.Run())
|
||||
})
|
||||
t.Run("none scope", func(t *testing.T) {
|
||||
_, 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, acc.SignTx(testchain.Network(), tx))
|
||||
require.NoError(t, chain.VerifyTx(tx))
|
||||
v, _ := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
v.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||
require.NoError(t, v.Run())
|
||||
ic := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||
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 {
|
||||
return nil, nil, err
|
||||
}
|
||||
v, finalize := s.chain.GetTestVM(trigger.Application, tx, b)
|
||||
v.GasLimit = core.HeaderVerificationGasLimit
|
||||
v.LoadScriptWithFlags(script, callflag.All)
|
||||
err = v.Run()
|
||||
ic := s.chain.GetTestVM(trigger.Application, tx, b)
|
||||
ic.VM.GasLimit = core.HeaderVerificationGasLimit
|
||||
ic.VM.LoadScriptWithFlags(script, callflag.All)
|
||||
err = ic.VM.Run()
|
||||
if err != nil {
|
||||
finalize()
|
||||
ic.Finalize()
|
||||
return nil, nil, fmt.Errorf("failed to run `%s` for %s: %w", method, h.StringLE(), err)
|
||||
}
|
||||
if v.Estack().Len() != 1 {
|
||||
finalize()
|
||||
return nil, nil, fmt.Errorf("invalid `%s` return values count: expected 1, got %d", method, v.Estack().Len())
|
||||
if ic.VM.Estack().Len() != 1 {
|
||||
ic.Finalize()
|
||||
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) {
|
||||
|
@ -1690,20 +1690,20 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash
|
|||
if err != nil {
|
||||
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 {
|
||||
vm.EnableInvocationTree()
|
||||
ic.VM.EnableInvocationTree()
|
||||
}
|
||||
vm.GasLimit = int64(s.config.MaxGasInvoke)
|
||||
ic.VM.GasLimit = int64(s.config.MaxGasInvoke)
|
||||
if t == trigger.Verification {
|
||||
// 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.
|
||||
gasPolicy := s.chain.GetMaxVerificationGAS()
|
||||
if vm.GasLimit > gasPolicy {
|
||||
vm.GasLimit = gasPolicy
|
||||
if ic.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)
|
||||
if res == nil {
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
vm.LoadScriptWithFlags(script, callflag.All)
|
||||
ic.VM.LoadScriptWithFlags(script, callflag.All)
|
||||
}
|
||||
err = vm.Run()
|
||||
err = ic.VM.Run()
|
||||
var faultException string
|
||||
if err != nil {
|
||||
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.
|
||||
|
|
|
@ -6,13 +6,13 @@ import (
|
|||
gio "io"
|
||||
|
||||
"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/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"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/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"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.
|
||||
// So make a copy of tx to avoid wrong hash caching.
|
||||
cp := *tx
|
||||
v, finalize := o.Chain.GetTestVM(trigger.Verification, &cp, nil)
|
||||
v.GasLimit = o.Chain.GetMaxVerificationGAS()
|
||||
v.LoadScriptWithHash(o.oracleScript, o.oracleHash, callflag.ReadOnly)
|
||||
v.Context().Jump(o.verifyOffset)
|
||||
ic := o.Chain.GetTestVM(trigger.Verification, &cp, nil)
|
||||
ic.VM.GasLimit = o.Chain.GetMaxVerificationGAS()
|
||||
ic.VM.LoadScriptWithHash(o.oracleScript, o.oracleHash, callflag.ReadOnly)
|
||||
ic.VM.Context().Jump(o.verifyOffset)
|
||||
|
||||
ok := isVerifyOk(v, finalize)
|
||||
return v.GasConsumed(), ok
|
||||
ok := isVerifyOk(ic)
|
||||
return ic.VM.GasConsumed(), ok
|
||||
}
|
||||
|
||||
func isVerifyOk(v *vm.VM, finalize func()) bool {
|
||||
defer finalize()
|
||||
if err := v.Run(); err != nil {
|
||||
func isVerifyOk(ic *interop.Context) bool {
|
||||
defer ic.Finalize()
|
||||
if err := ic.VM.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
if v.Estack().Len() != 1 {
|
||||
if ic.VM.Estack().Len() != 1 {
|
||||
return false
|
||||
}
|
||||
ok, err := v.Estack().Pop().Item().TryBool()
|
||||
ok, err := ic.VM.Estack().Pop().Item().TryBool()
|
||||
return err == nil && ok
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue