diff --git a/gno.land/pkg/integration/doc.go b/gno.land/pkg/integration/doc.go index 08ff699539f..bea0fe78349 100644 --- a/gno.land/pkg/integration/doc.go +++ b/gno.land/pkg/integration/doc.go @@ -23,7 +23,11 @@ // - Must be run before `gnoland start`. // - Creates a new user in the default keybase directory. // -// 4. `loadpkg`: +// 4. `adduserfrom`: +// - Must be run before `gnoland start`. +// - Creates a new user in the default keybase directory from a given seed. ( Optionally, account and index can be provided ) +// +// 5. `loadpkg`: // - Must be run before `gnoland start`. // - Loads a specific package from the 'examples' directory or from the working ($WORK) directory. // - Can be used to load a single package or all packages within a directory. diff --git a/gno.land/pkg/integration/testdata/adduserfrom.txtar b/gno.land/pkg/integration/testdata/adduserfrom.txtar new file mode 100644 index 00000000000..a23849aa604 --- /dev/null +++ b/gno.land/pkg/integration/testdata/adduserfrom.txtar @@ -0,0 +1,34 @@ +# adduserfrom just mnemonic +adduserfrom user1 'source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast' +stdout 'g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5' + +# adduserfrom mnemonic and account +adduserfrom user2 'source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast' 1 +stdout 'g18e22n23g462drp4pyszyl6e6mwxkaylthgeeq4' + +# adduserfrom mnemonic, account and index +adduserfrom user3 'source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast' 1 1 +stdout 'g1mtmrdmqfu0aryqfl4aw65n35haw2wdjkh5p4cp' + +## start a new node +gnoland start + +## check users initial balance +gnokey query bank/balances/${USER_ADDR_user1} +stdout '10000000ugnot' + +gnokey query bank/balances/g18e22n23g462drp4pyszyl6e6mwxkaylthgeeq4 +stdout '10000000ugnot' + +gnokey query auth/accounts/${USER_ADDR_user3} +stdout 'height: 0' +stdout 'data: {' +stdout ' "BaseAccount": {' +stdout ' "address": "g1mtmrdmqfu0aryqfl4aw65n35haw2wdjkh5p4cp",' +stdout ' "coins": "10000000ugnot",' +stdout ' "public_key": null,' +stdout ' "account_number": "58",' +stdout ' "sequence": "0"' +stdout ' }' +stdout '}' +! stderr '.+' # empty \ No newline at end of file diff --git a/gno.land/pkg/integration/testing_integration.go b/gno.land/pkg/integration/testing_integration.go index d8c03137763..654dda0b45e 100644 --- a/gno.land/pkg/integration/testing_integration.go +++ b/gno.land/pkg/integration/testing_integration.go @@ -168,7 +168,7 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params { break } - // get pacakges + // get packages pkgs := ts.Value(envKeyPkgsLoader).(*pkgsLoader) // grab logger creator := crypto.MustAddressFromString(DefaultAccount_Address) // test1 defaultFee := std.NewFee(50000, std.MustParseCoin("1000000ugnot")) @@ -193,7 +193,7 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params { // Register cleanup nodes[sid] = &testNode{Node: n} - // Add default environements + // Add default environments ts.Setenv("RPC_ADDR", remoteAddr) fmt.Fprintln(ts.Stdout(), "node started successfully") @@ -206,7 +206,7 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params { if err = n.Stop(); err == nil { delete(nodes, sid) - // Unset gnoland environements + // Unset gnoland environments ts.Setenv("RPC_ADDR", "") fmt.Fprintln(ts.Stdout(), "node stopped successfully") } @@ -284,6 +284,61 @@ func setupGnolandTestScript(t *testing.T, txtarDir string) testscript.Params { genesis := ts.Value(envKeyGenesis).(*gnoland.GnoGenesisState) genesis.Balances = append(genesis.Balances, balance) }, + // adduserfrom commands must be executed before starting the node; it errors out otherwise. + "adduserfrom": func(ts *testscript.TestScript, neg bool, args []string) { + if nodeIsRunning(nodes, getNodeSID(ts)) { + tsValidateError(ts, "adduserfrom", neg, errors.New("adduserfrom must be used before starting node")) + return + } + + var account, index uint64 + var err error + + switch len(args) { + case 2: + // expected user input + // adduserfrom 'username 'menmonic' + // no need to do anything + + case 4: + // expected user input + // adduserfrom 'username 'menmonic' 'account' 'index' + + // parse 'index' first, then fallghrough to `case 3` to parse 'account' + index, err = strconv.ParseUint(args[3], 10, 32) + if err != nil { + ts.Fatalf("invalid index number %s", args[3]) + } + + fallthrough // parse 'account' + case 3: + // expected user input + // adduserfrom 'username 'menmonic' 'account' + + account, err = strconv.ParseUint(args[2], 10, 32) + if err != nil { + ts.Fatalf("invalid account number %s", args[2]) + } + default: + ts.Fatalf("to create account from metadatas, user name and mnemonic are required ( account and index are optional )") + } + + kb, err := keys.NewKeyBaseFromDir(gnoHomeDir) + if err != nil { + ts.Fatalf("unable to get keybase") + } + + balance, err := createAccountFrom(ts, kb, args[0], args[1], uint32(account), uint32(index)) + if err != nil { + ts.Fatalf("error creating wallet %s", err) + } + + // Add balance to genesis + genesis := ts.Value(envKeyGenesis).(*gnoland.GnoGenesisState) + genesis.Balances = append(genesis.Balances, balance) + + fmt.Fprintf(ts.Stdout(), "Added %s(%s) to genesis", args[0], balance.Address) + }, // `loadpkg` load a specific package from the 'examples' or working directory "loadpkg": func(ts *testscript.TestScript, neg bool, args []string) { // special dirs @@ -493,6 +548,30 @@ func createAccount(env envSetter, kb keys.Keybase, accountName string) (gnoland. }, nil } +// createAccountFrom creates a new account with the given metadata and adds it to the keybase. +func createAccountFrom(env envSetter, kb keys.Keybase, accountName, mnemonic string, account, index uint32) (gnoland.Balance, error) { + var balance gnoland.Balance + + // check if mnemonic is valid + if !bip39.IsMnemonicValid(mnemonic) { + return balance, fmt.Errorf("invalid mnemonic") + } + + keyInfo, err := kb.CreateAccount(accountName, mnemonic, "", "", account, index) + if err != nil { + return balance, fmt.Errorf("unable to create account: %w", err) + } + + address := keyInfo.GetAddress() + env.Setenv("USER_SEED_"+accountName, mnemonic) + env.Setenv("USER_ADDR_"+accountName, address.String()) + + return gnoland.Balance{ + Address: address, + Amount: std.Coins{std.NewCoin("ugnot", 10e6)}, + }, nil +} + type pkgsLoader struct { pkgs []gnomod.Pkg visited map[string]struct{}