diff --git a/README.md b/README.md index dbdd0273458..cc5931de8ef 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,14 @@ You can discover additional details about current tools and Gno documentation on our [official documentation](https://docs.gno.land). Additionally, the [awesome-gno](https://github.com/gnolang/awesome-gno) repository offers more resources to dig into. We are eager to see your first PR! +## Gno Playground + + play.gno.land + +

+ +[Gno Playground](https://play.gno.land), available at [play.gno.land](https://play.gno.land), is a web app that allows users to write, share, and deploy Gno code. Developers can seamlessly test, debug, and deploy realms and packages on Gno.land, while being able to collaborate with peers to work on projects together and seek assistance. A key feature of Gno Playground is the ability to get started without the need to install any tools or manage any services, offering immediate access and convenience for users. + ## Repository structure * [examples](./examples) - Smart-contract examples and guides for new Gno developers. diff --git a/contribs/gnokeykc/go.mod b/contribs/gnokeykc/go.mod index d788410bfa7..b4838e353f0 100644 --- a/contribs/gnokeykc/go.mod +++ b/contribs/gnokeykc/go.mod @@ -15,9 +15,7 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect - github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/danieljoos/wincred v1.2.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/dgraph-io/badger/v3 v3.2103.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect @@ -43,13 +41,10 @@ require ( github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect go.etcd.io/bbolt v1.3.8 // indirect go.opencensus.io v0.22.5 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.18.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sys v0.16.0 // indirect golang.org/x/term v0.16.0 // indirect - golang.org/x/tools v0.13.0 // indirect google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/contribs/gnokeykc/go.sum b/contribs/gnokeykc/go.sum index 40652b5b087..abbb33ac576 100644 --- a/contribs/gnokeykc/go.sum +++ b/contribs/gnokeykc/go.sum @@ -35,8 +35,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= -github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -123,7 +121,6 @@ github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/linxGnu/grocksdb v1.8.5 h1:Okfk5B1h0ikCYdDM7Tc5yJUS8LTwAmMBq5IPWTmOLPs= @@ -167,7 +164,6 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -184,10 +180,6 @@ go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= -go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -253,8 +245,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/gno.land/cmd/gnokey/main.go b/gno.land/cmd/gnokey/main.go index 1dd61f22793..a64358ad5d8 100644 --- a/gno.land/cmd/gnokey/main.go +++ b/gno.land/cmd/gnokey/main.go @@ -4,6 +4,7 @@ import ( "context" "os" + "github.com/gnolang/gno/gno.land/pkg/keyscli" "github.com/gnolang/gno/gnovm/pkg/gnoenv" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" @@ -15,6 +16,6 @@ func main() { Remote: "127.0.0.1:26657", } - cmd := client.NewRootCmdWithBaseConfig(commands.NewDefaultIO(), baseCfg) + cmd := keyscli.NewRootCmd(commands.NewDefaultIO(), baseCfg) cmd.Execute(context.Background(), os.Args[1:]) } diff --git a/gno.land/pkg/integration/testing_integration.go b/gno.land/pkg/integration/testing_integration.go index a56a0948c31..8974ea75637 100644 --- a/gno.land/pkg/integration/testing_integration.go +++ b/gno.land/pkg/integration/testing_integration.go @@ -12,6 +12,7 @@ import ( "testing" "github.com/gnolang/gno/gno.land/pkg/gnoland" + "github.com/gnolang/gno/gno.land/pkg/keyscli" "github.com/gnolang/gno/gnovm/pkg/gnoenv" "github.com/gnolang/gno/tm2/pkg/bft/node" "github.com/gnolang/gno/tm2/pkg/commands" @@ -214,7 +215,7 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params { io := commands.NewTestIO() io.SetOut(commands.WriteNopCloser(ts.Stdout())) io.SetErr(commands.WriteNopCloser(ts.Stderr())) - cmd := client.NewRootCmd(io) + cmd := keyscli.NewRootCmd(io, client.DefaultBaseOptions) io.SetIn(strings.NewReader("\n")) // Inject empty password to stdin. defaultArgs := []string{ diff --git a/gno.land/pkg/keyscli/README.md b/gno.land/pkg/keyscli/README.md new file mode 100644 index 00000000000..a6d27fa4d40 --- /dev/null +++ b/gno.land/pkg/keyscli/README.md @@ -0,0 +1,12 @@ +## keycli + +`keycli` is an extension of `tm2/keys/client`, enhancing its functionality. It provides the following features: + +- **addpkg**: Allows you to upload a new package to the blockchain. +- **run**: Execute Gno code by invoking the main() function from the target package. +- **call**: Executes a single function call within a Realm. +- **maketx**: Compose a transaction (tx) document to sign (and possibly broadcast). + +--- + +Most of these features have been extracted from `tm2/keys/client` to ensure that `tm2` remains completely independent of `gnovm` and `gno.land`. For more detailed information regarding this change, please refer to [PR#1483](https://github.com/gnolang/gno/pull/1483) diff --git a/gno.land/pkg/keyscli/addpkg.go b/gno.land/pkg/keyscli/addpkg.go new file mode 100644 index 00000000000..1882f6de3d0 --- /dev/null +++ b/gno.land/pkg/keyscli/addpkg.go @@ -0,0 +1,138 @@ +package keyscli + +import ( + "context" + "flag" + "fmt" + + "github.com/gnolang/gno/gno.land/pkg/sdk/vm" + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/tm2/pkg/amino" + "github.com/gnolang/gno/tm2/pkg/commands" + "github.com/gnolang/gno/tm2/pkg/crypto/keys" + "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" + "github.com/gnolang/gno/tm2/pkg/errors" + "github.com/gnolang/gno/tm2/pkg/std" +) + +type MakeAddPkgCfg struct { + RootCfg *client.MakeTxCfg + + PkgPath string + PkgDir string + Deposit string +} + +func NewMakeAddPkgCmd(rootCfg *client.MakeTxCfg, io commands.IO) *commands.Command { + cfg := &MakeAddPkgCfg{ + RootCfg: rootCfg, + } + + return commands.NewCommand( + commands.Metadata{ + Name: "addpkg", + ShortUsage: "addpkg [flags] ", + ShortHelp: "Uploads a new package", + }, + cfg, + func(_ context.Context, args []string) error { + return execMakeAddPkg(cfg, args, io) + }, + ) +} + +func (c *MakeAddPkgCfg) RegisterFlags(fs *flag.FlagSet) { + fs.StringVar( + &c.PkgPath, + "pkgpath", + "", + "package path (required)", + ) + + fs.StringVar( + &c.PkgDir, + "pkgdir", + "", + "path to package files (required)", + ) + + fs.StringVar( + &c.Deposit, + "deposit", + "", + "deposit coins", + ) +} + +func execMakeAddPkg(cfg *MakeAddPkgCfg, args []string, io commands.IO) error { + if cfg.PkgPath == "" { + return errors.New("pkgpath not specified") + } + if cfg.PkgDir == "" { + return errors.New("pkgdir not specified") + } + + if len(args) != 1 { + return flag.ErrHelp + } + + // read account pubkey. + nameOrBech32 := args[0] + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.RootCfg.Home) + if err != nil { + return err + } + info, err := kb.GetByNameOrAddress(nameOrBech32) + if err != nil { + return err + } + creator := info.GetAddress() + // info.GetPubKey() + + // parse deposit. + deposit, err := std.ParseCoins(cfg.Deposit) + if err != nil { + panic(err) + } + + // open files in directory as MemPackage. + memPkg := gno.ReadMemPackage(cfg.PkgDir, cfg.PkgPath) + if memPkg.IsEmpty() { + panic(fmt.Sprintf("found an empty package %q", cfg.PkgPath)) + } + + // precompile and validate syntax + err = gno.PrecompileAndCheckMempkg(memPkg) + if err != nil { + panic(err) + } + + // parse gas wanted & fee. + gaswanted := cfg.RootCfg.GasWanted + gasfee, err := std.ParseCoin(cfg.RootCfg.GasFee) + if err != nil { + panic(err) + } + // construct msg & tx and marshal. + msg := vm.MsgAddPackage{ + Creator: creator, + Package: memPkg, + Deposit: deposit, + } + tx := std.Tx{ + Msgs: []std.Msg{msg}, + Fee: std.NewFee(gaswanted, gasfee), + Signatures: nil, + Memo: cfg.RootCfg.Memo, + } + + if cfg.RootCfg.Broadcast { + err := client.ExecSignAndBroadcast(cfg.RootCfg, args, tx, io) + if err != nil { + return err + } + } else { + fmt.Println(string(amino.MustMarshalJSON(tx))) + } + return nil +} diff --git a/tm2/pkg/crypto/keys/client/call.go b/gno.land/pkg/keyscli/call.go similarity index 63% rename from tm2/pkg/crypto/keys/client/call.go rename to gno.land/pkg/keyscli/call.go index 6f9c9d52f5f..5afbdf457b8 100644 --- a/tm2/pkg/crypto/keys/client/call.go +++ b/gno.land/pkg/keyscli/call.go @@ -1,4 +1,4 @@ -package client +package keyscli import ( "context" @@ -9,22 +9,23 @@ import ( "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/crypto/keys" + "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/std" ) -type callCfg struct { - rootCfg *makeTxCfg +type MakeCallCfg struct { + RootCfg *client.MakeTxCfg - send string - pkgPath string - funcName string - args commands.StringArr + Send string + PkgPath string + FuncName string + Args commands.StringArr } -func newCallCmd(rootCfg *makeTxCfg, io commands.IO) *commands.Command { - cfg := &callCfg{ - rootCfg: rootCfg, +func NewMakeCallCmd(rootCfg *client.MakeTxCfg, io commands.IO) *commands.Command { + cfg := &MakeCallCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -35,63 +36,63 @@ func newCallCmd(rootCfg *makeTxCfg, io commands.IO) *commands.Command { }, cfg, func(_ context.Context, args []string) error { - return execCall(cfg, args, io) + return execMakeCall(cfg, args, io) }, ) } -func (c *callCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *MakeCallCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( - &c.send, + &c.Send, "send", "", "send amount", ) fs.StringVar( - &c.pkgPath, + &c.PkgPath, "pkgpath", "", "package path (required)", ) fs.StringVar( - &c.funcName, + &c.FuncName, "func", "", "contract to call (required)", ) fs.Var( - &c.args, + &c.Args, "args", "arguments to contract", ) } -func execCall(cfg *callCfg, args []string, io commands.IO) error { - if cfg.pkgPath == "" { +func execMakeCall(cfg *MakeCallCfg, args []string, io commands.IO) error { + if cfg.PkgPath == "" { return errors.New("pkgpath not specified") } - if cfg.funcName == "" { + if cfg.FuncName == "" { return errors.New("func not specified") } if len(args) != 1 { return flag.ErrHelp } - if cfg.rootCfg.gasWanted == 0 { + if cfg.RootCfg.GasWanted == 0 { return errors.New("gas-wanted not specified") } - if cfg.rootCfg.gasFee == "" { + if cfg.RootCfg.GasFee == "" { return errors.New("gas-fee not specified") } // read statement. - fnc := cfg.funcName + fnc := cfg.FuncName // read account pubkey. nameOrBech32 := args[0] - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.rootCfg.Home) + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.RootCfg.Home) if err != nil { return err } @@ -103,14 +104,14 @@ func execCall(cfg *callCfg, args []string, io commands.IO) error { // info.GetPubKey() // Parse send amount. - send, err := std.ParseCoins(cfg.send) + send, err := std.ParseCoins(cfg.Send) if err != nil { return errors.Wrap(err, "parsing send coins") } // parse gas wanted & fee. - gaswanted := cfg.rootCfg.gasWanted - gasfee, err := std.ParseCoin(cfg.rootCfg.gasFee) + gaswanted := cfg.RootCfg.GasWanted + gasfee, err := std.ParseCoin(cfg.RootCfg.GasFee) if err != nil { return errors.Wrap(err, "parsing gas fee coin") } @@ -119,19 +120,19 @@ func execCall(cfg *callCfg, args []string, io commands.IO) error { msg := vm.MsgCall{ Caller: caller, Send: send, - PkgPath: cfg.pkgPath, + PkgPath: cfg.PkgPath, Func: fnc, - Args: cfg.args, + Args: cfg.Args, } tx := std.Tx{ Msgs: []std.Msg{msg}, Fee: std.NewFee(gaswanted, gasfee), Signatures: nil, - Memo: cfg.rootCfg.memo, + Memo: cfg.RootCfg.Memo, } - if cfg.rootCfg.broadcast { - err := signAndBroadcast(cfg.rootCfg, args, tx, io) + if cfg.RootCfg.Broadcast { + err := client.ExecSignAndBroadcast(cfg.RootCfg, args, tx, io) if err != nil { return err } diff --git a/gno.land/pkg/keyscli/maketx.go b/gno.land/pkg/keyscli/maketx.go new file mode 100644 index 00000000000..3aa54546863 --- /dev/null +++ b/gno.land/pkg/keyscli/maketx.go @@ -0,0 +1,83 @@ +package keyscli + +import ( + "flag" + + "github.com/gnolang/gno/tm2/pkg/commands" + "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" +) + +type MakeTxCfg struct { + RootCfg *client.BaseCfg + + GasWanted int64 + GasFee string + Memo string + + Broadcast bool + ChainID string +} + +func NewMakeTxCmd(rootCfg *client.BaseCfg, io commands.IO) *commands.Command { + cfg := &client.MakeTxCfg{ + RootCfg: rootCfg, + } + + cmd := commands.NewCommand( + commands.Metadata{ + Name: "maketx", + ShortUsage: " [flags] [...]", + ShortHelp: "Composes a tx document to sign", + }, + cfg, + commands.HelpExec, + ) + + cmd.AddSubCommands( + client.NewMakeSendCmd(cfg, io), + + // custom commands + NewMakeAddPkgCmd(cfg, io), + NewMakeCallCmd(cfg, io), + NewMakeRunCmd(cfg, io), + ) + + return cmd +} + +func (c *MakeTxCfg) RegisterFlags(fs *flag.FlagSet) { + fs.Int64Var( + &c.GasWanted, + "gas-wanted", + 0, + "gas requested for tx", + ) + + fs.StringVar( + &c.GasFee, + "gas-fee", + "", + "gas payment fee", + ) + + fs.StringVar( + &c.Memo, + "memo", + "", + "any descriptive text", + ) + + fs.BoolVar( + &c.Broadcast, + "broadcast", + false, + "sign and broadcast", + ) + + fs.StringVar( + &c.ChainID, + "chainid", + "dev", + "chainid to sign for (only useful if --broadcast)", + ) +} diff --git a/gno.land/pkg/keyscli/root.go b/gno.land/pkg/keyscli/root.go new file mode 100644 index 00000000000..dc5a4f1f9af --- /dev/null +++ b/gno.land/pkg/keyscli/root.go @@ -0,0 +1,47 @@ +// Dedicated to my love, Lexi. +package keyscli + +import ( + "github.com/gnolang/gno/tm2/pkg/commands" + "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" + + "github.com/peterbourgon/ff/v3" + "github.com/peterbourgon/ff/v3/fftoml" +) + +func NewRootCmd(io commands.IO, base client.BaseOptions) *commands.Command { + cfg := &client.BaseCfg{ + BaseOptions: base, + } + + cmd := commands.NewCommand( + commands.Metadata{ + ShortUsage: " [flags] [...]", + LongHelp: "Manages private keys for the node", + Options: []ff.Option{ + ff.WithConfigFileFlag("config"), + ff.WithConfigFileParser(fftoml.Parser), + }, + }, + cfg, + commands.HelpExec, + ) + + cmd.AddSubCommands( + client.NewAddCmd(cfg, io), + client.NewDeleteCmd(cfg, io), + client.NewGenerateCmd(cfg, io), + client.NewExportCmd(cfg, io), + client.NewImportCmd(cfg, io), + client.NewListCmd(cfg, io), + client.NewSignCmd(cfg, io), + client.NewVerifyCmd(cfg, io), + client.NewQueryCmd(cfg, io), + client.NewBroadcastCmd(cfg, io), + + // Custom MakeTX command + NewMakeTxCmd(cfg, io), + ) + + return cmd +} diff --git a/tm2/pkg/crypto/keys/client/run.go b/gno.land/pkg/keyscli/run.go similarity index 75% rename from tm2/pkg/crypto/keys/client/run.go rename to gno.land/pkg/keyscli/run.go index 1ae702c990e..e04452dde09 100644 --- a/tm2/pkg/crypto/keys/client/run.go +++ b/gno.land/pkg/keyscli/run.go @@ -1,10 +1,10 @@ -package client +package keyscli import ( "context" "flag" "fmt" - "io/ioutil" + "io" "os" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" @@ -12,17 +12,18 @@ import ( "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/crypto/keys" + "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/std" ) -type runCfg struct { - rootCfg *makeTxCfg +type MakeRunCfg struct { + RootCfg *client.MakeTxCfg } -func newRunCmd(rootCfg *makeTxCfg, io commands.IO) *commands.Command { - cfg := &runCfg{ - rootCfg: rootCfg, +func NewMakeRunCmd(rootCfg *client.MakeTxCfg, cmdio commands.IO) *commands.Command { + cfg := &MakeRunCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -33,21 +34,21 @@ func newRunCmd(rootCfg *makeTxCfg, io commands.IO) *commands.Command { }, cfg, func(_ context.Context, args []string) error { - return runRun(cfg, args, io) + return execMakeRun(cfg, args, cmdio) }, ) } -func (c *runCfg) RegisterFlags(fs *flag.FlagSet) {} +func (c *MakeRunCfg) RegisterFlags(fs *flag.FlagSet) {} -func runRun(cfg *runCfg, args []string, io commands.IO) error { +func execMakeRun(cfg *MakeRunCfg, args []string, cmdio commands.IO) error { if len(args) != 2 { return flag.ErrHelp } - if cfg.rootCfg.gasWanted == 0 { + if cfg.RootCfg.GasWanted == 0 { return errors.New("gas-wanted not specified") } - if cfg.rootCfg.gasFee == "" { + if cfg.RootCfg.GasFee == "" { return errors.New("gas-fee not specified") } @@ -55,7 +56,7 @@ func runRun(cfg *runCfg, args []string, io commands.IO) error { sourcePath := args[1] // can be a file path, a dir path, or '-' for stdin // read account pubkey. - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.rootCfg.Home) + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.RootCfg.Home) if err != nil { return err } @@ -66,15 +67,15 @@ func runRun(cfg *runCfg, args []string, io commands.IO) error { caller := info.GetAddress() // parse gas wanted & fee. - gaswanted := cfg.rootCfg.gasWanted - gasfee, err := std.ParseCoin(cfg.rootCfg.gasFee) + gaswanted := cfg.RootCfg.GasWanted + gasfee, err := std.ParseCoin(cfg.RootCfg.GasFee) if err != nil { return errors.Wrap(err, "parsing gas fee coin") } memPkg := &std.MemPackage{} if sourcePath == "-" { // stdin - data, err := ioutil.ReadAll(io.In()) + data, err := io.ReadAll(cmdio.In()) if err != nil { return fmt.Errorf("could not read stdin: %w", err) } @@ -124,11 +125,11 @@ func runRun(cfg *runCfg, args []string, io commands.IO) error { Msgs: []std.Msg{msg}, Fee: std.NewFee(gaswanted, gasfee), Signatures: nil, - Memo: cfg.rootCfg.memo, + Memo: cfg.RootCfg.Memo, } - if cfg.rootCfg.broadcast { - err := signAndBroadcast(cfg.rootCfg, args, tx, io) + if cfg.RootCfg.Broadcast { + err := client.ExecSignAndBroadcast(cfg.RootCfg, args, tx, cmdio) if err != nil { return err } diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index 86ca33f3dc8..9cbc38f8e40 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -9,6 +9,7 @@ import ( "log" "os" "path/filepath" + "runtime/debug" "sort" "strings" "text/template" @@ -471,8 +472,12 @@ func runTestFiles( printRuntimeMetrics bool, runFlag string, io commands.IO, -) error { - var errs error +) (errs error) { + defer func() { + if r := recover(); r != nil { + errs = multierr.Append(fmt.Errorf("panic: %v\nstack:\n%v\ngno machine: %v", r, string(debug.Stack()), m.String()), errs) + } + }() testFuncs := &testFuncs{ PackageName: pkgName, diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index b127cd32421..ceb7aa7d9a0 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -1797,8 +1797,6 @@ func (sb *StaticBlock) Define2(isConst bool, n Name, st Type, tv TypedValue) { // special case, // allow re-predefining for func upgrades. // keep the old type so we can check it at preprocessor. - // fmt.Println("QWEQWEQWE>>>", old.String()) - // fmt.Println("QWEQWEQWE>>>", tv.String()) tv.T = old.T fv := tv.V.(*FuncValue) fv.Type = old.T diff --git a/gnovm/pkg/gnolang/uverse.go b/gnovm/pkg/gnolang/uverse.go index 041f1557e61..a0e9913eaad 100644 --- a/gnovm/pkg/gnolang/uverse.go +++ b/gnovm/pkg/gnolang/uverse.go @@ -147,32 +147,32 @@ func UverseNode() *PackageNode { // As a special case, if arg1 is a string type, first convert it into // a data slice type. if arg1.TV.T != nil && arg1.TV.T.Kind() == StringKind { - arg1s := arg1.TV.GetString() + arg1String := arg1.TV.GetString() // NOTE: this hack works because // arg1 PointerValue is not a pointer, // so the modification here is only local. - av := m.Alloc.NewDataArray(len(arg1s)) - copy(av.Data, []byte(arg1s)) + newArrayValue := m.Alloc.NewDataArray(len(arg1String)) + copy(newArrayValue.Data, []byte(arg1String)) arg1.TV = &TypedValue{ T: m.Alloc.NewType(&SliceType{ // TODO: reuse Elt: Uint8Type, Vrd: true, }), - V: m.Alloc.NewSlice(av, 0, len(arg1s), len(arg1s)), // TODO: pool? + V: m.Alloc.NewSlice(newArrayValue, 0, len(arg1String), len(arg1String)), // TODO: pool? } } - xt := arg0.TV.T - argt := arg1.TV.T - switch xv := arg0.TV.V.(type) { + arg0Type := arg0.TV.T + arg1Type := arg1.TV.T + switch arg0Value := arg0.TV.V.(type) { // ---------------------------------------------------------------- // append(nil, ???) case nil: - switch args := arg1.TV.V.(type) { + switch arg1Value := arg1.TV.V.(type) { // ------------------------------------------------------------ // append(nil, nil) case nil: // no change m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: nil, }) return @@ -180,42 +180,44 @@ func UverseNode() *PackageNode { // ------------------------------------------------------------ // append(nil, *SliceValue) case *SliceValue: - argsl := args.Length - argso := args.Offset - argsb := args.GetBase(m.Store) - if argsl == 0 { // no change + arg1Length := arg1Value.Length + arg1Offset := arg1Value.Offset + arg1Base := arg1Value.GetBase(m.Store) + arg1EndIndex := arg1Offset + arg1Length + + if arg1Length == 0 { // no change m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: nil, }) return - } else if xt.Elem().Kind() == Uint8Kind { + } else if arg0Type.Elem().Kind() == Uint8Kind { // append(nil, *SliceValue) new data bytes --- - data := make([]byte, argsl) - if argsb.Data == nil { + data := make([]byte, arg1Length) + if arg1Base.Data == nil { copyListToData( - data[:argsl], - argsb.List[argso:argso+argsl]) + data[:arg1Length], + arg1Base.List[arg1Offset:arg1EndIndex]) } else { copy( - data[:argsl], - argsb.Data[argso:argso+argsl]) + data[:arg1Length], + arg1Base.Data[arg1Offset:arg1EndIndex]) } m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: m.Alloc.NewSliceFromData(data), }) return } else { // append(nil, *SliceValue) new list --------- - list := make([]TypedValue, argsl) - if 0 < argsl { - for i := 0; i < argsl; i++ { - list[i] = argsb.List[argso+i].unrefCopy(m.Alloc, m.Store) + list := make([]TypedValue, arg1Length) + if 0 < arg1Length { + for i := 0; i < arg1Length; i++ { + list[i] = arg1Base.List[arg1Offset+i].unrefCopy(m.Alloc, m.Store) } } m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: m.Alloc.NewSliceFromList(list), }) return @@ -224,36 +226,36 @@ func UverseNode() *PackageNode { // ------------------------------------------------------------ // append(nil, *NativeValue) case *NativeValue: - argsrv := args.Value - argsl := argsrv.Len() - if argsl == 0 { // no change + arg1NativeValue := arg1Value.Value + arg1NativeValueLength := arg1NativeValue.Len() + if arg1NativeValueLength == 0 { // no change m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: nil, }) return - } else if xt.Elem().Kind() == Uint8Kind { + } else if arg0Type.Elem().Kind() == Uint8Kind { // append(nil, *NativeValue) new data bytes -- - data := make([]byte, argsl) + data := make([]byte, arg1NativeValueLength) copyNativeToData( - data[:argsl], - argsrv, argsl) + data[:arg1NativeValueLength], + arg1NativeValue, arg1NativeValueLength) m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: m.Alloc.NewSliceFromData(data), }) return } else { // append(nil, *NativeValue) new list -------- - list := make([]TypedValue, argsl) - if 0 < argsl { + list := make([]TypedValue, arg1NativeValueLength) + if 0 < arg1NativeValueLength { copyNativeToList( m.Alloc, - list[:argsl], - argsrv, argsl) + list[:arg1NativeValueLength], + arg1NativeValue, arg1NativeValueLength) } m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: m.Alloc.NewSliceFromList(list), }) return @@ -267,143 +269,137 @@ func UverseNode() *PackageNode { // ---------------------------------------------------------------- // append(*SliceValue, ???) case *SliceValue: - xvl := xv.Length - xvo := xv.Offset - xvc := xv.Maxcap - xvb := xv.GetBase(m.Store) - switch args := arg1.TV.V.(type) { + arg0Length := arg0Value.Length + arg0Offset := arg0Value.Offset + arg0Capacity := arg0Value.Maxcap + arg0Base := arg0Value.GetBase(m.Store) + switch arg1Value := arg1.TV.V.(type) { // ------------------------------------------------------------ // append(*SliceValue, nil) case nil: // no change m.PushValue(TypedValue{ - T: xt, - V: xv, + T: arg0Type, + V: arg0Value, }) return // ------------------------------------------------------------ // append(*SliceValue, *SliceValue) case *SliceValue: - argsl := args.Length - argso := args.Offset - argsb := args.GetBase(m.Store) - if xvl+argsl <= xvc { + arg1Length := arg1Value.Length + arg1Offset := arg1Value.Offset + arg1Base := arg1Value.GetBase(m.Store) + if arg0Length+arg1Length <= arg0Capacity { // append(*SliceValue, *SliceValue) w/i capacity ----- - if 0 < argsl { // implies 0 < xvc - if xvb.Data == nil { + if 0 < arg1Length { // implies 0 < xvc + if arg0Base.Data == nil { // append(*SliceValue.List, *SliceValue) --------- - list := xvb.List - if argsb.Data == nil { - for i := 0; i < argsl; i++ { - oldElem := list[xvo+xvl+i] + list := arg0Base.List + if arg1Base.Data == nil { + for i := 0; i < arg1Length; i++ { + oldElem := list[arg0Offset+arg0Length+i] // unrefCopy will resolve references and copy their values // to copy by value rather than by reference. - newElem := argsb.List[argso+i].unrefCopy(m.Alloc, m.Store) - list[xvo+xvl+i] = newElem + newElem := arg1Base.List[arg1Offset+i].unrefCopy(m.Alloc, m.Store) + list[arg0Offset+arg0Length+i] = newElem m.Realm.DidUpdate( - xvb, + arg0Base, oldElem.GetFirstObject(m.Store), newElem.GetFirstObject(m.Store), ) } } else { copyDataToList( - list[xvo+xvl:xvo+xvl+argsl], - argsb.Data[argso:argso+argsl], - xt.Elem()) - m.Realm.DidUpdate(xvb, nil, nil) + list[arg0Offset+arg0Length:arg0Offset+arg0Length+arg1Length], + arg1Base.Data[arg1Offset:arg1Offset+arg1Length], + arg0Type.Elem()) + m.Realm.DidUpdate(arg1Base, nil, nil) } } else { // append(*SliceValue.Data, *SliceValue) --------- - data := xvb.Data - if argsb.Data == nil { + data := arg0Base.Data + if arg1Base.Data == nil { copyListToData( - data[xvo+xvl:xvo+xvl+argsl], - argsb.List[argso:argso+argsl]) - m.Realm.DidUpdate(xvb, nil, nil) + data[arg0Offset+arg0Length:arg0Offset+arg0Length+arg1Length], + arg1Base.List[arg1Offset:arg1Offset+arg1Length]) + m.Realm.DidUpdate(arg0Base, nil, nil) } else { copy( - data[xvo+xvl:xvo+xvl+argsl], - argsb.Data[argso:argso+argsl]) + data[arg0Offset+arg0Length:arg0Offset+arg0Length+arg1Length], + arg1Base.Data[arg1Offset:arg1Offset+arg1Length]) } } m.PushValue(TypedValue{ - T: xt, - V: m.Alloc.NewSlice(xvb, xvo, xvl+argsl, xvc), + T: arg0Type, + V: m.Alloc.NewSlice(arg0Base, arg0Offset, arg0Length+arg1Length, arg0Capacity), }) return } else { // no change m.PushValue(TypedValue{ - T: xt, - V: xv, + T: arg0Type, + V: arg0Value, }) return } - } else if xt.Elem().Kind() == Uint8Kind { + } else if arg0Type.Elem().Kind() == Uint8Kind { // append(*SliceValue, *SliceValue) new data bytes --- - data := make([]byte, xvl+argsl) - if 0 < xvl { - if xvb.Data == nil { + data := make([]byte, arg0Length+arg1Length) + if 0 < arg0Length { + if arg0Base.Data == nil { copyListToData( - data[:xvl], - xvb.List[xvo:xvo+xvl]) + data[:arg0Length], + arg0Base.List[arg0Offset:arg0Offset+arg0Length]) } else { copy( - data[:xvl], - xvb.Data[xvo:xvo+xvl]) + data[:arg0Length], + arg0Base.Data[arg0Offset:arg0Offset+arg0Length]) } } - if 0 < argsl { - if argsb.Data == nil { + if 0 < arg1Length { + if arg1Base.Data == nil { copyListToData( - data[xvl:xvl+argsl], - argsb.List[argso:argso+argsl]) + data[arg0Length:arg0Length+arg1Length], + arg1Base.List[arg1Offset:arg1Offset+arg1Length]) } else { copy( - data[xvl:xvl+argsl], - argsb.Data[argso:argso+argsl]) + data[arg0Length:arg0Length+arg1Length], + arg1Base.Data[arg1Offset:arg1Offset+arg1Length]) } } m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: m.Alloc.NewSliceFromData(data), }) return } else { // append(*SliceValue, *SliceValue) new list --------- - list := make([]TypedValue, xvl+argsl) - if 0 < xvl { - if xvb.Data == nil { - for i := 0; i < xvl; i++ { - list[i] = xvb.List[xvo+i].unrefCopy(m.Alloc, m.Store) + list := make([]TypedValue, arg0Length+arg1Length) + if 0 < arg0Length { + if arg0Base.Data == nil { + for i := 0; i < arg0Length; i++ { + list[i] = arg0Base.List[arg0Offset+i].unrefCopy(m.Alloc, m.Store) } } else { panic("should not happen") - /* - copyDataToList( - list[:xvl], - xvb.Data[xvo:xvo+xvl], - xt.Elem(), - ) - */ } } - if 0 < argsl { - if argsb.Data == nil { - for i := 0; i < argsl; i++ { - list[xvl+i] = argsb.List[argso+i].unrefCopy(m.Alloc, m.Store) + + if 0 < arg1Length { + if arg1Base.Data == nil { + for i := 0; i < arg1Length; i++ { + list[arg0Length+i] = arg1Base.List[arg1Offset+i].unrefCopy(m.Alloc, m.Store) } } else { copyDataToList( - list[xvl:xvl+argsl], - argsb.Data[argso:argso+argsl], - argt.Elem(), + list[arg0Length:arg0Length+arg1Length], + arg1Base.Data[arg1Offset:arg1Offset+arg1Length], + arg1Type.Elem(), ) } } m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: m.Alloc.NewSliceFromList(list), }) return @@ -412,78 +408,78 @@ func UverseNode() *PackageNode { // ------------------------------------------------------------ // append(*SliceValue, *NativeValue) case *NativeValue: - argsrv := args.Value - argsl := argsrv.Len() - if xvl+argsl <= xvc { + arg1NativeValue := arg1Value.Value + arg1NativeValueLength := arg1NativeValue.Len() + if arg0Length+arg1NativeValueLength <= arg0Capacity { // append(*SliceValue, *NativeValue) w/i capacity ---- - if 0 < argsl { // implies 0 < xvc - if xvb.Data == nil { + if 0 < arg1NativeValueLength { // implies 0 < xvc + if arg0Base.Data == nil { // append(*SliceValue.List, *NativeValue) -------- - list := xvb.List + list := arg0Base.List copyNativeToList( m.Alloc, - list[xvo:xvo+argsl], - argsrv, argsl) + list[arg0Offset:arg0Offset+arg1NativeValueLength], + arg1NativeValue, arg1NativeValueLength) } else { // append(*SliceValue.Data, *NativeValue) -------- - data := xvb.Data + data := arg0Base.Data copyNativeToData( - data[xvo:xvo+argsl], - argsrv, argsl) + data[arg0Offset:arg0Offset+arg1NativeValueLength], + arg1NativeValue, arg1NativeValueLength) } m.PushValue(TypedValue{ - T: xt, - V: m.Alloc.NewSlice(xvb, xvo, xvl+argsl, xvc), + T: arg0Type, + V: m.Alloc.NewSlice(arg0Base, arg0Offset, arg0Length+arg1NativeValueLength, arg0Capacity), }) return } else { // no change m.PushValue(TypedValue{ - T: xt, - V: xv, + T: arg0Type, + V: arg0Value, }) return } - } else if xt.Elem().Kind() == Uint8Kind { + } else if arg0Type.Elem().Kind() == Uint8Kind { // append(*SliceValue, *NativeValue) new data bytes -- - data := make([]byte, xvl+argsl) - if 0 < xvl { - if xvb.Data == nil { + data := make([]byte, arg0Length+arg1NativeValueLength) + if 0 < arg0Length { + if arg0Base.Data == nil { copyListToData( - data[:xvl], - xvb.List[xvo:xvo+xvl]) + data[:arg0Length], + arg0Base.List[arg0Offset:arg0Offset+arg0Length]) } else { copy( - data[:xvl], - xvb.Data[xvo:xvo+xvl]) + data[:arg0Length], + arg0Base.Data[arg0Offset:arg0Offset+arg0Length]) } } - if 0 < argsl { + if 0 < arg1NativeValueLength { copyNativeToData( - data[xvl:xvl+argsl], - argsrv, argsl) + data[arg0Length:arg0Length+arg1NativeValueLength], + arg1NativeValue, arg1NativeValueLength) } m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: m.Alloc.NewSliceFromData(data), }) return } else { // append(*SliceValue, *NativeValue) new list -------- - listLen := xvl + argsl + listLen := arg0Length + arg1NativeValueLength list := make([]TypedValue, listLen) - if 0 < xvl { + if 0 < arg0Length { for i := 0; i < listLen; i++ { - list[i] = xvb.List[xvo+i].unrefCopy(m.Alloc, m.Store) + list[i] = arg0Base.List[arg0Offset+i].unrefCopy(m.Alloc, m.Store) } } - if 0 < argsl { + if 0 < arg1NativeValueLength { copyNativeToList( m.Alloc, - list[xvl:xvl+argsl], - argsrv, argsl) + list[arg0Length:listLen], + arg1NativeValue, arg1NativeValueLength) } m.PushValue(TypedValue{ - T: xt, + T: arg0Type, V: m.Alloc.NewSliceFromList(list), }) return @@ -497,51 +493,51 @@ func UverseNode() *PackageNode { // ---------------------------------------------------------------- // append(*NativeValue, ???) case *NativeValue: - sv := xv.Value - switch args := arg1.TV.V.(type) { + arg0NativeValue := arg0Value.Value + switch arg1Value := arg1.TV.V.(type) { // ------------------------------------------------------------ // append(*NativeValue, nil) case nil: // no change m.PushValue(TypedValue{ - T: xt, - V: xv, + T: arg0Type, + V: arg0Value, }) return // ------------------------------------------------------------ // append(*NativeValue, *SliceValue) case *SliceValue: - st := sv.Type() - argso := args.Offset - argsl := args.Length - argsb := args.GetBase(m.Store) - if 0 < argsl { - argsrv := reflect.MakeSlice(st, argsl, argsl) - if argsb.Data == nil { - for i := 0; i < argsl; i++ { - etv := &(argsb.List[argso+i]) + arg0NativeValueType := arg0NativeValue.Type() + arg1Offset := arg1Value.Offset + arg1Length := arg1Value.Length + arg1Base := arg1Value.GetBase(m.Store) + if 0 < arg1Length { + newNativeArg1Slice := reflect.MakeSlice(arg0NativeValueType, arg1Length, arg1Length) + if arg1Base.Data == nil { + for i := 0; i < arg1Length; i++ { + etv := &(arg1Base.List[arg1Offset+i]) if etv.IsUndefined() { continue } erv := gno2GoValue(etv, reflect.Value{}) - argsrv.Index(i).Set(erv) + newNativeArg1Slice.Index(i).Set(erv) } } else { - for i := 0; i < argsl; i++ { - erv := argsrv.Index(i) - erv.SetUint(uint64(argsb.Data[argso+i])) + for i := 0; i < arg1Length; i++ { + erv := newNativeArg1Slice.Index(i) + erv.SetUint(uint64(arg1Base.Data[arg1Offset+i])) } } - resrv := reflect.AppendSlice(sv, argsrv) + modifiedNativeSlice := reflect.AppendSlice(arg0NativeValue, newNativeArg1Slice) m.PushValue(TypedValue{ - T: xt, - V: m.Alloc.NewNative(resrv), + T: arg0Type, + V: m.Alloc.NewNative(modifiedNativeSlice), }) return } else { // no change m.PushValue(TypedValue{ - T: xt, - V: xv, + T: arg0Type, + V: arg0Value, }) return } @@ -549,31 +545,31 @@ func UverseNode() *PackageNode { // ------------------------------------------------------------ // append(*NativeValue, *NativeValue) case *NativeValue: - argsrv := args.Value - resrv := reflect.AppendSlice(sv, argsrv) + arg1ReflectValue := arg1Value.Value + modifiedNativeSlice := reflect.AppendSlice(arg0NativeValue, arg1ReflectValue) m.PushValue(TypedValue{ - T: xt, - V: m.Alloc.NewNative(resrv), + T: arg0Type, + V: m.Alloc.NewNative(modifiedNativeSlice), }) return // ------------------------------------------------------------ // append(*NativeValue, StringValue) case StringValue: - if xt.Elem().Kind() == Uint8Kind { + if arg0Type.Elem().Kind() == Uint8Kind { // TODO this might be faster if reflect supports // appending this way without first converting to a slice. - argrv := reflect.ValueOf([]byte(arg1.TV.GetString())) - resrv := reflect.AppendSlice(sv, argrv) + arg1ReflectValue := reflect.ValueOf([]byte(arg1.TV.GetString())) + modifiedNativeSlice := reflect.AppendSlice(arg0NativeValue, arg1ReflectValue) m.PushValue(TypedValue{ - T: xt, - V: m.Alloc.NewNative(resrv), + T: arg0Type, + V: m.Alloc.NewNative(modifiedNativeSlice), }) return } else { panic(fmt.Sprintf( "cannot append %s to %s", - arg1.TV.T.String(), xt.String())) + arg1.TV.T.String(), arg0Type.String())) } // ------------------------------------------------------------ @@ -581,7 +577,7 @@ func UverseNode() *PackageNode { default: panic(fmt.Sprintf( "cannot append %s to %s", - arg1.TV.T.String(), xt.String())) + arg1.TV.T.String(), arg0Type.String())) } // ---------------------------------------------------------------- diff --git a/gnovm/stdlibs/std/native.go b/gnovm/stdlibs/std/native.go index 5f6cc8a0061..8cdddd916ad 100644 --- a/gnovm/stdlibs/std/native.go +++ b/gnovm/stdlibs/std/native.go @@ -1,7 +1,6 @@ package std import ( - "fmt" "reflect" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" @@ -112,7 +111,6 @@ func GetOrigPkgAddr(m *gno.Machine) crypto.Bech32Address { func GetCallerAt(m *gno.Machine, n int) crypto.Bech32Address { if n <= 0 { - fmt.Println("QWEQWEQWEQWE", n) m.Panic(typedString("GetCallerAt requires positive arg")) return "" } diff --git a/tm2/pkg/crypto/keys/client/add.go b/tm2/pkg/crypto/keys/client/add.go index 71dc6f03090..49436220974 100644 --- a/tm2/pkg/crypto/keys/client/add.go +++ b/tm2/pkg/crypto/keys/client/add.go @@ -14,24 +14,24 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto/multisig" ) -type addCfg struct { - rootCfg *baseCfg - - multisig commands.StringArr - multisigThreshold int - noSort bool - publicKey string - useLedger bool - recover bool - noBackup bool - dryRun bool - account uint64 - index uint64 +type AddCfg struct { + RootCfg *BaseCfg + + Multisig commands.StringArr + MultisigThreshold int + NoSort bool + PublicKey string + UseLedger bool + Recover bool + NoBackup bool + DryRun bool + Account uint64 + Index uint64 } -func newAddCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &addCfg{ - rootCfg: rootCfg, +func NewAddCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &AddCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -47,71 +47,71 @@ func newAddCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *addCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *AddCfg) RegisterFlags(fs *flag.FlagSet) { fs.Var( - &c.multisig, + &c.Multisig, "multisig", "Construct and store a multisig public key (implies --pubkey)", ) fs.IntVar( - &c.multisigThreshold, + &c.MultisigThreshold, "threshold", 1, "K out of N required signatures. For use in conjunction with --multisig", ) fs.BoolVar( - &c.noSort, + &c.NoSort, "nosort", false, "Keys passed to --multisig are taken in the order they're supplied", ) fs.StringVar( - &c.publicKey, + &c.PublicKey, "pubkey", "", "Parse a public key in bech32 format and save it to disk", ) fs.BoolVar( - &c.useLedger, + &c.UseLedger, "ledger", false, "Store a local reference to a private key on a Ledger device", ) fs.BoolVar( - &c.recover, + &c.Recover, "recover", false, "Provide seed phrase to recover existing key instead of creating", ) fs.BoolVar( - &c.noBackup, + &c.NoBackup, "nobackup", false, "Don't print out seed phrase (if others are watching the terminal)", ) fs.BoolVar( - &c.dryRun, + &c.DryRun, "dryrun", false, "Perform action, but don't add key to local keystore", ) fs.Uint64Var( - &c.account, + &c.Account, "account", 0, "Account number for HD derivation", ) fs.Uint64Var( - &c.index, + &c.Index, "index", 0, "Address index number for HD derivation", @@ -131,7 +131,7 @@ input output - armor encrypted private key (saved to file) */ -func execAdd(cfg *addCfg, args []string, io commands.IO) error { +func execAdd(cfg *AddCfg, args []string, io commands.IO) error { var ( kb keys.Keybase err error @@ -143,15 +143,15 @@ func execAdd(cfg *addCfg, args []string, io commands.IO) error { } name := args[0] - showMnemonic := !cfg.noBackup + showMnemonic := !cfg.NoBackup - if cfg.dryRun { + if cfg.DryRun { // we throw this away, so don't enforce args, // we want to get a new random seed phrase quickly kb = keys.NewInMemory() encryptPassword = DryRunKeyPass } else { - kb, err = keys.NewKeyBaseFromDir(cfg.rootCfg.Home) + kb, err = keys.NewKeyBaseFromDir(cfg.RootCfg.Home) if err != nil { return err } @@ -167,11 +167,11 @@ func execAdd(cfg *addCfg, args []string, io commands.IO) error { } } - multisigKeys := cfg.multisig + multisigKeys := cfg.Multisig if len(multisigKeys) != 0 { var pks []crypto.PubKey - multisigThreshold := cfg.multisigThreshold + multisigThreshold := cfg.MultisigThreshold if err := keys.ValidateMultisigThreshold(multisigThreshold, len(multisigKeys)); err != nil { return err } @@ -185,7 +185,7 @@ func execAdd(cfg *addCfg, args []string, io commands.IO) error { } // Handle --nosort - if !cfg.noSort { + if !cfg.NoSort { sort.Slice(pks, func(i, j int) bool { return pks[i].Address().Compare(pks[j].Address()) < 0 }) @@ -201,13 +201,13 @@ func execAdd(cfg *addCfg, args []string, io commands.IO) error { } // ask for a password when generating a local key - if cfg.publicKey == "" && !cfg.useLedger { + if cfg.PublicKey == "" && !cfg.UseLedger { encryptPassword, err = io.GetCheckPassword( [2]string{ "Enter a passphrase to encrypt your key to disk:", "Repeat the passphrase:", }, - cfg.rootCfg.InsecurePasswordStdin, + cfg.RootCfg.InsecurePasswordStdin, ) if err != nil { return err @@ -215,8 +215,8 @@ func execAdd(cfg *addCfg, args []string, io commands.IO) error { } } - if cfg.publicKey != "" { - pk, err := crypto.PubKeyFromBech32(cfg.publicKey) + if cfg.PublicKey != "" { + pk, err := crypto.PubKeyFromBech32(cfg.PublicKey) if err != nil { return err } @@ -227,11 +227,11 @@ func execAdd(cfg *addCfg, args []string, io commands.IO) error { return nil } - account := cfg.account - index := cfg.index + account := cfg.Account + index := cfg.Index // If we're using ledger, only thing we need is the path and the bech32 prefix. - if cfg.useLedger { + if cfg.UseLedger { bech32PrefixAddr := crypto.Bech32AddrPrefix info, err := kb.CreateLedger(name, keys.Secp256k1, bech32PrefixAddr, uint32(account), uint32(index)) if err != nil { @@ -245,7 +245,7 @@ func execAdd(cfg *addCfg, args []string, io commands.IO) error { var mnemonic string const bip39Passphrase string = "" // XXX research. - if cfg.recover { + if cfg.Recover { bip39Message := "Enter your bip39 mnemonic" mnemonic, err = io.GetString(bip39Message) if err != nil { @@ -270,7 +270,7 @@ func execAdd(cfg *addCfg, args []string, io commands.IO) error { } // Recover key from seed passphrase - if cfg.recover { + if cfg.Recover { // Hide mnemonic from output showMnemonic = false mnemonic = "" diff --git a/tm2/pkg/crypto/keys/client/add_test.go b/tm2/pkg/crypto/keys/client/add_test.go index 94cb945f113..4110ea32c9a 100644 --- a/tm2/pkg/crypto/keys/client/add_test.go +++ b/tm2/pkg/crypto/keys/client/add_test.go @@ -20,8 +20,8 @@ func Test_execAddBasic(t *testing.T) { assert.NotNil(t, kbHome) defer kbCleanUp() - cfg := &addCfg{ - rootCfg: &baseCfg{ + cfg := &AddCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ InsecurePasswordStdin: true, Home: kbHome, @@ -59,13 +59,13 @@ func Test_execAddPublicKey(t *testing.T) { assert.NotNil(t, kbHome) defer kbCleanUp() - cfg := &addCfg{ - rootCfg: &baseCfg{ + cfg := &AddCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ Home: kbHome, }, }, - publicKey: test2PubkeyBech32, // test2 account + PublicKey: test2PubkeyBech32, // test2 account } if err := execAdd(cfg, []string{"test2"}, nil); err != nil { @@ -80,14 +80,14 @@ func Test_execAddRecover(t *testing.T) { assert.NotNil(t, kbHome) defer kbCleanUp() - cfg := &addCfg{ - rootCfg: &baseCfg{ + cfg := &AddCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ InsecurePasswordStdin: true, Home: kbHome, }, }, - recover: true, // init test2 account + Recover: true, // init test2 account } test2Name := "test2" diff --git a/tm2/pkg/crypto/keys/client/addpkg.go b/tm2/pkg/crypto/keys/client/addpkg.go deleted file mode 100644 index 5bbd3f08ad0..00000000000 --- a/tm2/pkg/crypto/keys/client/addpkg.go +++ /dev/null @@ -1,222 +0,0 @@ -package client - -// TODO: move most of the logic in ROOT/gno.land/... - -import ( - "context" - "flag" - "fmt" - - "github.com/gnolang/gno/gno.land/pkg/sdk/vm" - gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/tm2/pkg/amino" - "github.com/gnolang/gno/tm2/pkg/commands" - "github.com/gnolang/gno/tm2/pkg/crypto/keys" - "github.com/gnolang/gno/tm2/pkg/errors" - "github.com/gnolang/gno/tm2/pkg/std" -) - -type addPkgCfg struct { - rootCfg *makeTxCfg - - pkgPath string - pkgDir string - deposit string -} - -func newAddPkgCmd(rootCfg *makeTxCfg, io commands.IO) *commands.Command { - cfg := &addPkgCfg{ - rootCfg: rootCfg, - } - - return commands.NewCommand( - commands.Metadata{ - Name: "addpkg", - ShortUsage: "addpkg [flags] ", - ShortHelp: "Uploads a new package", - }, - cfg, - func(_ context.Context, args []string) error { - return execAddPkg(cfg, args, io) - }, - ) -} - -func (c *addPkgCfg) RegisterFlags(fs *flag.FlagSet) { - fs.StringVar( - &c.pkgPath, - "pkgpath", - "", - "package path (required)", - ) - - fs.StringVar( - &c.pkgDir, - "pkgdir", - "", - "path to package files (required)", - ) - - fs.StringVar( - &c.deposit, - "deposit", - "", - "deposit coins", - ) -} - -func execAddPkg(cfg *addPkgCfg, args []string, io commands.IO) error { - if cfg.pkgPath == "" { - return errors.New("pkgpath not specified") - } - if cfg.pkgDir == "" { - return errors.New("pkgdir not specified") - } - - if len(args) != 1 { - return flag.ErrHelp - } - - // read account pubkey. - nameOrBech32 := args[0] - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.rootCfg.Home) - if err != nil { - return err - } - info, err := kb.GetByNameOrAddress(nameOrBech32) - if err != nil { - return err - } - creator := info.GetAddress() - // info.GetPubKey() - - // parse deposit. - deposit, err := std.ParseCoins(cfg.deposit) - if err != nil { - panic(err) - } - - // open files in directory as MemPackage. - memPkg := gno.ReadMemPackage(cfg.pkgDir, cfg.pkgPath) - if memPkg.IsEmpty() { - panic(fmt.Sprintf("found an empty package %q", cfg.pkgPath)) - } - - // precompile and validate syntax - err = gno.PrecompileAndCheckMempkg(memPkg) - if err != nil { - panic(err) - } - - // parse gas wanted & fee. - gaswanted := cfg.rootCfg.gasWanted - gasfee, err := std.ParseCoin(cfg.rootCfg.gasFee) - if err != nil { - panic(err) - } - // construct msg & tx and marshal. - msg := vm.MsgAddPackage{ - Creator: creator, - Package: memPkg, - Deposit: deposit, - } - tx := std.Tx{ - Msgs: []std.Msg{msg}, - Fee: std.NewFee(gaswanted, gasfee), - Signatures: nil, - Memo: cfg.rootCfg.memo, - } - - if cfg.rootCfg.broadcast { - err := signAndBroadcast(cfg.rootCfg, args, tx, io) - if err != nil { - return err - } - } else { - fmt.Println(string(amino.MustMarshalJSON(tx))) - } - return nil -} - -func signAndBroadcast( - cfg *makeTxCfg, - args []string, - tx std.Tx, - io commands.IO, -) error { - baseopts := cfg.rootCfg - txopts := cfg - - // query account - nameOrBech32 := args[0] - kb, err := keys.NewKeyBaseFromDir(baseopts.Home) - if err != nil { - return err - } - info, err := kb.GetByNameOrAddress(nameOrBech32) - if err != nil { - return err - } - accountAddr := info.GetAddress() - - qopts := &queryCfg{ - rootCfg: baseopts, - path: fmt.Sprintf("auth/accounts/%s", accountAddr), - } - qres, err := queryHandler(qopts) - if err != nil { - return errors.Wrap(err, "query account") - } - var qret struct{ BaseAccount std.BaseAccount } - err = amino.UnmarshalJSON(qres.Response.Data, &qret) - if err != nil { - return err - } - - // sign tx - accountNumber := qret.BaseAccount.AccountNumber - sequence := qret.BaseAccount.Sequence - sopts := &signCfg{ - rootCfg: baseopts, - sequence: sequence, - accountNumber: accountNumber, - chainID: txopts.chainID, - nameOrBech32: nameOrBech32, - txJSON: amino.MustMarshalJSON(tx), - } - if baseopts.Quiet { - sopts.pass, err = io.GetPassword("", baseopts.InsecurePasswordStdin) - } else { - sopts.pass, err = io.GetPassword("Enter password.", baseopts.InsecurePasswordStdin) - } - if err != nil { - return err - } - - signedTx, err := SignHandler(sopts) - if err != nil { - return errors.Wrap(err, "sign tx") - } - - // broadcast signed tx - bopts := &broadcastCfg{ - rootCfg: baseopts, - tx: signedTx, - } - bres, err := broadcastHandler(bopts) - if err != nil { - return errors.Wrap(err, "broadcast tx") - } - if bres.CheckTx.IsErr() { - return errors.Wrap(bres.CheckTx.Error, "check transaction failed: log:%s", bres.CheckTx.Log) - } - if bres.DeliverTx.IsErr() { - return errors.Wrap(bres.DeliverTx.Error, "deliver transaction failed: log:%s", bres.DeliverTx.Log) - } - io.Println(string(bres.DeliverTx.Data)) - io.Println("OK!") - io.Println("GAS WANTED:", bres.DeliverTx.GasWanted) - io.Println("GAS USED: ", bres.DeliverTx.GasUsed) - - return nil -} diff --git a/tm2/pkg/crypto/keys/client/broadcast.go b/tm2/pkg/crypto/keys/client/broadcast.go index 9c05f2c43b3..3443f4678c6 100644 --- a/tm2/pkg/crypto/keys/client/broadcast.go +++ b/tm2/pkg/crypto/keys/client/broadcast.go @@ -14,18 +14,18 @@ import ( "github.com/gnolang/gno/tm2/pkg/std" ) -type broadcastCfg struct { - rootCfg *baseCfg +type BroadcastCfg struct { + RootCfg *BaseCfg - dryRun bool + DryRun bool // internal tx *std.Tx } -func newBroadcastCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &broadcastCfg{ - rootCfg: rootCfg, +func NewBroadcastCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &BroadcastCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -41,16 +41,16 @@ func newBroadcastCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *broadcastCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *BroadcastCfg) RegisterFlags(fs *flag.FlagSet) { fs.BoolVar( - &c.dryRun, + &c.DryRun, "dry-run", false, "perform a dry-run broadcast", ) } -func execBroadcast(cfg *broadcastCfg, args []string, io commands.IO) error { +func execBroadcast(cfg *BroadcastCfg, args []string, io commands.IO) error { if len(args) != 1 { return flag.ErrHelp } @@ -67,7 +67,7 @@ func execBroadcast(cfg *broadcastCfg, args []string, io commands.IO) error { } cfg.tx = &tx - res, err := broadcastHandler(cfg) + res, err := BroadcastHandler(cfg) if err != nil { return err } @@ -85,12 +85,12 @@ func execBroadcast(cfg *broadcastCfg, args []string, io commands.IO) error { return nil } -func broadcastHandler(cfg *broadcastCfg) (*ctypes.ResultBroadcastTxCommit, error) { +func BroadcastHandler(cfg *BroadcastCfg) (*ctypes.ResultBroadcastTxCommit, error) { if cfg.tx == nil { return nil, errors.New("invalid tx") } - remote := cfg.rootCfg.Remote + remote := cfg.RootCfg.Remote if remote == "" || remote == "y" { return nil, errors.New("missing remote url") } @@ -102,8 +102,8 @@ func broadcastHandler(cfg *broadcastCfg) (*ctypes.ResultBroadcastTxCommit, error cli := client.NewHTTP(remote, "/websocket") - if cfg.dryRun { - return simulateTx(cli, bz) + if cfg.DryRun { + return SimulateTx(cli, bz) } bres, err := cli.BroadcastTxCommit(bz) @@ -114,7 +114,7 @@ func broadcastHandler(cfg *broadcastCfg) (*ctypes.ResultBroadcastTxCommit, error return bres, nil } -func simulateTx(cli client.ABCIClient, tx []byte) (*ctypes.ResultBroadcastTxCommit, error) { +func SimulateTx(cli client.ABCIClient, tx []byte) (*ctypes.ResultBroadcastTxCommit, error) { bres, err := cli.ABCIQuery(".app/simulate", tx) if err != nil { return nil, errors.Wrap(err, "simulate tx") diff --git a/tm2/pkg/crypto/keys/client/delete.go b/tm2/pkg/crypto/keys/client/delete.go index cf65b8fc60a..69c185c3e75 100644 --- a/tm2/pkg/crypto/keys/client/delete.go +++ b/tm2/pkg/crypto/keys/client/delete.go @@ -9,16 +9,16 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto/keys" ) -type deleteCfg struct { - rootCfg *baseCfg +type DeleteCfg struct { + RootCfg *BaseCfg - yes bool - force bool + Yes bool + Force bool } -func newDeleteCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &deleteCfg{ - rootCfg: rootCfg, +func NewDeleteCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &DeleteCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -34,30 +34,30 @@ func newDeleteCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *deleteCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *DeleteCfg) RegisterFlags(fs *flag.FlagSet) { fs.BoolVar( - &c.yes, + &c.Yes, "yes", false, "skip confirmation prompt", ) fs.BoolVar( - &c.force, + &c.Force, "force", false, "remove key unconditionally", ) } -func execDelete(cfg *deleteCfg, args []string, io commands.IO) error { +func execDelete(cfg *DeleteCfg, args []string, io commands.IO) error { if len(args) != 1 { return flag.ErrHelp } nameOrBech32 := args[0] - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.Home) + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.Home) if err != nil { return err } @@ -68,7 +68,7 @@ func execDelete(cfg *deleteCfg, args []string, io commands.IO) error { } if info.GetType() == keys.TypeLedger || info.GetType() == keys.TypeOffline { - if !cfg.yes { + if !cfg.Yes { if err := confirmDeletion(io); err != nil { return err } @@ -83,11 +83,11 @@ func execDelete(cfg *deleteCfg, args []string, io commands.IO) error { } // skip passphrase check if run with --force - skipPass := cfg.force + skipPass := cfg.Force var oldpass string if !skipPass { msg := "DANGER - enter password to permanently delete key:" - if oldpass, err = io.GetPassword(msg, cfg.rootCfg.InsecurePasswordStdin); err != nil { + if oldpass, err = io.GetPassword(msg, cfg.RootCfg.InsecurePasswordStdin); err != nil { return err } } diff --git a/tm2/pkg/crypto/keys/client/delete_test.go b/tm2/pkg/crypto/keys/client/delete_test.go index b3f83f1d9a2..a9724ac483b 100644 --- a/tm2/pkg/crypto/keys/client/delete_test.go +++ b/tm2/pkg/crypto/keys/client/delete_test.go @@ -23,8 +23,8 @@ func Test_execDelete(t *testing.T) { defer kbCleanUp() // initialize test options - cfg := &deleteCfg{ - rootCfg: &baseCfg{ + cfg := &DeleteCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ Home: kbHome, InsecurePasswordStdin: true, @@ -75,14 +75,14 @@ func Test_execDelete(t *testing.T) { } // Set config yes = true - cfg = &deleteCfg{ - rootCfg: &baseCfg{ + cfg = &DeleteCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ Home: kbHome, InsecurePasswordStdin: true, }, }, - yes: true, + Yes: true, } _, err = kb.GetByName(fakeKeyName2) diff --git a/tm2/pkg/crypto/keys/client/export.go b/tm2/pkg/crypto/keys/client/export.go index c3921c31fd7..58f533bd3be 100644 --- a/tm2/pkg/crypto/keys/client/export.go +++ b/tm2/pkg/crypto/keys/client/export.go @@ -2,6 +2,7 @@ package client import ( "context" + "errors" "flag" "fmt" "os" @@ -10,17 +11,17 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto/keys" ) -type exportCfg struct { - rootCfg *baseCfg +type ExportCfg struct { + RootCfg *BaseCfg - nameOrBech32 string - outputPath string - unsafe bool + NameOrBech32 string + OutputPath string + Unsafe bool } -func newExportCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &exportCfg{ - rootCfg: rootCfg, +func NewExportCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &ExportCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -36,36 +37,41 @@ func newExportCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *exportCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *ExportCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( - &c.nameOrBech32, + &c.NameOrBech32, "key", "", "Name or Bech32 address of the private key", ) fs.StringVar( - &c.outputPath, + &c.OutputPath, "output-path", "", "The desired output path for the armor file", ) fs.BoolVar( - &c.unsafe, + &c.Unsafe, "unsafe", false, "Export the private key armor as unencrypted", ) } -func execExport(cfg *exportCfg, io commands.IO) error { +func execExport(cfg *ExportCfg, io commands.IO) error { + // check keyname + if cfg.NameOrBech32 == "" { + return errors.New("key to be exported shouldn't be empty") + } + // Create a new instance of the key-base - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.Home) + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.Home) if err != nil { return fmt.Errorf( "unable to create a key base from directory %s, %w", - cfg.rootCfg.Home, + cfg.RootCfg.Home, err, ) } @@ -73,7 +79,7 @@ func execExport(cfg *exportCfg, io commands.IO) error { // Get the key-base decrypt password decryptPassword, err := io.GetPassword( "Enter a passphrase to decrypt your private key from disk:", - cfg.rootCfg.InsecurePasswordStdin, + cfg.RootCfg.InsecurePasswordStdin, ) if err != nil { return fmt.Errorf( @@ -87,10 +93,10 @@ func execExport(cfg *exportCfg, io commands.IO) error { exportErr error ) - if cfg.unsafe { + if cfg.Unsafe { // Generate the unencrypted armor armor, exportErr = kb.ExportPrivKeyUnsafe( - cfg.nameOrBech32, + cfg.NameOrBech32, decryptPassword, ) } else { @@ -100,7 +106,7 @@ func execExport(cfg *exportCfg, io commands.IO) error { "Enter a passphrase to encrypt your private key armor:", "Repeat the passphrase:", }, - cfg.rootCfg.InsecurePasswordStdin, + cfg.RootCfg.InsecurePasswordStdin, ) if err != nil { return fmt.Errorf( @@ -111,7 +117,7 @@ func execExport(cfg *exportCfg, io commands.IO) error { // Generate the encrypted armor armor, exportErr = kb.ExportPrivKey( - cfg.nameOrBech32, + cfg.NameOrBech32, decryptPassword, encryptPassword, ) @@ -126,7 +132,7 @@ func execExport(cfg *exportCfg, io commands.IO) error { // Write the armor to disk if err := os.WriteFile( - cfg.outputPath, + cfg.OutputPath, []byte(armor), 0o644, ); err != nil { @@ -136,7 +142,7 @@ func execExport(cfg *exportCfg, io commands.IO) error { ) } - io.Printfln("Private key armor successfully outputted to %s", cfg.outputPath) + io.Printfln("Private key armor successfully outputted to %s", cfg.OutputPath) return nil } diff --git a/tm2/pkg/crypto/keys/client/export_test.go b/tm2/pkg/crypto/keys/client/export_test.go index 0f4c5311dfa..dfd7c74ce38 100644 --- a/tm2/pkg/crypto/keys/client/export_test.go +++ b/tm2/pkg/crypto/keys/client/export_test.go @@ -81,16 +81,16 @@ func exportKey( exportOpts testExportKeyOpts, input io.Reader, ) error { - cfg := &exportCfg{ - rootCfg: &baseCfg{ + cfg := &ExportCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ Home: exportOpts.kbHome, InsecurePasswordStdin: true, }, }, - nameOrBech32: exportOpts.keyName, - outputPath: exportOpts.outputPath, - unsafe: exportOpts.unsafe, + NameOrBech32: exportOpts.keyName, + OutputPath: exportOpts.outputPath, + Unsafe: exportOpts.unsafe, } cmdIO := commands.NewTestIO() @@ -202,3 +202,19 @@ func TestExport_ExportKey(t *testing.T) { }) } } + +func TestExport_ExportKeyWithEmptyName(t *testing.T) { + // Generate a temporary key-base directory + _, kbHome := newTestKeybase(t) + err := exportKey( + testExportKeyOpts{ + testCmdKeyOptsBase: testCmdKeyOptsBase{ + kbHome: kbHome, + keyName: "", + }, + }, + nil, + ) + assert.Error(t, err) + assert.EqualError(t, err, "key to be exported shouldn't be empty") +} diff --git a/tm2/pkg/crypto/keys/client/generate.go b/tm2/pkg/crypto/keys/client/generate.go index 04a0ea8947f..bae3b6b42a3 100644 --- a/tm2/pkg/crypto/keys/client/generate.go +++ b/tm2/pkg/crypto/keys/client/generate.go @@ -10,15 +10,15 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto/bip39" ) -type generateCfg struct { - rootCfg *baseCfg +type GenerateCfg struct { + RootCfg *BaseCfg - customEntropy bool + CustomEntropy bool } -func newGenerateCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &generateCfg{ - rootCfg: rootCfg, +func NewGenerateCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &GenerateCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -34,17 +34,17 @@ func newGenerateCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *generateCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *GenerateCfg) RegisterFlags(fs *flag.FlagSet) { fs.BoolVar( - &c.customEntropy, + &c.CustomEntropy, "entropy", false, "supply custom entropy", ) } -func execGenerate(cfg *generateCfg, args []string, io commands.IO) error { - customEntropy := cfg.customEntropy +func execGenerate(cfg *GenerateCfg, args []string, io commands.IO) error { + customEntropy := cfg.CustomEntropy if len(args) != 0 { return flag.ErrHelp diff --git a/tm2/pkg/crypto/keys/client/generate_test.go b/tm2/pkg/crypto/keys/client/generate_test.go index 516912046b6..25eca1ed628 100644 --- a/tm2/pkg/crypto/keys/client/generate_test.go +++ b/tm2/pkg/crypto/keys/client/generate_test.go @@ -11,8 +11,8 @@ import ( func Test_execGenerateNormal(t *testing.T) { t.Parallel() - cfg := &generateCfg{ - customEntropy: false, + cfg := &GenerateCfg{ + CustomEntropy: false, } err := execGenerate(cfg, []string{}, commands.NewTestIO()) @@ -22,8 +22,8 @@ func Test_execGenerateNormal(t *testing.T) { func Test_execGenerateUser(t *testing.T) { t.Parallel() - cfg := &generateCfg{ - customEntropy: true, + cfg := &GenerateCfg{ + CustomEntropy: true, } io := commands.NewTestIO() diff --git a/tm2/pkg/crypto/keys/client/import.go b/tm2/pkg/crypto/keys/client/import.go index e4f20ff6402..cace9bc0964 100644 --- a/tm2/pkg/crypto/keys/client/import.go +++ b/tm2/pkg/crypto/keys/client/import.go @@ -2,6 +2,7 @@ package client import ( "context" + "errors" "flag" "fmt" "os" @@ -10,17 +11,17 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto/keys" ) -type importCfg struct { - rootCfg *baseCfg +type ImportCfg struct { + RootCfg *BaseCfg - keyName string - armorPath string - unsafe bool + KeyName string + ArmorPath string + Unsafe bool } -func newImportCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &importCfg{ - rootCfg: rootCfg, +func NewImportCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &ImportCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -36,46 +37,51 @@ func newImportCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *importCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *ImportCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( - &c.keyName, + &c.KeyName, "name", "", "The name of the private key", ) fs.StringVar( - &c.armorPath, + &c.ArmorPath, "armor-path", "", "The path to the encrypted armor file", ) fs.BoolVar( - &c.unsafe, + &c.Unsafe, "unsafe", false, "Import the private key armor as unencrypted", ) } -func execImport(cfg *importCfg, io commands.IO) error { +func execImport(cfg *ImportCfg, io commands.IO) error { + // check keyname + if cfg.KeyName == "" { + return errors.New("name shouldn't be empty") + } + // Create a new instance of the key-base - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.Home) + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.Home) if err != nil { return fmt.Errorf( "unable to create a key base from directory %s, %w", - cfg.rootCfg.Home, + cfg.RootCfg.Home, err, ) } // Read the raw encrypted armor - armor, err := os.ReadFile(cfg.armorPath) + armor, err := os.ReadFile(cfg.ArmorPath) if err != nil { return fmt.Errorf( "unable to read armor from path %s, %w", - cfg.armorPath, + cfg.ArmorPath, err, ) } @@ -85,11 +91,11 @@ func execImport(cfg *importCfg, io commands.IO) error { encryptPassword string ) - if !cfg.unsafe { + if !cfg.Unsafe { // Get the armor decrypt password decryptPassword, err = io.GetPassword( - "Enter a passphrase to decrypt your private key armor:", - cfg.rootCfg.InsecurePasswordStdin, + "Enter the passphrase to decrypt your private key armor:", + cfg.RootCfg.InsecurePasswordStdin, ) if err != nil { return fmt.Errorf( @@ -105,7 +111,7 @@ func execImport(cfg *importCfg, io commands.IO) error { "Enter a passphrase to encrypt your private key:", "Repeat the passphrase:", }, - cfg.rootCfg.InsecurePasswordStdin, + cfg.RootCfg.InsecurePasswordStdin, ) if err != nil { return fmt.Errorf( @@ -114,10 +120,10 @@ func execImport(cfg *importCfg, io commands.IO) error { ) } - if cfg.unsafe { + if cfg.Unsafe { // Import the unencrypted private key if err := kb.ImportPrivKeyUnsafe( - cfg.keyName, + cfg.KeyName, string(armor), encryptPassword, ); err != nil { @@ -129,7 +135,7 @@ func execImport(cfg *importCfg, io commands.IO) error { } else { // Import the encrypted private key if err := kb.ImportPrivKey( - cfg.keyName, + cfg.KeyName, string(armor), decryptPassword, encryptPassword, @@ -141,7 +147,7 @@ func execImport(cfg *importCfg, io commands.IO) error { } } - io.Printfln("Successfully imported private key %s", cfg.keyName) + io.Printfln("Successfully imported private key %s", cfg.KeyName) return nil } diff --git a/tm2/pkg/crypto/keys/client/import_test.go b/tm2/pkg/crypto/keys/client/import_test.go index 7bc00e06ec9..9788f3d700c 100644 --- a/tm2/pkg/crypto/keys/client/import_test.go +++ b/tm2/pkg/crypto/keys/client/import_test.go @@ -22,16 +22,16 @@ func importKey( importOpts testImportKeyOpts, input io.Reader, ) error { - cfg := &importCfg{ - rootCfg: &baseCfg{ + cfg := &ImportCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ Home: importOpts.kbHome, InsecurePasswordStdin: true, }, }, - keyName: importOpts.keyName, - armorPath: importOpts.armorPath, - unsafe: importOpts.unsafe, + KeyName: importOpts.keyName, + ArmorPath: importOpts.armorPath, + Unsafe: importOpts.unsafe, } cmdIO := commands.NewTestIO() @@ -152,3 +152,19 @@ func TestImport_ImportKey(t *testing.T) { }) } } + +func TestImport_ImportKeyWithEmptyName(t *testing.T) { + // Generate a temporary key-base directory + _, kbHome := newTestKeybase(t) + err := importKey( + testImportKeyOpts{ + testCmdKeyOptsBase: testCmdKeyOptsBase{ + kbHome: kbHome, + keyName: "", + }, + }, + nil, + ) + assert.Error(t, err) + assert.EqualError(t, err, "name shouldn't be empty") +} diff --git a/tm2/pkg/crypto/keys/client/list.go b/tm2/pkg/crypto/keys/client/list.go index bdee6b3bbe9..5a2c0dfb28a 100644 --- a/tm2/pkg/crypto/keys/client/list.go +++ b/tm2/pkg/crypto/keys/client/list.go @@ -8,7 +8,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto/keys" ) -func newListCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { +func NewListCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { return commands.NewCommand( commands.Metadata{ Name: "list", @@ -22,7 +22,7 @@ func newListCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func execList(cfg *baseCfg, args []string, io commands.IO) error { +func execList(cfg *BaseCfg, args []string, io commands.IO) error { if len(args) != 0 { return flag.ErrHelp } diff --git a/tm2/pkg/crypto/keys/client/list_test.go b/tm2/pkg/crypto/keys/client/list_test.go index ee0a147f3d3..69e96f1cfb1 100644 --- a/tm2/pkg/crypto/keys/client/list_test.go +++ b/tm2/pkg/crypto/keys/client/list_test.go @@ -36,7 +36,7 @@ func Test_execList(t *testing.T) { for _, tt := range testData { t.Run(tt.name, func(t *testing.T) { // Set current home - cfg := &baseCfg{ + cfg := &BaseCfg{ BaseOptions: BaseOptions{ Home: tt.kbDir, }, diff --git a/tm2/pkg/crypto/keys/client/maketx.go b/tm2/pkg/crypto/keys/client/maketx.go index c424b566c95..c78c5de25c8 100644 --- a/tm2/pkg/crypto/keys/client/maketx.go +++ b/tm2/pkg/crypto/keys/client/maketx.go @@ -2,24 +2,30 @@ package client import ( "flag" + "fmt" + "github.com/gnolang/gno/tm2/pkg/amino" + types "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" "github.com/gnolang/gno/tm2/pkg/commands" + "github.com/gnolang/gno/tm2/pkg/crypto/keys" + "github.com/gnolang/gno/tm2/pkg/errors" + "github.com/gnolang/gno/tm2/pkg/std" ) -type makeTxCfg struct { - rootCfg *baseCfg +type MakeTxCfg struct { + RootCfg *BaseCfg - gasWanted int64 - gasFee string - memo string + GasWanted int64 + GasFee string + Memo string - broadcast bool - chainID string + Broadcast bool + ChainID string } -func newMakeTxCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &makeTxCfg{ - rootCfg: rootCfg, +func NewMakeTxCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &MakeTxCfg{ + RootCfg: rootCfg, } cmd := commands.NewCommand( @@ -33,48 +39,148 @@ func newMakeTxCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) cmd.AddSubCommands( - newAddPkgCmd(cfg, io), - newSendCmd(cfg, io), - newCallCmd(cfg, io), - newRunCmd(cfg, io), + NewMakeSendCmd(cfg, io), ) return cmd } -func (c *makeTxCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *MakeTxCfg) RegisterFlags(fs *flag.FlagSet) { fs.Int64Var( - &c.gasWanted, + &c.GasWanted, "gas-wanted", 0, "gas requested for tx", ) fs.StringVar( - &c.gasFee, + &c.GasFee, "gas-fee", "", "gas payment fee", ) fs.StringVar( - &c.memo, + &c.Memo, "memo", "", "any descriptive text", ) fs.BoolVar( - &c.broadcast, + &c.Broadcast, "broadcast", false, "sign and broadcast", ) fs.StringVar( - &c.chainID, + &c.ChainID, "chainid", "dev", "chainid to sign for (only useful if --broadcast)", ) } + +func SignAndBroadcastHandler( + cfg *MakeTxCfg, + nameOrBech32 string, + tx std.Tx, + pass string, +) (*types.ResultBroadcastTxCommit, error) { + baseopts := cfg.RootCfg + txopts := cfg + + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.Home) + if err != nil { + return nil, err + } + + info, err := kb.GetByNameOrAddress(nameOrBech32) + if err != nil { + return nil, err + } + accountAddr := info.GetAddress() + + qopts := &QueryCfg{ + RootCfg: baseopts, + Path: fmt.Sprintf("auth/accounts/%s", accountAddr), + } + qres, err := QueryHandler(qopts) + if err != nil { + return nil, errors.Wrap(err, "query account") + } + var qret struct{ BaseAccount std.BaseAccount } + err = amino.UnmarshalJSON(qres.Response.Data, &qret) + if err != nil { + return nil, err + } + + // sign tx + accountNumber := qret.BaseAccount.AccountNumber + sequence := qret.BaseAccount.Sequence + sopts := &SignCfg{ + Pass: pass, + RootCfg: baseopts, + Sequence: sequence, + AccountNumber: accountNumber, + ChainID: txopts.ChainID, + NameOrBech32: nameOrBech32, + TxJSON: amino.MustMarshalJSON(tx), + } + + signedTx, err := SignHandler(sopts) + if err != nil { + return nil, errors.Wrap(err, "sign tx") + } + + // broadcast signed tx + bopts := &BroadcastCfg{ + RootCfg: baseopts, + tx: signedTx, + } + + return BroadcastHandler(bopts) +} + +func ExecSignAndBroadcast( + cfg *MakeTxCfg, + args []string, + tx std.Tx, + io commands.IO, +) error { + baseopts := cfg.RootCfg + + // query account + nameOrBech32 := args[0] + + var err error + var pass string + if baseopts.Quiet { + pass, err = io.GetPassword("", baseopts.InsecurePasswordStdin) + } else { + pass, err = io.GetPassword("Enter password.", baseopts.InsecurePasswordStdin) + } + + if err != nil { + return err + } + + bres, err := SignAndBroadcastHandler(cfg, nameOrBech32, tx, pass) + if err != nil { + return errors.Wrap(err, "broadcast tx") + } + if bres.CheckTx.IsErr() { + return errors.Wrap(bres.CheckTx.Error, "check transaction failed: log:%s", bres.CheckTx.Log) + } + if bres.DeliverTx.IsErr() { + return errors.Wrap(bres.DeliverTx.Error, "deliver transaction failed: log:%s", bres.DeliverTx.Log) + } + + io.Println(string(bres.DeliverTx.Data)) + io.Println("OK!") + io.Println("GAS WANTED:", bres.DeliverTx.GasWanted) + io.Println("GAS USED: ", bres.DeliverTx.GasUsed) + + return nil +} diff --git a/tm2/pkg/crypto/keys/client/query.go b/tm2/pkg/crypto/keys/client/query.go index 746048e772c..4c37a125749 100644 --- a/tm2/pkg/crypto/keys/client/query.go +++ b/tm2/pkg/crypto/keys/client/query.go @@ -10,20 +10,19 @@ import ( "github.com/gnolang/gno/tm2/pkg/errors" ) -type queryCfg struct { - rootCfg *baseCfg +type QueryCfg struct { + RootCfg *BaseCfg - data string - height int64 - prove bool + Data string + Height int64 + Prove bool - // internal - path string + Path string } -func newQueryCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &queryCfg{ - rootCfg: rootCfg, +func NewQueryCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &QueryCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -39,37 +38,37 @@ func newQueryCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *queryCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *QueryCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( - &c.data, + &c.Data, "data", "", "query data bytes", ) fs.Int64Var( - &c.height, + &c.Height, "height", 0, "query height (not yet supported)", ) fs.BoolVar( - &c.prove, + &c.Prove, "prove", false, "prove query result (not yet supported)", ) } -func execQuery(cfg *queryCfg, args []string, io commands.IO) error { +func execQuery(cfg *QueryCfg, args []string, io commands.IO) error { if len(args) != 1 { return flag.ErrHelp } - cfg.path = args[0] + cfg.Path = args[0] - qres, err := queryHandler(cfg) + qres, err := QueryHandler(cfg) if err != nil { return err } @@ -90,20 +89,20 @@ func execQuery(cfg *queryCfg, args []string, io commands.IO) error { return nil } -func queryHandler(cfg *queryCfg) (*ctypes.ResultABCIQuery, error) { - remote := cfg.rootCfg.Remote +func QueryHandler(cfg *QueryCfg) (*ctypes.ResultABCIQuery, error) { + remote := cfg.RootCfg.Remote if remote == "" || remote == "y" { return nil, errors.New("missing remote url") } - data := []byte(cfg.data) + data := []byte(cfg.Data) opts2 := client.ABCIQueryOptions{ // Height: height, XXX // Prove: false, XXX } cli := client.NewHTTP(remote, "/websocket") qres, err := cli.ABCIQueryWithOptions( - cfg.path, data, opts2) + cfg.Path, data, opts2) if err != nil { return nil, errors.Wrap(err, "querying") } diff --git a/tm2/pkg/crypto/keys/client/root.go b/tm2/pkg/crypto/keys/client/root.go index e09b31d45dd..bfccdc26bab 100644 --- a/tm2/pkg/crypto/keys/client/root.go +++ b/tm2/pkg/crypto/keys/client/root.go @@ -14,7 +14,7 @@ const ( mnemonicEntropySize = 256 ) -type baseCfg struct { +type BaseCfg struct { BaseOptions } @@ -23,7 +23,7 @@ func NewRootCmd(io commands.IO) *commands.Command { } func NewRootCmdWithBaseConfig(io commands.IO, base BaseOptions) *commands.Command { - cfg := &baseCfg{ + cfg := &BaseCfg{ BaseOptions: base, } @@ -41,23 +41,23 @@ func NewRootCmdWithBaseConfig(io commands.IO, base BaseOptions) *commands.Comman ) cmd.AddSubCommands( - newAddCmd(cfg, io), - newDeleteCmd(cfg, io), - newGenerateCmd(cfg, io), - newExportCmd(cfg, io), - newImportCmd(cfg, io), - newListCmd(cfg, io), - newSignCmd(cfg, io), - newVerifyCmd(cfg, io), - newQueryCmd(cfg, io), - newBroadcastCmd(cfg, io), - newMakeTxCmd(cfg, io), + NewAddCmd(cfg, io), + NewDeleteCmd(cfg, io), + NewGenerateCmd(cfg, io), + NewExportCmd(cfg, io), + NewImportCmd(cfg, io), + NewListCmd(cfg, io), + NewSignCmd(cfg, io), + NewVerifyCmd(cfg, io), + NewQueryCmd(cfg, io), + NewBroadcastCmd(cfg, io), + NewMakeTxCmd(cfg, io), ) return cmd } -func (c *baseCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *BaseCfg) RegisterFlags(fs *flag.FlagSet) { // Base options fs.StringVar( &c.Home, diff --git a/tm2/pkg/crypto/keys/client/send.go b/tm2/pkg/crypto/keys/client/send.go index a5098aea08c..a253f9d9f4e 100644 --- a/tm2/pkg/crypto/keys/client/send.go +++ b/tm2/pkg/crypto/keys/client/send.go @@ -14,16 +14,16 @@ import ( "github.com/gnolang/gno/tm2/pkg/std" ) -type sendCfg struct { - rootCfg *makeTxCfg +type MakeSendCfg struct { + RootCfg *MakeTxCfg - send string - to string + Send string + To string } -func newSendCmd(rootCfg *makeTxCfg, io commands.IO) *commands.Command { - cfg := &sendCfg{ - rootCfg: rootCfg, +func NewMakeSendCmd(rootCfg *MakeTxCfg, io commands.IO) *commands.Command { + cfg := &MakeSendCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -34,48 +34,48 @@ func newSendCmd(rootCfg *makeTxCfg, io commands.IO) *commands.Command { }, cfg, func(_ context.Context, args []string) error { - return execSend(cfg, args, io) + return execMakeSend(cfg, args, io) }, ) } -func (c *sendCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *MakeSendCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( - &c.send, + &c.Send, "send", "", "send amount", ) fs.StringVar( - &c.to, + &c.To, "to", "", "destination address", ) } -func execSend(cfg *sendCfg, args []string, io commands.IO) error { +func execMakeSend(cfg *MakeSendCfg, args []string, io commands.IO) error { if len(args) != 1 { return flag.ErrHelp } - if cfg.rootCfg.gasWanted == 0 { + if cfg.RootCfg.GasWanted == 0 { return errors.New("gas-wanted not specified") } - if cfg.rootCfg.gasFee == "" { + if cfg.RootCfg.GasFee == "" { return errors.New("gas-fee not specified") } - if cfg.send == "" { + if cfg.Send == "" { return errors.New("send (amount) must be specified") } - if cfg.to == "" { + if cfg.To == "" { return errors.New("to (destination address) must be specified") } // read account pubkey. nameOrBech32 := args[0] - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.rootCfg.Home) + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.RootCfg.Home) if err != nil { return err } @@ -87,20 +87,20 @@ func execSend(cfg *sendCfg, args []string, io commands.IO) error { // info.GetPubKey() // Parse to address. - toAddr, err := crypto.AddressFromBech32(cfg.to) + toAddr, err := crypto.AddressFromBech32(cfg.To) if err != nil { return err } // Parse send amount. - send, err := std.ParseCoins(cfg.send) + send, err := std.ParseCoins(cfg.Send) if err != nil { return errors.Wrap(err, "parsing send coins") } // parse gas wanted & fee. - gaswanted := cfg.rootCfg.gasWanted - gasfee, err := std.ParseCoin(cfg.rootCfg.gasFee) + gaswanted := cfg.RootCfg.GasWanted + gasfee, err := std.ParseCoin(cfg.RootCfg.GasFee) if err != nil { return errors.Wrap(err, "parsing gas fee coin") } @@ -115,11 +115,11 @@ func execSend(cfg *sendCfg, args []string, io commands.IO) error { Msgs: []std.Msg{msg}, Fee: std.NewFee(gaswanted, gasfee), Signatures: nil, - Memo: cfg.rootCfg.memo, + Memo: cfg.RootCfg.Memo, } - if cfg.rootCfg.broadcast { - err := signAndBroadcast(cfg.rootCfg, args, tx, io) + if cfg.RootCfg.Broadcast { + err := ExecSignAndBroadcast(cfg.RootCfg, args, tx, io) if err != nil { return err } diff --git a/tm2/pkg/crypto/keys/client/sign.go b/tm2/pkg/crypto/keys/client/sign.go index f8fcc02fdde..19022eaba81 100644 --- a/tm2/pkg/crypto/keys/client/sign.go +++ b/tm2/pkg/crypto/keys/client/sign.go @@ -2,7 +2,6 @@ package client import ( "context" - "errors" "flag" "fmt" "os" @@ -10,27 +9,26 @@ import ( "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/crypto/keys" + "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/std" ) -type signCfg struct { - rootCfg *baseCfg - - txPath string - chainID string - accountNumber uint64 - sequence uint64 - showSignBytes bool - - // internal flags, when called programmatically - nameOrBech32 string - txJSON []byte - pass string +type SignCfg struct { + RootCfg *BaseCfg + + TxPath string + ChainID string + AccountNumber uint64 + Sequence uint64 + ShowSignBytes bool + NameOrBech32 string + TxJSON []byte + Pass string } -func newSignCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &signCfg{ - rootCfg: rootCfg, +func NewSignCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &SignCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -46,54 +44,54 @@ func newSignCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *signCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *SignCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( - &c.txPath, + &c.TxPath, "txpath", "-", "path to file of tx to sign", ) fs.StringVar( - &c.chainID, + &c.ChainID, "chainid", "dev", "chainid to sign for", ) fs.Uint64Var( - &c.accountNumber, + &c.AccountNumber, "number", 0, "account number to sign with (required)", ) fs.Uint64Var( - &c.sequence, + &c.Sequence, "sequence", 0, "sequence to sign with (required)", ) fs.BoolVar( - &c.showSignBytes, + &c.ShowSignBytes, "show-signbytes", false, "show sign bytes and quit", ) } -func execSign(cfg *signCfg, args []string, io commands.IO) error { +func execSign(cfg *SignCfg, args []string, io commands.IO) error { var err error if len(args) != 1 { return flag.ErrHelp } - cfg.nameOrBech32 = args[0] + cfg.NameOrBech32 = args[0] // read tx to sign - txpath := cfg.txPath + txpath := cfg.TxPath if txpath == "-" { // from stdin. txjsonstr, err := io.GetString( "Enter tx to sign, terminated by a newline.", @@ -101,23 +99,23 @@ func execSign(cfg *signCfg, args []string, io commands.IO) error { if err != nil { return err } - cfg.txJSON = []byte(txjsonstr) + cfg.TxJSON = []byte(txjsonstr) } else { // from file - cfg.txJSON, err = os.ReadFile(txpath) + cfg.TxJSON, err = os.ReadFile(txpath) if err != nil { return err } } - if cfg.rootCfg.Quiet { - cfg.pass, err = io.GetPassword( + if cfg.RootCfg.Quiet { + cfg.Pass, err = io.GetPassword( "", - cfg.rootCfg.InsecurePasswordStdin, + cfg.RootCfg.InsecurePasswordStdin, ) } else { - cfg.pass, err = io.GetPassword( + cfg.Pass, err = io.GetPassword( "Enter password.", - cfg.rootCfg.InsecurePasswordStdin, + cfg.RootCfg.InsecurePasswordStdin, ) } if err != nil { @@ -138,20 +136,20 @@ func execSign(cfg *signCfg, args []string, io commands.IO) error { return nil } -func SignHandler(cfg *signCfg) (*std.Tx, error) { +func SignHandler(cfg *SignCfg) (*std.Tx, error) { var err error var tx std.Tx - if cfg.txJSON == nil { + if cfg.TxJSON == nil { return nil, errors.New("invalid tx content") } - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.Home) + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.Home) if err != nil { return nil, err } - err = amino.UnmarshalJSON(cfg.txJSON, &tx) + err = amino.UnmarshalJSON(cfg.TxJSON, &tx) if err != nil { return nil, err } @@ -174,16 +172,16 @@ func SignHandler(cfg *signCfg) (*std.Tx, error) { } // derive sign doc bytes. - chainID := cfg.chainID - accountNumber := cfg.accountNumber - sequence := cfg.sequence + chainID := cfg.ChainID + accountNumber := cfg.AccountNumber + sequence := cfg.Sequence signbz := tx.GetSignBytes(chainID, accountNumber, sequence) - if cfg.showSignBytes { + if cfg.ShowSignBytes { fmt.Printf("sign bytes: %X\n", signbz) return nil, nil } - sig, pub, err := kb.Sign(cfg.nameOrBech32, cfg.pass, signbz) + sig, pub, err := kb.Sign(cfg.NameOrBech32, cfg.Pass, signbz) if err != nil { return nil, err } @@ -201,7 +199,7 @@ func SignHandler(cfg *signCfg) (*std.Tx, error) { } if !found { return nil, errors.New( - fmt.Sprintf("addr %v (%s) not in signer set", addr, cfg.nameOrBech32), + fmt.Sprintf("addr %v (%s) not in signer set", addr, cfg.NameOrBech32), ) } diff --git a/tm2/pkg/crypto/keys/client/sign_test.go b/tm2/pkg/crypto/keys/client/sign_test.go index 6e9b1da5946..0d73d247637 100644 --- a/tm2/pkg/crypto/keys/client/sign_test.go +++ b/tm2/pkg/crypto/keys/client/sign_test.go @@ -23,17 +23,17 @@ func Test_execSign(t *testing.T) { defer kbCleanUp() // initialize test options - cfg := &signCfg{ - rootCfg: &baseCfg{ + cfg := &SignCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ Home: kbHome, InsecurePasswordStdin: true, }, }, - txPath: "-", // stdin - chainID: "dev", - accountNumber: 0, - sequence: 0, + TxPath: "-", // stdin + ChainID: "dev", + AccountNumber: 0, + Sequence: 0, } fakeKeyName1 := "signApp_Key1" @@ -43,7 +43,7 @@ func Test_execSign(t *testing.T) { io := commands.NewTestIO() // add test account to keybase. - kb, err := keys.NewKeyBaseFromDir(cfg.rootCfg.Home) + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.Home) assert.NoError(t, err) acc, err := kb.CreateAccount(fakeKeyName1, testMnemonic, "", encPassword, 0, 0) addr := acc.GetAddress() diff --git a/tm2/pkg/crypto/keys/client/verify.go b/tm2/pkg/crypto/keys/client/verify.go index fff2fcd852f..5a52ba76a3c 100644 --- a/tm2/pkg/crypto/keys/client/verify.go +++ b/tm2/pkg/crypto/keys/client/verify.go @@ -10,15 +10,15 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto/keys" ) -type verifyCfg struct { - rootCfg *baseCfg +type VerifyCfg struct { + RootCfg *BaseCfg - docPath string + DocPath string } -func newVerifyCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { - cfg := &verifyCfg{ - rootCfg: rootCfg, +func NewVerifyCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &VerifyCfg{ + RootCfg: rootCfg, } return commands.NewCommand( @@ -34,16 +34,16 @@ func newVerifyCmd(rootCfg *baseCfg, io commands.IO) *commands.Command { ) } -func (c *verifyCfg) RegisterFlags(fs *flag.FlagSet) { +func (c *VerifyCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( - &c.docPath, + &c.DocPath, "docpath", "", "path of document file to verify", ) } -func execVerify(cfg *verifyCfg, args []string, io commands.IO) error { +func execVerify(cfg *VerifyCfg, args []string, io commands.IO) error { var ( kb keys.Keybase err error @@ -58,8 +58,8 @@ func execVerify(cfg *verifyCfg, args []string, io commands.IO) error { if err != nil { return err } - docpath := cfg.docPath - kb, err = keys.NewKeyBaseFromDir(cfg.rootCfg.Home) + docpath := cfg.DocPath + kb, err = keys.NewKeyBaseFromDir(cfg.RootCfg.Home) if err != nil { return err } diff --git a/tm2/pkg/crypto/keys/client/verify_test.go b/tm2/pkg/crypto/keys/client/verify_test.go index 206c14682fd..796f6344852 100644 --- a/tm2/pkg/crypto/keys/client/verify_test.go +++ b/tm2/pkg/crypto/keys/client/verify_test.go @@ -21,14 +21,14 @@ func Test_execVerify(t *testing.T) { defer kbCleanUp() // initialize test options - cfg := &verifyCfg{ - rootCfg: &baseCfg{ + cfg := &VerifyCfg{ + RootCfg: &BaseCfg{ BaseOptions: BaseOptions{ Home: kbHome, InsecurePasswordStdin: true, }, }, - docPath: "", + DocPath: "", } io := commands.NewTestIO()