mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-29 23:33:37 +00:00
Merge pull request #463 from nspcc-dev/smartcontract-fixes
Smartcontract RPC fixes
This commit is contained in:
commit
2f6e678a19
14 changed files with 126 additions and 96 deletions
|
@ -6,18 +6,20 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/rpc"
|
"github.com/CityOfZion/neo-go/pkg/rpc"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm/compiler"
|
"github.com/CityOfZion/neo-go/pkg/vm/compiler"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
errNoEndpoint = errors.New("no RPC endpoint specified, use option '--endpoint' or '-e'")
|
||||||
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
|
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
|
||||||
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
||||||
errFileExist = errors.New("A file with given smart-contract name already exists")
|
errFileExist = errors.New("A file with given smart-contract name already exists")
|
||||||
|
@ -65,6 +67,10 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "Test an invocation of a smart contract on the blockchain",
|
Usage: "Test an invocation of a smart contract on the blockchain",
|
||||||
Action: testInvoke,
|
Action: testInvoke,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "endpoint, e",
|
||||||
|
Usage: "RPC endpoint address (like 'http://seed4.ngd.network:20332')",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in, i",
|
||||||
Usage: "Input location of the avm file that needs to be invoked",
|
Usage: "Input location of the avm file that needs to be invoked",
|
||||||
|
@ -91,6 +97,10 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "creates a user readable dump of the program instructions",
|
Usage: "creates a user readable dump of the program instructions",
|
||||||
Action: inspect,
|
Action: inspect,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "compile, c",
|
||||||
|
Usage: "compile input file (it should be go code then)",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "in, i",
|
Name: "in, i",
|
||||||
Usage: "input file of the program",
|
Usage: "input file of the program",
|
||||||
|
@ -163,16 +173,16 @@ func testInvoke(ctx *cli.Context) error {
|
||||||
if len(src) == 0 {
|
if len(src) == 0 {
|
||||||
return cli.NewExitError(errNoInput, 1)
|
return cli.NewExitError(errNoInput, 1)
|
||||||
}
|
}
|
||||||
|
endpoint := ctx.String("endpoint")
|
||||||
|
if len(endpoint) == 0 {
|
||||||
|
return cli.NewExitError(errNoEndpoint, 1)
|
||||||
|
}
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(src)
|
b, err := ioutil.ReadFile(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now we will hardcode the endpoint.
|
|
||||||
// On the long term the internal VM will run the script.
|
|
||||||
// TODO: remove RPC dependency, hardcoded node.
|
|
||||||
endpoint := "http://node1.ams2.bridgeprotocol.io:10332"
|
|
||||||
client, err := rpc.NewClient(context.TODO(), endpoint, rpc.ClientOptions{})
|
client, err := rpc.NewClient(context.TODO(), endpoint, rpc.ClientOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
|
@ -251,12 +261,24 @@ func parseContractDetails() ContractDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
func inspect(ctx *cli.Context) error {
|
func inspect(ctx *cli.Context) error {
|
||||||
src := ctx.String("in")
|
in := ctx.String("in")
|
||||||
if len(src) == 0 {
|
compile := ctx.Bool("compile")
|
||||||
|
if len(in) == 0 {
|
||||||
return cli.NewExitError(errNoInput, 1)
|
return cli.NewExitError(errNoInput, 1)
|
||||||
}
|
}
|
||||||
if err := compiler.CompileAndInspect(src); err != nil {
|
b, err := ioutil.ReadFile(in)
|
||||||
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
if compile {
|
||||||
|
b, err = compiler.Compile(bytes.NewReader(b))
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(errors.Wrap(err, "failed to compile"), 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v := vm.New()
|
||||||
|
v.LoadScript(b)
|
||||||
|
v.PrintOps()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
32
cli/vm/vm.go
32
cli/vm/vm.go
|
@ -1,10 +1,6 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm"
|
|
||||||
vmcli "github.com/CityOfZion/neo-go/pkg/vm/cli"
|
vmcli "github.com/CityOfZion/neo-go/pkg/vm/cli"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
@ -18,19 +14,6 @@ func NewCommands() []cli.Command {
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{Name: "debug, d"},
|
cli.BoolFlag{Name: "debug, d"},
|
||||||
},
|
},
|
||||||
Subcommands: []cli.Command{
|
|
||||||
{
|
|
||||||
Name: "inspect",
|
|
||||||
Usage: "dump instructions of the avm file given",
|
|
||||||
Action: inspect,
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "in, i",
|
|
||||||
Usage: "input file of the program (AVM)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,18 +21,3 @@ func startVMPrompt(ctx *cli.Context) error {
|
||||||
p := vmcli.New()
|
p := vmcli.New()
|
||||||
return p.Run()
|
return p.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func inspect(ctx *cli.Context) error {
|
|
||||||
avm := ctx.String("in")
|
|
||||||
if len(avm) == 0 {
|
|
||||||
return cli.NewExitError(errors.New("no input file given"), 1)
|
|
||||||
}
|
|
||||||
b, err := ioutil.ReadFile(avm)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
v := vm.New()
|
|
||||||
v.LoadScript(b)
|
|
||||||
v.PrintOps()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -432,19 +432,9 @@ func (bc *Blockchain) storeBlock(block *Block) error {
|
||||||
contracts[contract.ScriptHash()] = contract
|
contracts[contract.ScriptHash()] = contract
|
||||||
|
|
||||||
case *transaction.InvocationTX:
|
case *transaction.InvocationTX:
|
||||||
vm := vm.New()
|
|
||||||
vm.SetCheckedHash(tx.VerificationHash().Bytes())
|
|
||||||
vm.SetScriptGetter(func(hash util.Uint160) []byte {
|
|
||||||
cs := bc.GetContractState(hash)
|
|
||||||
if cs == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return cs.Script
|
|
||||||
})
|
|
||||||
systemInterop := newInteropContext(0x10, bc, tmpStore, block, tx)
|
systemInterop := newInteropContext(0x10, bc, tmpStore, block, tx)
|
||||||
vm.RegisterInteropFuncs(systemInterop.getSystemInteropMap())
|
vm := bc.spawnVMWithInterops(systemInterop)
|
||||||
vm.RegisterInteropFuncs(systemInterop.getNeoInteropMap())
|
vm.SetCheckedHash(tx.VerificationHash().Bytes())
|
||||||
vm.LoadScript(t.Script)
|
vm.LoadScript(t.Script)
|
||||||
err := vm.Run()
|
err := vm.Run()
|
||||||
if !vm.HasFailed() {
|
if !vm.HasFailed() {
|
||||||
|
@ -1110,6 +1100,30 @@ func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// spawnVMWithInterops returns a VM with script getter and interop functions set
|
||||||
|
// up for current blockchain.
|
||||||
|
func (bc *Blockchain) spawnVMWithInterops(interopCtx *interopContext) *vm.VM {
|
||||||
|
vm := vm.New()
|
||||||
|
vm.SetScriptGetter(func(hash util.Uint160) []byte {
|
||||||
|
cs := bc.GetContractState(hash)
|
||||||
|
if cs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return cs.Script
|
||||||
|
})
|
||||||
|
vm.RegisterInteropFuncs(interopCtx.getSystemInteropMap())
|
||||||
|
vm.RegisterInteropFuncs(interopCtx.getNeoInteropMap())
|
||||||
|
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
|
||||||
|
@ -1127,17 +1141,8 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vm := vm.New()
|
vm := bc.spawnVMWithInterops(interopCtx)
|
||||||
vm.SetCheckedHash(checkedHash.Bytes())
|
vm.SetCheckedHash(checkedHash.Bytes())
|
||||||
vm.SetScriptGetter(func(hash util.Uint160) []byte {
|
|
||||||
cs := bc.GetContractState(hash)
|
|
||||||
if cs == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return cs.Script
|
|
||||||
})
|
|
||||||
vm.RegisterInteropFuncs(interopCtx.getSystemInteropMap())
|
|
||||||
vm.RegisterInteropFuncs(interopCtx.getNeoInteropMap())
|
|
||||||
vm.LoadScript(verification)
|
vm.LoadScript(verification)
|
||||||
vm.LoadScript(witness.InvocationScript)
|
vm.LoadScript(witness.InvocationScript)
|
||||||
err := vm.Run()
|
err := vm.Run()
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,10 +192,6 @@ Methods:
|
||||||
|
|
||||||
results = peers
|
results = peers
|
||||||
|
|
||||||
case "getblocksysfee", "getcontractstate", "getrawmempool", "getstorage", "submitblock", "gettxout", "invoke", "invokefunction", "invokescript":
|
|
||||||
|
|
||||||
results = "TODO"
|
|
||||||
|
|
||||||
case "validateaddress":
|
case "validateaddress":
|
||||||
validateaddressCalled.Inc()
|
validateaddressCalled.Inc()
|
||||||
param, err := reqParams.Value(0)
|
param, err := reqParams.Value(0)
|
||||||
|
@ -242,6 +238,9 @@ Methods:
|
||||||
getrawtransactionCalled.Inc()
|
getrawtransactionCalled.Inc()
|
||||||
results, resultsErr = s.getrawtransaction(reqParams)
|
results, resultsErr = s.getrawtransaction(reqParams)
|
||||||
|
|
||||||
|
case "invokescript":
|
||||||
|
results, resultsErr = s.invokescript(reqParams)
|
||||||
|
|
||||||
case "sendrawtransaction":
|
case "sendrawtransaction":
|
||||||
sendrawtransactionCalled.Inc()
|
sendrawtransactionCalled.Inc()
|
||||||
results, resultsErr = s.sendrawtransaction(reqParams)
|
results, resultsErr = s.sendrawtransaction(reqParams)
|
||||||
|
@ -296,6 +295,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
|
||||||
|
}
|
|
@ -259,7 +259,7 @@ func handleLoadGo(c *ishell.Context) {
|
||||||
c.Err(err)
|
c.Err(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b, err := compiler.Compile(bytes.NewReader(fb), &compiler.Options{})
|
b, err := compiler.Compile(bytes.NewReader(fb))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Err(err)
|
c.Err(err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -14,7 +14,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm"
|
|
||||||
"golang.org/x/tools/go/loader"
|
"golang.org/x/tools/go/loader"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ type buildInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile compiles a Go program into bytecode that can run on the NEO virtual machine.
|
// Compile compiles a Go program into bytecode that can run on the NEO virtual machine.
|
||||||
func Compile(r io.Reader, o *Options) ([]byte, error) {
|
func Compile(r io.Reader) ([]byte, error) {
|
||||||
conf := loader.Config{ParserMode: parser.ParseComments}
|
conf := loader.Config{ParserMode: parser.ParseComments}
|
||||||
f, err := conf.ParseFile("", r)
|
f, err := conf.ParseFile("", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -85,7 +84,7 @@ func CompileAndSave(src string, o *Options) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
b, err = Compile(bytes.NewReader(b), o)
|
b, err = Compile(bytes.NewReader(b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while trying to compile smart contract file: %v", err)
|
return fmt.Errorf("error while trying to compile smart contract file: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -96,23 +95,6 @@ func CompileAndSave(src string, o *Options) error {
|
||||||
return ioutil.WriteFile(out, b, os.ModePerm)
|
return ioutil.WriteFile(out, b, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompileAndInspect compiles the program and dumps the opcode in a user friendly format.
|
|
||||||
func CompileAndInspect(src string) error {
|
|
||||||
b, err := ioutil.ReadFile(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
b, err = Compile(bytes.NewReader(b), &Options{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
v := vm.New()
|
|
||||||
v.LoadScript(b)
|
|
||||||
v.PrintOps()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func gopath() string {
|
func gopath() string {
|
||||||
gopath := os.Getenv("GOPATH")
|
gopath := os.Getenv("GOPATH")
|
||||||
if len(gopath) == 0 {
|
if len(gopath) == 0 {
|
||||||
|
|
|
@ -44,14 +44,10 @@ func filterFilename(infos []os.FileInfo) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileFile(src string) error {
|
func compileFile(src string) error {
|
||||||
o := compiler.Options{
|
|
||||||
Outfile: "tmp/contract.avm",
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Open(src)
|
file, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = compiler.Compile(file, &o)
|
_, err = compiler.Compile(file)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ type stackItem struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildStackOutput(s *Stack) string {
|
func stackToArray(s *Stack) []stackItem {
|
||||||
items := make([]stackItem, 0, s.Len())
|
items := make([]stackItem, 0, s.Len())
|
||||||
s.Iter(func(e *Element) {
|
s.Iter(func(e *Element) {
|
||||||
items = append(items, stackItem{
|
items = append(items, stackItem{
|
||||||
|
@ -17,7 +17,10 @@ func buildStackOutput(s *Stack) string {
|
||||||
Type: e.value.String(),
|
Type: e.value.String(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
b, _ := json.MarshalIndent(items, "", " ")
|
func buildStackOutput(s *Stack) string {
|
||||||
|
b, _ := json.MarshalIndent(stackToArray(s), "", " ")
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
@ -334,3 +335,8 @@ func (s *Stack) popSigElements() ([][]byte, error) {
|
||||||
}
|
}
|
||||||
return elems, nil
|
return elems, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements JSON marshalling interface.
|
||||||
|
func (s *Stack) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(stackToArray(s))
|
||||||
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func vmAndCompile(t *testing.T, src string) *vm.VM {
|
||||||
vm.RegisterInteropFunc("Neo.Storage.Put", storePlugin.Put, 1)
|
vm.RegisterInteropFunc("Neo.Storage.Put", storePlugin.Put, 1)
|
||||||
vm.RegisterInteropFunc("Neo.Storage.GetContext", storePlugin.GetContext, 1)
|
vm.RegisterInteropFunc("Neo.Storage.GetContext", storePlugin.GetContext, 1)
|
||||||
|
|
||||||
b, err := compiler.Compile(strings.NewReader(src), &compiler.Options{})
|
b, err := compiler.Compile(strings.NewReader(src))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,10 +199,11 @@ func (v *VM) LoadFile(path string) error {
|
||||||
|
|
||||||
// Load initializes the VM with the program given.
|
// Load initializes the VM with the program given.
|
||||||
func (v *VM) Load(prog []byte) {
|
func (v *VM) Load(prog []byte) {
|
||||||
// clear all stacks, it could be a reload.
|
// Clear all stacks and state, it could be a reload.
|
||||||
v.istack.Clear()
|
v.istack.Clear()
|
||||||
v.estack.Clear()
|
v.estack.Clear()
|
||||||
v.astack.Clear()
|
v.astack.Clear()
|
||||||
|
v.state = noneState
|
||||||
v.LoadScript(prog)
|
v.LoadScript(prog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +251,11 @@ func (v *VM) Stack(n string) string {
|
||||||
return buildStackOutput(s)
|
return buildStackOutput(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State returns string representation of the state for the VM.
|
||||||
|
func (v *VM) State() string {
|
||||||
|
return v.state.String()
|
||||||
|
}
|
||||||
|
|
||||||
// Ready returns true if the VM ready to execute the loaded program.
|
// Ready returns true if the VM ready to execute the loaded program.
|
||||||
// Will return false if no program is loaded.
|
// Will return false if no program is loaded.
|
||||||
func (v *VM) Ready() bool {
|
func (v *VM) Ready() bool {
|
||||||
|
|
Loading…
Reference in a new issue