b2a5e34aac
* Started RPC package to allow querying balances and sending raw transactions for sc's * integrate invoke cmd in cli * bumped version * added sendrawtransaction to the rpc client.
128 lines
2.7 KiB
Go
128 lines
2.7 KiB
Go
package smartcontract
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
|
|
"github.com/CityOfZion/neo-go/pkg/rpc"
|
|
"github.com/CityOfZion/neo-go/pkg/vm/compiler"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
const (
|
|
errNoInput = "Input file is mandatory and should be passed using -i flag."
|
|
)
|
|
|
|
// NewCommand returns a new contract command.
|
|
func NewCommand() cli.Command {
|
|
return cli.Command{
|
|
Name: "contract",
|
|
Usage: "compile - debug - deploy smart contracts",
|
|
Subcommands: []cli.Command{
|
|
{
|
|
Name: "compile",
|
|
Usage: "compile a smart contract to a .avm file",
|
|
Action: contractCompile,
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "in, i",
|
|
Usage: "Input file for the smart contract to be compiled",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "out, o",
|
|
Usage: "Output of the compiled contract",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "invoke",
|
|
Usage: "Test an invocation of a smart contract on the blockchain",
|
|
Action: testInvoke,
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "in, i",
|
|
Usage: "Input location of the avm file that needs to be invoked",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "opdump",
|
|
Usage: "dump the opcode of a .go file",
|
|
Action: contractDumpOpcode,
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "in, i",
|
|
Usage: "Input file for the smart contract",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func contractCompile(ctx *cli.Context) error {
|
|
src := ctx.String("in")
|
|
if len(src) == 0 {
|
|
return cli.NewExitError(errNoInput, 1)
|
|
}
|
|
|
|
o := &compiler.Options{
|
|
Outfile: ctx.String("out"),
|
|
Debug: true,
|
|
}
|
|
|
|
if err := compiler.CompileAndSave(src, o); err != nil {
|
|
return cli.NewExitError(err, 1)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func testInvoke(ctx *cli.Context) error {
|
|
src := ctx.String("in")
|
|
if len(src) == 0 {
|
|
return cli.NewExitError(errNoInput, 1)
|
|
}
|
|
b, err := ioutil.ReadFile(src)
|
|
if err != nil {
|
|
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://seed5.bridgeprotocol.io:10332"
|
|
opts := rpc.ClientOptions{}
|
|
client, err := rpc.NewClient(context.TODO(), endpoint, opts)
|
|
if err != nil {
|
|
return cli.NewExitError(err, 1)
|
|
}
|
|
|
|
scriptHex := hex.EncodeToString(b)
|
|
resp, err := client.InvokeScript(scriptHex)
|
|
if err != nil {
|
|
return cli.NewExitError(err, 1)
|
|
}
|
|
|
|
b, err = json.MarshalIndent(resp.Result, "", " ")
|
|
if err != nil {
|
|
return cli.NewExitError(err, 1)
|
|
}
|
|
|
|
fmt.Println(string(b))
|
|
|
|
return nil
|
|
}
|
|
|
|
func contractDumpOpcode(ctx *cli.Context) error {
|
|
src := ctx.String("in")
|
|
if len(src) == 0 {
|
|
return cli.NewExitError(errNoInput, 1)
|
|
}
|
|
if err := compiler.DumpOpcode(src); err != nil {
|
|
return cli.NewExitError(err, 1)
|
|
}
|
|
return nil
|
|
}
|