rpc/core: implement invokescript method, fix #348
Extend Blockchainer with one more method to spawn a VM for test runs and use it to run scripts. Gas consumption is not counted or limited in any way at the moment (see #424).
This commit is contained in:
parent
94776b8a1f
commit
ebc1ba4f38
5 changed files with 54 additions and 0 deletions
|
@ -1111,6 +1111,14 @@ func (bc *Blockchain) spawnVMWithInterops(interopCtx *interopContext) *vm.VM {
|
||||||
return vm
|
return vm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTestVM returns a VM and a Store setup for a test run of some sort of code.
|
||||||
|
func (bc *Blockchain) GetTestVM() (*vm.VM, storage.Store) {
|
||||||
|
tmpStore := storage.NewMemCachedStore(bc.store)
|
||||||
|
systemInterop := newInteropContext(0x10, bc, tmpStore, nil, nil)
|
||||||
|
vm := bc.spawnVMWithInterops(systemInterop)
|
||||||
|
return vm, tmpStore
|
||||||
|
}
|
||||||
|
|
||||||
// verifyHashAgainstScript verifies given hash against the given witness.
|
// verifyHashAgainstScript verifies given hash against the given witness.
|
||||||
func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, checkedHash util.Uint256, interopCtx *interopContext) error {
|
func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, checkedHash util.Uint256, interopCtx *interopContext) error {
|
||||||
verification := witness.VerificationScript
|
verification := witness.VerificationScript
|
||||||
|
|
|
@ -2,8 +2,10 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Blockchainer is an interface that abstract the implementation
|
// Blockchainer is an interface that abstract the implementation
|
||||||
|
@ -27,6 +29,7 @@ type Blockchainer interface {
|
||||||
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
|
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
|
||||||
GetStorageItem(scripthash util.Uint160, key []byte) *StorageItem
|
GetStorageItem(scripthash util.Uint160, key []byte) *StorageItem
|
||||||
GetStorageItems(hash util.Uint160) (map[string]*StorageItem, error)
|
GetStorageItems(hash util.Uint160) (map[string]*StorageItem, error)
|
||||||
|
GetTestVM() (*vm.VM, storage.Store)
|
||||||
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
||||||
GetUnspentCoinState(util.Uint256) *UnspentCoinState
|
GetUnspentCoinState(util.Uint256) *UnspentCoinState
|
||||||
References(t *transaction.Transaction) map[transaction.Input]*transaction.Output
|
References(t *transaction.Transaction) map[transaction.Input]*transaction.Output
|
||||||
|
|
|
@ -9,9 +9,11 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/network/payload"
|
"github.com/CityOfZion/neo-go/pkg/network/payload"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testChain struct {
|
type testChain struct {
|
||||||
|
@ -78,6 +80,9 @@ func (chain testChain) GetScriptHashesForVerifying(*transaction.Transaction) ([]
|
||||||
func (chain testChain) GetStorageItem(scripthash util.Uint160, key []byte) *core.StorageItem {
|
func (chain testChain) GetStorageItem(scripthash util.Uint160, key []byte) *core.StorageItem {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
func (chain testChain) GetTestVM() (*vm.VM, storage.Store) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
func (chain testChain) GetStorageItems(hash util.Uint160) (map[string]*core.StorageItem, error) {
|
func (chain testChain) GetStorageItems(hash util.Uint160) (map[string]*core.StorageItem, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,6 +227,9 @@ Methods:
|
||||||
case "getrawtransaction":
|
case "getrawtransaction":
|
||||||
results, resultsErr = s.getrawtransaction(reqParams)
|
results, resultsErr = s.getrawtransaction(reqParams)
|
||||||
|
|
||||||
|
case "invokescript":
|
||||||
|
results, resultsErr = s.invokescript(reqParams)
|
||||||
|
|
||||||
case "sendrawtransaction":
|
case "sendrawtransaction":
|
||||||
results, resultsErr = s.sendrawtransaction(reqParams)
|
results, resultsErr = s.sendrawtransaction(reqParams)
|
||||||
|
|
||||||
|
@ -280,6 +283,28 @@ func (s *Server) getrawtransaction(reqParams Params) (interface{}, error) {
|
||||||
return results, resultsErr
|
return results, resultsErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// invokescript implements the `invokescript` RPC call.
|
||||||
|
func (s *Server) invokescript(reqParams Params) (interface{}, error) {
|
||||||
|
hexScript, err := reqParams.ValueWithType(0, "string")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
script, err := hex.DecodeString(hexScript.StringVal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
vm, _ := s.chain.GetTestVM()
|
||||||
|
vm.LoadScript(script)
|
||||||
|
_ = vm.Run()
|
||||||
|
result := &wrappers.InvokeResult{
|
||||||
|
State: vm.State(),
|
||||||
|
GasConsumed: "0.1",
|
||||||
|
Script: hexScript.StringVal,
|
||||||
|
Stack: vm.Estack(),
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) sendrawtransaction(reqParams Params) (interface{}, error) {
|
func (s *Server) sendrawtransaction(reqParams Params) (interface{}, error) {
|
||||||
var resultsErr error
|
var resultsErr error
|
||||||
var results interface{}
|
var results interface{}
|
||||||
|
|
13
pkg/rpc/wrappers/invoke_result.go
Normal file
13
pkg/rpc/wrappers/invoke_result.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package wrappers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InvokeResult is used as a wrapper to represent an invokation result.
|
||||||
|
type InvokeResult struct {
|
||||||
|
State string `json:"state"`
|
||||||
|
GasConsumed string `json:"gas_consumed"`
|
||||||
|
Script string `json:"script"`
|
||||||
|
Stack *vm.Stack
|
||||||
|
}
|
Loading…
Reference in a new issue