forked from TrueCloudLab/neoneo-go
core, rpc: move getFakeNextBlock to Blockchain
It's needed for VM CLI as far and may be improved later.
This commit is contained in:
parent
0036c89d63
commit
79e13f73d8
13 changed files with 136 additions and 89 deletions
|
@ -333,7 +333,10 @@ func NewWithConfig(printLogotype bool, onExit func(int), c *readline.Config, cfg
|
|||
return nil, cli.NewExitError(fmt.Errorf("could not initialize blockchain: %w", err), 1)
|
||||
}
|
||||
// Do not run chain, we need only state-related functionality from it.
|
||||
ic := chain.GetTestVM(trigger.Application, nil, nil)
|
||||
ic, err := chain.GetTestVM(trigger.Application, nil, nil)
|
||||
if err != nil {
|
||||
return nil, cli.NewExitError(fmt.Errorf("failed to create test VM: %w", err), 1)
|
||||
}
|
||||
|
||||
vmcli := VMCLI{
|
||||
chain: chain,
|
||||
|
@ -483,7 +486,10 @@ func handleSlots(c *cli.Context) error {
|
|||
}
|
||||
|
||||
func handleLoadNEF(c *cli.Context) error {
|
||||
resetState(c.App)
|
||||
err := resetState(c.App)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
args := c.Args()
|
||||
if len(args) < 2 {
|
||||
|
@ -503,7 +509,10 @@ func handleLoadNEF(c *cli.Context) error {
|
|||
}
|
||||
|
||||
func handleLoadBase64(c *cli.Context) error {
|
||||
resetState(c.App)
|
||||
err := resetState(c.App)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
|
@ -520,7 +529,10 @@ func handleLoadBase64(c *cli.Context) error {
|
|||
}
|
||||
|
||||
func handleLoadHex(c *cli.Context) error {
|
||||
resetState(c.App)
|
||||
err := resetState(c.App)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
|
@ -537,7 +549,10 @@ func handleLoadHex(c *cli.Context) error {
|
|||
}
|
||||
|
||||
func handleLoadGo(c *cli.Context) error {
|
||||
resetState(c.App)
|
||||
err := resetState(c.App)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := getVMFromContext(c.App)
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
|
@ -564,7 +579,10 @@ func handleLoadGo(c *cli.Context) error {
|
|||
}
|
||||
|
||||
func handleReset(c *cli.Context) error {
|
||||
resetState(c.App)
|
||||
err := resetState(c.App)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
changePrompt(c.App)
|
||||
return nil
|
||||
}
|
||||
|
@ -577,11 +595,15 @@ func finalizeInteropContext(app *cli.App) {
|
|||
|
||||
// resetInteropContext calls finalizer for current interop context and replaces
|
||||
// it with the newly created one.
|
||||
func resetInteropContext(app *cli.App) {
|
||||
func resetInteropContext(app *cli.App) error {
|
||||
finalizeInteropContext(app)
|
||||
bc := getChainFromContext(app)
|
||||
newIc := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
newIc, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create test VM: %w", err)
|
||||
}
|
||||
setInteropContextInContext(app, newIc)
|
||||
return nil
|
||||
}
|
||||
|
||||
// resetManifest removes manifest from app context.
|
||||
|
@ -591,9 +613,13 @@ func resetManifest(app *cli.App) {
|
|||
|
||||
// resetState resets state of the app (clear interop context and manifest) so that it's ready
|
||||
// to load new program.
|
||||
func resetState(app *cli.App) {
|
||||
resetInteropContext(app)
|
||||
func resetState(app *cli.App) error {
|
||||
err := resetInteropContext(app)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to reset interop context state: %w", err)
|
||||
}
|
||||
resetManifest(app)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getManifestFromFile(name string) (*manifest.Manifest, error) {
|
||||
|
|
|
@ -298,7 +298,7 @@ func (chain *FakeChain) GetStorageItem(id int32, key []byte) state.StorageItem {
|
|||
}
|
||||
|
||||
// GetTestVM implements the Blockchainer interface.
|
||||
func (chain *FakeChain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) *interop.Context {
|
||||
func (chain *FakeChain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*interop.Context, error) {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
|
|
|
@ -2241,19 +2241,28 @@ func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) {
|
|||
}
|
||||
|
||||
// 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, error) {
|
||||
if b == nil {
|
||||
var err error
|
||||
h := bc.BlockHeight() + 1
|
||||
b, err = bc.getFakeNextBlock(h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create fake block for height %d: %w", h, err)
|
||||
}
|
||||
}
|
||||
systemInterop := bc.newInteropContext(t, bc.dao, b, tx)
|
||||
_ = systemInterop.SpawnVM() // All the other code suppose that the VM is ready.
|
||||
return systemInterop
|
||||
return systemInterop, nil
|
||||
}
|
||||
|
||||
// GetTestHistoricVM returns an interop context with VM set up for a test run.
|
||||
func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*interop.Context, error) {
|
||||
func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, nextBlockHeight uint32) (*interop.Context, error) {
|
||||
if bc.config.KeepOnlyLatestState {
|
||||
return nil, errors.New("only latest state is supported")
|
||||
}
|
||||
if b == nil {
|
||||
return nil, errors.New("block is mandatory to produce test historic VM")
|
||||
b, err := bc.getFakeNextBlock(nextBlockHeight)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create fake block for height %d: %w", nextBlockHeight, err)
|
||||
}
|
||||
var mode = mpt.ModeAll
|
||||
if bc.config.RemoveUntraceableBlocks {
|
||||
|
@ -2284,6 +2293,18 @@ func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transact
|
|||
return systemInterop, nil
|
||||
}
|
||||
|
||||
// getFakeNextBlock returns fake block with the specified index and pre-filled Timestamp field.
|
||||
func (bc *Blockchain) getFakeNextBlock(nextBlockHeight uint32) (*block.Block, error) {
|
||||
b := block.New(bc.config.StateRootInHeader)
|
||||
b.Index = nextBlockHeight
|
||||
hdr, err := bc.GetHeader(bc.GetHeaderHash(int(nextBlockHeight - 1)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.Timestamp = hdr.Timestamp + uint64(bc.config.SecondsPerBlock*int(time.Second/time.Millisecond))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Various witness verification errors.
|
||||
var (
|
||||
ErrWitnessHashMismatch = errors.New("witness hash mismatch")
|
||||
|
|
|
@ -32,7 +32,8 @@ var pathToInternalContracts = filepath.Join("..", "..", "..", "..", "internal",
|
|||
|
||||
func TestGetCallFlags(t *testing.T) {
|
||||
bc, _ := chain.NewSingle(t)
|
||||
ic := bc.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||
ic, err := bc.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||
require.NoError(t, err)
|
||||
|
||||
ic.VM.LoadScriptWithHash([]byte{byte(opcode.RET)}, util.Uint160{1, 2, 3}, callflag.All)
|
||||
require.NoError(t, contract.GetCallFlags(ic))
|
||||
|
@ -41,7 +42,8 @@ func TestGetCallFlags(t *testing.T) {
|
|||
|
||||
func TestCall(t *testing.T) {
|
||||
bc, _ := chain.NewSingle(t)
|
||||
ic := bc.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||
ic, err := bc.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||
require.NoError(t, err)
|
||||
|
||||
cs, currCs := contracts.GetTestContractState(t, pathToInternalContracts, 4, 5, random.Uint160()) // sender and IDs are not important for the test
|
||||
require.NoError(t, native.PutContractState(ic.DAO, cs))
|
||||
|
|
|
@ -65,7 +65,8 @@ func getSharpTestGenesis(t *testing.T) *block.Block {
|
|||
|
||||
func createVM(t testing.TB) (*vm.VM, *interop.Context, *core.Blockchain) {
|
||||
chain, _ := chain.NewSingle(t)
|
||||
ic := chain.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||
ic, err := chain.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||
require.NoError(t, err)
|
||||
v := ic.SpawnVM()
|
||||
return v, ic, chain
|
||||
}
|
||||
|
@ -523,7 +524,8 @@ func TestGetRandomCompatibility(t *testing.T) {
|
|||
|
||||
b := getSharpTestGenesis(t)
|
||||
tx := getSharpTestTx(util.Uint160{})
|
||||
ic := bc.GetTestVM(trigger.Application, tx, b)
|
||||
ic, err := bc.GetTestVM(trigger.Application, tx, b)
|
||||
require.NoError(t, err)
|
||||
ic.Network = 860833102 // Old mainnet magic used by C# tests.
|
||||
|
||||
ic.VM = vm.New()
|
||||
|
@ -550,7 +552,8 @@ func TestNotify(t *testing.T) {
|
|||
caller := random.Uint160()
|
||||
newIC := func(name string, args interface{}) *interop.Context {
|
||||
_, _, bc, cs := getDeployedInternal(t)
|
||||
ic := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
require.NoError(t, err)
|
||||
ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, callflag.NoneFlag, true, 0, -1, nil)
|
||||
ic.VM.Estack().PushVal(args)
|
||||
ic.VM.Estack().PushVal(name)
|
||||
|
|
|
@ -300,7 +300,8 @@ func TestFind(t *testing.T) {
|
|||
|
||||
func createVM(t testing.TB) (*vm.VM, *interop.Context, *core.Blockchain) {
|
||||
chain, _ := chain.NewSingle(t)
|
||||
ic := chain.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||
ic, err := chain.GetTestVM(trigger.Application, &transaction.Transaction{}, &block.Block{})
|
||||
require.NoError(t, err)
|
||||
v := ic.SpawnVM()
|
||||
return v, ic, chain
|
||||
}
|
||||
|
|
|
@ -74,7 +74,8 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
|
|||
require.NotNil(t, md)
|
||||
|
||||
t.Run("fail, bad current script hash", func(t *testing.T) {
|
||||
ic := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
require.NoError(t, err)
|
||||
v := ic.SpawnVM()
|
||||
fakeH := util.Uint160{1, 2, 3}
|
||||
v.LoadScriptWithHash(clState.NEF.Script, fakeH, callflag.All)
|
||||
|
@ -83,7 +84,7 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
|
|||
v.Context().Jump(md.Offset)
|
||||
|
||||
// Bad current script hash
|
||||
err := v.Run()
|
||||
err = v.Run()
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("native contract %s (version 0) not found", fakeH.StringLE())), err.Error())
|
||||
})
|
||||
|
@ -104,7 +105,8 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
|
|||
})
|
||||
eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
|
||||
|
||||
ic := bcBad.GetTestVM(trigger.Application, nil, nil)
|
||||
ic, err := bcBad.GetTestVM(trigger.Application, nil, nil)
|
||||
require.NoError(t, err)
|
||||
v := ic.SpawnVM()
|
||||
v.LoadScriptWithHash(clState.NEF.Script, clState.Hash, callflag.All) // hash is not affected by native update history
|
||||
input := []byte{1, 2, 3, 4}
|
||||
|
@ -112,13 +114,14 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
|
|||
v.Context().Jump(md.Offset)
|
||||
|
||||
// It's prohibited to call natives before NativeUpdateHistory[0] height.
|
||||
err := v.Run()
|
||||
err = v.Run()
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), "native contract CryptoLib is active after height = 1"))
|
||||
|
||||
// Add new block => CryptoLib should be active now.
|
||||
eBad.AddNewBlock(t)
|
||||
ic = bcBad.GetTestVM(trigger.Application, nil, nil)
|
||||
ic, err = bcBad.GetTestVM(trigger.Application, nil, nil)
|
||||
require.NoError(t, err)
|
||||
v = ic.SpawnVM()
|
||||
v.LoadScriptWithHash(clState.NEF.Script, clState.Hash, callflag.All) // hash is not affected by native update history
|
||||
v.Estack().PushVal(input)
|
||||
|
@ -130,7 +133,8 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("success", func(t *testing.T) {
|
||||
ic := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
require.NoError(t, err)
|
||||
v := ic.SpawnVM()
|
||||
v.LoadScriptWithHash(clState.NEF.Script, clState.Hash, callflag.All)
|
||||
input := []byte{1, 2, 3, 4}
|
||||
|
|
|
@ -374,7 +374,8 @@ func TestInvoke(bc *core.Blockchain, tx *transaction.Transaction) (*vm.VM, error
|
|||
// `GetTestVM` as well as `Run` can use a transaction hash which will set a cached value.
|
||||
// This is unwanted behavior, so we explicitly copy the transaction to perform execution.
|
||||
ttx := *tx
|
||||
ic := bc.GetTestVM(trigger.Application, &ttx, b)
|
||||
ic, _ := bc.GetTestVM(trigger.Application, &ttx, b)
|
||||
|
||||
defer ic.Finalize()
|
||||
|
||||
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||
|
|
|
@ -51,11 +51,14 @@ func (e *Executor) ValidatorInvoker(h util.Uint160) *ContractInvoker {
|
|||
func (c *ContractInvoker) TestInvoke(t testing.TB, method string, args ...interface{}) (*vm.Stack, error) {
|
||||
tx := c.PrepareInvokeNoSign(t, method, args...)
|
||||
b := c.NewUnsignedBlock(t, tx)
|
||||
ic := c.Chain.GetTestVM(trigger.Application, tx, b)
|
||||
ic, err := c.Chain.GetTestVM(trigger.Application, tx, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.Cleanup(ic.Finalize)
|
||||
|
||||
ic.VM.LoadWithFlags(tx.Script, callflag.All)
|
||||
err := ic.VM.Run()
|
||||
err = ic.VM.Run()
|
||||
return ic.VM.Estack(), err
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ type (
|
|||
GetBaseExecFee() int64
|
||||
GetConfig() config.ProtocolConfiguration
|
||||
GetMaxVerificationGAS() int64
|
||||
GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) *interop.Context
|
||||
GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*interop.Context, error)
|
||||
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package oracle
|
|||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
gio "io"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
|
@ -107,7 +108,10 @@ func (o *Oracle) CreateResponseTx(gasForResponse int64, vub uint32, resp *transa
|
|||
size := io.GetVarSize(tx)
|
||||
tx.Scripts = append(tx.Scripts, transaction.Witness{VerificationScript: oracleSignContract})
|
||||
|
||||
gasConsumed, ok := o.testVerify(tx)
|
||||
gasConsumed, ok, err := o.testVerify(tx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to prepare `verify` invocation: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
return nil, errors.New("can't verify transaction")
|
||||
}
|
||||
|
@ -131,18 +135,21 @@ func (o *Oracle) CreateResponseTx(gasForResponse int64, vub uint32, resp *transa
|
|||
return tx, nil
|
||||
}
|
||||
|
||||
func (o *Oracle) testVerify(tx *transaction.Transaction) (int64, bool) {
|
||||
func (o *Oracle) testVerify(tx *transaction.Transaction) (int64, bool, error) {
|
||||
// (*Blockchain).GetTestVM calls Hash() method of the provided transaction; once being called, this
|
||||
// method caches transaction hash, but tx building is not yet completed and hash will be changed.
|
||||
// So, make a copy of the tx to avoid wrong hash caching.
|
||||
cp := *tx
|
||||
ic := o.Chain.GetTestVM(trigger.Verification, &cp, nil)
|
||||
ic, err := o.Chain.GetTestVM(trigger.Verification, &cp, nil)
|
||||
if err != nil {
|
||||
return 0, false, fmt.Errorf("failed to create test VM: %w", err)
|
||||
}
|
||||
ic.VM.GasLimit = o.Chain.GetMaxVerificationGAS()
|
||||
ic.VM.LoadScriptWithHash(o.oracleScript, o.oracleHash, callflag.ReadOnly)
|
||||
ic.VM.Context().Jump(o.verifyOffset)
|
||||
|
||||
ok := isVerifyOk(ic)
|
||||
return ic.VM.GasConsumed(), ok
|
||||
return ic.VM.GasConsumed(), ok, nil
|
||||
}
|
||||
|
||||
func isVerifyOk(ic *interop.Context) bool {
|
||||
|
|
|
@ -1181,7 +1181,8 @@ func TestCreateNEP17TransferTx(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, acc.SignTx(testchain.Network(), tx))
|
||||
require.NoError(t, chain.VerifyTx(tx))
|
||||
ic := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
ic, err := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
require.NoError(t, err)
|
||||
ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||
require.NoError(t, ic.VM.Run())
|
||||
})
|
||||
|
@ -1195,7 +1196,8 @@ func TestCreateNEP17TransferTx(t *testing.T) {
|
|||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, chain.VerifyTx(tx))
|
||||
ic := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
ic, err := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
require.NoError(t, err)
|
||||
ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||
require.NoError(t, ic.VM.Run())
|
||||
require.Equal(t, 2, len(ic.Notifications))
|
||||
|
@ -1228,7 +1230,8 @@ func TestCreateNEP17TransferTx(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, acc.SignTx(testchain.Network(), tx))
|
||||
require.NoError(t, chain.VerifyTx(tx))
|
||||
ic := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
ic, err := chain.GetTestVM(trigger.Application, tx, nil)
|
||||
require.NoError(t, err)
|
||||
ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
|
||||
require.NoError(t, ic.VM.Run())
|
||||
})
|
||||
|
|
|
@ -89,8 +89,8 @@ type (
|
|||
GetNotaryServiceFeePerKey() int64
|
||||
GetStateModule() core.StateRoot
|
||||
GetStorageItem(id int32, key []byte) state.StorageItem
|
||||
GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*interop.Context, error)
|
||||
GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) *interop.Context
|
||||
GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, nextBlockHeight uint32) (*interop.Context, error)
|
||||
GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*interop.Context, error)
|
||||
GetTokenLastUpdated(acc util.Uint160) (map[int32]uint32, error)
|
||||
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
||||
GetValidators() ([]*keys.PublicKey, error)
|
||||
|
@ -1065,11 +1065,10 @@ func (s *Server) invokeReadOnlyMulti(bw *io.BufBinWriter, h util.Uint160, method
|
|||
}
|
||||
script := bw.Bytes()
|
||||
tx := &transaction.Transaction{Script: script}
|
||||
b, err := s.getFakeNextBlock(s.chain.BlockHeight() + 1)
|
||||
ic, err := s.chain.GetTestVM(trigger.Application, tx, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, fmt.Errorf("faile to prepare test VM: %w", err)
|
||||
}
|
||||
ic := s.chain.GetTestVM(trigger.Application, tx, b)
|
||||
ic.VM.GasLimit = core.HeaderVerificationGasLimit
|
||||
ic.VM.LoadScriptWithFlags(script, callflag.All)
|
||||
err = ic.VM.Run()
|
||||
|
@ -1832,7 +1831,7 @@ func (s *Server) invokeFunction(reqParams params.Params) (interface{}, *neorpc.E
|
|||
|
||||
// invokeFunctionHistoric implements the `invokeFunctionHistoric` RPC call.
|
||||
func (s *Server) invokeFunctionHistoric(reqParams params.Params) (interface{}, *neorpc.Error) {
|
||||
b, respErr := s.getHistoricParams(reqParams)
|
||||
nextH, respErr := s.getHistoricParams(reqParams)
|
||||
if respErr != nil {
|
||||
return nil, respErr
|
||||
}
|
||||
|
@ -1843,7 +1842,7 @@ func (s *Server) invokeFunctionHistoric(reqParams params.Params) (interface{}, *
|
|||
if respErr != nil {
|
||||
return nil, respErr
|
||||
}
|
||||
return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, b, verbose)
|
||||
return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, &nextH, verbose)
|
||||
}
|
||||
|
||||
func (s *Server) getInvokeFunctionParams(reqParams params.Params) (*transaction.Transaction, bool, *neorpc.Error) {
|
||||
|
@ -1899,7 +1898,7 @@ func (s *Server) invokescript(reqParams params.Params) (interface{}, *neorpc.Err
|
|||
|
||||
// invokescripthistoric implements the `invokescripthistoric` RPC call.
|
||||
func (s *Server) invokescripthistoric(reqParams params.Params) (interface{}, *neorpc.Error) {
|
||||
b, respErr := s.getHistoricParams(reqParams)
|
||||
nextH, respErr := s.getHistoricParams(reqParams)
|
||||
if respErr != nil {
|
||||
return nil, respErr
|
||||
}
|
||||
|
@ -1910,7 +1909,7 @@ func (s *Server) invokescripthistoric(reqParams params.Params) (interface{}, *ne
|
|||
if respErr != nil {
|
||||
return nil, respErr
|
||||
}
|
||||
return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, b, verbose)
|
||||
return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, &nextH, verbose)
|
||||
}
|
||||
|
||||
func (s *Server) getInvokeScriptParams(reqParams params.Params) (*transaction.Transaction, bool, *neorpc.Error) {
|
||||
|
@ -1953,7 +1952,7 @@ func (s *Server) invokeContractVerify(reqParams params.Params) (interface{}, *ne
|
|||
|
||||
// invokeContractVerifyHistoric implements the `invokecontractverifyhistoric` RPC call.
|
||||
func (s *Server) invokeContractVerifyHistoric(reqParams params.Params) (interface{}, *neorpc.Error) {
|
||||
b, respErr := s.getHistoricParams(reqParams)
|
||||
nextH, respErr := s.getHistoricParams(reqParams)
|
||||
if respErr != nil {
|
||||
return nil, respErr
|
||||
}
|
||||
|
@ -1964,7 +1963,7 @@ func (s *Server) invokeContractVerifyHistoric(reqParams params.Params) (interfac
|
|||
if respErr != nil {
|
||||
return nil, respErr
|
||||
}
|
||||
return s.runScriptInVM(trigger.Verification, invocationScript, scriptHash, tx, b, false)
|
||||
return s.runScriptInVM(trigger.Verification, invocationScript, scriptHash, tx, &nextH, false)
|
||||
}
|
||||
|
||||
func (s *Server) getInvokeContractVerifyParams(reqParams params.Params) (util.Uint160, *transaction.Transaction, []byte, *neorpc.Error) {
|
||||
|
@ -2007,64 +2006,45 @@ func (s *Server) getInvokeContractVerifyParams(reqParams params.Params) (util.Ui
|
|||
// with the specified index to perform the historic call. It also checks that
|
||||
// specified stateroot is stored at the specified height for further request
|
||||
// handling consistency.
|
||||
func (s *Server) getHistoricParams(reqParams params.Params) (*block.Block, *neorpc.Error) {
|
||||
func (s *Server) getHistoricParams(reqParams params.Params) (uint32, *neorpc.Error) {
|
||||
if s.chain.GetConfig().KeepOnlyLatestState {
|
||||
return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState))
|
||||
return 0, neorpc.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState))
|
||||
}
|
||||
if len(reqParams) < 1 {
|
||||
return nil, neorpc.ErrInvalidParams
|
||||
return 0, neorpc.ErrInvalidParams
|
||||
}
|
||||
height, respErr := s.blockHeightFromParam(reqParams.Value(0))
|
||||
if respErr != nil {
|
||||
hash, err := reqParams.Value(0).GetUint256()
|
||||
if err != nil {
|
||||
return nil, neorpc.NewInvalidParamsError(fmt.Sprintf("invalid block hash or index or stateroot hash: %s", err))
|
||||
return 0, neorpc.NewInvalidParamsError(fmt.Sprintf("invalid block hash or index or stateroot hash: %s", err))
|
||||
}
|
||||
b, err := s.chain.GetBlock(hash)
|
||||
if err != nil {
|
||||
stateH, err := s.chain.GetStateModule().GetLatestStateHeight(hash)
|
||||
if err != nil {
|
||||
return nil, neorpc.NewInvalidParamsError(fmt.Sprintf("unknown block or stateroot: %s", err))
|
||||
return 0, neorpc.NewInvalidParamsError(fmt.Sprintf("unknown block or stateroot: %s", err))
|
||||
}
|
||||
height = int(stateH)
|
||||
} else {
|
||||
height = int(b.Index)
|
||||
}
|
||||
}
|
||||
b, err := s.getFakeNextBlock(uint32(height + 1))
|
||||
if err != nil {
|
||||
return nil, neorpc.NewInternalServerError(fmt.Sprintf("can't create fake block for height %d: %s", height+1, err))
|
||||
}
|
||||
return b, nil
|
||||
return uint32(height) + 1, nil
|
||||
}
|
||||
|
||||
func (s *Server) getFakeNextBlock(nextBlockHeight uint32) (*block.Block, error) {
|
||||
// When transferring funds, script execution does no auto GAS claim,
|
||||
// because it depends on persisting tx height.
|
||||
// This is why we provide block here.
|
||||
b := block.New(s.stateRootEnabled)
|
||||
b.Index = nextBlockHeight
|
||||
hdr, err := s.chain.GetHeader(s.chain.GetHeaderHash(int(nextBlockHeight - 1)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.Timestamp = hdr.Timestamp + uint64(s.chain.GetConfig().SecondsPerBlock*int(time.Second/time.Millisecond))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (s *Server) prepareInvocationContext(t trigger.Type, script []byte, contractScriptHash util.Uint160, tx *transaction.Transaction, b *block.Block, verbose bool) (*interop.Context, *neorpc.Error) {
|
||||
func (s *Server) prepareInvocationContext(t trigger.Type, script []byte, contractScriptHash util.Uint160, tx *transaction.Transaction, nextH *uint32, verbose bool) (*interop.Context, *neorpc.Error) {
|
||||
var (
|
||||
err error
|
||||
ic *interop.Context
|
||||
)
|
||||
if b == nil {
|
||||
b, err = s.getFakeNextBlock(s.chain.BlockHeight() + 1)
|
||||
if nextH == nil {
|
||||
ic, err = s.chain.GetTestVM(t, tx, nil)
|
||||
if err != nil {
|
||||
return nil, neorpc.NewInternalServerError(fmt.Sprintf("can't create fake block: %s", err))
|
||||
return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to create test VM: %s", err))
|
||||
}
|
||||
ic = s.chain.GetTestVM(t, tx, b)
|
||||
} else {
|
||||
ic, err = s.chain.GetTestHistoricVM(t, tx, b)
|
||||
ic, err = s.chain.GetTestHistoricVM(t, tx, *nextH)
|
||||
if err != nil {
|
||||
return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to create historic VM: %s", err))
|
||||
}
|
||||
|
@ -2096,8 +2076,8 @@ func (s *Server) prepareInvocationContext(t trigger.Type, script []byte, contrac
|
|||
// witness invocation script in case of `verification` trigger (it pushes `verify`
|
||||
// arguments on stack before verification). In case of contract verification
|
||||
// contractScriptHash should be specified.
|
||||
func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash util.Uint160, tx *transaction.Transaction, b *block.Block, verbose bool) (*result.Invoke, *neorpc.Error) {
|
||||
ic, respErr := s.prepareInvocationContext(t, script, contractScriptHash, tx, b, verbose)
|
||||
func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash util.Uint160, tx *transaction.Transaction, nextH *uint32, verbose bool) (*result.Invoke, *neorpc.Error) {
|
||||
ic, respErr := s.prepareInvocationContext(t, script, contractScriptHash, tx, nextH, verbose)
|
||||
if respErr != nil {
|
||||
return nil, respErr
|
||||
}
|
||||
|
@ -2111,16 +2091,12 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash
|
|||
var id uuid.UUID
|
||||
|
||||
if sess != nil {
|
||||
// b == nil only when we're not using MPT-backed storage, therefore
|
||||
// nextH == nil only when we're not using MPT-backed storage, therefore
|
||||
// the second attempt won't stop here.
|
||||
if s.config.SessionBackedByMPT && b == nil {
|
||||
if s.config.SessionBackedByMPT && nextH == nil {
|
||||
ic.Finalize()
|
||||
b, err = s.getFakeNextBlock(ic.Block.Index)
|
||||
if err != nil {
|
||||
return nil, neorpc.NewInternalServerError(fmt.Sprintf("unable to prepare block for historic call: %s", err))
|
||||
}
|
||||
// Rerun with MPT-backed storage.
|
||||
return s.runScriptInVM(t, script, contractScriptHash, tx, b, verbose)
|
||||
return s.runScriptInVM(t, script, contractScriptHash, tx, &ic.Block.Index, verbose)
|
||||
}
|
||||
id = uuid.New()
|
||||
sessionID := id.String()
|
||||
|
|
Loading…
Reference in a new issue