From 5b29a509cd6c94fcc83aaadc88e8f538ae2aeb5b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 25 Jun 2018 17:37:10 -0400 Subject: [PATCH 01/77] gaiadebug: support bech32 --- cmd/gaia/cmd/gaiadebug/main.go | 93 +++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/cmd/gaia/cmd/gaiadebug/main.go b/cmd/gaia/cmd/gaiadebug/main.go index 79045c07bb..a3d3cac066 100644 --- a/cmd/gaia/cmd/gaiadebug/main.go +++ b/cmd/gaia/cmd/gaiadebug/main.go @@ -11,6 +11,7 @@ import ( "strings" gaia "github.com/cosmos/cosmos-sdk/cmd/gaia/app" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/spf13/cobra" crypto "github.com/tendermint/go-crypto" @@ -19,6 +20,7 @@ import ( func init() { rootCmd.AddCommand(txCmd) rootCmd.AddCommand(pubkeyCmd) + rootCmd.AddCommand(addrCmd) rootCmd.AddCommand(hackCmd) rootCmd.AddCommand(rawBytesCmd) } @@ -37,10 +39,16 @@ var txCmd = &cobra.Command{ var pubkeyCmd = &cobra.Command{ Use: "pubkey", - Short: "Decode a pubkey from hex or base64", + Short: "Decode a pubkey from hex, base64, or bech32", RunE: runPubKeyCmd, } +var addrCmd = &cobra.Command{ + Use: "addr", + Short: "Convert an address between hex and bech32", + RunE: runAddrCmd, +} + var hackCmd = &cobra.Command{ Use: "hack", Short: "Boilerplate to Hack on an existing state by scripting some Go...", @@ -80,30 +88,103 @@ func runPubKeyCmd(cmd *cobra.Command, args []string) error { } pubkeyString := args[0] + var pubKeyI crypto.PubKey - // try hex, then base64 + // try hex, then base64, then bech32 pubkeyBytes, err := hex.DecodeString(pubkeyString) if err != nil { var err2 error pubkeyBytes, err2 = base64.StdEncoding.DecodeString(pubkeyString) if err2 != nil { - return fmt.Errorf(`Expected hex or base64. Got errors: + var err3 error + pubKeyI, err3 = sdk.GetAccPubKeyBech32(pubkeyString) + if err3 != nil { + var err4 error + pubKeyI, err4 = sdk.GetValPubKeyBech32(pubkeyString) + + if err4 != nil { + return fmt.Errorf(`Expected hex, base64, or bech32. Got errors: hex: %v, base64: %v - `, err, err2) + bech32 acc: %v + bech32 val: %v + `, err, err2, err3, err4) + + } + } + } } - cdc := gaia.MakeCodec() var pubKey crypto.PubKeyEd25519 - copy(pubKey[:], pubkeyBytes) + if pubKeyI == nil { + copy(pubKey[:], pubkeyBytes) + } else { + pubKey = pubKeyI.(crypto.PubKeyEd25519) + pubkeyBytes = pubKey[:] + } + + cdc := gaia.MakeCodec() pubKeyJSONBytes, err := cdc.MarshalJSON(pubKey) if err != nil { return err } + accPub, err := sdk.Bech32ifyAccPub(pubKey) + if err != nil { + return err + } + valPub, err := sdk.Bech32ifyValPub(pubKey) + if err != nil { + return err + } fmt.Println("Address:", pubKey.Address()) fmt.Printf("Hex: %X\n", pubkeyBytes) fmt.Println("JSON (base64):", string(pubKeyJSONBytes)) + fmt.Println("Bech32 Acc:", accPub) + fmt.Println("Bech32 Val:", valPub) + return nil +} + +func runAddrCmd(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return fmt.Errorf("Expected single arg") + } + + addrString := args[0] + var addr sdk.Address + + // try hex, then bech32 + var err error + addr, err = hex.DecodeString(addrString) + if err != nil { + var err2 error + addr, err2 = sdk.GetAccAddressBech32(addrString) + if err2 != nil { + var err3 error + addr, err3 = sdk.GetValAddressBech32(addrString) + + if err3 != nil { + return fmt.Errorf(`Expected hex or bech32. Got errors: + hex: %v, + bech32 acc: %v + bech32 val: %v + `, err, err2, err3) + + } + } + } + + accAddr, err := sdk.Bech32ifyAcc(addr) + if err != nil { + return err + } + valAddr, err := sdk.Bech32ifyVal(addr) + if err != nil { + return err + } + fmt.Println("Address:", addr) + fmt.Println("Bech32 Acc:", accAddr) + fmt.Println("Bech32 Val:", valAddr) return nil } From 9233e357166d894936f0ab54be5573498eb56a3e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 25 Jun 2018 21:55:23 -0400 Subject: [PATCH 02/77] example app1 --- docs/core/examples/app1/main.go | 167 ++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 docs/core/examples/app1/main.go diff --git a/docs/core/examples/app1/main.go b/docs/core/examples/app1/main.go new file mode 100644 index 0000000000..59cc39e08c --- /dev/null +++ b/docs/core/examples/app1/main.go @@ -0,0 +1,167 @@ +package app + +import ( + "encoding/json" + "reflect" + + cmn "github.com/tendermint/tmlibs/common" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" + + bapp "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" +) + +const ( + appName = "MyApp" +) + +func NewApp(logger log.Logger, db dbm.DB) *bapp.BaseApp { + + // TODO: make this an interface or pass in + // a TxDecoder instead. + cdc := wire.NewCodec() + + // Create the base application object. + app := bapp.NewBaseApp(appName, cdc, logger, db) + + // Create a key for accessing the account store. + keyAccount := sdk.NewKVStoreKey("acc") + + // Determine how transactions are decoded. + app.SetTxDecoder(txDecoder) + + // Register message routes. + // Note the handler gets access to the account store. + app.Router(). + AddRoute("bank", NewHandler(keyAccount)) + + // Mount stores and load the latest state. + app.MountStoresIAVL(keyAccount) + err := app.LoadLatestVersion(keyAccount) + if err != nil { + cmn.Exit(err.Error()) + } + return app +} + +//------------------------------------------------------------------ +// Msg + +// MsgSend implements sdk.Msg +var _ sdk.Msg = MsgSend{} + +// MsgSend to send coins from Input to Output +type MsgSend struct { + From sdk.Address `json:"from"` + To sdk.Address `json:"to"` + Amount sdk.Coins `json:"amount"` +} + +// NewMsgSend +func NewMsgSend(from, to sdk.Address, amt sdk.Coins) MsgSend { + return MsgSend{from, to, amt} +} + +// Implements Msg. +func (msg MsgSend) Type() string { return "bank" } + +// Implements Msg. Ensure the addresses are good and the +// amount is positive. +func (msg MsgSend) ValidateBasic() sdk.Error { + if len(msg.From) == 0 { + return sdk.ErrInvalidAddress("From address is empty") + } + if len(msg.To) == 0 { + return sdk.ErrInvalidAddress("To address is empty") + } + if !msg.Amount.IsPositive() { + return sdk.ErrInvalidCoins("Amount is not positive") + } + return nil +} + +// Implements Msg. JSON encode the message. +func (msg MsgSend) GetSignBytes() []byte { + bz, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return bz +} + +// Implements Msg. Return the signer. +func (msg MsgSend) GetSigners() []sdk.Address { + return []sdk.Address{msg.From} +} + +//------------------------------------------------------------------ +// Handler for the message + +func NewHandler(keyAcc *sdk.KVStoreKey) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgSend: + return handleMsgSend(ctx, keyAcc, msg) + default: + errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +// Handle MsgSend. +func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result { + // NOTE: from, to, and amount were already validated + + store := ctx.KVStore(key) + bz := store.Get(msg.From) + if bz == nil { + // TODO + } + + var acc acc + err := json.Unmarshal(bz, &acc) + if err != nil { + // InternalError + } + + // TODO: finish the logic + + return sdk.Result{ + // TODO: Tags + } +} + +type acc struct { + Coins sdk.Coins `json:"coins"` +} + +//------------------------------------------------------------------ +// Tx + +// Simple tx to wrap the Msg. +type tx struct { + MsgSend +} + +// This tx only has one Msg. +func (tx tx) GetMsgs() []sdk.Msg { + return []sdk.Msg{tx.MsgSend} +} + +// TODO: remove the need for this +func (tx tx) GetMemo() string { + return "" +} + +// JSON decode MsgSend. +func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx tx + err := json.Unmarshal(txBytes, &tx) + if err != nil { + return nil, sdk.ErrTxDecode(err.Error()) + } + return tx, nil +} From 7e50e7d125aab130044c4a5193299a04168745d6 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 25 Jun 2018 22:30:20 -0400 Subject: [PATCH 03/77] docs: update readme structure with example apps --- docs/README.md | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/docs/README.md b/docs/README.md index 38609c5850..c70176053d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,18 +9,27 @@ NOTE: This documentation is a work-in-progress! - [Application Architecture](overview/apps.md) - Layers in the application architecture - [Install](install.md) - Install the library and example applications - [Core](core) - - [Messages](core/messages.md) - Messages contain the content of a transaction - - [Handlers](core/handlers.md) - Handlers are the workhorse of the app! - - [BaseApp](core/baseapp.md) - BaseApp is the base layer of the application - - [The MultiStore](core/multistore.md) - MultiStore is a rich Merkle database - - [Amino](core/amino.md) - Amino is the primary serialization library used in the SDK - - [Accounts](core/accounts.md) - Accounts are the prototypical object kept in the store - - [Transactions](core/transactions.md) - Transactions wrap messages and provide authentication - - [Keepers](core/keepers.md) - Keepers are the interfaces between handlers - - [Clients](core/clients.md) - Hook up your app to standard CLI and REST - interfaces for clients to use! - - [Advanced](core/advanced.md) - Trigger logic on a timer, use custom - serialization formats, advanced Merkle proofs, and more! + - [Introduction](core/intro.md) - Intro to the tutorial + - [App1 - The Basics](core/app1.md) + - [Messages](core/app1.md#messages) - Messages contain the content of a transaction + - [Handlers](core/app1.md#handlers) - Handlers are the workhorse of the app! + - [BaseApp](core/app1.md#baseapp) - BaseApp is the base layer of the application + - [The MultiStore](core/app1.md#multistore) - MultiStore is a rich Merkle database + - [App2 - Amino](core/app2.md) + - [Amino](core/app2.md#amino) - Amino is the primary serialization library used in the SDK + - [App3 - Authentication](core/app3.md) + - [Accounts](core/app3.md#accounts) - Accounts are the prototypical object kept in the store + - [Transactions](core/app3.md#transactions) - Transactions wrap messages and provide authentication + - [App4 - Modules and Keepers](core/app4.md) + - [Keepers](core/app4.md#keepers) - Keepers are the interfaces between handlers + - [App5 - Advanced](core/app5.md) + - [Validator Set Changes](core/app5.md#validators) - Change the + validator set + - [App6 - Basecoin](core/app6.md) - + - [Directory Structure](core/app6.md#directory-structure) - Keep your + application code organized + - [Clients](core/app6.md#clients) - Hook up your app to standard CLI and REST + interfaces for clients to use! - [Modules](modules) - [Bank](modules/bank.md) From 234d7498de03e98c10669b79ffcd6ae6b1a7fcc0 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 25 Jun 2018 22:43:57 -0400 Subject: [PATCH 04/77] docs/examples: templates for more examples --- docs/core/examples/{app1/main.go => app1.go} | 18 ++-- docs/core/examples/app2.go | 87 ++++++++++++++++++++ docs/core/examples/app3.go | 50 +++++++++++ docs/core/examples/app4.go | 49 +++++++++++ 4 files changed, 195 insertions(+), 9 deletions(-) rename docs/core/examples/{app1/main.go => app1.go} (90%) create mode 100644 docs/core/examples/app2.go create mode 100644 docs/core/examples/app3.go create mode 100644 docs/core/examples/app4.go diff --git a/docs/core/examples/app1/main.go b/docs/core/examples/app1.go similarity index 90% rename from docs/core/examples/app1/main.go rename to docs/core/examples/app1.go index 59cc39e08c..09c9aa134b 100644 --- a/docs/core/examples/app1/main.go +++ b/docs/core/examples/app1.go @@ -14,17 +14,17 @@ import ( ) const ( - appName = "MyApp" + app1Name = "App1" ) -func NewApp(logger log.Logger, db dbm.DB) *bapp.BaseApp { +func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { // TODO: make this an interface or pass in // a TxDecoder instead. cdc := wire.NewCodec() // Create the base application object. - app := bapp.NewBaseApp(appName, cdc, logger, db) + app := bapp.NewBaseApp(app1Name, cdc, logger, db) // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") @@ -35,7 +35,7 @@ func NewApp(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewHandler(keyAccount)) + AddRoute("bank", NewApp1Handler(keyAccount)) // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount) @@ -99,7 +99,7 @@ func (msg MsgSend) GetSigners() []sdk.Address { //------------------------------------------------------------------ // Handler for the message -func NewHandler(keyAcc *sdk.KVStoreKey) sdk.Handler { +func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case MsgSend: @@ -142,23 +142,23 @@ type acc struct { // Tx // Simple tx to wrap the Msg. -type tx struct { +type app1Tx struct { MsgSend } // This tx only has one Msg. -func (tx tx) GetMsgs() []sdk.Msg { +func (tx app1Tx) GetMsgs() []sdk.Msg { return []sdk.Msg{tx.MsgSend} } // TODO: remove the need for this -func (tx tx) GetMemo() string { +func (tx app1Tx) GetMemo() string { return "" } // JSON decode MsgSend. func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx tx + var tx app1Tx err := json.Unmarshal(txBytes, &tx) if err != nil { return nil, sdk.ErrTxDecode(err.Error()) diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go new file mode 100644 index 0000000000..fec259ca99 --- /dev/null +++ b/docs/core/examples/app2.go @@ -0,0 +1,87 @@ +package app + +import ( + "reflect" + + cmn "github.com/tendermint/tmlibs/common" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" + + bapp "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" +) + +const ( + app2Name = "App2" +) + +func NewCodec() *wire.Codec { + // TODO register + return nil +} + +func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { + + cdc := NewCodec() + + // Create the base application object. + app := bapp.NewBaseApp(app2Name, cdc, logger, db) + + // Create a key for accessing the account store. + keyAccount := sdk.NewKVStoreKey("acc") + keyIssuer := sdk.NewKVStoreKey("issuer") + + // Register message routes. + // Note the handler gets access to the account store. + app.Router(). + AddRoute("bank", NewApp2Handler(keyAccount, keyIssuer)) + + // Mount stores and load the latest state. + app.MountStoresIAVL(keyAccount, keyIssuer) + err := app.LoadLatestVersion(keyAccount) + if err != nil { + cmn.Exit(err.Error()) + } + return app +} + +//------------------------------------------------------------------ +// Msgs + +// TODO: MsgIssue + +//------------------------------------------------------------------ +// Handler for the message + +func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgSend: + return handleMsgSend(ctx, keyAcc, msg) + case MsgIssue: + // TODO + default: + errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +//------------------------------------------------------------------ +// Tx + +// Simple tx to wrap the Msg. +type app2Tx struct { + sdk.Msg +} + +// This tx only has one Msg. +func (tx app2Tx) GetMsgs() []sdk.Msg { + return []sdk.Msg{tx.Msg} +} + +// TODO: remove the need for this +func (tx app2Tx) GetMemo() string { + return "" +} diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go new file mode 100644 index 0000000000..b176816b75 --- /dev/null +++ b/docs/core/examples/app3.go @@ -0,0 +1,50 @@ +package app + +import ( + cmn "github.com/tendermint/tmlibs/common" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" + + bapp "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + app3Name = "App3" +) + +func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { + + cdc := NewCodec() + + // Create the base application object. + app := bapp.NewBaseApp(app3Name, cdc, logger, db) + + // Create a key for accessing the account store. + keyAccount := sdk.NewKVStoreKey("acc") + keyIssuer := sdk.NewKVStoreKey("issuer") + + // TODO: accounts, ante handler + + // Register message routes. + // Note the handler gets access to the account store. + app.Router(). + AddRoute("bank", NewApp2Handler(keyAccount, keyIssuer)) + + // Mount stores and load the latest state. + app.MountStoresIAVL(keyAccount, keyIssuer) + err := app.LoadLatestVersion(keyAccount) + if err != nil { + cmn.Exit(err.Error()) + } + return app +} + +//------------------------------------------------------------------ +// StdTx + +//------------------------------------------------------------------ +// Account + +//------------------------------------------------------------------ +// Ante Handler diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go new file mode 100644 index 0000000000..ae63b4afba --- /dev/null +++ b/docs/core/examples/app4.go @@ -0,0 +1,49 @@ +package app + +import ( + cmn "github.com/tendermint/tmlibs/common" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" + + bapp "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + app4Name = "App4" +) + +func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { + + cdc := NewCodec() + + // Create the base application object. + app := bapp.NewBaseApp(app4Name, cdc, logger, db) + + // Create a key for accessing the account store. + keyAccount := sdk.NewKVStoreKey("acc") + keyIssuer := sdk.NewKVStoreKey("issuer") + + // TODO: accounts, ante handler + + // TODO: AccountMapper, CoinKeepr + + // Register message routes. + // Note the handler gets access to the account store. + app.Router(). + AddRoute("bank", NewApp2Handler(keyAccount, keyIssuer)) + + // Mount stores and load the latest state. + app.MountStoresIAVL(keyAccount, keyIssuer) + err := app.LoadLatestVersion(keyAccount) + if err != nil { + cmn.Exit(err.Error()) + } + return app +} + +//------------------------------------------------------------------ +// AccountMapper + +//------------------------------------------------------------------ +// CoinsKeeper From 05db92f154790118047899d7994c2ed62792add4 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Tue, 26 Jun 2018 11:12:44 -0700 Subject: [PATCH 05/77] Added handler to app1 --- docs/core/examples/app1.go | 56 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index 09c9aa134b..fbbfb575c2 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -116,25 +116,75 @@ func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result // NOTE: from, to, and amount were already validated store := ctx.KVStore(key) + + // deduct msg amount from sender account bz := store.Get(msg.From) if bz == nil { - // TODO + // Account was not added to store. Return the result of the error. + return sdk.NewError(2, 101, "Account not added to store").Result() } - var acc acc + var acc account err := json.Unmarshal(bz, &acc) if err != nil { // InternalError + return sdk.ErrInternal("Error when deserializing account").Result() } // TODO: finish the logic + senderCoins := acc.Coins.Minus(msg.Amount) + + // If any coin has negative amount, return insufficient coins error. + if !senderCoins.IsNotNegative() { + return sdk.ErrInsufficientCoins("Insufficient coins in account").Result() + } + + // set acc coins to new amount + acc.Coins = senderCoins + + // Encode sender account + val, err := json.Marshal(acc) + if err != nil { + return sdk.ErrInternal("Account encoding error").Result() + } + + // Update store with updated sender account + store.Set(msg.From, val) + + // Add msg amount to receiver account + bz = store.Get(msg.To) + var acc2 account + if bz == nil { + // Sender account does not already exist, create a new one. + acc2 = account{} + } else { + // Sender account already exists. Retrieve and decode it. + err = json.Unmarshal(bz, &acc2) + if err != nil { + return sdk.ErrInternal("Account decoding error").Result() + } + } + + // Add amount to receiver's old coins + receiverCoins := acc2.Coins.Plus(msg.Amount) + + // Update receiver account + acc2.Coins = receiverCoins + + // Encode receiver account + val, err = json.Marshal(acc2) + if err != nil { + return sdk.ErrInternal("Account encoding error").Result() + } + + store.Set(msg.To, val) return sdk.Result{ // TODO: Tags } } -type acc struct { +type account struct { Coins sdk.Coins `json:"coins"` } From b3b075cc1265026c66f40e0e9b4c513f605c90c3 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 17:20:59 -0400 Subject: [PATCH 06/77] finish docs for app1 --- docs/README.md | 2 +- docs/core/app1.md | 392 ++++++++++++++++++++++++++++++++++++++++++++++ types/handler.go | 3 +- 3 files changed, 395 insertions(+), 2 deletions(-) create mode 100644 docs/core/app1.md diff --git a/docs/README.md b/docs/README.md index c70176053d..0ae1cc1162 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,9 +12,9 @@ NOTE: This documentation is a work-in-progress! - [Introduction](core/intro.md) - Intro to the tutorial - [App1 - The Basics](core/app1.md) - [Messages](core/app1.md#messages) - Messages contain the content of a transaction + - [Stores](core/app1.md#kvstore) - KVStore is a Merkle Key-Value store. - [Handlers](core/app1.md#handlers) - Handlers are the workhorse of the app! - [BaseApp](core/app1.md#baseapp) - BaseApp is the base layer of the application - - [The MultiStore](core/app1.md#multistore) - MultiStore is a rich Merkle database - [App2 - Amino](core/app2.md) - [Amino](core/app2.md#amino) - Amino is the primary serialization library used in the SDK - [App3 - Authentication](core/app3.md) diff --git a/docs/core/app1.md b/docs/core/app1.md new file mode 100644 index 0000000000..29a36fc30f --- /dev/null +++ b/docs/core/app1.md @@ -0,0 +1,392 @@ +# App1 + +The first application is a simple bank. Users have an account address and an account, +and they can send coins around. It has no authentication, and just uses JSON for +serialization. + +## Messages + +Messages are the primary inputs to the application state machine. +They define the content of transactions and can contain arbitrary information. +Developers can create messages by implementing the `Msg` interface: + +```go +type Msg interface { + + // Return the message type. + // Must be alphanumeric or empty. + // Must correspond to name of message handler (XXX). + Type() string + + // Get the canonical byte representation of the Msg. + // This is what is signed. + GetSignBytes() []byte + + // ValidateBasic does a simple validation check that + // doesn't require access to any other information. + ValidateBasic() error + + // Signers returns the addrs of signers that must sign. + // CONTRACT: All signatures must be present to be valid. + // CONTRACT: Returns addrs in some deterministic order. + GetSigners() []Address +} +``` + + +The `Msg` interface allows messages to define basic validity checks, as well as +what needs to be signed and who needs to sign it. + +Addresses in the SDK are arbitrary byte arrays that are hex-encoded when +displayed as a string or rendered in JSON. Typically, addresses are the hash of +a public key. + +For instance, take the simple token sending message type from app1.go: + +```go +// MsgSend to send coins from Input to Output +type MsgSend struct { + From sdk.Address `json:"from"` + To sdk.Address `json:"to"` + Amount sdk.Coins `json:"amount"` +} + +// Implements Msg. +func (msg MsgSend) Type() string { return "bank" } +``` + +It specifies that the message should be JSON marshaled and signed by the sender: + +```go +// Implements Msg. JSON encode the message. +func (msg MsgSend) GetSignBytes() []byte { + bz, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return bz +} + +// Implements Msg. Return the signer. +func (msg MsgSend) GetSigners() []sdk.Address { + return []sdk.Address{msg.From} +} +``` + +The basic validity check ensures the From and To address are specified and the +amount is positive: + +```go +// Implements Msg. Ensure the addresses are good and the +// amount is positive. +func (msg MsgSend) ValidateBasic() sdk.Error { + if len(msg.From) == 0 { + return sdk.ErrInvalidAddress("From address is empty") + } + if len(msg.To) == 0 { + return sdk.ErrInvalidAddress("To address is empty") + } + if !msg.Amount.IsPositive() { + return sdk.ErrInvalidCoins("Amount is not positive") + } + return nil +} +``` + +# KVStore + +The basic persistence layer for an SDK application is the KVStore: + +```go +type KVStore interface { + Store + + // Get returns nil iff key doesn't exist. Panics on nil key. + Get(key []byte) []byte + + // Has checks if a key exists. Panics on nil key. + Has(key []byte) bool + + // Set sets the key. Panics on nil key. + Set(key, value []byte) + + // Delete deletes the key. Panics on nil key. + Delete(key []byte) + + // Iterator over a domain of keys in ascending order. End is exclusive. + // Start must be less than end, or the Iterator is invalid. + // CONTRACT: No writes may happen within a domain while an iterator exists over it. + Iterator(start, end []byte) Iterator + + // Iterator over a domain of keys in descending order. End is exclusive. + // Start must be greater than end, or the Iterator is invalid. + // CONTRACT: No writes may happen within a domain while an iterator exists over it. + ReverseIterator(start, end []byte) Iterator + + // TODO Not yet implemented. + // CreateSubKVStore(key *storeKey) (KVStore, error) + + // TODO Not yet implemented. + // GetSubKVStore(key *storeKey) KVStore + } +``` + +Note it is unforgiving - it panics on nil keys! + +The primary implementation of the KVStore is currently the IAVL store. In the future, we plan to support other Merkle KVStores, +like Ethereum's radix trie. + +As we'll soon see, apps have many distinct KVStores, each with a different name and for a different concern. +Access to a store is mediated by *object-capability keys*, which must be granted to a handler during application startup. + +# Handlers + +Now that we have a message type and a store interface, we can define our state transition function using a handler: + +```go +// Handler defines the core of the state transition function of an application. +type Handler func(ctx Context, msg Msg) Result +``` + +Along with the message, the Handler takes environmental information (a `Context`), and returns a `Result`. + +Where is the KVStore in all of this? Access to the KVStore in a message handler is restricted by the Context via object-capability keys. +Only handlers which were given explict access to a store's key will be able to access that store during message processsing. + +## Context + +The SDK uses a `Context` to propogate common information across functions. +Most importantly, the `Context` restricts access to KVStores based on object-capability keys. +Only handlers which have been given explicit access to a key will be able to access the corresponding store. + +For instance, the FooHandler can only load the store it's given the key for: + +```go +// newFooHandler returns a Handler that can access a single store. +func newFooHandler(key sdk.StoreKey) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + store := ctx.KVStore(key) + // ... + } +} +``` + +`Context` is modeled after the Golang [context.Context](TODO), which has +become ubiquitous in networking middleware and routing applications as a means +to easily propogate request context through handler functions. +Many methods on SDK objects receive a context as the first argument. + +The Context also contains the [block header](TODO), which includes the latest timestamp from the blockchain and other information about the latest block. + +See the [Context API docs](TODO) for more details. + +## Result + +Result is motivated by the corresponding [ABCI result](TODO). It contains any return values, error information, logs, and meta data about the transaction: + +```go +// Result is the union of ResponseDeliverTx and ResponseCheckTx. +type Result struct { + + // Code is the response code, is stored back on the chain. + Code ABCICodeType + + // Data is any data returned from the app. + Data []byte + + // Log is just debug information. NOTE: nondeterministic. + Log string + + // GasWanted is the maximum units of work we allow this tx to perform. + GasWanted int64 + + // GasUsed is the amount of gas actually consumed. NOTE: unimplemented + GasUsed int64 + + // Tx fee amount and denom. + FeeAmount int64 + FeeDenom string + + // Tags are used for transaction indexing and pubsub. + Tags Tags +} +``` + +## Handler + +Let's define our handler for App1: + +```go +func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgSend: + return handleMsgSend(ctx, keyAcc, msg) + default: + errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} +``` + +We have only a single message type, so just one message-specific function to define, `handleMsgSend`. + +Note this handler has unfettered access to the store specified by the capability key `keyAcc`. So it must also define items in the store are encoded. +For this first example, we will define a simple account that is JSON encoded: + +```go +type acc struct { + Coins sdk.Coins `json:"coins"` +} +``` + +Coins is a useful type provided by the SDK for multi-asset accounts. While we could just use an integer here for a single coin type, +it's worth [getting to know `Coins`](TODO). + + +Now we're ready to handle the MsgSend: + +``` +// Handle MsgSend. +func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result { + // NOTE: from, to, and amount were already validated + + store := ctx.KVStore(key) + bz := store.Get(msg.From) + if bz == nil { + // TODO + } + + var acc acc + err := json.Unmarshal(bz, &acc) + if err != nil { + // InternalError + } + + // TODO: finish the logic + + return sdk.Result{ + // TODO: Tags + } +} +``` + +The handler is straight forward: + +- get the KVStore from the context using the granted capability key +- lookup the From address in the KVStore, and JSON unmarshal it into an `acc`, +- check that the account balance is greater than the `msg.Amount` +- transfer the `msg.Amount` + +And that's that! + +# BaseApp + +Finally, we stitch it all together using the `BaseApp`. + +The BaseApp is an abstraction over the [Tendermint +ABCI](https://github.com/tendermint/abci) that +simplifies application development by handling common low-level concerns. +It serves as the mediator between the two key components of an SDK app: the store +and the message handlers. + +The BaseApp implements the +[`abci.Application`](https://godoc.org/github.com/tendermint/abci/types#Application) interface. +It uses a `MultiStore` to manage the state, a `Router` for transaction handling, and +`Set` methods to specify functions to run at the beginning and end of every +block. It's quite a work of art :). + + +Here is the complete setup for App1: + +```go +func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { + + // TODO: make this an interface or pass in + // a TxDecoder instead. + cdc := wire.NewCodec() + + // Create the base application object. + app := bapp.NewBaseApp(app1Name, cdc, logger, db) + + // Create a key for accessing the account store. + keyAccount := sdk.NewKVStoreKey("acc") + + // Determine how transactions are decoded. + app.SetTxDecoder(txDecoder) + + // Register message routes. + // Note the handler gets access to the account store. + app.Router(). + AddRoute("bank", NewApp1Handler(keyAccount)) + + // Mount stores and load the latest state. + app.MountStoresIAVL(keyAccount) + err := app.LoadLatestVersion(keyAccount) + if err != nil { + cmn.Exit(err.Error()) + } + return app +} +``` + +Every app will have such a function that defines the setup of the app. +It will typically be contained in an `app.go` file. +We'll talk about how to connect this app object with the CLI, a REST API, +the logger, and the filesystem later in the tutorial. For now, note that this is where we grant handlers access to stores. +Here, we have only one store and one handler, and the handler is granted access by giving it the capability key. +In future apps, we'll have multiple stores and handlers, and not every handler will get access to every store. + +Note also the call to `SetTxDecoder`. While `Msg` contains the content for particular functionality in the application, the actual input +provided by the user is a serialized `Tx`. Applications may have many implementations of the `Msg` interface, but they should have only +a single implementation of `Tx`: + + +```go +// Transactions wrap messages. +type Tx interface { + // Gets the Msgs. + GetMsgs() []Msg +} +``` + +The `Tx` just wraps a `[]Msg`, and may include additional authentication data, like signatures and account nonces. +Applications must specify how their `Tx` is decoded, as this is the ultimate input into the application. +We'll talk more about `Tx` types later in the tutorial, specifically when we introduce the `StdTx`. + +For this example, we have a dead-simple `Tx` type that contains the `MsgSend` and is JSON decoded: + +```go +// Simple tx to wrap the Msg. +type app1Tx struct { + MsgSend +} + +// This tx only has one Msg. +func (tx app1Tx) GetMsgs() []sdk.Msg { + return []sdk.Msg{tx.MsgSend} +} + +// JSON decode MsgSend. +func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx app1Tx + err := json.Unmarshal(txBytes, &tx) + if err != nil { + return nil, sdk.ErrTxDecode(err.Error()) + } + return tx, nil +} +``` + +This means the input to the app must be a JSON encoded `app1Tx`. + +In the next tutorial, we'll introduce Amino, a superior encoding scheme that lets us decode into interface types! + +The last step in `NewApp1` is to mount the stores and load the latest version. Since we only have one store, we only mount one: + +```go + app.MountStoresIAVL(keyAccount) +``` + +We now have a complete implementation of a simple app. Next, we'll add another Msg type and another store, and use Amino for encoding! diff --git a/types/handler.go b/types/handler.go index 129f42647a..3a50e0ce05 100644 --- a/types/handler.go +++ b/types/handler.go @@ -1,7 +1,8 @@ package types -// core function variable which application runs for transactions +// Handler defines the core of the state transition function of an application. type Handler func(ctx Context, msg Msg) Result +// AnteHandler authenticates transactions, before their internal messages are handled. // If newCtx.IsZero(), ctx is used instead. type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool) From 7566ac2a9475f07dd505f90037386196df4522b1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 17:21:46 -0400 Subject: [PATCH 07/77] consolidate files into appX.md --- docs/core/accounts.md | 101 ------------------------ docs/core/{amino.md => app2.md} | 0 docs/core/{transactions.md => app3.md} | 102 +++++++++++++++++++++++++ docs/core/{keepers.md => app4.md} | 0 docs/core/baseapp.md | 19 ----- docs/core/handlers.md | 25 +----- docs/core/intro.md | 17 +++++ docs/core/messages.md | 76 ------------------ docs/core/multistore.md | 6 ++ 9 files changed, 127 insertions(+), 219 deletions(-) delete mode 100644 docs/core/accounts.md rename docs/core/{amino.md => app2.md} (100%) rename docs/core/{transactions.md => app3.md} (67%) rename docs/core/{keepers.md => app4.md} (100%) delete mode 100644 docs/core/baseapp.md create mode 100644 docs/core/intro.md delete mode 100644 docs/core/messages.md diff --git a/docs/core/accounts.md b/docs/core/accounts.md deleted file mode 100644 index 194c5e4d50..0000000000 --- a/docs/core/accounts.md +++ /dev/null @@ -1,101 +0,0 @@ -# Accounts - -### auth.Account - -```go -// Account is a standard account using a sequence number for replay protection -// and a pubkey for authentication. -type Account interface { - GetAddress() sdk.Address - SetAddress(sdk.Address) error // errors if already set. - - GetPubKey() crypto.PubKey // can return nil. - SetPubKey(crypto.PubKey) error - - GetAccountNumber() int64 - SetAccountNumber(int64) error - - GetSequence() int64 - SetSequence(int64) error - - GetCoins() sdk.Coins - SetCoins(sdk.Coins) error -} -``` - -Accounts are the standard way for an application to keep track of addresses and their associated balances. - -### auth.BaseAccount - -```go -// BaseAccount - base account structure. -// Extend this by embedding this in your AppAccount. -// See the examples/basecoin/types/account.go for an example. -type BaseAccount struct { - Address sdk.Address `json:"address"` - Coins sdk.Coins `json:"coins"` - PubKey crypto.PubKey `json:"public_key"` - AccountNumber int64 `json:"account_number"` - Sequence int64 `json:"sequence"` -} -``` - -The `auth.BaseAccount` struct provides a standard implementation of the Account interface with replay protection. -BaseAccount can be extended by embedding it in your own Account struct. - -### auth.AccountMapper - -```go -// This AccountMapper encodes/decodes accounts using the -// go-amino (binary) encoding/decoding library. -type AccountMapper struct { - - // The (unexposed) key used to access the store from the Context. - key sdk.StoreKey - - // The prototypical Account concrete type. - proto Account - - // The wire codec for binary encoding/decoding of accounts. - cdc *wire.Codec -} -``` - -The AccountMapper is responsible for managing and storing the state of all accounts in the application. - -Example Initialization: - -```go -// File: examples/basecoin/app/app.go -// Define the accountMapper. -app.accountMapper = auth.NewAccountMapper( - cdc, - app.keyAccount, // target store - &types.AppAccount{}, // prototype -) -``` - -The accountMapper allows you to retrieve the current account state by `GetAccount(ctx Context, addr auth.Address)` and change the state by -`SetAccount(ctx Context, acc Account)`. - -Note: To update an account you will first have to get the account, update the appropriate fields with its associated setter method, and then call -`SetAccount(ctx Context, acc updatedAccount)`. - -Updating accounts is made easier by using the `Keeper` struct in the `x/bank` module. - -Example Initialization: - -```go -// File: examples/basecoin/app/app.go -app.coinKeeper = bank.NewKeeper(app.accountMapper) -``` - -Example Usage: - -```go -// Finds account with addr in accountmapper -// Adds coins to account's coin array -// Sets updated account in accountmapper -app.coinKeeper.AddCoins(ctx, addr, coins) -``` - diff --git a/docs/core/amino.md b/docs/core/app2.md similarity index 100% rename from docs/core/amino.md rename to docs/core/app2.md diff --git a/docs/core/transactions.md b/docs/core/app3.md similarity index 67% rename from docs/core/transactions.md rename to docs/core/app3.md index aafcb105cb..5d14adf4e3 100644 --- a/docs/core/transactions.md +++ b/docs/core/app3.md @@ -152,3 +152,105 @@ app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeepe The antehandler is responsible for handling all authentication of a transaction before passing the message onto its handler. This generally involves signature verification. The antehandler should check that all of the addresses that are returned in `tx.GetMsg().GetSigners()` signed the message and that they signed over `tx.GetMsg().GetSignBytes()`. + +# Accounts + +### auth.Account + +```go +// Account is a standard account using a sequence number for replay protection +// and a pubkey for authentication. +type Account interface { + GetAddress() sdk.Address + SetAddress(sdk.Address) error // errors if already set. + + GetPubKey() crypto.PubKey // can return nil. + SetPubKey(crypto.PubKey) error + + GetAccountNumber() int64 + SetAccountNumber(int64) error + + GetSequence() int64 + SetSequence(int64) error + + GetCoins() sdk.Coins + SetCoins(sdk.Coins) error +} +``` + +Accounts are the standard way for an application to keep track of addresses and their associated balances. + +### auth.BaseAccount + +```go +// BaseAccount - base account structure. +// Extend this by embedding this in your AppAccount. +// See the examples/basecoin/types/account.go for an example. +type BaseAccount struct { + Address sdk.Address `json:"address"` + Coins sdk.Coins `json:"coins"` + PubKey crypto.PubKey `json:"public_key"` + AccountNumber int64 `json:"account_number"` + Sequence int64 `json:"sequence"` +} +``` + +The `auth.BaseAccount` struct provides a standard implementation of the Account interface with replay protection. +BaseAccount can be extended by embedding it in your own Account struct. + +### auth.AccountMapper + +```go +// This AccountMapper encodes/decodes accounts using the +// go-amino (binary) encoding/decoding library. +type AccountMapper struct { + + // The (unexposed) key used to access the store from the Context. + key sdk.StoreKey + + // The prototypical Account concrete type. + proto Account + + // The wire codec for binary encoding/decoding of accounts. + cdc *wire.Codec +} +``` + +The AccountMapper is responsible for managing and storing the state of all accounts in the application. + +Example Initialization: + +```go +// File: examples/basecoin/app/app.go +// Define the accountMapper. +app.accountMapper = auth.NewAccountMapper( + cdc, + app.keyAccount, // target store + &types.AppAccount{}, // prototype +) +``` + +The accountMapper allows you to retrieve the current account state by `GetAccount(ctx Context, addr auth.Address)` and change the state by +`SetAccount(ctx Context, acc Account)`. + +Note: To update an account you will first have to get the account, update the appropriate fields with its associated setter method, and then call +`SetAccount(ctx Context, acc updatedAccount)`. + +Updating accounts is made easier by using the `Keeper` struct in the `x/bank` module. + +Example Initialization: + +```go +// File: examples/basecoin/app/app.go +app.coinKeeper = bank.NewKeeper(app.accountMapper) +``` + +Example Usage: + +```go +// Finds account with addr in accountmapper +// Adds coins to account's coin array +// Sets updated account in accountmapper +app.coinKeeper.AddCoins(ctx, addr, coins) +``` + diff --git a/docs/core/keepers.md b/docs/core/app4.md similarity index 100% rename from docs/core/keepers.md rename to docs/core/app4.md diff --git a/docs/core/baseapp.md b/docs/core/baseapp.md deleted file mode 100644 index 7029b16ea4..0000000000 --- a/docs/core/baseapp.md +++ /dev/null @@ -1,19 +0,0 @@ -# BaseApp - -The BaseApp is an abstraction over the [Tendermint -ABCI](https://github.com/tendermint/abci) that -simplifies application development by handling common low-level concerns. -It serves as the mediator between the two key components of an SDK app: the store -and the message handlers. - -The BaseApp implements the -[`abci.Application`](https://godoc.org/github.com/tendermint/abci/types#Application) interface. -It uses a `MultiStore` to manage the state, a `Router` for transaction handling, and -`Set` methods to specify functions to run at the beginning and end of every -block. - -Every SDK app begins with a BaseApp: - -``` -app := baseapp.NewBaseApp(appName, cdc, logger, db), -``` diff --git a/docs/core/handlers.md b/docs/core/handlers.md index 5dbc22ef3c..8b2ef8f82e 100644 --- a/docs/core/handlers.md +++ b/docs/core/handlers.md @@ -1,26 +1,4 @@ -# Message Handling - -## Context - -The SDK uses a `Context` to propogate common information across functions. The -`Context` is modeled after the Golang `context.Context` object, which has -become ubiquitous in networking middleware and routing applications as a means -to easily propogate request context through handler functions. - -The main information stored in the `Context` includes the application -MultiStore, the last block header, and the transaction bytes. -Effectively, the context contains all data that may be necessary for processing -a transaction. - -Many methods on SDK objects receive a context as the first argument. - -## Handler - -Message processing in the SDK is defined through `Handler` functions: - -```go -type Handler func(ctx Context, msg Msg) Result -``` +# Handlers A handler takes a context and a message and returns a result. All information necessary for processing a message should be available in the @@ -50,3 +28,4 @@ app.Router().AddRoute("foo", newFooHandler(fooKey)) ``` Now it can only access the `foo` store, but not the `bar` or `cat` stores! + diff --git a/docs/core/intro.md b/docs/core/intro.md new file mode 100644 index 0000000000..df5c928d58 --- /dev/null +++ b/docs/core/intro.md @@ -0,0 +1,17 @@ +# Introduction + +Welcome to the Cosmos-SDK Core Documentation. + +Here you will learn how to use the Cosmos-SDK to build Basecoin, a +complete proof-of-stake cryptocurrency system + +We proceed through a series of increasingly advanced and complete implementations of +the Basecoin application, with each implementation showcasing a new component of +the SDK: + +- App1 - The Basics - Messages, Stores, Handlers, BaseApp +- App2 - Amino - Unmarshalling into interfaces +- App3 - Authentication - Accounts and Transactions, Signatures and Replay protection +- App4 - Access Control - Keepers selective expose access to stores +- App5 - Validator Set Changes - Change the Tendermint validator set +- App6 - Basecoin - Bringing it all together diff --git a/docs/core/messages.md b/docs/core/messages.md deleted file mode 100644 index 15190a8867..0000000000 --- a/docs/core/messages.md +++ /dev/null @@ -1,76 +0,0 @@ -# Messages - -Messages are the primary inputs to application state machines. -Developers can create messages containing arbitrary information by -implementing the `Msg` interface: - -```go -type Msg interface { - - // Return the message type. - // Must be alphanumeric or empty. - Type() string - - // Get the canonical byte representation of the Msg. - GetSignBytes() []byte - - // ValidateBasic does a simple validation check that - // doesn't require access to any other information. - ValidateBasic() error - - // Signers returns the addrs of signers that must sign. - // CONTRACT: All signatures must be present to be valid. - // CONTRACT: Returns addrs in some deterministic order. - GetSigners() []Address -} - -``` - -Messages must specify their type via the `Type()` method. The type should -correspond to the messages handler, so there can be many messages with the same -type. - -Messages must also specify how they are to be authenticated. The `GetSigners()` -method return a list of SDK addresses that must sign the message, while the -`GetSignBytes()` method returns the bytes that must be signed for a signature -to be valid. - -Addresses in the SDK are arbitrary byte arrays that are hex-encoded when -displayed as a string or rendered in JSON. - -Messages can specify basic self-consistency checks using the `ValidateBasic()` -method to enforce that message contents are well formed before any actual logic -begins. - -For instance, the `Basecoin` message types are defined in `x/bank/tx.go`: - -```go -// Send coins from many inputs to many outputs. -type MsgSend struct { - Inputs []Input `json:"inputs"` - Outputs []Output `json:"outputs"` -} - -// Issue new coins to many outputs. -type MsgIssue struct { - Banker sdk.Address `json:"banker"` - Outputs []Output `json:"outputs"` -} -``` - -Each specifies the addresses that must sign the message: - -```go -func (msg MsgSend) GetSigners() []sdk.Address { - addrs := make([]sdk.Address, len(msg.Inputs)) - for i, in := range msg.Inputs { - addrs[i] = in.Address - } - return addrs -} - -func (msg MsgIssue) GetSigners() []sdk.Address { - return []sdk.Address{msg.Banker} -} -``` - diff --git a/docs/core/multistore.md b/docs/core/multistore.md index 1ac80af8e7..9b7f6cd199 100644 --- a/docs/core/multistore.md +++ b/docs/core/multistore.md @@ -1,5 +1,7 @@ # MultiStore +TODO: reconcile this + The Cosmos-SDK provides a special Merkle database called a `MultiStore` to be used for all application storage. The MultiStore consists of multiple Stores that must be mounted to the MultiStore during application setup. Stores are mounted to the MultiStore using a capabilities key, @@ -14,6 +16,7 @@ The goals of the MultiStore are as follows: - Merkle proofs for various queries (existence, absence, range, etc.) on current and retained historical state - Allow for iteration within Stores - Provide caching for intermediate state during execution of blocks and transactions (including for iteration) + - Support historical state pruning and snapshotting Currently, all Stores in the MultiStore must satisfy the `KVStore` interface, @@ -55,9 +58,12 @@ through the `Context`. ## Notes +TODO: move this to the spec + In the example above, all IAVL nodes (inner and leaf) will be stored in mainDB with the prefix of "s/k:foo/" and "s/k:bar/" respectively, thus sharing the mainDB. All IAVL nodes (inner and leaf) for the cat KVStore are stored separately in catDB with the prefix of "s/\_/". The "s/k:KEY/" and "s/\_/" prefixes are there to disambiguate store items from other items of non-storage concern. + From bc35c7295275020087d3b227941511fe35e2ae05 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 17:39:14 -0400 Subject: [PATCH 08/77] minor fixes --- docs/core/app1.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 29a36fc30f..f966a11e16 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -1,8 +1,10 @@ -# App1 +# The Basics -The first application is a simple bank. Users have an account address and an account, -and they can send coins around. It has no authentication, and just uses JSON for -serialization. +Here we introduce the basic components of an SDK by building `App1`, a simple bank. +Users have an account address and an account, and they can send coins around. +It has no authentication, and just uses JSON for serialization. + +The complete code can be found in [app1.go](examples/app1.go). ## Messages @@ -18,7 +20,7 @@ type Msg interface { // Must correspond to name of message handler (XXX). Type() string - // Get the canonical byte representation of the Msg. + // Get the canonical byte representation of the Msg. // This is what is signed. GetSignBytes() []byte @@ -182,7 +184,8 @@ See the [Context API docs](TODO) for more details. ## Result -Result is motivated by the corresponding [ABCI result](TODO). It contains any return values, error information, logs, and meta data about the transaction: +Handler takes a Context and Msg and returns a Result. +Result is motivated by the corresponding [ABCI result](TODO). It contains return values, error information, logs, and meta data about the transaction: ```go // Result is the union of ResponseDeliverTx and ResponseCheckTx. @@ -212,6 +215,11 @@ type Result struct { } ``` +We'll talk more about these fields later in the tutorial. For now, note that a +`0` value for the `Code` is considered a success, and everything else is a +failure. The `Tags` can contain meta data about the transaction that will allow +us to easily lookup transactions that pertain to particular accounts or actions. + ## Handler Let's define our handler for App1: @@ -242,12 +250,12 @@ type acc struct { ``` Coins is a useful type provided by the SDK for multi-asset accounts. While we could just use an integer here for a single coin type, -it's worth [getting to know `Coins`](TODO). +it's worth [getting to know Coins](TODO). Now we're ready to handle the MsgSend: -``` +```go // Handle MsgSend. func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result { // NOTE: from, to, and amount were already validated @@ -289,14 +297,8 @@ The BaseApp is an abstraction over the [Tendermint ABCI](https://github.com/tendermint/abci) that simplifies application development by handling common low-level concerns. It serves as the mediator between the two key components of an SDK app: the store -and the message handlers. - -The BaseApp implements the +and the message handlers. The BaseApp implements the [`abci.Application`](https://godoc.org/github.com/tendermint/abci/types#Application) interface. -It uses a `MultiStore` to manage the state, a `Router` for transaction handling, and -`Set` methods to specify functions to run at the beginning and end of every -block. It's quite a work of art :). - Here is the complete setup for App1: @@ -383,10 +385,8 @@ This means the input to the app must be a JSON encoded `app1Tx`. In the next tutorial, we'll introduce Amino, a superior encoding scheme that lets us decode into interface types! -The last step in `NewApp1` is to mount the stores and load the latest version. Since we only have one store, we only mount one: +The last step in `NewApp1` is to mount the stores and load the latest version. Since we only have one store, we only mount one. -```go - app.MountStoresIAVL(keyAccount) -``` +We now have a complete implementation of a simple app! -We now have a complete implementation of a simple app. Next, we'll add another Msg type and another store, and use Amino for encoding! +In the next section, we'll add another Msg type and another store, and use Amino for encoding transactions! From cc4f2541c582c7ceab094af32657493711515311 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 17:42:00 -0400 Subject: [PATCH 09/77] fix comment --- docs/core/app1.md | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index f966a11e16..0c6936916a 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -14,24 +14,23 @@ Developers can create messages by implementing the `Msg` interface: ```go type Msg interface { - - // Return the message type. - // Must be alphanumeric or empty. + // Return the message type. + // Must be alphanumeric or empty. // Must correspond to name of message handler (XXX). - Type() string - + Type() string + // Get the canonical byte representation of the Msg. // This is what is signed. - GetSignBytes() []byte - - // ValidateBasic does a simple validation check that - // doesn't require access to any other information. - ValidateBasic() error - - // Signers returns the addrs of signers that must sign. - // CONTRACT: All signatures must be present to be valid. - // CONTRACT: Returns addrs in some deterministic order. - GetSigners() []Address + GetSignBytes() []byte + + // ValidateBasic does a simple validation check that + // doesn't require access to any other information. + ValidateBasic() error + + // Signers returns the addrs of signers that must sign. + // CONTRACT: All signatures must be present to be valid. + // CONTRACT: Returns addrs in some deterministic order. + GetSigners() []Address } ``` From 69a473765956463d6c71fc166ad48552d71d8c7a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 17:46:50 -0400 Subject: [PATCH 10/77] more minor fixes --- docs/core/app1.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 0c6936916a..0e57a8c7e2 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -298,6 +298,7 @@ simplifies application development by handling common low-level concerns. It serves as the mediator between the two key components of an SDK app: the store and the message handlers. The BaseApp implements the [`abci.Application`](https://godoc.org/github.com/tendermint/abci/types#Application) interface. +See the [BaseApp API documentation](TODO) for more details. Here is the complete setup for App1: @@ -311,14 +312,15 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Create the base application object. app := bapp.NewBaseApp(app1Name, cdc, logger, db) - // Create a key for accessing the account store. + // Create a capability key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") // Determine how transactions are decoded. app.SetTxDecoder(txDecoder) // Register message routes. - // Note the handler gets access to the account store. + // Note the handler receives the keyAccount and thus + // gets access to the account store. app.Router(). AddRoute("bank", NewApp1Handler(keyAccount)) @@ -382,10 +384,15 @@ func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { This means the input to the app must be a JSON encoded `app1Tx`. -In the next tutorial, we'll introduce Amino, a superior encoding scheme that lets us decode into interface types! - The last step in `NewApp1` is to mount the stores and load the latest version. Since we only have one store, we only mount one. +## Conclusion + We now have a complete implementation of a simple app! -In the next section, we'll add another Msg type and another store, and use Amino for encoding transactions! +In the next section, we'll add another Msg type and another store. Once we have multiple message types +we'll need a better way of decoding transactions, since we'll need to decode +into the `Msg` interface. This is where we introduce Amino, a superior encoding scheme that lets us decode into interface types! + + + From dde8abf9d76b7e4b3e1b25a3a7b5a26ad5609167 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 18:05:12 -0400 Subject: [PATCH 11/77] more structure for app2 and app3 md --- docs/core/app2.md | 40 ++++++++++++++++++++++++++++ docs/core/app3.md | 68 +++++------------------------------------------ 2 files changed, 46 insertions(+), 62 deletions(-) diff --git a/docs/core/app2.md b/docs/core/app2.md index f2c0aa4a6d..28f21131bd 100644 --- a/docs/core/app2.md +++ b/docs/core/app2.md @@ -1,5 +1,45 @@ # Amino +In the previous app we build a simple `bank` with one message type for sending +coins and one store for storing accounts. +Here we build `App2`, which expands on `App1` by introducing another message type for issuing new coins, and another store +for storing information about who can issue coins and how many. + +`App2` will allow us to better demonstrate the security model of the SDK, +using object-capability keys to determine which handlers can access which +stores. + +Having multiple implementations of `Msg` also requires a better transaction +decoder, since we won't know before hand which type is contained in the +serialized `Tx`. In effect, we'd like to unmarshal directly into the `Msg` +interface, but there's no standard way to unmarshal into interfaces in Go. +This is what Amino is for :) + + +## Message + +Let's introduce a new message type for issuing coins: + +```go +TODO +``` + +## Handler + +We'll need a new handler to support the new message type: + +```go +TODO +``` + +## BaseApp + +```go +TODO +``` + +## Amino + The SDK is flexible about serialization - application developers can use any serialization scheme to encode transactions and state. However, the SDK provides a native serialization format called diff --git a/docs/core/app3.md b/docs/core/app3.md index 5d14adf4e3..1cbcac1522 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -1,20 +1,11 @@ -### Transactions +# Authentication -A message is a set of instructions for a state transition. +In the previous app, we introduced a new `Msg` type and used Amino to encode +transactions. In that example, our `Tx` implementation was still just a simple +wrapper of the `Msg`, providing no actual authentication. Here, in `App3`, we +expand on `App2` to provide real authentication in the transactions. -For a message to be valid, it must be accompanied by at least one -digital signature. The signatures required are determined solely -by the contents of the message. - -A transaction is a message with additional information for authentication: - -```go -type Tx interface { - - GetMsg() Msg - -} -``` +## StdTx The standard way to create a transaction from a message is to use the `StdTx` struct defined in the `x/auth` module. @@ -73,53 +64,6 @@ type StdFee struct { } ``` -### Encoding and Decoding Transactions - -Messages and transactions are designed to be generic enough for developers to -specify their own encoding schemes. This enables the SDK to be used as the -framwork for constructing already specified cryptocurrency state machines, for -instance Ethereum. - -When initializing an application, a developer can specify a `TxDecoder` -function which determines how an arbitrary byte array should be unmarshalled -into a `Tx`: - -```go -type TxDecoder func(txBytes []byte) (Tx, error) -``` - -The default tx decoder is the Tendermint wire format which uses the go-amino library -for encoding and decoding all message types. - -In `Basecoin`, we use the default transaction decoder. The `go-amino` library has the nice -property that it can unmarshal into interface types, but it requires the -relevant types to be registered ahead of type. Registration happens on a -`Codec` object, so as not to taint the global name space. - -For instance, in `Basecoin`, we wish to register the `MsgSend` and `MsgIssue` -types: - -```go -cdc.RegisterInterface((*sdk.Msg)(nil), nil) -cdc.RegisterConcrete(bank.MsgSend{}, "cosmos-sdk/MsgSend", nil) -cdc.RegisterConcrete(bank.MsgIssue{}, "cosmos-sdk/MsgIssue", nil) -``` - -Note how each concrete type is given a name - these name determine the type's -unique "prefix bytes" during encoding. A registered type will always use the -same prefix-bytes, regardless of what interface it is satisfying. For more -details, see the [go-amino documentation](https://github.com/tendermint/go-amino/blob/develop). - -If you wish to use a custom encoding scheme, you must define a TxDecoder function -and set it as the decoder in your extended baseapp using the `SetTxDecoder(decoder sdk.TxDecoder)`. - -Ex: - -```go -app.SetTxDecoder(CustomTxDecodeFn) -``` - - ## AnteHandler The AnteHandler is used to do all transaction-level processing (i.e. Fee payment, signature verification) From 72c1381a4de724fe7d51a793c0981f74dfd304f8 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 21:29:54 -0400 Subject: [PATCH 12/77] some reordering in app1 and app3 --- docs/core/app1.md | 93 ++++++++++++----------- docs/core/app3.md | 184 ++++++++++++++++++++++++++++------------------ 2 files changed, 163 insertions(+), 114 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 0e57a8c7e2..3550b05145 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -288,6 +288,52 @@ The handler is straight forward: And that's that! +# Tx + +The final piece before putting it all together is the `Tx`. +While `Msg` contains the content for particular functionality in the application, the actual input +provided by the user is a serialized `Tx`. Applications may have many implementations of the `Msg` interface, +but they should have only a single implementation of `Tx`: + + +```go +// Transactions wrap messages. +type Tx interface { + // Gets the Msgs. + GetMsgs() []Msg +} +``` + +The `Tx` just wraps a `[]Msg`, and may include additional authentication data, like signatures and account nonces. +Applications must specify how their `Tx` is decoded, as this is the ultimate input into the application. +We'll talk more about `Tx` types later, specifically when we introduce the `StdTx`. + +For this example, we have a dead-simple `Tx` type that contains the `MsgSend` and is JSON decoded: + +```go +// Simple tx to wrap the Msg. +type app1Tx struct { + MsgSend +} + +// This tx only has one Msg. +func (tx app1Tx) GetMsgs() []sdk.Msg { + return []sdk.Msg{tx.MsgSend} +} + +// JSON decode MsgSend. +func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx app1Tx + err := json.Unmarshal(txBytes, &tx) + if err != nil { + return nil, sdk.ErrTxDecode(err.Error()) + } + return tx, nil +} +``` + +Thus, transactions in this blockchain are expected to be JSON encoded `MsgSend`. + # BaseApp Finally, we stitch it all together using the `BaseApp`. @@ -341,50 +387,9 @@ the logger, and the filesystem later in the tutorial. For now, note that this is Here, we have only one store and one handler, and the handler is granted access by giving it the capability key. In future apps, we'll have multiple stores and handlers, and not every handler will get access to every store. -Note also the call to `SetTxDecoder`. While `Msg` contains the content for particular functionality in the application, the actual input -provided by the user is a serialized `Tx`. Applications may have many implementations of the `Msg` interface, but they should have only -a single implementation of `Tx`: - - -```go -// Transactions wrap messages. -type Tx interface { - // Gets the Msgs. - GetMsgs() []Msg -} -``` - -The `Tx` just wraps a `[]Msg`, and may include additional authentication data, like signatures and account nonces. -Applications must specify how their `Tx` is decoded, as this is the ultimate input into the application. -We'll talk more about `Tx` types later in the tutorial, specifically when we introduce the `StdTx`. - -For this example, we have a dead-simple `Tx` type that contains the `MsgSend` and is JSON decoded: - -```go -// Simple tx to wrap the Msg. -type app1Tx struct { - MsgSend -} - -// This tx only has one Msg. -func (tx app1Tx) GetMsgs() []sdk.Msg { - return []sdk.Msg{tx.MsgSend} -} - -// JSON decode MsgSend. -func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx app1Tx - err := json.Unmarshal(txBytes, &tx) - if err != nil { - return nil, sdk.ErrTxDecode(err.Error()) - } - return tx, nil -} -``` - -This means the input to the app must be a JSON encoded `app1Tx`. - -The last step in `NewApp1` is to mount the stores and load the latest version. Since we only have one store, we only mount one. +After setting the transaction decoder and the message handling routes, the final +step is to mount the stores and load the latest version. +Since we only have one store, we only mount one. ## Conclusion diff --git a/docs/core/app3.md b/docs/core/app3.md index 1cbcac1522..7ef29074bb 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -5,54 +5,127 @@ transactions. In that example, our `Tx` implementation was still just a simple wrapper of the `Msg`, providing no actual authentication. Here, in `App3`, we expand on `App2` to provide real authentication in the transactions. +Without loss of generality, the SDK prescribes native +account and transaction types that are sufficient for a wide range of applications. +These are implemented in the `x/auth` module, where +all authentication related data structures and logic reside. +Applications that use `x/auth` don't need to worry about any of the details of +authentication and replay protection, as they are handled automatically. For +completeness, we will explain everything here. + +## Account + +The `Account` interface provides a model of accounts that have: + +- Address for identification +- PubKey for authentication +- AccountNumber to prune empty accounts +- Sequence to prevent transaction replays +- Coins to carry a balance + +It consists of getters and setters for each of these: + +```go +// Account is a standard account using a sequence number for replay protection +// and a pubkey for authentication. +type Account interface { + GetAddress() sdk.Address + SetAddress(sdk.Address) error // errors if already set. + + GetPubKey() crypto.PubKey // can return nil. + SetPubKey(crypto.PubKey) error + + GetAccountNumber() int64 + SetAccountNumber(int64) error + + GetSequence() int64 + SetSequence(int64) error + + GetCoins() sdk.Coins + SetCoins(sdk.Coins) error +} +``` + +## BaseAccount + +The default implementation of `Account` is the `BaseAccount`: + +```go +// BaseAccount - base account structure. +// Extend this by embedding this in your AppAccount. +// See the examples/basecoin/types/account.go for an example. +type BaseAccount struct { + Address sdk.Address `json:"address"` + Coins sdk.Coins `json:"coins"` + PubKey crypto.PubKey `json:"public_key"` + AccountNumber int64 `json:"account_number"` + Sequence int64 `json:"sequence"` +} +``` + +It simply contains a field for each of the methods. + +The `Address`, `PubKey`, and `AccountNumber` of the `BaseAccpunt` cannot be changed once they are set. + +The `Sequence` increments by one with every transaction. This ensures that a +given transaction can only be executed once, as the `Sequence` contained in the +transaction must match that contained in the account. + +The `Coins` will change according to the logic of each transaction type. + +If the `Coins` are ever emptied, the account will be deleted from the store. If +coins are later sent to the same `Address`, the account will be recreated but +with a new `AccountNumber`. This allows us to prune empty accounts from the +store, while still preventing transaction replay if accounts become non-empty +again in the future. + + + ## StdTx -The standard way to create a transaction from a message is to use the `StdTx` struct defined in the `x/auth` module. +The standard way to create a transaction from a message is to use the `StdTx` struct defined in the `x/auth` module: ```go +// StdTx is a standard way to wrap a Msg with Fee and Signatures. +// NOTE: the first signature is the FeePayer (Signatures must not be nil). type StdTx struct { - Msg sdk.Msg `json:"msg"` + Msgs []sdk.Msg `json:"msg"` Fee StdFee `json:"fee"` Signatures []StdSignature `json:"signatures"` + Memo string `json:"memo"` } ``` -The `StdTx.GetSignatures()` method returns a list of signatures, which must match -the list of addresses returned by `tx.Msg.GetSigners()`. The signatures come in -a standard form: +The `StdTx` includes a list of messages, information about the fee being paid, +and a list of signatures. It also includes an optional `Memo` for additional +data. Note that the list of signatures must match the result of `GetSigners()` +for each `Msg`! + +The signatures are provided in a standard form as `StdSignature`: ```go +// StdSignature wraps the Signature and includes counters for replay protection. +// It also includes an optional public key, which must be provided at least in +// the first transaction made by the account. type StdSignature struct { - crypto.PubKey // optional - crypto.Signature - AccountNumber int64 - Sequence int64 + crypto.PubKey `json:"pub_key"` // optional + crypto.Signature `json:"signature"` + AccountNumber int64 `json:"account_number"` + Sequence int64 `json:"sequence"` } ``` -It contains the signature itself, as well as the corresponding account's -sequence number. The sequence number is expected to increment every time a -message is signed by a given account. This prevents "replay attacks", where -the same message could be executed over and over again. +Recall that the `Sequence` is expected to increment every time a +message is signed by a given account in order to prevent "replay attacks" where +the same message could be executed over and over again. The `AccountNumber` is +assigned when the account is created or recreated after being emptied. The `StdSignature` can also optionally include the public key for verifying the -signature. An application can store the public key for each address it knows -about, making it optional to include the public key in the transaction. In the -case of Basecoin, the public key only needs to be included in the first -transaction send by a given account - after that, the public key is forever -stored by the application and can be left out of transactions. +signature. The public key only needs to be included the first time a transaction +is sent from a given account - from then on it will be stored in the `Account` +and can be left out of transactions. -The address responsible for paying the transactions fee is the first address -returned by msg.GetSigners(). The convenience function `FeePayer(tx Tx)` is provided -to return this. - -The standard bytes for signers to sign over is provided by: - -```go -func StdSignByes(chainID string, accnums []int64, sequences []int64, fee StdFee, msg sdk.Msg) []byte -``` - -in `x/auth`. The standard way to construct fees to pay for the processing of transactions is: +The fee is provided in a standard form as `StdFee`: ```go // StdFee includes the amount of coins paid in fees and the maximum @@ -64,6 +137,18 @@ type StdFee struct { } ``` +Note that the address responsible for paying the transactions fee is the first address +returned by msg.GetSigners() for the first `Msg`. The convenience function `FeePayer(tx Tx)` is provided +to return this. + +## Signing + +The standard bytes for signers to sign over is provided by: + +```go +TODO +``` + ## AnteHandler The AnteHandler is used to do all transaction-level processing (i.e. Fee payment, signature verification) @@ -101,47 +186,6 @@ This generally involves signature verification. The antehandler should check tha ### auth.Account -```go -// Account is a standard account using a sequence number for replay protection -// and a pubkey for authentication. -type Account interface { - GetAddress() sdk.Address - SetAddress(sdk.Address) error // errors if already set. - - GetPubKey() crypto.PubKey // can return nil. - SetPubKey(crypto.PubKey) error - - GetAccountNumber() int64 - SetAccountNumber(int64) error - - GetSequence() int64 - SetSequence(int64) error - - GetCoins() sdk.Coins - SetCoins(sdk.Coins) error -} -``` - -Accounts are the standard way for an application to keep track of addresses and their associated balances. - -### auth.BaseAccount - -```go -// BaseAccount - base account structure. -// Extend this by embedding this in your AppAccount. -// See the examples/basecoin/types/account.go for an example. -type BaseAccount struct { - Address sdk.Address `json:"address"` - Coins sdk.Coins `json:"coins"` - PubKey crypto.PubKey `json:"public_key"` - AccountNumber int64 `json:"account_number"` - Sequence int64 `json:"sequence"` -} -``` - -The `auth.BaseAccount` struct provides a standard implementation of the Account interface with replay protection. -BaseAccount can be extended by embedding it in your own Account struct. - ### auth.AccountMapper ```go From e6aec82f40e85cff1b7750993437cd59398431f2 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 21:30:13 -0400 Subject: [PATCH 13/77] update readme --- docs/README.md | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/docs/README.md b/docs/README.md index 0ae1cc1162..f0cdacc3dd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,21 +14,31 @@ NOTE: This documentation is a work-in-progress! - [Messages](core/app1.md#messages) - Messages contain the content of a transaction - [Stores](core/app1.md#kvstore) - KVStore is a Merkle Key-Value store. - [Handlers](core/app1.md#handlers) - Handlers are the workhorse of the app! + - [Tx](core/app1.md#tx) - Transactions are the ultimate input to the + application - [BaseApp](core/app1.md#baseapp) - BaseApp is the base layer of the application - - [App2 - Amino](core/app2.md) + - [App2 - Transactions](core/app2.md) - [Amino](core/app2.md#amino) - Amino is the primary serialization library used in the SDK - - [App3 - Authentication](core/app3.md) - - [Accounts](core/app3.md#accounts) - Accounts are the prototypical object kept in the store - - [Transactions](core/app3.md#transactions) - Transactions wrap messages and provide authentication - - [App4 - Modules and Keepers](core/app4.md) - - [Keepers](core/app4.md#keepers) - Keepers are the interfaces between handlers - - [App5 - Advanced](core/app5.md) - - [Validator Set Changes](core/app5.md#validators) - Change the - validator set - - [App6 - Basecoin](core/app6.md) - - - [Directory Structure](core/app6.md#directory-structure) - Keep your + - [Ante Handler](core/app2.md#ante-handler) - The AnteHandler + authenticates transactions + - [App3 - Modules](core/app3.md) + - [Account](core/app3.md#account) - Accounts are the prototypical object kept in the store + - [StdTx](core/app3.md#stdtx) - Transactions wrap messages and provide authentication + - [AccountMapper](core/app3.md#account-mapper) - AccountMapper + provides Account lookup on a KVStore + - [CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin + transfer on an underlying AccountMapper + - [App4 - Validator Set Changes](core/app4.md) + - [InitChain](core/app4.md#init-chain) - Initialize the application + state + - [BeginBlock](core/app4.md#begin-block) - BeginBlock logic runs at the + beginning of every block + - [EndBlock](core/app4.md#end-block) - EndBlock logic runs at the + end of every block + - [App5 - Basecoin](core/app5.md) - + - [Directory Structure](core/app5.md#directory-structure) - Keep your application code organized - - [Clients](core/app6.md#clients) - Hook up your app to standard CLI and REST + - [Clients](core/app5.md#clients) - Hook up your app to standard CLI and REST interfaces for clients to use! - [Modules](modules) From d1c9b8bdb9eefedd44fedae01b068908a4eb97e6 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Tue, 26 Jun 2018 19:09:54 -0700 Subject: [PATCH 14/77] Finish app1-3, app4 done minus staking --- docs/core/examples/app1.go | 9 +- docs/core/examples/app2.go | 214 +++++++++++++++++++++++++++++++++++-- docs/core/examples/app3.go | 140 +++++++++++++++++++++++- docs/core/examples/app4.go | 181 +++++++++++++++++++++++++++++-- 4 files changed, 523 insertions(+), 21 deletions(-) diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index fbbfb575c2..df5c57eb96 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -114,7 +114,6 @@ func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { // Handle MsgSend. func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result { // NOTE: from, to, and amount were already validated - store := ctx.KVStore(key) // deduct msg amount from sender account @@ -155,10 +154,10 @@ func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result bz = store.Get(msg.To) var acc2 account if bz == nil { - // Sender account does not already exist, create a new one. - acc2 = account{} + // Receiver account does not already exist, create a new one. + acc2 = account{Address: msg.To} } else { - // Sender account already exists. Retrieve and decode it. + // Receiver account already exists. Retrieve and decode it. err = json.Unmarshal(bz, &acc2) if err != nil { return sdk.ErrInternal("Account decoding error").Result() @@ -185,7 +184,9 @@ func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result } type account struct { + Address sdk.Address `json:"address"` Coins sdk.Coins `json:"coins"` + SequenceNumber int64 `json:"sequence"` } //------------------------------------------------------------------ diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index fec259ca99..034b8b05ce 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -2,23 +2,35 @@ package app import ( "reflect" + "encoding/json" + "fmt" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" + "github.com/tendermint/go-crypto" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" ) const ( app2Name = "App2" ) +var ( + issuer = crypto.GenPrivKeyEd25519().PubKey().Address() +) + func NewCodec() *wire.Codec { // TODO register - return nil + cdc := wire.NewCodec() + cdc.RegisterInterface((*sdk.Msg)(nil), nil) + cdc.RegisterConcrete(MsgSend{}, "example/MsgSend", nil) + cdc.RegisterConcrete(MsgIssue{}, "example/MsgIssue", nil) + return cdc } func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { @@ -29,16 +41,19 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { app := bapp.NewBaseApp(app2Name, cdc, logger, db) // Create a key for accessing the account store. + keyMain := sdk.NewKVStoreKey("main") keyAccount := sdk.NewKVStoreKey("acc") - keyIssuer := sdk.NewKVStoreKey("issuer") + + // set antehandler function + app.SetAnteHandler(antehandler) // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewApp2Handler(keyAccount, keyIssuer)) + AddRoute("bank", NewApp2Handler(keyAccount, keyMain)) // Mount stores and load the latest state. - app.MountStoresIAVL(keyAccount, keyIssuer) + app.MountStoresIAVL(keyAccount, keyMain) err := app.LoadLatestVersion(keyAccount) if err != nil { cmn.Exit(err.Error()) @@ -46,21 +61,73 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { return app } +// Coin Metadata +type CoinMetadata struct { + TotalSupply sdk.Int + CurrentSupply sdk.Int + Issuer sdk.Address + Decimal uint64 +} + //------------------------------------------------------------------ // Msgs -// TODO: MsgIssue +// Create Output struct to allow single message to issue arbitrary coins to multiple users +type Output struct { + Address sdk.Address + Coins sdk.Coins +} + +// Single permissioned issuer can issue multiple outputs +// Implements sdk.Msg Interface +type MsgIssue struct { + Issuer sdk.Address + Outputs []Output +} + +// nolint +func (msg MsgIssue) Type() string { return "bank" } + +func (msg MsgIssue) ValidateBasic() sdk.Error { + if len(msg.Issuer) == 0 { + return sdk.ErrInvalidAddress("Issuer address cannot be empty") + } + + for _, o := range msg.Outputs { + if len(o.Address) == 0 { + return sdk.ErrInvalidAddress("Output address cannot be empty") + } + // Cannot issue zero or negative coins + if !o.Coins.IsPositive() { + return sdk.ErrInvalidCoins("Cannot issue 0 or negative coin amounts") + } + } + return nil +} + +func (msg MsgIssue) GetSignBytes() []byte { + bz, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return bz +} + +// Implements Msg. Return the signer. +func (msg MsgIssue) GetSigners() []sdk.Address { + return []sdk.Address{msg.Issuer} +} //------------------------------------------------------------------ // Handler for the message -func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { +func NewApp2Handler(keyAcc *sdk.KVStoreKey, keyMain *sdk.KVStoreKey) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { switch msg := msg.(type) { case MsgSend: return handleMsgSend(ctx, keyAcc, msg) case MsgIssue: - // TODO + return handleMsgIssue(ctx, keyMain, keyAcc, msg) default: errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() @@ -68,12 +135,102 @@ func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { } } +// Handle Msg Issue +func handleMsgIssue(ctx sdk.Context, keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey, msg MsgIssue) sdk.Result { + store := ctx.KVStore(keyMain) + accStore := ctx.KVStore(keyAcc) + + for _, o := range msg.Outputs { + for _, coin := range o.Coins { + bz := store.Get([]byte(coin.Denom)) + var metadata CoinMetadata + + if bz == nil { + // Coin not set yet, initialize with issuer and default values + // Coin amount can't be above default value + if coin.Amount.GT(sdk.NewInt(1000000)) { + return sdk.ErrInvalidCoins("Cannot issue that many new coins").Result() + } + metadata = CoinMetadata{ + TotalSupply: sdk.NewInt(1000000), + CurrentSupply: sdk.NewInt(0), + Issuer: msg.Issuer, + Decimal: 10, + } + } else { + // Decode coin metadata + err := json.Unmarshal(bz, &metadata) + if err != nil { + return sdk.ErrInternal("Decoding coin metadata failed").Result() + } + } + + // Return error result if msg Issuer is not equal to coin issuer + if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) { + return sdk.ErrUnauthorized(fmt.Sprintf("Msg issuer cannot issue these coins: %s", coin.Denom)).Result() + } + + // Issuer cannot issue more than remaining supply + issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply) + if coin.Amount.GT(issuerSupply) { + return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result() + } + + // Update coin metadata + metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) + + val, err := json.Marshal(metadata) + if err != nil { + return sdk.ErrInternal("Encoding coin metadata failed").Result() + } + + // Update coin metadata in store + store.Set([]byte(coin.Denom), val) + } + + // Add coins to receiver account + bz := accStore.Get(o.Address) + var acc account + if bz == nil { + // Receiver account does not already exist, create a new one. + acc = account{} + } else { + // Receiver account already exists. Retrieve and decode it. + err := json.Unmarshal(bz, &acc) + if err != nil { + return sdk.ErrInternal("Account decoding error").Result() + } + } + + // Add amount to receiver's old coins + receiverCoins := acc.Coins.Plus(o.Coins) + + // Update receiver account + acc.Coins = receiverCoins + + // Encode receiver account + val, err := json.Marshal(acc) + if err != nil { + return sdk.ErrInternal("Account encoding error").Result() + } + + // set account with new issued coins in store + store.Set(o.Address, val) + } + + return sdk.Result{ + // TODO: Tags + } + +} + //------------------------------------------------------------------ // Tx // Simple tx to wrap the Msg. type app2Tx struct { sdk.Msg + Signatures []auth.StdSignature } // This tx only has one Msg. @@ -85,3 +242,46 @@ func (tx app2Tx) GetMsgs() []sdk.Msg { func (tx app2Tx) GetMemo() string { return "" } + +func (tx app2Tx) GetSignatures() []auth.StdSignature { + return tx.Signatures +} + +//------------------------------------------------------------------ + +// Simple antehandler that ensures msg signers has signed over msg signBytes w/ no replay protection +// Implement sdk.AnteHandler interface +func antehandler(ctx sdk.Context, tx sdk.Tx) (_ sdk.Context, _ sdk.Result, abort bool) { + appTx, ok := tx.(app2Tx) + if !ok { + // set abort boolean to true so that we don't continue to process failed tx + return ctx, sdk.ErrTxDecode("Tx must be of format app2Tx").Result(), true + } + + // expect only one msg in app2Tx + msg := tx.GetMsgs()[0] + + signerAddrs := msg.GetSigners() + signBytes := msg.GetSignBytes() + + if len(signerAddrs) != len(appTx.GetSignatures()) { + return ctx, sdk.ErrUnauthorized("Number of signatures do not match required amount").Result(), true + } + + for i, addr := range signerAddrs { + sig := appTx.GetSignatures()[i] + + // check that submitted pubkey belongs to required address + if !reflect.DeepEqual(sig.PubKey.Address(), addr) { + return ctx, sdk.ErrUnauthorized("Provided Pubkey does not match required address").Result(), true + } + + // check that signature is over expected signBytes + if !sig.PubKey.VerifyBytes(signBytes, sig.Signature) { + return ctx, sdk.ErrUnauthorized("Signature verification failed").Result(), true + } + } + + // authentication passed, app to continue processing by sending msg to handler + return ctx, sdk.Result{}, false +} diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index b176816b75..227fbe47d1 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -1,12 +1,19 @@ package app import ( + "reflect" + "encoding/json" + "fmt" + cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + ) const ( @@ -22,17 +29,24 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") - keyIssuer := sdk.NewKVStoreKey("issuer") + keyMain := sdk.NewKVStoreKey("main") + keyFees := sdk.NewKVStoreKey("fee") - // TODO: accounts, ante handler + // Set various mappers/keepers to interact easily with underlying stores + accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) + accountKeeper := bank.NewKeeper(accountMapper) + metadataMapper := NewApp3MetaDataMapper(keyMain) + feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) + + app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewApp2Handler(keyAccount, keyIssuer)) + AddRoute("bank", NewApp3Handler(accountKeeper, metadataMapper)) // Mount stores and load the latest state. - app.MountStoresIAVL(keyAccount, keyIssuer) + app.MountStoresIAVL(keyAccount, keyMain, keyFees) err := app.LoadLatestVersion(keyAccount) if err != nil { cmn.Exit(err.Error()) @@ -40,6 +54,124 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { return app } +func NewApp3Handler(accountKeeper bank.Keeper, metadataMapper MetaDataMapper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgSend: + return betterHandleMsgSend(ctx, accountKeeper, msg) + case MsgIssue: + return betterHandleMsgIssue(ctx, metadataMapper, accountKeeper, msg) + default: + errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func betterHandleMsgSend(ctx sdk.Context, accountKeeper bank.Keeper, msg MsgSend) sdk.Result { + // Subtract coins from sender account + _, _, err := accountKeeper.SubtractCoins(ctx, msg.From, msg.Amount) + if err != nil { + // if error, return its result + return err.Result() + } + + // Add coins to receiver account + _, _, err = accountKeeper.AddCoins(ctx, msg.To, msg.Amount) + if err != nil { + // if error, return its result + return err.Result() + } + + return sdk.Result{} +} + +func betterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, accountKeeper bank.Keeper, msg MsgIssue) sdk.Result { + for _, o := range msg.Outputs { + for _, coin := range o.Coins { + metadata := metadataMapper.GetMetaData(ctx, coin.Denom) + if len(metadata.Issuer) == 0 { + // coin doesn't have issuer yet, set issuer to msg issuer + metadata.Issuer = msg.Issuer + } + + // Check that msg Issuer is authorized to issue these coins + if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) { + return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue these coins: %s", coin.Denom)).Result() + } + + // Issuer cannot issue more than remaining supply + issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply) + if coin.Amount.GT(issuerSupply) { + return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result() + } + + // update metadata current circulating supply + metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) + + metadataMapper.SetMetaData(ctx, coin.Denom, metadata) + } + + // Add newly issued coins to output address + _, _, err := accountKeeper.AddCoins(ctx, o.Address, o.Coins) + if err != nil { + return err.Result() + } + } + + return sdk.Result{} +} + + + +//------------------------------------------------------------------ +// Mapper for Coin Metadata +// Example of a very simple user-defined mapper + +type MetaDataMapper interface { + GetMetaData(sdk.Context, string) CoinMetadata + SetMetaData(sdk.Context, string, CoinMetadata) +} + +type App3MetaDataMapper struct { + mainKey *sdk.KVStoreKey +} + +func NewApp3MetaDataMapper(key *sdk.KVStoreKey) App3MetaDataMapper { + return App3MetaDataMapper{mainKey: key} +} + +func (mdm App3MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata { + store := ctx.KVStore(mdm.mainKey) + + bz := store.Get([]byte(denom)) + if bz == nil { + // Coin metadata doesn't exist, create new metadata with default params + return CoinMetadata{ + TotalSupply: sdk.NewInt(1000000), + } + } + + var metadata CoinMetadata + err := json.Unmarshal(bz, &metadata) + if err != nil { + panic(err) + } + + return metadata +} + +func (mdm App3MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) { + store := ctx.KVStore(mdm.mainKey) + + val, err := json.Marshal(metadata) + if err != nil { + panic(err) + } + + store.Set([]byte(denom), val) +} + //------------------------------------------------------------------ // StdTx diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index ae63b4afba..b86976688d 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -1,12 +1,20 @@ package app import ( + "encoding/json" + "reflect" + "fmt" + cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" + abci "github.com/tendermint/abci/types" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" ) const ( @@ -18,23 +26,31 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { cdc := NewCodec() // Create the base application object. - app := bapp.NewBaseApp(app4Name, cdc, logger, db) + app := bapp.NewBaseApp(app3Name, cdc, logger, db) // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") - keyIssuer := sdk.NewKVStoreKey("issuer") + keyMain := sdk.NewKVStoreKey("main") + keyFees := sdk.NewKVStoreKey("fee") - // TODO: accounts, ante handler + // Set various mappers/keepers to interact easily with underlying stores + accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) + accountKeeper := bank.NewKeeper(accountMapper) + metadataMapper := NewApp4MetaDataMapper(keyMain) + feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) - // TODO: AccountMapper, CoinKeepr + app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) + + // Set InitChainer + app.SetInitChainer(NewInitChainer(cdc, accountMapper, metadataMapper)) // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewApp2Handler(keyAccount, keyIssuer)) + AddRoute("bank", NewApp4Handler(accountKeeper, metadataMapper)) // Mount stores and load the latest state. - app.MountStoresIAVL(keyAccount, keyIssuer) + app.MountStoresIAVL(keyAccount, keyMain, keyFees) err := app.LoadLatestVersion(keyAccount) if err != nil { cmn.Exit(err.Error()) @@ -42,6 +58,159 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { return app } +type GenesisState struct { + Accounts []*GenesisAccount `json:"accounts"` + Coins []*GenesisCoin `json:"coins"` +} + +// GenesisAccount doesn't need pubkey or sequence +type GenesisAccount struct { + Address sdk.Address `json:"address"` + Coins sdk.Coins `json:"coins"` +} + +func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount, err error) { + baseAcc := auth.BaseAccount{ + Address: ga.Address, + Coins: ga.Coins.Sort(), + } + return &baseAcc, nil +} + +// GenesisCoin enforces CurrentSupply is 0 at genesis. +type GenesisCoin struct { + Issuer sdk.Address `json:"issuer"` + TotalSupply sdk.Int `json:"total_supply` + Decimal uint64 `json:"decimals"` +} + +func (gc *GenesisCoin) ToMetaData() CoinMetadata { + return CoinMetadata{ + Issuer: gc.Issuer, + TotalSupply: gc.TotalSupply, + Decimal: gc.Decimal, + } +} + +// InitChainer will set initial balances for accounts as well as initial coin metadata +// MsgIssue can no longer be used to create new coin +func NewInitChainer(cdc *wire.Codec, accountMapper auth.AccountMapper, metadataMapper MetaDataMapper) sdk.InitChainer { + return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + stateJSON := req.AppStateBytes + + genesisState := new(GenesisState) + err := cdc.UnmarshalJSON(stateJSON, genesisState) + if err != nil { + panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 + // return sdk.ErrGenesisParse("").TraceCause(err, "") + } + + for _, gacc := range genesisState.Accounts { + acc, err := gacc.ToAccount() + if err != nil { + panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 + // return sdk.ErrGenesisParse("").TraceCause(err, "") + } + acc.AccountNumber = accountMapper.GetNextAccountNumber(ctx) + accountMapper.SetAccount(ctx, acc) + } + + return abci.ResponseInitChain{} + + } +} + +//--------------------------------------------------------------------------------------------- +// Now that initializing coin metadata is done in InitChainer we can simplifiy handleMsgIssue + +func NewApp4Handler(accountKeeper bank.Keeper, metadataMapper MetaDataMapper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgSend: + return betterHandleMsgSend(ctx, accountKeeper, msg) + case MsgIssue: + // use new MsgIssue handler + return evenBetterHandleMsgIssue(ctx, metadataMapper, accountKeeper, msg) + default: + errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + +func evenBetterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, accountKeeper bank.Keeper, msg MsgIssue) sdk.Result { + for _, o := range msg.Outputs { + for _, coin := range o.Coins { + // Metadata is no longer created on the fly since it is initalized at genesis with InitChain + metadata := metadataMapper.GetMetaData(ctx, coin.Denom) + // Check that msg Issuer is authorized to issue these coins + if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) { + return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue these coins: %s", coin.Denom)).Result() + } + + // Issuer cannot issue more than remaining supply + issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply) + if coin.Amount.GT(issuerSupply) { + return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result() + } + + // update metadata current circulating supply + metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) + + metadataMapper.SetMetaData(ctx, coin.Denom, metadata) + } + + // Add newly issued coins to output address + _, _, err := accountKeeper.AddCoins(ctx, o.Address, o.Coins) + if err != nil { + return err.Result() + } + } + + return sdk.Result{} +} + + +//--------------------------------------------------------------------------------------------- +// Simpler MetaDataMapper no longer able to initalize default CoinMetaData + +type App4MetaDataMapper struct { + mainKey *sdk.KVStoreKey +} + +func NewApp4MetaDataMapper(key *sdk.KVStoreKey) App4MetaDataMapper { + return App4MetaDataMapper{mainKey: key} +} + +func (mdm App4MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata { + store := ctx.KVStore(mdm.mainKey) + + bz := store.Get([]byte(denom)) + if bz == nil { + // Coin metadata doesn't exist, create new metadata with default params + return CoinMetadata{} + } + + var metadata CoinMetadata + err := json.Unmarshal(bz, &metadata) + if err != nil { + panic(err) + } + + return metadata +} + +func (mdm App4MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) { + store := ctx.KVStore(mdm.mainKey) + + val, err := json.Marshal(metadata) + if err != nil { + panic(err) + } + + store.Set([]byte(denom), val) +} + //------------------------------------------------------------------ // AccountMapper From c0445e52b05fca9921a7db657d811c766c305e5e Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Tue, 26 Jun 2018 19:17:36 -0700 Subject: [PATCH 15/77] Remove unnecessary fields from simple account --- docs/core/examples/app1.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index df5c57eb96..cf98978b0c 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -35,7 +35,7 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewApp1Handler(keyAccount)) + AddRoute("send", NewApp1Handler(keyAccount)) // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount) @@ -65,7 +65,7 @@ func NewMsgSend(from, to sdk.Address, amt sdk.Coins) MsgSend { } // Implements Msg. -func (msg MsgSend) Type() string { return "bank" } +func (msg MsgSend) Type() string { return "send" } // Implements Msg. Ensure the addresses are good and the // amount is positive. @@ -155,7 +155,7 @@ func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result var acc2 account if bz == nil { // Receiver account does not already exist, create a new one. - acc2 = account{Address: msg.To} + acc2 = account{} } else { // Receiver account already exists. Retrieve and decode it. err = json.Unmarshal(bz, &acc2) @@ -184,9 +184,7 @@ func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result } type account struct { - Address sdk.Address `json:"address"` Coins sdk.Coins `json:"coins"` - SequenceNumber int64 `json:"sequence"` } //------------------------------------------------------------------ From e11e4693405eac6f786fc80755ca215f3f965b81 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Tue, 26 Jun 2018 19:22:50 -0700 Subject: [PATCH 16/77] Initialize coin metadata in app4 and fmt --- docs/core/examples/app1.go | 2 +- docs/core/examples/app2.go | 22 +++++++++++----------- docs/core/examples/app3.go | 7 ++----- docs/core/examples/app4.go | 30 ++++++++++++++++++------------ 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index cf98978b0c..861ba4b70e 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -179,7 +179,7 @@ func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result store.Set(msg.To, val) return sdk.Result{ - // TODO: Tags + // TODO: Tags } } diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index 034b8b05ce..87bf0ba1c3 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -1,14 +1,14 @@ package app import ( - "reflect" "encoding/json" "fmt" + "reflect" + "github.com/tendermint/go-crypto" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" - "github.com/tendermint/go-crypto" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -63,10 +63,10 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Coin Metadata type CoinMetadata struct { - TotalSupply sdk.Int + TotalSupply sdk.Int CurrentSupply sdk.Int - Issuer sdk.Address - Decimal uint64 + Issuer sdk.Address + Decimal uint64 } //------------------------------------------------------------------ @@ -75,13 +75,13 @@ type CoinMetadata struct { // Create Output struct to allow single message to issue arbitrary coins to multiple users type Output struct { Address sdk.Address - Coins sdk.Coins + Coins sdk.Coins } // Single permissioned issuer can issue multiple outputs // Implements sdk.Msg Interface type MsgIssue struct { - Issuer sdk.Address + Issuer sdk.Address Outputs []Output } @@ -91,7 +91,7 @@ func (msg MsgIssue) Type() string { return "bank" } func (msg MsgIssue) ValidateBasic() sdk.Error { if len(msg.Issuer) == 0 { return sdk.ErrInvalidAddress("Issuer address cannot be empty") - } + } for _, o := range msg.Outputs { if len(o.Address) == 0 { @@ -152,10 +152,10 @@ func handleMsgIssue(ctx sdk.Context, keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStor return sdk.ErrInvalidCoins("Cannot issue that many new coins").Result() } metadata = CoinMetadata{ - TotalSupply: sdk.NewInt(1000000), + TotalSupply: sdk.NewInt(1000000), CurrentSupply: sdk.NewInt(0), - Issuer: msg.Issuer, - Decimal: 10, + Issuer: msg.Issuer, + Decimal: 10, } } else { // Decode coin metadata diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index 227fbe47d1..74142fd187 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -1,9 +1,9 @@ package app import ( - "reflect" "encoding/json" "fmt" + "reflect" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -13,7 +13,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" - ) const ( @@ -94,7 +93,7 @@ func betterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, accoun // coin doesn't have issuer yet, set issuer to msg issuer metadata.Issuer = msg.Issuer } - + // Check that msg Issuer is authorized to issue these coins if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue these coins: %s", coin.Denom)).Result() @@ -122,8 +121,6 @@ func betterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, accoun return sdk.Result{} } - - //------------------------------------------------------------------ // Mapper for Coin Metadata // Example of a very simple user-defined mapper diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index b86976688d..c7048409e3 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -2,13 +2,13 @@ package app import ( "encoding/json" - "reflect" "fmt" + "reflect" + abci "github.com/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" - abci "github.com/tendermint/abci/types" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -59,8 +59,8 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { } type GenesisState struct { - Accounts []*GenesisAccount `json:"accounts"` - Coins []*GenesisCoin `json:"coins"` + Accounts []*GenesisAccount `json:"accounts"` + Coins []*GenesisCoin `json:"coins"` } // GenesisAccount doesn't need pubkey or sequence @@ -79,16 +79,17 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount, err error) { // GenesisCoin enforces CurrentSupply is 0 at genesis. type GenesisCoin struct { - Issuer sdk.Address `json:"issuer"` - TotalSupply sdk.Int `json:"total_supply` - Decimal uint64 `json:"decimals"` + Denom string `json:"denom"` + Issuer sdk.Address `json:"issuer"` + TotalSupply sdk.Int `json:"total_supply` + Decimal uint64 `json:"decimals"` } -func (gc *GenesisCoin) ToMetaData() CoinMetadata { - return CoinMetadata{ - Issuer: gc.Issuer, +func (gc *GenesisCoin) ToMetaData() (string, CoinMetadata) { + return gc.Denom, CoinMetadata{ + Issuer: gc.Issuer, TotalSupply: gc.TotalSupply, - Decimal: gc.Decimal, + Decimal: gc.Decimal, } } @@ -115,6 +116,12 @@ func NewInitChainer(cdc *wire.Codec, accountMapper auth.AccountMapper, metadataM accountMapper.SetAccount(ctx, acc) } + // Initialize coin metadata. + for _, gc := range genesisState.Coins { + denom, metadata := gc.ToMetaData() + metadataMapper.SetMetaData(ctx, denom, metadata) + } + return abci.ResponseInitChain{} } @@ -170,7 +177,6 @@ func evenBetterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, ac return sdk.Result{} } - //--------------------------------------------------------------------------------------------- // Simpler MetaDataMapper no longer able to initalize default CoinMetaData From 41c61d2cc7cde3257e5e7e0bb2a1a3dbb7d7a004 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Tue, 26 Jun 2018 19:24:14 -0700 Subject: [PATCH 17/77] Revert changes to app1 router --- docs/core/examples/app1.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index 861ba4b70e..cc4389bf36 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -35,7 +35,7 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("send", NewApp1Handler(keyAccount)) + AddRoute("bank", NewApp1Handler(keyAccount)) // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount) @@ -65,7 +65,7 @@ func NewMsgSend(from, to sdk.Address, amt sdk.Coins) MsgSend { } // Implements Msg. -func (msg MsgSend) Type() string { return "send" } +func (msg MsgSend) Type() string { return "bank" } // Implements Msg. Ensure the addresses are good and the // amount is positive. From 354f9760f8951c87ff7493aedd4a74c1dad279c4 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 26 Jun 2018 22:49:13 -0400 Subject: [PATCH 18/77] move AnteHandler to app2 and some cleanup in app3 --- docs/README.md | 6 +- docs/core/app2.md | 99 +++++++++++++++++++++++------- docs/core/app3.md | 150 ++++++++++++++-------------------------------- 3 files changed, 124 insertions(+), 131 deletions(-) diff --git a/docs/README.md b/docs/README.md index f0cdacc3dd..41cfe403e6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,10 +22,10 @@ NOTE: This documentation is a work-in-progress! - [Ante Handler](core/app2.md#ante-handler) - The AnteHandler authenticates transactions - [App3 - Modules](core/app3.md) - - [Account](core/app3.md#account) - Accounts are the prototypical object kept in the store - - [StdTx](core/app3.md#stdtx) - Transactions wrap messages and provide authentication - - [AccountMapper](core/app3.md#account-mapper) - AccountMapper + - [Accounts](core/app3.md#accounts) - Accounts are the prototypical object kept in the store provides Account lookup on a KVStore + - [Transactions](core/app3.md#transactions) - `StdTx` is the default + implementation of `Tx` - [CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin transfer on an underlying AccountMapper - [App4 - Validator Set Changes](core/app4.md) diff --git a/docs/core/app2.md b/docs/core/app2.md index 28f21131bd..f97448b6ca 100644 --- a/docs/core/app2.md +++ b/docs/core/app2.md @@ -1,19 +1,15 @@ -# Amino +# Transactions -In the previous app we build a simple `bank` with one message type for sending +In the previous app we built a simple `bank` with one message type for sending coins and one store for storing accounts. -Here we build `App2`, which expands on `App1` by introducing another message type for issuing new coins, and another store -for storing information about who can issue coins and how many. +Here we build `App2`, which expands on `App1` by introducing -`App2` will allow us to better demonstrate the security model of the SDK, -using object-capability keys to determine which handlers can access which -stores. +- a new message type for issuing new coins +- a new store for coin metadata (like who can issue coins) +- a requirement that transactions include valid signatures -Having multiple implementations of `Msg` also requires a better transaction -decoder, since we won't know before hand which type is contained in the -serialized `Tx`. In effect, we'd like to unmarshal directly into the `Msg` -interface, but there's no standard way to unmarshal into interfaces in Go. -This is what Amino is for :) +Along the way, we'll be introduced to Amino for encoding and decoding +transactions and to the AnteHandler for processing them. ## Message @@ -32,20 +28,17 @@ We'll need a new handler to support the new message type: TODO ``` -## BaseApp - -```go -TODO -``` - ## Amino -The SDK is flexible about serialization - application developers can use any -serialization scheme to encode transactions and state. However, the SDK provides -a native serialization format called -[Amino](https://github.com/tendermint/go-amino). +Now that we have two implementations of `Msg`, we won't know before hand +which type is contained in a serialized `Tx`. Ideally, we would use the +`Msg` interface inside our `Tx` implementation, but the JSON decoder can't +decode into interface types. In fact, there's no standard way to unmarshal +into interfaces in Go. This is one of the primary reasons we built +[Amino](https://github.com/tendermint/go-amino) :). -The goal of Amino is to improve over the latest version of Protocol Buffers, +While SDK developers can encode transactions and state objects however they +like, Amino is the recommended format. The goal of Amino is to improve over the latest version of Protocol Buffers, `proto3`. To that end, Amino is compatible with the subset of `proto3` that excludes the `oneof` keyword. @@ -74,3 +67,63 @@ cdc := wire.NewCodec() cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/Send", nil) cdc.RegisterConcrete(MsgIssue{}, "cosmos-sdk/Issue", nil) ``` + +TODO: JSON, types table + +## Tx + +TODO + +## AnteHandler + +Now that we have an implementation of `Tx` that includes more than just the Msgs, +we need to specify how that extra information is validated and processed. This +is the role of the `AnteHandler`. The word `ante` here denotes "before", as the +`AnteHandler` is run before a `Handler`. While an app may have many Handlers, +one for each set of messages, it may have only a single `AnteHandler` that +corresponds to its single implementation of `Tx`. + + +The AnteHandler resembles a Handler: + + +```go +type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool) +``` + +Like Handler, AnteHandler takes a Context that restricts its access to stores +according to whatever capability keys it was granted. Instead of a `Msg`, +however, it takes a `Tx`. + +Like Handler, AnteHandler returns a `Result` type, but it also returns a new +`Context` and an `abort bool`. TODO explain (do we still need abort? ) + +For `App2`, we simply check if the PubKey matches the Address, and the Signature validates with the PubKey: + +```go +TODO +``` + +## App2 + +Let's put it all together now to get App2: + +```go +TODO +``` + +## Conclusion + +We've expanded on our first app by adding a new message type for issuing coins, +and by checking signatures. We learned how to use Amino for decoding into +interface types, allowing us to support multiple Msg types, and we learned how +to use the AnteHandler to validate transactions. + +Unfortunately, our application is still insecure, because any valid transaction +can be replayed multiple times to drain someones account! Besides, validating +signatures and preventing replays aren't things developers should have to think +about. + +In the next section, we introduce the built-in SDK modules `auth` and `bank`, +which respectively provide secure implementations for all our transaction authentication +and coin transfering needs. diff --git a/docs/core/app3.md b/docs/core/app3.md index 7ef29074bb..1912dfc824 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -1,21 +1,31 @@ -# Authentication +# Modules In the previous app, we introduced a new `Msg` type and used Amino to encode -transactions. In that example, our `Tx` implementation was still just a simple -wrapper of the `Msg`, providing no actual authentication. Here, in `App3`, we -expand on `App2` to provide real authentication in the transactions. +transactions. We also introduced additional data to the `Tx`, and used a simple +`AnteHandler` to validate it. -Without loss of generality, the SDK prescribes native -account and transaction types that are sufficient for a wide range of applications. -These are implemented in the `x/auth` module, where -all authentication related data structures and logic reside. -Applications that use `x/auth` don't need to worry about any of the details of -authentication and replay protection, as they are handled automatically. For -completeness, we will explain everything here. +Here, in `App3`, we introduce two built-in SDK modules to +replace the `Msg`, `Tx`, `Handler`, and `AnteHandler` implementations we've seen +so far. -## Account +The `x/auth` module implements `Tx` and `AnteHandler - it has everything we need to +authenticate transactions. It also includes a new `Account` type that simplifies +working with accounts in the store. -The `Account` interface provides a model of accounts that have: +The `x/bank` module implements `Msg` and `Handler` - it has everything we need +to transfer coins between accounts. + +Applications that use `x/auth` and `x/bank` thus significantly reduce the amount +of work they have to do so they can focus on their application specific logic in +their own modules. + +Here, we'll introduce the important types from `x/auth` and `x/bank`, and show +how to make `App3` by using them. The complete code can be found in [app3.go](examples/app3.go). + +## Accounts + +The `x/auth` module defines a model of accounts much like Ethereum. +In this model, an account contains: - Address for identification - PubKey for authentication @@ -23,7 +33,9 @@ The `Account` interface provides a model of accounts that have: - Sequence to prevent transaction replays - Coins to carry a balance -It consists of getters and setters for each of these: +### Account + +The `Account` interface captures this account model with getters and setters: ```go // Account is a standard account using a sequence number for replay protection @@ -46,7 +58,11 @@ type Account interface { } ``` -## BaseAccount +Note this is a low-level interface - it allows any of the fields to be over +written. As we'll soon see, access can be restricted using the `Keeper` +paradigm. + +### BaseAccount The default implementation of `Account` is the `BaseAccount`: @@ -80,8 +96,14 @@ store, while still preventing transaction replay if accounts become non-empty again in the future. +### AccountMapper -## StdTx +TODO + +## Transaction + + +### StdTx The standard way to create a transaction from a message is to use the `StdTx` struct defined in the `x/auth` module: @@ -141,7 +163,7 @@ Note that the address responsible for paying the transactions fee is the first a returned by msg.GetSigners() for the first `Msg`. The convenience function `FeePayer(tx Tx)` is provided to return this. -## Signing +### Signing The standard bytes for signers to sign over is provided by: @@ -151,94 +173,12 @@ TODO ## AnteHandler -The AnteHandler is used to do all transaction-level processing (i.e. Fee payment, signature verification) -before passing the message to its respective handler. +TODO + +## App3 + +Putting it all together, we get: ```go -type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool) +TODO ``` - -The antehandler takes a Context and a transaction and returns a new Context, a Result, and the abort boolean. -As with the handler, all information necessary for processing a message should be available in the -context. - -If the transaction fails, then the application should not waste time processing the message. Thus, the antehandler should -return an Error's Result method and set the abort boolean to `true` so that the application knows not to process the message in a handler. - -Most applications can use the provided antehandler implementation in `x/auth` which handles signature verification -as well as collecting fees. - -Note: Signatures must be over `auth.StdSignDoc` introduced above to use the provided antehandler. - -```go -// File: cosmos-sdk/examples/basecoin/app/app.go -app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) -``` - -### Handling Fee payment -### Handling Authentication - -The antehandler is responsible for handling all authentication of a transaction before passing the message onto its handler. -This generally involves signature verification. The antehandler should check that all of the addresses that are returned in -`tx.GetMsg().GetSigners()` signed the message and that they signed over `tx.GetMsg().GetSignBytes()`. - -# Accounts - -### auth.Account - -### auth.AccountMapper - -```go -// This AccountMapper encodes/decodes accounts using the -// go-amino (binary) encoding/decoding library. -type AccountMapper struct { - - // The (unexposed) key used to access the store from the Context. - key sdk.StoreKey - - // The prototypical Account concrete type. - proto Account - - // The wire codec for binary encoding/decoding of accounts. - cdc *wire.Codec -} -``` - -The AccountMapper is responsible for managing and storing the state of all accounts in the application. - -Example Initialization: - -```go -// File: examples/basecoin/app/app.go -// Define the accountMapper. -app.accountMapper = auth.NewAccountMapper( - cdc, - app.keyAccount, // target store - &types.AppAccount{}, // prototype -) -``` - -The accountMapper allows you to retrieve the current account state by `GetAccount(ctx Context, addr auth.Address)` and change the state by -`SetAccount(ctx Context, acc Account)`. - -Note: To update an account you will first have to get the account, update the appropriate fields with its associated setter method, and then call -`SetAccount(ctx Context, acc updatedAccount)`. - -Updating accounts is made easier by using the `Keeper` struct in the `x/bank` module. - -Example Initialization: - -```go -// File: examples/basecoin/app/app.go -app.coinKeeper = bank.NewKeeper(app.accountMapper) -``` - -Example Usage: - -```go -// Finds account with addr in accountmapper -// Adds coins to account's coin array -// Sets updated account in accountmapper -app.coinKeeper.AddCoins(ctx, addr, coins) -``` - From fc81c14a16ff8b3e3e289f8fd26f1d59ab5f76b0 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Jun 2018 07:51:46 -0400 Subject: [PATCH 19/77] update/finish app1 go and md --- docs/core/app1.md | 106 ++++++++++++++++++++++++++++++------- docs/core/examples/app1.go | 84 ++++++++++++++++++----------- 2 files changed, 141 insertions(+), 49 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 3550b05145..abc2c39b5d 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -243,7 +243,7 @@ Note this handler has unfettered access to the store specified by the capability For this first example, we will define a simple account that is JSON encoded: ```go -type acc struct { +type app1Account struct { Coins sdk.Coins `json:"coins"` } ``` @@ -256,35 +256,105 @@ Now we're ready to handle the MsgSend: ```go // Handle MsgSend. +// NOTE: msg.From, msg.To, and msg.Amount were already validated func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result { - // NOTE: from, to, and amount were already validated - + // Load the store. store := ctx.KVStore(key) - bz := store.Get(msg.From) - if bz == nil { - // TODO + + // Debit from the sender. + if res := handleFrom(store, msg.From, msg.Amount); !res.IsOK() { + return res } - var acc acc - err := json.Unmarshal(bz, &acc) - if err != nil { - // InternalError + // Credit the receiver. + if res := handleTo(store, msg.To, msg.Amount); !res.IsOK() { + return res } - // TODO: finish the logic - + // Return a success (Code 0). + // Add list of key-value pair descriptors ("tags"). return sdk.Result{ - // TODO: Tags + Tags: msg.Tags(), } } ``` -The handler is straight forward: +The handler is straight forward. We first load the KVStore from the context using the granted capability key. +Then we make two state transitions: one for the sender, one for the receiver. +Each one involves JSON unmarshalling the account bytes from the store, mutating +the `Coins`, and JSON marshalling back into the store: -- get the KVStore from the context using the granted capability key -- lookup the From address in the KVStore, and JSON unmarshal it into an `acc`, -- check that the account balance is greater than the `msg.Amount` -- transfer the `msg.Amount` +```go +func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { + // Get sender account from the store. + accBytes := store.Get(from) + if accBytes == nil { + // Account was not added to store. Return the result of the error. + return sdk.NewError(2, 101, "Account not added to store").Result() + } + + // Unmarshal the JSON account bytes. + var acc app1Account + err := json.Unmarshal(accBytes, &acc) + if err != nil { + // InternalError + return sdk.ErrInternal("Error when deserializing account").Result() + } + + // Deduct msg amount from sender account. + senderCoins := acc.Coins.Minus(amt) + + // If any coin has negative amount, return insufficient coins error. + if !senderCoins.IsNotNegative() { + return sdk.ErrInsufficientCoins("Insufficient coins in account").Result() + } + + // Set acc coins to new amount. + acc.Coins = senderCoins + + // Encode sender account. + accBytes, err = json.Marshal(acc) + if err != nil { + return sdk.ErrInternal("Account encoding error").Result() + } + + // Update store with updated sender account + store.Set(from, accBytes) + return sdk.Result{} +} + +func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { + // Add msg amount to receiver account + accBytes := store.Get(to) + var acc app1Account + if accBytes == nil { + // Receiver account does not already exist, create a new one. + acc = app1Account{} + } else { + // Receiver account already exists. Retrieve and decode it. + err := json.Unmarshal(accBytes, &acc) + if err != nil { + return sdk.ErrInternal("Account decoding error").Result() + } + } + + // Add amount to receiver's old coins + receiverCoins := acc.Coins.Plus(amt) + + // Update receiver account + acc.Coins = receiverCoins + + // Encode receiver account + accBytes, err := json.Marshal(acc) + if err != nil { + return sdk.ErrInternal("Account encoding error").Result() + } + + // Update store with updated receiver account + store.Set(to, accBytes) + return sdk.Result{} +} +``` And that's that! diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index cc4389bf36..2ac8fa5298 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -96,6 +96,12 @@ func (msg MsgSend) GetSigners() []sdk.Address { return []sdk.Address{msg.From} } +// Returns the sdk.Tags for the message +func (msg MsgSend) Tags() sdk.Tags { + return sdk.NewTags("sender", []byte(msg.From.String())). + AppendTag("receiver", []byte(msg.To.String())) +} + //------------------------------------------------------------------ // Handler for the message @@ -112,78 +118,99 @@ func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { } // Handle MsgSend. +// NOTE: msg.From, msg.To, and msg.Amount were already validated func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result { - // NOTE: from, to, and amount were already validated + // Load the store. store := ctx.KVStore(key) - // deduct msg amount from sender account - bz := store.Get(msg.From) - if bz == nil { + // Debit from the sender. + if res := handleFrom(store, msg.From, msg.Amount); !res.IsOK() { + return res + } + + // Credit the receiver. + if res := handleTo(store, msg.To, msg.Amount); !res.IsOK() { + return res + } + + // Return a success (Code 0). + // Add list of key-value pair descriptors ("tags"). + return sdk.Result{ + Tags: msg.Tags(), + } +} + +func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { + // Get sender account from the store. + accBytes := store.Get(from) + if accBytes == nil { // Account was not added to store. Return the result of the error. return sdk.NewError(2, 101, "Account not added to store").Result() } - var acc account - err := json.Unmarshal(bz, &acc) + // Unmarshal the JSON account bytes. + var acc app1Account + err := json.Unmarshal(accBytes, &acc) if err != nil { // InternalError return sdk.ErrInternal("Error when deserializing account").Result() } - // TODO: finish the logic - senderCoins := acc.Coins.Minus(msg.Amount) + // Deduct msg amount from sender account. + senderCoins := acc.Coins.Minus(amt) // If any coin has negative amount, return insufficient coins error. if !senderCoins.IsNotNegative() { return sdk.ErrInsufficientCoins("Insufficient coins in account").Result() } - // set acc coins to new amount + // Set acc coins to new amount. acc.Coins = senderCoins - // Encode sender account - val, err := json.Marshal(acc) + // Encode sender account. + accBytes, err = json.Marshal(acc) if err != nil { return sdk.ErrInternal("Account encoding error").Result() } // Update store with updated sender account - store.Set(msg.From, val) + store.Set(from, accBytes) + return sdk.Result{} +} +func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { // Add msg amount to receiver account - bz = store.Get(msg.To) - var acc2 account - if bz == nil { + accBytes := store.Get(to) + var acc app1Account + if accBytes == nil { // Receiver account does not already exist, create a new one. - acc2 = account{} + acc = app1Account{} } else { // Receiver account already exists. Retrieve and decode it. - err = json.Unmarshal(bz, &acc2) + err := json.Unmarshal(accBytes, &acc) if err != nil { return sdk.ErrInternal("Account decoding error").Result() } } // Add amount to receiver's old coins - receiverCoins := acc2.Coins.Plus(msg.Amount) + receiverCoins := acc.Coins.Plus(amt) // Update receiver account - acc2.Coins = receiverCoins + acc.Coins = receiverCoins // Encode receiver account - val, err = json.Marshal(acc2) + accBytes, err := json.Marshal(acc) if err != nil { return sdk.ErrInternal("Account encoding error").Result() } - store.Set(msg.To, val) - - return sdk.Result{ - // TODO: Tags - } + // Update store with updated receiver account + store.Set(to, accBytes) + return sdk.Result{} } -type account struct { +type app1Account struct { Coins sdk.Coins `json:"coins"` } @@ -200,11 +227,6 @@ func (tx app1Tx) GetMsgs() []sdk.Msg { return []sdk.Msg{tx.MsgSend} } -// TODO: remove the need for this -func (tx app1Tx) GetMemo() string { - return "" -} - // JSON decode MsgSend. func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { var tx app1Tx From 6a5a8b4721ab8bd2215440445f4cd7e715fb27fd Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Jun 2018 07:59:20 -0400 Subject: [PATCH 20/77] minor cleanup --- docs/core/app1.md | 8 ++++---- docs/core/examples/app1.go | 8 ++++---- docs/core/examples/app2.go | 12 +++--------- docs/core/examples/app3.go | 2 ++ 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index abc2c39b5d..7384db4330 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -243,7 +243,7 @@ Note this handler has unfettered access to the store specified by the capability For this first example, we will define a simple account that is JSON encoded: ```go -type app1Account struct { +type appAccount struct { Coins sdk.Coins `json:"coins"` } ``` @@ -294,7 +294,7 @@ func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { } // Unmarshal the JSON account bytes. - var acc app1Account + var acc appAccount err := json.Unmarshal(accBytes, &acc) if err != nil { // InternalError @@ -326,10 +326,10 @@ func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { // Add msg amount to receiver account accBytes := store.Get(to) - var acc app1Account + var acc appAccount if accBytes == nil { // Receiver account does not already exist, create a new one. - acc = app1Account{} + acc = appAccount{} } else { // Receiver account already exists. Retrieve and decode it. err := json.Unmarshal(accBytes, &acc) diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index 2ac8fa5298..ec5b779e7c 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -149,7 +149,7 @@ func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { } // Unmarshal the JSON account bytes. - var acc app1Account + var acc appAccount err := json.Unmarshal(accBytes, &acc) if err != nil { // InternalError @@ -181,10 +181,10 @@ func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { // Add msg amount to receiver account accBytes := store.Get(to) - var acc app1Account + var acc appAccount if accBytes == nil { // Receiver account does not already exist, create a new one. - acc = app1Account{} + acc = appAccount{} } else { // Receiver account already exists. Retrieve and decode it. err := json.Unmarshal(accBytes, &acc) @@ -210,7 +210,7 @@ func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { return sdk.Result{} } -type app1Account struct { +type appAccount struct { Coins sdk.Coins `json:"coins"` } diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index 87bf0ba1c3..5959fcd393 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -25,7 +25,6 @@ var ( ) func NewCodec() *wire.Codec { - // TODO register cdc := wire.NewCodec() cdc.RegisterInterface((*sdk.Msg)(nil), nil) cdc.RegisterConcrete(MsgSend{}, "example/MsgSend", nil) @@ -190,10 +189,10 @@ func handleMsgIssue(ctx sdk.Context, keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStor // Add coins to receiver account bz := accStore.Get(o.Address) - var acc account + var acc appAccount if bz == nil { // Receiver account does not already exist, create a new one. - acc = account{} + acc = appAccount{} } else { // Receiver account already exists. Retrieve and decode it. err := json.Unmarshal(bz, &acc) @@ -219,7 +218,7 @@ func handleMsgIssue(ctx sdk.Context, keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStor } return sdk.Result{ - // TODO: Tags + // TODO: Tags } } @@ -238,11 +237,6 @@ func (tx app2Tx) GetMsgs() []sdk.Msg { return []sdk.Msg{tx.Msg} } -// TODO: remove the need for this -func (tx app2Tx) GetMemo() string { - return "" -} - func (tx app2Tx) GetSignatures() []auth.StdSignature { return tx.Signatures } diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index 74142fd187..25036ef1b2 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -21,6 +21,7 @@ const ( func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { + // Create the codec with registered Msg types cdc := NewCodec() // Create the base application object. @@ -32,6 +33,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { keyFees := sdk.NewKVStoreKey("fee") // Set various mappers/keepers to interact easily with underlying stores + // TODO: Need to register Account interface or use different Codec accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) accountKeeper := bank.NewKeeper(accountMapper) metadataMapper := NewApp3MetaDataMapper(keyMain) From 098778789697d4e6239c37d1b3c1b30454eb8f84 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Jun 2018 08:11:11 -0400 Subject: [PATCH 21/77] more app1 cleanup --- docs/core/app1.md | 63 +++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 7384db4330..e4a9f4b147 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -378,7 +378,12 @@ The `Tx` just wraps a `[]Msg`, and may include additional authentication data, l Applications must specify how their `Tx` is decoded, as this is the ultimate input into the application. We'll talk more about `Tx` types later, specifically when we introduce the `StdTx`. -For this example, we have a dead-simple `Tx` type that contains the `MsgSend` and is JSON decoded: +In this first application, we won't have any authentication at all. This might +make sense in a private network where access is controlled by alternative means, +like client-side TLS certificates, but in general, we'll want to bake the authentication +right into our state machine. We'll use `Tx` to do that +in the next app. For now, the `Tx` just embeds `MsgSend` and uses JSON: + ```go // Simple tx to wrap the Msg. @@ -402,8 +407,6 @@ func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { } ``` -Thus, transactions in this blockchain are expected to be JSON encoded `MsgSend`. - # BaseApp Finally, we stitch it all together using the `BaseApp`. @@ -420,33 +423,32 @@ Here is the complete setup for App1: ```go func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { - - // TODO: make this an interface or pass in - // a TxDecoder instead. - cdc := wire.NewCodec() - - // Create the base application object. - app := bapp.NewBaseApp(app1Name, cdc, logger, db) - - // Create a capability key for accessing the account store. - keyAccount := sdk.NewKVStoreKey("acc") - - // Determine how transactions are decoded. - app.SetTxDecoder(txDecoder) - - // Register message routes. - // Note the handler receives the keyAccount and thus + // TODO: make this an interface or pass in + // a TxDecoder instead. + cdc := wire.NewCodec() + + // Create the base application object. + app := bapp.NewBaseApp(app1Name, cdc, logger, db) + + // Create a capability key for accessing the account store. + keyAccount := sdk.NewKVStoreKey("acc") + + // Determine how transactions are decoded. + app.SetTxDecoder(txDecoder) + + // Register message routes. + // Note the handler receives the keyAccount and thus // gets access to the account store. - app.Router(). - AddRoute("bank", NewApp1Handler(keyAccount)) - - // Mount stores and load the latest state. - app.MountStoresIAVL(keyAccount) - err := app.LoadLatestVersion(keyAccount) - if err != nil { - cmn.Exit(err.Error()) - } - return app + app.Router(). + AddRoute("bank", NewApp1Handler(keyAccount)) + + // Mount stores and load the latest state. + app.MountStoresIAVL(keyAccount) + err := app.LoadLatestVersion(keyAccount) + if err != nil { + cmn.Exit(err.Error()) + } + return app } ``` @@ -468,6 +470,3 @@ We now have a complete implementation of a simple app! In the next section, we'll add another Msg type and another store. Once we have multiple message types we'll need a better way of decoding transactions, since we'll need to decode into the `Msg` interface. This is where we introduce Amino, a superior encoding scheme that lets us decode into interface types! - - - From d6a01ba3a42d375b3f6267111cbbcaa766f610ab Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Jun 2018 08:24:40 -0400 Subject: [PATCH 22/77] minor updates in App2 --- docs/core/app2.md | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/docs/core/app2.md b/docs/core/app2.md index f97448b6ca..f9a2e060f3 100644 --- a/docs/core/app2.md +++ b/docs/core/app2.md @@ -62,25 +62,50 @@ Amino can also be used for persistent storage of interfaces. To use Amino, simply create a codec, and then register types: ``` -cdc := wire.NewCodec() - -cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/Send", nil) -cdc.RegisterConcrete(MsgIssue{}, "cosmos-sdk/Issue", nil) +func NewCodec() *wire.Codec { + cdc := wire.NewCodec() + cdc.RegisterInterface((*sdk.Msg)(nil), nil) + cdc.RegisterConcrete(MsgSend{}, "example/MsgSend", nil) + cdc.RegisterConcrete(MsgIssue{}, "example/MsgIssue", nil) + return cdc +} ``` -TODO: JSON, types table +Amino supports encoding and decoding in both a binary and JSON format. +See the [codec API docs](https://godoc.org/github.com/tendermint/go-amino#Codec) for more details. + +TODO: Update Amino and demo `cdc.PrintTypes` ## Tx -TODO +Now that we're using Amino, we can embed the `Msg` interface directly in our +`Tx`. We can also add a public key and a signature for authentication. + +```go +// Simple tx to wrap the Msg. +type app2Tx struct { + sdk.Msg + + PubKey crypto.PubKey + Signature crypto.Signature +} + +// This tx only has one Msg. +func (tx app2Tx) GetMsgs() []sdk.Msg { + return []sdk.Msg{tx.Msg} +} +``` + +We don't need a custom TxDecoder function anymore, since we're just using the +Amino codec! ## AnteHandler -Now that we have an implementation of `Tx` that includes more than just the Msgs, +Now that we have an implementation of `Tx` that includes more than just the Msg, we need to specify how that extra information is validated and processed. This is the role of the `AnteHandler`. The word `ante` here denotes "before", as the -`AnteHandler` is run before a `Handler`. While an app may have many Handlers, -one for each set of messages, it may have only a single `AnteHandler` that +`AnteHandler` is run before a `Handler`. While an app can have many Handlers, +one for each set of messages, it can have only a single `AnteHandler` that corresponds to its single implementation of `Tx`. From bd581b22e8308a42abc4da7899f82905496c9313 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Jun 2018 09:02:11 -0400 Subject: [PATCH 23/77] working on app3 --- docs/core/app3.md | 98 +++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/docs/core/app3.md b/docs/core/app3.md index 1912dfc824..c9a37c6f3e 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -6,9 +6,9 @@ transactions. We also introduced additional data to the `Tx`, and used a simple Here, in `App3`, we introduce two built-in SDK modules to replace the `Msg`, `Tx`, `Handler`, and `AnteHandler` implementations we've seen -so far. +so far: `x/auth` and `x/bank`. -The `x/auth` module implements `Tx` and `AnteHandler - it has everything we need to +The `x/auth` module implements `Tx` and `AnteHandler` - it has everything we need to authenticate transactions. It also includes a new `Account` type that simplifies working with accounts in the store. @@ -81,31 +81,35 @@ type BaseAccount struct { It simply contains a field for each of the methods. -The `Address`, `PubKey`, and `AccountNumber` of the `BaseAccpunt` cannot be changed once they are set. - -The `Sequence` increments by one with every transaction. This ensures that a -given transaction can only be executed once, as the `Sequence` contained in the -transaction must match that contained in the account. - -The `Coins` will change according to the logic of each transaction type. - -If the `Coins` are ever emptied, the account will be deleted from the store. If -coins are later sent to the same `Address`, the account will be recreated but -with a new `AccountNumber`. This allows us to prune empty accounts from the -store, while still preventing transaction replay if accounts become non-empty -again in the future. - - ### AccountMapper -TODO +In previous apps using our `appAccount`, we handled +marshaling/unmarshaling the account from the store ourselves, by performing +operations directly on the KVStore. But unrestricted access to a KVStore isn't really the interface we want +to work with in our applications. In the SDK, we use the term `Mapper` to refer +to an abstaction over a KVStore that handles marshalling and unmarshalling a +particular data type to and from the underlying store. -## Transaction +The `x/auth` module provides an `AccountMapper` that allows us to get and +set `Account` types to the store. Note the benefit of using the `Account` +interface here - developers can implement their own account type that extends +the `BaseAccount` to store additional data without requiring another lookup from +the store. +Creating an AccountMapper is easy - we just need to specify a codec, a +capability key, and a prototype of the object being encoded (TODO: change to +constructor): -### StdTx +```go +accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) +``` -The standard way to create a transaction from a message is to use the `StdTx` struct defined in the `x/auth` module: +See the [AccountMapper API docs](TODO) for more information. + +## StdTx + +Now that we have a native model for accounts, it's time to introduce the native +`Tx` type, the `auth.StdTx`: ```go // StdTx is a standard way to wrap a Msg with Fee and Signatures. @@ -118,12 +122,17 @@ type StdTx struct { } ``` -The `StdTx` includes a list of messages, information about the fee being paid, -and a list of signatures. It also includes an optional `Memo` for additional -data. Note that the list of signatures must match the result of `GetSigners()` -for each `Msg`! +This is the standard form for a transaction in the SDK. Besides the Msgs, it +includes: -The signatures are provided in a standard form as `StdSignature`: +- a fee to be paid by the first signer +- replay protecting nonces in the signature +- a memo of prunable additional data + +Details on how these components are validated is provided under +[auth.AnteHandler](#ante-handler) below. + +The standard form for signatures is `StdSignature`: ```go // StdSignature wraps the Signature and includes counters for replay protection. @@ -137,17 +146,7 @@ type StdSignature struct { } ``` -Recall that the `Sequence` is expected to increment every time a -message is signed by a given account in order to prevent "replay attacks" where -the same message could be executed over and over again. The `AccountNumber` is -assigned when the account is created or recreated after being emptied. - -The `StdSignature` can also optionally include the public key for verifying the -signature. The public key only needs to be included the first time a transaction -is sent from a given account - from then on it will be stored in the `Account` -and can be left out of transactions. - -The fee is provided in a standard form as `StdFee`: +And the standard form for a transaction fee is `StdFee`: ```go // StdFee includes the amount of coins paid in fees and the maximum @@ -159,11 +158,7 @@ type StdFee struct { } ``` -Note that the address responsible for paying the transactions fee is the first address -returned by msg.GetSigners() for the first `Msg`. The convenience function `FeePayer(tx Tx)` is provided -to return this. - -### Signing +## Signing The standard bytes for signers to sign over is provided by: @@ -175,6 +170,25 @@ TODO TODO +The list of signatures in the `StdTx` must match the result of `GetSigners()` +for each `Msg`. The validation rules for the `StdTx` will be defined in the + +Recall that the `Sequence` is expected to increment every time a +message is signed by a given account in order to prevent "replay attacks" where +the same message could be executed over and over again. The `AccountNumber` is +assigned when the account is created or recreated after being emptied. + +The `StdSignature` can also optionally include the public key for verifying the +signature. The public key only needs to be included the first time a transaction +is sent from a given account - from then on it will be stored in the `Account` +and can be left out of transactions. + +The fee is provided in a standard form as `StdFee`: +Note that the address responsible for paying the transactions fee is the first address +returned by msg.GetSigners() for the first `Msg`. The convenience function `FeePayer(tx Tx)` is provided +to return this. + + ## App3 Putting it all together, we get: From b335d3bb70873d6213d7ad7ff7bce5dc4561b8ab Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Jun 2018 09:53:00 -0400 Subject: [PATCH 24/77] app3 ante handler --- docs/README.md | 17 +++++---- docs/core/app3.md | 89 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 81 insertions(+), 25 deletions(-) diff --git a/docs/README.md b/docs/README.md index 41cfe403e6..e74d1aef86 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,13 +21,16 @@ NOTE: This documentation is a work-in-progress! - [Amino](core/app2.md#amino) - Amino is the primary serialization library used in the SDK - [Ante Handler](core/app2.md#ante-handler) - The AnteHandler authenticates transactions - - [App3 - Modules](core/app3.md) - - [Accounts](core/app3.md#accounts) - Accounts are the prototypical object kept in the store - provides Account lookup on a KVStore - - [Transactions](core/app3.md#transactions) - `StdTx` is the default - implementation of `Tx` - - [CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin - transfer on an underlying AccountMapper + - [App3 - Modules: Auth and Bank](core/app3.md) + - [auth.Account](core/app3.md#accounts) - Accounts are the prototypical object kept in the store + - [auth.AccountMapper](core/app3.md#account-mapper) - AccountMapper gets and sets Account on a KVStore + - [auth.StdTx](core/app3.md#stdtx) - `StdTx` is the default implementation of `Tx` + - [auth.StdSignBytes](core/app3.md#signing) - `StdTx` must be signed with certain + information + - [auth.AnteHandler](core/app3.md#ante-handler) - The `AnteHandler` + verifies `StdTx`, manages accounts, and deducts fees + - [bank.CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin + transfers on an underlying AccountMapper - [App4 - Validator Set Changes](core/app4.md) - [InitChain](core/app4.md#init-chain) - Initialize the application state diff --git a/docs/core/app3.md b/docs/core/app3.md index c9a37c6f3e..bbff36f2c0 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -33,6 +33,10 @@ In this model, an account contains: - Sequence to prevent transaction replays - Coins to carry a balance +Note that the `AccountNumber` is a unique number that is assigned when the account is +created, and the `Sequence` is incremented by one every time a transaction is +sent from the account. + ### Account The `Account` interface captures this account model with getters and setters: @@ -146,7 +150,21 @@ type StdSignature struct { } ``` -And the standard form for a transaction fee is `StdFee`: +The signature includes both an `AccountNumber` and a `Sequence`. +The `Sequence` must match the one in the +corresponding account when the transaction is processed, and will increment by +one with every transaction. This prevents the same +transaction from being replayed multiple times, resolving the insecurity that +remains in App2. + +The `AccountNumber` is also for replay protection - it allows accounts to be +deleted from the store when they run out of accounts. If an account receives +coins after it is deleted, the account will be re-created, with the Sequence +reset to 0, but a new AccountNumber. If it weren't for the AccountNumber, the +last sequence of transactions made by the account before it was deleted could be +replayed! + +Finally, the standard form for a transaction fee is `StdFee`: ```go // StdFee includes the amount of coins paid in fees and the maximum @@ -158,36 +176,71 @@ type StdFee struct { } ``` +The fee must be paid by the first signer. This allows us to quickly check if the +transaction fee can be paid, and reject the transaction if not. + ## Signing -The standard bytes for signers to sign over is provided by: +The `StdTx` supports multiple messages and multiple signers. +To sign the transaction, each signer must collect the following information: + +- the ChainID (TODO haven't mentioned this yet) +- the AccountNumber and Sequence for the given signer's account (from the + blockchain) +- the transaction fee +- the list of transaction messages +- an optional memo + +Then they can compute the transaction bytes to sign using the +`auth.StdSignBytes` function: ```go -TODO +bytesToSign := StdSignBytes(chainID, accNum, accSequence, fee, msgs, memo) ``` ## AnteHandler -TODO +As we saw in `App2`, we can use an `AnteHandler` to authenticate transactions +before we handle any of their internal messages. While previously we implemented +our own simple `AnteHandler`, the `x/auth` module provides a much more advanced +one that uses `AccountMapper` and works with `StdTx`: -The list of signatures in the `StdTx` must match the result of `GetSigners()` -for each `Msg`. The validation rules for the `StdTx` will be defined in the +```go +TODO: feekeeper :( +app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) +``` -Recall that the `Sequence` is expected to increment every time a -message is signed by a given account in order to prevent "replay attacks" where -the same message could be executed over and over again. The `AccountNumber` is -assigned when the account is created or recreated after being emptied. +The AnteHandler provided by `x/auth` enforces the following rules: -The `StdSignature` can also optionally include the public key for verifying the -signature. The public key only needs to be included the first time a transaction -is sent from a given account - from then on it will be stored in the `Account` -and can be left out of transactions. +- the memo must not be too big +- the right number of signatures must be provided (one for each unique signer + returned by `msg.GetSigner` for each `msg`) +- any account signing for the first-time must include a public key in the + StdSignature +- the signatures must be valid when authenticated in the same order as specified + by the messages -The fee is provided in a standard form as `StdFee`: -Note that the address responsible for paying the transactions fee is the first address -returned by msg.GetSigners() for the first `Msg`. The convenience function `FeePayer(tx Tx)` is provided -to return this. +Note that validating +signatures requires checking that the correct account number and sequence was +used by each signer, as this information is required in the `StdSignBytes`. +If any of the above are not satisfied, it returns an error. + +If all of the above verifications pass, the AnteHandler makes the following +changes to the state: + +- increment account sequence by one for all signers +- set the pubkey for any first-time signers +- deduct the fee from the first signer + +Recall that incrementing the `Sequence` prevents "replay attacks" where +the same message could be executed over and over again. + +The PubKey is required for signature verification, but it is only required in +the StdSignature once. From that point on, it will be stored in the account. + +The fee is paid by the first address returned by msg.GetSigners() for the first `Msg`. +The convenience function `FeePayer(tx Tx) sdk.Address` is provided to return this. ## App3 From 0c5e3fdc74be5e520432eeae8434fe82670fd52b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Jun 2018 10:08:55 -0400 Subject: [PATCH 25/77] some cleanup, remove old files --- docs/core/app1.md | 18 +++++++++++------- docs/core/app3.md | 36 ++++++++++++++++++++++++++++++++++++ docs/core/handlers.md | 31 ------------------------------- docs/core/intro.md | 9 ++++----- docs/core/multistore.md | 5 ++++- 5 files changed, 55 insertions(+), 44 deletions(-) delete mode 100644 docs/core/handlers.md diff --git a/docs/core/app1.md b/docs/core/app1.md index e4a9f4b147..08fcf73fe3 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -94,7 +94,7 @@ func (msg MsgSend) ValidateBasic() sdk.Error { } ``` -# KVStore +## KVStore The basic persistence layer for an SDK application is the KVStore: @@ -140,7 +140,7 @@ like Ethereum's radix trie. As we'll soon see, apps have many distinct KVStores, each with a different name and for a different concern. Access to a store is mediated by *object-capability keys*, which must be granted to a handler during application startup. -# Handlers +## Handlers Now that we have a message type and a store interface, we can define our state transition function using a handler: @@ -150,11 +150,12 @@ type Handler func(ctx Context, msg Msg) Result ``` Along with the message, the Handler takes environmental information (a `Context`), and returns a `Result`. +All information necessary for processing a message should be available in the context. Where is the KVStore in all of this? Access to the KVStore in a message handler is restricted by the Context via object-capability keys. Only handlers which were given explict access to a store's key will be able to access that store during message processsing. -## Context +### Context The SDK uses a `Context` to propogate common information across functions. Most importantly, the `Context` restricts access to KVStores based on object-capability keys. @@ -181,7 +182,7 @@ The Context also contains the [block header](TODO), which includes the latest ti See the [Context API docs](TODO) for more details. -## Result +### Result Handler takes a Context and Msg and returns a Result. Result is motivated by the corresponding [ABCI result](TODO). It contains return values, error information, logs, and meta data about the transaction: @@ -219,7 +220,7 @@ We'll talk more about these fields later in the tutorial. For now, note that a failure. The `Tags` can contain meta data about the transaction that will allow us to easily lookup transactions that pertain to particular accounts or actions. -## Handler +### Handler Let's define our handler for App1: @@ -455,8 +456,11 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { Every app will have such a function that defines the setup of the app. It will typically be contained in an `app.go` file. We'll talk about how to connect this app object with the CLI, a REST API, -the logger, and the filesystem later in the tutorial. For now, note that this is where we grant handlers access to stores. -Here, we have only one store and one handler, and the handler is granted access by giving it the capability key. +the logger, and the filesystem later in the tutorial. For now, note that this is where we +register handlers for messages and grant them access to stores. + +Here, we have only a single Msg type, `bank`, a single store for accounts, and a single handler. +The handler is granted access to the store by giving it the capability key. In future apps, we'll have multiple stores and handlers, and not every handler will get access to every store. After setting the transaction decoder and the message handling routes, the final diff --git a/docs/core/app3.md b/docs/core/app3.md index bbff36f2c0..2cfd0cb046 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -108,6 +108,21 @@ constructor): accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) ``` +Then we can get, modify, and set accounts. For instance, we could double the +amount of coins in an account: + +```go +acc := GetAccount(ctx, addr)` +acc.SetCoins(acc.Coins.Plus(acc.Coins)) +acc.SetAccount(ctx, addr) +``` + +Note that the `AccountMapper` takes a `Context` as the first argument, and will +load the KVStore from there using the capability key it was granted on creation. + +Also note that you must explicitly call `SetAccount` after mutating an account +for the change to persist! + See the [AccountMapper API docs](TODO) for more information. ## StdTx @@ -242,6 +257,27 @@ the StdSignature once. From that point on, it will be stored in the account. The fee is paid by the first address returned by msg.GetSigners() for the first `Msg`. The convenience function `FeePayer(tx Tx) sdk.Address` is provided to return this. +## CoinKeeper + +Updating accounts is made easier by using the `Keeper` struct in the `x/bank` module. + +Example Initialization: + +```go +// File: examples/basecoin/app/app.go +app.coinKeeper = bank.NewKeeper(app.accountMapper) +``` + +Example Usage: + +```go +// Finds account with addr in accountmapper +// Adds coins to account's coin array +// Sets updated account in accountmapper +app.coinKeeper.AddCoins(ctx, addr, coins) +``` + + ## App3 Putting it all together, we get: diff --git a/docs/core/handlers.md b/docs/core/handlers.md deleted file mode 100644 index 8b2ef8f82e..0000000000 --- a/docs/core/handlers.md +++ /dev/null @@ -1,31 +0,0 @@ -# Handlers - -A handler takes a context and a message and returns a result. All -information necessary for processing a message should be available in the -context. - -While the context holds the entire application state (ie. the -MultiStore), handlers are restricted in what they can do based on the -capabilities they were given when the application was set up. - -For instance, suppose we have a `newFooHandler`: - -```go -func newFooHandler(key sdk.StoreKey) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - store := ctx.KVStore(key) - // ... - } -} -``` - -This handler can only access one store based on whichever key its given. -So when we register the handler for the `foo` message type, we make sure -to give it the `fooKey`: - -``` -app.Router().AddRoute("foo", newFooHandler(fooKey)) -``` - -Now it can only access the `foo` store, but not the `bar` or `cat` stores! - diff --git a/docs/core/intro.md b/docs/core/intro.md index df5c928d58..c1347260de 100644 --- a/docs/core/intro.md +++ b/docs/core/intro.md @@ -10,8 +10,7 @@ the Basecoin application, with each implementation showcasing a new component of the SDK: - App1 - The Basics - Messages, Stores, Handlers, BaseApp -- App2 - Amino - Unmarshalling into interfaces -- App3 - Authentication - Accounts and Transactions, Signatures and Replay protection -- App4 - Access Control - Keepers selective expose access to stores -- App5 - Validator Set Changes - Change the Tendermint validator set -- App6 - Basecoin - Bringing it all together +- App2 - Transactions - Amino and AnteHandler +- App3 - Modules - `x/auth` and `x/bank` +- App4 - Validator Set Changes - Change the Tendermint validator set +- App5 - Basecoin - Bringing it all together diff --git a/docs/core/multistore.md b/docs/core/multistore.md index 9b7f6cd199..cd733ed217 100644 --- a/docs/core/multistore.md +++ b/docs/core/multistore.md @@ -1,6 +1,9 @@ # MultiStore -TODO: reconcile this +TODO: reconcile this with everything ... would be nice to have this explanation +somewhere but where does it belong ? So far we've already showed how to use it +all by creating KVStore keys and calling app.MountStoresIAVL ! + The Cosmos-SDK provides a special Merkle database called a `MultiStore` to be used for all application storage. The MultiStore consists of multiple Stores that must be mounted to the From 6bbe295d7fd75fc3693f68915519b483bdd4e514 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 27 Jun 2018 12:45:01 -0400 Subject: [PATCH 26/77] app3 coin keeper --- docs/README.md | 4 +-- docs/core/app3.md | 67 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/docs/README.md b/docs/README.md index e74d1aef86..341000a941 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,7 +19,7 @@ NOTE: This documentation is a work-in-progress! - [BaseApp](core/app1.md#baseapp) - BaseApp is the base layer of the application - [App2 - Transactions](core/app2.md) - [Amino](core/app2.md#amino) - Amino is the primary serialization library used in the SDK - - [Ante Handler](core/app2.md#ante-handler) - The AnteHandler + - [Ante Handler](core/app2.md#antehandler) - The AnteHandler authenticates transactions - [App3 - Modules: Auth and Bank](core/app3.md) - [auth.Account](core/app3.md#accounts) - Accounts are the prototypical object kept in the store @@ -27,7 +27,7 @@ NOTE: This documentation is a work-in-progress! - [auth.StdTx](core/app3.md#stdtx) - `StdTx` is the default implementation of `Tx` - [auth.StdSignBytes](core/app3.md#signing) - `StdTx` must be signed with certain information - - [auth.AnteHandler](core/app3.md#ante-handler) - The `AnteHandler` + - [auth.AnteHandler](core/app3.md#antehandler) - The `AnteHandler` verifies `StdTx`, manages accounts, and deducts fees - [bank.CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin transfers on an underlying AccountMapper diff --git a/docs/core/app3.md b/docs/core/app3.md index 2cfd0cb046..3f35b9c1eb 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -21,6 +21,7 @@ their own modules. Here, we'll introduce the important types from `x/auth` and `x/bank`, and show how to make `App3` by using them. The complete code can be found in [app3.go](examples/app3.go). +For more details, see the [x/auth](TODO) and [x/bank](TODO) API documentation. ## Accounts @@ -112,7 +113,7 @@ Then we can get, modify, and set accounts. For instance, we could double the amount of coins in an account: ```go -acc := GetAccount(ctx, addr)` +acc := GetAccount(ctx, addr) acc.SetCoins(acc.Coins.Plus(acc.Coins)) acc.SetAccount(ctx, addr) ``` @@ -149,7 +150,7 @@ includes: - a memo of prunable additional data Details on how these components are validated is provided under -[auth.AnteHandler](#ante-handler) below. +[auth.AnteHandler](#antehandler) below. The standard form for signatures is `StdSignature`: @@ -213,6 +214,11 @@ Then they can compute the transaction bytes to sign using the bytesToSign := StdSignBytes(chainID, accNum, accSequence, fee, msgs, memo) ``` +Note these bytes are unique for each signer, as they depend on the particular +signers AccountNumber, Sequence, and optional memo. To facilitate easy +inspection before signing, the bytes are actually just a JSON encoded form of +all the relevant information. + ## AnteHandler As we saw in `App2`, we can use an `AnteHandler` to authenticate transactions @@ -239,14 +245,14 @@ Note that validating signatures requires checking that the correct account number and sequence was used by each signer, as this information is required in the `StdSignBytes`. -If any of the above are not satisfied, it returns an error. +If any of the above are not satisfied, the AnteHandelr returns an error. If all of the above verifications pass, the AnteHandler makes the following changes to the state: - increment account sequence by one for all signers -- set the pubkey for any first-time signers -- deduct the fee from the first signer +- set the pubkey in the account for any first-time signers +- deduct the fee from the first signer's account Recall that incrementing the `Sequence` prevents "replay attacks" where the same message could be executed over and over again. @@ -254,33 +260,64 @@ the same message could be executed over and over again. The PubKey is required for signature verification, but it is only required in the StdSignature once. From that point on, it will be stored in the account. -The fee is paid by the first address returned by msg.GetSigners() for the first `Msg`. +The fee is paid by the first address returned by `msg.GetSigners()` for the first `Msg`. The convenience function `FeePayer(tx Tx) sdk.Address` is provided to return this. ## CoinKeeper -Updating accounts is made easier by using the `Keeper` struct in the `x/bank` module. +Now that we've seen the `auth.AccountMapper` and how its used to build a +complete AnteHandler, it's time to look at how to build higher-level +abstractions for taking action on accounts. -Example Initialization: +Earlier, we noted that `Mappers` abstactions over a KVStore that handles marshalling and unmarshalling a +particular data type to and from the underlying store. We can build another +abstraction on top of `Mappers` that we call `Keepers`, which expose only +limitted functionality on the underlying types stored by the `Mapper`. + +For instance, the `x/bank` module defines the canonical versions of `MsgSend` +and `MsgIssue` for the SDK, as well as a `Handler` for processing them. However, +rather than passing a `KVStore` or even an `AccountMapper` directly to the handler, +we introduce a `bank.Keeper`, which can only be used to transfer coins in and out of accounts. +This allows us to determine up front that the only effect the bank module's +`Handler` can have on the store is to change the amount of coins in an account - +it can't increment sequence numbers, change PubKeys, or otherwise. + + +A `bank.Keeper` is easily instantiated from an `AccountMapper`: ```go -// File: examples/basecoin/app/app.go -app.coinKeeper = bank.NewKeeper(app.accountMapper) +coinKeeper = bank.NewKeeper(accountMapper) ``` -Example Usage: +We can then use it within a handler, instead of working directly with the +`AccountMapper`. For instance, to add coins to an account: ```go -// Finds account with addr in accountmapper -// Adds coins to account's coin array -// Sets updated account in accountmapper +// Finds account with addr in AccountMapper. +// Adds coins to account's coin array. +// Sets updated account in AccountMapper app.coinKeeper.AddCoins(ctx, addr, coins) ``` +See the [bank.Keeper API docs](TODO) for the full set of methods. + +Note we can refine the `bank.Keeper` by restricting it's method set. For +instance, the `bank.ViewKeeper` is a read-only version, while the +`bank.SendKeeper` only executes transfers of coins from input accounts to output +accounts. + +We use this `Keeper` paradigm extensively in the SDK as the way to define what +kind of functionality each module gets access to. In particular, we try to +follow the *principle of least authority*, where modules only get access to the +absolutely narrowest set of functionality they need to get the job done. Hence, +rather than providing full blown access to the `KVStore` or the `AccountMapper`, +we restrict access to a small number of functions that do very specific things. ## App3 -Putting it all together, we get: +Armed with an understanding of mappers and keepers, in particular the +`auth.AccountMapper` and the `bank.Keeper`, we're now ready to build `App3` +using the `x/auth` and `x/bank` modules to do all the heavy lifting: ```go TODO From 49f421db1936c68d8405001055ff955858f15334 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Wed, 27 Jun 2018 15:33:56 -0700 Subject: [PATCH 27/77] Merge PR #1332: benchmarks: Add benchmark for block time to bank module * benchmarks: Add benchmark folder, and single benchmark for block time * Move benchmark into module * Fix merge conflict errors * Fix spelling * Add instructions to run benchmark * Update auth_app_test.go --- CHANGELOG.md | 2 + baseapp/baseapp_test.go | 2 +- x/auth/mock/auth_app_test.go | 71 +++++++++++++++++++++++++++++++---- x/auth/mock/simulate_block.go | 20 +++++++++- x/bank/app_test.go | 12 +++++- x/bank/bench_test.go | 41 ++++++++++++++++++++ 6 files changed, 136 insertions(+), 12 deletions(-) create mode 100644 x/bank/bench_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c55365cf9..7f73eaa84c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ FEATURES * Supported proposal types: just binary (pass/fail) TextProposals for now * Proposals need deposits to be votable; deposits are burned if proposal fails * Delegators delegate votes to validator by default but can override (for their stake) +* Add benchmarks for signing and delivering a block with a single bank transaction + * Run with `cd x/bank && go test --bench=.` * [tools] make get_tools installs tendermint's linter, and gometalinter * [tools] Switch gometalinter to the stable version * [tools] Add checking for misspellings and for incorrectly formatted files in circle CI diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index c939996c76..dc46b38d15 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -3,7 +3,6 @@ package baseapp import ( "encoding/json" "fmt" - "github.com/cosmos/cosmos-sdk/x/bank" "os" "testing" @@ -20,6 +19,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" ) func defaultLogger() log.Logger { diff --git a/x/auth/mock/auth_app_test.go b/x/auth/mock/auth_app_test.go index 4442200f10..8da93c9670 100644 --- a/x/auth/mock/auth_app_test.go +++ b/x/auth/mock/auth_app_test.go @@ -3,14 +3,38 @@ package mock import ( "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/auth" + abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" ) +// A mock transaction that has a validation which can fail. +type testMsg struct { + signers []sdk.Address + positiveNum int64 +} + +// TODO: Clean this up, make it public +const msgType = "testMsg" + +func (tx testMsg) Type() string { return msgType } +func (tx testMsg) GetMsg() sdk.Msg { return tx } +func (tx testMsg) GetMemo() string { return "" } +func (tx testMsg) GetSignBytes() []byte { return nil } +func (tx testMsg) GetSigners() []sdk.Address { return tx.signers } +func (tx testMsg) GetSignatures() []auth.StdSignature { return nil } +func (tx testMsg) ValidateBasic() sdk.Error { + if tx.positiveNum >= 0 { + return nil + } + return sdk.ErrTxDecode("positiveNum should be a non-negative integer.") +} + // test auth module messages var ( @@ -20,19 +44,50 @@ var ( addr2 = priv2.PubKey().Address() coins = sdk.Coins{sdk.NewCoin("foocoin", 10)} - sendMsg1 = bank.MsgSend{ - Inputs: []bank.Input{bank.NewInput(addr1, coins)}, - Outputs: []bank.Output{bank.NewOutput(addr2, coins)}, - } + testMsg1 = testMsg{signers: []sdk.Address{addr1}, positiveNum: 1} ) // initialize the mock application for this module func getMockApp(t *testing.T) *App { mapp := NewApp() - coinKeeper := bank.NewKeeper(mapp.AccountMapper) - mapp.Router().AddRoute("bank", bank.NewHandler(coinKeeper)) - + mapp.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{})) return mapp } + +func TestMsgPrivKeys(t *testing.T) { + mapp := getMockApp(t) + mapp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil) + + // Construct some genesis bytes to reflect basecoin/types/AppAccount + // Give 77 foocoin to the first key + coins := sdk.Coins{sdk.NewCoin("foocoin", 77)} + acc1 := &auth.BaseAccount{ + Address: addr1, + Coins: coins, + } + accs := []auth.Account{acc1} + + // Construct genesis state + SetGenesis(mapp, accs) + + // A checkTx context (true) + ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) + res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) + assert.Equal(t, acc1, res1.(*auth.BaseAccount)) + + // Run a CheckDeliver + SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{0}, true, priv1) + + // signing a SendMsg with the wrong privKey should be an auth error + mapp.BeginBlock(abci.RequestBeginBlock{}) + tx := GenTx([]sdk.Msg{testMsg1}, []int64{0}, []int64{1}, priv2) + res := mapp.Deliver(tx) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) + + // resigning the tx with the correct priv key should still work + res = SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{1}, true, priv1) + + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), res.Code, res.Log) +} diff --git a/x/auth/mock/simulate_block.go b/x/auth/mock/simulate_block.go index e2e67b4cf0..7e8f508433 100644 --- a/x/auth/mock/simulate_block.go +++ b/x/auth/mock/simulate_block.go @@ -54,6 +54,23 @@ func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyE return auth.NewStdTx(msgs, fee, sigs, memo) } +// generate a set of signed transactions a msg, that differ only by having the +// sequence numbers incremented between every transaction. +func GenSequenceOfTxs(msgs []sdk.Msg, accnums []int64, initSeqNums []int64, numToGenerate int, priv ...crypto.PrivKeyEd25519) []auth.StdTx { + txs := make([]auth.StdTx, numToGenerate, numToGenerate) + for i := 0; i < numToGenerate; i++ { + txs[i] = GenTx(msgs, accnums, initSeqNums, priv...) + incrementAllSequenceNumbers(initSeqNums) + } + return txs +} + +func incrementAllSequenceNumbers(initSeqNums []int64) { + for i := 0; i < len(initSeqNums); i++ { + initSeqNums[i]++ + } +} + // check a transaction result func SignCheck(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.Result { tx := GenTx(msgs, accnums, seq, priv...) @@ -62,7 +79,7 @@ func SignCheck(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int } // simulate a block -func SignCheckDeliver(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) { +func SignCheckDeliver(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) sdk.Result { // Sign the tx tx := GenTx(msgs, accnums, seq, priv...) @@ -86,4 +103,5 @@ func SignCheckDeliver(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnum app.EndBlock(abci.RequestEndBlock{}) app.Commit() + return res } diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 6107126b47..b38ef4a45d 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -77,14 +77,22 @@ var ( // initialize the mock application for this module func getMockApp(t *testing.T) *mock.App { + mapp, err := getBenchmarkMockApp() + require.NoError(t, err) + return mapp +} + +// getBenchmarkMockApp initializes a mock application for this module, for purposes of benchmarking +// Any long term API support commitments do not apply to this function. +func getBenchmarkMockApp() (*mock.App, error) { mapp := mock.NewApp() RegisterWire(mapp.Cdc) coinKeeper := NewKeeper(mapp.AccountMapper) mapp.Router().AddRoute("bank", NewHandler(coinKeeper)) - require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{})) - return mapp + err := mapp.CompleteSetup([]*sdk.KVStoreKey{}) + return mapp, err } func TestMsgSendWithAccounts(t *testing.T) { diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go new file mode 100644 index 0000000000..97a5c45262 --- /dev/null +++ b/x/bank/bench_test.go @@ -0,0 +1,41 @@ +package bank + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/mock" + + abci "github.com/tendermint/abci/types" +) + +func BenchmarkOneBankSendTxPerBlock(b *testing.B) { + benchmarkApp, _ := getBenchmarkMockApp() + + // Add an account at genesis + acc := &auth.BaseAccount{ + Address: addr1, + // Some value conceivably higher than the benchmarks would ever go + Coins: sdk.Coins{sdk.NewCoin("foocoin", 100000000000)}, + } + accs := []auth.Account{acc} + + // Construct genesis state + mock.SetGenesis(benchmarkApp, accs) + // Precompute all txs + txs := mock.GenSequenceOfTxs([]sdk.Msg{sendMsg1}, []int64{0}, []int64{int64(0)}, b.N, priv1) + b.ResetTimer() + // Run this with a profiler, so its easy to distinguish what time comes from + // Committing, and what time comes from Check/Deliver Tx. + for i := 0; i < b.N; i++ { + benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) + x := benchmarkApp.Check(txs[i]) + if !x.IsOK() { + panic("something is broken in checking transaction") + } + benchmarkApp.Deliver(txs[i]) + benchmarkApp.EndBlock(abci.RequestEndBlock{}) + benchmarkApp.Commit() + } +} From 9b4838d96e846b2e26e7acc7632c6ac458b056fe Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 27 Jun 2018 15:45:10 -0700 Subject: [PATCH 28/77] Merge PR #1367: Set ChainID on InitChain * Added chain-id to context in InitChain * Fix bug in test * fmt * Appease linter * updated changelog * Remove chainID hack * setCheckState in InitChain * Fix bug * Fix initialization errors in example tests * Initialize app tests with default stake genesis * fix comments --- CHANGELOG.md | 1 + baseapp/baseapp.go | 19 +++++++++++-------- baseapp/baseapp_test.go | 18 ++++++++++++++---- examples/basecoin/app/app_test.go | 13 +++++++++++++ examples/democoin/app/app_test.go | 1 + 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f73eaa84c..2a2ed1de36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ FIXES * Fixed bug where chain ID wasn't passed properly in x/bank REST handler, removed Viper hack from ante handler * Fixed bug where `democli account` didn't decode the account data correctly * \#1343 - fixed unnecessary parallelism in CI +* \#1367 - set ChainID in InitChain * \#1353 - CLI: Show pool shares fractions in human-readable format * \#1258 - printing big.rat's can no longer overflow int64 diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index b1c7e54605..9c4d100cd3 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -224,9 +224,6 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error { } */ - // initialize Check state - app.setCheckState(abci.Header{}) - return nil } @@ -287,12 +284,13 @@ func (app *BaseApp) SetOption(req abci.RequestSetOption) (res abci.ResponseSetOp // Implements ABCI // InitChain runs the initialization logic directly on the CommitMultiStore and commits it. func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain) { + // Initialize the deliver state and check state with ChainID and run initChain + app.setDeliverState(abci.Header{ChainID: req.ChainId}) + app.setCheckState(abci.Header{ChainID: req.ChainId}) + if app.initChainer == nil { return } - - // Initialize the deliver state and run initChain - app.setDeliverState(abci.Header{}) app.initChainer(app.deliverState.ctx, req) // no error // NOTE: we don't commit, but BeginBlock for block 1 @@ -379,10 +377,15 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) { // Initialize the DeliverTx state. // If this is the first block, it should already - // be initialized in InitChain. It may also be nil - // if this is a test and InitChain was never called. + // be initialized in InitChain. + // Otherwise app.deliverState will be nil, since it + // is reset on Commit. if app.deliverState == nil { app.setDeliverState(req.Header) + } else { + // In the first block, app.deliverState.ctx will already be initialized + // by InitChain. Context is now updated with Header information. + app.deliverState.ctx = app.deliverState.ctx.WithBlockHeader(req.Header) } if app.beginBlocker != nil { res = app.beginBlocker(app.deliverState.ctx, req) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index dc46b38d15..c208ec3b8f 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -202,7 +202,15 @@ func TestInitChainer(t *testing.T) { // set initChainer and try again - should see the value app.SetInitChainer(initChainer) - app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}")}) // must have valid JSON genesis file, even if empty + app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty + + // assert that chainID is set correctly in InitChain + chainID := app.deliverState.ctx.ChainID() + assert.Equal(t, "test-chain-id", chainID, "ChainID in deliverState not set correctly in InitChain") + + chainID = app.checkState.ctx.ChainID() + assert.Equal(t, "test-chain-id", chainID, "ChainID in checkState not set correctly in InitChain") + app.Commit() res = app.Query(query) assert.Equal(t, value, res.Value) @@ -378,13 +386,15 @@ func TestSimulateTx(t *testing.T) { return ttx, nil }) + app.InitChain(abci.RequestInitChain{}) + nBlocks := 3 for blockN := 0; blockN < nBlocks; blockN++ { // block1 header.Height = int64(blockN + 1) app.BeginBlock(abci.RequestBeginBlock{Header: header}) result := app.Simulate(tx) - require.Equal(t, result.Code, sdk.ABCICodeOK) + require.Equal(t, result.Code, sdk.ABCICodeOK, result.Log) require.Equal(t, int64(80), result.GasUsed) counter-- encoded, err := json.Marshal(tx) @@ -397,8 +407,8 @@ func TestSimulateTx(t *testing.T) { require.Equal(t, queryResult.Code, uint32(sdk.ABCICodeOK)) var res sdk.Result app.cdc.MustUnmarshalBinary(queryResult.Value, &res) - require.Equal(t, sdk.ABCICodeOK, res.Code) - require.Equal(t, int64(160), res.GasUsed) + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) + require.Equal(t, int64(160), res.GasUsed, res.Log) app.EndBlock(abci.RequestEndBlock{}) app.Commit() } diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 23bc531c03..c3ba39b3d3 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -2,7 +2,9 @@ package app import ( "os" + "fmt" "testing" + "encoding/json" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -12,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/stake" + gen "github.com/cosmos/cosmos-sdk/x/stake/types" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" @@ -71,6 +74,16 @@ func TestGenesis(t *testing.T) { // reload app and ensure the account is still there bapp = NewBasecoinApp(logger, db) + // Initialize stake data with default genesis state + stakedata := gen.DefaultGenesisState() + genState, err := json.Marshal(stakedata) + if err != nil { + panic(err) + } + + // InitChain with default stake data. Initializes deliverState and checkState context + bapp.InitChain(abci.RequestInitChain{AppStateBytes: []byte(fmt.Sprintf("{\"stake\": %s}", string(genState)))}) + ctx = bapp.BaseApp.NewContext(true, abci.Header{}) res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address) assert.Equal(t, acc, res1) diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index 01264399ae..a477ef79bb 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -55,6 +55,7 @@ func TestGenesis(t *testing.T) { // reload app and ensure the account is still there bapp = NewDemocoinApp(logger, db) + bapp.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}")}) ctx = bapp.BaseApp.NewContext(true, abci.Header{}) res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address) assert.Equal(t, acc, res1) From 4effa6f8d4f8a09586d09ef38c40ee5dccbddf20 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Wed, 27 Jun 2018 16:49:59 -0700 Subject: [PATCH 29/77] Merge PR #1357: RESTful governance endpoints * get deposit rest endpoint * query proposals * changelog * fixed commented out headers * fixed undeterministic tests * increase circle test timeout * MustBech32ifyAcc * asdf --- .circleci/config.yml | 2 +- CHANGELOG.md | 1 + client/lcd/lcd_test.go | 144 +++++++++++++++++++++-- x/gov/client/rest/rest.go | 241 ++++++++++++++++++++++++++++++++++---- x/gov/depositsvotes.go | 26 +++- x/gov/keeper.go | 8 +- 6 files changed, 380 insertions(+), 42 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ce01e3971c..bb1ad16714 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -119,7 +119,7 @@ jobs: for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v /vendor/ | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | circleci tests split --split-by=timings); do id=$(basename "$pkg") - go test -timeout 5m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" + go test -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" done - persist_to_workspace: root: /tmp/workspace diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a2ed1de36..70d3c303ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ BREAKING CHANGES * Removed MsgChangePubKey from auth * Removed setPubKey from account mapper * Removed GetMemo from Tx (it is still on StdTx) +* Gov module REST endpoints changed to be more RESTful * [cli] rearranged commands under subcommands * [stake] remove Tick and add EndBlocker * [stake] introduce concept of unbonding for delegations and validators diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 40bc77b7ee..07bb4b252e 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -475,6 +475,10 @@ func TestDeposit(t *testing.T) { // query proposal proposal = getProposal(t, port, proposalID) assert.True(t, proposal.TotalDeposit.IsEqual(sdk.Coins{sdk.NewCoin("steak", 10)})) + + // query deposit + deposit := getDeposit(t, port, proposalID, addr) + assert.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewCoin("steak", 10)})) } func TestVote(t *testing.T) { @@ -515,6 +519,75 @@ func TestVote(t *testing.T) { assert.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option) } +func TestProposalsQuery(t *testing.T) { + name, password := "test", "1234567890" + name2, password := "test2", "1234567890" + addr, seed := CreateAddr(t, "test", password, GetKB(t)) + addr2, seed2 := CreateAddr(t, "test2", password, GetKB(t)) + cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{addr, addr2}) + defer cleanup() + + // Addr1 proposes (and deposits) proposals #1 and #2 + resultTx := doSubmitProposal(t, port, seed, name, password, addr) + var proposalID1 int64 + cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1) + tests.WaitForHeight(resultTx.Height+1, port) + resultTx = doSubmitProposal(t, port, seed, name, password, addr) + var proposalID2 int64 + cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2) + tests.WaitForHeight(resultTx.Height+1, port) + + // Addr2 proposes (and deposits) proposals #3 + resultTx = doSubmitProposal(t, port, seed2, name2, password, addr2) + var proposalID3 int64 + cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3) + tests.WaitForHeight(resultTx.Height+1, port) + + // Addr2 deposits on proposals #2 & #3 + resultTx = doDeposit(t, port, seed2, name2, password, addr2, proposalID2) + tests.WaitForHeight(resultTx.Height+1, port) + resultTx = doDeposit(t, port, seed2, name2, password, addr2, proposalID3) + tests.WaitForHeight(resultTx.Height+1, port) + + // Addr1 votes on proposals #2 & #3 + resultTx = doVote(t, port, seed, name, password, addr, proposalID2) + tests.WaitForHeight(resultTx.Height+1, port) + resultTx = doVote(t, port, seed, name, password, addr, proposalID3) + tests.WaitForHeight(resultTx.Height+1, port) + + // Addr2 votes on proposal #3 + resultTx = doVote(t, port, seed2, name2, password, addr2, proposalID3) + tests.WaitForHeight(resultTx.Height+1, port) + + // Test query all proposals + proposals := getProposalsAll(t, port) + assert.Equal(t, proposalID1, (proposals[0]).ProposalID) + assert.Equal(t, proposalID2, (proposals[1]).ProposalID) + assert.Equal(t, proposalID3, (proposals[2]).ProposalID) + + // Test query deposited by addr1 + proposals = getProposalsFilterDepositer(t, port, addr) + assert.Equal(t, proposalID1, (proposals[0]).ProposalID) + + // Test query deposited by addr2 + proposals = getProposalsFilterDepositer(t, port, addr2) + assert.Equal(t, proposalID2, (proposals[0]).ProposalID) + assert.Equal(t, proposalID3, (proposals[1]).ProposalID) + + // Test query voted by addr1 + proposals = getProposalsFilterVoter(t, port, addr) + assert.Equal(t, proposalID2, (proposals[0]).ProposalID) + assert.Equal(t, proposalID3, (proposals[1]).ProposalID) + + // Test query voted by addr2 + proposals = getProposalsFilterVoter(t, port, addr2) + assert.Equal(t, proposalID3, (proposals[0]).ProposalID) + + // Test query voted and deposited by addr1 + proposals = getProposalsFilterVoterDepositer(t, port, addr, addr) + assert.Equal(t, proposalID2, (proposals[0]).ProposalID) +} + //_____________________________________________________________________________ // get the account to get the sequence func getAccount(t *testing.T, port string, addr sdk.Address) auth.Account { @@ -766,9 +839,19 @@ func getProposal(t *testing.T, port string, proposalID int64) gov.ProposalRest { return proposal } +func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.Address) gov.DepositRest { + bechDepositerAddr := sdk.MustBech32ifyAcc(depositerAddr) + res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, bechDepositerAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + var deposit gov.DepositRest + err := cdc.UnmarshalJSON([]byte(body), &deposit) + require.Nil(t, err) + return deposit +} + func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.Address) gov.VoteRest { bechVoterAddr := sdk.MustBech32ifyAcc(voterAddr) - res, body := Request(t, port, "GET", fmt.Sprintf("/gov/votes/%d/%s", proposalID, bechVoterAddr), nil) + res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes/%s", proposalID, bechVoterAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var vote gov.VoteRest err := cdc.UnmarshalJSON([]byte(body), &vote) @@ -776,6 +859,53 @@ func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.Address) return vote } +func getProposalsAll(t *testing.T, port string) []gov.ProposalRest { + res, body := Request(t, port, "GET", "/gov/proposals", nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var proposals []gov.ProposalRest + err := cdc.UnmarshalJSON([]byte(body), &proposals) + require.Nil(t, err) + return proposals +} + +func getProposalsFilterDepositer(t *testing.T, port string, depositerAddr sdk.Address) []gov.ProposalRest { + bechDepositerAddr := sdk.MustBech32ifyAcc(depositerAddr) + + res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositer=%s", bechDepositerAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var proposals []gov.ProposalRest + err := cdc.UnmarshalJSON([]byte(body), &proposals) + require.Nil(t, err) + return proposals +} + +func getProposalsFilterVoter(t *testing.T, port string, voterAddr sdk.Address) []gov.ProposalRest { + bechVoterAddr := sdk.MustBech32ifyAcc(voterAddr) + + res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?voter=%s", bechVoterAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var proposals []gov.ProposalRest + err := cdc.UnmarshalJSON([]byte(body), &proposals) + require.Nil(t, err) + return proposals +} + +func getProposalsFilterVoterDepositer(t *testing.T, port string, voterAddr sdk.Address, depositerAddr sdk.Address) []gov.ProposalRest { + bechVoterAddr := sdk.MustBech32ifyAcc(voterAddr) + bechDepositerAddr := sdk.MustBech32ifyAcc(depositerAddr) + + res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositer=%s&voter=%s", bechDepositerAddr, bechVoterAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var proposals []gov.ProposalRest + err := cdc.UnmarshalJSON([]byte(body), &proposals) + require.Nil(t, err) + return proposals +} + func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) { // get the account to get the sequence acc := getAccount(t, port, proposerAddr) @@ -802,7 +932,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA "gas": 100000 } }`, bechProposerAddr, name, password, chainID, accnum, sequence)) - res, body := Request(t, port, "POST", "/gov/submitproposal", jsonStr) + res, body := Request(t, port, "POST", "/gov/proposals", jsonStr) fmt.Println(res) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -826,7 +956,6 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk // deposit on proposal jsonStr := []byte(fmt.Sprintf(`{ "depositer": "%s", - "proposalID": %d, "amount": [{ "denom": "steak", "amount": 5 }], "base_req": { "name": "%s", @@ -836,8 +965,8 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk "sequence": %d, "gas": 100000 } - }`, bechProposerAddr, proposalID, name, password, chainID, accnum, sequence)) - res, body := Request(t, port, "POST", "/gov/deposit", jsonStr) + }`, bechProposerAddr, name, password, chainID, accnum, sequence)) + res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), jsonStr) fmt.Println(res) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -861,7 +990,6 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ad // vote on proposal jsonStr := []byte(fmt.Sprintf(`{ "voter": "%s", - "proposalID": %d, "option": "Yes", "base_req": { "name": "%s", @@ -871,8 +999,8 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ad "sequence": %d, "gas": 100000 } - }`, bechProposerAddr, proposalID, name, password, chainID, accnum, sequence)) - res, body := Request(t, port, "POST", "/gov/vote", jsonStr) + }`, bechProposerAddr, name, password, chainID, accnum, sequence)) + res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), jsonStr) fmt.Println(res) require.Equal(t, http.StatusOK, res.StatusCode, body) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 7b53e5bf10..f065ca616a 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -17,17 +17,22 @@ import ( // REST Variable names // nolint const ( - ProposalRestID = "proposalID" - RestVoter = "voterAddress" + RestProposalID = "proposalID" + RestDepositer = "depositer" + RestVoter = "voter" ) // RegisterRoutes - Central function to define routes that get registered by the main application func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - r.HandleFunc("/gov/submitproposal", postProposalHandlerFn(cdc, kb, ctx)).Methods("POST") - r.HandleFunc("/gov/deposit", depositHandlerFn(cdc, kb, ctx)).Methods("POST") - r.HandleFunc("/gov/vote", voteHandlerFn(cdc, kb, ctx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", ProposalRestID), queryProposalHandlerFn("gov", cdc, kb, ctx)).Methods("GET") - r.HandleFunc(fmt.Sprintf("/gov/votes/{%s}/{%s}", ProposalRestID, RestVoter), queryVoteHandlerFn("gov", cdc, kb, ctx)).Methods("GET") + r.HandleFunc("/gov/proposals", postProposalHandlerFn(cdc, kb, ctx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, kb, ctx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, kb, ctx)).Methods("POST") + + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn("gov", cdc, kb, ctx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn("gov", cdc, kb, ctx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn("gov", cdc, kb, ctx)).Methods("GET") + + r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn("gov", cdc, kb, ctx)).Methods("GET") } type postProposalReq struct { @@ -40,17 +45,15 @@ type postProposalReq struct { } type depositReq struct { - BaseReq baseReq `json:"base_req"` - ProposalID int64 `json:"proposalID"` // ID of the proposal - Depositer string `json:"depositer"` // Address of the depositer - Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit + BaseReq baseReq `json:"base_req"` + Depositer string `json:"depositer"` // Address of the depositer + Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit } type voteReq struct { - BaseReq baseReq `json:"base_req"` - Voter string `json:"voter"` // address of the voter - ProposalID int64 `json:"proposalID"` // proposalID of the proposal - Option string `json:"option"` // option from OptionSet chosen by the voter + BaseReq baseReq `json:"base_req"` + Voter string `json:"voter"` // address of the voter + Option string `json:"option"` // option from OptionSet chosen by the voter } func postProposalHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { @@ -92,8 +95,25 @@ func postProposalHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCon func depositHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strProposalID := vars[RestProposalID] + + if len(strProposalID) == 0 { + w.WriteHeader(http.StatusBadRequest) + err := errors.New("proposalId required but not specified") + w.Write([]byte(err.Error())) + return + } + + proposalID, err := strconv.ParseInt(strProposalID, 10, 64) + if err != nil { + err := errors.Errorf("proposalID [%d] is not positive", proposalID) + w.Write([]byte(err.Error())) + return + } + var req depositReq - err := buildReq(w, r, &req) + err = buildReq(w, r, &req) if err != nil { return } @@ -109,7 +129,7 @@ func depositHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) } // create the message - msg := gov.NewMsgDeposit(depositer, req.ProposalID, req.Amount) + msg := gov.NewMsgDeposit(depositer, proposalID, req.Amount) err = msg.ValidateBasic() if err != nil { writeErr(&w, http.StatusBadRequest, err.Error()) @@ -123,8 +143,25 @@ func depositHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) func voteHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strProposalID := vars[RestProposalID] + + if len(strProposalID) == 0 { + w.WriteHeader(http.StatusBadRequest) + err := errors.New("proposalId required but not specified") + w.Write([]byte(err.Error())) + return + } + + proposalID, err := strconv.ParseInt(strProposalID, 10, 64) + if err != nil { + err := errors.Errorf("proposalID [%d] is not positive", proposalID) + w.Write([]byte(err.Error())) + return + } + var req voteReq - err := buildReq(w, r, &req) + err = buildReq(w, r, &req) if err != nil { return } @@ -146,7 +183,7 @@ func voteHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) ht } // create the message - msg := gov.NewMsgVote(voter, req.ProposalID, voteOptionByte) + msg := gov.NewMsgVote(voter, proposalID, voteOptionByte) err = msg.ValidateBasic() if err != nil { writeErr(&w, http.StatusBadRequest, err.Error()) @@ -161,7 +198,7 @@ func voteHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) ht func queryProposalHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - strProposalID := vars[ProposalRestID] + strProposalID := vars[RestProposalID] if len(strProposalID) == 0 { w.WriteHeader(http.StatusBadRequest) @@ -180,7 +217,7 @@ func queryProposalHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx := context.NewCoreContextFromViper() res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) - if len(res) == 0 || err != nil { + if err != nil || len(res) == 0 { err := errors.Errorf("proposalID [%d] does not exist", proposalID) w.Write([]byte(err.Error())) return @@ -199,10 +236,76 @@ func queryProposalHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, } } +func queryDepositHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strProposalID := vars[RestProposalID] + bechDepositerAddr := vars[RestDepositer] + + if len(strProposalID) == 0 { + w.WriteHeader(http.StatusBadRequest) + err := errors.New("proposalId required but not specified") + w.Write([]byte(err.Error())) + return + } + + proposalID, err := strconv.ParseInt(strProposalID, 10, 64) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + err := errors.Errorf("proposalID [%d] is not positive", proposalID) + w.Write([]byte(err.Error())) + return + } + + if len(bechDepositerAddr) == 0 { + w.WriteHeader(http.StatusBadRequest) + err := errors.New("depositer address required but not specified") + w.Write([]byte(err.Error())) + return + } + + depositerAddr, err := sdk.GetAccAddressBech32(bechDepositerAddr) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer) + w.Write([]byte(err.Error())) + return + } + + ctx := context.NewCoreContextFromViper() + + res, err := ctx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) + if err != nil || len(res) == 0 { + res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + if err != nil || len(res) == 0 { + w.WriteHeader(http.StatusNotFound) + err := errors.Errorf("proposalID [%d] does not exist", proposalID) + w.Write([]byte(err.Error())) + return + } + w.WriteHeader(http.StatusNotFound) + err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID) + w.Write([]byte(err.Error())) + return + } + + var deposit gov.Deposit + cdc.MustUnmarshalBinary(res, &deposit) + depositRest := gov.DepositToRest(deposit) + output, err := wire.MarshalJSONIndent(cdc, depositRest) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + w.Write(output) + } +} + func queryVoteHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - strProposalID := vars[ProposalRestID] + strProposalID := vars[RestProposalID] bechVoterAddr := vars[RestVoter] if len(strProposalID) == 0 { @@ -214,11 +317,19 @@ func queryVoteHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx proposalID, err := strconv.ParseInt(strProposalID, 10, 64) if err != nil { + w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("proposalID [%s] is not positive", proposalID) w.Write([]byte(err.Error())) return } + if len(bechVoterAddr) == 0 { + w.WriteHeader(http.StatusBadRequest) + err := errors.New("voter address required but not specified") + w.Write([]byte(err.Error())) + return + } + voterAddr, err := sdk.GetAccAddressBech32(bechVoterAddr) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -229,16 +340,17 @@ func queryVoteHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx ctx := context.NewCoreContextFromViper() - key := []byte(gov.KeyVote(proposalID, voterAddr)) - res, err := ctx.QueryStore(key, storeName) - if len(res) == 0 || err != nil { + res, err := ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) + if err != nil || len(res) == 0 { res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) - if len(res) == 0 || err != nil { + if err != nil || len(res) == 0 { + w.WriteHeader(http.StatusNotFound) err := errors.Errorf("proposalID [%d] does not exist", proposalID) w.Write([]byte(err.Error())) return } + w.WriteHeader(http.StatusNotFound) err = errors.Errorf("voter [%s] did not vote on proposalID [%d]", bechVoterAddr, proposalID) w.Write([]byte(err.Error())) return @@ -256,3 +368,80 @@ func queryVoteHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx w.Write(output) } } + +func queryProposalsWithParameterFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + bechVoterAddr := r.URL.Query().Get(RestVoter) + bechDepositerAddr := r.URL.Query().Get(RestDepositer) + + var err error + var voterAddr sdk.Address + var depositerAddr sdk.Address + + if len(bechVoterAddr) != 0 { + voterAddr, err = sdk.GetAccAddressBech32(bechVoterAddr) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter) + w.Write([]byte(err.Error())) + return + } + } + + if len(bechDepositerAddr) != 0 { + depositerAddr, err = sdk.GetAccAddressBech32(bechDepositerAddr) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer) + w.Write([]byte(err.Error())) + return + } + } + + ctx := context.NewCoreContextFromViper() + + res, err := ctx.QueryStore(gov.KeyNextProposalID, storeName) + if err != nil { + err = errors.New("no proposals exist yet and proposalID has not been set") + w.Write([]byte(err.Error())) + return + } + var maxProposalID int64 + cdc.MustUnmarshalBinary(res, &maxProposalID) + + matchingProposals := []gov.ProposalRest{} + + for proposalID := int64(0); proposalID < maxProposalID; proposalID++ { + if voterAddr != nil { + res, err = ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) + if err != nil || len(res) == 0 { + continue + } + } + + if depositerAddr != nil { + res, err = ctx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) + if err != nil || len(res) == 0 { + continue + } + } + + res, err = ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + if err != nil || len(res) == 0 { + continue + } + var proposal gov.Proposal + cdc.MustUnmarshalBinary(res, &proposal) + + matchingProposals = append(matchingProposals, gov.ProposalToRest(proposal)) + } + + output, err := wire.MarshalJSONIndent(cdc, matchingProposals) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + w.Write(output) + } +} diff --git a/x/gov/depositsvotes.go b/x/gov/depositsvotes.go index bf36e3b0cb..5fbdc1600b 100644 --- a/x/gov/depositsvotes.go +++ b/x/gov/depositsvotes.go @@ -25,8 +25,9 @@ type Vote struct { // Deposit type Deposit struct { - Depositer sdk.Address `json:"depositer"` // Address of the depositer - Amount sdk.Coins `json:"amount"` // Deposit amount + Depositer sdk.Address `json:"depositer"` // Address of the depositer + ProposalID int64 `json:"proposal_id"` // proposalID of the proposal + Amount sdk.Coins `json:"amount"` // Deposit amount } // ProposalTypeToString for pretty prints of ProposalType @@ -72,6 +73,25 @@ func StringToVoteOption(str string) (VoteOption, sdk.Error) { } //----------------------------------------------------------- +// REST + +// Rest Deposits +type DepositRest struct { + Depositer string `json:"voter"` // address of the voter + ProposalID int64 `json:"proposal_id"` // proposalID of the proposal + Amount sdk.Coins `json:"option"` +} + +// Turn any Deposit to a DepositRest +func DepositToRest(deposit Deposit) DepositRest { + bechAddr := sdk.MustBech32ifyAcc(deposit.Depositer) + return DepositRest{ + Depositer: bechAddr, + ProposalID: deposit.ProposalID, + Amount: deposit.Amount, + } +} + // Rest Votes type VoteRest struct { Voter string `json:"voter"` // address of the voter @@ -79,7 +99,7 @@ type VoteRest struct { Option string `json:"option"` } -// Turn any Vote to a ProposalRest +// Turn any Vote to a VoteRest func VoteToRest(vote Vote) VoteRest { bechAddr, _ := sdk.Bech32ifyAcc(vote.Voter) return VoteRest{ diff --git a/x/gov/keeper.go b/x/gov/keeper.go index bc91533044..7d0eb04067 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -101,7 +101,7 @@ func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID int64) sdk if bz != nil { return ErrInvalidGenesis(keeper.codespace, "Initial ProposalID already set") } - bz = keeper.cdc.MustMarshalBinary(proposalID) // TODO: switch to MarshalBinaryBare when new go-amino gets added + bz = keeper.cdc.MustMarshalBinary(proposalID) store.Set(KeyNextProposalID, bz) return nil } @@ -112,8 +112,8 @@ func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID int64, err sd if bz == nil { return -1, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set") } - keeper.cdc.MustUnmarshalBinary(bz, &proposalID) // TODO: switch to UnmarshalBinaryBare when new go-amino gets added - bz = keeper.cdc.MustMarshalBinary(proposalID + 1) // TODO: switch to MarshalBinaryBare when new go-amino gets added + keeper.cdc.MustUnmarshalBinary(bz, &proposalID) + bz = keeper.cdc.MustMarshalBinary(proposalID + 1) store.Set(KeyNextProposalID, bz) return proposalID, nil } @@ -264,7 +264,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr // Add or update deposit object currDeposit, found := keeper.GetDeposit(ctx, proposalID, depositerAddr) if !found { - newDeposit := Deposit{depositerAddr, depositAmount} + newDeposit := Deposit{depositerAddr, proposalID, depositAmount} keeper.setDeposit(ctx, proposalID, depositerAddr, newDeposit) } else { currDeposit.Amount = currDeposit.Amount.Plus(depositAmount) From 6d9f07dfee4651242785e049ec6d031f1d73bf14 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Wed, 27 Jun 2018 17:32:06 -0700 Subject: [PATCH 30/77] tools: Add go vet as a linter (#1421) * tools: add go vet * tools: Add go vet as a linter --- .circleci/config.yml | 3 +-- CHANGELOG.md | 9 ++++++--- Makefile | 3 ++- client/tx/broadcast.go | 2 +- client/tx/sign.go | 6 +++--- examples/basecoin/app/app_test.go | 8 ++++---- examples/democoin/x/oracle/oracle_test.go | 6 +++--- x/stake/types/delegation.go | 4 ++-- 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bb1ad16714..149b5546de 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -67,8 +67,7 @@ jobs: name: Lint source command: | export PATH="$GOBIN:$PATH" - gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --vendor ./... - find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s + make test_lint test_unit: <<: *defaults parallelism: 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 70d3c303ad..cd11eff370 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ BREAKING CHANGES * [stake] remove Tick and add EndBlocker * [stake] introduce concept of unbonding for delegations and validators * `gaiacli stake unbond` replaced with `gaiacli stake begin-unbonding` - * introduced: + * introduced: * `gaiacli stake complete-unbonding` * `gaiacli stake begin-redelegation` * `gaiacli stake complete-redelegation` @@ -34,14 +34,17 @@ FEATURES * Run with `cd x/bank && go test --bench=.` * [tools] make get_tools installs tendermint's linter, and gometalinter * [tools] Switch gometalinter to the stable version -* [tools] Add checking for misspellings and for incorrectly formatted files in circle CI +* [tools] Add the following linters + * misspell + * gofmt + * go vet -composites=false * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates * [tests] Add WaitForNextNBlocksTM helper method * [types] Switches internal representation of Int/Uint/Rat to use pointers * [gaiad] unsafe_reset_all now resets addrbook.json * [democoin] add x/oracle, x/assoc -FIXES +FIXES * [gaia] Added self delegation for validators in the genesis creation * [lcd] tests now don't depend on raw json text * [stake] error strings lower case diff --git a/Makefile b/Makefile index 41883cfaf7..f2fbdd2b8f 100644 --- a/Makefile +++ b/Makefile @@ -108,7 +108,8 @@ test_cover: @bash tests/test_cover.sh test_lint: - gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --vendor ./... + gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --linter='vet:go vet -composites=false:PATH:LINE:MESSAGE' --enable='vet' --vendor ./... + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s benchmark: @go test -bench=. $(PACKAGES_NOCLITEST) diff --git a/client/tx/broadcast.go b/client/tx/broadcast.go index 7f55e97d79..21f576db41 100644 --- a/client/tx/broadcast.go +++ b/client/tx/broadcast.go @@ -9,7 +9,7 @@ import ( // Tx Broadcast Body type BroadcastTxBody struct { - TxBytes string `json="tx"` + TxBytes string `json:"tx"` } // BroadcastTx REST Handler diff --git a/client/tx/sign.go b/client/tx/sign.go index 2d885b049b..36a765eed4 100644 --- a/client/tx/sign.go +++ b/client/tx/sign.go @@ -11,9 +11,9 @@ import ( // REST request body // TODO does this need to be exposed? type SignTxBody struct { - Name string `json="name"` - Password string `json="password"` - TxBytes string `json="tx"` + Name string `json:"name"` + Password string `json:"password"` + TxBytes string `json:"tx"` } // sign transaction REST Handler diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index c3ba39b3d3..81ed40f21a 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -1,10 +1,10 @@ package app import ( - "os" - "fmt" - "testing" "encoding/json" + "fmt" + "os" + "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -83,7 +83,7 @@ func TestGenesis(t *testing.T) { // InitChain with default stake data. Initializes deliverState and checkState context bapp.InitChain(abci.RequestInitChain{AppStateBytes: []byte(fmt.Sprintf("{\"stake\": %s}", string(genState)))}) - + ctx = bapp.BaseApp.NewContext(true, abci.Header{}) res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address) assert.Equal(t, acc, res1) diff --git a/examples/democoin/x/oracle/oracle_test.go b/examples/democoin/x/oracle/oracle_test.go index 27c5aa08b2..1cd73b1c1c 100644 --- a/examples/democoin/x/oracle/oracle_test.go +++ b/examples/democoin/x/oracle/oracle_test.go @@ -106,9 +106,9 @@ func TestOracle(t *testing.T) { addr3 := []byte("addr3") addr4 := []byte("addr4") valset := &mock.ValidatorSet{[]mock.Validator{ - mock.Validator{addr1, sdk.NewRat(7)}, - mock.Validator{addr2, sdk.NewRat(7)}, - mock.Validator{addr3, sdk.NewRat(1)}, + {addr1, sdk.NewRat(7)}, + {addr2, sdk.NewRat(7)}, + {addr3, sdk.NewRat(1)}, }} key := sdk.NewKVStoreKey("testkey") diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 235e1e6081..410cfbe1d8 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -101,8 +101,8 @@ type Redelegation struct { ValidatorDstAddr sdk.Address `json:"validator_dst_addr"` // validator redelegation destination owner addr CreationHeight int64 `json:"creation_height"` // height which the redelegation took place MinTime int64 `json:"min_time"` // unix time for redelegation completion - SharesSrc sdk.Rat `json:"shares` // amount of source shares redelegating - SharesDst sdk.Rat `json:"shares` // amount of destination shares redelegating + SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating } // nolint From 473ac4a38e89fee9b992fb220e20c44db05e1e33 Mon Sep 17 00:00:00 2001 From: Rigel Date: Wed, 27 Jun 2018 21:22:57 -0400 Subject: [PATCH 31/77] Merge PR #1423: PR Template labels --- .github/PULL_REQUEST_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index caa5415105..521a4c3359 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,3 +10,4 @@ v If a checkbox is n/a - please still include it but + a little note why * [ ] Updated CHANGELOG.md * [ ] Updated Gaia/Examples * [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)) +* [ ] Added appropriate labels to PR (ex. wip, ready-for-review, docs) From 2755c66545407d06743d706bdd0cd9c24826a487 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Thu, 28 Jun 2018 09:08:29 -0700 Subject: [PATCH 32/77] Merge PR #1424: tools: add unconvert linter unconvert checks for unnecessary type conversions --- CHANGELOG.md | 1 + Makefile | 2 +- client/context/helpers.go | 4 ++-- client/lcd/version.go | 2 +- tests/util.go | 2 +- tools/Makefile | 16 ++++++++++++++++ types/coin.go | 4 ++-- x/ibc/mapper.go | 2 +- x/slashing/tick.go | 4 ++-- 9 files changed, 27 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd11eff370..488ce17edc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ FEATURES * misspell * gofmt * go vet -composites=false + * unconvert * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates * [tests] Add WaitForNextNBlocksTM helper method * [types] Switches internal representation of Int/Uint/Rat to use pointers diff --git a/Makefile b/Makefile index f2fbdd2b8f..8316955f33 100644 --- a/Makefile +++ b/Makefile @@ -108,7 +108,7 @@ test_cover: @bash tests/test_cover.sh test_lint: - gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --linter='vet:go vet -composites=false:PATH:LINE:MESSAGE' --enable='vet' --vendor ./... + gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --enable='unconvert' --linter='vet:go vet -composites=false:PATH:LINE:MESSAGE' --enable='vet' --vendor ./... find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s benchmark: diff --git a/client/context/helpers.go b/client/context/helpers.go index c782503b09..fa46c73fdf 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -127,8 +127,8 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msgs []sdk.Msg, cdc signMsg := auth.StdSignMsg{ ChainID: chainID, - AccountNumber: int64(accnum), - Sequence: int64(sequence), + AccountNumber: accnum, + Sequence: sequence, Msgs: msgs, Memo: memo, Fee: auth.NewStdFee(ctx.Gas, sdk.Coin{}), // TODO run simulate to estimate gas? diff --git a/client/lcd/version.go b/client/lcd/version.go index 0c8ef4ef6e..be097393e0 100644 --- a/client/lcd/version.go +++ b/client/lcd/version.go @@ -24,6 +24,6 @@ func NodeVersionRequestHandler(cdc *wire.Codec, ctx context.CoreContext) http.Ha w.Write([]byte(fmt.Sprintf("Could't query version. Error: %s", err.Error()))) return } - w.Write([]byte(version)) + w.Write(version) } } diff --git a/tests/util.go b/tests/util.go index cc95f1e241..1b68a9fd98 100644 --- a/tests/util.go +++ b/tests/util.go @@ -104,7 +104,7 @@ func waitForHeight(height int64, url string) { res.Body.Close() var resultBlock ctypes.ResultBlock - err = cdc.UnmarshalJSON([]byte(body), &resultBlock) + err = cdc.UnmarshalJSON(body, &resultBlock) if err != nil { fmt.Println("RES", res) fmt.Println("BODY", string(body)) diff --git a/tools/Makefile b/tools/Makefile index c623ba46ff..bfa6a790db 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -7,9 +7,12 @@ all: get_tools DEP = github.com/golang/dep/cmd/dep GOLINT = github.com/tendermint/lint/golint GOMETALINTER = gopkg.in/alecthomas/gometalinter.v2 +UNCONVERT = github.com/mdempsky/unconvert + DEP_CHECK := $(shell command -v dep 2> /dev/null) GOLINT_CHECK := $(shell command -v golint 2> /dev/null) GOMETALINTER_CHECK := $(shell command -v gometalinter.v2 2> /dev/null) +UNCONVERT_CHECK := $(shell command -v unconvert 2> /dev/null) check_tools: ifndef DEP_CHECK @@ -27,6 +30,11 @@ ifndef GOMETALINTER_CHECK else @echo "Found gometalinter in path." endif +ifndef UNCONVERT_CHECK + @echo "No unconvert in path. Install with 'make get_tools'." +else + @echo "Found unconvert in path." +endif get_tools: ifdef DEP_CHECK @@ -47,6 +55,12 @@ else @echo "Installing gometalinter.v2" go get -v $(GOMETALINTER) endif +ifdef UNCONVERT_CHECK + @echo "Unconvert is already installed. Run 'make update_tools' to update." +else + @echo "Installing unconvert" + go get -v $(UNCONVERT) +endif update_tools: @echo "Updating dep" @@ -55,6 +69,8 @@ update_tools: go get -u -v $(GOLINT) @echo "Updating gometalinter.v2" go get -u -v $(GOMETALINTER) + @echo "Updating unconvert" + go get -u -v $(UNCONVERT) # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. diff --git a/types/coin.go b/types/coin.go index 30f84abdf6..eba6459321 100644 --- a/types/coin.go +++ b/types/coin.go @@ -244,11 +244,11 @@ func (coins Coins) AmountOf(denom string) Int { midIdx := len(coins) / 2 // 2:1, 3:1, 4:2 coin := coins[midIdx] if denom < coin.Denom { - return Coins(coins[:midIdx]).AmountOf(denom) + return coins[:midIdx].AmountOf(denom) } else if denom == coin.Denom { return coin.Amount } else { - return Coins(coins[midIdx+1:]).AmountOf(denom) + return coins[midIdx+1:].AmountOf(denom) } } } diff --git a/x/ibc/mapper.go b/x/ibc/mapper.go index 06631179b5..2516996170 100644 --- a/x/ibc/mapper.go +++ b/x/ibc/mapper.go @@ -39,7 +39,7 @@ func (ibcm Mapper) PostIBCPacket(ctx sdk.Context, packet IBCPacket) sdk.Error { } store.Set(EgressKey(packet.DestChain, index), bz) - bz, err = ibcm.cdc.MarshalBinary(int64(index + 1)) + bz, err = ibcm.cdc.MarshalBinary(index + 1) if err != nil { panic(err) } diff --git a/x/slashing/tick.go b/x/slashing/tick.go index 6eb6eeb32b..eed083b9a9 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -22,11 +22,11 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags if err != nil { panic(err) } - switch string(evidence.Type) { + switch evidence.Type { case tmtypes.ABCIEvidenceTypeDuplicateVote: sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) default: - ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("ignored unknown evidence type: %s", string(evidence.Type))) + ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("ignored unknown evidence type: %s", evidence.Type)) } } From 3e14868bd627cfbcfaebf694ed052acd3fbd4144 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Thu, 28 Jun 2018 10:12:02 -0700 Subject: [PATCH 33/77] Merge PR #1429: tools: Add ineffassign linter * tools: Add ineffassign linter This errors on assignments that don't actually do anything. i.e. x, err := myFunc(1) y, err = myFunc(2) This will call out that the first function's call error was never used. * Fix makefile, add misspell to makefile --- .circleci/config.yml | 1 - CHANGELOG.md | 1 + Makefile | 2 +- client/lcd/lcd_test.go | 46 +++++++++---------- examples/democoin/app/app_test.go | 1 + examples/democoin/cmd/democoind/main.go | 3 ++ .../democoin/x/simplestake/keeper_test.go | 2 + store/iavlstore_test.go | 4 +- tools/Makefile | 30 ++++++++++++ x/stake/client/cli/tx.go | 12 +++++ x/stake/keeper/delegation.go | 3 ++ x/stake/keeper/inflation_test.go | 2 +- x/stake/keeper/validator_test.go | 2 + 13 files changed, 81 insertions(+), 28 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 149b5546de..d58cbad5fc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -62,7 +62,6 @@ jobs: command: | export PATH="$GOBIN:$PATH" make get_tools - go get -u github.com/client9/misspell/cmd/misspell - run: name: Lint source command: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 488ce17edc..0aca8de106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ FEATURES * gofmt * go vet -composites=false * unconvert + * ineffassign * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates * [tests] Add WaitForNextNBlocksTM helper method * [types] Switches internal representation of Int/Uint/Rat to use pointers diff --git a/Makefile b/Makefile index 8316955f33..9cf1b14bc8 100644 --- a/Makefile +++ b/Makefile @@ -108,7 +108,7 @@ test_cover: @bash tests/test_cover.sh test_lint: - gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --enable='unconvert' --linter='vet:go vet -composites=false:PATH:LINE:MESSAGE' --enable='vet' --vendor ./... + gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --enable='unconvert' --enable='ineffassign' --linter='vet:go vet -composites=false:PATH:LINE:MESSAGE' --enable='vet' --deadline=500s --vendor ./... find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s benchmark: diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 07bb4b252e..9776e9c453 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -51,7 +51,7 @@ func TestKeys(t *testing.T) { var jsonStr = []byte(fmt.Sprintf(`{"name":"test_fail", "password":"%s"}`, password)) res, body = Request(t, port, "POST", "/keys", jsonStr) - assert.Equal(t, http.StatusBadRequest, res.StatusCode, "Account creation should require a seed") + assert.Equal(t, http.StatusBadRequest, res.StatusCode, "Account creation should require a seed "+body) jsonStr = []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed": "%s"}`, newName, newPassword, newSeed)) res, body = Request(t, port, "POST", "/keys", jsonStr) @@ -212,7 +212,7 @@ func TestValidators(t *testing.T) { // -- res, body = Request(t, port, "GET", "/validatorsets/1000000000", nil) - require.Equal(t, http.StatusNotFound, res.StatusCode) + require.Equal(t, http.StatusNotFound, res.StatusCode, body) } func TestCoinSend(t *testing.T) { @@ -520,43 +520,43 @@ func TestVote(t *testing.T) { } func TestProposalsQuery(t *testing.T) { - name, password := "test", "1234567890" - name2, password := "test2", "1234567890" - addr, seed := CreateAddr(t, "test", password, GetKB(t)) - addr2, seed2 := CreateAddr(t, "test2", password, GetKB(t)) + name, password1 := "test", "1234567890" + name2, password2 := "test2", "1234567890" + addr, seed := CreateAddr(t, "test", password1, GetKB(t)) + addr2, seed2 := CreateAddr(t, "test2", password2, GetKB(t)) cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{addr, addr2}) defer cleanup() // Addr1 proposes (and deposits) proposals #1 and #2 - resultTx := doSubmitProposal(t, port, seed, name, password, addr) + resultTx := doSubmitProposal(t, port, seed, name, password1, addr) var proposalID1 int64 cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1) tests.WaitForHeight(resultTx.Height+1, port) - resultTx = doSubmitProposal(t, port, seed, name, password, addr) + resultTx = doSubmitProposal(t, port, seed, name, password1, addr) var proposalID2 int64 cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2) tests.WaitForHeight(resultTx.Height+1, port) // Addr2 proposes (and deposits) proposals #3 - resultTx = doSubmitProposal(t, port, seed2, name2, password, addr2) + resultTx = doSubmitProposal(t, port, seed2, name2, password2, addr2) var proposalID3 int64 cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3) tests.WaitForHeight(resultTx.Height+1, port) // Addr2 deposits on proposals #2 & #3 - resultTx = doDeposit(t, port, seed2, name2, password, addr2, proposalID2) + resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID2) tests.WaitForHeight(resultTx.Height+1, port) - resultTx = doDeposit(t, port, seed2, name2, password, addr2, proposalID3) + resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID3) tests.WaitForHeight(resultTx.Height+1, port) // Addr1 votes on proposals #2 & #3 - resultTx = doVote(t, port, seed, name, password, addr, proposalID2) + resultTx = doVote(t, port, seed, name, password1, addr, proposalID2) tests.WaitForHeight(resultTx.Height+1, port) - resultTx = doVote(t, port, seed, name, password, addr, proposalID3) + resultTx = doVote(t, port, seed, name, password1, addr, proposalID3) tests.WaitForHeight(resultTx.Height+1, port) // Addr2 votes on proposal #3 - resultTx = doVote(t, port, seed2, name2, password, addr2, proposalID3) + resultTx = doVote(t, port, seed2, name2, password2, addr2, proposalID3) tests.WaitForHeight(resultTx.Height+1, port) // Test query all proposals @@ -717,9 +717,9 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, "bond": { "denom": "%s", "amount": 60 } } ], - "begin_unbondings": [], - "complete_unbondings": [], - "begin_redelegates": [], + "begin_unbondings": [], + "complete_unbondings": [], + "begin_redelegates": [], "complete_redelegates": [] }`, name, password, accnum, sequence, chainID, delegatorAddrBech, validatorAddrBech, "steak")) res, body := Request(t, port, "POST", "/stake/delegations", jsonStr) @@ -760,9 +760,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, "validator_addr": "%s", "shares": "30" } - ], - "complete_unbondings": [], - "begin_redelegates": [], + ], + "complete_unbondings": [], + "begin_redelegates": [], "complete_redelegates": [] }`, name, password, accnum, sequence, chainID, delegatorAddrBech, validatorAddrBech)) res, body := Request(t, port, "POST", "/stake/delegations", jsonStr) @@ -798,8 +798,8 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, "gas": 10000, "chain_id": "%s", "delegations": [], - "begin_unbondings": [], - "complete_unbondings": [], + "begin_unbondings": [], + "complete_unbondings": [], "begin_redelegates": [ { "delegator_addr": "%s", @@ -807,7 +807,7 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, "validator_dst_addr": "%s", "shares": "30" } - ], + ], "complete_redelegates": [] }`, name, password, accnum, sequence, chainID, delegatorAddrBech, validatorSrcAddrBech, validatorDstAddrBech)) res, body := Request(t, port, "POST", "/stake/delegations", jsonStr) diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index a477ef79bb..a75eee0f38 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -43,6 +43,7 @@ func TestGenesis(t *testing.T) { }, } stateBytes, err := json.MarshalIndent(genesisState, "", "\t") + require.Nil(t, err) vals := []abci.Validator{} bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 76d29075e9..9e84c02571 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -34,6 +34,9 @@ func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso "trend": "ice-cold" }`) appState, err = server.AppendJSON(cdc, appState, key, value) + if err != nil { + return + } key = "pow" value = json.RawMessage(`{ "difficulty": 1, diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index 2b73800324..9315a7ccf6 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" @@ -79,6 +80,7 @@ func TestBonding(t *testing.T) { assert.Nil(t, err) power, err := stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewCoin("steak", 10)) + require.Nil(t, err) assert.Equal(t, int64(20), power) pk, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr) diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index e2f2f9c174..25e8724c9a 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -155,7 +155,7 @@ func TestIAVLSubspaceIterator(t *testing.T) { iavlStore.Set([]byte{byte(255), byte(255), byte(1)}, []byte("test4")) iavlStore.Set([]byte{byte(255), byte(255), byte(255)}, []byte("test4")) - i := 0 + var i int iter := sdk.KVStorePrefixIterator(iavlStore, []byte("test")) expected := []string{"test1", "test2", "test3"} @@ -214,7 +214,7 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) { iavlStore.Set([]byte{byte(255), byte(255), byte(1)}, []byte("test4")) iavlStore.Set([]byte{byte(255), byte(255), byte(255)}, []byte("test4")) - i := 0 + var i int iter := sdk.KVStoreReversePrefixIterator(iavlStore, []byte("test")) expected := []string{"test3", "test2", "test1"} diff --git a/tools/Makefile b/tools/Makefile index bfa6a790db..7fb1e886c5 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -8,11 +8,15 @@ DEP = github.com/golang/dep/cmd/dep GOLINT = github.com/tendermint/lint/golint GOMETALINTER = gopkg.in/alecthomas/gometalinter.v2 UNCONVERT = github.com/mdempsky/unconvert +INEFFASSIGN = github.com/gordonklaus/ineffassign +MISSPELL = github.com/client9/misspell/cmd/misspell DEP_CHECK := $(shell command -v dep 2> /dev/null) GOLINT_CHECK := $(shell command -v golint 2> /dev/null) GOMETALINTER_CHECK := $(shell command -v gometalinter.v2 2> /dev/null) UNCONVERT_CHECK := $(shell command -v unconvert 2> /dev/null) +INEFFASSIGN_CHECK := $(shell command -v ineffassign 2> /dev/null) +MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null) check_tools: ifndef DEP_CHECK @@ -35,6 +39,16 @@ ifndef UNCONVERT_CHECK else @echo "Found unconvert in path." endif +ifndef INEFFASSIGN_CHECK + @echo "No ineffassign in path. Install with 'make get_tools'." +else + @echo "Found ineffassign in path." +endif +ifndef MISSPELL_CHECK + @echo "No misspell in path. Install with 'make get_tools'." +else + @echo "Found misspell in path." +endif get_tools: ifdef DEP_CHECK @@ -61,6 +75,18 @@ else @echo "Installing unconvert" go get -v $(UNCONVERT) endif +ifdef INEFFASSIGN_CHECK + @echo "Ineffassign is already installed. Run 'make update_tools' to update." +else + @echo "Installing ineffassign" + go get -v $(INEFFASSIGN) +endif +ifdef MISSPELL_CHECK + @echo "misspell is already installed. Run 'make update_tools' to update." +else + @echo "Installing misspell" + go get -v $(MISSPELL) +endif update_tools: @echo "Updating dep" @@ -71,6 +97,10 @@ update_tools: go get -u -v $(GOMETALINTER) @echo "Updating unconvert" go get -u -v $(UNCONVERT) + @echo "Updating ineffassign" + go get -u -v $(INEFFASSIGN) + @echo "Updating misspell" + go get -u -v $(MISSPELL) # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 7543d2707b..b7941e2bb8 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -117,6 +117,9 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { } delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator)) + if err != nil { + return err + } validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err @@ -259,7 +262,13 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator)) + if err != nil { + return err + } validatorSrcAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidatorSrc)) + if err != nil { + return err + } validatorDstAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidatorDst)) if err != nil { return err @@ -351,6 +360,9 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator)) + if err != nil { + return err + } validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index e9155d7f98..844ffb9b48 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -321,6 +321,9 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd return types.ErrBadRedelegationDst(k.Codespace()) } sharesCreated, err := k.Delegate(ctx, delegatorAddr, returnCoin, dstValidator) + if err != nil { + return err + } // create the unbonding delegation minTime := ctx.BlockHeader().Time + params.UnbondingTime diff --git a/x/stake/keeper/inflation_test.go b/x/stake/keeper/inflation_test.go index cb2f6007a4..d748ce0cb2 100644 --- a/x/stake/keeper/inflation_test.go +++ b/x/stake/keeper/inflation_test.go @@ -212,7 +212,7 @@ func TestLargeBond(t *testing.T) { keeper.SetParams(ctx, params) // validator[9] will be bonded, bringing us from 25% to ~50% (bonding 400,000,000 tokens) - pool, validator, _, _ = types.OpBondOrUnbond(r, pool, validator) + pool, _, _, _ = types.OpBondOrUnbond(r, pool, validator) keeper.SetPool(ctx, pool) // process provisions after the bonding, to compare the difference in expProvisions and expInflation diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 245954ad13..3bbcee94c0 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -34,6 +34,7 @@ func TestSetValidator(t *testing.T) { // Check each store for being saved resVal, found := keeper.GetValidator(ctx, addrVals[0]) assert.True(ValEq(t, validator, resVal)) + assert.True(t, found) resVals := keeper.GetValidatorsBonded(ctx) require.Equal(t, 1, len(resVals)) @@ -87,6 +88,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool = keeper.GetPool(ctx) validator, found = keeper.GetValidator(ctx, addrVals[0]) + assert.True(t, found) power = GetValidatorsByPowerIndexKey(validator, pool) assert.True(t, keeper.validatorByPowerIndexExists(ctx, power)) } From 98be0e7f76fe89aa2d2c786ff5f2481d0022d9a4 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 27 Jun 2018 14:42:30 -0700 Subject: [PATCH 34/77] Improved apps with better handling/routing and simpler MsgIssue --- docs/core/examples/app1.go | 65 ++++++------ docs/core/examples/app2.go | 196 ++++++++++++++++--------------------- docs/core/examples/app3.go | 115 ++++++++++++---------- docs/core/examples/app4.go | 73 +++++++------- 4 files changed, 214 insertions(+), 235 deletions(-) diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index ec5b779e7c..56fcea0ec9 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -2,7 +2,6 @@ package app import ( "encoding/json" - "reflect" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -35,7 +34,7 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewApp1Handler(keyAccount)) + AddRoute("send", handleMsgSend(keyAccount)) // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount) @@ -65,7 +64,7 @@ func NewMsgSend(from, to sdk.Address, amt sdk.Coins) MsgSend { } // Implements Msg. -func (msg MsgSend) Type() string { return "bank" } +func (msg MsgSend) Type() string { return "send" } // Implements Msg. Ensure the addresses are good and the // amount is positive. @@ -105,41 +104,40 @@ func (msg MsgSend) Tags() sdk.Tags { //------------------------------------------------------------------ // Handler for the message -func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { +// Handle MsgSend. +// NOTE: msg.From, msg.To, and msg.Amount were already validated +func handleMsgSend(key *sdk.KVStoreKey) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgSend: - return handleMsgSend(ctx, keyAcc, msg) - default: - errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() + sendMsg, ok := msg.(MsgSend) + if !ok { + // Create custom error message and return result + // Note: Using unreserved error codespace + return sdk.NewError(2, 1, "Send Message is malformed").Result() + } + + + // Load the store. + store := ctx.KVStore(key) + + // Debit from the sender. + if res := handleFrom(store, sendMsg.From, sendMsg.Amount); !res.IsOK() { + return res + } + + // Credit the receiver. + if res := handleTo(store, sendMsg.To, sendMsg.Amount); !res.IsOK() { + return res + } + + // Return a success (Code 0). + // Add list of key-value pair descriptors ("tags"). + return sdk.Result{ + Tags: sendMsg.Tags(), } } } -// Handle MsgSend. -// NOTE: msg.From, msg.To, and msg.Amount were already validated -func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result { - // Load the store. - store := ctx.KVStore(key) - - // Debit from the sender. - if res := handleFrom(store, msg.From, msg.Amount); !res.IsOK() { - return res - } - - // Credit the receiver. - if res := handleTo(store, msg.To, msg.Amount); !res.IsOK() { - return res - } - - // Return a success (Code 0). - // Add list of key-value pair descriptors ("tags"). - return sdk.Result{ - Tags: msg.Tags(), - } -} - +// Convenience Handlers func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { // Get sender account from the store. accBytes := store.Get(from) @@ -210,6 +208,7 @@ func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { return sdk.Result{} } +// Simple account struct type appAccount struct { Coins sdk.Coins `json:"coins"` } diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index 5959fcd393..ff5ee981f9 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -49,7 +49,8 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewApp2Handler(keyAccount, keyMain)) + AddRoute("send", handleMsgSend(keyAccount)). + AddRoute("issue", handleMsgIssue(keyAccount, keyMain)) // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount, keyMain) @@ -71,36 +72,32 @@ type CoinMetadata struct { //------------------------------------------------------------------ // Msgs -// Create Output struct to allow single message to issue arbitrary coins to multiple users -type Output struct { - Address sdk.Address - Coins sdk.Coins -} - -// Single permissioned issuer can issue multiple outputs +// Single permissioned issuer can issue Coin to Receiver +// if he is the issuer in Coin Metadata // Implements sdk.Msg Interface type MsgIssue struct { Issuer sdk.Address - Outputs []Output + Receiver sdk.Address + Coin sdk.Coin } // nolint -func (msg MsgIssue) Type() string { return "bank" } +func (msg MsgIssue) Type() string { return "issue" } func (msg MsgIssue) ValidateBasic() sdk.Error { if len(msg.Issuer) == 0 { return sdk.ErrInvalidAddress("Issuer address cannot be empty") } - for _, o := range msg.Outputs { - if len(o.Address) == 0 { - return sdk.ErrInvalidAddress("Output address cannot be empty") - } - // Cannot issue zero or negative coins - if !o.Coins.IsPositive() { - return sdk.ErrInvalidCoins("Cannot issue 0 or negative coin amounts") - } + if len(msg.Receiver) == 0 { + return sdk.ErrInvalidAddress("Receiver address cannot be empty") } + + // Cannot issue zero or negative coins + if !msg.Coin.IsPositive() { + return sdk.ErrInvalidCoins("Cannot issue 0 or negative coin amounts") + } + return nil } @@ -117,112 +114,89 @@ func (msg MsgIssue) GetSigners() []sdk.Address { return []sdk.Address{msg.Issuer} } +// Returns the sdk.Tags for the message +func (msg MsgIssue) Tags() sdk.Tags { + return sdk.NewTags("issuer", []byte(msg.Issuer.String())). + AppendTag("receiver", []byte(msg.Receiver.String())) +} + //------------------------------------------------------------------ // Handler for the message -func NewApp2Handler(keyAcc *sdk.KVStoreKey, keyMain *sdk.KVStoreKey) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgSend: - return handleMsgSend(ctx, keyAcc, msg) - case MsgIssue: - return handleMsgIssue(ctx, keyMain, keyAcc, msg) - default: - errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - // Handle Msg Issue -func handleMsgIssue(ctx sdk.Context, keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey, msg MsgIssue) sdk.Result { - store := ctx.KVStore(keyMain) - accStore := ctx.KVStore(keyAcc) - - for _, o := range msg.Outputs { - for _, coin := range o.Coins { - bz := store.Get([]byte(coin.Denom)) - var metadata CoinMetadata - - if bz == nil { - // Coin not set yet, initialize with issuer and default values - // Coin amount can't be above default value - if coin.Amount.GT(sdk.NewInt(1000000)) { - return sdk.ErrInvalidCoins("Cannot issue that many new coins").Result() - } - metadata = CoinMetadata{ - TotalSupply: sdk.NewInt(1000000), - CurrentSupply: sdk.NewInt(0), - Issuer: msg.Issuer, - Decimal: 10, - } - } else { - // Decode coin metadata - err := json.Unmarshal(bz, &metadata) - if err != nil { - return sdk.ErrInternal("Decoding coin metadata failed").Result() - } - } - - // Return error result if msg Issuer is not equal to coin issuer - if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) { - return sdk.ErrUnauthorized(fmt.Sprintf("Msg issuer cannot issue these coins: %s", coin.Denom)).Result() - } - - // Issuer cannot issue more than remaining supply - issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply) - if coin.Amount.GT(issuerSupply) { - return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result() - } - - // Update coin metadata - metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) - - val, err := json.Marshal(metadata) - if err != nil { - return sdk.ErrInternal("Encoding coin metadata failed").Result() - } - - // Update coin metadata in store - store.Set([]byte(coin.Denom), val) +func handleMsgIssue(keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + issueMsg, ok := msg.(MsgIssue) + if !ok { + return sdk.NewError(2, 1, "IssueMsg is malformed").Result() } - // Add coins to receiver account - bz := accStore.Get(o.Address) - var acc appAccount - if bz == nil { - // Receiver account does not already exist, create a new one. - acc = appAccount{} - } else { - // Receiver account already exists. Retrieve and decode it. - err := json.Unmarshal(bz, &acc) - if err != nil { - return sdk.ErrInternal("Account decoding error").Result() - } + store := ctx.KVStore(keyMain) + accStore := ctx.KVStore(keyAcc) + + if res := handleMetaData(store, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { + return res } - // Add amount to receiver's old coins - receiverCoins := acc.Coins.Plus(o.Coins) - - // Update receiver account - acc.Coins = receiverCoins - - // Encode receiver account - val, err := json.Marshal(acc) - if err != nil { - return sdk.ErrInternal("Account encoding error").Result() + // Issue coins to receiver using previously defined handleTo function + if res := handleTo(accStore, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}); !res.IsOK() { + return res } - // set account with new issued coins in store - store.Set(o.Address, val) + return sdk.Result{ + Tags: issueMsg.Tags(), + } } - - return sdk.Result{ - // TODO: Tags - } - } +func handleMetaData(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result { + bz := store.Get([]byte(coin.Denom)) + var metadata CoinMetadata + + if bz == nil { + // Coin not set yet, initialize with issuer and default values + // Coin amount can't be above default value + if coin.Amount.GT(sdk.NewInt(1000000)) { + return sdk.ErrInvalidCoins("Cannot issue that many new coins").Result() + } + metadata = CoinMetadata{ + TotalSupply: sdk.NewInt(1000000), + CurrentSupply: sdk.NewInt(0), + Issuer: issuer, + Decimal: 10, + } + } else { + // Decode coin metadata + err := json.Unmarshal(bz, &metadata) + if err != nil { + return sdk.ErrInternal("Decoding coin metadata failed").Result() + } + } + + if !reflect.DeepEqual(metadata.Issuer, issuer) { + return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() + } + + // Update coin current circulating supply + metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) + + // Current supply cannot exceed total supply + if metadata.TotalSupply.LT(metadata.CurrentSupply) { + return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result() + } + + val, err := json.Marshal(metadata) + if err != nil { + return sdk.ErrInternal(fmt.Sprintf("Error encoding metadata: %s", err.Error())).Result() + } + + // Update store with new metadata + store.Set([]byte(coin.Denom), val) + + return sdk.Result{} +} + + //------------------------------------------------------------------ // Tx diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index 25036ef1b2..28d51c77a1 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -2,8 +2,8 @@ package app import ( "encoding/json" - "fmt" "reflect" + "fmt" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -44,7 +44,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewApp3Handler(accountKeeper, metadataMapper)) + AddRoute("send", betterHandleMsgSend(accountKeeper)). + AddRoute("issue", betterHandleMsgIssue(metadataMapper, accountKeeper)) // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount, keyMain, keyFees) @@ -55,71 +56,77 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { return app } -func NewApp3Handler(accountKeeper bank.Keeper, metadataMapper MetaDataMapper) sdk.Handler { +func betterHandleMsgSend(accountKeeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgSend: - return betterHandleMsgSend(ctx, accountKeeper, msg) - case MsgIssue: - return betterHandleMsgIssue(ctx, metadataMapper, accountKeeper, msg) - default: - errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() + sendMsg, ok := msg.(MsgSend) + if !ok { + return sdk.NewError(2, 1, "Send Message Malformed").Result() + } + + // Subtract coins from sender account + _, _, err := accountKeeper.SubtractCoins(ctx, sendMsg.From, sendMsg.Amount) + if err != nil { + // if error, return its result + return err.Result() + } + + // Add coins to receiver account + _, _, err = accountKeeper.AddCoins(ctx, sendMsg.To, sendMsg.Amount) + if err != nil { + // if error, return its result + return err.Result() + } + + return sdk.Result{ + Tags: sendMsg.Tags(), } } } -func betterHandleMsgSend(ctx sdk.Context, accountKeeper bank.Keeper, msg MsgSend) sdk.Result { - // Subtract coins from sender account - _, _, err := accountKeeper.SubtractCoins(ctx, msg.From, msg.Amount) - if err != nil { - // if error, return its result - return err.Result() - } - - // Add coins to receiver account - _, _, err = accountKeeper.AddCoins(ctx, msg.To, msg.Amount) - if err != nil { - // if error, return its result - return err.Result() - } - - return sdk.Result{} -} - -func betterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, accountKeeper bank.Keeper, msg MsgIssue) sdk.Result { - for _, o := range msg.Outputs { - for _, coin := range o.Coins { - metadata := metadataMapper.GetMetaData(ctx, coin.Denom) - if len(metadata.Issuer) == 0 { - // coin doesn't have issuer yet, set issuer to msg issuer - metadata.Issuer = msg.Issuer - } - - // Check that msg Issuer is authorized to issue these coins - if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) { - return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue these coins: %s", coin.Denom)).Result() - } - - // Issuer cannot issue more than remaining supply - issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply) - if coin.Amount.GT(issuerSupply) { - return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result() - } - - // update metadata current circulating supply - metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) - - metadataMapper.SetMetaData(ctx, coin.Denom, metadata) +func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + issueMsg, ok := msg.(MsgIssue) + if !ok { + return sdk.NewError(2, 1, "Issue Message Malformed").Result() } + if res := betterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { + return res + } + // Add newly issued coins to output address - _, _, err := accountKeeper.AddCoins(ctx, o.Address, o.Coins) + _, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}) if err != nil { return err.Result() } + + return sdk.Result{ + Tags: issueMsg.Tags(), + } + } +} + +func betterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result { + metadata := metadataMapper.GetMetaData(ctx, coin.Denom) + + // Metadata was created fresh, should set issuer to msg issuer + if len(metadata.Issuer) == 0 { + metadata.Issuer = issuer } + if !reflect.DeepEqual(metadata.Issuer, issuer) { + return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() + } + + // Update current circulating supply + metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) + + // Current supply cannot exceed total supply + if metadata.TotalSupply.LT(metadata.CurrentSupply) { + return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result() + } + + metadataMapper.SetMetaData(ctx, coin.Denom, metadata) return sdk.Result{} } diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index c7048409e3..c8905f9a9d 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -47,7 +47,8 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("bank", NewApp4Handler(accountKeeper, metadataMapper)) + AddRoute("send", betterHandleMsgSend(accountKeeper)). + AddRoute("issue", evenBetterHandleMsgIssue(metadataMapper, accountKeeper)) // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount, keyMain, keyFees) @@ -130,50 +131,48 @@ func NewInitChainer(cdc *wire.Codec, accountMapper auth.AccountMapper, metadataM //--------------------------------------------------------------------------------------------- // Now that initializing coin metadata is done in InitChainer we can simplifiy handleMsgIssue -func NewApp4Handler(accountKeeper bank.Keeper, metadataMapper MetaDataMapper) sdk.Handler { +func evenBetterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgSend: - return betterHandleMsgSend(ctx, accountKeeper, msg) - case MsgIssue: - // use new MsgIssue handler - return evenBetterHandleMsgIssue(ctx, metadataMapper, accountKeeper, msg) - default: - errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() + issueMsg, ok := msg.(MsgIssue) + if !ok { + return sdk.NewError(2, 1, "Issue Message Malformed").Result() + } + + if res := evenBetterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { + return res + } + + _, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}) + if err != nil { + return err.Result() + } + + return sdk.Result{ + Tags: issueMsg.Tags(), } } } -func evenBetterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, accountKeeper bank.Keeper, msg MsgIssue) sdk.Result { - for _, o := range msg.Outputs { - for _, coin := range o.Coins { - // Metadata is no longer created on the fly since it is initalized at genesis with InitChain - metadata := metadataMapper.GetMetaData(ctx, coin.Denom) - // Check that msg Issuer is authorized to issue these coins - if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) { - return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue these coins: %s", coin.Denom)).Result() - } +func evenBetterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result { + metadata := metadataMapper.GetMetaData(ctx, coin.Denom) - // Issuer cannot issue more than remaining supply - issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply) - if coin.Amount.GT(issuerSupply) { - return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result() - } - - // update metadata current circulating supply - metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) - - metadataMapper.SetMetaData(ctx, coin.Denom, metadata) - } - - // Add newly issued coins to output address - _, _, err := accountKeeper.AddCoins(ctx, o.Address, o.Coins) - if err != nil { - return err.Result() - } + if reflect.DeepEqual(metadata, CoinMetadata{}) { + return sdk.ErrInvalidCoins(fmt.Sprintf("Cannot find metadata for coin: %s", coin.Denom)).Result() } + if !reflect.DeepEqual(metadata.Issuer, issuer) { + return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() + } + + // Update current circulating supply + metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) + + // Current supply cannot exceed total supply + if metadata.TotalSupply.LT(metadata.CurrentSupply) { + return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result() + } + + metadataMapper.SetMetaData(ctx, coin.Denom, metadata) return sdk.Result{} } From e3f38b6f6c297f16dbfcbd8b04f9adcce9e5ca41 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 27 Jun 2018 14:50:59 -0700 Subject: [PATCH 35/77] Added some documentation --- docs/core/examples/app2.go | 4 ++++ docs/core/examples/app3.go | 3 +++ docs/core/examples/app4.go | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index ff5ee981f9..2254210d93 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -131,9 +131,11 @@ func handleMsgIssue(keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler return sdk.NewError(2, 1, "IssueMsg is malformed").Result() } + // Retrieve stores store := ctx.KVStore(keyMain) accStore := ctx.KVStore(keyAcc) + // Handle updating metadata if res := handleMetaData(store, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { return res } @@ -144,6 +146,7 @@ func handleMsgIssue(keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler } return sdk.Result{ + // Return result with Issue msg tags Tags: issueMsg.Tags(), } } @@ -173,6 +176,7 @@ func handleMetaData(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Re } } + // Msg Issuer is not authorized to issue these coins if !reflect.DeepEqual(metadata.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index 28d51c77a1..b48ab5beaf 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -90,6 +90,7 @@ func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keep return sdk.NewError(2, 1, "Issue Message Malformed").Result() } + // Handle updating metadata if res := betterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { return res } @@ -101,6 +102,7 @@ func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keep } return sdk.Result{ + // Return result with Issue msg tags Tags: issueMsg.Tags(), } } @@ -114,6 +116,7 @@ func betterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer metadata.Issuer = issuer } + // Msg Issuer is not authorized to issue these coins if !reflect.DeepEqual(metadata.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index c8905f9a9d..078a43d8bd 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -138,16 +138,19 @@ func evenBetterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank. return sdk.NewError(2, 1, "Issue Message Malformed").Result() } + // Handle updating metadata if res := evenBetterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { return res } + // Add newly issued coins to output address _, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}) if err != nil { return err.Result() } return sdk.Result{ + // Return result with Issue msg tags Tags: issueMsg.Tags(), } } @@ -156,10 +159,12 @@ func evenBetterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank. func evenBetterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result { metadata := metadataMapper.GetMetaData(ctx, coin.Denom) + // Coin metadata does not exist in store if reflect.DeepEqual(metadata, CoinMetadata{}) { return sdk.ErrInvalidCoins(fmt.Sprintf("Cannot find metadata for coin: %s", coin.Denom)).Result() } + // Msg Issuer not authorized to issue these coins if !reflect.DeepEqual(metadata.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } From 4e2eb240f366f780c0dc37efbcc6c0c6c3ddac59 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 27 Jun 2018 15:05:04 -0700 Subject: [PATCH 36/77] Appease linter --- docs/core/examples/app2.go | 4 +++- docs/core/examples/app3.go | 8 +++++++- docs/core/examples/app4.go | 15 +++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index 2254210d93..f0260ac432 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -81,9 +81,10 @@ type MsgIssue struct { Coin sdk.Coin } -// nolint +// Implements Msg. func (msg MsgIssue) Type() string { return "issue" } +// Implements Msg. Ensures addresses are valid and Coin is positive func (msg MsgIssue) ValidateBasic() sdk.Error { if len(msg.Issuer) == 0 { return sdk.ErrInvalidAddress("Issuer address cannot be empty") @@ -101,6 +102,7 @@ func (msg MsgIssue) ValidateBasic() sdk.Error { return nil } +// Implements Msg. Get canonical sign bytes for MsgIssue func (msg MsgIssue) GetSignBytes() []byte { bz, err := json.Marshal(msg) if err != nil { diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index b48ab5beaf..e20bbcb70c 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -135,21 +135,26 @@ func betterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer //------------------------------------------------------------------ // Mapper for Coin Metadata -// Example of a very simple user-defined mapper +// Example of a very simple user-defined mapper interface type MetaDataMapper interface { GetMetaData(sdk.Context, string) CoinMetadata SetMetaData(sdk.Context, string, CoinMetadata) } +// Implements MetaDataMapper type App3MetaDataMapper struct { mainKey *sdk.KVStoreKey } +// Construct new App3MetaDataMapper func NewApp3MetaDataMapper(key *sdk.KVStoreKey) App3MetaDataMapper { return App3MetaDataMapper{mainKey: key} } +// Implements MetaDataMpper. Returns metadata for coin +// If metadata does not exist in store, function creates default metadata and returns it +// without adding it to the store. func (mdm App3MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata { store := ctx.KVStore(mdm.mainKey) @@ -170,6 +175,7 @@ func (mdm App3MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMet return metadata } +// Implements MetaDataMapper. Sets metadata in store with key equal to denom. func (mdm App3MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) { store := ctx.KVStore(mdm.mainKey) diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index 078a43d8bd..564039798d 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -59,6 +59,7 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { return app } +// Application state at Genesis has accounts with starting balances and coins with starting metadata type GenesisState struct { Accounts []*GenesisAccount `json:"accounts"` Coins []*GenesisCoin `json:"coins"` @@ -70,6 +71,7 @@ type GenesisAccount struct { Coins sdk.Coins `json:"coins"` } +// Converts GenesisAccount to auth.BaseAccount for storage in account store func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount, err error) { baseAcc := auth.BaseAccount{ Address: ga.Address, @@ -86,6 +88,7 @@ type GenesisCoin struct { Decimal uint64 `json:"decimals"` } +// Converts GenesisCoin to its denom and metadata for storage in main store func (gc *GenesisCoin) ToMetaData() (string, CoinMetadata) { return gc.Denom, CoinMetadata{ Issuer: gc.Issuer, @@ -129,8 +132,10 @@ func NewInitChainer(cdc *wire.Codec, accountMapper auth.AccountMapper, metadataM } //--------------------------------------------------------------------------------------------- -// Now that initializing coin metadata is done in InitChainer we can simplifiy handleMsgIssue +// Now that initializing coin metadata is done in InitChainer we can simplify handleMsgIssue +// New MsgIssue handler will no longer generate coin metadata on the fly. +// Allows issuers (permissioned at genesis) to issue coin to receiver. func evenBetterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { issueMsg, ok := msg.(MsgIssue) @@ -156,6 +161,8 @@ func evenBetterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank. } } +// No longer generates metadata on the fly. +// Returns error result when it cannot find coin metadata func evenBetterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result { metadata := metadataMapper.GetMetaData(ctx, coin.Denom) @@ -182,16 +189,19 @@ func evenBetterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, is } //--------------------------------------------------------------------------------------------- -// Simpler MetaDataMapper no longer able to initalize default CoinMetaData +// Simpler MetaDataMapper no longer able to initialize default CoinMetaData +// Implements MetaDataMapper type App4MetaDataMapper struct { mainKey *sdk.KVStoreKey } +// Constructs new App4MetaDataMapper func NewApp4MetaDataMapper(key *sdk.KVStoreKey) App4MetaDataMapper { return App4MetaDataMapper{mainKey: key} } +// Returns coin Metadata. If metadata not found in store, function returns empty struct. func (mdm App4MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata { store := ctx.KVStore(mdm.mainKey) @@ -210,6 +220,7 @@ func (mdm App4MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMet return metadata } +// Sets metadata in store with key equal to coin denom. Same behavior as App3 implementation. func (mdm App4MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) { store := ctx.KVStore(mdm.mainKey) From 090aaf81371ee49f14f3495843dc2f05e507cf1c Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Thu, 28 Jun 2018 15:23:47 -0400 Subject: [PATCH 37/77] Merge #1412: Add async flag and functionality to gaiacli send * added async functionality to gaiacli * addressed requested changes, updated changelog --- CHANGELOG.md | 1 + client/context/helpers.go | 41 +++++++++++++++++++++++++++++++++++-- client/context/viper.go | 2 +- x/bank/client/cli/sendtx.go | 13 ++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aca8de106..560694b995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ FEATURES * [types] Switches internal representation of Int/Uint/Rat to use pointers * [gaiad] unsafe_reset_all now resets addrbook.json * [democoin] add x/oracle, x/assoc +* [gaiacli] added an --async flag to the cli to deliver transactions without waiting for a tendermint response FIXES * [gaia] Added self delegation for validators in the genesis creation diff --git a/client/context/helpers.go b/client/context/helpers.go index fa46c73fdf..dfe75e4870 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -44,6 +44,22 @@ func (ctx CoreContext) BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, return res, err } +// Broadcast the transaction bytes to Tendermint +func (ctx CoreContext) BroadcastTxAsync(tx []byte) (*ctypes.ResultBroadcastTx, error) { + + node, err := ctx.GetNode() + if err != nil { + return nil, err + } + + res, err := node.BroadcastTxAsync(tx) + if err != nil { + return res, err + } + + return res, err +} + // Query information about the connected node func (ctx CoreContext) Query(path string) (res []byte, err error) { return ctx.query(path, nil) @@ -160,8 +176,7 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msgs []sdk.Msg, cdc } // sign and build the transaction from the msg -func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) { - +func (ctx CoreContext) ensureSignBuild(name string, msgs []sdk.Msg, cdc *wire.Codec) (tyBytes []byte, err error) { ctx, err = EnsureAccountNumber(ctx) if err != nil { return nil, err @@ -182,9 +197,31 @@ func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc return nil, err } + return txBytes, err +} + +// sign and build the transaction from the msg +func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) { + + txBytes, err := ctx.ensureSignBuild(name, msgs, cdc) + if err != nil { + return nil, err + } + return ctx.BroadcastTx(txBytes) } +// sign and build the async transaction from the msg +func (ctx CoreContext) EnsureSignBuildBroadcastAsync(name string, msgs []sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTx, err error) { + + txBytes, err := ctx.ensureSignBuild(name, msgs, cdc) + if err != nil { + return nil, err + } + + return ctx.BroadcastTxAsync(txBytes) +} + // get the next sequence for the account address func (ctx CoreContext) GetAccountNumber(address []byte) (int64, error) { if ctx.Decoder == nil { diff --git a/client/context/viper.go b/client/context/viper.go index d3896fe580..a0c991bbfd 100644 --- a/client/context/viper.go +++ b/client/context/viper.go @@ -56,7 +56,7 @@ func defaultChainID() (string, error) { return doc.ChainID, nil } -// EnsureSequence - automatically set sequence number if none provided +// EnsureAccount - automatically set account number if none provided func EnsureAccountNumber(ctx CoreContext) (CoreContext, error) { // Should be viper.IsSet, but this does not work - https://github.com/spf13/viper/pull/331 if viper.GetInt64(client.FlagAccountNumber) != 0 { diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index fe2f7fc2af..d3f7377fab 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -16,6 +16,7 @@ import ( const ( flagTo = "to" flagAmount = "amount" + flagAsync = "async" ) // SendTxCommand will create a send tx and sign it with the given key @@ -47,16 +48,28 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint msg := client.BuildMsg(from, to, coins) + + if viper.GetBool(flagAsync) { + res, err := ctx.EnsureSignBuildBroadcastAsync(ctx.FromAddressName, []sdk.Msg{msg}, cdc) + if err != nil { + return err + } + fmt.Println("Async tx sent. tx hash: ", res.Hash.String()) + return nil + } res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) if err != nil { return err } fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) return nil + }, } cmd.Flags().String(flagTo, "", "Address to send coins") cmd.Flags().String(flagAmount, "", "Amount of coins to send") + cmd.Flags().Bool(flagAsync, false, "Pass the async flag to send a tx without waiting for the tx to be included in a block") + return cmd } From ac3adff1e885c15fa2d645022f56c9b774b4145f Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Thu, 28 Jun 2018 15:52:10 -0700 Subject: [PATCH 38/77] Merge PR #1438: Tools: Add errcheck linter This linter ensures that all errors are checked. This is disabled in the client directories, since its not needed on those writes --- CHANGELOG.md | 1 + Makefile | 1 + baseapp/baseapp.go | 10 ++++++++-- baseapp/helpers.go | 12 ++++++++++-- cmd/gaia/cmd/gaiacli/main.go | 6 +++++- cmd/gaia/cmd/gaiad/main.go | 6 +++++- examples/basecoin/cmd/basecli/main.go | 6 +++++- examples/basecoin/cmd/basecoind/main.go | 6 +++++- examples/democoin/cmd/democli/main.go | 6 +++++- examples/democoin/cmd/democoind/main.go | 6 +++++- examples/kvstore/main.go | 10 ++++++++-- server/init.go | 8 ++++---- server/mock/helpers.go | 6 +++++- server/start.go | 10 ++++++++-- server/test_helpers.go | 17 +++++++++++++++-- server/testnet.go | 11 ++++++----- server/util.go | 6 +++++- store/iavlstore.go | 6 +++++- store/rootmultistore.go | 6 +++++- tests/util.go | 10 ++++++++-- tools/Makefile | 15 +++++++++++++++ types/lib/linear.go | 6 +++++- x/auth/ante.go | 15 +++++++++++---- x/auth/mapper.go | 24 ++++++++++++++++++++---- x/auth/mock/app.go | 6 +++++- x/bank/keeper.go | 6 +++++- x/gov/genesis.go | 6 +++++- x/slashing/test_common.go | 3 ++- x/stake/keeper/delegation.go | 5 ++++- x/stake/keeper/test_common.go | 3 ++- 30 files changed, 193 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 560694b995..5beaf64c88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ FEATURES * go vet -composites=false * unconvert * ineffassign + * errcheck * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates * [tests] Add WaitForNextNBlocksTM helper method * [types] Switches internal representation of Int/Uint/Rat to use pointers diff --git a/Makefile b/Makefile index 9cf1b14bc8..46dd5dae5e 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,7 @@ test_cover: test_lint: gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --enable='unconvert' --enable='ineffassign' --linter='vet:go vet -composites=false:PATH:LINE:MESSAGE' --enable='vet' --deadline=500s --vendor ./... + !(gometalinter.v2 --disable-all --enable='errcheck' --vendor ./... | grep -v "client/") find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s benchmark: diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 9c4d100cd3..331b30b655 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -164,13 +164,19 @@ func (app *BaseApp) Router() Router { return app.router } // load latest application version func (app *BaseApp) LoadLatestVersion(mainKey sdk.StoreKey) error { - app.cms.LoadLatestVersion() + err := app.cms.LoadLatestVersion() + if err != nil { + return err + } return app.initFromStore(mainKey) } // load application version func (app *BaseApp) LoadVersion(version int64, mainKey sdk.StoreKey) error { - app.cms.LoadVersion(version) + err := app.cms.LoadVersion(version) + if err != nil { + return err + } return app.initFromStore(mainKey) } diff --git a/baseapp/helpers.go b/baseapp/helpers.go index b7ac45d9aa..e620774e9a 100644 --- a/baseapp/helpers.go +++ b/baseapp/helpers.go @@ -13,12 +13,20 @@ func RunForever(app abci.Application) { srv, err := server.NewServer("0.0.0.0:26658", "socket", app) if err != nil { cmn.Exit(err.Error()) + return + } + err = srv.Start() + if err != nil { + cmn.Exit(err.Error()) + return } - srv.Start() // Wait forever cmn.TrapSignal(func() { // Cleanup - srv.Stop() + err := srv.Stop() + if err != nil { + cmn.Exit(err.Error()) + } }) } diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 8c6e971e72..37e3f1664f 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -142,5 +142,9 @@ func main() { // prepare and add flags executor := cli.PrepareMainCmd(rootCmd, "GA", app.DefaultCLIHome) - executor.Execute() + err := executor.Execute() + if err != nil { + // handle with #870 + panic(err) + } } diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 5d0eb90300..24ff148ce2 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -31,7 +31,11 @@ func main() { // prepare and add flags executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome) - executor.Execute() + err := executor.Execute() + if err != nil { + // handle with #870 + panic(err) + } } func newApp(logger log.Logger, db dbm.DB) abci.Application { diff --git a/examples/basecoin/cmd/basecli/main.go b/examples/basecoin/cmd/basecli/main.go index 7aae47d46a..1191aab6ab 100644 --- a/examples/basecoin/cmd/basecli/main.go +++ b/examples/basecoin/cmd/basecli/main.go @@ -80,5 +80,9 @@ func main() { // prepare and add flags executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.basecli")) - executor.Execute() + err := executor.Execute() + if err != nil { + // handle with #870 + panic(err) + } } diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 4a6498e1be..3665aedba4 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -33,7 +33,11 @@ func main() { // prepare and add flags rootDir := os.ExpandEnv("$HOME/.basecoind") executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) - executor.Execute() + err := executor.Execute() + if err != nil { + // handle with #870 + panic(err) + } } func newApp(logger log.Logger, db dbm.DB) abci.Application { diff --git a/examples/democoin/cmd/democli/main.go b/examples/democoin/cmd/democli/main.go index cdf9396d6c..cbf43508ba 100644 --- a/examples/democoin/cmd/democli/main.go +++ b/examples/democoin/cmd/democli/main.go @@ -92,5 +92,9 @@ func main() { // prepare and add flags executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.democli")) - executor.Execute() + err := executor.Execute() + if err != nil { + // handle with #870 + panic(err) + } } diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 9e84c02571..58b9af06a7 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -72,5 +72,9 @@ func main() { // prepare and add flags rootDir := os.ExpandEnv("$HOME/.democoind") executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) - executor.Execute() + err := executor.Execute() + if err != nil { + // handle with #870 + panic(err) + } } diff --git a/examples/kvstore/main.go b/examples/kvstore/main.go index 6835f54071..459099b687 100644 --- a/examples/kvstore/main.go +++ b/examples/kvstore/main.go @@ -55,12 +55,18 @@ func main() { fmt.Println(err) os.Exit(1) } - srv.Start() + err = srv.Start() + if err != nil { + cmn.Exit(err.Error()) + } // Wait forever cmn.TrapSignal(func() { // Cleanup - srv.Stop() + err = srv.Stop() + if err != nil { + cmn.Exit(err.Error()) + } }) return } diff --git a/server/init.go b/server/init.go index 3424c73bc6..7558a9779c 100644 --- a/server/init.go +++ b/server/init.go @@ -88,7 +88,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { viper.GetBool(FlagOWK), ip, } - cliPrint, genTxFile, err := gentxWithConfig(ctx, cdc, appInit, config, genTxConfig) + cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig) if err != nil { return err } @@ -112,7 +112,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { return cmd } -func gentxWithConfig(ctx *Context, cdc *wire.Codec, appInit AppInit, config *cfg.Config, genTxConfig serverconfig.GenTx) ( +func gentxWithConfig(cdc *wire.Codec, appInit AppInit, config *cfg.Config, genTxConfig serverconfig.GenTx) ( cliPrint json.RawMessage, genTxFile json.RawMessage, err error) { nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) if err != nil { @@ -169,7 +169,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { viper.GetBool(FlagOverwrite), } - chainID, nodeID, appMessage, err := initWithConfig(ctx, cdc, appInit, config, initConfig) + chainID, nodeID, appMessage, err := initWithConfig(cdc, appInit, config, initConfig) if err != nil { return err } @@ -200,7 +200,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { return cmd } -func initWithConfig(ctx *Context, cdc *wire.Codec, appInit AppInit, config *cfg.Config, initConfig InitConfig) ( +func initWithConfig(cdc *wire.Codec, appInit AppInit, config *cfg.Config, initConfig InitConfig) ( chainID string, nodeID string, appMessage json.RawMessage, err error) { nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) if err != nil { diff --git a/server/mock/helpers.go b/server/mock/helpers.go index 601fee897d..a7a0001730 100644 --- a/server/mock/helpers.go +++ b/server/mock/helpers.go @@ -1,6 +1,7 @@ package mock import ( + "fmt" "io/ioutil" "os" @@ -19,7 +20,10 @@ func SetupApp() (abci.Application, func(), error) { } cleanup := func() { - os.RemoveAll(rootDir) + err := os.RemoveAll(rootDir) + if err != nil { + fmt.Printf("could not delete %s, had error %s\n", rootDir, err.Error()) + } } app, err := NewApp(rootDir, logger) diff --git a/server/start.go b/server/start.go index 77a18fffb9..82fcca08bb 100644 --- a/server/start.go +++ b/server/start.go @@ -58,12 +58,18 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error { return errors.Errorf("error creating listener: %v\n", err) } svr.SetLogger(ctx.Logger.With("module", "abci-server")) - svr.Start() + err = svr.Start() + if err != nil { + cmn.Exit(err.Error()) + } // Wait forever cmn.TrapSignal(func() { // Cleanup - svr.Stop() + err = svr.Stop() + if err != nil { + cmn.Exit(err.Error()) + } }) return nil } diff --git a/server/test_helpers.go b/server/test_helpers.go index fc6098e3cf..5abf57c17c 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -21,7 +21,16 @@ func FreeTCPAddr() (addr, port string, err error) { if err != nil { return "", "", err } - defer l.Close() + + closer := func() { + err := l.Close() + if err != nil { + // TODO: Handle with #870 + panic(err) + } + } + + defer closer() portI := l.Addr().(*net.TCPAddr).Port port = fmt.Sprintf("%d", portI) @@ -36,7 +45,11 @@ func setupViper(t *testing.T) func() { require.Nil(t, err) viper.Set(cli.HomeFlag, rootDir) return func() { - os.RemoveAll(rootDir) + err := os.RemoveAll(rootDir) + if err != nil { + // TODO: Handle with #870 + panic(err) + } } } diff --git a/server/testnet.go b/server/testnet.go index 4d7643750e..a60701d246 100644 --- a/server/testnet.go +++ b/server/testnet.go @@ -9,11 +9,12 @@ import ( gc "github.com/cosmos/cosmos-sdk/server/config" + "os" + "github.com/cosmos/cosmos-sdk/wire" "github.com/spf13/viper" cfg "github.com/tendermint/tendermint/config" cmn "github.com/tendermint/tmlibs/common" - "os" ) var ( @@ -42,7 +43,7 @@ Example: `, RunE: func(_ *cobra.Command, _ []string) error { config := ctx.Config - err := testnetWithConfig(config, ctx, cdc, appInit) + err := testnetWithConfig(config, cdc, appInit) return err }, } @@ -58,7 +59,7 @@ Example: return cmd } -func testnetWithConfig(config *cfg.Config, ctx *Context, cdc *wire.Codec, appInit AppInit) error { +func testnetWithConfig(config *cfg.Config, cdc *wire.Codec, appInit AppInit) error { outDir := viper.GetString(outputDir) // Generate private key, node ID, initial transaction @@ -104,7 +105,7 @@ func testnetWithConfig(config *cfg.Config, ctx *Context, cdc *wire.Codec, appIni } // Run `init gen-tx` and generate initial transactions - cliPrint, genTxFile, err := gentxWithConfig(ctx, cdc, appInit, config, genTxConfig) + cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig) if err != nil { return err } @@ -154,7 +155,7 @@ func testnetWithConfig(config *cfg.Config, ctx *Context, cdc *wire.Codec, appIni config.SetRoot(nodeDir) // Run `init` and generate genesis.json and config.toml - _, _, _, err := initWithConfig(ctx, cdc, appInit, config, initConfig) + _, _, _, err := initWithConfig(cdc, appInit, config, initConfig) if err != nil { return err } diff --git a/server/util.go b/server/util.go index e0746f7528..bd9d48d752 100644 --- a/server/util.go +++ b/server/util.go @@ -69,7 +69,11 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error // If a new config is created, change some of the default tendermint settings func interceptLoadConfig() (conf *cfg.Config, err error) { tmpConf := cfg.DefaultConfig() - viper.Unmarshal(tmpConf) + err = viper.Unmarshal(tmpConf) + if err != nil { + // TODO: Handle with #870 + panic(err) + } rootDir := tmpConf.RootDir configFilePath := filepath.Join(rootDir, "config/config.toml") // Intercept only if the file doesn't already exist diff --git a/store/iavlstore.go b/store/iavlstore.go index 3b4e77ee0a..865a22f0f3 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -67,7 +67,11 @@ func (st *iavlStore) Commit() CommitID { // Release an old version of history if st.numHistory > 0 && (st.numHistory < st.tree.Version64()) { toRelease := version - st.numHistory - st.tree.DeleteVersion(toRelease) + err := st.tree.DeleteVersion(toRelease) + if err != nil { + // TODO: Handle with #870 + panic(err) + } } return CommitID{ diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 05a2e13fba..4a97f0e288 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -343,7 +343,11 @@ func (si storeInfo) Hash() []byte { // include them via the keys. bz, _ := cdc.MarshalBinary(si.Core) // Does not error hasher := ripemd160.New() - hasher.Write(bz) + _, err := hasher.Write(bz) + if err != nil { + // TODO: Handle with #870 + panic(err) + } return hasher.Sum(nil) } diff --git a/tests/util.go b/tests/util.go index 1b68a9fd98..54432f9927 100644 --- a/tests/util.go +++ b/tests/util.go @@ -101,7 +101,10 @@ func waitForHeight(height int64, url string) { if err != nil { panic(err) } - res.Body.Close() + err = res.Body.Close() + if err != nil { + panic(err) + } var resultBlock ctypes.ResultBlock err = cdc.UnmarshalJSON(body, &resultBlock) @@ -136,7 +139,10 @@ func WaitForStart(port string) { // waiting for server to start ... if res.StatusCode != http.StatusOK { - res.Body.Close() + err = res.Body.Close() + if err != nil { + panic(err) + } return } } diff --git a/tools/Makefile b/tools/Makefile index 7fb1e886c5..516de1a426 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -10,6 +10,7 @@ GOMETALINTER = gopkg.in/alecthomas/gometalinter.v2 UNCONVERT = github.com/mdempsky/unconvert INEFFASSIGN = github.com/gordonklaus/ineffassign MISSPELL = github.com/client9/misspell/cmd/misspell +ERRCHECK = github.com/kisielk/errcheck DEP_CHECK := $(shell command -v dep 2> /dev/null) GOLINT_CHECK := $(shell command -v golint 2> /dev/null) @@ -17,6 +18,7 @@ GOMETALINTER_CHECK := $(shell command -v gometalinter.v2 2> /dev/null) UNCONVERT_CHECK := $(shell command -v unconvert 2> /dev/null) INEFFASSIGN_CHECK := $(shell command -v ineffassign 2> /dev/null) MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null) +ERRCHECK_CHECK := $(shell command -v errcheck 2> /dev/null) check_tools: ifndef DEP_CHECK @@ -49,6 +51,11 @@ ifndef MISSPELL_CHECK else @echo "Found misspell in path." endif +ifndef MISSPELL_CHECK + @echo "No errcheck in path. Install with 'make get_tools'." +else + @echo "Found errcheck in path." +endif get_tools: ifdef DEP_CHECK @@ -87,6 +94,12 @@ else @echo "Installing misspell" go get -v $(MISSPELL) endif +ifdef ERRCHECK_CHECK + @echo "misspell is already installed. Run 'make update_tools' to update." +else + @echo "Installing misspell" + go get -v $(ERRCHECK) +endif update_tools: @echo "Updating dep" @@ -101,6 +114,8 @@ update_tools: go get -u -v $(INEFFASSIGN) @echo "Updating misspell" go get -u -v $(MISSPELL) + @echo "Updating errcheck" + go get -u -v $(ERRCHECK) # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. diff --git a/types/lib/linear.go b/types/lib/linear.go index 75cb719a5d..5a311a01fb 100644 --- a/types/lib/linear.go +++ b/types/lib/linear.go @@ -233,7 +233,11 @@ func (m Linear) Flush(ptr interface{}, fn func() bool) { var i uint64 for i = top; i < length; i++ { - m.Get(i, ptr) + err := m.Get(i, ptr) + if err != nil { + // TODO: Handle with #870 + panic(err) + } m.Delete(i) if fn() { break diff --git a/x/auth/ante.go b/x/auth/ante.go index 5bcea123e2..ff3145d456 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -140,8 +140,11 @@ func processSig( return nil, sdk.ErrInvalidSequence( fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result() } - acc.SetSequence(seq + 1) - + err := acc.SetSequence(seq + 1) + if err != nil { + // Handle w/ #870 + panic(err) + } // If pubkey is not known for account, // set it from the StdSignature. pubKey := acc.GetPubKey() @@ -154,7 +157,7 @@ func processSig( return nil, sdk.ErrInvalidPubKey( fmt.Sprintf("PubKey does not match Signer address %v", addr)).Result() } - err := acc.SetPubKey(pubKey) + err = acc.SetPubKey(pubKey) if err != nil { return nil, sdk.ErrInternal("setting PubKey on signer's account").Result() } @@ -181,7 +184,11 @@ func deductFees(acc Account, fee StdFee) (Account, sdk.Result) { errMsg := fmt.Sprintf("%s < %s", coins, feeAmount) return nil, sdk.ErrInsufficientFunds(errMsg).Result() } - acc.SetCoins(newCoins) + err := acc.SetCoins(newCoins) + if err != nil { + // Handle w/ #870 + panic(err) + } return acc, sdk.Result{} } diff --git a/x/auth/mapper.go b/x/auth/mapper.go index 4baa9c466b..8ceba3e506 100644 --- a/x/auth/mapper.go +++ b/x/auth/mapper.go @@ -39,14 +39,26 @@ func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto Account) AccountM // Implaements sdk.AccountMapper. func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) Account { acc := am.clonePrototype() - acc.SetAddress(addr) - acc.SetAccountNumber(am.GetNextAccountNumber(ctx)) + err := acc.SetAddress(addr) + if err != nil { + // Handle w/ #870 + panic(err) + } + err = acc.SetAccountNumber(am.GetNextAccountNumber(ctx)) + if err != nil { + // Handle w/ #870 + panic(err) + } return acc } // New Account func (am AccountMapper) NewAccount(ctx sdk.Context, acc Account) Account { - acc.SetAccountNumber(am.GetNextAccountNumber(ctx)) + err := acc.SetAccountNumber(am.GetNextAccountNumber(ctx)) + if err != nil { + // TODO: Handle with #870 + panic(err) + } return acc } @@ -114,7 +126,11 @@ func (am AccountMapper) setSequence(ctx sdk.Context, addr sdk.Address, newSequen if acc == nil { return sdk.ErrUnknownAddress(addr.String()) } - acc.SetSequence(newSequence) + err := acc.SetSequence(newSequence) + if err != nil { + // Handle w/ #870 + panic(err) + } am.SetAccount(ctx, acc) return nil } diff --git a/x/auth/mock/app.go b/x/auth/mock/app.go index f532432092..880b5153e7 100644 --- a/x/auth/mock/app.go +++ b/x/auth/mock/app.go @@ -77,7 +77,11 @@ func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.Respo // load the accounts for _, genacc := range app.GenesisAccounts { acc := app.AccountMapper.NewAccountWithAddress(ctx, genacc.GetAddress()) - acc.SetCoins(genacc.GetCoins()) + err := acc.SetCoins(genacc.GetCoins()) + if err != nil { + // TODO: Handle with #870 + panic(err) + } app.AccountMapper.SetAccount(ctx, acc) } diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 71c884ffe4..0c8bb24f0e 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -131,7 +131,11 @@ func setCoins(ctx sdk.Context, am auth.AccountMapper, addr sdk.Address, amt sdk. if acc == nil { acc = am.NewAccountWithAddress(ctx, addr) } - acc.SetCoins(amt) + err := acc.SetCoins(amt) + if err != nil { + // Handle w/ #870 + panic(err) + } am.SetAccount(ctx, acc) return nil } diff --git a/x/gov/genesis.go b/x/gov/genesis.go index bf0b3a1556..40218ca868 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -24,7 +24,11 @@ func DefaultGenesisState() GenesisState { // InitGenesis - store genesis parameters func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { - k.setInitialProposalID(ctx, data.StartingProposalID) + err := k.setInitialProposalID(ctx, data.StartingProposalID) + if err != nil { + // TODO: Handle this with #870 + panic(err) + } } // WriteGenesis - output genesis parameters diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 795483efdf..0f3ee3f10c 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -66,10 +66,11 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep genesis.Pool.LooseTokens = initCoins.MulRaw(int64(len(addrs))).Int64() stake.InitGenesis(ctx, sk, genesis) for _, addr := range addrs { - ck.AddCoins(ctx, addr, sdk.Coins{ + _, _, err = ck.AddCoins(ctx, addr, sdk.Coins{ {sk.GetParams(ctx).BondDenom, initCoins}, }) } + require.Nil(t, err) keeper := NewKeeper(cdc, keySlashing, sk, DefaultCodespace) return ctx, ck, sk, keeper } diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 844ffb9b48..aab1dda90c 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -295,7 +295,10 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr return types.ErrNotMature(k.Codespace(), "unbonding", "unit-time", ubd.MinTime, ctxTime) } - k.coinKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{ubd.Balance}) + _, _, err := k.coinKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{ubd.Balance}) + if err != nil { + return err + } k.RemoveUnbondingDelegation(ctx, ubd) return nil } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index eea71c07e7..8460f78bcb 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -114,9 +114,10 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context // fill all the addresses with some coins, set the loose pool tokens simultaneously for _, addr := range Addrs { pool := keeper.GetPool(ctx) - ck.AddCoins(ctx, addr, sdk.Coins{ + _, _, err := ck.AddCoins(ctx, addr, sdk.Coins{ {keeper.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)}, }) + require.Nil(t, err) pool.LooseTokens += initCoins keeper.SetPool(ctx, pool) } From e8946e9b36b72c97acd1d393d8f8dc45ce9b869c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 28 Jun 2018 19:06:10 -0400 Subject: [PATCH 39/77] fixes from review --- docs/core/app1.md | 55 ++++++++++++++++++++++++++++---------- docs/core/app2.md | 6 ++--- docs/core/app3.md | 4 +-- docs/core/examples/app1.go | 2 +- docs/core/examples/app2.go | 13 +++++---- docs/core/examples/app3.go | 8 +++--- docs/core/examples/app4.go | 3 ++- types/tx_msg.go | 6 ++--- 8 files changed, 62 insertions(+), 35 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 08fcf73fe3..da51b0a89a 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -18,15 +18,15 @@ type Msg interface { // Must be alphanumeric or empty. // Must correspond to name of message handler (XXX). Type() string + + // ValidateBasic does a simple validation check that + // doesn't require access to any other information. + ValidateBasic() error // Get the canonical byte representation of the Msg. // This is what is signed. GetSignBytes() []byte - // ValidateBasic does a simple validation check that - // doesn't require access to any other information. - ValidateBasic() error - // Signers returns the addrs of signers that must sign. // CONTRACT: All signatures must be present to be valid. // CONTRACT: Returns addrs in some deterministic order. @@ -38,10 +38,6 @@ type Msg interface { The `Msg` interface allows messages to define basic validity checks, as well as what needs to be signed and who needs to sign it. -Addresses in the SDK are arbitrary byte arrays that are hex-encoded when -displayed as a string or rendered in JSON. Typically, addresses are the hash of -a public key. - For instance, take the simple token sending message type from app1.go: ```go @@ -74,8 +70,14 @@ func (msg MsgSend) GetSigners() []sdk.Address { } ``` +Note Addresses in the SDK are arbitrary byte arrays that are [Bech32](TODO) encoded +when displayed as a string or rendered in JSON. Typically, addresses are the hash of +a public key, so we can use them to uniquely identify the required signers for a +transaction. + + The basic validity check ensures the From and To address are specified and the -amount is positive: +Amount is positive: ```go // Implements Msg. Ensure the addresses are good and the @@ -94,6 +96,8 @@ func (msg MsgSend) ValidateBasic() sdk.Error { } ``` +Note the `ValidateBasic` method is called automatically by the SDK! + ## KVStore The basic persistence layer for an SDK application is the KVStore: @@ -240,8 +244,10 @@ func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { We have only a single message type, so just one message-specific function to define, `handleMsgSend`. -Note this handler has unfettered access to the store specified by the capability key `keyAcc`. So it must also define items in the store are encoded. -For this first example, we will define a simple account that is JSON encoded: +Note this handler has unrestricted access to the store specified by the capability key `keyAcc`, +so it must define what to store and how to encode it. Later, we'll introduce +higher-level abstractions so Handlers are restricted in what they can do. +For this first example, we use a simple account that is JSON encoded: ```go type appAccount struct { @@ -249,7 +255,8 @@ type appAccount struct { } ``` -Coins is a useful type provided by the SDK for multi-asset accounts. While we could just use an integer here for a single coin type, +Coins is a useful type provided by the SDK for multi-asset accounts. +We could just use an integer here for a single coin type, but it's worth [getting to know Coins](TODO). @@ -258,6 +265,7 @@ Now we're ready to handle the MsgSend: ```go // Handle MsgSend. // NOTE: msg.From, msg.To, and msg.Amount were already validated +// in ValidateBasic(). func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result { // Load the store. store := ctx.KVStore(key) @@ -359,7 +367,7 @@ func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { And that's that! -# Tx +## Tx The final piece before putting it all together is the `Tx`. While `Msg` contains the content for particular functionality in the application, the actual input @@ -408,7 +416,7 @@ func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { } ``` -# BaseApp +## BaseApp Finally, we stitch it all together using the `BaseApp`. @@ -467,6 +475,25 @@ After setting the transaction decoder and the message handling routes, the final step is to mount the stores and load the latest version. Since we only have one store, we only mount one. +## Execution + +We're now done the core logic of the app! From here, we could write transactions +in Go and execute them against the application using the `app.DeliverTx` method. +In a real setup, the app would run as an ABCI application and +would be driven by blocks of transactions from the Tendermint consensus engine. +Later in the tutorial, we'll connect our app to a complete suite of components +for running and using a live blockchain application. For complete details on +how ABCI applications work, see the [ABCI documentation](TODO). + +For now, we note the follow sequence of events occurs when a transaction is +received (through `app.DeliverTx`): + +- serialized transaction is received by `app.DeliverTx` +- transaction is deserialized using `TxDecoder` +- for each message in the transaction, run `msg.ValidateBasic()` +- for each message in the transaction, load the appropriate handler and execute + it with the message + ## Conclusion We now have a complete implementation of a simple app! diff --git a/docs/core/app2.md b/docs/core/app2.md index f9a2e060f3..2cf62b8a25 100644 --- a/docs/core/app2.md +++ b/docs/core/app2.md @@ -84,10 +84,10 @@ Now that we're using Amino, we can embed the `Msg` interface directly in our ```go // Simple tx to wrap the Msg. type app2Tx struct { - sdk.Msg - + sdk.Msg + PubKey crypto.PubKey - Signature crypto.Signature + Signature crypto.Signature } // This tx only has one Msg. diff --git a/docs/core/app3.md b/docs/core/app3.md index 3f35b9c1eb..141264ac25 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -113,9 +113,9 @@ Then we can get, modify, and set accounts. For instance, we could double the amount of coins in an account: ```go -acc := GetAccount(ctx, addr) +acc := accountMapper.GetAccount(ctx, addr) acc.SetCoins(acc.Coins.Plus(acc.Coins)) -acc.SetAccount(ctx, addr) +accountMapper.SetAccount(ctx, addr) ``` Note that the `AccountMapper` takes a `Context` as the first argument, and will diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index 56fcea0ec9..2e57743f77 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -106,6 +106,7 @@ func (msg MsgSend) Tags() sdk.Tags { // Handle MsgSend. // NOTE: msg.From, msg.To, and msg.Amount were already validated +// in ValidateBasic(). func handleMsgSend(key *sdk.KVStoreKey) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { sendMsg, ok := msg.(MsgSend) @@ -115,7 +116,6 @@ func handleMsgSend(key *sdk.KVStoreKey) sdk.Handler { return sdk.NewError(2, 1, "Send Message is malformed").Result() } - // Load the store. store := ctx.KVStore(key) diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index f0260ac432..bed5b0f447 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -1,9 +1,9 @@ package app import ( + "bytes" "encoding/json" "fmt" - "reflect" "github.com/tendermint/go-crypto" cmn "github.com/tendermint/tmlibs/common" @@ -76,9 +76,9 @@ type CoinMetadata struct { // if he is the issuer in Coin Metadata // Implements sdk.Msg Interface type MsgIssue struct { - Issuer sdk.Address + Issuer sdk.Address Receiver sdk.Address - Coin sdk.Coin + Coin sdk.Coin } // Implements Msg. @@ -179,7 +179,7 @@ func handleMetaData(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Re } // Msg Issuer is not authorized to issue these coins - if !reflect.DeepEqual(metadata.Issuer, issuer) { + if !bytes.Equal(metadata.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } @@ -198,11 +198,10 @@ func handleMetaData(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Re // Update store with new metadata store.Set([]byte(coin.Denom), val) - + return sdk.Result{} } - //------------------------------------------------------------------ // Tx @@ -246,7 +245,7 @@ func antehandler(ctx sdk.Context, tx sdk.Tx) (_ sdk.Context, _ sdk.Result, abort sig := appTx.GetSignatures()[i] // check that submitted pubkey belongs to required address - if !reflect.DeepEqual(sig.PubKey.Address(), addr) { + if !bytes.Equal(sig.PubKey.Address(), addr) { return ctx, sdk.ErrUnauthorized("Provided Pubkey does not match required address").Result(), true } diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index e20bbcb70c..a9a4b9759d 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -1,8 +1,8 @@ package app import ( + "bytes" "encoding/json" - "reflect" "fmt" cmn "github.com/tendermint/tmlibs/common" @@ -94,13 +94,13 @@ func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keep if res := betterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { return res } - + // Add newly issued coins to output address _, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}) if err != nil { return err.Result() } - + return sdk.Result{ // Return result with Issue msg tags Tags: issueMsg.Tags(), @@ -117,7 +117,7 @@ func betterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer } // Msg Issuer is not authorized to issue these coins - if !reflect.DeepEqual(metadata.Issuer, issuer) { + if !bytes.Equal(metadata.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index 564039798d..5494e1bd2d 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -1,6 +1,7 @@ package app import ( + "bytes" "encoding/json" "fmt" "reflect" @@ -172,7 +173,7 @@ func evenBetterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, is } // Msg Issuer not authorized to issue these coins - if !reflect.DeepEqual(metadata.Issuer, issuer) { + if !bytes.Equal(metadata.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } diff --git a/types/tx_msg.go b/types/tx_msg.go index 12146f5b73..c1af91df82 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -11,13 +11,13 @@ type Msg interface { // Must be alphanumeric or empty. Type() string - // Get the canonical byte representation of the Msg. - GetSignBytes() []byte - // ValidateBasic does a simple validation check that // doesn't require access to any other information. ValidateBasic() Error + // Get the canonical byte representation of the Msg. + GetSignBytes() []byte + // Signers returns the addrs of signers that must sign. // CONTRACT: All signatures must be present to be valid. // CONTRACT: Returns addrs in some deterministic order. From e7081040d02dd6ea4ae237c7a58e439866025e6c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 28 Jun 2018 19:41:40 -0400 Subject: [PATCH 40/77] address TODOs in app 1 and 2 --- docs/core/app1.md | 32 ++++---- docs/core/app2.md | 151 +++++++++++++++++++++++++++++++++++-- docs/core/examples/app1.go | 4 +- docs/core/examples/app2.go | 84 ++++++--------------- 4 files changed, 183 insertions(+), 88 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index da51b0a89a..4242348cd1 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -70,7 +70,8 @@ func (msg MsgSend) GetSigners() []sdk.Address { } ``` -Note Addresses in the SDK are arbitrary byte arrays that are [Bech32](TODO) encoded +Note Addresses in the SDK are arbitrary byte arrays that are +[Bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) encoded when displayed as a string or rendered in JSON. Typically, addresses are the hash of a public key, so we can use them to uniquely identify the required signers for a transaction. @@ -128,11 +129,6 @@ type KVStore interface { // CONTRACT: No writes may happen within a domain while an iterator exists over it. ReverseIterator(start, end []byte) Iterator - // TODO Not yet implemented. - // CreateSubKVStore(key *storeKey) (KVStore, error) - - // TODO Not yet implemented. - // GetSubKVStore(key *storeKey) KVStore } ``` @@ -177,19 +173,24 @@ func newFooHandler(key sdk.StoreKey) sdk.Handler { } ``` -`Context` is modeled after the Golang [context.Context](TODO), which has +`Context` is modeled after the Golang +[context.Context](https://golang.org/pkg/context/), which has become ubiquitous in networking middleware and routing applications as a means to easily propogate request context through handler functions. Many methods on SDK objects receive a context as the first argument. -The Context also contains the [block header](TODO), which includes the latest timestamp from the blockchain and other information about the latest block. +The Context also contains the +[block header](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#header), +which includes the latest timestamp from the blockchain and other information about the latest block. -See the [Context API docs](TODO) for more details. +See the [Context API +docs](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Context) for more details. ### Result Handler takes a Context and Msg and returns a Result. -Result is motivated by the corresponding [ABCI result](TODO). It contains return values, error information, logs, and meta data about the transaction: +Result is motivated by the corresponding [ABCI result](https://github.com/tendermint/abci/blob/master/types/types.proto#L165). +It contains return values, error information, logs, and meta data about the transaction: ```go // Result is the union of ResponseDeliverTx and ResponseCheckTx. @@ -257,7 +258,8 @@ type appAccount struct { Coins is a useful type provided by the SDK for multi-asset accounts. We could just use an integer here for a single coin type, but -it's worth [getting to know Coins](TODO). +it's worth [getting to know +Coins](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Coins). Now we're ready to handle the MsgSend: @@ -426,14 +428,13 @@ simplifies application development by handling common low-level concerns. It serves as the mediator between the two key components of an SDK app: the store and the message handlers. The BaseApp implements the [`abci.Application`](https://godoc.org/github.com/tendermint/abci/types#Application) interface. -See the [BaseApp API documentation](TODO) for more details. +See the [BaseApp API +documentation](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp) for more details. Here is the complete setup for App1: ```go func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { - // TODO: make this an interface or pass in - // a TxDecoder instead. cdc := wire.NewCodec() // Create the base application object. @@ -483,7 +484,8 @@ In a real setup, the app would run as an ABCI application and would be driven by blocks of transactions from the Tendermint consensus engine. Later in the tutorial, we'll connect our app to a complete suite of components for running and using a live blockchain application. For complete details on -how ABCI applications work, see the [ABCI documentation](TODO). +how ABCI applications work, see the [ABCI +documentation](https://github.com/tendermint/abci/blob/master/specification.md). For now, we note the follow sequence of events occurs when a transaction is received (through `app.DeliverTx`): diff --git a/docs/core/app2.md b/docs/core/app2.md index 2cf62b8a25..d245aea41a 100644 --- a/docs/core/app2.md +++ b/docs/core/app2.md @@ -11,23 +11,88 @@ Here we build `App2`, which expands on `App1` by introducing Along the way, we'll be introduced to Amino for encoding and decoding transactions and to the AnteHandler for processing them. +The complete code can be found in [app2.go](examples/app2.go). + ## Message Let's introduce a new message type for issuing coins: ```go -TODO +// MsgIssue to allow a registered issuer +// to issue new coins. +type MsgIssue struct { + Issuer sdk.Address + Receiver sdk.Address + Coin sdk.Coin +} + +// Implements Msg. +func (msg MsgIssue) Type() string { return "issue" } ``` +Note the `Type()` method returns `"issue"`, so this message is of a different +type and will be executed by a different handler than `MsgSend`. The other +methods for `MsgIssue` are similar to `MsgSend`. + ## Handler -We'll need a new handler to support the new message type: +We'll need a new handler to support the new message type. It just checks if the +sender of the `MsgIssue` is the correct issuer for the given coin type, as per the information +in the issuer store: ```go -TODO +// Handle MsgIssue +func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + issueMsg, ok := msg.(MsgIssue) + if !ok { + return sdk.NewError(2, 1, "MsgIssue is malformed").Result() + } + + // Retrieve stores + issueStore := ctx.KVStore(keyIssue) + accStore := ctx.KVStore(keyAcc) + + // Handle updating coin info + if res := handleIssuer(issueStore, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { + return res + } + + // Issue coins to receiver using previously defined handleTo function + if res := handleTo(accStore, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}); !res.IsOK() { + return res + } + + return sdk.Result{ + // Return result with Issue msg tags + Tags: issueMsg.Tags(), + } + } +} + +func handleIssuer(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result { + // the issuer address is stored directly under the coin denomination + denom := []byte(coin.Denom) + issuerAddress := store.Get(denom) + if issuerAddress == nil { + return sdk.ErrInvalidCoins(fmt.Sprintf("Unknown coin type %s", coin.Denom)).Result() + } + + // Msg Issuer is not authorized to issue these coins + if !bytes.Equal(issuerAddress, issuer) { + return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() + } + + return sdk.Result{} +} ``` +Note we're just storing the issuer address for each coin directly under the +coin's denomination in the issuer store. We could of course use a struct with more +fields, like the current supply of coins in existence, and the maximum supply +allowed to be issued. + ## Amino Now that we have two implementations of `Msg`, we won't know before hand @@ -74,8 +139,6 @@ func NewCodec() *wire.Codec { Amino supports encoding and decoding in both a binary and JSON format. See the [codec API docs](https://godoc.org/github.com/tendermint/go-amino#Codec) for more details. -TODO: Update Amino and demo `cdc.PrintTypes` - ## Tx Now that we're using Amino, we can embed the `Msg` interface directly in our @@ -121,12 +184,47 @@ according to whatever capability keys it was granted. Instead of a `Msg`, however, it takes a `Tx`. Like Handler, AnteHandler returns a `Result` type, but it also returns a new -`Context` and an `abort bool`. TODO explain (do we still need abort? ) +`Context` and an `abort bool`. For `App2`, we simply check if the PubKey matches the Address, and the Signature validates with the PubKey: ```go -TODO +// Simple anteHandler that ensures msg signers have signed. +// Provides no replay protection. +func antehandler(ctx sdk.Context, tx sdk.Tx) (_ sdk.Context, _ sdk.Result, abort bool) { + appTx, ok := tx.(app2Tx) + if !ok { + // set abort boolean to true so that we don't continue to process failed tx + return ctx, sdk.ErrTxDecode("Tx must be of format app2Tx").Result(), true + } + + // expect only one msg in app2Tx + msg := tx.GetMsgs()[0] + + signerAddrs := msg.GetSigners() + + if len(signerAddrs) != len(appTx.GetSignatures()) { + return ctx, sdk.ErrUnauthorized("Number of signatures do not match required amount").Result(), true + } + + signBytes := msg.GetSignBytes() + for i, addr := range signerAddrs { + sig := appTx.GetSignatures()[i] + + // check that submitted pubkey belongs to required address + if !bytes.Equal(sig.PubKey.Address(), addr) { + return ctx, sdk.ErrUnauthorized("Provided Pubkey does not match required address").Result(), true + } + + // check that signature is over expected signBytes + if !sig.PubKey.VerifyBytes(signBytes, sig.Signature) { + return ctx, sdk.ErrUnauthorized("Signature verification failed").Result(), true + } + } + + // authentication passed, app to continue processing by sending msg to handler + return ctx, sdk.Result{}, false +} ``` ## App2 @@ -134,9 +232,46 @@ TODO Let's put it all together now to get App2: ```go -TODO +func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { + + cdc := NewCodec() + + // Create the base application object. + app := bapp.NewBaseApp(app2Name, cdc, logger, db) + + // Create a key for accessing the account store. + keyAccount := sdk.NewKVStoreKey("acc") + // Create a key for accessing the issue store. + keyIssue := sdk.NewKVStoreKey("issue") + + // set antehandler function + app.SetAnteHandler(antehandler) + + // Register message routes. + // Note the handler gets access to the account store. + app.Router(). + AddRoute("send", handleMsgSend(keyAccount)). + AddRoute("issue", handleMsgIssue(keyAccount, keyIssue)) + + // Mount stores and load the latest state. + app.MountStoresIAVL(keyAccount, keyIssue) + err := app.LoadLatestVersion(keyAccount) + if err != nil { + cmn.Exit(err.Error()) + } + return app +} ``` +The main difference here, compared to `App1`, is that we use a second capability +key for a second store that is *only* passed to a second handler, the +`handleMsgIssue`. The first `handleMsgSend` has no access to this second store and cannot read or write to +it, ensuring a strong separation of concerns. + +Note also that we do not need to use `SetTxDecoder` here - now that we're using +Amino, we simply create a codec, register our types on the codec, and pass the +codec into `NewBaseApp`. The SDK takes care of the rest for us! + ## Conclusion We've expanded on our first app by adding a new message type for issuing coins, diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index 2e57743f77..9daf8d3334 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -18,8 +18,6 @@ const ( func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { - // TODO: make this an interface or pass in - // a TxDecoder instead. cdc := wire.NewCodec() // Create the base application object. @@ -113,7 +111,7 @@ func handleMsgSend(key *sdk.KVStoreKey) sdk.Handler { if !ok { // Create custom error message and return result // Note: Using unreserved error codespace - return sdk.NewError(2, 1, "Send Message is malformed").Result() + return sdk.NewError(2, 1, "MsgSend is malformed").Result() } // Load the store. diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index bed5b0f447..2c10299c56 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -40,8 +40,9 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { app := bapp.NewBaseApp(app2Name, cdc, logger, db) // Create a key for accessing the account store. - keyMain := sdk.NewKVStoreKey("main") keyAccount := sdk.NewKVStoreKey("acc") + // Create a key for accessing the issue store. + keyIssue := sdk.NewKVStoreKey("issue") // set antehandler function app.SetAnteHandler(antehandler) @@ -50,10 +51,10 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Note the handler gets access to the account store. app.Router(). AddRoute("send", handleMsgSend(keyAccount)). - AddRoute("issue", handleMsgIssue(keyAccount, keyMain)) + AddRoute("issue", handleMsgIssue(keyAccount, keyIssue)) // Mount stores and load the latest state. - app.MountStoresIAVL(keyAccount, keyMain) + app.MountStoresIAVL(keyAccount, keyIssue) err := app.LoadLatestVersion(keyAccount) if err != nil { cmn.Exit(err.Error()) @@ -61,20 +62,11 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { return app } -// Coin Metadata -type CoinMetadata struct { - TotalSupply sdk.Int - CurrentSupply sdk.Int - Issuer sdk.Address - Decimal uint64 -} - //------------------------------------------------------------------ // Msgs -// Single permissioned issuer can issue Coin to Receiver -// if he is the issuer in Coin Metadata -// Implements sdk.Msg Interface +// MsgIssue to allow a registered issuer +// to issue new coins. type MsgIssue struct { Issuer sdk.Address Receiver sdk.Address @@ -125,20 +117,20 @@ func (msg MsgIssue) Tags() sdk.Tags { //------------------------------------------------------------------ // Handler for the message -// Handle Msg Issue -func handleMsgIssue(keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler { +// Handle MsgIssue +func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { issueMsg, ok := msg.(MsgIssue) if !ok { - return sdk.NewError(2, 1, "IssueMsg is malformed").Result() + return sdk.NewError(2, 1, "MsgIssue is malformed").Result() } // Retrieve stores - store := ctx.KVStore(keyMain) + issueStore := ctx.KVStore(keyIssue) accStore := ctx.KVStore(keyAcc) - // Handle updating metadata - if res := handleMetaData(store, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { + // Handle updating coin info + if res := handleIssuer(issueStore, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { return res } @@ -154,51 +146,19 @@ func handleMsgIssue(keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler } } -func handleMetaData(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result { - bz := store.Get([]byte(coin.Denom)) - var metadata CoinMetadata - - if bz == nil { - // Coin not set yet, initialize with issuer and default values - // Coin amount can't be above default value - if coin.Amount.GT(sdk.NewInt(1000000)) { - return sdk.ErrInvalidCoins("Cannot issue that many new coins").Result() - } - metadata = CoinMetadata{ - TotalSupply: sdk.NewInt(1000000), - CurrentSupply: sdk.NewInt(0), - Issuer: issuer, - Decimal: 10, - } - } else { - // Decode coin metadata - err := json.Unmarshal(bz, &metadata) - if err != nil { - return sdk.ErrInternal("Decoding coin metadata failed").Result() - } +func handleIssuer(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result { + // the issuer address is stored directly under the coin denomination + denom := []byte(coin.Denom) + issuerAddress := store.Get(denom) + if issuerAddress == nil { + return sdk.ErrInvalidCoins(fmt.Sprintf("Unknown coin type %s", coin.Denom)).Result() } // Msg Issuer is not authorized to issue these coins - if !bytes.Equal(metadata.Issuer, issuer) { + if !bytes.Equal(issuerAddress, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } - // Update coin current circulating supply - metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) - - // Current supply cannot exceed total supply - if metadata.TotalSupply.LT(metadata.CurrentSupply) { - return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result() - } - - val, err := json.Marshal(metadata) - if err != nil { - return sdk.ErrInternal(fmt.Sprintf("Error encoding metadata: %s", err.Error())).Result() - } - - // Update store with new metadata - store.Set([]byte(coin.Denom), val) - return sdk.Result{} } @@ -222,8 +182,8 @@ func (tx app2Tx) GetSignatures() []auth.StdSignature { //------------------------------------------------------------------ -// Simple antehandler that ensures msg signers has signed over msg signBytes w/ no replay protection -// Implement sdk.AnteHandler interface +// Simple anteHandler that ensures msg signers have signed. +// Provides no replay protection. func antehandler(ctx sdk.Context, tx sdk.Tx) (_ sdk.Context, _ sdk.Result, abort bool) { appTx, ok := tx.(app2Tx) if !ok { @@ -235,12 +195,12 @@ func antehandler(ctx sdk.Context, tx sdk.Tx) (_ sdk.Context, _ sdk.Result, abort msg := tx.GetMsgs()[0] signerAddrs := msg.GetSigners() - signBytes := msg.GetSignBytes() if len(signerAddrs) != len(appTx.GetSignatures()) { return ctx, sdk.ErrUnauthorized("Number of signatures do not match required amount").Result(), true } + signBytes := msg.GetSignBytes() for i, addr := range signerAddrs { sig := appTx.GetSignatures()[i] From 778b102a52f9e6e805a5dd1eedbe75ef787ca123 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 28 Jun 2018 20:08:38 -0400 Subject: [PATCH 41/77] more app1/app2 cleanup --- docs/core/app1.md | 64 +++++++++++++++----------------------- docs/core/app2.md | 26 +++++++++++----- docs/core/examples/app2.go | 19 ++++++++--- 3 files changed, 59 insertions(+), 50 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index 4242348cd1..ef56b50813 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -229,41 +229,6 @@ us to easily lookup transactions that pertain to particular accounts or actions. Let's define our handler for App1: -```go -func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgSend: - return handleMsgSend(ctx, keyAcc, msg) - default: - errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} -``` - -We have only a single message type, so just one message-specific function to define, `handleMsgSend`. - -Note this handler has unrestricted access to the store specified by the capability key `keyAcc`, -so it must define what to store and how to encode it. Later, we'll introduce -higher-level abstractions so Handlers are restricted in what they can do. -For this first example, we use a simple account that is JSON encoded: - -```go -type appAccount struct { - Coins sdk.Coins `json:"coins"` -} -``` - -Coins is a useful type provided by the SDK for multi-asset accounts. -We could just use an integer here for a single coin type, but -it's worth [getting to know -Coins](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Coins). - - -Now we're ready to handle the MsgSend: - ```go // Handle MsgSend. // NOTE: msg.From, msg.To, and msg.Amount were already validated @@ -290,10 +255,26 @@ func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result } ``` -The handler is straight forward. We first load the KVStore from the context using the granted capability key. -Then we make two state transitions: one for the sender, one for the receiver. -Each one involves JSON unmarshalling the account bytes from the store, mutating -the `Coins`, and JSON marshalling back into the store: +We have only a single message type, so just one message-specific function to define, `handleMsgSend`. + +Note this handler has unrestricted access to the store specified by the capability key `keyAcc`, +so it must define what to store and how to encode it. Later, we'll introduce +higher-level abstractions so Handlers are restricted in what they can do. +For this first example, we use a simple account that is JSON encoded: + +```go +type appAccount struct { + Coins sdk.Coins `json:"coins"` +} +``` + +Coins is a useful type provided by the SDK for multi-asset accounts. +We could just use an integer here for a single coin type, but +it's worth [getting to know +Coins](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Coins). + + +Now we're ready to handle the two parts of the MsgSend: ```go func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result { @@ -367,6 +348,11 @@ func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { } ``` +The handler is straight forward. We first load the KVStore from the context using the granted capability key. +Then we make two state transitions: one for the sender, one for the receiver. +Each one involves JSON unmarshalling the account bytes from the store, mutating +the `Coins`, and JSON marshalling back into the store. + And that's that! ## Tx diff --git a/docs/core/app2.md b/docs/core/app2.md index d245aea41a..f87ff557fc 100644 --- a/docs/core/app2.md +++ b/docs/core/app2.md @@ -74,24 +74,36 @@ func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handle func handleIssuer(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result { // the issuer address is stored directly under the coin denomination denom := []byte(coin.Denom) - issuerAddress := store.Get(denom) - if issuerAddress == nil { + infoBytes := store.Get(denom) + if infoBytes == nil { return sdk.ErrInvalidCoins(fmt.Sprintf("Unknown coin type %s", coin.Denom)).Result() } + var coinInfo coinInfo + err := json.Unmarshal(infoBytes, &coinInfo) + if err != nil { + return sdk.ErrInternal("Error when deserializing coinInfo").Result() + } + // Msg Issuer is not authorized to issue these coins - if !bytes.Equal(issuerAddress, issuer) { + if !bytes.Equal(coinInfo.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } return sdk.Result{} } + +// coinInfo stores meta data about a coin +type coinInfo struct { + Issuer sdk.Address `json:"issuer"` +} ``` -Note we're just storing the issuer address for each coin directly under the -coin's denomination in the issuer store. We could of course use a struct with more -fields, like the current supply of coins in existence, and the maximum supply -allowed to be issued. +Note we've introduced the `coinInfo` type to store the issuer address for each coin. +We JSON serialize this type and store it directly under the denomination in the +issuer store. We could of course add more fields and logic around this, +like including the current supply of coins in existence, and enforcing a maximum supply, +but that's left as an excercise for the reader :). ## Amino diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index 2c10299c56..ff9baa7bcd 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -117,7 +117,7 @@ func (msg MsgIssue) Tags() sdk.Tags { //------------------------------------------------------------------ // Handler for the message -// Handle MsgIssue +// Handle MsgIssue. func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { issueMsg, ok := msg.(MsgIssue) @@ -149,19 +149,30 @@ func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handle func handleIssuer(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result { // the issuer address is stored directly under the coin denomination denom := []byte(coin.Denom) - issuerAddress := store.Get(denom) - if issuerAddress == nil { + infoBytes := store.Get(denom) + if infoBytes == nil { return sdk.ErrInvalidCoins(fmt.Sprintf("Unknown coin type %s", coin.Denom)).Result() } + var coinInfo coinInfo + err := json.Unmarshal(infoBytes, &coinInfo) + if err != nil { + return sdk.ErrInternal("Error when deserializing coinInfo").Result() + } + // Msg Issuer is not authorized to issue these coins - if !bytes.Equal(issuerAddress, issuer) { + if !bytes.Equal(coinInfo.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } return sdk.Result{} } +// coinInfo stores meta data about a coin +type coinInfo struct { + Issuer sdk.Address `json:"issuer"` +} + //------------------------------------------------------------------ // Tx From d0efeb1020716ed53454e454bd3e4e8ee32c870e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 28 Jun 2018 20:16:47 -0400 Subject: [PATCH 42/77] fill in app3 todos. simplify app3.go --- docs/core/app3.md | 15 +++--- docs/core/examples/app3.go | 105 ++++++++++++------------------------- 2 files changed, 42 insertions(+), 78 deletions(-) diff --git a/docs/core/app3.md b/docs/core/app3.md index 141264ac25..3dd2fdcf26 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -21,7 +21,8 @@ their own modules. Here, we'll introduce the important types from `x/auth` and `x/bank`, and show how to make `App3` by using them. The complete code can be found in [app3.go](examples/app3.go). -For more details, see the [x/auth](TODO) and [x/bank](TODO) API documentation. +For more details, see the +[x/auth](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth) and [x/bank](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank) API documentation. ## Accounts @@ -102,8 +103,7 @@ the `BaseAccount` to store additional data without requiring another lookup from the store. Creating an AccountMapper is easy - we just need to specify a codec, a -capability key, and a prototype of the object being encoded (TODO: change to -constructor): +capability key, and a prototype of the object being encoded ```go accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) @@ -124,7 +124,8 @@ load the KVStore from there using the capability key it was granted on creation. Also note that you must explicitly call `SetAccount` after mutating an account for the change to persist! -See the [AccountMapper API docs](TODO) for more information. +See the [AccountMapper API +docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth#AccountMapper) for more information. ## StdTx @@ -200,7 +201,7 @@ transaction fee can be paid, and reject the transaction if not. The `StdTx` supports multiple messages and multiple signers. To sign the transaction, each signer must collect the following information: -- the ChainID (TODO haven't mentioned this yet) +- the ChainID - the AccountNumber and Sequence for the given signer's account (from the blockchain) - the transaction fee @@ -227,7 +228,6 @@ our own simple `AnteHandler`, the `x/auth` module provides a much more advanced one that uses `AccountMapper` and works with `StdTx`: ```go -TODO: feekeeper :( app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) ``` @@ -299,7 +299,8 @@ We can then use it within a handler, instead of working directly with the app.coinKeeper.AddCoins(ctx, addr, coins) ``` -See the [bank.Keeper API docs](TODO) for the full set of methods. +See the [bank.Keeper API +docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#Keeper) for the full set of methods. Note we can refine the `bank.Keeper` by restricting it's method set. For instance, the `bank.ViewKeeper` is a read-only version, while the diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index a9a4b9759d..7790d0a507 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -35,8 +35,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Set various mappers/keepers to interact easily with underlying stores // TODO: Need to register Account interface or use different Codec accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) - accountKeeper := bank.NewKeeper(accountMapper) - metadataMapper := NewApp3MetaDataMapper(keyMain) + coinKeeper := bank.NewKeeper(accountMapper) + infoMapper := NewCoinInfoMapper(keyMain) feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) @@ -44,8 +44,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("send", betterHandleMsgSend(accountKeeper)). - AddRoute("issue", betterHandleMsgIssue(metadataMapper, accountKeeper)) + AddRoute("send", handleMsgSendWithKeeper(coinKeeper)). + AddRoute("issue", handleMsgIssueWithInfoMapper(infoMapper, coinKeeper)) // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount, keyMain, keyFees) @@ -56,7 +56,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { return app } -func betterHandleMsgSend(accountKeeper bank.Keeper) sdk.Handler { +func handleMsgSendWithKeeper(coinKeeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { sendMsg, ok := msg.(MsgSend) if !ok { @@ -64,14 +64,14 @@ func betterHandleMsgSend(accountKeeper bank.Keeper) sdk.Handler { } // Subtract coins from sender account - _, _, err := accountKeeper.SubtractCoins(ctx, sendMsg.From, sendMsg.Amount) + _, _, err := coinKeeper.SubtractCoins(ctx, sendMsg.From, sendMsg.Amount) if err != nil { // if error, return its result return err.Result() } // Add coins to receiver account - _, _, err = accountKeeper.AddCoins(ctx, sendMsg.To, sendMsg.Amount) + _, _, err = coinKeeper.AddCoins(ctx, sendMsg.To, sendMsg.Amount) if err != nil { // if error, return its result return err.Result() @@ -83,7 +83,7 @@ func betterHandleMsgSend(accountKeeper bank.Keeper) sdk.Handler { } } -func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keeper) sdk.Handler { +func handleMsgIssueWithInfoMapper(infoMapper coinInfoMapper, coinKeeper bank.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { issueMsg, ok := msg.(MsgIssue) if !ok { @@ -91,107 +91,70 @@ func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keep } // Handle updating metadata - if res := betterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { + if res := handleCoinInfoWithMapper(ctx, infoMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { return res } // Add newly issued coins to output address - _, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}) + _, _, err := coinKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}) if err != nil { return err.Result() } return sdk.Result{ - // Return result with Issue msg tags Tags: issueMsg.Tags(), } } } -func betterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result { - metadata := metadataMapper.GetMetaData(ctx, coin.Denom) +func handleCoinInfoWithMapper(ctx sdk.Context, infoMapper CoinInfoMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result { + coinInfo := infoMapper.GetInfo(ctx, coin.Denom) // Metadata was created fresh, should set issuer to msg issuer - if len(metadata.Issuer) == 0 { - metadata.Issuer = issuer + if len(coinInfo.Issuer) == 0 { + coinInfo.Issuer = issuer } // Msg Issuer is not authorized to issue these coins - if !bytes.Equal(metadata.Issuer, issuer) { + if !bytes.Equal(coinInfo.Issuer, issuer) { return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() } - // Update current circulating supply - metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) - - // Current supply cannot exceed total supply - if metadata.TotalSupply.LT(metadata.CurrentSupply) { - return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result() - } - - metadataMapper.SetMetaData(ctx, coin.Denom, metadata) return sdk.Result{} } //------------------------------------------------------------------ -// Mapper for Coin Metadata +// Mapper for CoinInfo -// Example of a very simple user-defined mapper interface -type MetaDataMapper interface { - GetMetaData(sdk.Context, string) CoinMetadata - SetMetaData(sdk.Context, string, CoinMetadata) +// Example of a very simple user-defined read-only mapper interface. +type CoinInfoMapper interface { + GetInfo(sdk.Context, string) coinInfo } -// Implements MetaDataMapper -type App3MetaDataMapper struct { - mainKey *sdk.KVStoreKey +// Implements CoinInfoMapper. +type coinInfoMapper struct { + key *sdk.KVStoreKey } -// Construct new App3MetaDataMapper -func NewApp3MetaDataMapper(key *sdk.KVStoreKey) App3MetaDataMapper { - return App3MetaDataMapper{mainKey: key} +// Construct new CoinInfoMapper. +func NewCoinInfoMapper(key *sdk.KVStoreKey) coinInfoMapper { + return coinInfoMapper{key: key} } -// Implements MetaDataMpper. Returns metadata for coin -// If metadata does not exist in store, function creates default metadata and returns it -// without adding it to the store. -func (mdm App3MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata { - store := ctx.KVStore(mdm.mainKey) +// Implements CoinInfoMapper. Returns info for coin. +func (cim coinInfoMapper) GetInfo(ctx sdk.Context, denom string) coinInfo { + store := ctx.KVStore(cim.key) - bz := store.Get([]byte(denom)) - if bz == nil { - // Coin metadata doesn't exist, create new metadata with default params - return CoinMetadata{ - TotalSupply: sdk.NewInt(1000000), - } + infoBytes := store.Get([]byte(denom)) + if infoBytes == nil { + // TODO } - var metadata CoinMetadata - err := json.Unmarshal(bz, &metadata) + var coinInfo coinInfo + err := json.Unmarshal(infoBytes, &coinInfo) if err != nil { panic(err) } - return metadata + return coinInfo } - -// Implements MetaDataMapper. Sets metadata in store with key equal to denom. -func (mdm App3MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) { - store := ctx.KVStore(mdm.mainKey) - - val, err := json.Marshal(metadata) - if err != nil { - panic(err) - } - - store.Set([]byte(denom), val) -} - -//------------------------------------------------------------------ -// StdTx - -//------------------------------------------------------------------ -// Account - -//------------------------------------------------------------------ -// Ante Handler From d1a42e06911799157883d032c6f968c748f0bc31 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 28 Jun 2018 20:23:09 -0400 Subject: [PATCH 43/77] satisfy linter --- docs/core/examples/app3.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index 7790d0a507..d916d235e5 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -36,7 +36,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { // TODO: Need to register Account interface or use different Codec accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) coinKeeper := bank.NewKeeper(accountMapper) - infoMapper := NewCoinInfoMapper(keyMain) + infoMapper := newCoinInfoMapper(keyMain) feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) @@ -137,7 +137,7 @@ type coinInfoMapper struct { } // Construct new CoinInfoMapper. -func NewCoinInfoMapper(key *sdk.KVStoreKey) coinInfoMapper { +func newCoinInfoMapper(key *sdk.KVStoreKey) coinInfoMapper { return coinInfoMapper{key: key} } From 59aadf42aaeb4e8bfe9b39ac4ea43caf07d2f30a Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 29 Jun 2018 02:54:47 +0200 Subject: [PATCH 44/77] Ledger integration (#931) Merges the keybase and Ledger code from go-crypto (which is no more) into the SDK Adds support for Ledger into gaiacli Cherry-picks updated error handling from #1158 --- CHANGELOG.md | 4 + Gopkg.lock | 132 ++++-- Gopkg.toml | 36 +- baseapp/baseapp.go | 5 +- baseapp/baseapp_test.go | 19 +- baseapp/helpers.go | 4 +- client/context/helpers.go | 20 +- client/context/types.go | 7 + client/context/viper.go | 1 + client/flags.go | 3 + client/keys.go | 4 +- client/keys/add.go | 82 ++-- client/keys/delete.go | 2 +- client/keys/show.go | 4 +- client/keys/update.go | 2 +- client/keys/utils.go | 16 +- client/lcd/lcd_test.go | 90 ++--- client/lcd/root.go | 5 +- client/lcd/test_helpers.go | 13 +- client/rpc/status.go | 2 +- client/tx/query.go | 5 +- client/tx/sign.go | 2 +- cmd/gaia/app/app.go | 2 +- cmd/gaia/app/app_test.go | 2 +- cmd/gaia/app/genesis.go | 2 +- cmd/gaia/app/genesis_test.go | 2 +- cmd/gaia/cli_test/cli_test.go | 2 +- cmd/gaia/cmd/gaiad/main.go | 2 +- cmd/gaia/cmd/gaiadebug/hack.go | 4 +- cmd/gaia/cmd/gaiadebug/main.go | 2 +- crypto/amino.go | 19 + crypto/encode_test.go | 122 ++++++ crypto/keys/bcrypt/base64.go | 35 ++ crypto/keys/bcrypt/bcrypt.go | 297 ++++++++++++++ crypto/keys/bip39/wordcodec.go | 60 +++ crypto/keys/bip39/wordcodec_test.go | 15 + crypto/keys/hd/fundraiser_test.go | 80 ++++ crypto/keys/hd/hdpath.go | 168 ++++++++ crypto/keys/hd/hdpath_test.go | 75 ++++ crypto/keys/hd/test.json | 1 + crypto/keys/keybase.go | 364 +++++++++++++++++ crypto/keys/keybase_test.go | 382 ++++++++++++++++++ crypto/keys/keys.go | 12 + crypto/keys/keys.toml | 2 + crypto/keys/mintkey.go | 115 ++++++ crypto/keys/types.go | 144 +++++++ crypto/keys/wire.go | 19 + crypto/ledger_common.go | 19 + crypto/ledger_secp256k1.go | 126 ++++++ crypto/ledger_test.go | 65 +++ examples/basecoin/app/app.go | 2 +- examples/basecoin/app/app_test.go | 7 +- examples/basecoin/cmd/basecoind/main.go | 2 +- examples/democoin/app/app.go | 2 +- examples/democoin/app/app_test.go | 46 ++- examples/democoin/cmd/democoind/main.go | 2 +- examples/democoin/mock/validator.go | 2 +- .../democoin/x/assoc/validator_set_test.go | 2 +- examples/democoin/x/cool/app_test.go | 9 +- examples/democoin/x/cool/keeper_test.go | 2 +- examples/democoin/x/cool/types.go | 8 +- examples/democoin/x/oracle/oracle_test.go | 6 +- examples/democoin/x/pow/app_test.go | 4 +- examples/democoin/x/pow/handler_test.go | 2 +- examples/democoin/x/pow/keeper_test.go | 2 +- examples/democoin/x/pow/mine.go | 2 +- examples/democoin/x/pow/types.go | 2 +- .../x/simplestake/client/cli/commands.go | 2 +- examples/democoin/x/simplestake/keeper.go | 2 +- .../democoin/x/simplestake/keeper_test.go | 4 +- examples/democoin/x/simplestake/msgs.go | 2 +- examples/democoin/x/simplestake/msgs_test.go | 2 +- examples/democoin/x/simplestake/types.go | 2 +- examples/kvstore/kvstore | Bin 20701460 -> 20725748 bytes examples/kvstore/main.go | 2 +- server/constructors.go | 2 +- server/init.go | 23 +- server/mock/app.go | 4 +- server/mock/app_test.go | 2 +- server/mock/helpers.go | 2 +- server/start.go | 3 +- server/start_test.go | 2 +- store/iavlstore.go | 11 +- store/iavlstore_test.go | 2 +- store/rootmultistore.go | 2 +- store/rootmultistore_test.go | 2 +- types/abci.go | 2 +- types/account.go | 2 +- types/context.go | 2 +- types/context_test.go | 2 +- types/errors.go | 91 +++-- types/int.go | 19 +- types/lib/linear_test.go | 2 +- types/stake.go | 4 +- types/store.go | 2 +- wire/wire.go | 4 +- x/auth/account.go | 2 +- x/auth/account_test.go | 2 +- x/auth/ante_test.go | 24 +- x/auth/context_test.go | 2 +- x/auth/feekeeper_test.go | 2 +- x/auth/mapper.go | 2 +- x/auth/mapper_test.go | 2 +- x/auth/mock/app.go | 4 +- x/auth/mock/auth_app_test.go | 4 +- x/auth/mock/simulate_block.go | 10 +- x/auth/stdtx.go | 28 +- x/auth/stdtx_test.go | 2 +- x/bank/app_test.go | 4 +- x/bank/bench_test.go | 2 +- x/bank/client/rest/sendtx.go | 7 +- x/bank/keeper_test.go | 2 +- x/bank/msgs.go | 14 +- x/bank/msgs_test.go | 4 +- x/gov/client/rest/rest.go | 8 +- x/gov/client/rest/util.go | 7 +- x/gov/endblocker_test.go | 2 +- x/gov/keeper_test.go | 2 +- x/gov/tally_test.go | 4 +- x/gov/test_common.go | 4 +- x/ibc/app_test.go | 4 +- x/ibc/client/rest/transfer.go | 4 +- x/ibc/ibc_test.go | 4 +- x/ibc/types.go | 2 +- x/slashing/app_test.go | 4 +- x/slashing/keeper.go | 2 +- x/slashing/keeper_test.go | 2 +- x/slashing/test_common.go | 4 +- x/slashing/tick.go | 2 +- x/slashing/tick_test.go | 2 +- x/stake/app_test.go | 4 +- x/stake/client/rest/rest.go | 2 +- x/stake/client/rest/tx.go | 17 +- x/stake/handler.go | 3 +- x/stake/handler_test.go | 2 +- x/stake/keeper/key.go | 2 +- x/stake/keeper/slash.go | 2 +- x/stake/keeper/test_common.go | 4 +- x/stake/keeper/validator.go | 4 +- x/stake/types/msg.go | 2 +- x/stake/types/msg_test.go | 2 +- x/stake/types/test_common.go | 2 +- x/stake/types/validator.go | 4 +- 143 files changed, 2699 insertions(+), 424 deletions(-) create mode 100644 crypto/amino.go create mode 100644 crypto/encode_test.go create mode 100644 crypto/keys/bcrypt/base64.go create mode 100644 crypto/keys/bcrypt/bcrypt.go create mode 100644 crypto/keys/bip39/wordcodec.go create mode 100644 crypto/keys/bip39/wordcodec_test.go create mode 100644 crypto/keys/hd/fundraiser_test.go create mode 100644 crypto/keys/hd/hdpath.go create mode 100644 crypto/keys/hd/hdpath_test.go create mode 100644 crypto/keys/hd/test.json create mode 100644 crypto/keys/keybase.go create mode 100644 crypto/keys/keybase_test.go create mode 100644 crypto/keys/keys.go create mode 100644 crypto/keys/keys.toml create mode 100644 crypto/keys/mintkey.go create mode 100644 crypto/keys/types.go create mode 100644 crypto/keys/wire.go create mode 100644 crypto/ledger_common.go create mode 100644 crypto/ledger_secp256k1.go create mode 100644 crypto/ledger_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 5beaf64c88..1ff5efbfb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ BREAKING CHANGES * Removed MsgChangePubKey from auth * Removed setPubKey from account mapper * Removed GetMemo from Tx (it is still on StdTx) +* Keybase and Ledger support from go-crypto merged into the SDK in the `crypto` folder * Gov module REST endpoints changed to be more RESTful * [cli] rearranged commands under subcommands * [stake] remove Tick and add EndBlocker @@ -46,6 +47,9 @@ FEATURES * [types] Switches internal representation of Int/Uint/Rat to use pointers * [gaiad] unsafe_reset_all now resets addrbook.json * [democoin] add x/oracle, x/assoc +* [gaiacli] Ledger support added + - You can now use a Ledger with `gaiacli --ledger` for all key-related commands + - Ledger keys can be named and tracked locally in the key DB * [gaiacli] added an --async flag to the cli to deliver transactions without waiting for a tendermint response FIXES diff --git a/Gopkg.lock b/Gopkg.lock index f3d8f3acc3..a974602f74 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,12 +1,30 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + branch = "master" + name = "github.com/bartekn/go-bip39" + packages = ["."] + revision = "a05967ea095d81c8fe4833776774cfaff8e5036c" + +[[projects]] + branch = "master" + name = "github.com/beorn7/perks" + packages = ["quantile"] + revision = "3a771d992973f24aa725d07868b467d1ddfceafb" + [[projects]] name = "github.com/bgentry/speakeasy" packages = ["."] revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd" version = "v0.1.0" +[[projects]] + branch = "master" + name = "github.com/brejski/hid" + packages = ["."] + revision = "06112dcfcc50a7e0e4fd06e17f9791e788fdaafc" + [[projects]] branch = "master" name = "github.com/btcsuite/btcd" @@ -42,7 +60,11 @@ packages = [ "log", "log/level", - "log/term" + "log/term", + "metrics", + "metrics/discard", + "metrics/internal/lv", + "metrics/prometheus" ] revision = "4dc7be5d2d12881735283bcab7352178e190fc71" version = "v0.6.0" @@ -125,12 +147,6 @@ ] revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" -[[projects]] - branch = "master" - name = "github.com/howeyc/crc16" - packages = ["."] - revision = "2b2a61e366a66d3efb279e46176e7291001e0354" - [[projects]] name = "github.com/inconshreveable/mousetrap" packages = ["."] @@ -161,6 +177,12 @@ revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" version = "v0.0.3" +[[projects]] + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" + version = "v1.0.1" + [[projects]] branch = "master" name = "github.com/mitchellh/mapstructure" @@ -185,6 +207,42 @@ revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" +[[projects]] + name = "github.com/prometheus/client_golang" + packages = [ + "prometheus", + "prometheus/promhttp" + ] + revision = "c5b7fccd204277076155f10851dad72b76a49317" + version = "v0.8.0" + +[[projects]] + branch = "master" + name = "github.com/prometheus/client_model" + packages = ["go"] + revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" + +[[projects]] + branch = "master" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model" + ] + revision = "7600349dcfe1abd18d72d3a1770870d9800a7801" + +[[projects]] + branch = "master" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfs", + "xfs" + ] + revision = "7d6f385de8bea29190f15ba9931442a0eaef9af7" + [[projects]] branch = "master" name = "github.com/rcrowley/go-metrics" @@ -236,8 +294,8 @@ "assert", "require" ] - revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" - version = "v1.2.2" + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" [[projects]] branch = "master" @@ -258,18 +316,6 @@ ] revision = "0d5a0ceb10cf9ab89fdd744cc8c50a83134f6697" -[[projects]] - name = "github.com/tendermint/abci" - packages = [ - "client", - "example/code", - "example/kvstore", - "server", - "types" - ] - revision = "198dccf0ddfd1bb176f87657e3286a05a6ed9540" - version = "v0.12.0" - [[projects]] branch = "master" name = "github.com/tendermint/ed25519" @@ -283,20 +329,8 @@ [[projects]] name = "github.com/tendermint/go-amino" packages = ["."] - revision = "ed62928576cfcaf887209dc96142cd79cdfff389" - version = "0.9.9" - -[[projects]] - name = "github.com/tendermint/go-crypto" - packages = [ - ".", - "keys", - "keys/bcrypt", - "keys/words", - "keys/words/wordlist" - ] - revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19" - version = "v0.6.2" + revision = "2106ca61d91029c931fd54968c2bb02dc96b1412" + version = "0.10.1" [[projects]] name = "github.com/tendermint/iavl" @@ -304,17 +338,23 @@ ".", "sha256truncated" ] - revision = "c9206995e8f948e99927f5084a88a7e94ca256da" - version = "v0.8.0-rc0" + revision = "481b89cbbe6a641f7f6cb5db92b30b20f5a2e001" [[projects]] name = "github.com/tendermint/tendermint" packages = [ + "abci/client", + "abci/example/code", + "abci/example/kvstore", + "abci/server", + "abci/types", "blockchain", "cmd/tendermint/commands", "config", "consensus", "consensus/types", + "crypto", + "crypto/tmhash", "evidence", "libs/events", "libs/pubsub", @@ -347,7 +387,7 @@ "types", "version" ] - revision = "696e8c6f9e950eec15f150f314d2dd9ddf6bc601" + revision = "8412b75b1070ac023405e8228e017ed36531fe1b" [[projects]] name = "github.com/tendermint/tmlibs" @@ -364,7 +404,13 @@ "merkle", "merkle/tmhash" ] - revision = "0c98d10b4ffbd87978d79c160e835b3d3df241ec" + revision = "49596e0a1f48866603813df843c9409fc19805c6" + version = "v0.9.0" + +[[projects]] + name = "github.com/zondax/ledger-goclient" + packages = ["."] + revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a" [[projects]] branch = "master" @@ -377,6 +423,7 @@ "nacl/secretbox", "openpgp/armor", "openpgp/errors", + "pbkdf2", "poly1305", "ripemd160", "salsa20/salsa" @@ -393,15 +440,16 @@ "http2/hpack", "idna", "internal/timeseries", + "netutil", "trace" ] - revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9" + revision = "e514e69ffb8bc3c76a71ae40de0118d794855992" [[projects]] branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "a200a19cb90b19de298170992778b1fda7217bd6" + revision = "7138fd3d9dc8335c567ca206f4333fb75eb05d56" [[projects]] name = "golang.org/x/text" @@ -462,6 +510,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "8ad5e4b90e57805024944a6ee5eed246f109c18724d453093e82bac1469dbd9e" + inputs-digest = "578ae0e0126ffd04006b6755a02bc25c95e2eb2ecb4ea99869c4ada133f29f6b" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index a8b510e6a8..85b15a019c 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -36,10 +36,6 @@ name = "github.com/mattn/go-isatty" version = "~0.0.3" -[[constraint]] - name = "github.com/pkg/errors" - version = "~0.8.0" - [[constraint]] name = "github.com/spf13/cobra" version = "~0.0.1" @@ -48,33 +44,37 @@ name = "github.com/spf13/viper" version = "~1.0.0" +[[constraint]] + name = "github.com/pkg/errors" + version = "=0.8.0" + [[constraint]] name = "github.com/stretchr/testify" - version = "~1.2.1" - -[[constraint]] - name = "github.com/tendermint/abci" - version = "=0.12.0" - -[[constraint]] - name = "github.com/tendermint/go-crypto" - version = "=0.6.2" + version = "=1.2.1" [[constraint]] name = "github.com/tendermint/go-amino" - version = "=0.9.9" + version = "=0.10.1" [[constraint]] name = "github.com/tendermint/iavl" - version = "=0.8.0-rc0" + revision = "481b89cbbe6a641f7f6cb5db92b30b20f5a2e001" [[constraint]] name = "github.com/tendermint/tendermint" - revision = "696e8c6f9e950eec15f150f314d2dd9ddf6bc601" + revision = "8412b75b1070ac023405e8228e017ed36531fe1b" -[[override]] +[[constraint]] name = "github.com/tendermint/tmlibs" - revision = "0c98d10b4ffbd87978d79c160e835b3d3df241ec" + version = "=0.9.0" + +[[constraint]] + name = "github.com/bartekn/go-bip39" + branch = "master" + +[[constraint]] + name = "github.com/zondax/ledger-goclient" + revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a" # this got updated and broke, so locked to an old working commit ... [[override]] diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 331b30b655..1b4e701196 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -7,7 +7,7 @@ import ( "github.com/pkg/errors" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -85,7 +85,6 @@ func NewBaseApp(name string, cdc *wire.Codec, logger log.Logger, db dbm.DB) *Bas txDecoder: defaultTxDecoder(cdc), } // Register the undefined & root codespaces, which should not be used by any modules - app.codespacer.RegisterOrPanic(sdk.CodespaceUndefined) app.codespacer.RegisterOrPanic(sdk.CodespaceRoot) return app } @@ -135,7 +134,7 @@ func defaultTxDecoder(cdc *wire.Codec) sdk.TxDecoder { // are registered by MakeTxCodec err := cdc.UnmarshalBinary(txBytes, &tx) if err != nil { - return nil, sdk.ErrTxDecode("").Trace(err.Error()) + return nil, sdk.ErrTxDecode("").TraceSDK(err.Error()) } return tx, nil } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index c208ec3b8f..9d567c6bff 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -9,8 +9,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -397,7 +397,7 @@ func TestSimulateTx(t *testing.T) { require.Equal(t, result.Code, sdk.ABCICodeOK, result.Log) require.Equal(t, int64(80), result.GasUsed) counter-- - encoded, err := json.Marshal(tx) + encoded, err := app.cdc.MarshalJSON(tx) require.Nil(t, err) query := abci.RequestQuery{ Path: "/app/simulate", @@ -735,9 +735,14 @@ func GenTx(chainID string, msgs []sdk.Msg, accnums []int64, seq []int64, priv .. sigs := make([]auth.StdSignature, len(priv)) for i, p := range priv { + sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, "")) + // TODO: replace with proper error handling: + if err != nil { + panic(err) + } sigs[i] = auth.StdSignature{ PubKey: p.PubKey(), - Signature: p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, "")), + Signature: sig, AccountNumber: accnums[i], Sequence: seq[i], } @@ -994,17 +999,15 @@ func copyVal(val abci.Validator) abci.Validator { } func toJSON(o interface{}) []byte { - bz, err := json.Marshal(o) + bz, err := wire.Cdc.MarshalJSON(o) if err != nil { panic(err) } - // fmt.Println(">> toJSON:", string(bz)) return bz } func fromJSON(bz []byte, ptr interface{}) { - // fmt.Println(">> fromJSON:", string(bz)) - err := json.Unmarshal(bz, ptr) + err := wire.Cdc.UnmarshalJSON(bz, ptr) if err != nil { panic(err) } diff --git a/baseapp/helpers.go b/baseapp/helpers.go index e620774e9a..65c18315fd 100644 --- a/baseapp/helpers.go +++ b/baseapp/helpers.go @@ -1,8 +1,8 @@ package baseapp import ( - "github.com/tendermint/abci/server" - abci "github.com/tendermint/abci/types" + "github.com/tendermint/tendermint/abci/server" + abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" ) diff --git a/client/context/helpers.go b/client/context/helpers.go index dfe75e4870..8dd813f824 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -126,7 +126,7 @@ func (ctx CoreContext) GetFromAddress() (from sdk.Address, err error) { return nil, errors.Errorf("no key for: %s", name) } - return info.PubKey.Address(), nil + return info.GetPubKey().Address(), nil } // sign and build the transaction from the msg @@ -187,15 +187,29 @@ func (ctx CoreContext) ensureSignBuild(name string, msgs []sdk.Msg, cdc *wire.Co return nil, err } - passphrase, err := ctx.GetPassphraseFromStdin(name) + var txBytes []byte + + keybase, err := keys.GetKeyBase() if err != nil { return nil, err } - txBytes, err := ctx.SignAndBuild(name, passphrase, msgs, cdc) + info, err := keybase.Get(name) if err != nil { return nil, err } + var passphrase string + // Only need a passphrase for locally-stored keys + if info.GetType() == "local" { + passphrase, err = ctx.GetPassphraseFromStdin(name) + if err != nil { + return nil, fmt.Errorf("Error fetching passphrase: %v", err) + } + } + txBytes, err = ctx.SignAndBuild(name, passphrase, msgs, cdc) + if err != nil { + return nil, fmt.Errorf("Error signing transaction: %v", err) + } return txBytes, err } diff --git a/client/context/types.go b/client/context/types.go index 6b0c074f2c..3b7573dceb 100644 --- a/client/context/types.go +++ b/client/context/types.go @@ -20,6 +20,7 @@ type CoreContext struct { Client rpcclient.Client Decoder auth.AccountDecoder AccountStore string + UseLedger bool } // WithChainID - return a copy of the context with an updated chainID @@ -94,3 +95,9 @@ func (c CoreContext) WithAccountStore(accountStore string) CoreContext { c.AccountStore = accountStore return c } + +// WithUseLedger - return a copy of the context with an updated UseLedger +func (c CoreContext) WithUseLedger(useLedger bool) CoreContext { + c.UseLedger = useLedger + return c +} diff --git a/client/context/viper.go b/client/context/viper.go index a0c991bbfd..3637e06abc 100644 --- a/client/context/viper.go +++ b/client/context/viper.go @@ -40,6 +40,7 @@ func NewCoreContextFromViper() CoreContext { Client: rpc, Decoder: nil, AccountStore: "acc", + UseLedger: viper.GetBool(client.FlagUseLedger), } } diff --git a/client/flags.go b/client/flags.go index eb390e8a04..31e9c087bf 100644 --- a/client/flags.go +++ b/client/flags.go @@ -4,6 +4,7 @@ import "github.com/spf13/cobra" // nolint const ( + FlagUseLedger = "ledger" FlagChainID = "chain-id" FlagNode = "node" FlagHeight = "height" @@ -25,6 +26,7 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { for _, c := range cmds { // TODO: make this default false when we support proofs c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for responses") + c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device") c.Flags().String(FlagChainID, "", "Chain ID of tendermint node") c.Flags().String(FlagNode, "tcp://localhost:26657", ": to tendermint rpc interface for this chain") c.Flags().Int64(FlagHeight, 0, "block height to query, omit to get most recent provable block") @@ -42,6 +44,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().String(FlagFee, "", "Fee to pay along with transaction") c.Flags().String(FlagChainID, "", "Chain ID of tendermint node") c.Flags().String(FlagNode, "tcp://localhost:26657", ": to tendermint rpc interface for this chain") + c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device") c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction") } return cmds diff --git a/client/keys.go b/client/keys.go index 47eb0b9c95..8c11561c5f 100644 --- a/client/keys.go +++ b/client/keys.go @@ -1,8 +1,7 @@ package client import ( - "github.com/tendermint/go-crypto/keys" - "github.com/tendermint/go-crypto/keys/words" + "github.com/cosmos/cosmos-sdk/crypto/keys" dbm "github.com/tendermint/tmlibs/db" ) @@ -11,7 +10,6 @@ import ( func GetKeyBase(db dbm.DB) keys.Keybase { keybase := keys.New( db, - words.MustLoadCodec("english"), ) return keybase } diff --git a/client/keys/add.go b/client/keys/add.go index 5210a388a6..f0055366ac 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -12,7 +12,9 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/go-crypto/keys" + ccrypto "github.com/cosmos/cosmos-sdk/crypto" + "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/tendermint/tmlibs/cli" ) @@ -21,6 +23,8 @@ const ( flagRecover = "recover" flagNoBackup = "no-backup" flagDryRun = "dry-run" + flagAccount = "account" + flagIndex = "index" ) func addKeyCommand() *cobra.Command { @@ -32,10 +36,13 @@ If you select --seed/-s you can recover a key from the seed phrase, otherwise, a new key will be generated.`, RunE: runAddCmd, } - cmd.Flags().StringP(flagType, "t", "ed25519", "Type of private key (ed25519|secp256k1|ledger)") + cmd.Flags().StringP(flagType, "t", "secp256k1", "Type of private key (secp256k1|ed25519)") + cmd.Flags().Bool(client.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device") cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating") cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore") + cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation") + cmd.Flags().Uint32(flagIndex, 0, "Index number for HD derivation") return cmd } @@ -70,21 +77,34 @@ func runAddCmd(cmd *cobra.Command, args []string) error { } } - pass, err = client.GetCheckPassword( - "Enter a passphrase for your key:", - "Repeat the passphrase:", buf) - if err != nil { - return err + // ask for a password when generating a local key + if !viper.GetBool(client.FlagUseLedger) { + pass, err = client.GetCheckPassword( + "Enter a passphrase for your key:", + "Repeat the passphrase:", buf) + if err != nil { + return err + } } } - if viper.GetBool(flagRecover) { + if viper.GetBool(client.FlagUseLedger) { + account := uint32(viper.GetInt(flagAccount)) + index := uint32(viper.GetInt(flagIndex)) + path := ccrypto.DerivationPath{44, 118, account, 0, index} + algo := keys.SigningAlgo(viper.GetString(flagType)) + info, err := kb.CreateLedger(name, path, algo) + if err != nil { + return err + } + printCreate(info, "") + } else if viper.GetBool(flagRecover) { seed, err := client.GetSeed( "Enter your recovery seed phrase:", buf) if err != nil { return err } - info, err := kb.Recover(name, pass, seed) + info, err := kb.CreateFundraiserKey(name, seed, pass) if err != nil { return err } @@ -92,8 +112,8 @@ func runAddCmd(cmd *cobra.Command, args []string) error { viper.Set(flagNoBackup, true) printCreate(info, "") } else { - algo := keys.CryptoAlgo(viper.GetString(flagType)) - info, seed, err := kb.Create(name, pass, algo) + algo := keys.SigningAlgo(viper.GetString(flagType)) + info, seed, err := kb.CreateMnemonic(name, keys.English, pass, algo) if err != nil { return err } @@ -108,7 +128,7 @@ func printCreate(info keys.Info, seed string) { case "text": printInfo(info) // print seed unless requested not to. - if !viper.GetBool(flagNoBackup) { + if !viper.GetBool(client.FlagUseLedger) && !viper.GetBool(flagNoBackup) { fmt.Println("**Important** write this seed phrase in a safe place.") fmt.Println("It is the only way to recover your account if you ever forget your password.") fmt.Println() @@ -139,7 +159,12 @@ func printCreate(info keys.Info, seed string) { type NewKeyBody struct { Name string `json:"name"` Password string `json:"password"` - Seed string `json:"seed"` +} + +// new key response REST body +type NewKeyResponse struct { + Address string `json:"address"` + Mnemonic string `json:"mnemonic"` } // add new key REST handler @@ -172,16 +197,11 @@ func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("You have to specify a password for the locally stored account.")) return } - if m.Seed == "" { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("You have to specify a seed for the locally stored account.")) - return - } // check if already exists infos, err := kb.List() for _, i := range infos { - if i.Name == m.Name { + if i.GetName() == m.Name { w.WriteHeader(http.StatusConflict) w.Write([]byte(fmt.Sprintf("Account with name %s already exists.", m.Name))) return @@ -189,22 +209,30 @@ func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) { } // create account - info, err := kb.Recover(m.Name, m.Password, m.Seed) + info, mnemonic, err := kb.CreateMnemonic(m.Name, keys.English, m.Password, keys.Secp256k1) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } - w.Write([]byte(info.PubKey.Address().String())) + bz, err := json.Marshal(NewKeyResponse{ + Address: info.GetPubKey().Address().String(), + Mnemonic: mnemonic, + }) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + w.Write(bz) } // function to just a new seed to display in the UI before actually persisting it in the keybase -func getSeed(algo keys.CryptoAlgo) string { +func getSeed(algo keys.SigningAlgo) string { kb := client.MockKeyBase() pass := "throwing-this-key-away" name := "inmemorykey" - - _, seed, _ := kb.Create(name, pass, algo) + _, seed, _ := kb.CreateMnemonic(name, keys.English, pass, algo) return seed } @@ -212,11 +240,11 @@ func getSeed(algo keys.CryptoAlgo) string { func SeedRequestHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) algoType := vars["type"] - // algo type defaults to ed25519 + // algo type defaults to secp256k1 if algoType == "" { - algoType = "ed25519" + algoType = "secp256k1" } - algo := keys.CryptoAlgo(algoType) + algo := keys.SigningAlgo(algoType) seed := getSeed(algo) w.Write([]byte(seed)) diff --git a/client/keys/delete.go b/client/keys/delete.go index e9f3c1abe7..f38c529a6f 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -6,8 +6,8 @@ import ( "net/http" "github.com/cosmos/cosmos-sdk/client" + keys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/gorilla/mux" - keys "github.com/tendermint/go-crypto/keys" "github.com/spf13/cobra" ) diff --git a/client/keys/show.go b/client/keys/show.go index 9051aba160..873c45a4b6 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -4,8 +4,8 @@ import ( "encoding/json" "net/http" + keys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/gorilla/mux" - keys "github.com/tendermint/go-crypto/keys" "github.com/spf13/cobra" ) @@ -28,7 +28,7 @@ var showKeysCmd = &cobra.Command{ func getKey(name string) (keys.Info, error) { kb, err := GetKeyBase() if err != nil { - return keys.Info{}, err + return nil, err } return kb.Get(name) diff --git a/client/keys/update.go b/client/keys/update.go index f3db82c3f4..0308b89bdb 100644 --- a/client/keys/update.go +++ b/client/keys/update.go @@ -6,8 +6,8 @@ import ( "net/http" "github.com/cosmos/cosmos-sdk/client" + keys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/gorilla/mux" - keys "github.com/tendermint/go-crypto/keys" "github.com/spf13/cobra" ) diff --git a/client/keys/utils.go b/client/keys/utils.go index 8b6cfcb351..c0d7f876fa 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -6,7 +6,7 @@ import ( "github.com/spf13/viper" - keys "github.com/tendermint/go-crypto/keys" + keys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" @@ -49,6 +49,7 @@ func SetKeyBase(kb keys.Keybase) { // used for outputting keys.Info over REST type KeyOutput struct { Name string `json:"name"` + Type string `json:"type"` Address string `json:"address"` PubKey string `json:"pub_key"` Seed string `json:"seed,omitempty"` @@ -69,16 +70,17 @@ func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) { // create a KeyOutput in bech32 format func Bech32KeyOutput(info keys.Info) (KeyOutput, error) { - bechAccount, err := sdk.Bech32ifyAcc(sdk.Address(info.PubKey.Address().Bytes())) + bechAccount, err := sdk.Bech32ifyAcc(sdk.Address(info.GetPubKey().Address().Bytes())) if err != nil { return KeyOutput{}, err } - bechPubKey, err := sdk.Bech32ifyAccPub(info.PubKey) + bechPubKey, err := sdk.Bech32ifyAccPub(info.GetPubKey()) if err != nil { return KeyOutput{}, err } return KeyOutput{ - Name: info.Name, + Name: info.GetName(), + Type: info.GetType(), Address: bechAccount, PubKey: bechPubKey, }, nil @@ -91,7 +93,7 @@ func printInfo(info keys.Info) { } switch viper.Get(cli.OutputFlag) { case "text": - fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") + fmt.Printf("NAME:\tTYPE:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") printKeyOutput(ko) case "json": out, err := MarshalJSON(ko) @@ -109,7 +111,7 @@ func printInfos(infos []keys.Info) { } switch viper.Get(cli.OutputFlag) { case "text": - fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") + fmt.Printf("NAME:\tTYPE:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") for _, ko := range kos { printKeyOutput(ko) } @@ -123,5 +125,5 @@ func printInfos(infos []keys.Info) { } func printKeyOutput(ko KeyOutput) { - fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey) + fmt.Printf("%s\t%s\t%s\t%s\n", ko.Name, ko.Type, ko.Address, ko.PubKey) } diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 9776e9c453..feaadc922d 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -2,7 +2,6 @@ package lcd import ( "encoding/hex" - "encoding/json" "fmt" "net/http" "regexp" @@ -12,8 +11,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - cryptoKeys "github.com/tendermint/go-crypto/keys" + cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys" + abci "github.com/tendermint/tendermint/abci/types" p2p "github.com/tendermint/tendermint/p2p" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tmlibs/common" @@ -23,6 +22,7 @@ import ( rpc "github.com/cosmos/cosmos-sdk/client/rpc" tests "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/stake" @@ -36,9 +36,9 @@ func TestKeys(t *testing.T) { defer cleanup() // get seed + // TODO Do we really need this endpoint? res, body := Request(t, port, "GET", "/keys/seed", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - newSeed := body reg, err := regexp.Compile(`([a-z]+ ){12}`) require.Nil(t, err) match := reg.MatchString(seed) @@ -48,16 +48,14 @@ func TestKeys(t *testing.T) { newPassword := "0987654321" // add key - var jsonStr = []byte(fmt.Sprintf(`{"name":"test_fail", "password":"%s"}`, password)) - res, body = Request(t, port, "POST", "/keys", jsonStr) - - assert.Equal(t, http.StatusBadRequest, res.StatusCode, "Account creation should require a seed "+body) - - jsonStr = []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed": "%s"}`, newName, newPassword, newSeed)) + jsonStr := []byte(fmt.Sprintf(`{"name":"%s", "password":"%s"}`, newName, newPassword)) res, body = Request(t, port, "POST", "/keys", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) - addr2 := body + var resp keys.NewKeyResponse + err = wire.Cdc.UnmarshalJSON([]byte(body), &resp) + require.Nil(t, err) + addr2 := resp.Address assert.Len(t, addr2, 40, "Returned address has wrong format", addr2) // existing keys @@ -171,7 +169,7 @@ func TestBlock(t *testing.T) { res, body = Request(t, port, "GET", "/blocks/1", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - err = json.Unmarshal([]byte(body), &resultBlock) + err = wire.Cdc.UnmarshalJSON([]byte(body), &resultBlock) require.Nil(t, err, "Couldn't parse block") assert.NotEqual(t, ctypes.ResultBlock{}, resultBlock) @@ -604,9 +602,9 @@ func doSend(t *testing.T, port, seed, name, password string, addr sdk.Address) ( // create receive address kb := client.MockKeyBase() - receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519")) + receiveInfo, _, err := kb.CreateMnemonic("receive_address", cryptoKeys.English, "1234567890", cryptoKeys.SigningAlgo("secp256k1")) require.Nil(t, err) - receiveAddr = receiveInfo.PubKey.Address() + receiveAddr = receiveInfo.GetPubKey().Address() receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr) acc := getAccount(t, port, addr) @@ -615,7 +613,7 @@ func doSend(t *testing.T, port, seed, name, password string, addr sdk.Address) ( chainID := viper.GetString(client.FlagChainID) // send - coinbz, err := json.Marshal(sdk.NewCoin("steak", 1)) + coinbz, err := cdc.MarshalJSON(sdk.NewCoin("steak", 1)) if err != nil { panic(err) } @@ -623,9 +621,9 @@ func doSend(t *testing.T, port, seed, name, password string, addr sdk.Address) ( jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", - "account_number":%d, - "sequence":%d, - "gas": 10000, + "account_number":"%d", + "sequence":"%d", + "gas": "10000", "amount":[%s], "chain_id":"%s" }`, name, password, accnum, sequence, coinbz, chainID)) @@ -641,9 +639,9 @@ func doSend(t *testing.T, port, seed, name, password string, addr sdk.Address) ( func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) { // create receive address kb := client.MockKeyBase() - receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519")) + receiveInfo, _, err := kb.CreateMnemonic("receive_address", cryptoKeys.English, "1234567890", cryptoKeys.SigningAlgo("secp256k1")) require.Nil(t, err) - receiveAddr := receiveInfo.PubKey.Address() + receiveAddr := receiveInfo.GetPubKey().Address() receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr) chainID := viper.GetString(client.FlagChainID) @@ -657,14 +655,14 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Add jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password": "%s", - "account_number":%d, - "sequence": %d, - "gas": 100000, + "account_number":"%d", + "sequence": "%d", + "gas": "100000", "chain_id": "%s", "amount":[ { "denom": "%s", - "amount": 1 + "amount": "1" } ] }`, name, password, accnum, sequence, chainID, "steak")) @@ -706,15 +704,15 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, jsonStr := []byte(fmt.Sprintf(`{ "name": "%s", "password": "%s", - "account_number": %d, - "sequence": %d, - "gas": 10000, + "account_number": "%d", + "sequence": "%d", + "gas": "10000", "chain_id": "%s", "delegations": [ { "delegator_addr": "%s", "validator_addr": "%s", - "bond": { "denom": "%s", "amount": 60 } + "bond": { "denom": "%s", "amount": "60" } } ], "begin_unbondings": [], @@ -749,9 +747,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, jsonStr := []byte(fmt.Sprintf(`{ "name": "%s", "password": "%s", - "account_number": %d, - "sequence": %d, - "gas": 10000, + "account_number": "%d", + "sequence": "%d", + "gas": "10000", "chain_id": "%s", "delegations": [], "begin_unbondings": [ @@ -793,9 +791,9 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, jsonStr := []byte(fmt.Sprintf(`{ "name": "%s", "password": "%s", - "account_number": %d, - "sequence": %d, - "gas": 10000, + "account_number": "%d", + "sequence": "%d", + "gas": "10000", "chain_id": "%s", "delegations": [], "begin_unbondings": [], @@ -922,18 +920,17 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA "description": "test", "proposal_type": "Text", "proposer": "%s", - "initial_deposit": [{ "denom": "steak", "amount": 5 }], + "initial_deposit": [{ "denom": "steak", "amount": "5" }], "base_req": { "name": "%s", "password": "%s", "chain_id": "%s", - "account_number": %d, - "sequence": %d, - "gas": 100000 + "account_number":"%d", + "sequence":"%d", + "gas":"100000" } }`, bechProposerAddr, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", "/gov/proposals", jsonStr) - fmt.Println(res) require.Equal(t, http.StatusOK, res.StatusCode, body) var results ctypes.ResultBroadcastTxCommit @@ -956,18 +953,17 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk // deposit on proposal jsonStr := []byte(fmt.Sprintf(`{ "depositer": "%s", - "amount": [{ "denom": "steak", "amount": 5 }], + "amount": [{ "denom": "steak", "amount": "5" }], "base_req": { "name": "%s", "password": "%s", "chain_id": "%s", - "account_number": %d, - "sequence": %d, - "gas": 100000 + "account_number":"%d", + "sequence": "%d", + "gas":"100000" } }`, bechProposerAddr, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), jsonStr) - fmt.Println(res) require.Equal(t, http.StatusOK, res.StatusCode, body) var results ctypes.ResultBroadcastTxCommit @@ -995,9 +991,9 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ad "name": "%s", "password": "%s", "chain_id": "%s", - "account_number": %d, - "sequence": %d, - "gas": 100000 + "account_number": "%d", + "sequence": "%d", + "gas":"100000" } }`, bechProposerAddr, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), jsonStr) diff --git a/client/lcd/root.go b/client/lcd/root.go index 96e8504dd4..f9c30de861 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -31,6 +31,7 @@ import ( func ServeCommand(cdc *wire.Codec) *cobra.Command { flagListenAddr := "laddr" flagCORS := "cors" + flagMaxOpenConnections := "max-open" cmd := &cobra.Command{ Use: "rest-server", @@ -40,7 +41,8 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command { handler := createHandler(cdc) logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)). With("module", "rest-server") - listener, err := tmserver.StartHTTPServer(listenAddr, handler, logger) + maxOpen := viper.GetInt(flagMaxOpenConnections) + listener, err := tmserver.StartHTTPServer(listenAddr, handler, logger, tmserver.Config{MaxOpenConnections: maxOpen}) if err != nil { return err } @@ -58,6 +60,7 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command { cmd.Flags().String(flagCORS, "", "Set to domains that can make CORS requests (* for all)") cmd.Flags().StringP(client.FlagChainID, "c", "", "ID of chain we connect to") cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") + cmd.Flags().IntP(flagMaxOpenConnections, "o", 1000, "Maximum open connections") return cmd } diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 93a14585f6..0d5d7cad2f 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -15,10 +15,10 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - crkeys "github.com/tendermint/go-crypto/keys" + crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" + abci "github.com/tendermint/tendermint/abci/types" tmcfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/crypto" nm "github.com/tendermint/tendermint/node" pvm "github.com/tendermint/tendermint/privval" "github.com/tendermint/tendermint/proxy" @@ -83,9 +83,9 @@ func GetKB(t *testing.T) crkeys.Keybase { func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (addr sdk.Address, seed string) { var info crkeys.Info var err error - info, seed, err = kb.Create(name, password, crkeys.AlgoEd25519) + info, seed, err = kb.CreateMnemonic(name, crkeys.English, password, crkeys.Secp256k1) require.NoError(t, err) - addr = info.PubKey.Address() + addr = info.GetPubKey().Address() return } @@ -193,6 +193,7 @@ func startTM(tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, proxy.NewLocalClientCreator(app), genDocProvider, dbProvider, + nm.DefaultMetricsProvider, logger.With("module", "node")) if err != nil { return nil, err @@ -213,7 +214,7 @@ func startTM(tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, // start the LCD. note this blocks! func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) { handler := createHandler(cdc) - return tmrpc.StartHTTPServer(listenAddr, handler, logger) + return tmrpc.StartHTTPServer(listenAddr, handler, logger, tmrpc.Config{}) } // make a test lcd test request diff --git a/client/rpc/status.go b/client/rpc/status.go index 96517cc190..0c1f415930 100644 --- a/client/rpc/status.go +++ b/client/rpc/status.go @@ -82,7 +82,7 @@ func NodeSyncingRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { return } - syncing := status.SyncInfo.Syncing + syncing := status.SyncInfo.CatchingUp if err != nil { w.WriteHeader(500) w.Write([]byte(err.Error())) diff --git a/client/tx/query.go b/client/tx/query.go index 01cf959c8d..e70ecea399 100644 --- a/client/tx/query.go +++ b/client/tx/query.go @@ -2,7 +2,6 @@ package tx import ( "encoding/hex" - "encoding/json" "fmt" "net/http" "strconv" @@ -12,7 +11,7 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" "github.com/spf13/viper" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/cosmos/cosmos-sdk/client" @@ -72,7 +71,7 @@ func queryTx(cdc *wire.Codec, ctx context.CoreContext, hashHexStr string, trustN return nil, err } - return json.MarshalIndent(info, "", " ") + return wire.MarshalJSONIndent(cdc, info) } func formatTxResult(cdc *wire.Codec, res *ctypes.ResultTx) (txInfo, error) { diff --git a/client/tx/sign.go b/client/tx/sign.go index 36a765eed4..bedd202b48 100644 --- a/client/tx/sign.go +++ b/client/tx/sign.go @@ -5,7 +5,7 @@ import ( "net/http" keybase "github.com/cosmos/cosmos-sdk/client/keys" - keys "github.com/tendermint/go-crypto/keys" + keys "github.com/cosmos/cosmos-sdk/crypto/keys" ) // REST request body diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 67aea321f6..bdb2d3a2d0 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index 0523c54998..759fc55a6c 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/stake" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ) func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error { diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index c5b40b927f..ce4b6ccfca 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -5,7 +5,7 @@ import ( "errors" "github.com/spf13/pflag" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/server" diff --git a/cmd/gaia/app/genesis_test.go b/cmd/gaia/app/genesis_test.go index 03ff46e50d..90677e8ff1 100644 --- a/cmd/gaia/app/genesis_test.go +++ b/cmd/gaia/app/genesis_test.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/stretchr/testify/assert" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) func TestToAccount(t *testing.T) { diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 70d9f5564c..f8937c42dc 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -17,7 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/stake" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) func TestGaiaCLISend(t *testing.T) { diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 24ff148ce2..1915ef7517 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 2c84184bf7..0cb1160f5b 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -8,8 +8,8 @@ import ( "path" "github.com/spf13/cobra" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/cmd/gaia/cmd/gaiadebug/main.go b/cmd/gaia/cmd/gaiadebug/main.go index a3d3cac066..7139ae5faa 100644 --- a/cmd/gaia/cmd/gaiadebug/main.go +++ b/cmd/gaia/cmd/gaiadebug/main.go @@ -14,7 +14,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/spf13/cobra" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) func init() { diff --git a/crypto/amino.go b/crypto/amino.go new file mode 100644 index 0000000000..18d67e3d6a --- /dev/null +++ b/crypto/amino.go @@ -0,0 +1,19 @@ +package crypto + +import ( + "github.com/tendermint/go-amino" + tcrypto "github.com/tendermint/tendermint/crypto" +) + +var cdc = amino.NewCodec() + +func init() { + RegisterAmino(cdc) + tcrypto.RegisterAmino(cdc) +} + +// RegisterAmino registers all go-crypto related types in the given (amino) codec. +func RegisterAmino(cdc *amino.Codec) { + cdc.RegisterConcrete(PrivKeyLedgerSecp256k1{}, + "tendermint/PrivKeyLedgerSecp256k1", nil) +} diff --git a/crypto/encode_test.go b/crypto/encode_test.go new file mode 100644 index 0000000000..f0627d4c4a --- /dev/null +++ b/crypto/encode_test.go @@ -0,0 +1,122 @@ +package crypto + +import ( + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "os" + "testing" + + tcrypto "github.com/tendermint/tendermint/crypto" +) + +type byter interface { + Bytes() []byte +} + +func checkAminoBinary(t *testing.T, src byter, dst interface{}, size int) { + // Marshal to binary bytes. + bz, err := cdc.MarshalBinaryBare(src) + require.Nil(t, err, "%+v", err) + // Make sure this is compatible with current (Bytes()) encoding. + assert.Equal(t, src.Bytes(), bz, "Amino binary vs Bytes() mismatch") + // Make sure we have the expected length. + if size != -1 { + assert.Equal(t, size, len(bz), "Amino binary size mismatch") + } + // Unmarshal. + err = cdc.UnmarshalBinaryBare(bz, dst) + require.Nil(t, err, "%+v", err) +} + +func checkAminoJSON(t *testing.T, src interface{}, dst interface{}, isNil bool) { + // Marshal to JSON bytes. + js, err := cdc.MarshalJSON(src) + require.Nil(t, err, "%+v", err) + if isNil { + assert.Equal(t, string(js), `null`) + } else { + assert.Contains(t, string(js), `"type":`) + assert.Contains(t, string(js), `"value":`) + } + // Unmarshal. + err = cdc.UnmarshalJSON(js, dst) + require.Nil(t, err, "%+v", err) +} + +//nolint +func ExamplePrintRegisteredTypes() { + cdc.PrintTypes(os.Stdout) + // Output: | Type | Name | Prefix | Length | Notes | + //| ---- | ---- | ------ | ----- | ------ | + //| PrivKeyLedgerSecp256k1 | tendermint/PrivKeyLedgerSecp256k1 | 0x10CAB393 | variable | | + //| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE64 | 0x20 | | + //| PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE987 | 0x21 | | + //| PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288910 | 0x40 | | + //| PrivKeySecp256k1 | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | 0x20 | | + //| SignatureEd25519 | tendermint/SignatureEd25519 | 0x2031EA53 | 0x40 | | + //| SignatureSecp256k1 | tendermint/SignatureSecp256k1 | 0x7FC4A495 | variable | | +} + +func TestKeyEncodings(t *testing.T) { + cases := []struct { + privKey tcrypto.PrivKey + privSize, pubSize int // binary sizes + }{ + { + privKey: tcrypto.GenPrivKeyEd25519(), + privSize: 69, + pubSize: 37, + }, + { + privKey: tcrypto.GenPrivKeySecp256k1(), + privSize: 37, + pubSize: 38, + }, + } + + for _, tc := range cases { + + // Check (de/en)codings of PrivKeys. + var priv2, priv3 tcrypto.PrivKey + checkAminoBinary(t, tc.privKey, &priv2, tc.privSize) + assert.EqualValues(t, tc.privKey, priv2) + checkAminoJSON(t, tc.privKey, &priv3, false) // TODO also check Prefix bytes. + assert.EqualValues(t, tc.privKey, priv3) + + // Check (de/en)codings of Signatures. + var sig1, sig2, sig3 tcrypto.Signature + sig1, err := tc.privKey.Sign([]byte("something")) + assert.NoError(t, err) + checkAminoBinary(t, sig1, &sig2, -1) // Signature size changes for Secp anyways. + assert.EqualValues(t, sig1, sig2) + checkAminoJSON(t, sig1, &sig3, false) // TODO also check Prefix bytes. + assert.EqualValues(t, sig1, sig3) + + // Check (de/en)codings of PubKeys. + pubKey := tc.privKey.PubKey() + var pub2, pub3 tcrypto.PubKey + checkAminoBinary(t, pubKey, &pub2, tc.pubSize) + assert.EqualValues(t, pubKey, pub2) + checkAminoJSON(t, pubKey, &pub3, false) // TODO also check Prefix bytes. + assert.EqualValues(t, pubKey, pub3) + } +} + +func TestNilEncodings(t *testing.T) { + + // Check nil Signature. + var a, b tcrypto.Signature + checkAminoJSON(t, &a, &b, true) + assert.EqualValues(t, a, b) + + // Check nil PubKey. + var c, d tcrypto.PubKey + checkAminoJSON(t, &c, &d, true) + assert.EqualValues(t, c, d) + + // Check nil PrivKey. + var e, f tcrypto.PrivKey + checkAminoJSON(t, &e, &f, true) + assert.EqualValues(t, e, f) + +} diff --git a/crypto/keys/bcrypt/base64.go b/crypto/keys/bcrypt/base64.go new file mode 100644 index 0000000000..fc31160908 --- /dev/null +++ b/crypto/keys/bcrypt/base64.go @@ -0,0 +1,35 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bcrypt + +import "encoding/base64" + +const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +var bcEncoding = base64.NewEncoding(alphabet) + +func base64Encode(src []byte) []byte { + n := bcEncoding.EncodedLen(len(src)) + dst := make([]byte, n) + bcEncoding.Encode(dst, src) + for dst[n-1] == '=' { + n-- + } + return dst[:n] +} + +func base64Decode(src []byte) ([]byte, error) { + numOfEquals := 4 - (len(src) % 4) + for i := 0; i < numOfEquals; i++ { + src = append(src, '=') + } + + dst := make([]byte, bcEncoding.DecodedLen(len(src))) + n, err := bcEncoding.Decode(dst, src) + if err != nil { + return nil, err + } + return dst[:n], nil +} diff --git a/crypto/keys/bcrypt/bcrypt.go b/crypto/keys/bcrypt/bcrypt.go new file mode 100644 index 0000000000..e24120bfbe --- /dev/null +++ b/crypto/keys/bcrypt/bcrypt.go @@ -0,0 +1,297 @@ +package bcrypt + +// MODIFIED BY TENDERMINT TO EXPOSE NONCE +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing +// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf + +// The code is a port of Provos and Mazières's C implementation. +import ( + "crypto/subtle" + "errors" + "fmt" + "strconv" + + "golang.org/x/crypto/blowfish" +) + +const ( + // the minimum allowable cost as passed in to GenerateFromPassword + MinCost int = 4 + // the maximum allowable cost as passed in to GenerateFromPassword + MaxCost int = 31 + // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword + DefaultCost int = 10 +) + +// The error returned from CompareHashAndPassword when a password and hash do +// not match. +var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password") + +// The error returned from CompareHashAndPassword when a hash is too short to +// be a bcrypt hash. +var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password") + +// The error returned from CompareHashAndPassword when a hash was created with +// a bcrypt algorithm newer than this implementation. +type HashVersionTooNewError byte + +func (hv HashVersionTooNewError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion) +} + +// The error returned from CompareHashAndPassword when a hash starts with something other than '$' +type InvalidHashPrefixError byte + +// Format error +func (ih InvalidHashPrefixError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih)) +} + +// Invalid bcrypt cost +type InvalidCostError int + +func (ic InvalidCostError) Error() string { + return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost)) // nolint: unconvert +} + +const ( + majorVersion = '2' + minorVersion = 'a' + maxSaltSize = 16 + maxCryptedHashSize = 23 + encodedSaltSize = 22 + encodedHashSize = 31 + minHashSize = 59 +) + +// magicCipherData is an IV for the 64 Blowfish encryption calls in +// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes. +var magicCipherData = []byte{ + 0x4f, 0x72, 0x70, 0x68, + 0x65, 0x61, 0x6e, 0x42, + 0x65, 0x68, 0x6f, 0x6c, + 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, + 0x6f, 0x75, 0x62, 0x74, +} + +type hashed struct { + hash []byte + salt []byte + cost int // allowed range is MinCost to MaxCost + major byte + minor byte +} + +// GenerateFromPassword returns the bcrypt hash of the password at the given +// cost. If the cost given is less than MinCost, the cost will be set to +// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, +// to compare the returned hashed password with its cleartext version. +func GenerateFromPassword(salt []byte, password []byte, cost int) ([]byte, error) { + if len(salt) != maxSaltSize { + return nil, fmt.Errorf("salt len must be %v", maxSaltSize) + } + p, err := newFromPassword(salt, password, cost) + if err != nil { + return nil, err + } + return p.Hash(), nil +} + +// CompareHashAndPassword compares a bcrypt hashed password with its possible +// plaintext equivalent. Returns nil on success, or an error on failure. +func CompareHashAndPassword(hashedPassword, password []byte) error { + p, err := newFromHash(hashedPassword) + if err != nil { + return err + } + + otherHash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return err + } + + otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor} + if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 { + return nil + } + + return ErrMismatchedHashAndPassword +} + +// Cost returns the hashing cost used to create the given hashed +// password. When, in the future, the hashing cost of a password system needs +// to be increased in order to adjust for greater computational power, this +// function allows one to establish which passwords need to be updated. +func Cost(hashedPassword []byte) (int, error) { + p, err := newFromHash(hashedPassword) + if err != nil { + return 0, err + } + return p.cost, nil +} + +func newFromPassword(salt []byte, password []byte, cost int) (*hashed, error) { + if cost < MinCost { + cost = DefaultCost + } + p := new(hashed) + p.major = majorVersion + p.minor = minorVersion + + err := checkCost(cost) + if err != nil { + return nil, err + } + p.cost = cost + + p.salt = base64Encode(salt) + hash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return nil, err + } + p.hash = hash + return p, err +} + +func newFromHash(hashedSecret []byte) (*hashed, error) { + if len(hashedSecret) < minHashSize { + return nil, ErrHashTooShort + } + p := new(hashed) + n, err := p.decodeVersion(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + n, err = p.decodeCost(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + + // The "+2" is here because we'll have to append at most 2 '=' to the salt + // when base64 decoding it in expensiveBlowfishSetup(). + p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2) + copy(p.salt, hashedSecret[:encodedSaltSize]) + + hashedSecret = hashedSecret[encodedSaltSize:] + p.hash = make([]byte, len(hashedSecret)) + copy(p.hash, hashedSecret) + + return p, nil +} + +func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) { + cipherData := make([]byte, len(magicCipherData)) + copy(cipherData, magicCipherData) + + c, err := expensiveBlowfishSetup(password, uint32(cost), salt) + if err != nil { + return nil, err + } + + for i := 0; i < 24; i += 8 { + for j := 0; j < 64; j++ { + c.Encrypt(cipherData[i:i+8], cipherData[i:i+8]) + } + } + + // Bug compatibility with C bcrypt implementations. We only encode 23 of + // the 24 bytes encrypted. + hsh := base64Encode(cipherData[:maxCryptedHashSize]) + return hsh, nil +} + +func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) { + + csalt, err := base64Decode(salt) + if err != nil { + return nil, err + } + + // Bug compatibility with C bcrypt implementations. They use the trailing + // NULL in the key string during expansion. + ckey := append(key, 0) + + c, err := blowfish.NewSaltedCipher(ckey, csalt) + if err != nil { + return nil, err + } + + var i, rounds uint64 + rounds = 1 << cost + for i = 0; i < rounds; i++ { + blowfish.ExpandKey(ckey, c) + blowfish.ExpandKey(csalt, c) + } + + return c, nil +} + +func (p *hashed) Hash() []byte { + arr := make([]byte, 60) + arr[0] = '$' + arr[1] = p.major + n := 2 + if p.minor != 0 { + arr[2] = p.minor + n = 3 + } + arr[n] = '$' + n++ + copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost))) + n += 2 + arr[n] = '$' + n++ + copy(arr[n:], p.salt) + n += encodedSaltSize + copy(arr[n:], p.hash) + n += encodedHashSize + return arr[:n] +} + +func (p *hashed) decodeVersion(sbytes []byte) (int, error) { + if sbytes[0] != '$' { + return -1, InvalidHashPrefixError(sbytes[0]) + } + if sbytes[1] > majorVersion { + return -1, HashVersionTooNewError(sbytes[1]) + } + p.major = sbytes[1] + n := 3 + if sbytes[2] != '$' { + p.minor = sbytes[2] + n++ + } + return n, nil +} + +// sbytes should begin where decodeVersion left off. +func (p *hashed) decodeCost(sbytes []byte) (int, error) { + cost, err := strconv.Atoi(string(sbytes[0:2])) + if err != nil { + return -1, err + } + err = checkCost(cost) + if err != nil { + return -1, err + } + p.cost = cost + return 3, nil +} + +func (p *hashed) String() string { + return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor) +} + +func checkCost(cost int) error { + if cost < MinCost || cost > MaxCost { + return InvalidCostError(cost) + } + return nil +} diff --git a/crypto/keys/bip39/wordcodec.go b/crypto/keys/bip39/wordcodec.go new file mode 100644 index 0000000000..d874fe58cb --- /dev/null +++ b/crypto/keys/bip39/wordcodec.go @@ -0,0 +1,60 @@ +package bip39 + +import ( + "strings" + + "github.com/bartekn/go-bip39" +) + +// ValidSentenceLen defines the mnemonic sentence lengths supported by this BIP 39 library. +type ValidSentenceLen uint8 + +const ( + // FundRaiser is the sentence length used during the cosmos fundraiser (12 words). + FundRaiser ValidSentenceLen = 12 + // FreshKey is the sentence length used for newly created keys (24 words). + FreshKey ValidSentenceLen = 24 +) + +// NewMnemonic will return a string consisting of the mnemonic words for +// the given sentence length. +func NewMnemonic(len ValidSentenceLen) (words []string, err error) { + // len = (entropySize + checksum) / 11 + var entropySize int + switch len { + case FundRaiser: + entropySize = 128 + case FreshKey: + entropySize = 256 + } + var entropy []byte + entropy, err = bip39.NewEntropy(entropySize) + if err != nil { + return + } + var mnemonic string + mnemonic, err = bip39.NewMnemonic(entropy) + if err != nil { + return + } + words = strings.Split(mnemonic, " ") + return +} + +// MnemonicToSeed creates a BIP 39 seed from the passed mnemonic (with an empty BIP 39 password). +// This method does not validate the mnemonics checksum. +func MnemonicToSeed(mne string) (seed []byte) { + // we do not checksum here... + seed = bip39.NewSeed(mne, "") + return +} + +// MnemonicToSeedWithErrChecking returns the same seed as MnemonicToSeed. +// It creates a BIP 39 seed from the passed mnemonic (with an empty BIP 39 password). +// +// Different from MnemonicToSeed it validates the checksum. +// For details on the checksum see the BIP 39 spec. +func MnemonicToSeedWithErrChecking(mne string) (seed []byte, err error) { + seed, err = bip39.NewSeedWithErrorChecking(mne, "") + return +} diff --git a/crypto/keys/bip39/wordcodec_test.go b/crypto/keys/bip39/wordcodec_test.go new file mode 100644 index 0000000000..dbc5c0d020 --- /dev/null +++ b/crypto/keys/bip39/wordcodec_test.go @@ -0,0 +1,15 @@ +package bip39 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWordCodec_NewMnemonic(t *testing.T) { + _, err := NewMnemonic(FundRaiser) + assert.NoError(t, err, "unexpected error generating fundraiser mnemonic") + + _, err = NewMnemonic(FreshKey) + assert.NoError(t, err, "unexpected error generating new 24-word mnemonic") +} diff --git a/crypto/keys/hd/fundraiser_test.go b/crypto/keys/hd/fundraiser_test.go new file mode 100644 index 0000000000..3e45de7e2d --- /dev/null +++ b/crypto/keys/hd/fundraiser_test.go @@ -0,0 +1,80 @@ +package hd + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "testing" + + "github.com/bartekn/go-bip39" + "github.com/stretchr/testify/assert" + + "github.com/tendermint/tendermint/crypto" +) + +type addrData struct { + Mnemonic string + Master string + Seed string + Priv string + Pub string + Addr string +} + +func initFundraiserTestVectors(t *testing.T) []addrData { + // NOTE: atom fundraiser address + // var hdPath string = "m/44'/118'/0'/0/0" + var hdToAddrTable []addrData + + b, err := ioutil.ReadFile("test.json") + if err != nil { + t.Fatalf("could not read fundraiser test vector file (test.json): %s", err) + } + + err = json.Unmarshal(b, &hdToAddrTable) + if err != nil { + t.Fatalf("could not decode test vectors (test.json): %s", err) + } + return hdToAddrTable +} + +func TestFundraiserCompatibility(t *testing.T) { + hdToAddrTable := initFundraiserTestVectors(t) + + for i, d := range hdToAddrTable { + privB, _ := hex.DecodeString(d.Priv) + pubB, _ := hex.DecodeString(d.Pub) + addrB, _ := hex.DecodeString(d.Addr) + seedB, _ := hex.DecodeString(d.Seed) + masterB, _ := hex.DecodeString(d.Master) + + seed := bip39.NewSeed(d.Mnemonic, "") + + t.Log("================================") + t.Logf("ROUND: %d MNEMONIC: %s", i, d.Mnemonic) + + master, ch := ComputeMastersFromSeed(seed) + priv, err := DerivePrivateKeyForPath(master, ch, "44'/118'/0'/0/0") + assert.NoError(t, err) + pub := crypto.PrivKeySecp256k1(priv).PubKey() + + t.Log("\tNODEJS GOLANG\n") + t.Logf("SEED \t%X %X\n", seedB, seed) + t.Logf("MSTR \t%X %X\n", masterB, master) + t.Logf("PRIV \t%X %X\n", privB, priv) + t.Logf("PUB \t%X %X\n", pubB, pub) + + assert.Equal(t, seedB, seed) + assert.Equal(t, master[:], masterB, fmt.Sprintf("Expected masters to match for %d", i)) + assert.Equal(t, priv[:], privB, "Expected priv keys to match") + var pubBFixed [33]byte + copy(pubBFixed[:], pubB) + assert.Equal(t, pub, crypto.PubKeySecp256k1(pubBFixed), fmt.Sprintf("Expected pub keys to match for %d", i)) + + addr := pub.Address() + t.Logf("ADDR \t%X %X\n", addrB, addr) + assert.Equal(t, addr, crypto.Address(addrB), fmt.Sprintf("Expected addresses to match %d", i)) + + } +} diff --git a/crypto/keys/hd/hdpath.go b/crypto/keys/hd/hdpath.go new file mode 100644 index 0000000000..1427752b4f --- /dev/null +++ b/crypto/keys/hd/hdpath.go @@ -0,0 +1,168 @@ +// Package hd provides basic functionality Hierarchical Deterministic Wallets. +// +// The user must understand the overall concept of the BIP 32 and the BIP 44 specs: +// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki +// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki +// +// In combination with the bip39 package in go-crypto this package provides the functionality for deriving keys using a +// BIP 44 HD path, or, more general, by passing a BIP 32 path. +// +// In particular, this package (together with bip39) provides all necessary functionality to derive keys from +// mnemonics generated during the cosmos fundraiser. +package hd + +import ( + "crypto/hmac" + "crypto/sha512" + "encoding/binary" + "errors" + "fmt" + "math/big" + "strconv" + "strings" + + "github.com/btcsuite/btcd/btcec" + "github.com/tendermint/tendermint/crypto" +) + +// BIP44Prefix is the parts of the BIP32 HD path that are fixed by what we used during the fundraiser. +const ( + BIP44Prefix = "44'/118'/" + FullFundraiserPath = BIP44Prefix + "0'/0/0" +) + +// BIP44Params wraps BIP 44 params (5 level BIP 32 path). +// To receive a canonical string representation ala +// m / purpose' / coin_type' / account' / change / address_index +// call String() on a BIP44Params instance. +type BIP44Params struct { + purpose uint32 + coinType uint32 + account uint32 + change bool + addressIdx uint32 +} + +// NewParams creates a BIP 44 parameter object from the params: +// m / purpose' / coin_type' / account' / change / address_index +func NewParams(purpose, coinType, account uint32, change bool, addressIdx uint32) *BIP44Params { + return &BIP44Params{ + purpose: purpose, + coinType: coinType, + account: account, + change: change, + addressIdx: addressIdx, + } +} + +// NewFundraiserParams creates a BIP 44 parameter object from the params: +// m / 44' / 118' / account' / 0 / address_index +// The fixed parameters (purpose', coin_type', and change) are determined by what was used in the fundraiser. +func NewFundraiserParams(account uint32, addressIdx uint32) *BIP44Params { + return NewParams(44, 118, account, false, addressIdx) +} + +func (p BIP44Params) String() string { + var changeStr string + if p.change { + changeStr = "1" + } else { + changeStr = "0" + } + // m / purpose' / coin_type' / account' / change / address_index + return fmt.Sprintf("%d'/%d'/%d'/%s/%d", + p.purpose, + p.coinType, + p.account, + changeStr, + p.addressIdx) +} + +// ComputeMastersFromSeed returns the master public key, master secret, and chain code in hex. +func ComputeMastersFromSeed(seed []byte) (secret [32]byte, chainCode [32]byte) { + masterSecret := []byte("Bitcoin seed") + secret, chainCode = i64(masterSecret, seed) + + return +} + +// DerivePrivateKeyForPath derives the private key by following the BIP 32/44 path from privKeyBytes, +// using the given chainCode. +func DerivePrivateKeyForPath(privKeyBytes [32]byte, chainCode [32]byte, path string) ([32]byte, error) { + data := privKeyBytes + parts := strings.Split(path, "/") + for _, part := range parts { + // do we have an apostrophe? + harden := part[len(part)-1:] == "'" + // harden == private derivation, else public derivation: + if harden { + part = part[:len(part)-1] + } + idx, err := strconv.Atoi(part) + if err != nil { + return [32]byte{}, fmt.Errorf("invalid BIP 32 path: %s", err) + } + if idx < 0 { + return [32]byte{}, errors.New("invalid BIP 32 path: index negative ot too large") + } + data, chainCode = derivePrivateKey(data, chainCode, uint32(idx), harden) + } + var derivedKey [32]byte + n := copy(derivedKey[:], data[:]) + if n != 32 || len(data) != 32 { + return [32]byte{}, fmt.Errorf("expected a (secp256k1) key of length 32, got length: %v", len(data)) + } + + return derivedKey, nil +} + +// derivePrivateKey derives the private key with index and chainCode. +// If harden is true, the derivation is 'hardened'. +// It returns the new private key and new chain code. +// For more information on hardened keys see: +// - https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki +func derivePrivateKey(privKeyBytes [32]byte, chainCode [32]byte, index uint32, harden bool) ([32]byte, [32]byte) { + var data []byte + if harden { + index = index | 0x80000000 + data = append([]byte{byte(0)}, privKeyBytes[:]...) + } else { + // this can't return an error: + pubkey := crypto.PrivKeySecp256k1(privKeyBytes).PubKey() + + public := pubkey.(crypto.PubKeySecp256k1) + data = public[:] + } + data = append(data, uint32ToBytes(index)...) + data2, chainCode2 := i64(chainCode[:], data) + x := addScalars(privKeyBytes[:], data2[:]) + return x, chainCode2 +} + +// modular big endian addition +func addScalars(a []byte, b []byte) [32]byte { + aInt := new(big.Int).SetBytes(a) + bInt := new(big.Int).SetBytes(b) + sInt := new(big.Int).Add(aInt, bInt) + x := sInt.Mod(sInt, btcec.S256().N).Bytes() + x2 := [32]byte{} + copy(x2[32-len(x):], x) + return x2 +} + +func uint32ToBytes(i uint32) []byte { + b := [4]byte{} + binary.BigEndian.PutUint32(b[:], i) + return b[:] +} + +// i64 returns the two halfs of the SHA512 HMAC of key and data. +func i64(key []byte, data []byte) (IL [32]byte, IR [32]byte) { + mac := hmac.New(sha512.New, key) + // sha512 does not err + _, _ = mac.Write(data) + I := mac.Sum(nil) + copy(IL[:], I[:32]) + copy(IR[:], I[32:]) + return +} diff --git a/crypto/keys/hd/hdpath_test.go b/crypto/keys/hd/hdpath_test.go new file mode 100644 index 0000000000..58398655f0 --- /dev/null +++ b/crypto/keys/hd/hdpath_test.go @@ -0,0 +1,75 @@ +package hd + +import ( + "encoding/hex" + "fmt" + "github.com/cosmos/cosmos-sdk/crypto/keys/bip39" +) + +//nolint +func ExampleStringifyPathParams() { + path := NewParams(44, 0, 0, false, 0) + fmt.Println(path.String()) + // Output: 44'/0'/0'/0/0 +} + +//nolint +func ExampleSomeBIP32TestVecs() { + + seed := bip39.MnemonicToSeed("barrel original fuel morning among eternal " + + "filter ball stove pluck matrix mechanic") + master, ch := ComputeMastersFromSeed(seed) + fmt.Println("keys from fundraiser test-vector (cosmos, bitcoin, ether)") + fmt.Println() + // cosmos + priv, _ := DerivePrivateKeyForPath(master, ch, FullFundraiserPath) + fmt.Println(hex.EncodeToString(priv[:])) + // bitcoin + priv, _ = DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/0") + fmt.Println(hex.EncodeToString(priv[:])) + // ether + priv, _ = DerivePrivateKeyForPath(master, ch, "44'/60'/0'/0/0") + fmt.Println(hex.EncodeToString(priv[:])) + + fmt.Println() + fmt.Println("keys generated via https://coinomi.com/recovery-phrase-tool.html") + fmt.Println() + + seed = bip39.MnemonicToSeed( + "advice process birth april short trust crater change bacon monkey medal garment " + + "gorilla ranch hour rival razor call lunar mention taste vacant woman sister") + master, ch = ComputeMastersFromSeed(seed) + priv, _ = DerivePrivateKeyForPath(master, ch, "44'/1'/1'/0/4") + fmt.Println(hex.EncodeToString(priv[:])) + + seed = bip39.MnemonicToSeed("idea naive region square margin day captain habit " + + "gun second farm pact pulse someone armed") + master, ch = ComputeMastersFromSeed(seed) + priv, _ = DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/420") + fmt.Println(hex.EncodeToString(priv[:])) + + fmt.Println() + fmt.Println("BIP 32 example") + fmt.Println() + + // bip32 path: m/0/7 + seed = bip39.MnemonicToSeed("monitor flock loyal sick object grunt duty ride develop assault harsh history") + master, ch = ComputeMastersFromSeed(seed) + priv, _ = DerivePrivateKeyForPath(master, ch, "0/7") + fmt.Println(hex.EncodeToString(priv[:])) + + // Output: keys from fundraiser test-vector (cosmos, bitcoin, ether) + // + // bfcb217c058d8bbafd5e186eae936106ca3e943889b0b4a093ae13822fd3170c + // e77c3de76965ad89997451de97b95bb65ede23a6bf185a55d80363d92ee37c3d + // 7fc4d8a8146dea344ba04c593517d3f377fa6cded36cd55aee0a0bb968e651bc + // + // keys generated via https://coinomi.com/recovery-phrase-tool.html + // + // a61f10c5fecf40c084c94fa54273b6f5d7989386be4a37669e6d6f7b0169c163 + // 32c4599843de3ef161a629a461d12c60b009b676c35050be5f7ded3a3b23501f + // + // BIP 32 example + // + // c4c11d8c03625515905d7e89d25dfc66126fbc629ecca6db489a1a72fc4bda78 +} diff --git a/crypto/keys/hd/test.json b/crypto/keys/hd/test.json new file mode 100644 index 0000000000..fa9610999c --- /dev/null +++ b/crypto/keys/hd/test.json @@ -0,0 +1 @@ +[{"mnemonic":"measure slogan connect luggage stereo federal stuff stomach stumble security end differ","master":"c177fa4bd21420b6ba2246e4f7a43fbe76545d1204174cae942ffbd79a434d11","seed":"c237f7aa198c5bd560ac8daf5b8421d03855171465b2999b07159671e9186461e7d75dba6c7264b963108431f8674ac8d095b7a22878fa0ab8b582e5d6ea1986","priv":"91bba8805845210665d7a9c5aff63ef69f7604fbeddb485706d31f04458f572c","pub":"0210ddc89abc90bbcbec8c63f5a4ebb016b58063b9d1a77854502042bdfcac5e51","addr":"72e7d6e9cfa899043a0783752a4876423f8effb8"},{"mnemonic":"car taste absurd genius miracle toy earth true glare mobile pig forest","master":"d7e07c472b05a2d668328c148ca07264afb4b53e078a2e1c106470b51c6ef81c","seed":"fda7006f5e9b8d1c02404df6d4e4497ff5c2edf29c801180a046dc54fca2e019554da6e3dd2c26073a7871c5ac529ad465ccf77ec3608727cc47ef88f998ae2b","priv":"1122ac929a0a3b2947ef99c33c20b657cf7342ea09be92869c363cfc52118200","pub":"03d0b431b56ae65aeb5a572654445b3fc968fa9d73995d3b21243cb07ed1ef0067","addr":"63eba204c249c795cd9dbdad58561db56b1d0c9b"},{"mnemonic":"trophy crop coffee oppose pelican help sense note bar faint hen aunt","master":"d1baaea05c34a4bbdc6791ada5aad77fdb0e626642cb884e48d25cd4ef6c9bed","seed":"1cdcfda64cb0e4f5806a48ff374e9f5f7d2939815e7adcce3abd898a7a9204eec4a5822997ca556ad797b4610c4ae6accddc29d80fd651a33d5ed911892479f1","priv":"c4bbb8f1ec60271c1e4f9e019ea45f82ca0ee3c42d8ac268f898fdbdfc28cf48","pub":"03abff20397222f9cae536d6b6776ba48c9b51898f7527dea918058f986fbfad15","addr":"fb6abc72817a9d2c6c1a2fe652434999661e1178"},{"mnemonic":"embrace office author among dream island social gift ask drill polar festival","master":"8d58a57b66a08bc0bd8dde7a718432a01f7aff03cbf999aeb3830d7a1c3d0d54","seed":"65b81faccab573d4a4272ab7c46e5fcc7db66eceeab6796d6dd70d8c54d6c95c3b73a637210a96a95df5ef736f51eec1dd3af4ccca53e98fb7f16d4e22dc3f52","priv":"dec3ffc51d5c9eadfb11e11dcc640f8cb294a21cfbb4a230f164693d57851b3b","pub":"03ef202a875683203e9d9643a2943cb40ff5a69b6efb3b0dedfc8ab1c6928261d1","addr":"db1a5fd30abfe666a049f5c6689a0e3db3ebec1e"},{"mnemonic":"aware gospel lemon tomorrow east wheel member forest walnut virus shallow stick","master":"24075bca853e0066909a6ff06ff02f196d4d641c00677704a6472810b0e3263e","seed":"1a4419cb19e2e7686fe68187aa55a2d4fab8d655c505c5666963d61bc9e92cfb990402d8527f9463b2deb3e86894055e3c6b31cf9995ca5bdf9959db755c9e90","priv":"853665c8f66682e50db33fe699ee72dae036422bee03e37093ed95c871ae8309","pub":"02a4e19e61decd6006bec54fa9c7ada7ee63ca6df12640e9fcf4214faafce791e6","addr":"155dac0e19dc24880b5aed827ebabb05bb563b23"},{"mnemonic":"perfect chief lend clock bracket guard extend medal slice vague cheese child","master":"b594e8d22e4864bdf75ddf29de16b7b207b2bbbdf29132b859f9c71c919ff669","seed":"631fc64164825a9769c4cd376cd736d4dd4191b7728e70b1e84b46322cb8bfb01b5b33cc6707d59bed09f6e7c82335541cd7dfc51ebedfcc2786713a9d141663","priv":"eab18ec583e155fd4ece4a14248bda80c75a6f209a1e4a9b1801e1a707b4356e","pub":"0247995311612868a8d1f6927f18ae5163a9d64a41d8f4015f9dcbbdace9277ed3","addr":"1f42f6538f64d844cef39b941986465076da3d54"},{"mnemonic":"edge early ten vicious piece begin observe ripple neutral farm volume accident","master":"1d6462662cd27419936c1f5b579eb7ebbafe84a6b1a58906c37fc0c2aa612d22","seed":"fb9588a1e3a2d9c26dcdb3cb010b8f868b29c493c95f7fe16761b2a666a8b96ca62997646e8d2cea1ff8ec3b85bd2311741ee327076515ad075623853279b57e","priv":"081847ec4f11a7d54ddd78c6f0fb3cdc32508e4956da14e0d728ddd3862124ce","pub":"03533c9f60afc94de73a0abb7d3e98906fa72cd2aebb202fdac32e2014452779d1","addr":"bcab563beb9ead1a87ab5adabc708502dc4081de"},{"mnemonic":"escape crystal wrist method cave retire wedding unable fringe inhale vibrant inform","master":"8b8597cd8ca42fe10236cc933bf0adda507132be6c41451d6ddda615b4032798","seed":"84582da23a6c4cf3d8f75be55db0d2710e10e31e9d6cee8288d827ed17d6585f19d81831aac12aff8d2724ace9c4220924e7d778eaebb3ff7ac4976b5ee25cc9","priv":"d011566a0c3996c99cf02ee41aa3f24c3328b5773ad0c9ea23f1bda1967a7e2c","pub":"03dcb9dd25915f827965c2d64e258eed1e4cf55f9fa3a9a8b5b411cbccffb11de0","addr":"54eea7e51aec6be8eca7a556c0ba5abfb702b34f"},{"mnemonic":"alter buddy rival question bachelor expose unique menu east sample also fence","master":"0eff009e6a00061a23a9b26f365cc00b0189825fe2eec0a3e78928fbd9f4dd7b","seed":"afa260446549711688b754edf33e313ceaece5502d0dbd8d82bc3c797151741620e403575ba6b54b0071e7122c8ae54893ccf29a43de209c67f7a8c296e47c84","priv":"39be182557862e0b7cf6440fb23568e54772edf734b4710ef571b37a6c27d16c","pub":"032c0d9bdbb97f2b7041734968eae96b3283573b9eefcd3ea1ce286c872bc8df4b","addr":"cbc2321a8e91ea81a56150689921b65a402b5c63"},{"mnemonic":"jar toward train panic unhappy control artefact horse deposit liar minimum pink","master":"009a99faadbdaa139f7ad2297367fdf92103c75194097133b51e0dd57629d06f","seed":"75b28bd52420c950aad1b4270fea0f8816c240e1bb16ad7f35a4bcc234e1c0bce4642422ea359dfae0332417c188a10e1b7efda4a9129809d98a179e8ef618dc","priv":"fbb6c27c23346fb30aa1aca0004f3adff649067efcbcdd58f9e8ed1be9167624","pub":"02463386f13659d68ca10edbecafab3294fddfb989b8012dd8a306c1e716ea73bc","addr":"9aef504159fcefcce23e49b64fe73d64b652751a"},{"mnemonic":"wise undo month ugly case garbage cannon torch sight burst flock enter","master":"e8533102aa8baa896888094c49fd096151adde972cbdd46429095b6081226d88","seed":"c64eab45997b8f27af96667bb8b3e3b1f13cd1cae3f33d357ef8996e958a24f78c6fff1dd21a7aad45a236d02e93722a74827e723415f4c3d2e28b5755ce74bf","priv":"7b28255abe4b5dfc46dd3e4a78aff23fd519ee20d0fccf77fa1f08dc87d4c2a8","pub":"03666213b09e6838c37edd56d858361cc7252aff15c86d9cbb7fd2ffaab2797eff","addr":"8de416131b81c2b4fb347c619e162e5b9d8e9171"},{"mnemonic":"fever hotel cup cover lake cream hello drastic scrap appear device skill","master":"c0c7ae8be6467f73da04bf31893fed60a7d2874a1b8b40cf6b947d3e0c072fd8","seed":"ba8ccb1d6df012c48cd0e97e126aca7192fc49ffe58fe554f2f96b85f7c8ee842e582a7967e053c4ea26f5ee0730dd7b78212b397f5ad89c0691c151c5b649b2","priv":"2d28bdd1c56e6f0c953b97ea571d7ee13f4b53557e9de79de436faee8b984944","pub":"02d4ef64e150ee986d14953bb42d7da5a26e184ae00d33c648e552ec31cc81df62","addr":"1919c6f2d0c93447d4fb8f10b8af4c57a06ad235"},{"mnemonic":"camp pizza test idea attend urban pond gym solution denial coach oppose","master":"e85ce81ff0663a945753449ea5a53a72e429a7badc3c681d7c13bb1b75a4d2ed","seed":"2bc62e90ae9d83635b316ef55f4ada1652dea512da332474598f53f93268ee1e18802ba19e75df651cfe931049ccc7aba7b96d43b62182e0e5b0e21a1cc2f489","priv":"bbd3109cd6edfc583ad1fca84b3c32def7d41e36f1994ac40eb5fd9f72211a47","pub":"032a3e6b6d55ede0c25b78a2bb860adea7ec8b3dbaf7340197ad2d0c07e1673a1f","addr":"4f9ba3935c15ff8ce14f0b09ef498e50693c4c90"},{"mnemonic":"solution buffalo armor capital enter cat banana manage caution loan people gauge","master":"1d894a5d9932bc19f91fa92f0d03f25136a77b4eb961ddd742b74c54edad9332","seed":"b833db5ff34a1bddbbee895d96518261025bbc6a9be596d58435468f1547ff378f504062aab7add0c69763708238d0ab42a90f6af0b790caa1569d1cc089b605","priv":"4e26066e7ff8936e63fb011173f70b0206c1b6ecaa519fb252185e18dbc19705","pub":"03fd00f281ba6065cdc8f6a8cf17cdb22b2ccad62eeb535708381004b2a260837f","addr":"e6247dacab881ff882e412630350eaa6de14817a"},{"mnemonic":"power answer mixture choose course crop decline border carpet absorb long artwork","master":"1d74c0120756009f821899f220d3a9e77291e0549241481b657ddb84af1b66f8","seed":"cd9ac735fee9bbcf45bd79b31196138b3ca002513bd1fb973eae4bffd0c5732611cd67006af3f79dd127ce21532947a0c1355cc774faee82f58cdbef6f8bd7fa","priv":"45f7df4a90d4ed0f58c47ab4839220f50689cb2a5663acd9cbb359d6a23e465e","pub":"02697233abb54eeef1f03a371b0da9a97e85ffe404707b5b7ee3f0e3d2e2f0768f","addr":"0f5addad3faaad7ebaf37c3d3f2576a0a1a5e533"},{"mnemonic":"patrol room turtle cinnamon remain tank butter hazard expose winner rough pull","master":"91eb616d5be757e91052fe74042515b828e2bb14f5666370d7ec37c45018abbd","seed":"7e3b9d910c4b16b06e813b2b003d9c0e8c76ec520702be210d9ec2ef2406e7f473f09f41fda56b6a657c2f1000130e11a88362209c6b4b47362e786b7880916c","priv":"ffc2a31bf0371a095cadbad2e0b5adc5669ceb6faad08da818c3c64e4af53b44","pub":"03b50efecc97cc7d7f101fdcae02662d49d118a63f03180889d8321019f245f6aa","addr":"0c43cd72c09dee746c3af1691b495a8c02286612"},{"mnemonic":"bulb neglect chalk congress cattle found balcony easy tube sick journey quick","master":"a7c632878e900903d4e0e6bc57291f1e64981d703e27b82c2da00dec800d5570","seed":"aaa765dce33f6b289d37fff2e409a540a29f3830a7baa0526eba3317d559ef59e8936e8285b6ea8a62753ec72616163e24963e49d795f38df210836ffc7d8807","priv":"f8b281b658e9a584087e16eab0179747db5c38193cada4fc85364a8f743bfec9","pub":"0384df6f5de3f50793f62eee838d30334501d6339998a25889688ba305998d15cf","addr":"cfe9adc1e454387351d4ef2dfd086101a0012863"},{"mnemonic":"arm asthma voyage mansion hurdle alley ensure team coffee palm spice general","master":"48e37cc4961ff1234938ca5ad6ed22f668b29017067c283ebf2d9642cfc2e57b","seed":"6bec879e82e5d243a6bbd5a0a5dcd21a6403d450f0f498975d5205da7154f62350cf0afa034f921cfedd4dd4dde0b6e3e9cc118b16b6682686211040b3b80b6c","priv":"b0b487d336dbb594947dab6717a5f140056d998f9e8428307491d12b3f9e3883","pub":"039db2ffbad67e7e824bfd0cd9fd8798647390b8c9a583807995a9b49e252279c3","addr":"1353002776f22c179aa208bbdddeab3c369c51be"},{"mnemonic":"spread curtain furnace trim funny usual age floor crunch blue urge pistol","master":"3c44072b545e2e955892ee4e6e5949b748d17d47d3ebeda85fb50a341bda7668","seed":"05376e4a1725d48191bebb1e03bdf76880d82b033f597182becbdcf78f167b260bb5cd6b79681f7ecd7ec75c241f90cb40b2d57d108bcc1b7766a63002af1960","priv":"58285cb1f39d00c6aa84a32a69e0e108ca80e33e75b7b4890e182a7e19485a36","pub":"02e4194b7eab20702d498ee7eb7cc98c3ac8d8b2fc63aa66bc81aad93bb1aa3b71","addr":"9b8ded654ae3336405f0bdf768d4293c462ed51d"},{"mnemonic":"century outdoor world grunt member stuff holiday intact property race mutual vehicle","master":"9b9fcc1fedcf63ae9fd216f9a7253f85cdec90f9b1fdca0c36b03169a5860ff6","seed":"e39f8455cceaf542d4062d998b8de4d7e153e594224ef7d7069abc38acf479fd2485f0821fd9af2116c58180f0069af32d10f0b7222eaef6622de83741824999","priv":"e7b4c942473ebc56868904e588bea3342f761528ca90f2add423e17615ef80cd","pub":"02059867db3a2ab4307a5ff502e9f89c45837927eb2f2b75fe55f0dcf25df9e1ee","addr":"714b9aa6afc10a40d702076990a451dc3ee4fa4b"},{"mnemonic":"world trade divert sad unable plug stereo autumn father ankle biology clown","master":"dae1a9e15469905d0d20172bbaa768be4ea4900594080499a56a69d1ae6d0557","seed":"50169fc286de6432685d85b4352908b079ab4fd11f1d8c6a82093093a9161650c2e10d8407f65f8cd1cf4d9d557590f21f5c717a761e7918ef8ca9b73f410120","priv":"4cd8309f36881d1afbfba66b9fcfa09f948d544db0baa3d81d3bd4d2067950b7","pub":"02a86d26c5b309f49017d4778b13be315cdd1d7c3baceeb61fb91c78bfafda4447","addr":"36e8463e55df56e01fd08b8fafa3ec1704ca5480"},{"mnemonic":"observe minute art scheme pear lava search dove cube entry orbit worth","master":"b7ad8e5b587bf747fae6c42423fc4cafecde0db7c9443d48afe10115d95f9b93","seed":"f3ac2022097390a9a0ae0e47d7746e6bce017d15d97ab74b1f99f70ed1c1e9b3534bdafb69e2aba1a7fa2ad787e9ac6b408f2259259ed4f744054504b05c2001","priv":"63797b9d76fe914825f90664c4a109501be006ce9049d561b9f6798d5e518c33","pub":"028b851a2e41625548564242b16e4bfe07cbf685e2df45dfdaefb4aee9fcd607c9","addr":"16d7f83a219857fe095aff5c31e30333e06b329c"},{"mnemonic":"sphere diamond electric milk furnace uniform tomorrow fatigue mercy isolate judge arena","master":"f88c8bbcf7deb1636c5d96003a2bab945a518278d9d58782cc9e7c9fba4facbf","seed":"5660e5ac88a5c43cf14cdae6929c3894ea5aa3bccf3307f85f1162880562ca352153fc1955b21e8533ce844e79583ab95df0c4199b9bac4520ca1c2821ab4f18","priv":"700fd3176db1c0988d7c35d5ef2cd109c7f52b583ae665011f5d476e5a7b3ff5","pub":"022efb00f6c83d296a12f787239fb7905b7f0c27e4fbb62ae62fe43a91cffa9bf7","addr":"7e4a94be643599be266227f349d4797fb7befb89"},{"mnemonic":"syrup unfair confirm hunt flee armor limb travel hint ski mother credit","master":"01aa87dd513611771cfeee1a39986b13fff29760f0d4c7cfde678e70fd053909","seed":"0e54e0db6ff149c9c572a14c3902fdddd567c8ec361ba3bcccb3a407e3e5c6767ec71eaae2c75aa1fcebaaa95e14920e803d824ae4ce64b13413734dd4526836","priv":"72258e31f535c698fc029b953da4c0a89448e5633cccf27e3e6680bb895dfb99","pub":"02b9e8b06d6ef0ae29f911d48c7facd2528a45f432efb4f2c1f1eeb6056380de2b","addr":"90500208588f51b84399e4ba62ffb653d513cd43"},{"mnemonic":"embrace travel lake capital dream shaft focus kind card hood enjoy memory","master":"04e38c8074b77f3ae174593b3c69cf2f55bcbdc02bde68079691e2d8f4e26e6b","seed":"f9d883ef73a830ccfea41726a150e50c9c51b9acda9e4d022c0b8852a57f6df5d8f26542ef1bfaf83eddbe276b8f16cb7ef151fc512dbe005e473a64a5b84250","priv":"3c1b914b34fb0e5866ef082def1cc4fa589ac0d7be5813621d22fffe68b0d4eb","pub":"0381cc19aa68c4ce5bb656a1ac6d1f93375ae096826f99b46548b69c4a9d07e30e","addr":"2b82395c3c65dfe0c8a82928bb3a53e745e29d26"},{"mnemonic":"rabbit choose combine yellow permit raw puppy interest spring work wall humble","master":"04d834acb4020196f894564e1fe631420ce9e801b27bfdcf221c3068aecf3eef","seed":"1089688a78e4c6e35761aee10a12600d9f48eca57d239eb4573b4ccf28925cf72561c2921b31bdc5b00a222c537ef8c37773cedc7742f61633f1adcf94dee039","priv":"132eb740a216f2e92c7c5f96605ae61824ebcc4fbecddfd17689a1452fa174c0","pub":"03ad014b5a58c19ea616716e555dc7f30c67b5fe06bf77cd91e179f8218ddf89fa","addr":"8e05459a88d149b8473c0411a175c0b070423e05"},{"mnemonic":"bracket what unlock tooth melody wire chapter verb grow direct spin rescue","master":"f64c4e7a30ad534ca260cd280f1e8a6055e63f546d57e61071d5c7937273b4e6","seed":"56ad6c16f5bcdad95f566e8628fcceec9f00cedde68816077e0b6db1c106fc3203052ad334a0fa4b232157ba09983087d853240495fd010ee416a38cd3158108","priv":"37f99cd9868a0e44bf26a0a3180cb13f7e4fc0e379cb035b30bff23dac6518fa","pub":"0218c1d6b479b4a8ed804f62c84397d0ba8405a1a266c5318130f0c8473a60412b","addr":"224d710168a45dea667015231a3b8f910ba91191"},{"mnemonic":"position nation recipe recipe friend defense friend engine that leave match finish","master":"15aef2c47f684437bf88e44e9e518a5c517f16e163efa24f1ed8414d5e975933","seed":"15df2473af5b7147abb3b7d17da3d9668901d37ccc86ff652c9ebc75b596e8f3939e77ba39194276a659bd86947a50fef8ba147058db007232a4648e8c642ca9","priv":"59eaffd27a11231bdb4b39137e6667fe2c3ed81e6ead13818e4cd966729d558e","pub":"03865fbd6db962067b2547f69afd7effe57fb3dd3342bf5255ea6d5456dfea0842","addr":"0a0c1411a031ffc35f95c214e9a580ba4eae6c02"},{"mnemonic":"sight broken hockey empower hair never bean beyond glue small coil barely","master":"b6847c7371864fa8e19e57718425d640a027593b535d779b815e003098294910","seed":"3ad83d292efb99c2fcec6c12433c5fab6d250ae5895e0da6f1db3103bc12d82527be2853711532331280d3defa5f8bfe58fd325d11621c9a10b5c7712b02821b","priv":"9c3f71613d8ca92267a45b562e39e7e12305473be0a6498b3d2b9fa4c65b743d","pub":"02f9461c5bbb2e8ab8281f1384b5f0d412abb970b82e43ef0f1c44b9476319d87b","addr":"501b211909a1647afffe57f1ab7754d4c48940b4"},{"mnemonic":"pause usual cigar festival vanish direct amateur bone orchard cloud fall fat","master":"acdcc1f311b27f850eade92937a5d7a3a9ea1513e2ab5d08fbacba42ea267c30","seed":"cf00b72b84afc0e4b0e2480c6ae55ec1c5ef8eaa0bfa531432b3e9578fdd4ed5199cd24ab22e1cade76f0b763d901becebe686770f3409a8aafd2ee89f111b00","priv":"f0412e04a062aa3cb70cd68fcd327446121c76c33bc440ff93f63e05cd1aeea8","pub":"033708eb3564ba835b779fbce8ad6d64501333c05d0fd798c92f926256464149a4","addr":"92a06b244988b778f0986502d8ffe1804f78d10f"},{"mnemonic":"caution unusual response boost dose jaguar nice exhaust chunk tobacco cable toward","master":"7c584d3382f394a4d07684df15e04c482ba0dd3c8223a97c92c091bc95d2021f","seed":"17e49b743fda3aafe81ad205605dc7012a2096cef2475b7b12e79e54b625de459de8661ebdfacef620c851a11a0237c781ad2a84e7e30abe42f63d8da460267c","priv":"9666bc12bd5dbf4eb4bc1a8acfa021ba8f862e5551d16dd97e8e49381259196a","pub":"0314e1d0b675c88061db3d87de6bf4728ce8ec170bafc754f4fd846341ddad619e","addr":"9b695fc1b1429ec5f697df05a1f4c850489830c6"},{"mnemonic":"dream walk typical enroll knife gallery kingdom dynamic extend course shove power","master":"a0bef19259cafacafdb4854e37f36b332066b5c571538e970a7057ca0d97db1a","seed":"7d2bc8f37a8215149b75577f9efd29e0ada9f5db469e9125883804162dc7b100373f020667c06bebbcc593452dada790237ba11ef638573210d2fe67c7e7f205","priv":"370caa36a7e3a5aead2d4abb58d57b90299b4a65484613e5f39b0b7d1733e1ca","pub":"03bfddfb81e4058e08f3ee57b06065194c252e2a31b074acbb15cc7c5f6487368e","addr":"6299fc81f05eb71fa12dc69b2ca4ddfb6514af29"},{"mnemonic":"apology benefit donkey van target neutral success hen easy capable smart stuff","master":"dd96dfa3d46e0bf70df538f0da3b94cdbd7c20e170c8875032285ed7f6654ba2","seed":"c3e6214d2db9684e4c7022311861a013853761ae9900ea823fc4bc6d70bcb8de98f100664f0a04d32e18cceeba41539f9237e89400cf94e0017fc66622a902a8","priv":"3add5757d65ed58816a2b90411d2019d206b56692205724d6e412a26da88abe9","pub":"033607f86548d8e432cc23c8c995749dbb0bc0731121b90b952465fadec31df521","addr":"e2073969ad58513da3df1225e5266e03c0917e46"},{"mnemonic":"sing eagle hello october action alien equip tongue riot pave oyster fit","master":"03f58c7803af441682b522de573e37b218fdaeef55d9637c1ff8c58e01e57564","seed":"7b9cca7d24f97bf461619b101ecd343455f9b00146fec997ddf3e1c569c615e010cdac3b6643a6e9f4ec45be954bfde0b0320e86b0e869c121ca0adca7d11b5a","priv":"21f52146c31e0a6ab9016b717f0435b36847d5b72d83183b3719890171599068","pub":"02f391dc750aa937a7b89dffc9543f72e73d6939fda1c0d74dcf99f27140656307","addr":"7719d5badc862468acdaae65afef4e1e2ba5fd08"},{"mnemonic":"proof symptom trap diary biology tail cement interest fruit tobacco soccer prosper","master":"a0e4189e097622681654ff2b346e79bbffb8e4e7be139567fba8b2c6aa427096","seed":"557153d485c01cf29622ee3a2e1fdad38c815a7cfe72eb18c85605a96c30e38b16ab37d9a2be07cbee7a211e911bdaf460d47a07d83f385fdae9217eb70487e0","priv":"57a2ee34ff6e6cc2dcc3fe3b907cb44fcce0251013877d46b04e24c9aa20ab73","pub":"026172d3d801fb6e855e2eb0f1171de15e6823bb13002b4e9b01a41cd430da7f69","addr":"a1a953df8d8ff38614bbed7ea9f704ef98a37435"},{"mnemonic":"wire gorilla pupil since trust open amateur evil chicken razor minute science","master":"bb549a48f5610f28b23bff00b8b0de2c93bf4e093400989632c98feb3f45967e","seed":"b05c272f522ec2c53dc26679e207f2c16b6506de02e8fb231175265445218fd8617222a374beadfe1999ed617d5a1f89e0a93c85bc022eff6468c4646f3ea381","priv":"2e96c265f6cafb5912bb2748ff4e0d4b9e960d0b4fbc92967a73591c6d7f54c6","pub":"030d6aa64cba047b2ee2c5af2d3893e17004e66762696e6375b09e32e3675daa21","addr":"e065248114f65902b5cc3aefcc1bbbec4d7ed597"},{"mnemonic":"deer meat share below retire when crash original boy wide leaf blade","master":"47f23c913c2e53d34f7c5d869fccfc07a9a5a7a2e2e811abf9781c69aebb4ec4","seed":"7f1a2f19bab3b121415adf5ffc709749b009fdb90df35b6f3b7d17d8eeeae0d41e0f37565c5320b90edb50076d712aaa5e606a88a44460cea67cb686f1886984","priv":"dcb974cc926c246144d1e6c1c5b3babeb4de3be7dd24ad40d6fbbbc592f384ee","pub":"038d6fa489c22c5a8d95d6931144de5d61748be81076b8cc2f6a0c928065f098c7","addr":"4c8a5b45086b2514f8094d3579b2d420b36f7af4"},{"mnemonic":"accident symbol token cotton enough false cereal verify item army pulse sell","master":"70b049648afff7bafb6ac1d8f5a2e2d78bea9fa93c2924f0cba70d4aee27dde6","seed":"d58819c9862ce8078a2b4db0a25434f03631bac4143590f1a245eed73d41f68f0ab089753064eb879b2edf1a56ccb83d0fa88721cbe2ce05f2c46c040dbfe14c","priv":"ffccb427730c5e0b70f535e6ed079888f64b56b8ff51a7f5be1f1312ab63567a","pub":"03e4300d0181f901e200b71f607729f6db5b422c1dccc6facd28f7c694975d2bcd","addr":"66cff13f2cef89b9313377ef24b4a1fbe2851a64"},{"mnemonic":"modify monster ridge bullet lazy sweet output acid shove hire warrior broken","master":"014daa371dd0446424b0b8cbeacbf8209c5136f184cb97346e82ed155b535b58","seed":"a5c1919d9fab0049de70600a275930979ad0da3a3da6333feccbb1aa41ce461ff1bfc5fe0fa6db126fcd96887dfdc2f531a522fbb90741aea5cf2c7dbde8d585","priv":"b66d283958f01a72683b8c7637dbe3910575fa853c7cdfc395904dc73723fff3","pub":"0298afdd5257542bc7918449a8e22a85c5c6bee8311ebf6c712da73232252ac3bf","addr":"22a6f55327b02536e91a046e9a8347c38be6f111"},{"mnemonic":"economy relief sort silly pizza trick urge harbor coffee flash fantasy sorry","master":"f1ad3c0e0551b62d80ac54f85aa89c9f241f0601397b1b4e12206a67479443c5","seed":"d3abce93f99595d45d0e9eb84aa18cf836f0d7eef60345b8eb2a9d4c87a8eccb7a0304907adca904503d8211dd31ba96e076a4b2eaa91ae575d4d1f7c815e670","priv":"4aab4cc83a2acee81a99bf7fe4fea79cebf133b1a7f0fa3f583912efd60a8525","pub":"03b241333aa683b8319975cd9ab2b046cb7731459e79a0ee9facfafa85bf0a31ea","addr":"9ff29de09deaa15e5050b5156754f9168ddd6df8"},{"mnemonic":"wage thumb correct coffee salute rice trade middle monkey height hint plunge","master":"22c4ec2703eaaf2de49e585a5ac5b7e17340a07523aa46e35503176a3a53fe28","seed":"b93e4f76a12d3cf66af70b58b30a66d5d648918be7d5db33fc3d573d6ca546f39490d3101dd686185e61f4334f4880f1e52d94919b358806812057aeda57bef9","priv":"d5e46c667c3e8c08bec8c7f7dfb1dcff3a628cb39f1eb6b8e117ccfa96551354","pub":"03219d1b8b9d5562e550d0fdd5cb6227988622d664bdc48fcad2c07dc78b82f1a7","addr":"d8f9a7f71ad4a92a07ea0c53a54395895fac7134"},{"mnemonic":"miracle penalty base jeans inhale state roof size tent chair life afraid","master":"82e0e8ce42e1a391f362bd19a0959529139153e6102eb5c947a64ba6b8699c36","seed":"d43f307257db97baf0e458c06b0f509e5534aea2bf8e2972eeef0a5408b9fd52a13df5b73adeccad68ef61017d63243dedcd167185e10402e7a7c03c88087527","priv":"8a82fb302c3b5cf10e119ff3ab01a036e002e9e2d49f0db0a40d5b6828291bc4","pub":"0233cb5096a11a4c79e54cea37e42139a1198a1385cf4e0d37c704352aa3551a13","addr":"e019149a5036bbaadf18788e3be72fa5292a2bed"},{"mnemonic":"stumble army virtual virtual plunge until pudding universe suspect palace bacon dream","master":"32da9154b165c960e927f0b01be8435f2b6ace7dcecda4416a449a50aaa56774","seed":"72bd5c92a8ab4478fa1dad0761118bd3d9a1ce6322c00f81b527701a74e0c4aeea63238017e64d4acaa92bc61af2c41a734d90567799ddfd15deecefba60988b","priv":"63c7d3a6da6149655588c4fab367f187f940101e99618de1d01963aac0dc639b","pub":"03df276b793ee770816ffd90ce2c45b6f24558bb90cedeb19f17264beb53344b29","addr":"03c20b0d41439a374a8a84ed7f139382b6b012f7"},{"mnemonic":"label script force inside outer pulse style nut meadow design receive panel","master":"bb084bcc5df57ad10abb3342888508e399cf723415d35f5440d0eaf808a56d1e","seed":"07029905fd6a538b5ba773384b0084bd11b5ede855a98189b8ca1b3b0457add4b365f98bdc75874ccaf85882c5f1aa59f0f9b77b5a823178cacbb4ff72d0969c","priv":"91eaffd2ddcb6d055c1ab3c7c87e313ba520c263312a6f3d267d41018d7cdec0","pub":"035bbb055ca818cf974da73d5d87d7cc447ff5b9dcbdd39552fb28c925c2077636","addr":"baa25da619099b41aebbbf1282dc6af9dc268664"},{"mnemonic":"nest decorate update alcohol system panel cool grape mind ivory ski dance","master":"64666caf25c290b5f46e27737e61124c34cd428b0d1a09e88ec47cd059765729","seed":"8db4806ada7b82f0811b24aca3b0e11d087cfc27e3e83b77e29c7d5695a126f577304e443f71b3de9239ca743acd05563c1f08f071eca5de4a9961fec463c372","priv":"eadb5c2704fe1eec4f121714b3a6d655d9eb985fae7d535c6543df13214bbfaa","pub":"022bcbc7676ad7693e97a587886293b6190edea96a339e225adaf3f3d6c493851f","addr":"5310b04cdfc366f6268deaaec22d7c628dc4b1f2"},{"mnemonic":"section supreme grit scan arrow flower rebel trend film sting govern museum","master":"29616b872561d14ef56f4761a29da1c5dc768092cf7eeb4ac28aad39e35ab274","seed":"4b8d6961db3f7b123dd71ba5fdc1b7809a19d84dcf25bd1b443b610cdbe44e5d5391aaaa4374ae9d6ca988b5898dadaf5fb79fcc09859851538842cec7acd36e","priv":"da2a60ed2f49ed3b6c1ff78698e3eedb2d9cbe9a707dd91e047f8a17db4f8e92","pub":"0304262df894cfd35a5330eed4008630b6527971f58075282290a070906c0d69a8","addr":"656996e8dc55902fc01bd95e93edb12e1e7dc440"},{"mnemonic":"vacant peanut senior skill helmet absorb turtle regular inmate hidden captain street","master":"7c329d40208ae70f5ecfe8b3a5930adfd09a2f618098e549c972036bea9fa4e1","seed":"b7fb706e9e43c671d401c374984ba22ab5465e15d8572eef3c3302a3fdc77ec8b5cbe7b2a8e42fca582a74fbefe6b755e442e6389592a0845aadf56975a4b212","priv":"29ea2c32ecc076c6e25dd9cc06b9736d730a8306a007df2410143153ec0d7402","pub":"020ee0b300f1714f378676bb533ed50b8336bd288180f4b55a338bb1ada82e0054","addr":"dfba016ba98cae2160c861d8e5117b5afb76a50b"},{"mnemonic":"setup asset fan host pride decide museum fashion disorder coconut school cause","master":"53bdc111a1d4208f6d04234dcdb764ca24c2f42d7dd1de46cb69dd00594f9c67","seed":"0039f1f4e2000001b1af4c47f72dc1f8347a6b7c0559a9625881eb6f7492c2e1fd186b778fe30540ec9dae03de4b8e4ad414ff5692490a547e1127ab03dfadc8","priv":"899611b8bfbc35a6bbf5cb80c193463849fa665aaad680d576f910bec97dc8f4","pub":"031a099725389ba4d2fbe5509cdeb5893a14a7d743a6f87be7af37701e99be18d1","addr":"5d12852d8132e60b6ed5707c4a589107c7c40c72"},{"mnemonic":"debris bus thought unhappy coconut sing sign piano exact favorite zoo title","master":"c2d02edb9583033a0db1b44443769d5c7b9d545aca03ce9d1db0c90c97e648b7","seed":"411ae07dd870bb2c367b72b5d131853088b501476fe0e09896004271dec37068722bd8952aede6c4ea32371361842f9507c5854f7e95b6e1685d8315c4a635fb","priv":"91047f9554ccc47f0c641022c8779e064ccbdf969827d374dc3419fd462c9ca6","pub":"02a6a4280980aa2a570d54d10c295a94acc7d22040a2299c79b9e72808274dd0e1","addr":"f1c8da3f0438f82da710f6e2604b5adc033cc0d0"},{"mnemonic":"stove romance diet season ramp mango swear behave rotate steak alter parent","master":"039f8ff7fd7e498c643ebecc5cd54018fbe4aceb34a92877746471c3d9446517","seed":"2df95585063422c193cafab822373fbcebb38780acb2349ba1e3d5b98f3a5c63f1631fad81649fd22a5acb3673c3c1cc4c93c6fac5e28bf9ce2c2d25a8215543","priv":"251fc43c061854edae6e1bfd0748770965d44ba5c0ba1cd9784aaa07a17ebed1","pub":"035b5a07e862224a2324a8bf3af20fd4dba7157baefaae03124b51274c4b50b48f","addr":"14f3a5e955fe78fdd87fa3b0eb3ef3195b7bad3b"},{"mnemonic":"cruel equip glow protect trade clever charge gadget valid inspire canal unable","master":"e47ebf7c8d4b5f5b80555c25c8fc89bdcfe7eec0d39b2c18adabfc81c90b676d","seed":"5eb48012a0412a9911b697a3b838605813f73a885a967be55432e73870d703f8db4649a59483b1ba26b739fc39af73e4f3f12d78648e78215c98c08428e5cf15","priv":"fa28e24225703620c1dafbcc09015b04b3839f8dbf170e454a8f6216c01f7800","pub":"027b56b3e5859e3df96d60366bd54a5024ec84efbba102ab1b4c85383f34b61d48","addr":"23890ab09f410c91db179e68ea1d942d25bc0c34"},{"mnemonic":"nest wool midnight tragic exit enemy knock oil tenant survey opera sense","master":"7074c03dfebcb8ed77af28e9b01b77d803c6f2ac88b61a17ae902797c82cbab7","seed":"c4740919291e1af1c7986906a374b081f0386c40601e4f832cdd3f5c4a453a0dfafa1aaa02b00d98f49803a16baa8cb64bcb186c4cf045eb803d8ffab66fd54b","priv":"1f0dbcbe498866989dc0e0b55e6f4b83b93ed2191df2db3ccaddb3f789e434f9","pub":"0396454c50b1a4ce149ed251ebfc6ab07f0d4c42ae84a80c90ca1b64112bb3ca57","addr":"8198e949ce71c8a950f39a8a691f2ec180106997"},{"mnemonic":"brush sustain penalty chalk palace slab learn decide agent private pigeon then","master":"3acf99c19afbfe290a99911c085a656eec61af6f976623c9b6d2d1500e7033dd","seed":"38ed979eea68a00495e0e4c045cfdd1cbe5aabefe628538c35a6debec1be144d41745cecb2003dd870dd87c4246b64e6fa4662173078ad7a4fe471bbc14ab9e9","priv":"1424627b12902bbb162cef56ce5609ac356e68e3ada9005bd92541d0d8766559","pub":"036155ad03bacc613c9fbfb87294091a9bdb7845e58231f4d585603153871a8c3a","addr":"1792e857fca4355189ade1f45066dad9c986e7d6"},{"mnemonic":"autumn sudden learn laundry erode claim exchange jelly jaguar vault deal humble","master":"1a616c74e30a912dad799fe8d65d6ffa77245f89e81a367310fc02d08be13522","seed":"976e55f1fbcebbd1e448edbe90d68d407d80bd5ae197082bcd7ae8e7a640f3246e0057c65271e9e403297b3725a895f15c502284ab342ce1416f40c892bd73aa","priv":"701e7206d44ca9269e1bca00dca53d7287d55fc39214ed4c7e8f7201a68d6792","pub":"031a31e47cc6d75f0652de6698757b8fb2ed1ac181697158f0bd50ec6e7abdcf65","addr":"a73ac9e548e47d6f1f3ec200593a6693297a9143"},{"mnemonic":"priority dinner offer glimpse sudden light work absurd unknown process gas tooth","master":"d969ece198e95be043e46dd8ecb45cd2e5bcc09d8e6b00bfd7aeb59eabcb0ce2","seed":"aa9cc6daf79e31c5e3ed594dd896b1ca39161add5e5a7dba0159f4a8fe262c51d742e66a19f28cf01f32a90fafe5195b0b359e87f5a5a60e31d883ebca08d433","priv":"81d13a5954925641ace6c24f38c68954d782b094002a689500f015a401d5c6cd","pub":"029b1e4dfd01689451ea069e8a193de0b506d87faae6eabd9edf5dc49633c0a03e","addr":"bb2704f3f0270cab3a5fc918b58561bc1505f718"},{"mnemonic":"glide sadness text grunt burst balance ask hair include refuse mom advice","master":"5a105765bef30fb458b9cdc3d6758479f003f96bdfc1d0c21ea1e4987f768ccf","seed":"0131a60482c920093bf7b7375a70bea607a2015bd0bc9deb04e99d214a0c3a4966b21c3bac01544f816a8f4c3583920758e70f8991506cea52c9450c1972a9b7","priv":"41505f80b9b0941d93341815a72fb32dea916912e3dc1b7b7c763fdfb5c541f8","pub":"039df863578cf71fd48dccaed45c21d1cf176c924bd5ed8ec5fd8dc1bd6fcd1a46","addr":"396984e26d5b3a4cc3cf4a5a868ac88776541564"},{"mnemonic":"jealous subject gap april eagle goose double door dynamic robust impose ordinary","master":"ceef22480f535024fa3fc2a7cea96559f4fe8133e45301807d3213ff7e49e0d4","seed":"52d4a03cd2da0a541450a4530565a5901953d1f3ea0ee9440748c1796a5b8ec8ff674a8cf3ee2fda215a720f0fed119ccaa97619f6fe76b736b6ff804c2dc299","priv":"308bee98e778b1037cfd69c0691b6cce81b1935c776a8473a1b3a49bef313305","pub":"02ff9d7bab97fa367a753ded100c11ca4bee7173c04ddb242fd928502a58149587","addr":"7bc8cb221d4de586491bee3016d9129a42fe0527"},{"mnemonic":"panther camp coconut patch blanket census able melody bid sketch protect illness","master":"aa867cfcb578d828df3a6cc4ed1496f3af72f94635ea82574bedf2d88f9fb0ae","seed":"1bf0752a4872e6a4bdbf9f15dcda591184c8e1c61910d958642b376086cb9db6902d7ec0997afa3a0872ae3fa4fa7751605a4b3a3ccb3e4fb5a6afe26e2aafad","priv":"ce6de5f65b6a0cc1e9c4f7751230aec5f2b5401686e7e42b81f1d8eb55f77303","pub":"03f6c0da8154df0baeb15a7bccdd79252c38901ce2dc59e6e08d2d292bf6668a71","addr":"38a888c98b1f68797a879b64e5907b909f81c386"},{"mnemonic":"great history exit include clean have vague stick victory else iron trim","master":"6fce540ed685440130d194a3e8af78417f9b73df783721ccf184807b3973e384","seed":"2459cdc80eda19acec0c704f020082b617952f652b109c268035607139ba2710dcb8dfaf546257f09f5a1b19dce62e83f603f561d2cc2fefacdac6fc902d311d","priv":"26d08c2b95d15b5e1313aa62cc275b10544f0aad3c2ca677426551d5a039a551","pub":"02d165d97ddc4cb451d52895521d7c0cc217d1a004b9a760aa3eee40edcba4ca37","addr":"7bccaf7fc14e648667e8d7001f7b0777bef7813a"},{"mnemonic":"pause you skirt bundle opinion soap wall doctor head method tent lava","master":"b97cd03b20895737ec084f536ba06f459831e6bf2eab51fc4097ca943014f29f","seed":"b661487c12002df5c65a204ef12698be70837ec522fa1bf17d789d0d0cd0be443a819e4c6a494ad8d66a8ebe25ddd833d6ef7d9dd80e3e5e276ab94e0d572e5e","priv":"6860cbc7b6017128bff9c6d48abb20200aea06a7e8c9168d46f51260dd7125a9","pub":"03d7666fd2ac98121523262fa6695c719d3ea6fbf8abac8266b7c8550a498a55fc","addr":"6a2c9c329b85c35721b69d2885cb8ffa3006ef1c"},{"mnemonic":"senior liquid release beauty echo castle honey limb junk carry clarify high","master":"b3dd9a9379270f2bee11afa64bd9e49e4d9f44fd997c383d651fce6b54e8a82f","seed":"4caef4408f37ba86781693fb979534b9c9534972c7b866f74318930f180a2a36875960ceab41e8725ee4e25f56d160455f7d372a7d08282ddb5d7c1d24f14daf","priv":"6d9ad9c1011761fedce7f7947b5325622ffb1cd6283eeb22cf5cfa3cbf214e69","pub":"03f173aac293bdfd7a98b5055feef56e70d07d3e0549bf278bcc7fef559c0a413a","addr":"93ef2c58e7de60d861c0dc994add27a914477d20"},{"mnemonic":"scrub pupil rural fat taxi area example spring doctor ripple obscure asthma","master":"bf805260160dc14eb96077258ac64d1f67979f7702c99c411fa075a3813ad57d","seed":"ece2913f94e791b8c5c37dff29cd19f9725bbb0a1d84e7c3958eca1b646858de1b3188c8dfade823903a4b4fd12b892bf55e570ed68286741dd02aa4ccb08820","priv":"d158bf7adfec3d4d7f941fd9ffccc1c089075fea66fca2039dc4e2b2a7d1a000","pub":"02d5c76872253c3890a8e1276ec4df0c874fcd46d1f7b84462893776b6d14fe972","addr":"a98c98b13f7cfe6fea7de31de3fbd325648a9357"},{"mnemonic":"first shallow crawl asset vocal special rural bomb random pair shock live","master":"a0f6894a4375e267aae6dc2d23843375250b44bdccbc63d1436a2f172214f928","seed":"7518a5b622fa57389790c2484ad833c95e5cf2caa12f71ffb0fad4c9fe044854ff1f7e97b188545679ea936816217d2a26204a0bde6eb7335328dd0c86814bcb","priv":"027d54b7a844be318ea4442113e4cecd464455e239c0726236e2cbbd4c559fe3","pub":"03f5c6a2e2a82d331268c789527b5ae6d3f36e3fdcb344fdfd7e200d5243b075a3","addr":"bd4e60a76b171fde2684d4c7690e8feb7ad06854"},{"mnemonic":"famous vital monitor opera strike coffee shield throw emotion enlist east smart","master":"f1a0708b891c80724310e95b29183394390ec56c3a6828bb4ec394a39726c256","seed":"61f06f35b43abe9256e635720f4e74c8e3796ed4222c8d914c3ceb0f26e48d9ff772040475acfefda1a907f24c369190b48f50feb2fbebd3a84c0c9d3850ff14","priv":"8c2d6f4673846749f8d2e2f9902f28f66d33625d0ba04a11477335390f908552","pub":"03f8139b274b297d1d669fa505ab797a7caea82e76c5d7a3341c71133fe3dae164","addr":"bc940ec509f5275207ae9b086be155154aefa3ad"},{"mnemonic":"flat cushion trend region glove humor below edit ticket west multiply black","master":"2e72ddd445cd917369177b7060dfc92883b4b56e301dd6b0c7049517c102ac22","seed":"85ca476c295a5b708beeb6af45aad1eb6bb691fab82fae7c6d4dca48723f7819551d04395581ff769554ddb94e0d065f4c710afa7674f0c3480c1c2c4299591b","priv":"a57387ddae40887dbb0f99e8c84c092ac1fb8e245ddf3c9909e189ca2b70d52d","pub":"02d19eb0bd72884a3d753121d0d4489215a369aaab5ad3bbecf47f2246c5ebe928","addr":"84141ec76f71f2bb4dcfc9f81fb5333b9cd1ea8e"},{"mnemonic":"domain produce address tunnel burst emerge divorce health frog rare cook series","master":"983fc11c91dcbfcb3c1869da88972b03f7cc51f54db49533c012238ba89ea234","seed":"9d7cf4d9d3c664b8e51db516449d3dac01d290d774cafa90326e0464290faaa6ed6b780f792e80955ee5e6d7aa8ce0efdec13c20ea0fd88e5e40367f6df818a5","priv":"b96264f6b7f9d01e386ae43893c2a6b8683162394bbfc8048dedd4ce129e52cf","pub":"02ac9b86bcb1d8c6991572ce5044b58560ddfcc25a26dc4c74b12271c263e9f1e0","addr":"345821fe95bca3c777328a7148106d46afad6861"},{"mnemonic":"dutch oyster switch layer rapid fat prefer bamboo stereo staff spin midnight","master":"47d4c05e953b7636bdaa099a136986544444911d1fa720575872370f2aaec934","seed":"f120c319991b7564a6bf0086d918b39aef44877b361883f58db6f95551a66bfffd1f9708140c07135d40d624ab78bae8969883a2239b4cb6de5270aa5eef59d9","priv":"968356e312506427072e2e628a136e6e0104e3b9f74d8a00f384da0d62e58a30","pub":"03efbe8d47bd3c1c6ed07bbb357e6ade29f46d70d204f4af19e5ccba2dbec7c811","addr":"27bbceb99a49bc927eb0d6434b41c873ecdbe782"},{"mnemonic":"green claw tiny bring meadow tone improve advance federal talent drop fruit","master":"f0d9b5313bed52a853a177c338cdfa1080fca511d1a3157e3aafac06a6a753e7","seed":"8acbd6c36b27634ea9017b1ff25913a3b6aee3ba578272ea70d753dd1390ee31e9b0a7685c76aae5bd0e3cefb34fe6d077a7aa0a1da2fe3a2b4d8592907f7c9b","priv":"633d8cb5c8aac8d9e8f3e540ffae0f9a2fe54ec4b9f95c4378927be49f785bb5","pub":"03479063239cddb13d026158bb3519ecb95590d0be4abe036668f3bd134ce8b0b4","addr":"5a6321ea26d9fe346e9af87801f30f823cae4e5f"},{"mnemonic":"model famous make lawn wrist busy food envelope town menu hint dove","master":"034f244b9742152cc762f84ab5fcd03ea6020e30d766d209240f4a1a4bbf4859","seed":"79c41d550c0fa03c15114feb0492e362030a17a72d2e3d05064d459ff8a5ae877c2d94243615ea0f41bb82030e0401ea6a51eebef49c520cdf9bd923f9427e12","priv":"3dc937a202f6c5f20a3d57c657f16269b84f52a4701da93bb1786ea0711335b5","pub":"03e26c7ba82177671230c877902563ed09283148d9f83f400006e11c735620d94b","addr":"b4faab756175074173121e758b65bf2663b792c4"},{"mnemonic":"leisure buddy divert feature soda reward moon doctor fence neutral bomb truly","master":"9e8c30422c780174c05f3a5c333e116be6d54acdcfa666db96e0bc3587fa457a","seed":"728465a73b67017cff82a9e1d5b3cc77276f286e491e9621c21317485b78766fe8828fd0f03016ec67a9e9a42c355804c875874206b60d474c09e49e1eaec89c","priv":"90c91a0f640add78f765fa475ba8267e5e3533b0175d29150138b659397b0a47","pub":"02c0b78775eaf3515a49cf8ee65dd95e8fea30340601229dcdf2d2dcb3d39b3839","addr":"0c300d4bc57ff741c4c634a063c24823a18b1ac9"},{"mnemonic":"excite cargo radar baby paddle century average nature tackle blue rhythm garbage","master":"6a4cd79ab70b5555d3815424bbb8c232351a14511aaa3708dc4449ea80fa7330","seed":"7356daf4bbcbf682469878ee2a8e7a35d659d8f19095059e7b59fe14d9893c054559bc2beba994c527e8417f86c3f57a69b3f42954aa9a4647c91155fcbe2488","priv":"ae2aca6963de88ac0a4e709c4f84f5ebbc2d1a18f55be9c036e97fd46200ef48","pub":"0304f4343dc04ad6ea1c528296ac17c9d47a42cfb744e311f206bb154abab6ff59","addr":"ed8d1537a6fcf980fd7297ba56f1638935ae0fc9"},{"mnemonic":"must trophy era antique goddess local green rhythm gift van target island","master":"52e55a55dbb99a2b170c489c99d50811c47be205294704a2d6e7f234b2a938c6","seed":"9797425288539f83d965bea50c769e5a681c7fd6860502bc7d7d953a36fe16d8f0af0e6441a92b421cca44ff0fdc17d6118801dd17814308af5f6f1436a2e28c","priv":"8eacce7419f6f8b94e426adcae21818ce6525f0ba624bafdae44f0838d36676b","pub":"0244ae10f79e38d499c76996fd6ace738b1fc3dfa60042775f200315cb1e827855","addr":"15b8bec456e7346a6446c9679afb13a7e4e82079"},{"mnemonic":"day include route train grow number traffic across acoustic render save gadget","master":"553843ecb6e4e0383bea60a245b7f34c46d8d505806f4d900c7344b2dd4e1787","seed":"abdb30b82471a0c81df74e7d8f9fc2315b7ed04580689d5ad91f8947cffa9375ef2b6c315b695e642f43d08edcda3712afcd48e86583b00bdf5085d2920ddfcb","priv":"ea826d758734cf1965b67fe0133a2b78aecf582aef9efa46c96c61cb512ba593","pub":"0304501989badca08ee05c3984c8e299e5ecfc91feea52daf24cca7f236684ca81","addr":"9bd24b970d41b73640a86beb27f3533d2bf35c82"},{"mnemonic":"safe favorite ticket bus picture tomato unaware lucky spy creek upgrade duty","master":"8be9a1fc81f80c427683964bc29c2eeb135a3ddda8bad041399e63053cc37fac","seed":"3b7f10be92522ba2544356227f415046ba8b2faae9c3dbef1563aee039d00afe8b476743cce4495c264ed01fc095fdd09e3c2159b9b91ae01f49e5610f3dc375","priv":"114c0269408ee0ad873b847793743f06dee7be10da15d0db533fa682a644a017","pub":"03876eec35fcf39732629c5b3ea22c2309a28549335b9f221001ceb0097ee8565d","addr":"fc82a1a044603663dc758d6987b8b699d56af1fc"},{"mnemonic":"slam jar adult liberty small adjust right sheriff cover below space fiction","master":"75e789f7c7da1a83a34d2a2a9b54d4af6403292156cc775be81ade0edec4d566","seed":"ce1684c7045cbd4ee4c6c23d52ad78dca82e426256dcdb3a5f5fd9c635e0dafff12612e981dbe983e1ec5d88d6bc3294b84f8705cfb553923e397da5044b896a","priv":"bae08dd84c10433159fb11a08f8e3df9fdc503e5cd543a4e9231e96468094a4a","pub":"02269218f35c468c3fead430880577410b580b9dd979d68c94f6531adba7dab809","addr":"5e44c323c10036262a3b02974a6d69f953d0e359"},{"mnemonic":"real acid movie gadget duty hole apple inner essence confirm laptop duty","master":"132081c3acbf9bcedb0a237fbd41c882232976e1bf5467c067892a80f5d30691","seed":"495b41f5b0f22b227458857db55d2787c126b832dfae01384ad0213eb28d79baaadd13a365e63cc7c250504c5f9a2fc5bf38e174769c33ddb629a012219a38e2","priv":"44b3ef5a4c7005846196bd9b7987308ba1bb7923687749509cfb733b3aebc95a","pub":"022803c31147ee31f5fbcfbdb2313c5ef39b80b505cc21275cc01e0527dc6ed6de","addr":"063cf369f1f4122821f7ba400ba1e8248535fd44"},{"mnemonic":"banner indicate tell thing elbow mechanic express stairs robust rival shadow matrix","master":"6e76cc6fe8099d9232c107ffb8959c3c6a24badc35579975ffdc29316ecb2b5e","seed":"f1224c30cb0141c0da3f5cb31632ef8cbd88896e5ce98a5290ab708f5c0c084043fb19a4e360c17e161a3e6122e8fb9d3991c9ed7129dd5ee26bbb2388e9b7f0","priv":"215dad8e633e3ebbacdca2ba68a9747ec69de4d5bf794748500768272445d516","pub":"0259f48c2e291b1d0b29890c10ca516ae8e186d06bec8dd2d966d0b336b9a68a8c","addr":"7863b183b3f98f4ed5ca402c3f1bce45a9d58aee"},{"mnemonic":"boat minute dutch sadness globe congress color sort feature boost regret gallery","master":"6be1882f4d3812eb5cc92b5ec4ae762b565596a01b1c4216f16337663d33f85f","seed":"dbcdc6e305e0330f5fcaf159763664a8decb12dc27003831213b93c241d886ce26175c726b6f899e8de4f2b15aea6af2be816eda613f00a3f8bb3ef3c162027f","priv":"e30847af4ca7d0bf9f76d2c15906c955de0d89ce994abf7696ebbe0880171675","pub":"02a6f99d68bb927000aa3cb6847e349fc7f0412a75869cecbbcbf223707b7fe8c7","addr":"eaa5c8da5482c10d473be2c62206eb82312f3ac6"},{"mnemonic":"icon echo become average ramp undo actress sea water struggle interest trash","master":"d07e7e040dc9b1ce70fa78ff50d10345880fcabac783c380ed43885532d79ab5","seed":"9498c9409da005532ea8fa71aa658c9b160c6630498514e52aec48589ab60207f2770e4cf0f47a04a2d46a878b3b2a2f0f58c478d708ec9dc8f54b51ed1f0506","priv":"33a881e07441283721c695c58caadeb68e5576a526ae465ef48812b98d66bd9a","pub":"03226330049e98e5513799ded19923809dbed40226e958f9c36218e8eeb5cf47dd","addr":"b02c8d95cbc1417b891ba5d5c912a6e3b8cb6748"},{"mnemonic":"scan book mean egg situate dash chair water surge major sugar shield","master":"a50dba88cae4daa6db49e8cdbe710a305429ed2e4ff43c0b87cb0b88956f8f02","seed":"ca8bf187bbde692601b88a74c124c967cdd17810a5b4db55254a22278add4880b8360a66b5d91c0ce1c105f78873994361d2169a3d39bac0807a6ab7cb6b894b","priv":"4ecb295b77c3b1296fc214e554e77fb47df10cbfb22b980ba6e9436a2d884ab5","pub":"02c302c47bb2ead02062861ddb4c876b797607ed2a775317c7ad258c97139767bd","addr":"6f6f55426f790072f9752fd182a68710c2b3e72f"},{"mnemonic":"hint sign broom plate brown beauty figure song stumble setup polar road","master":"e4721371d82355bc7be6836a7915a19917d2efb313eab36abca855fc00f4cc7a","seed":"7f654f0582ce0c83d46e01477fafaecdaa7321d095ba1468ecd9fd6c04c67471a2e32187c02178522d11d9b9160de10c6cfd74eef79d6c50d013044a5e6562ed","priv":"612986c34ddfc5e93d93337f68645bcfaa2bdd37c8a6beeb7d58cab6e54ce3b7","pub":"0309c0b133a0af4f468285b0399a3c3cdaaf8c2b29ef61a4f8ef19d526b23eae6e","addr":"dbd39ec36261d32e313a82b4745c47489de5e955"},{"mnemonic":"eager item digital loop loud drill script ethics crystal tornado pride cattle","master":"1ed90fe65b73b2b50464a59268cc2a7a9bac67f2fb167c5b4714dfcb354a24ba","seed":"2e5bce8308d9ee56a168da570cfbe30f0dfa341df84cbd7674f198b4e419d48c65e1ec2b8600a2e7608bd148291c54ba29e5e7ed0a39d4418eb212ac6d7811bd","priv":"ab27d9960f7821dce58d2271652b42f8ddab5edbc87a23ce3177a0454b775167","pub":"02e1ed58d8c50877a6133c16e793fb6608515accbeb46ba07cbd3972c274534066","addr":"54b513aaef1aba872f8f521bd3b86c885563cde9"},{"mnemonic":"asset toilet hazard chief boy over trap session abandon jump wheat group","master":"43ca7686bc87728e62a5406222efe3ff40d4364a7904f7307437d1b2b13ced43","seed":"e04b7a46a47cf1c4a9382aacf36a32da16724eb1ba82f65a3c66679d793d410d3952fd7bb0c735bf96a089521acf7ec4e1f41b179b09dd75645b7bdeeb539292","priv":"e7295badc4984f21bc64f9ba723a92799ebb18acd8315686b5040feb603f03e4","pub":"02cda17b0a54b09d9389a06259a44004a569a7d862a9397d33f9fb598fe374bccd","addr":"f69a0e9ead6daf22623a1235062510360f0dc7fe"},{"mnemonic":"flat eagle owner ladder enlist chair next good solar drum service escape","master":"2de24f772282ea286aa716777f39a9233b38a5a8018dcd730b74bca33c5bcbdf","seed":"d571b7aca82b969fff273b5d4e876188c5b1124684d3ab8056f69bd521b1d030b617d201313ee42068f48dac836443ed6e8725ae2369a955133cf74682e6090a","priv":"232c2f9a62655637fc64e4173855506ddb4d3530807f4dd441a137981d636c11","pub":"025996bfa0d3593c05503476f4c340ff2bc32290affa52a130f2038b72deba930a","addr":"ea8a8d16976a6d922be30695d49a670027cc065b"},{"mnemonic":"hamster such legal analyst despair robot tumble embody coin taxi liquid cart","master":"f78ba19a1149f8dd5ff019f40fe5efaf8e0c5f9df5ef2a1b32df2b9a0cdaed8e","seed":"9d863569bb0a87d17b02c10eef8aa06edbd9ed37ecff427001f2e43cd4f101def938da306ecac02bc5ee83b886857e43f6248eca72e65e67828f243c625de0bc","priv":"5a2a5c105c9393cbec8cbdd79022c23407c556a503ede10645d744f20ec9ebce","pub":"03a14ba5b2261911010d2b2a7602b37dee944891b1e49d075b6729e62627a252b8","addr":"73ff0ff918c11d261453041ee18b38194d3aa57d"},{"mnemonic":"gun monitor turkey humble private essence limit member bike person cook ahead","master":"c3d138412cb4861effe93888a20e5072f887b2b3d3feac310fc8f40bb523f98b","seed":"6c79ddee8365c1c293e6424cd0c4ad5fa00256e9f8377e5692c3c60c1550cd4e00d3f08aa61441609b3954c271404888677aa4f7e075d7e93ada2f452984133a","priv":"865fdc61a6559f4ef787eb57210c09bcfd82ba9aa87a13a09e62746470eff4b1","pub":"03777c19e60200e1fd48d07f17c58c29bf6440aecefe503421bb13cd347bcd3e6c","addr":"a77712c1f028f11782d2805950c79e11d2229002"},{"mnemonic":"bargain doll comic scan fancy soap fragile benefit private sword share milk","master":"b26f239a994fc404b1aeb31ffd7f0bbcb625c881585dc57247cea88ed890b042","seed":"928a043d2007258b4cea3a478dd6b1cb133ca290142366af0ac60086f880cdec35541f080c8cc1d8d76cae811b5138d9de189557b37dc6726ac1df11ccc9ef92","priv":"ad650db8c2457981a143a3cf400ef1eadb5790368965a5fb8f28e8e0dae1991c","pub":"027ce8003309913c6f99fc6a5eb2020400118e3e253f618a418816e772b5008a75","addr":"67996609609bda5dfb179da0fe5e6c7614ffa922"},{"mnemonic":"father accident gaze obvious visa deal plug narrow shrimp motor pigeon sheriff","master":"643240ce9abd6d36e330c0cf47343823c3a3d4b533f6887aaac16d737c8a1a4a","seed":"9ebd83a564ca724a559e57e896940ac08d28a71613e9b414170539b29a5187a2ee91e3fd4bf258256e26ec5c41af2a57fd8dfd30f054403599cf9b4f45af5839","priv":"adc7eba12216571143e05626980ef0644521269bbe8870545b7cab11838537a8","pub":"023b065c65ef208f46ff43bd1051b494f60b1a395543952e14a3d53a6d1f347e96","addr":"7a7b0429f9706215b02ec49c205ec4710705a68f"},{"mnemonic":"reflect slab donkey village mushroom style brown pen mother pipe raccoon mass","master":"bfc2912b21b64143fa0c5a924573da251a9ca151aafc79a9038b96e21551dee4","seed":"fc21dffbf43c67a07c5333e57d238f07d0e1b987bf4f0ec763f1abce471a2e0fb27e733d5098fbeb81ed9cb2d4093ebc9c565b196c9900f39faf4da5448a2b15","priv":"d34fe09f482ae273ca07b2623d5b13180db5d14693025b57aadd6c7c51e640ce","pub":"0329edd6f8ab6a57ade9179889b4f54306a45f89b0007cf9843755b3aaab725586","addr":"c69fbd3b6e36a75ac8583713c1e3207253ec53de"},{"mnemonic":"lunch process rice hazard word vault surprise useful fiber trouble pride mean","master":"12caee441e7ec1c4109c53e42c8cad66704ca395108237f68953b137072d1aeb","seed":"19033ccf459d27009a9072905bae12152c877115e145eb5469f20ac8d763570d2d0ef57cfa6a482da6a1f2c38e7dd43fb6260a4826b54c0f03f0501df94e4132","priv":"4a2616ff7d529e66e3fb200e7531b4a08911a338e6a80c80182a0b98803eb14f","pub":"03e996278cd3c0374adb59287c00a526fa8a409a53a2606fb230748cedbed12f14","addr":"0f96e89ff4109143a838165bfaa158dd64603fa8"},{"mnemonic":"boring unaware cram sun mistake rule view rubber gravity humble detect zone","master":"23b29bcf96e849e44c0e8848e86596eb41908018dccdb91b9fd81b35cfe24523","seed":"25d1e2d98bbe47da86d732e8975f5c2ecdf2e107b641c6e9a259a49014dc35dcbb83ded97117bde45b0e78379ab0b7785aa8e45e2a628442be1ccc9a98e78a5c","priv":"d2c91726674b440f3aa7f105c17848c1e63d123bdc6ddaf88ecf0e6db40b7d1e","pub":"0367113b62388057da87fe1c781210074e0200b872a7243e05a8c9f39ced994acd","addr":"264fa5eeac6f6b37e249f8ba03168cd17aa7e258"},{"mnemonic":"extra hobby pond foil below injury light brief struggle gun visual recall","master":"80cfd73c33f507495340ad9370aa922b436b84d3f584d7f65cf6173b367331c2","seed":"d965ec811bf471bbdeb7aeb4c0fc43d710cb47fa63806f29661bc1aef4873455c6a97f85e675f6da0e975ffabb1356d310daaad51da951de68927933937e85be","priv":"67654951ada1ef3a6e15b3941d0eebbd1bcecb831bb084dac0d70d610ecac13b","pub":"02a1ad9bcf4e359f15d3a447b61b9f18bf2dfd56c52c20f267ae13b04bd60b0d25","addr":"13fe548ac9d9ecfd28e5c5b5d0b865b89b36e8a3"},{"mnemonic":"copy thank warfare visa else rally shuffle gauge method favorite dirt mushroom","master":"f76da13cf3b11641e547c33aed72ab423b7dbfed236da81ff3759d4ba3ba3aa0","seed":"24e7ebdd3792e56171fc46aa5112514874b67fce474a0ea4399b6cab23ead2dd6bc5201826f9127bae7419504de04342357c90a34884015edf094e52a7080d0b","priv":"0bd271e0b2adf4aa3f1b0ea862eb4efe72958d40ef2153e784ede4ffed2d4b51","pub":"03b42c815258c481e1e994ce430135aca9e8546585e82927066067a7f3eacf0223","addr":"95ee4a4c887ab69a23000fa3bb062d1bdd96371d"},{"mnemonic":"rude wolf aim frozen bargain false remember circle axis arrive virus echo","master":"98d35496c8e4f142a6be9c704611257b0520a14b328203fcc0b6b9419a71e366","seed":"ca47d7e6f88717ebac85734beded4a18c6a46e6775cb64b7ea5aa167559f90bb5d8eb9254599df6e09999d8dddc1e487c657c95eab703f756199ddc3196a5962","priv":"9dbde9c5f35f2fdd7bb33208c733021a8ed055af962137c23e06e252cb999456","pub":"02ed94e8e6ff816a2b053b959b261e7d8f8809f58bae0cfb84459d885da88355f3","addr":"38a0dc2d9bdffd96930010699ba2f39fd244c3d7"},{"mnemonic":"deputy among shuffle online fence mouse clutch joy away bean hybrid void","master":"e13cc05ed1c7f3415610c4011f994446c9c9c65df5e1568af347d42b31e36d30","seed":"f3b73f8483fd0cf17bba1032397207d4b593f54140391a91df47c5b8960fe5918b0160a18a1a2da8f3acc6585fccc19911c613424c91b47afab4eef5f06bb569","priv":"d323538934f97f44d23c78be6a5f6005a882126475ba4a7c953b19bec7678142","pub":"02e6c50799013ab284a676715c3c575be75806a5676281144cafd4c17481ea053c","addr":"788f0092868345453e40b0f38d44f4ff4af0f2a8"},{"mnemonic":"panda rule subway ceiling awake decorate forum cluster place club surge lunch","master":"f0aa8e87884a3e3462bd3a230081a29739fc62fafca9aadd9353986d27de4509","seed":"7ad436a119093e3862065629b195087e0162f2060d6e2a1e653be2e894cc9c3c4ddc2bae40f447ef87c0f3b2232420fd938c155938b4ff5fedb3fc7bd26e9eb6","priv":"9db3eddb02be190b266cd3bc93f5e45d126577bfdfb1df60ea9f2f3bc21cd2ce","pub":"03c4e1511881edd8d598fa65bfb4f9dfd93dc1f2f4944c790c2abc650492ce0a20","addr":"c61ee0480e8379e854a631caec02572b91c2b23a"},{"mnemonic":"addict foster exclude debris moral uphold couple surge reopen blind trash real","master":"9c7714714335b5d3bc2057f206da041c5b0e74213413c2cb9c98f521d2890209","seed":"4905780290404b998ba3ea764cf22ff5ee689aa9d783a7f6ccf57c9d2b4b27e4312941a2e4328232b6e0d2e7729cf30978b094dfa6ea369b34b6da35ee2ef73a","priv":"4e5be9010cf1a4ec010712d82bb0d18d5b1b1cd3095a56cced0ce00f430e81e1","pub":"02a18e4eb8623e1f0fc37434d1e18531ebf5e2dc9bf93af3f831cc72389cb3ed83","addr":"7acf8d7f9f6fe56e21ad77cc6e41b3b49bb542dc"},{"mnemonic":"bracket dragon until token cotton giant enter lyrics apart supreme pupil fashion","master":"dc8282dcc0f6d147d01f8ac326a3017380d56e242fe415fd17c0b6ea92dfca0a","seed":"b1a0043eff67b480d9b3b2c0b6676dc17da38225428cec06ca7884060b830ae243d50b659cba06166b6e8eae8d9c9d67a38554f5feee3315e90859b544833dc6","priv":"7c19323897d7640d225bbcab428731abe01c7b6160557476fc0bf97799f6cbc7","pub":"03f1a65a290bf4a7ad8585680304d187f5aeb3e51d44c9941443450270c457edb7","addr":"72caa875e043f9f2d3712a87317cf12c34980ace"},{"mnemonic":"catch unfair toy shadow hobby tuition remain leaf put blanket fall diagram","master":"611504571157c7451ce639658fb04945cbcfde1b2e487f9cb97ad430ad3c3801","seed":"b1b9002dcfec6d7bf1d7068a45615abb4aa076ad65e34f15d3f4006ec82384c3bb7d737fe7680e58089281ce9305ffc178bd1a23e95087c2fed495a20316ddcc","priv":"3fabb4604bf9163d245a293a4b50a4f844277afb9b260100ecf406fdb24a6d9c","pub":"032568275e2158b5b88f191d77cfc23742157a4c03863da61ccba04a29d6a5fc43","addr":"061151483994a2a2f420b081148754d5807cfe96"},{"mnemonic":"divert spot love tragic vast error crucial print snow filter fantasy forward","master":"817b4fb465a25b5dd9921ff72634202f30b98ac3040cd5006ca5e18fa851f4f6","seed":"824e5275f61c11ca6db812ffadec349e61afa0313d4d299c911eaba5ddd38ccbfa39a42d323f43aa4999bf95b997958a6ed0522930bff6968dc9cca2adaaa204","priv":"43919dba40cfbbdc53b2f8c097b6c66a6a391c28d9478fcfe23f29daa4f80194","pub":"02c32a7eec00f33e70c83aa4281d312bfba257bbe920f349dd3b674decf43e3aab","addr":"fb3e6b782cd14938a296f8986daefcb9c1424232"},{"mnemonic":"marble start nest primary author steel video science wire sister tonight invite","master":"8d62341b89e0c045322c270870d8c438ab41ca077b96681b9288ce2b04160b8f","seed":"ff79b45850f134169e1d12bc2c95c5f48933815e3062296a93644c8e88ec70f2faac59c5e0e20b1fe8799989509190442356a67596657156dd7b1eaaeb976adc","priv":"75adc55e735bce443ba38fa066c269d20c986d18d31b9c67a6f41215dc6205e2","pub":"0262ad481271c2b42b162d09eb549bf2e09ff953d78cc3b58f9633f0a2f0a1cb32","addr":"289c5796cb64589fc90d10c269093d9525249ae4"},{"mnemonic":"mesh rose keen want voyage net brave bargain session creek shoulder glimpse","master":"d3230ab8890910c45a3bf9d9d21b8c24a6a1aca2b87467b42c75cdb9204e1f2f","seed":"d61ef67df124c9b43132bf496bb3b18220a28c7c540247a11e25c2dff3ab8b7d0dabbfcd8125f03496a8fc4f888d6b8f8df9828ca406a3864881029e95578c2b","priv":"92d844eea97086fb63381e19e56e3b494af47e7cad3257a5ef1b46e21c4cc4ed","pub":"03be77c3a96734aed00ac4a0a18151670a213a911f3a9d78cf6f4e1fc33b7d0aca","addr":"e3a1325741de4de93501261a3850b374423ec97f"},{"mnemonic":"host increase panel pact gorilla alter cause cook voice ugly crop that","master":"22daa7841a31b77e2d006277ba1afd48ad7f066b4cc2b778926b4d4b8931271a","seed":"c1b9b9f1d4097d76288576869071b7efedc756fbc81bc62965c462fb0ac49ede2fba8110e4afaee3d9e187933fc28783aecfc9ceeaf87f63e75f4bc1eefc1860","priv":"2aedb3ffca9d76ee5070f107bf5c0dcb583bef571b1f498baa8708495f8f466c","pub":"027c929945ff29b6a5df3d4ad096849a270ae3052aa1dc74b7a14d4288421e47fc","addr":"97944948d7d679a5c9658168f6b1ea9772c49ce5"},{"mnemonic":"shy garage devote private degree cradle special fee plastic lonely legal agree","master":"b2150fb985a296a6548cd57d30f25bdb2a51c7163e96207353ad064ed0eba53d","seed":"474ce9dae1748e7f1c4096dc603c17696ec21f329b508083ead0651fe00dbd404a1703a7a90f0bd2f66553af28224c6abb93563527a6413732ec636f234b472d","priv":"2c079aefe8f9d45940fa7ca547243a229ac8aead5570a310ff0ea50e9579416b","pub":"03368684efade7cbe5d1017c8cb099718ee9b7ef52e7ec384d507117d1716faf3a","addr":"e0a6539483dfd061a878096e5cd0efd475b9318e"},{"mnemonic":"marine local subway mixed width zone palm lake sort radar matrix pumpkin","master":"5b1142363291deddd7fda0bd7775c7f2b1bdab5959d17d87830d96c3d07c15f6","seed":"c49978eee2d39326d8950c89a69ce6cfd4d51dd84973bdadb5dc517bb60185bb4354b3c5fca5dd0d10a9d8793c205304d1569af0b739bb796cc3f604edfd8959","priv":"84f09a48e36698ca0fa65597368284089059688c2cca84c72a22510f37989c85","pub":"0262798b5fba21efde82c22dd36df8261745c8f7046704e239996c634302efe8ff","addr":"6d81cb6953042af66fc1fa7755f48f3c3b529495"},{"mnemonic":"morning vast nut patrol owner body between neither earth always trouble mechanic","master":"abe0226f5383b2e40ac23a3cb7b486521f7b7af6b1108f24941fcdeef71edd81","seed":"14189de5d7d30504ea20b94fcdfa6054f70ff63f4378cb3a6715126216b571075879cd9fa1c1694ee16c656d8f8a2020adeef01f56dc814cf341aca1ee9e8e33","priv":"8da48fadffb800299535e930330f1c2f9dfeb45772c58764451079696ab3275f","pub":"0283e5b3d662399b88cac949cd41d65e33dac46101c6be4ab6718d7b7d4c1c2df8","addr":"bece5507c72c79ddee993158241c20ffeb20596d"},{"mnemonic":"weasel emerge sight shell cook develop entry truth era radar panther prepare","master":"2233dae87c1e1a6a98e1df4a573f6139dcfe49db3f2fc663b44503ee267b0c95","seed":"787e8fd15da3e7723f91521e3fe4b501b070ff5bbfbcd2b4af147a6067d751d5d1d992716519ad71b59a41ce329eb282a94cbd15bdef52567c8279c327651bf2","priv":"ef6ec780a7823965a871595f4f0c2e2e7ab07409f39ed825b1efafea19f39440","pub":"03a545388da649a8800ff9fff4bb33f70d94000e4b1a767ceec92f5c3f7b880783","addr":"57222240ca41ace976ea1ac308bb027ea4c64d36"},{"mnemonic":"switch sea bomb symbol foster flag grain bicycle case crystal august crazy","master":"32694a657bac54bb8b77e7d0d84014e41adafde6023723aa5779645c7c798d65","seed":"2719e5e2d4ea727d045817bb8cff56c62360b3c1c66522ee74d1b3e5c8d6ebd98700887d532f9d1f17a64bf683622b44df8dca30ac1bae5e296422cbb7741790","priv":"47b1b2ec336e0257687c8837c9aefdca2f45394bace57de882d7eba6c61da49b","pub":"034ad373c9e20284f233959b09432c82b0e7b430eb625c9edd1d5371a7038baba4","addr":"0900f4003360d4641626e75f3fedd19874b11671"},{"mnemonic":"asthma make clump clap tongue away used shift fiction siege tooth purchase","master":"0f28a391e22257fcc97aa8c229209ad0734e9d0ec8ecd67a203582f2c0ce7289","seed":"006b61f87ea0d6f9f87b0410ebb5bb54c9b8af72d3dc6283152b6e66a299b8ae0650ae528dea7b6fe5c6cf1652bd1b2c67b7e1c9ba5ccdd4111589216bdd02d7","priv":"6ad416539a8a969ee72e48e1b20e9502b90078dce0b5a4245d7cf12d4857eb5d","pub":"0274de9f743f31744d6e7ecf30c74ef56201c71b2ab56d03eb849f2adec2e3dbfd","addr":"67e73523c5eab9e70230fb7a806793419d28df99"},{"mnemonic":"nephew kick predict rotate maximum giant fit love float kitten embark another","master":"dd3cc8f83542c0fab49c660198ab42f48681db60661015e15fe4da87840b371a","seed":"5795b7fa476bc8f7b07738d313716d991a7bc2fb303fcd7012dc54e411bf7111d9c9159c9b28d74d5614b1f3a738bcdd63666b6b14b896311df18609521695ef","priv":"d84c0f29a4b95296e349bdc8bc9283367f5f68155fe92192a74f8a08e3c6e38f","pub":"02bc5af041b0710cedf1cb8895da55349d68ef4677670e89ce5da29f43bb063027","addr":"ad020570cc250019ba70e84f13a0b0c388443c08"},{"mnemonic":"filter vendor slice outside win urge welcome behave valley merge gun talent","master":"e20ace834dc8b88a259a3c6f983a8065ec612205e25da42103e40e968d1bbf98","seed":"1cedd43d959db14714c7e6f2f2caac10f548115f54bf7fb10ff4f178bb410530d8ade24d2dd770f92ccb459ba2dcf433d064c9c24f0d59137a2f808421e189d6","priv":"ca111d268b05839d504787ab4173f2d53cc459ea69c4965bc267db40b3499f18","pub":"0316b77b50cc08af7251303e190a4a12a96ce586631188d5f2ead491825db0b27f","addr":"c691a61bf6a5626bfa6b11f79a36c89e5f7efdf9"},{"mnemonic":"salt vote cook live accident leave define home section loop fiction sport","master":"30f08d7392ec4b37ec8fe00847aaaecc975ad1c98d64625b6e83525fd363b89d","seed":"85abff82357508cc583ff2c4cdfda7867467cc6889fb46caba56624f8c14e6141231c6b26ddd373b9e3504d90ce8b01da123ee72ae5a4db46aebf4ac7b8dda44","priv":"297a3c7969c15e6a3b4325ec6b4c768128aeb99e81dd4aa3cdbbd488e124b73f","pub":"02191258d0ce26b1e6adb0b84d19317fba6818f06993a46df1829a61a682a93185","addr":"a1082e1177f32b0b369429050324ae1c06461e44"},{"mnemonic":"model today toward awful apple actress hard reject discover type must member","master":"58168653609c2e12f079d799a7a344292edb46cfb7cf69a85f8a608acc6e47b0","seed":"bf3a70e5a322c0fad6db542bd4ffee2ed3ff85073e6d3ae01ddb7cf30773250c294529d69dc31f86ef390f30907c6da925cac78d10091d9df0fc97a6e48d9860","priv":"0a7c2b48dd3ec606816404246a0e28c36790c3b2f398531ddb7f1b7aa7e7d624","pub":"03f12f02b0cd5d3146eb28fe6a57eafcb542ac30833b7153e1a9121c3817d0854a","addr":"06eaa20c1fb4487be17eed4bcc57d49f1eeba446"},{"mnemonic":"popular among unable purchase matter athlete fever acquire mom install glance where","master":"fedb71f6c870bf049aa1355f4858675ca0c9a6268be575844d2313365df45382","seed":"be3448251aef8d22e97fa58862ff534bbe7a854eb0f1d574ebb49c4197328783c9f7a1b51202e5a37bf5b2410e3b6e11322977898c75241ed4806d1972102457","priv":"3f27d257bf6a625ea3dd1cc4ca9787c29027c105bda25d3fb44df992baa4ea45","pub":"026abcb82486454ef9ef70f5991f76cb263684624b040f9c7b1265569e65087036","addr":"197ff1aedd06d9015acb4712a4a3ed76b420be68"},{"mnemonic":"kiwi rail hen destroy path mistake protect carpet occur jewel pizza lazy","master":"7690775869756887b1866a93233ce2188202d12a4f0e01501e381b8aa120fd2b","seed":"82e3b78430fbad5184c4c7bcb1873d922de0758894d770edcc7a487ad5c10dd381345aee23f7d996dc8fbd44ed171b3e6e9b6dc19ba5c093925991aff3b303be","priv":"b0af5290094803ecbd0076266db8a65837d363be36738f267df6a5c37ea87b26","pub":"03a4b20c1179246419b5b5cd861ed440f3856b616c4bd5a04e0f9d45de91e25daf","addr":"ba2734783c80b277d6196850cfdbb7f1d599fd3e"},{"mnemonic":"cannon hill absorb ozone play derive duty quick unknown divorce history march","master":"668302ce757bac9a084220ac55e22027595a5bbf777dd344351fcfe668e58ff8","seed":"9282bc012e007bb31f889b9b284ed8dd02bcfe5b14528ffa0e128fe0b3d2bc27d3ce5240d14d581b5a530f66ba3c7146d891595a215b8faca2a0093287155171","priv":"82f9994e259551b52e63de92d93f21222b01c9f371c8cb0e9af15a6ac93b3fa9","pub":"030c0ca2aa6353264f3683210199ee7ebc1c051dc657a47f8ed9e95d50ecca2840","addr":"285debf5e963ce3fbd66a5fbb0841cb8d0a67745"},{"mnemonic":"wild saddle spring meadow spray lobster enroll album coconut chat marble follow","master":"14f5a8838df5b6546b7179704bcd40d5a168393bf9a65d0d5b80658e750b9cc4","seed":"565ab133d78d7fe7e8763fd73fd89ce7a5eeabe6841e5cdebb9a86f867c63f1ac7f3e1ea44029409bd48befc187f762480c3555d62fe9ab653ec2f8523b55516","priv":"229e28ae8746b90e772aa80afbe866cc08b0f49e40d4b1a512be21ea728ee0a5","pub":"026f08a2daea40b6a076b79c26de11bb1a5f74b9d127e79e1310d5a40675d5da0c","addr":"b262603b81f2f0ea718ee4fbcc9c807cb0317e70"},{"mnemonic":"firm mystery spoon brown rely mutual isolate degree stay brick brown abstract","master":"ffae4ec244b67e40036dceb4241614869beecad4e84fe6e41645159d3d5edb23","seed":"4e88efeeda99c5136e145dc0fc827d1a8edc96839311ae7c13e80443b4f8e7a907040d9a38be8d789200314110a91404119e33797e4ff5fdc790404322a7479f","priv":"be1343cf39f3758c560e38fb2b949c86225aa5a32af5328af3f476c94186e1c1","pub":"0379e9a16c9624525c15070ee3730fa02a9b8dac0d1847263789ce4df4ad22b533","addr":"2defd48b2cf9556c1bf6fde9307b17bad70018ab"},{"mnemonic":"shell open sing action exact cream scatter slim right sausage victory case","master":"d0bd4329ae716aebd1dbc4b75a06a4e6103540eb1185de24e180af67174cfc61","seed":"e55f447b58f363276a8f67672f8a4cd6a3bb014b5cda555f8d94e701dc775c4092e313e1aa102f36c98edc9f1c76d863afcec6dada643667f8dc612c43cba71a","priv":"31818b15c3b42238821b8a127a33e90100c6599d6c2ea10797f111b5a741860d","pub":"03c749cbf61f0e5b3cf815c454804486f64dc15e73c53b8957f4a1b0c1b3f36942","addr":"586fd2221b5f4dd31469ce689ba34160ecb002e1"},{"mnemonic":"mistake eye absorb midnight box nose bronze joy body trim give purchase","master":"8a97dbdb939254072731791791f1cb5f86bd61bee1b1a7b1c0220362b73f9048","seed":"ff955704f42fc8451d66092b720eee4153c1edfad5ac3b96bc87d0e1ff27a1655eb4c1127aba45906799197e1a92dfbb040304cc5acbb228f20c828d0f28689a","priv":"81b5ed5d49563e225a164180c53a55ee86432ee9e59ff5c6b1ba2dfdee8ecc87","pub":"0214a81bb7326df6f884b465b655f497c20bc68d2ac499d931945a56a20b21bab3","addr":"e4d30cd4f5b383401bdd02a01bdf1e7003ff9e7b"},{"mnemonic":"stadium blouse more trend reopen sick test trash glass bounce brain total","master":"a47cb7d914af1a75ca7ff6bc0192725a7b4b4daf386a039e9aefd8679f8a9f66","seed":"2a9aaff54cc77a16b4ab472b006768beb7403cbd11cc78aea80e19765ba685abadc03dc27c6444960bcffca5e206dc28f5564fdd05292f68ed825bb06ed6fe5a","priv":"7125901a72c60386b41bb65e8bb4aff64334ba8f2e032d2c032869b3b3a648a8","pub":"03a74cd7b3d21dd8698c7cfa4c30d81a454a55ce294171f30aa70f564f4ed71751","addr":"4a8f9540cb406aa75b0d68c2eb40869a8c25da92"},{"mnemonic":"fetch use target promote later more increase logic oxygen provide original high","master":"f06c1e5b33b4d18d65ca7e0b7627c23ae19da34a6aa55ccc8509fbe9fa25de3d","seed":"8ca3dcf901cddd77ad4f6db2a2e3a48fc1a00a81b372fde0dc926c4006c8cf81862013008d9e119d811512b9f98a84c7c655b071d28c295a5dd565491b961d45","priv":"44bff7bd7e57b709b5adfc54ec47d084d80ab9549479f4707a27e06a06083f2b","pub":"028d649230f94064c7837760706a615e7a714cae79a7b2363d493f9d4300b9a2e2","addr":"23b883cc57bdf88831c021ad62b2ae475e09d365"},{"mnemonic":"boat cause tooth danger box anxiety luggage panther engage human army language","master":"2c0c2474241d615780d2a1f34c4cda2a98e138c7bdfd13c97b341ddb8f5e87e6","seed":"98246a445ad873a5e8ac532ad64643c7e4d0ecabe60c7683996d58afbeea843c61cb9518461270cd2786453ce2ef39cac5818cb1aee0f336da3112be523349e6","priv":"f94665aaee7b5a07c328d74e3f5a51bdc0896f899c739c284bb9d882636c9b67","pub":"039f75b5dd06095b39778b0b5126907ad39a9c034dd5fc5e33f53cc00ecbecd8d3","addr":"af2307aaf8e07bc2feb04eaece0063867e64c4e5"},{"mnemonic":"much youth team what empty door language travel attitude rose furnace all","master":"df555390632d0ff6d8e472ef734e8e3f8f83061d5ddbbb2034f9370310356e35","seed":"f450c859e941b9d5e84126dd4710bd0113adabda8f962d383f8ba54bcc53d0e6e1da264d1841547ebd7c1bdfb8c29089a57ce05b64093653aa57e0ba51b0084e","priv":"89705fd7c86cbe5c18758ab9d4dcb7b1b6df12979c77a61c128ec13672b4433b","pub":"027949604d41872f518c8fabd333f8f351f16d68cd7e79e341f1b8368fe1b79842","addr":"36d1cbb6eb2510e0e3c2e76c2400dacfd9eae736"},{"mnemonic":"hamster adjust rally crew clinic skull private oval vast object school liar","master":"face99969ad94de93d7979a246a8e69e85dc6249bfc71f58ab6d774449e4f18b","seed":"ecc06609969bc31a47adc214324b7f7d81d09e0e3cb32eaf6b7be548f74eac5a9397300f0ff5650bff02ca895db55241d49b7037a54cf70e3fa62a3edd7206c4","priv":"c1d424295f77f3eb9f3a71c3f800d9a5292a2df311456daa694f5f6e12a7abad","pub":"0334e88812c848228b83e80283f709bd9827e991db6076a22f7497a3e73b641ee3","addr":"5f1a48e1eab155c3a698b69f11c0db64a556140d"},{"mnemonic":"dove grab grow giraffe pulp lift judge pluck dignity theme cigar annual","master":"3bb034fc63ce92269589e21c4fe89e16081e7cb3a29ec91f5ffb30bc077d914c","seed":"6f44f1782162a9d78af64e243dfe4d44c1ac521dbc8a00977e5260b6ea5d7aba6c205bc51b6c56b5139274d8b07bb31a728702df2dc2efd8f4f07c09bbff19b2","priv":"c2d5188d3db0a2dd9853104e3978c27d490eec8c3601259c4a4bf6e0fc30260a","pub":"03f7de67b6490d9cfe61818b22380450d5b5c815767c4efd821f3962ef4d430b58","addr":"0b5513fa903ae028a8bc3153b5f50b2df555a77d"},{"mnemonic":"wire silver blouse theme lumber modify muscle among orphan genius diary crystal","master":"28064c9af3e4436ebc8e71b424d749bdc6599b56f7ef1ead765606b4920d81cf","seed":"2a132c76e5b88181c24491f83f72b215b7963972f98c3d165c3a452f88165b459bb6e3756a511f40f9de0d47df6a030e91484a2fecb1648b9f194199143ce49b","priv":"232ec9cf0fce12247cc6335c9c8d54418a7db5aae86365558646d9d69b64af02","pub":"033e30397518d760b53821e3c0b3b43b324853c919b77a855250abe95d3924741f","addr":"dc7c6c94e8f7823485edd555741cbf224087f137"},{"mnemonic":"pattern syrup now tired gentle accuse rib cruel cluster wagon sting situate","master":"39f3af4487b768e1f9c7b04b0f713d4c56a5250994850ea4b20ec010a0879028","seed":"387138abf6c255b137a365dec7b8141ada4fe9fc55d75af013270f2df78328048981e69487873ee8740da3548ba611cc90f5a9315efafff651ec41df50732068","priv":"7270c0bd092550db36c7f5787dc20d17fd98edcf34d3d662085af7dfe604c8ec","pub":"026d65397b9ec78af76ec8a6ca1270cd0caded21aebef86160d4ea446b3dcc2f6c","addr":"35566b676261d80bd15792cbb348b79da3b10f56"},{"mnemonic":"blind force awesome radar law patch warfare defy device exist chuckle because","master":"b5eb133b2b7cdeb1bf5e6d3210f6a26b79b544ecf911f6f8cd838c7a6383e0ab","seed":"8a4539eb40090aa2cee32979ca6e8a23c1dcff202c935319db667cef1d2d49cd2a71f9cc54bdacbbed179b20feab254b932bc3c900d24216c089ac4f5c2cbac5","priv":"45e109f71861222311afe9d12b8a2a26d6f3fd0484b97a96bce464bec83346a0","pub":"03fd6c933a364638f867e6fa329d5cbf35aa9701061743ce5f1f6f6daa7137b3c1","addr":"dc3b76c2afeb877b256d7a9375618d0ec526fd6a"},{"mnemonic":"chef flock stem illegal later shadow tragic story tongue also fade core","master":"b7e82f75da29acb35a7714d3bf3aea45196e1857b5597a25b8a7ef6b69e9271f","seed":"7d02c419d5370133b6a0d0bda76a70b784e530c9a0b389cf2f6eebaa07ccaf946859cf4a7b2076814909f71c9c84ce3c0e45ee8caca9a753d5c2240029ca8847","priv":"555a830f9fc1f99debe0fbefcf34df402655484e5054c3fbd6c6a127e3356675","pub":"0238bc6cfb2c3c335b1564fe159e478d700a95ecc34ef23b7af3d571da8d136214","addr":"d3e9edf902c8dc5fabd17c17db492b15bdc33ae4"},{"mnemonic":"paddle appear actress output peace maid foam share afraid quick into erosion","master":"a3eb9cf3115d6b2f3cbe4bcc4f06e879b837d3b8960853a955f1231b8f95318e","seed":"a6b3ea2da0b83408010911cc091f9bb6d296fb13c1607cabb850824591ee5f69d0a2d4576a4361f3b368d34469f53282a1f9adadab3f8ab12956efa6d323cd5b","priv":"a37a2cf232918206e68593863c195d4319548c85d113456a0531b160b1c4509f","pub":"02a129fb596143418f94ec7bb1272aa1fda227e606c99f86cde12e8e7dd9b06755","addr":"69cfe226958b42832adcf69c7c84b734459af9f2"},{"mnemonic":"they garment wave wolf rubber firm toast hidden grit puzzle march rebel","master":"9c20ee12718c0fea98422c9ae0fa861da154552ffeb9e9991443edf224557309","seed":"99880bead4bf15beec406d9e980b46db9cfccd80473fe36d3471a0be1cce8f13bab732ace2e3589b1edbc5900c6641e088dc7a972bf11541ad475d97a66bd61c","priv":"b38db625f8ee7badcd89d159fa867b7d30ae946f199141f63af8e36c59750150","pub":"03ba880b842c952123b8bdb306fb0ec8c3c39e6bae28f2241242858c5c9c8c574a","addr":"24b75369a914827ee1e2697d5f591a58cf3f7be5"},{"mnemonic":"virus stand margin found heavy gadget depart idle guess siren mandate sock","master":"b6489aba56cfbac38041a70c7442bd298928cc37706dd01481fae719a2cc1222","seed":"fe240f7a830cd984b4b07cd77ba9a4f6b25e753cd2c981231e1458ed6775969a6b032be398838d2b5a706563d575177812361fa7cd35798e9a260b5454f3cc53","priv":"801663a31b3fa9f6788c826388b6d7272c53b0c331843c3ad19ab8f97eafb1b9","pub":"03067a334f5db13f9918aca85c5465042a8e994b835d6491604ea7c6b5d8a4403c","addr":"10cbc824bf4e61e2eb4091c0b1afe0f24ffec681"},{"mnemonic":"logic drip eternal frozen equal defense pudding prosper destroy chase faculty position","master":"df13ceb0854b9a18c97c8c972bc42e85231d26c4cdc87dfd3b8870b8ae0bda01","seed":"df990ef85f0d21de059f96b7037b905062b9e098a5f401afe29ae379a60c611a45cdd93f98f4994f231e549f739478566e71e7793fa750e92630aaa661b30e99","priv":"0395a33ce515a68172c9d8a324fdcb81073cd903f092581beb8ca73e8fd3016b","pub":"025a43eb1e0914d6f3c9269123280ec49ad469058d623230885b1f5dbb5f8dbcfa","addr":"6fa784b66d9a3c27073fc463e5a306916bd64374"},{"mnemonic":"nephew august wise enjoy age comfort hurdle cross feel depend south current","master":"9c01203e9921c9cbc2a05aff4cb90757f3d2e615ee6c6ef2d79100b48a48214d","seed":"19b2972d829bab57e706d21f00356d24cbbce556251aec246c36cd7a5243898371c92ef562ab2619244ab5e4854b9f76f76e2886b35cbf591a154a2e915a8a11","priv":"29af8262b1361dad291ed3e682a77a6bb09378c6503037da5c236b5eee1ccc69","pub":"02bc9c65596cc3f49aadad747651387a44d922de3f8b68a9876fb55e50372f1fd0","addr":"c4e1dd670e6c2ffb3a964315b0f7a51b2116126c"},{"mnemonic":"elder badge muscle tunnel sunny ring kite glide post slot injury crime","master":"e5dd0863b56bb3058b0aa457e17bed226f7f8afbc09c7ebf3cde93ac5912d22d","seed":"cd12f2dd94caf3a76292863e9528acd822c915385d8b84a09326b498ad5f1a60a1750686204b2c51093a3a3003ea558bd490cec607837675d2561a0b6f666a81","priv":"0f8717c113f78a6aaf7d57a93d5e7ec3a0326c119f792e8d16dee61b485beb16","pub":"02be9b54e62d1d26d08c1a2126c813a3a3a1a8d399440471491534dba209b3b8db","addr":"dde70795b05c51858f513bb59e2e0aa9d0330aa1"},{"mnemonic":"lunch cereal approve swing poet fresh sphere spray tower scale clerk main","master":"3c7e4e9876b819aad6e94d6decb42f615923873a72a2ca8b6df3b8b0ee1c77b5","seed":"0f9fb7102299f4b02874a785f60009c616ffc1e74e4386e78ab3abe2124257c7aec23b8926883dfd343f7260bad204f1261bb76cf0233dae8785c5e3dc9b015a","priv":"17b7b6f6184325c77195a60bcb15358b318a53ec2990dd46d8f60d0bf7e2e245","pub":"03eddd35bf621d1a943edeae5f5a5242687ee7f99f14be22f694653e449b77c177","addr":"06e8ee97a22bb6b2d458bc408bee7384749ada83"},{"mnemonic":"night law title fitness critic soap runway patrol carry drift damp state","master":"f7cc66a4812f3a394f9d52a0d83777f22eaf8fef4575561e26b0c636c4beff55","seed":"99acca4b65136a2b94c935892e265d125a1e8ef834e52efdb7b2ad09d973806dc318c43b0805924f5b239b74e6e516615ebf42d0379baee78ab63a2a24d03bb3","priv":"14506c9564b199203e8222c7508dac642fc6f15c981a7ed0fd21658c18660f04","pub":"0205f6b2c6ac7c0785d7f0c9aa85258167a314bacafa71f478c2577b5f9a3f9dc9","addr":"b380fefd78145bbe311a87e314ddf3b33d9bb34b"},{"mnemonic":"predict either bean grace myth scout number used void clown route member","master":"c7cba4de1441602a0b8ea2e11a4d72d7a21cae827db034ed4e43cbb38e608a51","seed":"8e80bededc4b64dac814dcb6e8dc5ce3acfb6f59988f13e24106fa7b3205c72eca6a16ee44ab51a54ab0a07d1e7d855fc75e3bcdd5d652e10a8fe33f623b15a1","priv":"6577584c26c25b3d6b11a1f669030008793f3d173721acc811f2dfd470d9e136","pub":"02e7f1c5213aded8dc3a44b14874cd9098a41e5cf0a7c83b7b3e045b8707d1d306","addr":"17614a88c0e044659cb6f99334fd1d8a83390df6"},{"mnemonic":"actual between river curve keep sing hollow bread theme corn mad easily","master":"e5498c15a99ef460088da7513360cc0e8ed3de095027783154425011575afd70","seed":"55fdc52505724e42ec76e0871860226daee30280de52f3d0538b8cbcc426ecd2d44287b4f1f11c01889ef63a6012896311a81f202c41e70725f3dff333f357c0","priv":"05b5a9a68afd24c6970b1686297582b3cb806729a277a056853f8918a706b0df","pub":"021a01e00670749567cd09de2ed8d0a66f0a0cb00cebb969ec43dcc9d6718da372","addr":"fb0c39ecab019c2d259baeba4819d924f8b9d97c"},{"mnemonic":"route aunt shed razor invite board ignore tower penalty claw absent solar","master":"c0f943565964df86bc140e8a8099ccb23417e7b86bf3c9f4d8aabdf7271cc721","seed":"111f3c5d234f0c02921ba5b30149d1913956a6c37e93fafaddbb3bf437b6709599bd623ad6ca97610717db77802f9c591ba352e7b08f4a06a4b897b9ac25c8ab","priv":"bba974522cb69e90b6b10ddd32f3b313bf5dfc129628bd2f10ad84a742a22cf8","pub":"0341c52f99a97637d09d68695b7b28f0c99d3fc5218d297e7bd95b267d2d7cac6c","addr":"5b4e4a18db22862daf7c43ec209bcb61ee139904"},{"mnemonic":"roof select rather approve must trumpet during more outside off owner blanket","master":"840894a95b0850e37a7424cdf10f73361387fffd96783a988a5d0e27012cb2cd","seed":"9eb1782d3ddbca4be52803a2dfdc85ef8ed55bc9b939246b9220dd911360c7323908996bfdcebf51b87c31c55cf2109c4792cf54b60374bff8f2c46bdfb97973","priv":"2db028d5651025a18a06e2c9bf77282f4bf35a8f54788624ffaadcb0caf34474","pub":"031c85b1faa9a2c9b3ad80328c54eb24cf27837d1418dba04fce05565f91e3344e","addr":"a7e4da90a801adcb7b3d9b947e760966fb4aadd6"},{"mnemonic":"album ball volume coffee motion cattle album wing unusual tornado bread stairs","master":"8bdb565fdd586d6aa72a53ecf88e2c81d48552034401bed5d130c862f179d159","seed":"aa0aeb0065b4c8e008fc9b1363fd4b32c0405359dd99f3a27670874bee96e8f1d76fdc807bd903289fb66b33138b92902ecb0d2c1627ef39353eb973b21b0003","priv":"54288cb0b5530aacba3ae1b16945a783e76ffde7e7c523c0c1e1293f00b5adc7","pub":"036974570620961a4e32d0329c851cb1e4218566056249c534ae92d77aabb73438","addr":"d7e65a2d95bb5d705ee894e16e4b6e4aea4821ec"},{"mnemonic":"start staff chalk volume emotion liar route lady sample mind casual involve","master":"aa479da35fc7c15a84e37a118102c41bb62012d872e34fb4f1317b67f9d7c452","seed":"70a8a8b15f77356e12438aef9fc97e6e6279be885fdcb28968db25d5c7bd2a3685aae1ee882d49658414af583c4339fc97f75f70f5b6ab23d184768cf12472b5","priv":"e1f12833fe2e792a0d959de815678a79e1e86342c7a092faba765979fde1d93f","pub":"02f127e13853937be361e47873d965fb8a6d602426c89389ffb45ee712e86e8231","addr":"4fdff2b288741e9f96b6595136c780d979403e2c"},{"mnemonic":"canvas fashion mandate will phrase spend galaxy good advance dismiss inhale holiday","master":"71707593bfe88f2751e6b381282fd71177be82bdc7b930c89c3f30606e0fd356","seed":"c0367432ce6b26e2d0b279b008b1d7d55e89b50b3dc55244360eb611d3af8c4e2dc6ee92f38e5e32309d4ca3b0b5c9eb9f8ba5edff66650dd052ac01f65ffc7c","priv":"0d53e4411bf7c498836412991515876c671967b55704e2928d87f3559a922911","pub":"03bccf2d3a8927babc9cdb6ae16addef1734739941071149122e780c9afd83877e","addr":"e1f22608018d5a6ad02dcac24a9ff28e065ce2c1"},{"mnemonic":"area thumb debate bracket unhappy muffin liar cute subject resource oppose nice","master":"416206edbc49f77c17405abe51397e5d5b547d300d296334b9848e4a844f355e","seed":"a08e97cf029eef0c4bcb3b2dca43e64b7a358199ced33a114c390ea81bdeef23aa7a4d6255993367426d051a56106e485d78f9b4057b4c50dc242d95484b39ba","priv":"9379dd5b24819205a9c7cc6a30ca2a416e6008af93817087b16778e9fa022fba","pub":"03e0796e8edc870070f179c669ef8acac6ba5d745c954762e5738e6db4d73317b4","addr":"ba2f7b307d6c8ba32f9f39174616def7551c4dc5"},{"mnemonic":"ahead face gloom dutch simple battle either hour abandon slush episode view","master":"5c953db2136db4be64531ea6556d5b93f1731332727eafa12630307dbc65c587","seed":"31d751f855507457129f25ecfa2ab8a50db37da0fb13b62ea4e232fdb8c7093c236502da769a0b3474a9436351b87df03a69c70b1b96c61f1675b8fec00f8ab1","priv":"aed4993762d4e8e31a12b500f8beecc1a3e747c2ff290c4e70141de4ed12be8b","pub":"02c922d80cccb9faa955b2ea0a90d3f72a88d8dd203a51e0aafb36c38af1f4c880","addr":"cb41fed3b24d89ef058d25d7264b6113e0481ce6"},{"mnemonic":"van custom clump rug floor what joy live art weekend unfold frame","master":"ab89a9c945f11e8ba88683d2a13cab657a9c938bd9014f19cf552bfd1db49bae","seed":"fffc2e2b6c4e1ff826e0d68ef4a2660417278cfce527ca55e48c5d3286d78ab4d6ca874514d70164e9040641281478b8c3b078bee6447d78262cc0556b463c4c","priv":"cfea30906faf51cc15f5ea6fd96ed92a40dc4bf80737a20ba37280e63ff1ddc0","pub":"020bcb8f7581415d4fe27dc7d0dcb25e4e4883d1290284f9d3028a6d0d618daa0d","addr":"57563ee5328ec10f7af2d0c44b95e5084afca64e"},{"mnemonic":"icon series document grass dutch green blossom report violin beauty window luggage","master":"9a203cb69ec2d8d19660947de9dd0b46ccbb07c9fcccb63da50fd3383c5f31e0","seed":"4acb08487e8a407ea10685ffa35b1c040e4dbdcb7e18a25c94a459bc7a2224246a00b66b88e6bea84948ed07f818e6e1a8fd4ebd102339773e704ce048a359ea","priv":"64d25c6a43d0aae389e2bc5b8f7d260098d85dd6a8ce929e42597490e5240ef8","pub":"03602214319ab01e65bda4711f9d03be60da39e092472d50492397e8f38d90f8fc","addr":"21fed5aa21ab9fdad79aa757d1408c0921d08cf0"},{"mnemonic":"upon legal wear defy path object fold security stem face question hint","master":"efa4834167d9f43a0807a950687e79ccf9327ec707fa4324ce8bdb40ed65e692","seed":"da5371985f4c48954726882bb278971512f9e4ee681645fea98415bd3ed4c7b049bfed3a3105f4d064b61de443500f53b4996c1fd7d2835d6b3e5b52cf67df5f","priv":"963ebebc47e1bf6c8f8cb515d7044f2095f61a8f77ecc2c7d5f8d1900af3b41e","pub":"0267d73ad34ba786e92207f5485f8aed4c634bccefe1a6c6a018dd30a9969bf1b9","addr":"f7b39221ff5352c17537d201c7d8422ea4c2f256"},{"mnemonic":"adjust symbol absorb winter dilemma reflect private all eager naive bundle lucky","master":"f8469edc4fc1bc6f3b934bc6ff8658f03fe2bae4d9be0b2689caea9f23d708e2","seed":"cfcf7299ef520c324a79db53e24326523e1d2346f173ecdd2bfdb38462a83c290cf80260353ceac5089efdfd9c819c3f0f15ed653ac3c4719b0ee6f0481335de","priv":"44025bd2acfbc6710d64d8b71eeec4934e054ab201419fbd553f6427e33d5197","pub":"02bbe2326c3d6c372c22c3aaf8118742442d237830428824160c5e703c268e06bc","addr":"81986a5c30d253a2b2ad8cec56dfd56ee3435772"},{"mnemonic":"fringe betray observe subway nation dignity stem omit topic lyrics index cause","master":"b8656cb35da2ecaf6b5189d8d252a08a15495afbf756ad1365ed757bcb46945b","seed":"cf0cce225311bc1fae42b654561de73cd2720d5a2e280cf39a1391cda8937fba9e69bb5b73b31e929d39a5f58f9505351f752d7666aa81211f69945ad81feba2","priv":"d55bc330b3ab7d09b0da10c1640c6fdf10909e5c6318801c3e7f877654b8576f","pub":"0222c2696c6480e840a7ff5d106f025d87309a0754a3638fcec93a6c7b8ab1f48e","addr":"2bbcd167f45d4f265075a2aac85d0ab7582d435e"},{"mnemonic":"ski labor urge doctor repair purity winter pond virtual salon number supreme","master":"283171546741970d2804029ce72b5848cc479f32f719b4f28670b00729c9ebf4","seed":"4aff8616a56b882083dc3f586afe1128f17aaae7b0c751bd24109094144c0f7aba69dd63cc4490301a72ac950e6a9c71959fd387629429a65178d1d4c7850322","priv":"2a0f5db45dca9a199102d2b920615cf2cd2c3a1d06d3fe72d5a64291fecfa116","pub":"0294a39a5a6f878929b7c18b0df75c7f42318864d84eaaaa68891f075f51906231","addr":"5173ecedd00d5de79bacab582a5b3de6f0534765"},{"mnemonic":"surge move forum tongue female cart foam coffee hole screen short clever","master":"57dd827d6deb98495732fbf12e0098970959ecdf113d441bbe6bd5064abc07f2","seed":"606c47f8d6984ce47270900cadf4cf5df3461f9293beeeaddc537c2e4b1d3ee7456ec7165c51e267d3c02a8cbbb5a2478626e475483f121ca5856005d0cccac3","priv":"3895a34ceb1de14e7e863759517cad044901cc7c8323e8565bbba98f5f3719b0","pub":"03a30052a8169da7d2342be9b0e2788df3e5ba7b4e6fef048662427476d875f537","addr":"9d9d8be022457576a9bf8a6a48f760fe346f22e1"},{"mnemonic":"ladder now flat food giraffe myth tattoo client party address tip avocado","master":"9986ab1b096cc4a635c2f99e7b191ee4d786b090cb1e00bed2cf18d6ff919aff","seed":"2bdf711ea898c4d62fc1c30a4a55dcec4928186c9d118befa4afd8c52d14291b3254ed926b1b1bbbcfe5ae775f74da99fe2112c7e2c64013b8f3b9de5adc18b2","priv":"cd0cf663053d6ac0d9785c3a56ae190fb8d0da670d6529e2f4572c1388dc6d8b","pub":"02ea2969ffa84be7d76fa55f4a897ecc63ebd61858b7561d41e179a38c7dbf8b79","addr":"a640cc723fd1d903e60a9de68e0a009b5e215812"},{"mnemonic":"change velvet mobile copy column cabin mountain shoe hub collect gym armed","master":"f80e68b799c63dd914912454f68a3c6ee5e01530bc48c130f1a4cfe46fdf2265","seed":"1bf846591febdca13c576bcdadd352b4b8b2ab8e346ab7db8213120d5b2f7a8031144adfe06a47f1d200f69c46bf9dd6dfae8e2d8dc94089b4974275960964d5","priv":"370af5ea565ec8725dbb8f63e141b12480bf43d39c219d612ff28e2a5fef031f","pub":"024f70c3096eeaa522240b50c1ad7347f1df1e764a305b8e618489788bf15865d7","addr":"e5226a6737202e5ea8d44f84620317f65fcd4ffe"},{"mnemonic":"crystal impose connect thing cement grow gospel reopen hand frame child shuffle","master":"a8d5b74cb00dc99c4fefff90a2f203b7e73daec3c7edfc71723894db050771f1","seed":"4e7c12a432766826d61cd07bec71147cd4282b2777b8ada1d09be5b873b9c51fb90ff4f4ea75739254fe7124e24696f66313d75289dcfb64ba5f5c8988b27ff8","priv":"7bae6919d134d0f150972cb0d96b0cbb3002d0d3b70efb2f9b03541c3830ae21","pub":"02daefc7677b5d77ec5fd27cead44fb3bd2d089be2b2e9744c1dcdc2e7def701e4","addr":"dd3ece1b6e903523289949e7aff1de580a536746"},{"mnemonic":"seek rain danger defy olive pluck people trumpet wide pave still cactus","master":"9d45b99a256e90347877aa27845d7ce7a259a8b50f7039852c60c16c372202c4","seed":"9c3f7dcb4aada2a8c204bef9a28c039dddd431f3daf5e70feb240be712cbb3dee3e5b65ed1e681255e9bb53bf762d82b95dad1bdedb27d0e18801ef1c5edd7bd","priv":"f43ce1484840f98f862f7d9c835bb3987fbc0413cf9121233bc29e829c779d45","pub":"02d82770b2af7ebb2a5eec49138178dd7899783a1ae1ea43ec3b2a13d6acd90c4c","addr":"49c6feff9794634c9fa66c76150375637f52ccc2"},{"mnemonic":"cat bid just hat diagram mimic field engine light elder resource render","master":"bf8a65e5cde0094db2ec4a5d776acfc944b0b482343bbe167a4bcb0a3492a9dc","seed":"780befda0890785a11f947a7da4280b897ddac841fa65e7cfbb01b09a46af665c25dba88abf759bac86e02d25d90c41347cd872f8abaedb158743dca746e87c7","priv":"b3f9f0ea5881318a1e011283a4e845ef6fa8e1ec5110bcdbb02cd37c4321c0b8","pub":"0214709b38a99a173a8b030bf9392534ae50d157e9e247f83d271be86872846336","addr":"9a7dc12f808fc5e599e2c03f73147317e381822e"},{"mnemonic":"eye thing material display own coral ankle spell hurry empty pitch sadness","master":"1a7c1facdec5151ca8d52af1f507f45c6614d12836d2604421138339c81dee2e","seed":"9c741558ad4c72086738a34898567312930af3221d13b160a39467d966862405a7f9b0b8718207bff6e26929cd33c578457b0d43e2e6358d488016c6ed7754bc","priv":"960704fe746bbf00a1c8d6bada8e500f2a7155af9f8328b7e4da7fc89fe079cf","pub":"0217e48b2a7ca750baac93ffa241b6fd3cd2422989096e0ff5eaf89f23277efcdd","addr":"13c55c8720eb51b5638331330ca19291213fdcfd"},{"mnemonic":"attend analyst stage network secret matter tackle safe stumble rifle lemon minimum","master":"e23dd8723b90971d4e03e21655e597b5f8110f0388392eff572e88db7f644cad","seed":"cfde90f605bace06583d24be20b13f73b3fd0acc60fcd93c2cb7d4eb6fcf70c885da2da7b709ba036ba20c275d99dd3a6af434b00932addbbd7b51a10cb5ddf4","priv":"ee54ee95a349da703f6d192fec6f776db6141a0cfa80372be04ef8b12ab65f82","pub":"020850e7d1011e08d7fd3ce20083b6c2658dcbdfdc067c979bea22d86403da9992","addr":"d834b0d108165f814c2616c91e18ba8b76a0ce92"},{"mnemonic":"student list element dilemma air faint eternal beach approve virtual fold large","master":"0dbc34013e5fddd9a1fc2d3e67a2d6d7445bc31e8343b4bf1a9c4941a24a2691","seed":"61b310aaa1875695f855a341f64b849774e3746db36303ada42eb60bbc91bc0fa7199c10f853e1def5fbf0a9ff2c38dcd803866d5473808a5b6340d88260cf57","priv":"ece1069e2cec7f5d270c3504e0cd9d8806eeb7ce8ce48a138c92d93d68fc9b7b","pub":"037989ae45a6a1f0ffcf9f73f1910a91bdb1ec39101810f3916d29a70b92232949","addr":"10c79559de51b7b96a7e0aa97f567289c41df1b7"},{"mnemonic":"ordinary fade chapter cheese patch injury better toddler rare manual rug opera","master":"ef81a17192ebb6e980676cacc7c9ace6af5d449a3c976d4f9a8a541dcef9d7a9","seed":"5a277523f2cd468b96db9dc30f8dec2d006035e388ef5348bb327eecd108d9e2815b3575b0f6d0da7560fdee6244194eefedb25edafd6f53019a91063478dca4","priv":"86e5fbe3136bcb11f0ed6dd97e3fc30afc0590d38b637fb19589947bd33f26a1","pub":"032fc8cd996500910443186db8432f24eddd6e04e00aac15db80cb5fcd73b7ec5e","addr":"db0aaf4c44693b2b93a8901640b940104d4931c4"},{"mnemonic":"leg easy evil ceiling candy okay afford apology around duck access ostrich","master":"098f864a847ca737aa5866f14fa96e9e5a6958758b56bc205d5c45f77b2f6fa5","seed":"7e6d013d39c652c2d57ccbec782fd0b9da7610d3c716b1c5f374daabf44f0a21726cf39b503850a5fe7daac263cd12dafe5c81a38b47e59b254027ceb298b520","priv":"1b5e814a954729ec4d4d25e01b52e6a48fc3beec84e43153cf9e5b4d5e61b852","pub":"0207214c051cc66259f234100e278a89b7ca3185ecf264d596ac8a4d3baddea28f","addr":"45cc1c7df7fb67a482dde6285b4dff7087857970"},{"mnemonic":"episode suspect cinnamon recall shell search allow hedgehog web avoid hero expand","master":"ede0db7b34ead2b35bd378d62d1b202ec206a389e27ba6d70813e3f98544f7ea","seed":"186c47e08e2fa1151bdafa4c8d16c5f6d8e9a61600a7ed76257cd3b41338a6d158d34ab84448c34c871243e211fc5082d3a6e199749ecf5bcc3fd8341e2b7784","priv":"d19884813f89a780962d2bdb40f36debddb81d132baa29795022b9498f04de0b","pub":"035f028dd1b126d6ea1b8091ac9dee9a3f44589a166d84a88ee982bc040c67d1eb","addr":"77b6f1f39bd0c5c636763b855396d1fcc5109778"},{"mnemonic":"safe run differ offer valve sing stomach table update base pitch pyramid","master":"1f6e07713ac34f997bbbfa0148cf2cfded624ee8eb4c89a66e2a88af2becaa6c","seed":"9c07c30f9b29fccb62670c57b8bc2210851ae9c80a3aee48c03e6bd35357626ebc6af1226f236508624fffbb52a8cc56fd21d8d2ab72a893a931c4891a33bc09","priv":"94c75ada800b2f73bc43625d569caf9f59f3afab6c2a8f9b023abf169c1a50e7","pub":"03263f919a4f79646ba17e1521c15f30d62c545d59c12344d4ce7d7561f8dd8428","addr":"17a63a29abe177f8bd93648ae4283b175b83c841"},{"mnemonic":"bubble bracket panda fury turkey decide obvious nest carpet defense side destroy","master":"d429dd03c2aac3ad66e8ea577ff48889d6ee006906f0d74be45d935c11f95c4e","seed":"d665e949ccba3afe3d3e14c8328f9d2eed1b3838e97a12d137bb188b4480b31f5f8ff388c4ea3aae961e6e98ae40177bd7ae075fe09aabfbab8140da075e8702","priv":"651abfb657e1b400e230b0fa3de8c022fc6fe33c2a80e425b13a3485aca1bef2","pub":"039d2e95484a02e3be5176e31ad41d9d38fd616aa37bc2f3032594f99b1d4225b7","addr":"cdd7ea2dfee41bc45d88e147ca87f15cf0278778"},{"mnemonic":"magnet setup unhappy slide human frequent notice unfold use ticket raccoon worry","master":"6a50fb7353ff7e3eff6054bee3ed8a156e3f4d65d712ef024ebbd58c11b16223","seed":"15195988c4a41524602465915d8c66b71acb07f8681a81bfcc77f5e8ae0071da3d900792c6666ed7f42e5362d1b22ec5de2856019e1d98d34f3bd977e5d6e712","priv":"e2e5997cea44fa966ed05107ee5347fe245ed436396a54dbd7bb0dcd45b02a5d","pub":"0251022b3f87060b140337f8a192c3037fa423b86f761c8e8b9abe13fdc7e954de","addr":"fb33e8b4227a4e31ee6d062f14129d86c190b864"},{"mnemonic":"extend expect crunch wear narrow crater opera dumb poet tone crunch eyebrow","master":"3a18fd4a5605d4a691097909a8fad033a9eacf3a8a6abbffbea184cb43bc4054","seed":"37661f80614a95188f9bf047b8b78201ba0512421b3fdbdb079d36cff88be9fcc6b2ee25a98495eec605c23eca528535adb4381b524ead9327671006a34d81e2","priv":"66b6e15ade42ef203b614a0d4db859263aab55cf9d98ae2118cbae7a2a8ba190","pub":"0318a0e61048878782f581429fdb2acfb382c59ede2a9c9f96112fc0a4dce78702","addr":"d3cbc69596f7f398a77be321ab4b306cad08798e"},{"mnemonic":"genius genius letter space share rich lava tenant drastic today vivid attract","master":"b1cf44f330ef51b5bfc09c224b83f3f678381b54328d6e407368f34f6b96a7f0","seed":"adbba0a0b7e15f2e7a8f95b0cc9e3b212fd3db246c0dd0b2dc41fe740c2d045aad24b9113dadc5b72d7e53d6c681fd702ae46b6bac877303e1ef4f9b1daa2822","priv":"4bc6a6a787283d7110cf4dd8e5f41b5abfbb302a5bd627cdc78cc419bd77ecf2","pub":"02fd610c024bf89e83940d0a5142c1b716786ae7c02e8779de11b72d3474b27260","addr":"f31609b8ee21b0da14e6d7ebab364b57230a8cc5"},{"mnemonic":"shadow ramp scan elbow cinnamon intact flash bulk squirrel pill zero tail","master":"46e4cc1975a8a363b8834ef06ff7a413a6158244a769ef15a9fcfe8981a0a6de","seed":"a8e143c8945640084294cee0afa09fbe4607059c8497259afe64dadc11b18b2d0eea33617b28b0f80419fed842afcb83fd1ab72c163c65e798bd1668cda9ba43","priv":"914a656705241622201d5ec8893d0d2484de7f4546847b3b2b2bc5afff743547","pub":"02f44993307ba52f2a927c5e7f7aa0baa6036a1e396d1d8593be5fecfd330e8d70","addr":"f966ac61247fc88e7d8a8eeaa2e682a669f17e81"},{"mnemonic":"wire list water over regret much ketchup slim capable proud then bike","master":"161946d516fc549a577b76ca6361f97b95ec58ec3bd2486dcef7f0d9ac9de062","seed":"c9af9f1c0f7fdcd56a69faf1274e563dc8ab739fad639e2032b4c0de10081544112b54ffb36fa1f6dc6419a7c073e0f3b4f2fc1a9ed95e4ee7dd300ea15d48c5","priv":"9f7f59143beb62116a592e3884d34d28a845c557be670278877c34f3749e74dd","pub":"027ab6afbdf54f5e952ac1d254cab364ffd91d49838354b02415a97421f9b9bdff","addr":"3824d1afbe44568f2ff4762157046e8f9bb561be"},{"mnemonic":"elder stereo hurt upon process furnace treat tool hole return base protect","master":"331d45143f0f94ba73de22ff235fec62132559735071ef806fb696e36f113352","seed":"4967f2af0a49298099ac49d75a3d99b99edf1165e3507c9055a9cb39a69aa05f6c07c192984e86f6abec6ab9b7fe8e66d22451aed158a6664ecd59b48932d9d2","priv":"7d547ee935de522967f92d0114dd40bb5c25d4f5aa2a1f70ad291601b7d0eaf3","pub":"03caf4c539853b640bf55c9db886e9906888e05fad3e18668f6c6d529434a73f32","addr":"816e255b2ca6837ba06d35fb834c3c246563d638"},{"mnemonic":"faith ski shell chest left entry admit smooth since hire pipe firm","master":"65f1eb6d72553cefc6fa5202583bb6db0af228fc0f008af45a3301cfbd279e05","seed":"2b778002d9097d84bb24e0dc577059a08e0dc24b47d401a37ece9b43c45585d49ccf9fdc6dfd87dfa2c4a70a226b9879f0927b0f3bf33b8f25573c1b6da98679","priv":"249dd8ddb06d455e6883a7126084aeccba0193a8ca0eadc6f924c16922ad891c","pub":"0390281dd22e02560114169d73fd72ae58ac7a83681a8d985cbf25fb39b485ba1e","addr":"9fb024edfc6a4e72e4fee5a4387c7bf09583eb1e"},{"mnemonic":"junior bracket pigeon swamp morning kitchen friend bike question emerge month faculty","master":"7a3d1634588a1d344986c5bdb8e5aade22a0fe74b5d234bce3591edfbc2279e9","seed":"4429c5b3dbd4db57f6ce8cf79533a746db6c28e1494de3610f225eeb00d2a6fef327aa17d68c75ae552c9c76b0dec4e06c583d531e45d6ab1f7d5dbcc259ae29","priv":"20b7253a740bf61bdee294c67b31aae21f90a41b2bd31a02267a773af049f983","pub":"03531e337b7ed416851867015996fe06b19a82bab432137ac32c914503fdf7ef58","addr":"e225e41ab3e0798b3631d71e753179bcd9226ede"},{"mnemonic":"farm frog apple capital foam behind grid project vague rural ugly sail","master":"22f4185158d434b8084c21d62c2fe3e653f9f1c5e2d592d72188bc36e9194e57","seed":"b92f9f3c0d496fc264acc1c04a42bca773f34137c92bb0f8fae52009166f48ed36d81c15be9e8eee8fe5f1ea2e7e0311a2d2b683285730cd6657ff862947ec4f","priv":"696f26ebb007bf4615ffedcb8a08ebc1b92be88955fb34eb5f08210970d566a0","pub":"03bb83731e190bdf7777058603180bc89a85f4bdd68fab3ecbd5c8a43f0e9bdc93","addr":"9c9f3d7c144c33f06ab476c752227c12149d9217"},{"mnemonic":"spare twenty above tape monster topple brush excuse squirrel pigeon maple fun","master":"a1ee9e1be2cb0f318e9cfca44f99ce405115ff3336d1678d94904efdb71f65c6","seed":"e90734515d14ab1b96bccb6f823abf76f21d47b450841ed1fe9ab7bec8a0e673828d09ee61b6a3f9bac0dfca778287abd21d70d45c596cd606261bd4baacc98e","priv":"d8239cc87c27ee5b6aa13d55505a8b0b2785392d26b0945976b575867b3aa068","pub":"0314db00f6e43e36e5f9e6a30cb2bb595cf4abc4cf26ada7d3bc7502b0e6be8919","addr":"fa50a1e20f2f4e490359a011ae4277ec61ca2a61"},{"mnemonic":"token cruel spot firm initial trouble slogan arrive steak inner champion affair","master":"4fd49883fd0f3b32564fa038cb60f762bcf4e65d3e297649cda474a6de9e16c1","seed":"c8b7b6807f2cef122125ddccd237435abeb2370a33db98f34336a28763996b81c336e7405e782d61f6b391b0ab2792b3788e27e67cf467127a50a6b2603820ad","priv":"e57e8f46f2eabf828cd024b4c7935126c95661bcbaf58488ddf7954b1a4486d2","pub":"03d959dd4d72e64be96260d31018ff3b3cc626ea3b80af1d6c3f9f8ed6452f9da6","addr":"e03c8d22c2e4513ffebefa5ed6e89245d36c1741"},{"mnemonic":"gentle whale exist height dress develop beef lounge apple gadget foil sea","master":"ed29987b8768b2f2636556eb1db2a69d48e6969f8b5ed455e39d6239ef376537","seed":"f4a08df5d89dd733e9b73df8a8518a0f3b632debdea655ea75b8b5b6afcc7c52d8bc0a2cf1337226c2e065ca0d71b6854109e360da8037b9c2a01156b2ca2b86","priv":"656e7a54258d7e2f4c493ae80e28c4eb08452175635cf0cf5a9111bdb6f76695","pub":"02f5f6c66a11efe81e76e7a5d440b9ca1b0dd73429426f4a27f3493f5dc7140927","addr":"e01072fa64ebf18099a46ee3799bffb49b990972"},{"mnemonic":"warm offer tattoo home elegant sausage sister cancel rocket struggle insane theme","master":"a58d8e3b8c25c182f6ba0e9e61b8aab35c04d846d1e44ccf3b305bbc03d839f7","seed":"ae94ef9d748fc2b348be876474f261458e3653cdd3f10448af8ee2caab848195cb802050f7d5d098e737672e331f1e48ee0e14c5924665f0aba855b89544f1a0","priv":"4534e2a9248df1bf1882da1a11ac8401b2db9cd92e5c3698d4610d120e6ff882","pub":"0246a4a61fd11a856a818f3726163b7f2f5f41b95f5ec513554f7237d8c85c867c","addr":"dbcf36e66ca99566f38ab8fb86930494c28405fe"},{"mnemonic":"ill orbit raise deliver fat age remind throw stomach country duck neglect","master":"9899f940702cfb78dbb9fe8d743301e2de5129f943c8dcfc4215e937c59280d8","seed":"789537517312103fd88f70345425c402bf0c665c34baf7d3e24c2c969162afae078adf365a0bc732de7abecda4ef5b12e213f4027a9e0ae621dbb6a16532ecd5","priv":"cb4acbee9d41eff9ef210ca73ed0ac71f353464210fc29b30c863a0c23214653","pub":"032779afee4e50503db9c67efc858d521ad8454cd691febc52540c4cf96ca92231","addr":"bc60e5da2c9e96698f32bbd087bf1b3b599a94d5"},{"mnemonic":"fold concert earth alley broom render ranch worry motor virtual industry bullet","master":"3eaddb6d4a2a73a1f0d094957901b9a53f4b36ef00451c9157a3dc159b523cb7","seed":"479d7ca92dade2e47b3f410fa563624cb9a7419921c687e93aba27d82af323bf1d0f04d12faa018732a476fc626df000f705525706a5e5958afe59891f10e43a","priv":"d0e151f6b58c2f48d0311fb2800e66db4fbd9ec14c92f84654907c5018f81c98","pub":"0372820ca8fc7a193815e924dc1e7fd405afd0b03e39ed8cd01a33bdcd35f899c6","addr":"90b134c6bb272ff804b6117fc1d6f3dba538e3d8"},{"mnemonic":"grid street boss erosion spike bunker indicate erase path mixture inflict group","master":"c5063e2bcf9fea3164cc8bacdac300a35b0b1dccef63e1de233ab39356249b9d","seed":"2c98b2b7703e3cc2fbf089d78184f2cdfcabc7bf269ba3b57e7b033629fd149263063e3f08c0d7fd3a785ceeab1f9b2f7e383fd2dffd7d9e982e7342ec90ee64","priv":"b6082dee45243a3fcf3313715ee9a644bb95d550cf8f275a99930372bf265e59","pub":"0282b6a0a9dfbbe648db6afcb9596fed1c02b8d7264925c88ba7007cd5cecc10c1","addr":"e9e9b9eb2c9d88b080af25d6c5fbf425e86c8f9b"},{"mnemonic":"flock entire rent cricket shadow inhale organ pioneer pottery faculty west umbrella","master":"e1beb66b50360f8bf5253b40e1fae368fe8ce267dd992a951b06896ec8e44404","seed":"267dd95caf4834b42cc69941de4dbeb3b37321af83548c865efda2b3cf9eb983c8244dbe65af863f0c88d2e0bb530d7580a0641d23a2bb98c4b64ac4b38d84c9","priv":"b35f776a36af618b48658829c0a914f8ee193070fd9b88ab34f3b4c35197ea97","pub":"03e030c12765cdf97520be291bd25d0a34aefb295f7749904b9aaef1ece99cb3aa","addr":"5c842dfe540f09579539e1fa6e961f929a5b7b60"},{"mnemonic":"all hurt survey laundry follow earn car music online reopen boring monkey","master":"56a9ee4a3e11b98885540ffd3e639369e2124f9d9b7108894cdfcb154279921c","seed":"ad2252df70bfa330e6a7c48da592336d202ff2f91d1654d34e9139ab644d54a04f88f3664822aecf8565453b58ab77a6785e81ecd7156bd7d560ddbfecd8a287","priv":"4181c26d8062eb8cdd8464524bbd2d82b56f423ee8aff8fe49385ccf98130a4d","pub":"0336b154ca3bca67a440c55add8c0ec34bdda413d57e8488ec58402a61eb93f861","addr":"2de1dd6ffa17618df2f9361a427dfc9689d7df99"},{"mnemonic":"obvious spot fuel leaf company birth drill baby lucky oven since fringe","master":"c75aa6398d3568764b147d2a951f2a93a38ca76f3e380e0574f35a6a69d0967d","seed":"d2793c736f85dac48f03f67c39b2b943b297744268dfad708ce9eddb74c649515632a25468a3d444bd07a0b9c4c9d650ae8676737e8373edd1b0f672206d7b72","priv":"cc9cbdf4b34dfcafad90d774b31313b08c6861e6409d659ee77afb75a1ebfb86","pub":"0251043d6ed5e0325ed3d7cf2caa3db8eec2a63c4c5472421a37831e96fc5a2bb3","addr":"9f75fc6e07b3935e5e8f3a39fadba8252e10cb41"},{"mnemonic":"funny online improve knife crumble critic grain vessel wood inspire venture ostrich","master":"83a4036503ba3499d266352b5d7736d5a16519870f9cac08d4706bb3a57e5d7e","seed":"23ab1c440ecfdba702427c5024503232b28aca8de6cba59d7ee1e070e84a4ce15cfa84e06c84c9907fb6bdc9d73c94abff5ce5c4828da89631cf77a3b091cb7e","priv":"e7cff4b876f286e6a8181763e453faac2d92582b0f9caa41b5aad8235f79ee86","pub":"03f2a9ed2bcd20f9ab0b50a3ed8f7ecca7c172997cbc877a896dc9ac740ebe03ea","addr":"ef1badd2e02541f774b7ccfccf8f550a0da31f48"},{"mnemonic":"elevator scan glimpse immense shoe buyer punch tomato chuckle art catalog coach","master":"ce00293fa3230ba3fff5f53d163acb0a06bcebc77606c6c22166f29d4f84d290","seed":"e06c12a0d1f8bb93596839e0c3c566b5b59421226c1523cb54f86e93e391883486e86807472313115c366495a9973d34b2c7cefd919f0023bf2039e95f22ba72","priv":"94e11d645e24aa3653caecfa6cafb3404a6b107c076fa2fc03d3a2d3127c8e95","pub":"036ff6332fa0db2db68b6a74a68ba0eba2cdff43f896de3d4b3b0d26ad1017b608","addr":"82ea6dd1ca5f8bd08633e5b69cffd8dacbdc3993"},{"mnemonic":"emotion super skull trade tell drum lake scrap alley reopen true prosper","master":"8bd8b2834c0aae5a8a207a40ece04ebf9fec51892b8c75dc7e4dfb256fba3b6e","seed":"6d9fa2ef59c1cd981a97e8d3e788b8bfb9738ebb23561d2eb72fd3bf3741e90eaca1c4e821e711756ad8adfb3c5d355f55fa8f7a41ddf260a85288416228d257","priv":"5adc84e56a3d3e6b43e1d42d01f2c7ab1bc340cbf8ce99c30cd94323e1107d9a","pub":"029aecdc08e10d442234814770ddd891241afabbb088e7dfe41f6ee0edc30a7581","addr":"19ce22a905e023e40b9a090b750870bb4d220d4a"},{"mnemonic":"federal math bicycle copy diary bind clap dose clown fabric hover draft","master":"05e5ae86313b56b4083a77339441c22cac4d675f18089028b841e12d0be35480","seed":"bfc46d250c423dfd4f123a91d8c7d556d484f1b8091132cc6e288fffb4b786d721a87d93414f71fb87457ef7b4f17d65d751fa43d7d67523d95997e357141ce0","priv":"760e1221ff1a283d14bc3fef817244affa4787036a46d3009d53911bb873dd4d","pub":"03286bd104bff54d0d01837e72b47e1bb582c13c78311a73a08dcffdf5d5e6bb42","addr":"d03ae88abf654c466a93dc167be85b7d1d172e38"},{"mnemonic":"parrot poem unique trim auto april under pear brown flag critic ship","master":"438ae7958c45b13e2f2d275f52ef71e6ce20d00545051101fdb5be7e235d49d2","seed":"85ca4c5faa1bd0c0a3b74b8a9f5afcc0849be00a0d1e67222a7b70a9f6343c0c637843756750852dd6247d311ae14f581b642e5c3c4cfea3b689dd1c9d4dd18a","priv":"f725a96177c31ae08f065255578e34f58145b921267c2a2e26f09a3fe0d58e61","pub":"02fb792c0736e01eff225a1cfc6f56ccb8ce70fbbb9c050da326ee5475fde784df","addr":"d096954bbd94038190e6aa959ebb8e6d4c5cafc7"},{"mnemonic":"expand enough goose wrestle title hamster purpose illegal peace patch moon spin","master":"fcd43f2a177b9c6f19b22a5864b41a30e9e4ff29cffad7663a6d5e5574910a2e","seed":"0dcfb2c19f6b6b6560db73bcc164ff84e117fac8a11027b0c8c2caf5c97256961e019dc1ae14752af47abd7290cddcb8400084eb59b8ebe5fe1b148806c422ac","priv":"645c6babf5d7abdf9a111ce1ef7a860466b73c47d2afc83d5091265dec741fcf","pub":"039d7f9485265190c0986c0ea74c065beefaf0b8a567c2502c122139f4f7d0f834","addr":"9de7c6791416a501bc1b3dfa5940e4ede894bca3"},{"mnemonic":"property grow toilet hollow slogan pioneer gate fresh still notable happy peanut","master":"9e289e0abc03cfab28e00b885be5328d88886a24e71d88c120cfcf697e1573ff","seed":"3deae69499f305108ec27c7ac5e844140b59316a354d08a9571e671d5f71ed8a35e060b084deb4ac2f55c3968184f7b625246c5635e8ae85cb511ed87582a712","priv":"3765a9eaffda6c370a95ca1c2ecd178a5a7799034fed7d051a37f658e1db0fab","pub":"039bbdd61b3e1570f585fe38ef1ff516a4d1ea27c9d9a2b11775f9f462b5e1e764","addr":"c0a75bc9853ea8ff8070b22b5e6b22c57ca2e820"},{"mnemonic":"grape arena buddy shrug foot fiscal move transfer beach else alone city","master":"903560571ef0d4cc0fc20d79ff830f6cd360a1ff387bcd893b436b8d8cc4a4c4","seed":"6b232fcb4175b92836ad60e8cb9bdc82856d663558adad2fd001fb71db4eecc55d0a9b0cb62c938c8e699f0bd55f3e773080cb3804d74e4c7503420b2f0640e6","priv":"b693be937db9f0aafcf2b68b9c3ad8dff86d250f4d7c7ce0bee4fec7cc164035","pub":"034178d1a76406edcea9b3e501aa11161cdd14d6760769cbd0070862148192ed81","addr":"91379f6876f01696ede09b112da349125ae3db9f"},{"mnemonic":"spirit march luxury planet review rhythm mother food orphan inhale dinosaur ginger","master":"88b72d270aaad97e466b4c6cc2d5376e0bd9d5d4389bf1c5e5fe3cd60eda1cdc","seed":"ae53ffbf1695fe13e7590e3c0d225621f392ba5885387cc5ba1ddbdff13f83051293be338369236cd2cefb39682019b257a4766eef632cb2f805c226a611d5c4","priv":"8cd4d3c8a6a6a18eef4b30056d4c23908d100a30566ee7ed486f96831be8657f","pub":"030dbc527c5e03ce3a6ba9caf81c44f0dd0c0b0374617efa819a71319879027fef","addr":"345000ace68ff89bef2f2c197da7f50329c739a9"},{"mnemonic":"cause enact push shove account orchard grunt sausage mosquito deny relief sun","master":"d66d0216c675ef09072623aa75fd8a9df788af3cf26b16d38091ba5ec8cc8cb8","seed":"07d83a41e284788319bc0e5b9b7b1849485b2bdb8cf408843184f09b1dededf8ca56160aff2f6ed2e0559e0c005f5f0dab7b3e36500db5e45c55612091818f60","priv":"bcd7f078131f5644373c0e0ced2f33822c116df476cfab34c39dc9a8d5b9aec2","pub":"026c0d381a709b557135d33bd1760de196b604b5d720269ba4e8d749b7737da2e9","addr":"7e268fec12b43d71998eba89c8e0df3205c094d6"},{"mnemonic":"faint jelly paper blush cute hope project giraffe muffin strike pistol blood","master":"3e2eece9505cdbdd0e44e237a90a023837b45c6305c01802fa278d6690afe9bc","seed":"7ff4975b81e3165068c8b861a748013e93614bd56c4af844080373a3c60d0e763d5c934ed4d4941f195e97eaad4257eb55ef4842d43ae648ebadfb82421d5b7c","priv":"d2e9c0441d876bc0c189a109a564404e00e3a7540cb2f84095da70e38321adc2","pub":"02a49b4d38662800e8aadabc72fc7fd3ff080c9c9aef5cc3c3970d6411ca92d2f3","addr":"b0bfe3ee05d361865a65678fa612cc64ba633789"},{"mnemonic":"jazz ten exchange horn junior frog surface blur color pill bonus science","master":"037073838661b05747c80ed9a91ef9fc07db4f4b9a89c56a26a517d74615a83d","seed":"92333a0fcd8cc74457ded4de145027c19de4d04d4e791c0418092ff599869c5a0f7f585692c0de272362e6ef3a8d31fd793e83701f1aaf41a0355a818ec061d1","priv":"04cb6c660a8006068ae929e97db3b29cf55093f52bb7292d212774db7b6544a9","pub":"034a39172b568cbecfe119e7c751086392e0a6b8c5ffc755453596ed74a75bd1c0","addr":"bde2747790882434b15deea070cd36c696c73bbc"},{"mnemonic":"chair practice neglect hawk panic sponsor ritual bid sick fiction vendor defy","master":"1f908e1559b37dc8ffde2f89ca0dbba2202260f6a848461d75cdc8791f53a1f5","seed":"0fcf390d0c757b52a520a2fc8c30dc740b0c481adf1e17a6e8d445f355c3c266bad1671bcdba99fba9c69e473a294c5e3f6ac51027a1048987cd3dc7a52dd3e8","priv":"6444a8b09434528113de487508dc7e30cd184c3a9f52ce20b30c7b6f40d5a031","pub":"0344d47049e125a655b9dff7de696e72689ee478b8b4f13a0bcdc71df4737689d1","addr":"3ad17b540fa37171f21fb9d4cf6cc061008ce652"},{"mnemonic":"dilemma main solar balcony differ bring close popular couple educate hobby mule","master":"2a9a19b24310a9019114beb8d3222df214ff8eef4ce190e7017bae4e45861092","seed":"ed8bd81a4515d1c43c24d69aca3ceb065d0552b79ad01db75ad19c2af3cd23a6a213163f9db3743d3b2fab6bc166954b2285bead616d1a50f036bf144856e762","priv":"1c8c89946f2dee6c92348f5d82506ddd9065f83b2eb8f8d173cf9642b971a0c4","pub":"02855f225d510b6b0d64fa5abfc9639488358272957b9003b1bc697d474577c45b","addr":"df365a12508a519bdf095aa5979b93acf59681c4"},{"mnemonic":"sudden cattle enough output make code tonight matter reduce enjoy file prison","master":"ab474b0afda779ae957963eb8643db33d1f2d879a5ebc2a79b5d8f2f9946223f","seed":"f732b62445528f4d96e0c95b58c4459e8ab7528d47ec2a925e3f5515e1459c952abbfa40fa5cd7f8b7c2f059e3df2c2a5a3813b4c37e322c9f2c8f55e66ce3cc","priv":"5d5af8bd1921fe03619088250bd74a2a1f58bcac8158230c0cc0e7ad304790e8","pub":"03ce0673f40df25344d5f2d85a374d6d40b6ab5b8bddeb5f9e2adc9120e2242c17","addr":"a9f1d96cfeeeeb011efc76ac43d3d121a2e7195e"},{"mnemonic":"oblige broccoli transfer midnight display talk jazz wall fit harsh kick ahead","master":"b5e760adc086f5be87b58aeabc63d74d018aaf2f673205620685c4ec32776769","seed":"3fd39274348d2cf5ea5ab4239dfa66dc65b33a7f4975b25e334d26b67e32ccb4865599f9b4fddfe8cf8a2630cd5787ef0188371d1563c8b9880b33201bf259a4","priv":"5e9b5b2a5628a5a57510469db849aea45ee2989c929bb1fc06918736f115edf8","pub":"039e5e293c463f16d26fd845e92d4503e551013864e5682e1c28bc21072589baeb","addr":"a784eadc4951c1e92e63a83204473dd467f5d558"},{"mnemonic":"prosper must remove pulse wink rabbit shadow harbor equal twenty air muscle","master":"ad8244b4d4221944b73939b681b275f280e1a8d42fe6583f63740865dc6483bb","seed":"a3258a6176d098bc96dced14718524f05669cc6c9f3ba5680a56c8c80b83bf50f32345843aab72e13df9bd8727408ec114bdc0099902857ff1889bd94a3a1388","priv":"32fde5f62df796263bd40267e1d1573f73d86d2fc98076008a5ea46092f8d01b","pub":"03ac2d243cf6580c8c0bdfc091c8ef1afffca6aede2ba5375e149efd2db54c23f4","addr":"504cf87560e4ccf69ce6f81aa5b0b3af45ec2899"},{"mnemonic":"harbor focus scare envelope slow margin boss giraffe daughter mouse hazard step","master":"28831264a522026221c9739fd286152e1123809699955d06149f34a0157a667c","seed":"bdb6f459beb7d6627a96b920ea39dd34b38b21cf45bafe88b66823c5ff02babd02b40ce25a9ce7b4d04696294910a967858fca74b18a5cb46f8afe294ff8d56c","priv":"4834d0601e457f6903e3dc08b3168411c351ed97df34a0932ba19f7bcecafc4b","pub":"03ba2538c15c37b3e0969adeabb0e5e1d093170f7e352ce0696aeb9e5e36150295","addr":"a259af3663c6ed69b149c94f73dddf22e4c91442"},{"mnemonic":"elite magic excite apology sleep cable refuse carpet ethics fortune assault hazard","master":"384338593c8198935c4bd0ced828784a7a26797b5e68212f7b142d25c5e8bef3","seed":"4ad678a061c1fa3351872cc3451c1410f5506919afce9ed62e5dfb05e9be36471fb80a5a94312ab603ec397cdb8ccf9acf8ce405fe7b834c9b14eddc570d5411","priv":"d07f63e9ed19bf7c7f89a598727dabde42bbe0e4cbdfc0dd889f8b5c4998a023","pub":"03d5199768e4a175f47831e46382232c217d58e94aa99f5cfcf7e85887865d4da9","addr":"427a4855b7d2222cc2d54dccc2de0b225b09c315"},{"mnemonic":"awake robust situate increase salmon tell roof agent grunt wear license kitchen","master":"c30d435feb0cf93a3cebc4584e94e00ff40ee2950cb3053ef2f7832799bab885","seed":"b49401408240429ba30ebfb5d9afd6fb74e79971be6b9f76e3810b83ab1993958f2d9f9fb5b75dee68607a2510ad621968d384873d16b4a194c939ff1358a67b","priv":"def35e61e636973967024d7cf9ee2ab0c232348c70fa25b945d6d4a6f220b9ba","pub":"032255b26a5ab86ade14eb9acd3c97e774aebd710b00e81719d04d7dfaad37251f","addr":"aafe58c581f30d3a55de219c15724e2b26dd2c5b"},{"mnemonic":"host proud little want shoulder guess acoustic spin since slight myth detail","master":"200f4964bac08715f0dc5bc750261c71ab2c5e5b70c6e20bf748aed10c4e6ae2","seed":"3fd02e2249ce332bd4f4bd3d9c0ab61e169d0f0c011a826d072153001c6f093e7fddebc437bfd7b9dd60093686147e069c4ff3806124cfeb02501b807205c47f","priv":"005e6a885009202c44f2dfd911fbd495214b9c53d2305b52c6bd7c1a2efbbb17","pub":"03a99eeec3b673289bf785c9482ee94fd906f992dbc11b6e0624e0c98c6b9ddefc","addr":"57a1472c9d2e1d80bad1e84b1a88356d973cac1f"},{"mnemonic":"chimney organ announce town worth finger donate hint vehicle sniff defense famous","master":"8059f2264cbba67a9868b20e25cd6ea7d5ac2c77a86b5f36b9890560b8ac9d42","seed":"a2317e376ede3b6bfc464a993815e5b32c7e2d896b462a3f636cad9e3837f7b454cfd3ce17e221a5f46a8b38a8eca74f6f1508d376ac9ebdbd92d6603178e8f9","priv":"e8e7e337feed5b08f418d6757b0cebc3cd2e037fddf8ecb51b42c1f71d83bce1","pub":"033ccaccdda15edadbe824e3340c73e27303df9c1e40037d0108bb2dea87e84235","addr":"13ae50b4bb386c1c5360404f5f43a2dfd95e1967"},{"mnemonic":"wolf found absurd device rare desk average water excite ring chest version","master":"5dec910d707536db8776b138103e97ed8a34d75e89d79c3657320ad9bd064d6b","seed":"421737ab059b231f6bac2f012f4472ec7215f94a5c9f5cafeeb43bb03d8b936c39afe6a712530fad6a5e4bac736b7ca12e488b3c377faf58476e9e8fe4897829","priv":"17e9344eade9c62a67b5d72af06616bc455ae6f9aa03dd48432efa2a242356e7","pub":"03776634e0508958ca0a9cf4f15b038f544a4d2d0497674ac7a1deef315d80ba81","addr":"63fde94bb741395136727075993a876ea1e59336"},{"mnemonic":"disorder improve say diamond present elegant evoke latin lonely muffin main resist","master":"e8e118fdfad2b3eaaecb31ccdb8ef3ef04e904c543245766a7bbc365dbe37174","seed":"c32d703d39d06d3c61464db0345ffe546f020678149496ee357acb0e93f9575d39ed2309f46917f89a2a299f1704958806f65404ad80aacb295242a91c0f6a53","priv":"947651ee70f613036de219df6d42b78dd5d1504af999c5c2ac7cccc656f578ce","pub":"02e0ca79766b0cdbe0cca0c4d4647e9d82740a6db151f0ad56df0881a0799e56b5","addr":"dd0179f1d538a9c67a42ca0fbc262edd506842db"},{"mnemonic":"define lion input friend used deny obvious basic fantasy initial grit jaguar","master":"e749606fd4eed5b54a718207b0c44af3dc32dafdc192d6f26744fe02b1cee804","seed":"2f67dd5c538358009d036e68d2205254ef898826613d01617abfdc83deca452603008226dcf4569f3faa21a18ba72e3f22ba0beedfc89888701ea2005be93912","priv":"59321cf870be317e697723d132c9f52b20ab43a84efa0f53d3af3b2e1bb075f9","pub":"02e681a3823e20e1482ae8888dd3fd54bf8b9843c1e480d36e72f6ec8f9311ef7a","addr":"c13389a74d1657b472efdd2fecfe736872952513"},{"mnemonic":"caution unable glue tissue toast august decide leisure foster session position match","master":"a0ae79723ea7b60a8234be8bae9acd64bad5472f789c7b8854d95862ffc441dd","seed":"9e1e3a5e11633be7f211cf442cf66b9350f2f4d84829ebe6da491e7749f2a9e6a3656feb5edd3584b723a9c4edbe1f2f530d4360f55bb1d32abe8a82d7383204","priv":"b2a560b474971b2ed48e47c0a27858b70c4485256ec288849a97be5d5eae26c5","pub":"03fe1ac82b75d9ce75fec2839d343954429207d4ffd7ad0e037c2bfe50d7f8c68f","addr":"85bf34297752337da3c79c124508daeab88faa11"},{"mnemonic":"pull drive tired success sorry raise top ship visual filter tag upon","master":"e5b018ed831659613748160d29f704367c0933b09ee12a8582f36ebac586ae78","seed":"1bcc9ff7923777f97fbcc49e5653ce6a7397668eb7b08aad407c77b5f7ddcc62323d8a566c15b51dd6032a57be69054c1273dd50e2c0698e42595258cdd05e7c","priv":"1a859101a7582121828f09eb02de30f34f6e1cda405cb36fda0279b25e1ffda7","pub":"028e0aafb274dcd1f7f8154bb6f1a6ee6207f69d8d7720c96a0d73e2fb2277f92b","addr":"ef934026abefbf19a96bab8f59b9f048ba4c14a1"},{"mnemonic":"grant enroll monster verb voice bench when certain kingdom nuclear save stem","master":"e8221f0b15c9ec7cac1bf373219481d9952b907ee29914d4506d079ae99ec17d","seed":"158737e586b7d0515efcf931d780a88fe0dbf150133a9f605bfa9c4f0df1b7d1c4f56f9745fe76b51640d45735b91e2a6391e3a53f1200824d58ea8cd9bf25ee","priv":"cb61489db37dc70695fdfd54887dcb61f17ba29925d6267f10999ef088acc11c","pub":"0272502a28dfa3e7ebef4c97ee7ee9817756e84733c1030a94820db6d25c82fb97","addr":"d941f06898ddb082c3f8dcdac5a455ba88be2dab"},{"mnemonic":"shrimp forward swarm olive laundry team fashion run tiger atom guitar blush","master":"e726598bbe78396d7d21a334ad1ddfb95285f72e5c6f015f6d76d7b018a8486f","seed":"7f59fa24106d19a2fc887bfdbd01f1f0c2e037869cdeddc6543354a29952785a31146ae4de6d7ceec9ea95df088dda0f195d491d8be3a6ff63bd427532a1d979","priv":"1bcf9039d65d76bac2b14698585db46cefc7de88f2724118dbf1b0597bea6960","pub":"021b8a68d6c12165a3c11dd81c93edcae4437c983751e8c2a4dc509f2e3bd4d400","addr":"9be822a10983a2c398dd72cb43eab3dcc2ee30f6"},{"mnemonic":"object lava wise decorate donate panther chicken enforce hood donkey lock better","master":"f2e88ff11892f72f22627d7cc7048909ff7403a121a23ebd9744a9017a013adb","seed":"9b7eef532cce30af1499362b675c2b6c3e6333f672c102d41459152f380661115461b1dee3613ee5be55beed081d1655b70d941e819754de304beed5269c5fc9","priv":"e19e47c990399d9bb11760b2b00847fe8b85d7a73c5c4fd99414ac37822b5ed6","pub":"02d0840b212aa20d204c8946877da8d6307b50c890a463a123d7eeaf877811f998","addr":"b85c15ec5abcbbb0991c18fbc788af88ff36e66d"},{"mnemonic":"blade reward angle predict text salad auto drum alert grace valve dove","master":"935ad9d81bdf740c8cec1414d56cba9a807d0d47d39b0d9169027cfa38491fd0","seed":"7888677a5dbd757788a5fa116a954610d3234aed529b85cce2bbc34413db5b7fa4b25ae8d9f4bbe367ac55b0dca61724399f70e5404e346506ea2e5708269639","priv":"a6f5a6d090cfb99f935d72d79e77d00c7eaac00b9d23ac1a4aacd6289fdd4604","pub":"0308cd34578b15b3f459d9c0507830af364ed359f27c1135ec0dce2fb9d256b65a","addr":"f05e198f7feacf7a2fdb37f598137f27dfbfafa3"},{"mnemonic":"icon aunt fiscal day never reflect rapid scatter exist fit prosper what","master":"9bf8057a5a94ecd164969fa719a846494e7fb8f40d6571ff0f021940bdb5567e","seed":"0532364343a12a5b821d7cb9c88317dbf802d8b3f24359b49ff32d79882f89f489a4f1f63e4c52ef1ba92a3789e971d56f056b39cc9b0821b3570ececeee9c3f","priv":"0b204e7b6e74dbf35602dd6914458af9860593d672f3409ceb133e431b3f6cc2","pub":"03d5efdd40e97200646f202db82895e2bbe0c16f2cb29bff1622169787433ffa56","addr":"472be066059dfe1d34abb3564037b0149137ff75"},{"mnemonic":"mass wing office match couch tent tumble rug beach mass october already","master":"1b63074ed73326c5629aa6bb9863f1a3cc2369f50f05aa1281d6b208a787adc5","seed":"8e96902f01dbbb458201370b5524fda040322026f83c8f77bc2e91e843ce6b63581b979f71368038e81aa627e3a10897692c1a215fe27a446ac914f043ff8f75","priv":"bf5a466ca37a2c297ba1ee4ff4ff26d62ff44b98b02a5713fc4b2f7427ce9e99","pub":"02827ec005329241a597b6c7faa5e92a0624179425549777ff922482d2a1f48d04","addr":"67f3445c15a8f34a0a5d374acfabc072c3fdf74b"},{"mnemonic":"lottery skull bleak sand drum domain rice eight card frown world much","master":"8a09b9b68f5f87795c60d6dc08146a2780f410f44560f4519194eb1dc6ed26be","seed":"f2dc56a6fc9f382d54b3d92785724815c9b78866ad586448cd9ca06e59d713dc136f41425b16b28d45ce094d3f817aed13bda99e73659a77c06064a1fc123d07","priv":"09b6ccac9c9109ada552b0982202838b3c1e53a816748176c2a3f6c04681300d","pub":"028211fce683bfffa2067cca19d0e003e9e86a066b40db4e16756723cbb525c042","addr":"9853d04f14981533312e56c75a32f10e98d543f8"},{"mnemonic":"advance poet beach endless idle castle inherit jaguar wife grief frequent wide","master":"c16f77a5a5931add45a26fb906cbffd87c7e5ef3d146b83df93e5a3d5b9ca9ef","seed":"26b3842ad77946bb585a05ef148b8ebde2994c800d30224adc7dc1110a4605c02a6651d30709f5f8c0a532c6976504344887bff1503e6afb6cb8b1ae0f909f66","priv":"58a69857570ddabf8a5454e97655e1a833194b64ec4421befe3e0d9e45ffe97a","pub":"033a877e03d2b871bb879b53196da3ca45459485eb38eac76e938c62979d23a1de","addr":"0bf6320bffe291c8f1c0676ed864232cc84b4e57"},{"mnemonic":"stove tennis wait major grass network mountain before inhale glare bird moon","master":"b1bb7df0cf5b8143e91787646825f92d175664fe68751c114824d5a374850672","seed":"73f5867400033e088b346620983d128294338a0988a8b4282999a2a960a26caa12686db680247520196fa9a1e34901841d999b4fdad40aee63834dab615cdf43","priv":"37af5d2736154cfef5c59e974f1954e541683331de3555976a9e9efffb7c960f","pub":"032c5fdf3604c6ef170e65007bdb75ded577aae6652f099ee41d4ecfd1020cc065","addr":"7ef3d9bcee0b3e3d131fab4dd7f79d6dad548889"},{"mnemonic":"sting nut gasp like spread sponsor march behave zoo vanish noble dirt","master":"9f74f4075e987922ac30b7f5f43bada33f0dd385a4a30a1ff42718fd43f76c93","seed":"4d6e6b8a41454924355067b754e619b663ea585f305482febb6db99d26d62fd1a1a5441b7fa1d02de242f0dd35c965ed62fb0d9bc7a857ba257dec94ce462a9c","priv":"53afc4f00fe2a5003c77e92b4d0837d7c8fc54b4ec1e76e0434ef38aa3712850","pub":"020f710a1596997eb3a95815ef79efb5a7204d3bc5fcff171e067f4c6b3692f5e1","addr":"f41ded9fb4ec7cae1a9e8aaaec7de6309644a2c8"},{"mnemonic":"tent trumpet jungle into loop target myth analyst symbol ask december rural","master":"3a8fc48e8e08afe8b32bc8e9c25ada84feb1b84922ea10135a590927eed2b3be","seed":"7c9d5d2681c85e71d49392aeb0502fee5643e8a6ed60c4b84bcc202a5bada19a99dad7f88e365abb6cce65985117d642ca1ae4733a0863e1cd15fad4edd1e8e0","priv":"56b266ef3f1a45b33ea1465c15dc6ec5779289522c8b2b6588c8cf2c182d2fbe","pub":"0206b8e7a5350358fd35bbf173d9ce5b0ec91ee8c710837b9198b5d5ef327a11e6","addr":"fb059b5167a4fb3bb07c0b3b3516bd6fc84f66c5"},{"mnemonic":"juice barely airport rigid miracle afraid funny combine address guard omit idle","master":"787086d46e0777b03c3774933f35e4fe65b4ff069de5ca9b09cb84caff915ddb","seed":"ed6db1f257a45468761be9dd26ce88f78ed7ed1c488e4affb3a8f8ff8550602848ba2fa284c930cd387188ec4f057c6865964ca93bd181bda40e4059c4fc4d28","priv":"9d6f46f7c329d6e57b2ae84150c23c983bab43e7e6ad7190bc95dbeac977c617","pub":"03ec60e506de8acf2a518ce07e3394421450db339cdb6b91ca52924b1e1c3afe22","addr":"0a4359701fca7026cfb2d196df28e34337a34960"},{"mnemonic":"uniform enter number remove obey arrive print version cake alcohol swallow mistake","master":"047c71cb3066ee3fc151a4dd961a06595d63b393c54e77c756966fbca8a749bb","seed":"3db076729af5e872e92581e3c8d8812b60dbe4ed85a59f034fed43c9c4e0015fc4363643dc8ee5ade53ddf68af54b3d63d6bd79457eba414f45bb0c809e90af7","priv":"557c62286ae6440a2a0b17ea98dbb4992333093a054b59a37345a61de1b871b8","pub":"03ad3f7e2e2279b486c88e7e12d2a97a3860aa31a3854987853a1d73cde6aa734d","addr":"ff0a8d5fca9824e71cdf434cd868c12957fc61c9"},{"mnemonic":"split lecture predict rich inflict flush bike sound credit girl pudding ridge","master":"12fb50c5a687fa1552f07cc9b56d6f5ecb7b68376c3cdae621190494ea279f9e","seed":"29d6e5b0c2cbb22e6048158990f14be89c6c2416b36761c2f4d4de70a3dee2c7f9e86bf6dcfb07e99ac1d15f66f7393fc48b00195b0981f0699652a9f3f0c340","priv":"b02635341dd14b0b5e701222337dce09c3426a6f80370b06dabc31c417d9cd2b","pub":"0365f2fe5611808dd6fcaea62ad335d9b992d1b8f91333d6dc7b96c0b3ac97b209","addr":"ee3da08bcfb0e2fd4331e8b1ea3c0905c6c2f005"},{"mnemonic":"fiscal deer minor dwarf measure goat enrich emerge act view cancel shrug","master":"4cb7b43c2efcc7f6e6d84d5b47ca352ff8aa3c1c44fd8d2de7dc75b3fcb310b5","seed":"f48a89c3f2dc87ad41069c06d0b8751881c993c5895cb548b06974194cb410122d1268a9f962790ca461e875148cba07c216439df21bb37a06600456f5bba35a","priv":"b77f4a13edd7f5ae33725c340b1f8982fd02829ba2756d70f4086dc4a38a5d21","pub":"029844babe3ab249b969895b2b0c6d3cf7a79104721e96ea3b24784a4593fcb7e1","addr":"20a6d611a9ea918d6697d2e09900cf4fc9f676c5"},{"mnemonic":"expect speak gasp outside word glue fluid neutral casual train left mountain","master":"a774f13c1b5a22667ed1d3954ef64f9ddf3f841890b894660bb291745f8c5d23","seed":"7e8078aab4d3b5d121cb17213ee1a06fe4b0ec7d95dbfccab17cd0cae6917151197385c2f75dfecc7221ad518d5899384c22d2641a66250dc581096ff5326a6c","priv":"663b4bbe218e2f6efaa30e02460985ec708e76abd845ca365de83d2bcf547680","pub":"02b78aee27b6c719f89f3f21c55e8c34b9b83e94864c894188a7e39c348622e5c2","addr":"1c716ff8774a14f48623598e80fed3877d974bed"},{"mnemonic":"grace clinic host vehicle drastic april sibling response laptop escape creek neglect","master":"0f2dd943aef0644bf150f38baddc31c3c2a95b813c1fd893ef936f36c6972aec","seed":"e21b62815782f3954ef2be4e9551f7ba47d6f471b566d3b9db6a07d29b42c2edd10e500c7e701ba60963315f21afc2a4ea0d4c187fe4e08f775d3439279572b1","priv":"df825cb149c95352cf0bb17fb8b12cb686ca246c76f7bdfd8ae4633fa18ec30c","pub":"029bb63c2664225dab9c6a93294891127728b77e7d9a9a8e187531f5f154ad36ac","addr":"55266b5a04683c1d61e2cbcf4180d7087550c9f1"},{"mnemonic":"neither help draw cup grief hood swing task okay wasp angle sweet","master":"5a89607cd2cdd7717fc0918d92e661dc7960b5f92a7083482079468afae827db","seed":"8a1d0d7f2799cf70744d682e734352e2330494cc309b2bf785cfe799f004b67c936f3987f75954e18f4eb3adece8e2a3c57ae24b3c8f747884f473cfdb671112","priv":"30a055fcbb2c88fd87963e2ed60117cdf5a82979a7829238f5093f0c27fd7380","pub":"02181e5dacd8408db30a736957d7b19448d5925417e4d38d487391dcdfb8ac4dab","addr":"9ee3469dbceacd60c741f1530646f7550b94be6c"},{"mnemonic":"fall laugh virtual service grit left clip betray wise correct walnut online","master":"7c11681ada91e9349c1e062d0036a29290bcf0bc1564428f7080ee0b81fc5a0c","seed":"c2ab87d2eab816dd1b81ae4acea81e034f2a7cd2cf7103ad3985e739d696248dc0cbc6ff2864e598ae736b58c6ac4f3898f1ddb7eff76413fa1383a63f6c7716","priv":"13edbf55d44ea6951f3825d67c2486a96030bc58ba15d282df4061a0d644a2a0","pub":"0386590dcb32fd11ada507c55069b5607182a1db6ec02c810c79668a27d60411be","addr":"71bdce836bd62d85f5a53f9fcfe2310d40bacc56"},{"mnemonic":"hedgehog light govern fruit season cousin shy tumble maple promote feature lonely","master":"f4575fea61d7539101b4f89674218bf8fb206563cd07d729a834bd7cd8e3cc62","seed":"147de64775c5b285b09b2f846212750577cd9cf77bdc64f198da75003dfbda9c9dc742bf9ef1de8390641ddf9b03db8958cea480e5b4660236e29ef5d2d6a6a1","priv":"9ce717cacb307400d04739f7431fbf02cdaa3ae9035e00e8a31d03d6cf7e193d","pub":"031b6e5958fd3a5883f0cff00cd6dd14ac6cd4d92611e97c4cdd751d76323ffe0c","addr":"775cfbe90a93b73c27172b699506e4b40020a47d"},{"mnemonic":"normal tuna cry human world wonder suit tribe company pink weird unable","master":"834e035154ca70f5719e0df0dea3581a2ea19c4f9c4f7e1348810e0a47eaaf81","seed":"c1682262a9bb26399355c5a226abf198db50fd6891e48afd60094127db569a3306b5e556fc166907a4ef90c80069d9c0027b74532491ca54560f7a85ee1c2934","priv":"035c6aa4e2ae3ca2d2a356112809945b068a21a4c3a448819d8b29ce406423f1","pub":"02a18ee68f4c04f7c9698d484b9e87a672f05ecb87d127746b67f3caa820406285","addr":"b6f3c63322c96f7cd1bc13195acd2a9485b45232"},{"mnemonic":"school kitten swap accuse vivid spirit team verb border write boss barely","master":"b97687333b05ee2da13ce7c5d488aa076a1cd16c8b21f43e38eb0606fa3887cc","seed":"7a770e511a21a4712fbb40f9cfbab467a97e5165e89f70b27dfc8bf5a6a69fcd8658bb6527d0203e93ac549a89dad65068f06e8699cc9748e6448eb8faafa2fd","priv":"de3f7ccc0001822d6320b5ccf27dd38dfdea7ba8fb5c73afe8b6f71982b06eb1","pub":"029d4b9f7e55bc7fa1e84f403a19bcff9eb9a9afb873476b082374e19d3e7c6589","addr":"2cff960c82af319d91e2b1fed8171fe04d47a491"},{"mnemonic":"banner lecture vacuum metal clutch return maid furnace beef armor excuse mother","master":"e944b1515fcab7dd33ccb6c027535d3e4d5db2798809fa6e9317587a1a9f8a07","seed":"6089209e2ba24a756beb9a5946df522adc87d9d98dab2c528d5469bb35ca2da36662d661b0daf50695322dab3578a5bc3cdd918a7097c0a10bca063568abe8a1","priv":"c0b5d1c2ba77450237956cccc68a162c2e32c62e662a0bcbc7e27f2ffa24743a","pub":"02b52a9589c4a631aeee16e8ce808a2c20c63134407bddd7986a517ecd46f6f1c7","addr":"d79746b3b45903cdefbfc4146489ea550bf9361d"},{"mnemonic":"lottery uncover blood that bench peace raccoon define scale fault erupt bean","master":"faee8490c1b9b5e79da43146bf8697b1aac582410ceccf66d1fa54a8b4e8c1aa","seed":"cb558b5816b5a3ec5d63468859b71f9d2b5c4b7ad07bc00e5e4e3dfeceb12fce337cf1acd97af6f5b8d9277cda0197dbac16c9700fd41df33d9d470cdb35e545","priv":"1f77e09b423c423043b8c41b93060c9e795b6b0e05ef0fe75eae4a53abdac019","pub":"022a4a7f860dc1ecb21faa1f827907b01b87a552f8cb0a085af3a6a0758d922390","addr":"7566766fb425c0d00ad475dcdca95e94b17faae6"},{"mnemonic":"bounce someone uniform blush plastic edge bachelor tenant office report lounge brick","master":"8766a5c2858ac393f9e73c6d842184953eb0806304fdcbccc43916ba70ce8924","seed":"cb6a680c6044a9bd171e97e38f4933a86f94a643a398e54ed042cb7d2039e11287876ec24794a0a078398e14cf471ec6357d02c83009eacbc377cf77385834a0","priv":"a5f252e60b69ac73744b617924ea8158b93d4dbdc2cba19db4506b86d413f6cc","pub":"038d3945d243fd90ab18ce1353e36b3c07143dcce74ae9670fc8e0ee12a2fd01a8","addr":"b184c47600390fb017cf60d2b5c89c28f72d64b1"},{"mnemonic":"alley wide siren matrix cigar paddle spin fame receive cave student tree","master":"2cacce92a105ed6a199a6d881ad7a43a7faa74f967b4e8330a55b263102fbd8e","seed":"c67bddd95507e4a9f9153f7da3de4e5951c53750a5842f11192328994742669c32cc61ed14139ddb72365ec7065436583b360ce6e2aee5c196beaab9b10e9991","priv":"f6dc107f30701827bf1f83113ea3853017e384d6995205dc9fd23176e802ef4d","pub":"02c3dc3ea3727f6f351a12d3f5b3fa52beb25ddcb5ec397042aea4e646d9aee6af","addr":"5ef50803371d9c915ddeee096f7131461323c489"},{"mnemonic":"pipe brisk focus nurse rare arrow seek spike guess enough unlock transfer","master":"ad585f1ab0b6e5f8d224fee37b6c3d1fdab1e6c757ea93a9df059a36b3f96646","seed":"5b76d0f7fa0ed23b52ec73d65d109d7026f7cc4c207988c6a003a142f3e6201fb1770f8e662fa8cf4acfc0f23e0620bf2f7b139fa9d8d71e5a3c5b5c2ab75e68","priv":"dfd55ba52a10f26aad26e7532f6631986acb0247fadb1b86c45ff9537924e42c","pub":"036bfbb102ab379a9dea1cc63dba5944b22d48a941a0d1e534170cca9a53d3fb0e","addr":"af337ff42bf6280f7e518df5f4f064a84fe209fe"},{"mnemonic":"coast opinion view orbit knife december pepper elbow boss junior wreck escape","master":"4eecc11aef13009bdfc444037aa185585c147be182442a33459b5a07b61aa555","seed":"f543bbe5ed92b75d06089c2335fd22db68f41e499634760dafaa6661e23178e7d075b2f8aa3630aa528ed77d85737601d041278d182458ae28c04420ddc25b5d","priv":"0fee3e3e025dc742e5a95f41f2e2c84d94bc8cf068bdc67db76e0378c1ff01af","pub":"03e58501a3f5052e4b7b1a4bb264c5f5a61d60c542a761a015606ffbf97f63c10d","addr":"c51fc7f607bb0e1cdba35f503f3e397346148784"},{"mnemonic":"indoor dinner fantasy cup move solve pride dust cross note raw balcony","master":"6346159218b27d00feda5a8fd63349956636147e058d9eafd60bd94bcd18efce","seed":"1c39176421e5c49e7fb6257ae70dd7d1ec60b3e2a1a4523bc4aec59b040708f0e48099520c0ae4de467da994082c82e0db6f1445c159f625559adefa55c7ce8d","priv":"74d7f00b88798ba5190b71e59dcc4bd7f2cb11e93669d7ba0372f4155308b947","pub":"03a07ad498d80dc84ce120f5518a541b5310e50bcbf0c669455c8ce2a0eb13e253","addr":"277346e420f814e9bb1a8ab16b11af318bd78d4a"},{"mnemonic":"please neither sister wrap comfort omit stamp roast lunch steel night report","master":"1f0fb7b99b38b57321f40b4327cc38f7c41c5688a478e4be908353df70477fcc","seed":"6d383d1ab8febb2334354e9e5261d6d4797bee2e6b9242521d59d22f982525ca87141e713b32cd60b6aea587caca213d8e0524c1d55cb209a6d06f607d7b74d2","priv":"95236694952fae12a92d15ca17c54cdfbd234109aadf6c295bf664115cc35a27","pub":"02f29a1a01ba6702e3a441386986ab5ef7227532704cbcfa08f2339c5273fe5f7e","addr":"048f26f774131d92ca52228106fe61d12e7d28c1"},{"mnemonic":"lawsuit trip betray slam tornado polar demise appear east dose produce market","master":"8e659f66e4dcd50dc7ba617e17e4dc45c75fe957b656039a73f3583944b16ac1","seed":"d982fe48080c3bee97fe1ae2ffdc0c5ff2445817d28b30bccd6f89bee138ef1e9828b04fd99cd70512cc8d0e58010ecd7c4460c0b2614211e7ebd8acd27d2061","priv":"4d053df57043c403659a370f486e8ebfd60fa2804430a6b97d95ecfde846d63c","pub":"035001c721d157c1af6dfa4d1de23852ba2d9be1133f30628588c5d9ec890a7662","addr":"bbd41b5af33ef8bd075e93a01f5377d486ddc475"},{"mnemonic":"hen build sand sister borrow victory syrup scrap rack aerobic shoot pole","master":"a4f3bc4a89dd86f38c5908d229f58a57c11f4a3d6872a0fd448043a6a214f938","seed":"3823745cd7589411813362179d13b2d2e1cb65bad1d53f34d512c349215e3cd5bef97ed86faf0096d2cfd5dd75556bdcbac1ac385c9caa9f928a19cb926082e3","priv":"5c14903308d7a83b6570ad2cbcffa3953b458572a72c3d5148a79a494fd90cf5","pub":"03b18bbcb61fe68f733542afa7c4c02214c8980ae4212caf818a8febce1166aeb2","addr":"fd5a9ed68124fee88f30a8d7f19e65e5ee47e681"},{"mnemonic":"chest hard axis own found relax skull bus frown distance gauge angle","master":"6eda34ed25b73c45cc0465aed51577fd35c45ef7e8d8e137c621c5bd6a726888","seed":"fd71ceb91c1c0c2176d7c75ef17010fca12beafc5a54feb3408a69461e1cbf1ad0421da9f31532aeb1f32ee6503899eb0e20fac3756d5c1d9fb23fa2738605c3","priv":"7ee2eab961362c9fb48f0cec5f63d1bfb0b38e819ae3fc1a4a3c6fe6d4d35725","pub":"03131e751282bed411e12a03c7b2ae4ba4c8f81fe5e62f3d40bba09ed7ff099509","addr":"f8a2d049f67222d673df66844d4355ca77a34db5"},{"mnemonic":"large merry tray craft fat clip album company nation tent increase armor","master":"c442b107b26f9c853ef65260fe813449152c2fc93d28774824153cfb4d67e1c2","seed":"bcdce56a81179b6fb0224a34b26583b1d1dc1d24a06bdeae60eb578df673d4d9ab5d8d639c494fcc024a945284be11ff55dd88d2470bb3740b3046155818a7ba","priv":"f359be0bbc26a121997cf2b6678b41c08d6815a5903c184c7743464e287e8557","pub":"032641e977e838507e61d0e85b1a2ff16f0b8d8a351f7958ea615bc2a8723cf1d0","addr":"924690289cc78854d75ddbcb2b06b241404fea7a"},{"mnemonic":"carry pipe make glory famous word shoot artwork ostrich slice blossom episode","master":"f6ad202d1f7acfe41ce8f97c809d0f8ab9c7959866c5a435faa9d551e98d921d","seed":"5b956478a0cf11e9e0bebfd97b3ca56a6cfd8499843d21f95a2ed58db8abb7b06c672e713a556c35258fba0533721cdeb38313565c8edbaedb17dbc1c8396a6b","priv":"0bf855554127bbd03b3779577449c37dfb82ca4457adaa0edf26f1e5e5d7ee27","pub":"03452b2268005ebdce5fb467e4ee5376624cb0dab31704c4725796dc68561b6f92","addr":"ce486d831a5c2e1b95a254c13393e50bea0cea66"},{"mnemonic":"inject more grid coach cause inner ordinary crucial mouse access attitude upgrade","master":"6556ec1bca4ce356846f9ad603e8b2e9a1ced7e2f875bb6330bac32baba3e820","seed":"c5248835bc868983d65e6009b983ec48b262a0da70dc66ba76cb167b9618730ff79b9da8e2321731b55ff63b8cfc8a2b59aa435146b5d2a21b8608bc14808bcb","priv":"3b783218c59cd664b88380619db7a4bfb4b3343fbf38d0a576849c60cb4eae41","pub":"038f88cb7546e49c3dec3d356b0bc70be0716a1b146c641447326aa077d91d055b","addr":"09e570c6a4c7439d6272bfd611dfe723d2fb632b"},{"mnemonic":"viable material flock borrow pear cup barrel fire exclude vintage economy force","master":"ed54a092853793849e78e0c42ef95242414a2dfaffc92d6b7c25efa46715e23a","seed":"013530be872ace250a72aabb73add7e4cc4568da3aac9447c094c49663be2cb6bbdc1fded3bffd41109eb14cf1e8ee48aa65da60166962aff17451bc86dc9bf9","priv":"669218899eadcca8823c6c10476cd25fe546f918495590051f8d45debeae3cf4","pub":"03f54a4a58259314bea899e9f6126305d13afc7e8de6b346e95934358b524a5b4b","addr":"b38f1873c88ab12cb5c839ab1e70639538b331a5"},{"mnemonic":"injury expose attend toward air brain carry neither amazing symptom number name","master":"769158e4432add662ca03b558828568f25369b5fff971076f7a303b8c89bb3f6","seed":"827d52b757b28ecee8ddbc402de54ed6911dfdf19abd00739766f70fb688f47575da03177ce2610263013c2d22e3ca7556c5aa134f74b8faf61dcfba1a4d5ee9","priv":"2d276c19d260ba43e8de8e4b982bb21e16f52b5c8e231cfb6bf71901a9137c62","pub":"0310fe6ba12f805a118c9052ba2cd3218418217e1e48da3daa5887bed6b2fe9bbf","addr":"0ca37f96efe4af7507cf85213a2aecd7dddfb51b"},{"mnemonic":"seat other color road pulse melody error hire scene lamp best analyst","master":"c4e172dcd2a54bbfd30fdea8363eb10b9f0bbdd0d1ff3d33ad3eb01e820d417b","seed":"32d43e6b794040093d6348fc46a452a8733e49a66a06cc8ed2045359c881630531e282ddd70a4d630a3ee69821764b45ab949650d4276a925cad0c3121c31074","priv":"828b3cddb3d902d31386264f84bc54d3574325f56df7d4e8e06b2145d60a0de1","pub":"0275e251466e97a728d0ab4527e04031e315de4d03d9cee50b5b52210fb697a9a9","addr":"c0e6ac260e64b92beed9f4370cb006e2697dea6b"},{"mnemonic":"tonight nature salute state carpet sad zero heart limit skill vehicle elephant","master":"7f116fc76af767fab661d90b8ce20b51cf5d0727ece353410e06409d79ebaea3","seed":"226457053ec313b3368e877c76f9f8a2cd5a7dbde6cfe91de075974f42f994d195f056d20802fef8bef78cdd49c6383e95933eb2517cde2bf353872a13d87da7","priv":"1f069518222310563fa736833f06041805cc0a9ada1ab2b704e85ad91b980ef5","pub":"0221fd13bb9d0177d081c7cc6b9012b0494ccc42ed79ffdcb2409c252f42b66b9f","addr":"401f8cd411f3c5475482430cd0c480ed383e8455"},{"mnemonic":"window awesome survey swear neutral tackle essence elephant weird emerge gesture click","master":"ffb27c19b7d6241a29a08c54605f0408d7de2af078a3eabde97ba6e973b9c31a","seed":"29aaedc60b8cdaeb799707830413942cac78b57c0fa1a4cae0542411a81efeb36d7e48e222f90b6d42bcae97202772d687c226a13143a9541b0d7a3bf7dbe600","priv":"68ab3dca6b53b32bfe8a1b2d428332415b6278cd258fecd927f9d8b371075789","pub":"0234cb69b2f76362ff4ff138f81499d5c2e0a1912fa47098c0d826f98f1be4facb","addr":"54637f8b0f2dad74bb46e7745d1957bb8b16f4fd"},{"mnemonic":"island pact measure trigger frost flee tape napkin wide kick select sense","master":"013a5ecc8a93bac063e18e79f5654cf0881e8c39fa43c467a8aad833b6a7ea76","seed":"19cee1ab2babcd2cc5cb4bc34acb350deaf24b997d603814a5509374a2f60ba133f498a20a9066cba31b4903a6c9da661dd459343004f69b2dc78ded2dde67d5","priv":"16b0960d535046bc5b95e335cd0326d0b0a902a3c81f70490453f75154a05e8a","pub":"03e6198bef79e7bbe034d1786e47f00fd53aa3132318ed99fef38b6f46bbdd9109","addr":"199fb6c909420f711c3b452df497d03da191911c"},{"mnemonic":"before shed sweet will sunset rapid color tattoo winter foil spring orchard","master":"29289b59bf6ad91e0f9b24900803f57d08b45194782e76102f5377c142c17f65","seed":"7b721e94ae18b7666bf293bdb8eaffd70c6bbd2c2ddc582a0939100f1f131009752be6759491e0006cfc424f88efd97868132fa2e6bee0b05a520c881c632951","priv":"f6d7fbb1fa8957d132b1d43414b0664cbc25020055c35635a5ae005e86e40767","pub":"0368c1403ed0df7c1f9faa90fcd60937094cc975d1ab5bc7a9eb03bdfe764dcb7e","addr":"6657bcebfa3816af66b1a0a92f8269cd3f515fe3"},{"mnemonic":"view forget toss steel right echo life candy fine unhappy document pulp","master":"5c6355a65617952bc05b16623992e81daf07695ee5cd3d9bb2b8fa600ffb2576","seed":"20909264d02b6b88a472678b6d457850ce4f67a228a4f6ad7f45be104029ecb68f25075f30680416e0e43469452ad903a1e7b0486932d0dea4b1c5f56b21406f","priv":"4495c90b188f706dbe1106966e49745c49676e5c54f78176eac166629a4c0815","pub":"03b828ccb3f9f1766cf1d1c1c57e8e5c9c96936adbcac4a8ea47b0a7e3139c5771","addr":"4a382d15c13a06adbf075cd847ae9e80dbdf4ca3"},{"mnemonic":"fetch planet injury lecture myth goat drill sea reflect tattoo story rival","master":"3725eab28e9f4275bf2dd2dd5a94aa550688b8d111798185383a58088d6f8b56","seed":"0d42a4096e20202bcaa4d1939ce86cc6975092d2e6081c149b374f3dbd6cda81188c442e1cc7b67032fee9effda37e20da0d809f0d969977ad2c547e9a075224","priv":"7abbbf9aa4375ec489d3ad3ef6041e9e371f4582eec1ed753f9d7de3b4fcb57a","pub":"0371b9cf4994f36ac2b5117a2daf84d7c072f63e51d9f7c5e547548bc2ce51a16f","addr":"d59315e071460c09d108bfa31e05cf37545b19d6"},{"mnemonic":"close raw empty danger educate metal vendor coil observe response scene army","master":"da1ffa0441ba19153f0f98af4092dbe68eb5ffc9d82823710dde6654684e8fec","seed":"f8ea358ea3a369cf72266a1f30e10c445817766080ba50991a2b10ae1f23d1fd3681ffd4cf4a7ac47b39ee9b04ea246cbf5337eb33e0d6e7c1da921d153e2cfa","priv":"5e3f256a55dbfbf2750e56067779fbc05503bea90e1a999c17a0bc27801a0bbb","pub":"02329640a5fbee753825fc310c06f9761cedfefb880d6e3dfb67eecc68ee269813","addr":"904c7b3d1cd8303fc3c8b0e3b0fd60fcb54807b7"},{"mnemonic":"ship puppy grab also merit doctor fine east venue resist loyal radar","master":"f7e49c26a890aa8deb888da48d82935a69730bfa0af67783b39d209ca803de9c","seed":"dd5c5df895a6663cea37b5e7c58c268420e290e4f20d7e0b7c98defa35fde4d372f52215b52bb2745481b8c63aa08c2ba163dd89f2a9e51a3bc92199be8d57ef","priv":"19a311da10e6f11ea3c91231a7e5bd22097701bb56c0248014958e6df186e596","pub":"023acf91dfb359e537f9183080ccd67f65b1b9efe314f682deebcbf718454d6bd4","addr":"618fb20184dd651d18d2e039ac0fa43e53feff61"},{"mnemonic":"beef hen spring repeat define hurry slab midnight liar either arch original","master":"85a6a3be23cc74b32c40f1dbe431584f8767f4116a98ace1a08c934956e8582e","seed":"cbe260dd75a3f8e7b7b9588f0a1325dd88b839a5536e39facf324cbbee3ae951903e2c17370ef673c770ff2e0fc3f1975a26f45d27c681a143f0e60fac8d18c8","priv":"42c6ccd133fbb7d3bd8bde8309f8202eb155c46829aaa558226b6e53abdb203e","pub":"02d1bd732a69043343e72e22432f7bc309e25e96d49b087572f021996297abba75","addr":"9eab0f06ec4e0a8058e4fde3ebd5a1b2f5ab043d"},{"mnemonic":"lend total guess ski divide diesel tumble heavy slight expose clump park","master":"6ad684d3e30778a46d5af816c3deaeaa0af5c4fc04cd74045dd80947faba053c","seed":"d63dd68a0b8296a41ff8698494d9823d18b4700b0564318f022b1bca641a8fd622ca403b48fb835c848f053557cb91fe4290f37ea9edc4f2428226983802e1cb","priv":"9625f841a7384f3fb64c643ee715ab0c5693d60132c4c9838c7f41e1c9163e1f","pub":"035e82a39dd7b61ad9f79ae31b0694af43378fe1b5cd6fa824ad2427da0834e00f","addr":"b88aca334f2bfafdb66c2e338a7d3b6c8be8bdcb"},{"mnemonic":"toss hand crystal buffalo during more laundry fantasy give dizzy bench want","master":"075697aef6de8c5b0b418fb3faa6038442349ded65421ae1089517423120ffac","seed":"4226da530678cd25633e2f87951c6f8f5bb4e3dda3172494dbc03ea15795b22d1042ba8265d67cfeddbc205b800ba7b7b05ed231845ad54cb3224c7ad0f9d8fe","priv":"8db99c4eb921431ead557ec1fc62bd6a9bc34eabb3516345a46bfe8c6106be6c","pub":"029eee00e90a02beca7c3813af59feaec320d26b585e5620de11efdc09a06d2c5d","addr":"e9a4a29d0e7267016b03bd23d6cc78b9eb1681be"},{"mnemonic":"camera gate trick sphere oven sick promote apology reason fiction item meadow","master":"7af52d41d0e35f2cad60fa2fb6c13d046f8aa4e0be104251dee489edce66a229","seed":"16ce2107f57bc5feff86b9dc81c98838cfb7b6274e835d6e35a46525d5870fd84c74cb528f6e2b87b0cef21bc6931793f472e5430b9582f036630c3b7c66df87","priv":"5f428e529d340883faceda659fdb36193f3cedbe2307dc4b8bee55a6845b9068","pub":"02c71ec0f9fc74db1da6d2a4a9d6a7f24980fa17e656c1d7f43a845a17625b2445","addr":"31dd6642a6d913d82b06c3793ae678670ea9bef1"},{"mnemonic":"slim guilt leader segment actor sick debate enough what rate fork rebuild","master":"674b90a421dab99750e982cd3c693668c45d7a39377cb82e3887552f047eadf8","seed":"115114f315f7af942dea64857c5bfe6a22c80031e6b1dd0c19a42a28526c0b9995b0eb39bf8e78ce849559eebdfa3c269783987bd4fd926e776984396a3c604e","priv":"2fdb1afdc8248d6afc69e387a698ef467dc0473323203445bf1dd5aaf5789936","pub":"03dd070062a8c3e65333572beea40f434d6f1b68e528ffefdfa8dd3d8b4c5a729c","addr":"8938c102cfbb8030cf69c660b04fee696a902f96"},{"mnemonic":"kind prefer arrow industry arrive cherry pupil arena strong tuition wide grunt","master":"c4b509d9b1e60d97cb8b862b96a2dfbf960b0553f0625af7430abd3951c59b2a","seed":"85ce840ce0f6625294d32cbd5f68b3c2abc3151db02b5a84b1d78ebd7c05ab24bd49a519a340cd19bdce6aee845ce59b6b5d2efd7a2b1640c7919177bed27b4f","priv":"ba8628565338b55d2a79b21fb9e47da978611095abcef86f305a0e2988e8128d","pub":"02bbbb0be37e3975749a095a9dcc025bd57368eee362cb896540c0dbebba42f0b9","addr":"4d8e97ff30d95baeb64ced528ab999c72aa4cbe1"},{"mnemonic":"slight bronze prevent civil junk van female movie vibrant soon grain suggest","master":"4d07291eea03d51cf9a3790ab0a77ebef383f2cdf184b0ebd872fdce93b0b889","seed":"4f770292818429f588226c4df9bf6053024a42f11a2499f0c2c5ce56f25d16489a2e554b99105c70fa57657b8d8b724d1879fabdfeea8aa43421d19849a0fad0","priv":"bc6ab78b16b831178cd9f2722bb8afb27664d1967cde464af0b951c3aea935b6","pub":"02673643c7fd4c12f47007a27a56537d152d607225a6d561fd0e18d30064752e38","addr":"3cd7ea7b1daecd3efdd14826508409791d8ce865"},{"mnemonic":"chief drill utility gauge tired alien bid deliver tooth amused busy run","master":"dbf20f3b945820a74898fd73218ed84a61ccbbb28d815d26dea7a7e9a9b0b430","seed":"93d2bcfeea8a87f021002ffadc33b664810eb8ed60342c8dd74a937cee64877d5823c45a4d34dddfb7d4381addeeff63e80a191b92dd7f1b4f0dbf5c5e8006a4","priv":"c38542f0dd692e74e8635dd784fe14d8c70ba931c354d6ea08f1e0b9080d74dc","pub":"0225dfa0e7d37e8903213d8d4900a2e56107e7dd02c66cdb7f86e9d9c0a05a835f","addr":"a94ac8358eca1fdb0ab8ded1cd80b492dda39dd6"},{"mnemonic":"large endless art unusual tornado loan planet excuse dolphin million reduce chair","master":"8f029c13f62099a1d280224f9af2d9458014903b3df1eb65647507e4a5262012","seed":"03d076444f817fb054603f746350c40c0551c3d155ded436620451c4f53ad1254d0b52bb0592197becf9e1fa14bdc65d04c7ab9c5bba7737841d800cb4f7c869","priv":"1cf63efe6800cfee972815f1fd71c68224594557d7894fe8902f56b40163ecd1","pub":"03cab792d05c87c205acd8d78771692507eab35d8c7bf729e2d36551ee0c7aac67","addr":"9f27d874704a788d3e3c3f63f9f1a42c27b83c18"},{"mnemonic":"recycle wine system erosion train make sting talent beauty decide beach pigeon","master":"d702a0785f59e080e2ec13280ec397e3af1c60a36bbf2c92c252da896caa7371","seed":"ffd0dd43668393be9b0949bb5872279ebd606be9ad58f8611ece8dd8b408c0714d5435c771ec87d23b83952af75a6853d94fb0ae88a9b9c1b506e3c0887f3bd6","priv":"d27a5cc824bc9e78ed2c991b8ca86498ed48775aec94dc79332057f2a36536db","pub":"02f85cda3ef9d19e68c4a3778ad99fe008904aa9a80c4dfa8d07355ffc840249a2","addr":"da42d3051e6dc70d85b5fa901e1a4c55ee12a47c"},{"mnemonic":"solve snake loyal grape island deputy monkey art pet candy enhance truck","master":"e866de4a10e7067fc8f6462938f3ea5fa7c88c93e2f630ca81dd07361c646fa6","seed":"82483d5e61c9eb2b0c588b438e24cb0a24922abc6cf0571cf3680474f1eb31496e387ae1c017d5a817c88e48020c5cc1298cfbd78d7175be0a1ebdfbf94853f9","priv":"919e4b231311f40772a47f03948b136879c13f5f0797c939e703b7082d65e637","pub":"0227c29a984f46d5a99c08f31355c3471eea9d231ad414286a25fb91bd8a3a6f92","addr":"e1ef4d05f41df82d47c287ad0347197e8deee0d6"},{"mnemonic":"energy buzz square deliver jaguar chapter analyst chat rare over bottom river","master":"3074c2d8f092896e7a197abaf388828f95eccde75986fd280c9b098586e18396","seed":"70be3c734ae665956abefaa3f94101b5863086c14d8c17ab288a3586bb69aadea314ff47dd19a4dd4295ecdab627a34d9bd56231180b20156b65660082e70d35","priv":"47ed2e3406d068624039f71e17f949c4b7865f4c8d006d6b4a635176b700bf2e","pub":"03786b91b237ba9c1c209d8386ab1fef86e0c667cf2a9a3cb25fbe06927ba3214e","addr":"67ba9f0de66103c6d6f1b799564ec38d4eb9f708"},{"mnemonic":"document move actress food guilt fence govern adjust supreme upon stay sibling","master":"6d110c56993597b6bd473eae083493e1a17b4cb971999b078e4c74c2a675f0d7","seed":"e6a300fc434aca28cb75f2113a8f7788778f2b9398290f82f8e5d989bd002659a645c18057ba64807f0d4ae3c064e56a2947d5aaeb83ff3c593e942fdd0542a3","priv":"fbf0d5b6e019bf7aa6745c4d95c0f9a428d0dd57b7af9e71eb2e39a6628b8d86","pub":"03725d6b7196d57cf1d3b193f1a6661613d02912981225beddd4e1db8de60682bb","addr":"9aad1b39fb3cd3fdef63130bb1a7c8d12bdcd866"},{"mnemonic":"express birth sweet kit special board rose sound place chimney awkward injury","master":"c60b7e5a1c89797d3ba7ce33ba487182144b4203379c04e51ec7ef4ee621f0f5","seed":"48274a66272c61abcdb72d36f16b6ae8a1853d299d9514516374096b443368656ec28f59c9f78f6707d1d1fd78c4aee00e046cbd3df66ee7b143b60e262ce162","priv":"972cf1431308c25e45efc26b86a87c85ade411bf3fe1cb6e88143684910dee6b","pub":"0243447732d68ec3287f154750f1b27df3ade846a0d4cda8e5e5f62f3875de6b86","addr":"c199f50b3c111205cc2c7309c9239393bc2c1e57"},{"mnemonic":"future desk scorpion enlist confirm favorite ill expire evidence cushion rapid staff","master":"0f15c9b1f3210c53c5c408329c3c028211660eaac42f27749a4e8901ee17dff5","seed":"c2db1a2615fb9b849717825a326e5bc2ffb8941755a529cf27903c0c3be806b4261cc3ed7afa8748d87d1ccdd36372fa02f92316f1adc28a354feeda7a0edaf0","priv":"39de89d88ac3f8b23ec57f82c83f9bf12a32762c2df4a612ad647ac9ba287c93","pub":"031abd39702f34958e3366a4d438a7285bb9d5ad5b8a29071ddf77ccea7f9c4358","addr":"a7bd49b9e2804e22072b1f336578334c53b6755a"},{"mnemonic":"interest judge only feel scissors illness quiz goddess transfer person position this","master":"f60677c75a51c5c9e8ebc4fc1320dbbc82e00a42507af218a71812d6f981344c","seed":"6e431ec0f7627bceab5dedf9165968ebfb03ca749aa8d021725338ca8e0e8ab3b00cd0395a68ab955068046c63daea7ba57117ebf7c99b242df8e63d01bfa625","priv":"41af5034dc87e11bb1cca3cca70f80fa057a5839b711927d3fab85048ff8620e","pub":"0321c6b392ae7a49201d0a7c89fc3541bf1c0c1287c051c405cf32a246df97c231","addr":"a71580dfa7773d8a2ce44c7dbbf03d285b46e56f"},{"mnemonic":"foil remember sample infant bread year evoke laptop buzz chuckle voyage gentle","master":"88ba5191913e778f76cbc28850f221e96f380724d29646f7cfd4fb6da20171c8","seed":"64485dc0ccee0c0b13c0bc76e44f8c3a26070a6c08fec558519503ed85769ce3f858978cdcd630b9c017a290ae4a7bdbeb0f66fa5e3fdf3ea227187a165ca654","priv":"117e2b0842cf25a1ee21eb2f244a2c1fcf2a3a6946b3b830707f7c96057616a9","pub":"02b349892030c73203e3fbadf870e1c8325ad0ba1747738706734f7a66e9c66ba7","addr":"1f6488347a7155806da3103c9a82954072a1abb7"},{"mnemonic":"pony super panther surround glow lounge kidney increase actual tray bulb device","master":"54c50d2520ae7023ffdd39740b46d029ae9e31211349193fef33cdaf373030a2","seed":"3d11ec99f173c1864ca6638a27554549c3f619a86e0099e5957972722b2937f5db767d86f5fa0c6b3e0a81d75a9aac5786cbf01f2245b51c9202cd4b4ea88a99","priv":"81741675b625a14760a1ee9e108a9ec6be183c480df05878cb31b45e0d0babcf","pub":"02b0bbfc4e33a79bec82682552fb4c0506528d121ef67a7a42d2ee26bd0b1661ae","addr":"8ec9b249788a123e1301100da2db3db71c913a78"},{"mnemonic":"achieve sail manual vibrant unhappy ripple aisle fossil pledge wrong cherry trim","master":"ca9ac46762b80571c25c2a9a6690181896f86ab3f728b4e372552fc9cf1f7e7a","seed":"4c1cf0279c8a29b8077b5797b6592397112b65e75e91b829a0a9f26b94803a53a02069ef774e7cb5c3cbb0a8e074c69b9afc5a4136e04913403b70046759471a","priv":"09503bd2da16f128b857cfc635cd90064446130c2477004a3870a0c5b1f1febe","pub":"022b34a4abc0a4288805719d72f0b64c3118d924d09a4dad4f26d39ed056349e00","addr":"ef2b6bfbe737261b45e770b5eb42d1950c556282"},{"mnemonic":"injury love grit wait junk bridge myself sister hidden dilemma gas paper","master":"b4781c7979c0b72d0c50c9889432fe2a54d6f08a4101778f88176dc661bb02a1","seed":"03bd824d7f4487af26d236950a69eef9c878361038f0e8be44145e558779d4accd58a8c5550bf5ea86ad169e5258947512c4b72f94bdf60b9135c28a4c779541","priv":"68354a2599b3be8ec6dd827b35290d9dfc068c267f1d89dd57851b22d69c95ea","pub":"028af1d826d45a920dcfcca8d9f86dad10d7356b3027d4051dd4c46ddaf32dc623","addr":"1f356a55f3d3fa48e5d5b36fa31f738bc8f83de3"},{"mnemonic":"domain congress cake cradle express despair devote swing meadow piece border cross","master":"a3ebb93b7fb0fac2b02408c0491f66800c220c7d47190c3c97023f3d6db86555","seed":"15494e78dec34f3fb759000cb0584e42addd40f1794bf2932c6bcbbba20e40a381bb9bc1b8dfd3a231d8e249aa3d51a257590a93188fbf116eed9321195a2267","priv":"1f1ae70c46a36ba70674c7b17e6cf0b8e08bda0a17473d8ae69bc54311239821","pub":"03d7d916b054c003413ac84402e59b976e5515f48bbc30ff8cb6bca7f4ee92c03e","addr":"54d0f98b9dad14550c844bbfce8a4031dd677a1a"},{"mnemonic":"pistol news assist poverty squirrel machine aisle sausage harbor garage truck type","master":"581d692fafd753f080fb83318856ccbf059b74a3f26ba22d4b93916e2165aec6","seed":"49abafbfd7b0c65ccf2e22eff01c78245c764d8ba7bd468fe1baf62a156aaa0a6af143c624241ac753ff8432712ea58f1df9e75cd969f905bea80c15b5fd84bf","priv":"f1d7e572b03a08cdf0ce00908c701053a5804fe566168436b90efd1302bd7f1b","pub":"03882ef7180679169f638a7da20a2b522c948b1979802cf4df83fe1b62581e4d4b","addr":"40bbf61a5ea5b704d02ae13d032f3dff4e597ba3"},{"mnemonic":"field tree license quality chase certain hedgehog alarm melt elbow screen pigeon","master":"dc22c189c264812f22664d39ea1fa2f7d986b981d59f1df2ec6f8582d640e196","seed":"37ab0888876ccb32b9ab73f144ba2a352b31b27fcf6b7f8fcc5a2d4802e7099a199242cd5f7f2a3c3a7d86e8c1abd871ca35881a6a47f605d04a063b589fb0b7","priv":"f82f484f92d1719d3e6832d49bbd493d5f7191acbc07872b345385c32f2d38ff","pub":"0390c62a3315cd02fa64216cfbcc1788d537818eab5cf932a24f9eafe6f4031f48","addr":"8933e5a789211fe61396f29fbc55be6ac7031550"},{"mnemonic":"wish vintage fiction false gap bonus abandon cloth usage hurry toss slender","master":"27f3a0c1791709a32f8ac4fc1e9c71eb24c06e2fcdd8dc959940cc1c8655a5ee","seed":"36932e48e1712c3d03261d432a17e940f1f21d730a3f22d37c1834ca0591b71b438d684c926ebdd51e6431502b8efba8e9c32cf457e68b71079864dcd0d1886a","priv":"bc0037a14a0297d3dd969b365a6d8dde9c6397dd3c8aeba6d701dfb1bc8b24f8","pub":"035ec8335e2f6ef0fa2dc6be7f3271b1117545ab02cf1c8cced03f9cfaaef7c602","addr":"5f64f8eccae09dd614ff9f7224a20eaad60c23d5"},{"mnemonic":"fatal strong idle grief present photo aware various april april card village","master":"ae83fc216ef4c81e2d128d90e91cba0b475be472d95ba77c2ab9cecaa511e308","seed":"3901e5518ac7cf29a42b94de334dc641e1db3b97b44a30d69f3865c050fdac8339dece5f9ed96a17e669d51d59ce856db902e918497ea8523e5ba49fbd06f621","priv":"1bef5a9ab2f2ebb16d9d08b958317a37f252f3de91a70b2c8b5b5ddc0a187ab5","pub":"0250e5876c37987b4189513c7a5dacb31a308c563bd09d7557f2584a3c86bc9d5d","addr":"bb82bd68b31663a75d0d007646e8575934991f43"},{"mnemonic":"error monkey argue fluid afraid hand cactus sand misery close laugh comfort","master":"1b4ea203fb592e2dad7f40b6cd4c8ab53c6a0a7656cb674f9e22d6a0e4e84efc","seed":"3c0544c9b9c32165fcaf9445e49518f8d0a2dc6ad672a01a15183ce1e2188f6fac026cebec0ac4ca58906d5599d781c18b2cd77d32992be9cfb01441d396faab","priv":"e0d0b452b3e1f760762f1bdc692225e7b14277d8227d619bda49bcc608658bb2","pub":"02e7a7156cd53cc7c8b4840772854e25b8c6c532c520770883da9d574c86551c7c","addr":"696d7a61a2ab18eb503cd724f0dd316340f96c90"},{"mnemonic":"demise know punch page upgrade gun smooth fruit machine long nominee radio","master":"b36ae5062ebe21f31bebf7b2078ec651ec579494eb764bedda7169095b73fce8","seed":"0f71fa966c1a56c3e11c54798052789cb0f450761a0227336ac50dc8206f032133937511e93fffd54103132d822b8e717ef15fcd4e68f391a398f14cc795cd76","priv":"6b9a3d2e63d666909216a0420709f127318f809549df2e99869fa70956e41dda","pub":"02d72eca95feaccd5a78567311e882d7b5eb2914d1d844e639b03c4cfa036155ab","addr":"9465a8f3afcc348d661bc198cf8220e74faa5895"},{"mnemonic":"install lawsuit guilt myself arena enable unable thumb domain lift feel object","master":"c033a48b64aff8d6c7fcabfab52087c0f7b9a4228837a7a21d8156358e5eb529","seed":"8075fb6cd8bfcc08f1678c005e9d2d0bcac710a6a62cfea46a1ccbf81747362a0e6a25cea2fa958fd320205e0f95eb8a5884c6f39cc3ad17d58fe49e43feb513","priv":"24e83fd857d2a0ef62052625d84e6aa37e96b14f2c8dbe5294107b647b369a7c","pub":"02d95869834be368c5bc37a45153135a1c4f003be6a44bb9af89e55485118826b7","addr":"631e72e50070f34e23ddd155ca0670c8c8db49d8"},{"mnemonic":"antique insect develop sheriff erosion appear easy fog kind apology stamp noodle","master":"72baea3e04811ee7447249a1140ba62e56bf473d5298b610235ec3178b388692","seed":"e751bd7ff01706f38b8d3a28ef3b1565f20a8ad221d521176347e7791d2cbcb9cecfbc8b51c2e36c303be55df280273711d94c416dd74a7e7a18ae52520cf89e","priv":"0ec2ef082498bbbf0a0686fd232a3b4bec66d867cca50bd0cb0e3221bc9223ad","pub":"03952fb023bb76ea74a6b5b9c4a035b193553a8adc1c0774f7ce4976ee2e8c7fae","addr":"9d63d52c57fd76c7036b882ed40f4a6714164c27"},{"mnemonic":"become tell dentist play light illegal work animal library dragon now gallery","master":"895a420763a2dd6fb934ef8d83762051b00235a83f621f57377a0d63b71bd43e","seed":"05975302d82f413289a1679cf6a69feaf8be733d7fd10deafe1470a08ed5796bfec454adde87e825ea80ff05586c12f5d0de69478cf72238b3e73851f691a3ed","priv":"f94266abb2a93d963a2505da57d66c36d37ea3f871654a0e4221ec911a6b507b","pub":"0256fe9203bb64e250fb0e68a7cd3b0d3c90cfa8f8db06c74524c63ebd66098ea2","addr":"4f73259b06b65db4afde238bf4b42a801178d92d"},{"mnemonic":"average anchor total witness carpet myth life admit gesture inject sustain valid","master":"aa36181d7a04a32433e6f4b1e4830d3e0796ea00b8b03d466087911931c16abc","seed":"e2bf601f15b7edaa2176e6a0e734c72f99ea63086ac463ba2dc317dd70466753fd1334cd27e28c382c99179db6a5b00003124f93a7a93da3a0018838b3b04595","priv":"235e293ad68581b4e24a554704eab59caf513b60b8af6b15fa5d8cfe4265e44b","pub":"03b9e9b4b67e3bd6500e6b0c3f0d0f69a15d0824f236553f7fa12a58111e5aee7e","addr":"3733ba0b6386f7534c7714e9e2382675e0dff54e"},{"mnemonic":"liberty cradle play vague cute borrow around that tongue wave solution share","master":"87869b74fcb6e5d4b0b5c5d53679737f275396d63cfceb1133e49458c9c74613","seed":"c60ac4201963706912996e289e5b6d886693f7277875b46ea166f4506bfc3a2652ae2fe5b466bc171c7c7f09f2920b8ecc6d9c7d2e0ba1ca2cb10b528119cfa8","priv":"a8cf8fb93cdc5c13402976952ddf2ba5c2b37d5756861536df21d02eb7d2c593","pub":"03c12a9f6ffe4d7b01364f266b835be4eda6515d601bd39399f6577c53b1289e12","addr":"cf72bf854dfe493a6c742d6941a4f22fbdabae1a"},{"mnemonic":"hip dose artefact tumble keen favorite truly stand accuse spin opera wire","master":"94ade552d985f2e8625e18360914a5046ad14b6cc5fa6abb4ada333de8973595","seed":"c1d9d325396486e588972df5ed2a281a1cef82184a90c7ed7ff1334e35ae92a15cbaec6d27c47742a28dd458474980dabcbc651d6a2eadcb97dcca08f295359c","priv":"9d3f309f684c2c61a0f05fc88e27894cfec51b738058bdb246f1a9fc65937fbe","pub":"02c1da3c5abf3dc4b52336b362614a1a7a24853759f72fae971b43940500badf86","addr":"cb143b40309bc078f3db3e24009ab54ec4741b9f"},{"mnemonic":"history team sight sibling art over pulse network sausage garbage october slogan","master":"2eacb1cbf92401aa2996b19c77a2f110faa835203cc6baa1c98204ad1740963f","seed":"70b0ab283cce0e7735ec8d05bad6178bbe5a19b747ca1d5d3f5a29c83fb634b43c39f621b11210a7d89ec988b94588b9d8b8f2f4c2a9ccb687cb807e230403ea","priv":"986837f4c2853f751c51e09e514d2d40b36d3995e9561b451474cec6ce431a5b","pub":"035ed85029803a151586b8b3da3f7b2208b257738dc43fd1af08c6f76798e82609","addr":"931b1e70776f50c1186cecec2dc8fcc917974e00"},{"mnemonic":"labor area outside toddler street now same obvious demise mammal puppy boost","master":"720c9f77cdac069406469500511e891b35f1a5782ed330f31ad1dde4bbdfe7e7","seed":"ddce9ca2ae36975072a321de56c51a6ba88b53c226d66006b81d4572af6c8c39303a5a8d56b1626510ad730d578105ee84ac079538118f9cf8e56b43e9da71e3","priv":"8182fafb8ffddf9b157f5a072e57d778e766f7fe5b1bf58ff6cf6bcef46e1d32","pub":"03399e5ef2e4a978be70fe20b7d44201b5130894588033d89e1c0b891576a7eccd","addr":"15a638bbd12f6cce559e0f03312fec99d8f5126a"},{"mnemonic":"coil room slice arrive lady world turkey huge point gorilla course oyster","master":"bf665f511652b19a5ba1b0a51137aa72e392a7149c2df6af31a0244dcdee4475","seed":"2abc97e164bca2a5f45001574f9781dd837304f949c28c102c9de3d713d8cb0443a3be55a324817e53d78b50f0a939346ad414eff0b6307cfabea6023c2258b0","priv":"dd27b678563eac5bd7565e130f6856fecfefe3b1364ee0afdace0408b5ac09a3","pub":"03ff0c0d776d27564be0a465e29923384215370508961a1a7c25c261d09115f8dd","addr":"c4e5450d737defbb8f4d406650c93d79b1820043"},{"mnemonic":"diamond empty network apple radio divide ritual flip correct phrase kidney say","master":"f451294347b6c2035d9cc0c635b777af0d1fa756e1a72c2e41863a753776bf49","seed":"9108fc851316d1f63bf92d68e1db688328b7ae4c5ddec9248d8b5012709dd14dda42ebfef74e61085ae56c64a9125e3a47184320e53ca82684074ea0d359e6d1","priv":"db4465c5493f98c16b002401e28422b630bfcfddf32f8112c10ba71787490e44","pub":"0370a09ad6af977beadc07793db44c7bbb94cdc060a12ab36949bd36a3aca9c776","addr":"b9a0c2f7fe9d2f416596b71538982206c70a38b6"},{"mnemonic":"cruel music theme kid pattern weather become same arch foot host region","master":"82dc215e8155458ad1f3c61deccef305932839a6087250839c41afc36a043f62","seed":"0bf672820da35a6601782bae8a773f4dc6381fda5fa60a3ded12cec851225042769cd147c614f0ad34515996bc1f90675c431a5517c2b5fed80552b2bba59d7c","priv":"a63537932e88d10143726eabb410b3fcf0baaa550892ec17fcef874a2df8b70c","pub":"03b01ab00751243c746766568875b948e12eb1b88e85dbbcf2b538cd65544b57c5","addr":"137ffba20e834d732918f15a7e8537f014d2f3e3"},{"mnemonic":"pass avocado year kick ticket chair pelican finish lamp eight latin hero","master":"5f0d43392033f39e4488d6d9ecf9cfc7cf358fd718c1534c30c67aac21ec94fe","seed":"577d6f62d28192b753fd00bfd3f5af506d7b9d1608eb31cad9f8b08019011dbd20aec03ad7ee731f74811ad060249113b9d2a4aaec0f9d3317a4e72745876822","priv":"5600cbd7c571ddf6d0493f88ea45ac92e33fca9e6644165365cd59f91e68eb21","pub":"036f3194e13694cb0cfa7af94b8a60cd641159d60130fd114cb496f5b828fc2132","addr":"d3b8b4027a87f928323589e9f5a85330a349b821"},{"mnemonic":"deny improve give spin carbon lobster shell lava romance jacket village canal","master":"8b58d86d8564a0f23f0d38e08f50c68ca12a7c55956ca8f34cf790b7260dfb60","seed":"1d5a8348a7c66d8d7f6b5b99f844a7ca23bfbd4558497c1eb72f6679df2e0a03404e99e97f68a3c0a47d56e8fbc0d565f4c1bd0f7da014845038466c7bd8386e","priv":"eacfcd11a571bcdfd73a64a8c0b935fa343b21c0044f8e4d9d2d882c75db1733","pub":"037fda0cd490d64febaebdf19a0236a1f7a1bc6d523d065cdb2626ca122e9d50a1","addr":"9dfc787aebcbfa396a0ac4fe9b1513ceb1cda121"},{"mnemonic":"target tunnel liar bargain bounce lesson silk lake artefact coin coffee degree","master":"86437b39d0a0db7f5b0a27f627146b1ba6ee9c2cfd4fc12663ec3a2fd06d6495","seed":"fe9740cbcde2cc458420431b44c8158a35c172637b748b4051b79dd1ac1d100ba0cc60d4928160ce8eb6cdd5232152f9b90439fa2f4a3aa40f1f884d79f0e520","priv":"5e56256b91d4e255d9a64d5e3fe5fd0cfc2eb558b683f2289d773d09008a41db","pub":"0273026ac3c43ee59dd6d703efc5fac4d31e6b6585e27820bd8d91185dc399cb36","addr":"a0d89229e673a6f6962045c70faffbfefb0764fd"},{"mnemonic":"rail ripple tuition once odor barrel winter antique woman merry nut offer","master":"33ed9b3e5babe3904c48a79769a0d8a8285fcd9b7c1154316429382876726bad","seed":"595dd0a7f36a71e38b37baf88967b9960baacf11b249edf1afa2f2bdcf68a96e867644b712a78173609202b7d8b7cf2a3cc82014ea28bb955ddc46027dd10f7c","priv":"de65d8250e9eba67bcc69a2840187c2ea7c64f44766c1b7ac0b648afa0f297c6","pub":"031a160d7d3b13d9190c2a0a684161bd00d7a3fd6f472368f5cc4bf5ef3f84cede","addr":"a0469ba7da8af387308cea748507999662a7f76e"},{"mnemonic":"mix you afford area also raw water fabric mother industry mystery victory","master":"d458f52e08056473bdc1a73f5ba148da38f58a53be4f7d5d8e5d2974da6474ef","seed":"fcfefea963149047cc195afa589c8a81189eb27bc30d6bdbcadc5a74495400eb12d7fbd3cede6ab7e67c42e308dbcb4f74cf2ba1335b873c8bdbd13ff19dde6c","priv":"d5ef3fde07814e0967f9ec90b44a749a1c2f4bae73f76af2e10a0f73681e58bf","pub":"03388e81cbddfdbad87b95d800bec6e1869bbae59b2098b51e083e97272ef82fe6","addr":"3570a61894c36414a607cc787e0eafa997ed0506"},{"mnemonic":"find fade drip oblige either deputy noodle trial hand clown athlete chapter","master":"1131d43aafe4c9a2314a3c41116a0ccc68080cfcc525fca0acc53d5a2d4c80fe","seed":"207bd6fc9c91ebe2521cb131c261de75c71aa28935feb420a2e9603659826c326e996074bdc78b7075bec54f4268c828ee8a62aafe993cd7cf481665a2303e29","priv":"22ca0a4c09e5d6a96ff37eae29507b62715a643d3ac24389217e35f4bea4d9cb","pub":"02ca3c47a5367b7c9d83057333cd716b44a429d7034bda65761ee1dc503038d520","addr":"64be7f76e0669905f362892b53491230aa4c6834"},{"mnemonic":"anger level recycle lemon material pear robust decide they hammer coyote fade","master":"0efa37efdf167ca18fe15ceace835d75ae94027d7cf4186b4ac7bb5b91d54fcd","seed":"8838fceccf5c30285bfff02ec64ee34d7518c30b9cd722ab8a732d1ced8135fe1919af7e3afab63a55f1551d43d4222f1f62d0349ec185e4d45076b849de8972","priv":"16f41120d317d7387aad821cd0374d715a1ec1049057268b3ee090210a00a6b2","pub":"02b13c5607cfd0675ec1f33f82a09a9cfd88ea6a212a84f9528fba9857d012f5fb","addr":"4cf25877cd8e38cf5a37a9dac81a9222e8cb5461"},{"mnemonic":"fall run bread slight rhythm flock pipe employ fault side kitchen position","master":"89394aaca338752755e33fde878862096328720570957a7c105ddb90599dd87c","seed":"a2fe89e4a22f8ff5dc458ff49870dfdd7be85afb9fdced1165efc1a2bc93ed44e4d0ea1be438f347f8bf7c9812ad6aa31f07c8eb3b5ec7cd40e37540876b12bc","priv":"c0c189d49e3735f5eb9c7007e1e0a841127998d7c462deaba60912a55c9f0de5","pub":"02199a2f84eab6e63c60f7aeaa56b5799c6013df61e51fd2b9e2be56e4d6e5b121","addr":"085ecfb2737f0ffc78f1ce0a15868b24d09fbda1"},{"mnemonic":"judge soccer grace train conduct duty arrest output roast candy total vacuum","master":"a5fe2db0c41ad910231deb8112f6e10998895d48655cd77b142ad9846fe62458","seed":"4ce2ea9a4984030e65ab6eaf3ce543a450881597d8585c79a66d324606c00cdcb2c3cba4fc83160f0426dfc5a89cd27a9c9d05f94e3a04e3bb550bf698076b0f","priv":"b9eceef7003d3258ec2bca498b34d3181b38aa493f8b3b1237588873751539e3","pub":"02bb8de097658d0e711f875089062c135df56e33fe97e2c828da5a5023ba634765","addr":"963bbc3ce38f6bcf2e15a3c300e7eef5cf2b648c"},{"mnemonic":"lumber lawsuit animal member stool claim know frown knock hotel noodle pulse","master":"fee5ba9a343f60a5f0f38b80c3208908e2db6f03c8a37dec5cf55d833e913fad","seed":"e1fbac7d494d3e1def8d193a71872395f24b8d62bc052ef2aa6a09220451ed59b1f74a2bd02ddc0fcc0ab0f4ad65bc17462497c431f2689d6bb9490573ce022d","priv":"8dfa11b3935e4e660e246fa935b438bf9aa9b5efded0e62db64f61cd678e71b3","pub":"036dc946490687b821115c280ff113002a160325f212b2ebde71628ebd27e418eb","addr":"3e6e6935d3d9715f525fc9a43eb1e7465a1178ee"},{"mnemonic":"city drastic advice adult taxi build local olive unknown leisure bounce umbrella","master":"0aecf2bf80c660dc6e9a987d260fd4f38daf6a00979e2e6ff0769907c6cbe893","seed":"f66f4fc74817a4edceed1cbfce8986d1cb9c9f77b23f5b33032616879c452e64b5b598518aad9216ff0b210b38cae0a6d417b7200df3fd7f2c8cac9cde2fb946","priv":"c8bb1e0db0df18c9a4254cac791a309045d9fbe6daee301d431ad9dfbdbfec38","pub":"0376d3fa96698c82b0ca3d704e8754838a80f05d01c6cc99894640da9aad067d47","addr":"9532ab7fb7493cf19a9d2e61a808fba45dea3ca8"},{"mnemonic":"assist obscure army approve salt tourist program raccoon coral economy connect around","master":"27262a815e351c2e583835dbcbb7fce7c5f96d7b8deec45a6325d02b095135f8","seed":"72315d5e5ae5936c29173566fe17da012160290050475356063fc678a8a41530edba5dafdc2404c410c4b5cebe8dfdf5cd0f6fd855d94a08ba7e856c984b7371","priv":"2849c2468ce054e94252fa34a7e704e04042dee4bda5fd82d6b38e17d2451c20","pub":"03a278a4623f9f8d32bc8198c694e961868709bb5f425f6000413e6be33cfab059","addr":"4bb9c78ec04e00e84fd3310d101f3af4949351d0"},{"mnemonic":"limb nerve equip power pyramid nest sure kitchen lady burst pig void","master":"47e667f4fa090bc0f8df1db86c5c7f835d7e43b8151b6ae51ea12b917d4b23c5","seed":"ee38177c8d3f2c0076cc84887f8ec20b9b6a874d67a0eed6dddb889c1c7af30ee9031215b6739d7858a3ec35253f0136217f888c20621b217b8aec2a900bbb1b","priv":"153335c0a20adc5347c99b869b1f1b2a30eebd4e1c71082b8f16a4641c88df14","pub":"02a2f7b5767ee89ba4aed85a5c198b9b7e62118433b61bed2f85c843576428683e","addr":"50c74e9486961c8b0bdf5b2289f5484ebd6554d7"},{"mnemonic":"toast fame primary broccoli valley fit chase critic life absent crucial chest","master":"f4a62f84c5ea1fd074494763e0a541015341f6e96d965b884fee68c0ef5e4f33","seed":"27302ff242190977db86f09e9399621c82a5f953e57dbc3a01a6c38ce8b5da4a61b0e6d5bb79bce239e5fe59f3dd12f62cb634f9347afddd89680b592872d348","priv":"7ebfe174b48e60f3809ee65cae852fbdbdc292fdb934d2dcd101f9f9be11f769","pub":"03b2b6586fe30ab7d00dd7a4da4bdc74c8092284f9d7a3e78eb9f298dc26b3b856","addr":"bfa414a410c1cbe1566a050fccc48c99a9b3c973"},{"mnemonic":"live mistake embrace other bar tell promote derive assist deposit stable chuckle","master":"d8dace20cfcf215f4cee2e55c6b9b8f65225291d629cc8f7e456778cb2f5b5df","seed":"0a5c716e273df360383a4e29cf2e2df63f47012be5f0acfac32d37241bc5580096e1538491b5daa0cb4929807a26b4225afa988057cd195d8180f5beae9a7b35","priv":"15330ed9be835c3ab25357f437b5809dad522ed0c5e1e19dc78ecbace52def0b","pub":"03b6ee1d8c8a1fe25b6982ae76008d65b5a1ee20a3537898d5c3ce528f55544315","addr":"b0a03a30af7c4a79cf777c64a86d66251d0b5b07"},{"mnemonic":"orbit recycle wedding rhythm write come apology plug blur pave job rice","master":"fc498e657b1ba22254ab35dc64173d6f9c790501b8cddd18f1edd625964c8f57","seed":"af14771135c60a6cea8c4790a008ba09c890d826c8606c94c5cc50bc8eb36f06bc8eb374fa18a67d738adab33cd849bf1d8bf744a7b33197055c75e924f8b1e8","priv":"94442c669d73ed4cfce1b2a87c76696f3954ff4fd3a867232c5f878f2fec1737","pub":"03db45a44b5dcd8b34b4a5125e54811b800879a45593af61a28a83180f75817a1e","addr":"20505c7aefd22f78b05bc45cecfae800fa1575bb"},{"mnemonic":"oppose brush collect swim cup age gate forward spirit boat century annual","master":"c156132e600a1d3c359813d2d3fab0cf5ff13d8713569cb3da35ec78a424e193","seed":"8a1ce5772eeba927d2f237acb22b9e86ed2fafc89c18e33d1fa040274d1dbce37bb2e93e1ec8e2dfbd32cb299fc966e43567f11bc0022811e6d43becb43e2e1c","priv":"f2c9a5337186920bd738336ee616ace6f7c21b68e731c8cd84dc023c89198525","pub":"021a7131768f1e6f03b1177153f36815503e411c54a6c33ee6a20281fa8bfbb8c0","addr":"50e772de1a2e1028fc46d8958f96ee5802d477c5"},{"mnemonic":"genre seminar green olive grow close siren sadness farm promote bottom few","master":"ce632e9a0596520a05d8c096928811ded1f9a09b461d2924f9e4ffaeadfed8c2","seed":"dba3b4f2981a61525481c49e34db737274b80b86ebd2eb6cc64b05d8e321f871a97938e56abadb178688373b8c29a7c752d7c53a55d7e26d660ca948c8ea76cf","priv":"14e58e498bf7d472247df7024c6465db0c2f7b390a65dd05028b42576a3d7678","pub":"02ab7825f84bb603bddf4325c2afd8f7497bd1d22b412576e8155f1fb91fb9b777","addr":"a2e64380682dcd5ba6a4a5e7347389da76ab39d1"},{"mnemonic":"radio minute vivid clean cost gadget ritual front tilt other valve now","master":"c1fc2d9a7484bbbf513ce72d4280d4d6f01ee0359c59f29a2910d44bd06b41fc","seed":"8d4a332dca82af94bdc825c3ab49b970c5a2263e8a07e848841392f4274b44cbbc57908d6522369b32a584de1d8fc012f8f7f763421cc309678386f593e2f819","priv":"fdb87e0dd6892d1b7e29e59dd43d7cc5bd7825329e569d5dad839836d551381c","pub":"0274c7216f289b5ace0f684dbd8f9360679909aee0244f5f16b65ae33b1f0d9737","addr":"ed20a72a5800b88c62873ded8f5e31bf0ae08944"},{"mnemonic":"clay verb soccer near actress august like venture goat rug brief scrap","master":"d888a8d4f3c351b37b6bf708f47ffa1f0d56dfa35f039d4c8c6e49531043c4f4","seed":"470399a3fdf3f7f113b6996468b4cd22524b05290e7e91dcedb0f8cb6d2fdd39ded069f3faa72799ed18d0692301a64a214fec0cab41b3bae69d121d06dfb2af","priv":"971aa66792510f25849cdc1a7ccfd7aa8fd82a0f42df4a947ab675fd96db7022","pub":"03f7c82b2ab42b8e221f661ee3eeebe6231f5d98ada0133431715db7302814d448","addr":"2d306db9a75411f5ee640e2778daeeac539b1a52"},{"mnemonic":"rose team vapor oyster embark shell six object rescue village rug retreat","master":"471f619784e65272a58248f67516ec85a69dbff66719eb5bd17948c4e2e27c94","seed":"39dc2669bc21baa81e45013e856e8289b858778d3b5ab601a26115beebacc708236e742bc105fbba968e364745e34a0c9fda0799b79b859c02efab3c3a4c7204","priv":"581e1940af1601b7ffc624a6465519cd6959234d112353d3a6f2ce4ab3c75711","pub":"02ba88784648b8476c55f9cc4be65140c478b835d79fa596abde69038f9b5a2b2f","addr":"bea24bf839a66b47497014c0f29f98bbd506e9c0"},{"mnemonic":"blossom turn knee oblige digital mail phrase fly soldier unaware corn journey","master":"d7f58c53d2b777e2f1162bf97573c03446afc51dc758bfaad0468c0edec615e4","seed":"f13ee4c99a6c39751bc6922c9be96321c7704c36ae6537f13146b4eda938fb8b2900e44e901223b2906db6392617d4e156554da83644731ff6e56b0b3fef24a2","priv":"c4231def1f2510c02388455fd0d5a2ccc80aacf2faefafb3534544f1b75630d6","pub":"02f0e5922755d841b79fb76f0f129ed3d10175ed4c377d02403cbfcc1c9ffd9c64","addr":"8c664b57dfede7168c0bde20acd37674a1922dcd"},{"mnemonic":"crisp joy brain treat actual later nice ensure village bind powder merit","master":"01058624d066cd1e0527da16937d9ad9bee8b7aeb76c279ea53f5c5d7e56f6d8","seed":"389060cdd3a98f5625f373a0a536f70f84cd0cc6a7d5bd8ee20fb94a2aab9652bdf61af9cc532ebcf217fb7d860c30ac1ccef4fa46b0478971653a42a1879811","priv":"7c0389b4564ae01f4c14da09842984f9b9720fca2d09fceb0244623db5cc07fb","pub":"03420010f464371dd52a34cc193d55de94a3ffb3e746c5566bf8a8e6bef686efec","addr":"c9ad4a84c23c753544d4c3972b0c3d2d86ae397f"},{"mnemonic":"three scare horse film rice divert frost gather photo weird nuclear hamster","master":"b5107f515bd7ce629e85b64264b2c9ec80595816d9bd47f04eaa6971dd565d8c","seed":"ee242699f11339f305818f44a171f79b174f45c09f2322f53ddf3094e830fddbf4e418bc3ade62f03164d8435036514791b936ccbf5f405defd33bf68984ca01","priv":"99513bf817cf2726237c70a70cf6bf5e2ffae1494b433e1d77c8b9c59a3e47e0","pub":"02641d322b89339dd17528573b100647bb082e91d7cf24bfc897e90b20f270f791","addr":"d8545d2e2a4ab61af14c04d40fcda9ad39bcaa33"},{"mnemonic":"circle pond sing route tribe grace exile leisure health cluster prevent year","master":"5cdab97cd5aecd22d671964282f6971ba4be01267c90677091d6db6b5adee0c9","seed":"929117b95286a76aa839e45e768b9f5cd23be5bfa73f929ab835df15cc1c96c2c57cad593b7e396296c0223d38c38b03a4ede097bf3b188a11631537dc6223a5","priv":"35fafc87a67c7547f256f7bffc5b19395349e1665e01a89f228f44af8086b118","pub":"03fee2e799ed5232ca3a29238e0140cfbe5f1bc6ed2c1429c0914c4000ad59fb3e","addr":"2bf9cf4c3f34de93078928aa8c6192450a29af02"},{"mnemonic":"rebuild address giggle city tired dice sorry danger onion cry cheap sock","master":"83df9579ad9f629ea3a09976302888929c52527620ec7041fc9d4e36380fa953","seed":"7cd7ab5cd9f450b45515985a2af469765286510461f42d4ee5258608aedb40b7f60365b685a706d0e0d82f775da38f0171bc8be56543113805227c5f9526e7bf","priv":"a1613406d358b4c1db8439a3e69a4d7072dbf78e06c8a8b72c37425761f874ae","pub":"0395d2c96136983d906c50caabd2f61d1c1b19a227549f7bfeea2ee327c5cea276","addr":"b51131cafeb358b0f90101072a0bd70fe5226726"},{"mnemonic":"toward turtle false distance spider plate aim daughter team jar case option","master":"229e0c7738aff8a44fa62ad310f3cb18f6b94610c83faca246c428c26f47ca18","seed":"405cc161455171571df109c3baa2b3ae25a8ab9b3c7affe9b09b32a755ea443ee590f722f9d2f3c39e9e828a2f276f46a6f9b65b024a11c6d9ae76929210ad23","priv":"095f70fb24f7f97994339cf37a6afc4e95f1a421d9b076cd714453ba2dfd29c4","pub":"037fee3b9ddecb153acb32358781fb541283c3a61ce2f25366b199f970a87057e7","addr":"f3e1bdca0ac89c2f4036f07cad45f65ecc94bd61"},{"mnemonic":"mind mirror athlete assume piece surface raccoon struggle inject horn body engage","master":"75156c7a3676b6a756cf4eba160d44d94ecbc6ae06457ca714f4313367e8493b","seed":"c754f1684d8944deeaec89ae5977458ea9843b4bfa0997a7c1213633c6203a154b65f2109e4e2746735c85ffb7dce803bcc57b38cd617b43345c2b486ce44ebd","priv":"c03717d4cef8ebc0e4bd6d78ab5ff3d5975da9919fab3cef3249d329d488fe28","pub":"02638868a04c039201022036284a8916939b6432f4a469c132748955f7e6dc468d","addr":"d7906686be6e6b9e1dc032c9e89d30ca8768c698"},{"mnemonic":"armed lottery garment beef manage knee subway market enough end clever edge","master":"08432ba7a4152d14119d22b52f8913f2e221237f125f58e4df5e5c87da81a74e","seed":"7660fa9d42eaee32aaba664593f1271cb60e092a5758bf3353c03a448360ccd74ef45b01612aae2637aeb86f8d9380bb8ce6b9eef5e0739c85736cc50b612d51","priv":"4f9e5ef095a07a939d5f3296b211fd938ca90d21f52640da2272ab812947127f","pub":"034c3bdf7e1bea7d629e2b1f82371d1d7d04bbce016317bff603a0cc2682544a93","addr":"8ecb13c1076cb132990cbd0efeb072e58fd3d1bc"},{"mnemonic":"city chest trip critic advance sign push patient choose pride lucky cage","master":"5069d7379310d03e01f740871ddb8043daa108e523ee5c2aaca252d079b9b99e","seed":"5459d94456d6fec414efec5630285ec7e05293d92c8290a07b1070b5a7fecb8f7356beffc82790b50da2fbfb28921bbdc64ac0d94e1d565f6ead799c1c04e7e6","priv":"6d334f7f362d2dfb4e7af20f7fe30887e3c91186954a8252078f215ca22e4b07","pub":"03fdb94e64855c4c973fee4157d3949bb9b840ead95906a672c1d08390e3be4883","addr":"bfa8840559e159b5cf6e7831c4696238202171cc"},{"mnemonic":"fuel derive exit magnet shallow salute clown prevent inmate hurry conduct series","master":"0c721f303dc4ba98877e76b3c36d82a82639ff6c02318dfd4547943b39d7fb36","seed":"877d16863699cca3246681de6e1b9f2c4b59ad600341c0ce16dd8c95c1f5cb1964bdafccff0af5d29eddaf9bb564552499234eee8e493549d0f6d2cea0a71695","priv":"b4f009ace3092938c51c2d7557b52900941c6dc437306883a89a51e29af04900","pub":"024cc003cb7be1724456fd703edfb7e339285883088e97247d83cc64e8283f796f","addr":"b2bfd256adb5be91b637eefc2c20efed75659f8e"},{"mnemonic":"soul junior garlic chunk eyebrow betray heart sunny average coast help champion","master":"7c420ff72c69dbc9006c4969beb830d7fbbac17dfedebbb7d7852430f17490b3","seed":"34ec95dad85e66b55bd9bde227e68b86298e4bb51b3b3514ff774298ade39fd769eea0f2433392a09578da35738cdaa31a0d71cf043204083006cbccb9ada2a5","priv":"719c2fbf2db0df066f36fb31275ab75a3905c52b04335f97f778c540e103a7fe","pub":"022333046c912253a37832140cd42243733ccded5a7a13f20ffd6e59cdf19443f2","addr":"048677f2e035a21eb91d40555f0c9ff53f335660"},{"mnemonic":"private outer service journey dry exact thank ability wheel destroy blade scout","master":"6d87dbea0c85b9ce5e67831bfab7e5118ea85d7e9103140842ed4b7aa46c2b87","seed":"d0fdad93d2b727475db3da1a5cee5a4dd8c9a0794a6a73b5c3d6078541df7e7717aaf0053edf1d4a670dbddb96a6085bee0b7bf0c4428f09bae98a46c93e139c","priv":"aea666b18ff888190a0119fd38604a711a66d235bdfd514378e6a52efe4067da","pub":"0275d06c981e89fc560ea25164baf2c238b6fe33bb65e78952e6912b9cf991a65b","addr":"32aa41676d1ab5e54575d0d13f673c352f0f99b6"},{"mnemonic":"diesel suspect urban fatal total motion other opera taste shock prize lesson","master":"6760aa56bdd6d9a29615c425d934b788ccd70b80066c85caa2091e3861a5508b","seed":"bb3df25ef6c4ac87b93991710c0b927a24c47bfe467cc3d057ae3cc5867bff989d6e8df8b790b52661ad3d310730dc55ba8fdbbda118d3fdf75a21750f2f8089","priv":"399d6d98eb0cef3674ce7d155b426638ea4679fddc624cc582e13b7f2927a8f8","pub":"03e6082570bd65f91edcdac9564f3d71efe75a4bbdedc379774ca9879fc8a57cf6","addr":"d3a69b264f967565d19aa3be68b6a20ed054da40"},{"mnemonic":"tide rain throw pink treat sphere soft season network good left potato","master":"a2f3cb3671d233a245fbbdc8b769089035cf13a9312a78826972dbb99eb4e619","seed":"0fa23be9b8c9a11dd03a5d6c1677ef78526ff2ce3e12de5195d2e1b40f2df6b90515bbb6eacfffc2e9b82ff66426fa1e3a86b51e98a733d054c4b58b6b5e7025","priv":"34fd376b792658501ede9f9f2726a94f8763151e20a3325d05eaa7e6b92b19a6","pub":"02f2f3b3ca1654334091af786f28f9b64dd599f188902cc24f2890edb62f0f7527","addr":"1f06acf38751a45fc0734766e3c794547a31434b"},{"mnemonic":"hold forest select elevator skull warm crater help sing liquid foil burden","master":"20bdfc70225db1ad0d9a1f53a1558efe992ceb7001f181a0ab5a0394851dc81c","seed":"8839e0268e51734574d033b2ac42d3de449819e0e6a916b9f59380d15be767f5a491076bb4e9c2c586cf92d07812f7338400962d28a06c2218a3674bffaf586a","priv":"8c1f88886e7ee663a9df9ad3b31871cb864bcc1ecac7e19bff14344423581796","pub":"022dc59925b511f1420f897805f13b684d9e91731c88672121dc59308ab4fd7c12","addr":"3911febb503ec0cfe4bb41bb6e9fd1924a027aca"},{"mnemonic":"power orange shoulder stove sunset during jungle buffalo funny enough immune skill","master":"51384a8d4d886c1f0a7b4b1938d798c0463e44fb0ef05f6392d5f0c3c0c1813d","seed":"ef0f86555bc2d06fb8b676196c8d046aecc752a61a95d4783f8e90cd0a3117e08c11171214fa63a8e86a8280ef98cf4cf780eb384eb78ece725b94a261770268","priv":"e644ce7c5f3541acf3649d8a44423d277301e519147f50be97dadd4ae1d629ee","pub":"0312f8f9435994bd6156ef158a80b721e73dbca17671aaac7f7d67cc847bda7ed4","addr":"82167c6542716e9c1a072228a6159af1b02f8893"},{"mnemonic":"black evoke reform inmate similar wall machine deliver gift photo axis mean","master":"2cd652f239c8ee231e516843dc9bfed097ad33378563e2cc50e07a48cf0bd28c","seed":"02da5a82f2f4a6ac1a4a962d5450899e949e702f96eee80f364faa7751b50a55b438c6e4f4fac1b6e495b06fc55f63ab9ec1d288df3d62f6644bd59dacbcea1f","priv":"f6566def1b32c210a1369b859cd8815efcf5565a2e1334afb0663115acbb5724","pub":"033055d70eb1aaa92d91e04edae35bdcf2dcaf4bd80cb2f798f2be9bfb6a6fcf3e","addr":"dbed2e50e81e7b093ccadb9cb1ec9ad86837ba09"},{"mnemonic":"sea snow child feature gadget oven this lake post entry essay alpha","master":"0ca6e7a0b4fa4522ed7b8ae0834949bf8a35f7fcfe099c237513d7ba59d82562","seed":"94a9ae63647a2b63121725f961c7e56c7c6b6985a169c43ae41434c3155ccc8244ce10d6376fcc473d7663189d51049b035e5e232834b470a404f24e286e88b0","priv":"9b029add6a255727c4cb80b868975e95086487b3a463cb35870a74414fc6c14c","pub":"028a44cde34153397149442c970964c1647e214fc15dcb345c4025cdc26cdbd3a8","addr":"a23cebeb59b458c97abd67a3e32387bbc56545e3"},{"mnemonic":"couple regret airport shy symptom shrug mom sail insane culture detail shrug","master":"37711c29531e793d6a5e2b4931b3aa0240ccef541c9b8408c29bc5b68eded038","seed":"9c054a9047e66665412432f402f94e0dc5f87d7cbc1a32f6486cd928bc2a9a0aa898ab91fd3aabb962af985da396eae7a0d00fd739650bffaf070c9af44721ad","priv":"b9f1026e086eeeac648193494b398770b7226d46221cfd7281e5519e81fd8fa5","pub":"02de158ec50efb1b8567d63331fd7aa66aaa59ff26a621a59a52ad9341330b028f","addr":"aafa96d9be89b09030494856cf6275b8e9eb387e"},{"mnemonic":"mechanic sadness easy credit eyebrow sample health pyramid bargain actor power glad","master":"68c40248a8f7049062f18ada91f3f2166b37865895d4fdc8000268dfe263ef9f","seed":"d28287812cbbf2cb8509eff491ac456ed199dd2dfc8cd3c93e05b0541c154850f09f686a573994d41f163884708db205b37afb02752a8f0b2b9785c6eff504b3","priv":"250d326d0c232bdf26b6eb8e349ae5b49e30b0507fcce0be1be3bce55b0f7645","pub":"02d5713f20005136dcf9d8653dbfd75bedca3f42b2682ec9918b92394f2b685b13","addr":"409ab6606687cf83eb6c2388d6ebe296b4799967"},{"mnemonic":"mercy spell despair dirt board clerk about symbol supply provide rigid evoke","master":"37a0b9c11386b995b71a8c8a5e150ff76d238779b8148a2137e5d4666fe9fba2","seed":"9e3ec2ab97061086be1e02cae7a0a30493c019247411a7e7271c0c5f7f40bf027ad3230a1f113580365c82549ae23c024ad85a8601a30b6f78276744ec803a35","priv":"0385392be6a34bae1ff02570948ce1217fd11700ac753bbbbd47a1ece41ba38b","pub":"03218315e18c8a5128f74186223d32ece9c3987a0427db95ef51eee9acda922c03","addr":"725139ec60574c941c133ad2e09e793c1cd32cf3"},{"mnemonic":"emotion exile anchor charge silent nose family tube view lottery neither razor","master":"d8e841a6199f937fa9bab3c3905db51899d456f9caa5d85d9d930f9981ba6ddf","seed":"c8610e5fa0b9d9a83610c4458129802434d7045fe44917de29366c6d900f123e5414fda889e21284405c4c64fe745a36966ee86fd6f61d1dce6f809e0e63624f","priv":"b567d59ec087a81214968756017868e483e62326bd7239fddb27586745412349","pub":"03182c009fea42d30f31f24b6a5d251b70e72c1262d22f25418653cee5a226bd15","addr":"9f5d2ece004dd9ddd79b164c4b51361eceaf077b"},{"mnemonic":"orphan attract pair execute fresh interest artefact shaft sail advice vanish moment","master":"b58a705076e0c5aeade31776d78d319529bb76ce748aacb266dc910595dcddf3","seed":"a156c3c4b6241c4e99bb63dc221b13fa77219f2419f7c33a7a7752b5dd89d5be2178b6c2de2225292bdd0bbcf3b90bbccceb93ea65deacc866a5a3da4944ab1d","priv":"857564d0b2bfda18ecf561ea17dccd6d1bec2100e79b6adc8a74997b55f53126","pub":"03eddc58dac77538639745d167c174b907a448072ea4ef9b14563217716fb606fa","addr":"b3a656fa40d9a7f6471cf6dbb00fa0e2687df914"},{"mnemonic":"guilt awesome champion wasp execute purchase better mirror such prevent stay actual","master":"ffd1b0b635383f57d0086c1e6e4925d82a9cb9b310d0757afa8d941a13a1d61f","seed":"c36560913942649932b4aa8027520c46155135b50d66b0c6b33a7f63272b3d531946fe3aa0efd22c6e91d5e19cbed5183ac2bc7a18c219ee3e47dfaf35ef15dc","priv":"d5d35667bd3f54b40858f3cb4c6f09feb889f11d6da386935fe8b42e3a37f58d","pub":"039cffe0fa0a30d9ab9b1ca354ace89b5c9cd21d2653eb5a7a8c5b66c03912bc8e","addr":"1f2543b17460c4f7c2d53369fce6383771c0f7d8"},{"mnemonic":"pyramid soul ahead tongue observe void whale sense keen feed today abuse","master":"272cd80e4846e16f0449c68c8ed4c78071613b57660b85206f716203014c9231","seed":"2f342928932ee8e588bb75ca7cdcd7cc61f32eb317401047cca5b4133e963776ad86474999f9013be1f6cd947cfd9cf4add3be93e686d467223864851ea71751","priv":"d52cf3cfd4e6b6310bf47db08d27ebf0109582f78419d369c4c5da596f22bdb6","pub":"038f855f837abe423fcea3ce81efeccc49da313c71630cb08089956afb73e96e95","addr":"c888d0e5e1840b29f6d85a64cd9704221fd3046c"},{"mnemonic":"speak mother wage grid column movie pluck deal bulb stem okay own","master":"60b4e8cd422ac64986d88f4412e0c694d77d09d4469b06bbc8b4d9146ca5e412","seed":"ecddae7245f9ceb3b2eb324a78421ba99d3b39819bf394be90309cea21d6275ee32a068aef8078fe3514cde61a69e31ebe091669392b5c8a442451b895591ad8","priv":"4695ad7f839e5997df9747bb6d4ceffbad85f6bb26d01c328e6c6e8f6e68800d","pub":"038e3e274ef62db04582bdf01f4c443fdc5b590da7d2c0f5f1d1d55abb0752d440","addr":"359c60c1bfe3a11711423effbacf7d857d39437f"},{"mnemonic":"unveil toast planet basic limit bubble lawsuit grunt lonely favorite inherit write","master":"32bd1431071e17e039819b0f3d9d959c5b88813cf49ca69c90fd547a4fedccea","seed":"d036fc1412c23cd5406860b96814ad9f54359e103834f5d9d1e5f79d52b2e0a8432c4ae705d2fffa9d87d4946dbed2c847a4589542f8051cf6e37689617964c3","priv":"93fac9e5a9e35c2138568864525be7a43492e11f715c097879033aa4019cd723","pub":"03b0e30e8c5bedab8f9ff703df5c9440855b96594e19a367f3c1da13aff1f606ce","addr":"0e70b83293cbdc8b5e3cbec03cf2d0602f221bb8"},{"mnemonic":"cereal forum again rail lawsuit mandate above vacuum hour tiny rain mad","master":"1bfbb49078074dcdc191bb798d3c02462d736f786d7e91461000fd644aff7cf8","seed":"2aef95fae13809c1689d4b5a6598ad4e642ec6373dc6a10b6f348718360e3397eee9a2ea24acd344260d4002b2e7857e71daa1e7111f943ba036d4d94deaa339","priv":"75d0ffb17edca54a389371ddfbeed3a930ff3ca88ef166a67101b9091636d7a8","pub":"03c1ab2904a55bcbd56d1f1b2840a4b09f665576e980cdf2fcd45db21c007fdf82","addr":"cedaa1fd49e697c467d8ce47a2d67ffbfcfe1d56"},{"mnemonic":"infant glad torch shoulder benefit pledge social indicate present deer glare hope","master":"fa580a50eb13d1df4efe98cd3e86a1927e4e9b8262a279f2e782d298641a7378","seed":"a3e088fc36097fcbb0286a2103e2b8f8c1b3e0f6d8521c82c2c93fe06a8c1b97748143b02d9196f095ec1be5044aa0d89b39bb131c4488858e549879cca4c8f4","priv":"61c933db24e871ee66fcce148c2ecc3fc85def76b1e6f8ea784001941deffca3","pub":"021922866e34e3d7e28c1f5778c70e7b8742c2c9151ca5559039949f32ff0854b2","addr":"e550531be6f31c18a90bc6add24c02895e444794"},{"mnemonic":"laptop vapor rotate chief frame trap duck satoshi obvious pen oblige bubble","master":"239c6fca9e52e705ba0d2d9190a08748408d3a53ba0d19bd51fef426b56e1ac1","seed":"15a573343b11562370b53ccc9f11be74e183b1a341ee922cdfeb8c84a4dc914d23ed6a7f58ab451cf57d5f610c8ed9f16e2072a71ab8edd82414fb9d24cacc3c","priv":"ac37a60d2ff77750624fdc0d41531ebc6dfc1786f681dcdb436ec920f91a34b0","pub":"025dd6a2cf772db80dbbe6957ad1606603cd5b065177ec93263ab0194505c420eb","addr":"5693d8a59358cd00f21dd8786248538bdfd0edc6"},{"mnemonic":"walk raven camp kingdom defy nice hero copper velvet lock era south","master":"b4292f1b198481120f507ff13017c2756208cbc9652c555807472d872a58b9bb","seed":"6d2f085ea9e128fb3652d78d9e14e38eaf793ef1aa8b455798556482a5c2f3dd43933c26ab9fc38fc4943c82cb85c8c5b027534f005d45b740b31f63c683b87a","priv":"ad8fc7544b1b79028e05e96c9889004d9c5cdeddbcdaf05bead09b2075dadbba","pub":"0285d2a820245c70d9f3cfc930d6c4e467585f3c831cb7bcd46f58d637bc827729","addr":"4c7c3cb79dffd93e81882b609f7424431e55d4a3"},{"mnemonic":"impulse certain olympic advice entry initial bean glimpse begin flip cotton mechanic","master":"b092aa1b7fa22bacb8915bfbee4018484dfa4313c5779142e71e6d80e334dac1","seed":"9dbec0ace8784d915fe1bd3cc88b7c774fdc4791ace38856dc0500927aa02975feac3d82cb9771bd69d5b2f8c11c663e887b27292e3ecb36ff33ef5b3b3a804f","priv":"19497a3611ce0f1fb43aa5c55325099b6fb18811c99ec1d38c743c3338ddf5a4","pub":"03ca79e260e5a06bd3717cd969610c06580f65aa158e770eb418653a95a52cd0f4","addr":"f83b4129ec37643eee9f5d262cfe80087c5c5841"},{"mnemonic":"trip brass eyebrow plug sibling couple tuition tired warm spoon october finish","master":"ba1d19fb67d08931e7fc46b55c02651d374c7edc6df6a3b89fdf9e28670de4ef","seed":"736522d275c19137d354d8899542497b76b304e33c348e8f446970cd77aea927e2fc1d493b5f8dcdbe48c0a535722ba4223ef52925a57db21065f92779ba66a8","priv":"5d7ece46202706ddb8db591c4e125403f9aadb33c96f259105a0648ca1e2acfa","pub":"03791637ee34fa2e798c0cd98ea21cd17a4c02c429f05a9df5197b852fb643216a","addr":"e46722ace3466a38d3b5f66d5f94786d4576390a"},{"mnemonic":"suspect brick cloud coin tomato guilt inflict type lesson panel right still","master":"56a2d9f123ae22001633fda68b5b6f1fce4959ef19dac2c2a88ca5f774cb7d71","seed":"bc3b42627e5dfb76f1808f75e8cce883afff811821dd615262fa62c98c00cc0e0fd97b213f3b386ac00dc38de399e6e56b9216e34e4deabd15d23d70ff94cfd5","priv":"0d2c63fef727f339b9563c1f8bda5edc3755029ed45010e99bff74bf805f187e","pub":"02742f8b32ff1cf54225fd667425daf286705a0852e554e3294d057f5b41bb737d","addr":"4ac1a9bbd5d9d9597587bb809db80b69485d7e47"},{"mnemonic":"innocent interest smoke fortune smoke nothing clutch dust ladder clutch property glad","master":"ef88eb840ba3b3a072860d726b16c5309b9959381db68debc03d9516a7a7205f","seed":"33a6441e74f21794565c5e219b98416a17316a7b9335f8a0f5a5ae45608b315539c9938740266b663f8410e773dbf361f67550e185c0d42fdd4b406fec4cecea","priv":"5360d32f6dad727cc98c0c1b0dea7bf59f89aad2e5127050294adb9d7b116788","pub":"02bb5f40466fe161d106ccbae569709217ce1da9764078d27d3c8375752d7d1f87","addr":"fbdf59b3297e67600290d6bbffbbd39fb6f460a6"},{"mnemonic":"employ ladder boil blossom level pitch vapor gain permit manage coin supply","master":"c550d7336d80488c81ee8f2a8c3fde04784b8f3079d63add93b1b8800f796024","seed":"a80406c58b6958a30c0bb15f3b6f9efcf7e0c8cd0f01114a72f9c446130801c539028c964321ed9ba511831aeb00dba1be82eb28977319f727de1a9f44b1a7a5","priv":"9233c90da7ccf973268310430efa073e4e070cc5b9dfa29612bcc9541ca3417a","pub":"03c070cf8379e2461ab6158755f45d881ab8fa7de1501bcf0530a871abcef79947","addr":"fcb4e5a3f2c568e0d513d1ad97c7b806a96debce"},{"mnemonic":"winter absorb stamp enroll brush paper spawn slide salad special front update","master":"ee7f947acde43c8fc5761af3ca28fd0e87d0883043ea4401f0d692ea818d5573","seed":"0f1b5f166616c83c129d6b2e0d1cf706d46fb56e60698beb77f9eb105bc0726fa7159a4a492b6de462517d692bf26a310528379ce47b4325879772f46ea0d82b","priv":"31f98cc2cdb0cc6d88d91f21960136650d3e7bca690a569edf2ddd6095026e38","pub":"039ad4a48de652c30e015c424c2ef3083f234e5df78791f112eaaab2f74deb71d8","addr":"68306083576ce37fb1bc653ef33e46ade3af0c7d"},{"mnemonic":"focus usual earn deputy execute climb broom save robust coral piece shell","master":"148c7f123552e1be3f696b2f8b0df4885de067d43f9c1e5c671ae6a3ba4dd361","seed":"a4f311017ce37d0f1199253671b0f615ebb09f92648cd33590c2292d4bbe1eb45d6f1a94e71e1438c5cc25974efb3b8ccd03272ea0218f171b01c7fde17adefe","priv":"587f36966f566888d5684aa983d86c124b4657ae02e7d540939c5265ca50ae59","pub":"03cc82a5871dbe05fc52fa3308bbde84a7744780a4c6344910989437b37b59a0c5","addr":"6fcc01f30a9e9733ae95a049ff8b3ae0ea8c97c0"},{"mnemonic":"twin over wire boy dragon drift erode human shy minor panther library","master":"1488ced839d3116ec99c8d4fef9208224ce28d270e4d3242999e8c3d1bcc1719","seed":"099d13da6ce761e666e6df0199a79e95e83d0c911279aebf8037196af6c7070dd08867dea0da8d9148dde2d14ac55864a7dfd09464282d93037aeda70520d664","priv":"1c2871733b9b2fc6224400612807d75387c37b87b925caae6486b777b0dc1e53","pub":"03496d39cdb3d666703b041d5bbb69482537addb552335c7f26d29e09d5ab8500d","addr":"7b89136f5fa6320f53c25a260b4b75eb5bee5774"},{"mnemonic":"potato lecture exit color target shell more push day catch entry erode","master":"a44668b008915d6eb656347398a007187c18cfe766ea167a89e855a77b9b9c37","seed":"815db5e7fd253567cffc54d938a3fd307968b45e95407617c55201d661f2ed581e92f86a1391154e6421bcf04487da1d3c098382a3587e8c5679704407812fab","priv":"de5ca4846103dca9d947e7867ed764c9094d40ce189cd2366befcb557325616f","pub":"0342ebbb943a1f8100441035ea11cf76c17dde7b7298d160ed56e3dc8fcdc7a8a6","addr":"68f2cf5a8b290409689d5e08f99cf1b882582e06"},{"mnemonic":"grit flavor pass apart swallow quick payment view weasel decline travel hat","master":"3a2d8a4e041357a246be12beaade6b6c36fdab6dfbcae0f8230106a09c5157ab","seed":"a69ea95da4c681f004cd5fa6d357c39e50594b66c73a42a93672c13d6dfea0ff0d741bc1b406851c36680895a8137086f6de132d2aaa47af5d4872fe08818171","priv":"502b2d14765f2f80f6ee0c10b98333e498dc7d33a46424555f8429488d57de1f","pub":"02aea2e315932b900ac7e31d5b6b82e9966e45b098dfec8990e2efbf4457e581b1","addr":"c6f8426ba017b6ac4fd45a95341e760f158f0e41"},{"mnemonic":"machine insane tomorrow island assault follow verify spatial pizza major cannon inquiry","master":"be46461a96c733b1add1465d664d74b8e1a28fc1bf25746b9e9d44ddef81ac4d","seed":"2a5d713bf4b71dcb40d0526767f8466c87f04ff5b2fe38ac17d5a7418f099b25761917cddec77d369471bc22a1f26d2d7f6fcfb00b3dbb28f08279ee0ac85f1a","priv":"097be27be2a0c6960b436acd651792cff207d877695acebd02c088e6f3617b9e","pub":"029cde9790e6e1b55d54aacbfc6d13f09fd6b5b04976d0ba5e01cf25da0a2c3976","addr":"06ffc6a5742544cb3a66bf443ec0d8894e5822d1"},{"mnemonic":"plate grid latin above champion demise idea urban raw exotic day diet","master":"9daa2224bd8c15a22941090eac1262e88dd2faeb708ecc00f404c88723bf617b","seed":"e07adaff2724a1af34ea6f3ef3e583086fa835ca126f731875f97b366322aafaa8d39b72a22dbe70bce68d8539f1ac109e3af03db42317f3807e91c35748438b","priv":"423d528c82af34cddc13f8873534984302e072e0aabc9f29b10c70335bd72a3b","pub":"03241547e0145dfbac8bbd5daca05314e2fddcc22aadaa8b49952e461fccce7d17","addr":"2c1ea451fe2233aa3d2120f2b836d11cba72905e"},{"mnemonic":"august quality apology more ring armed hamster raw gentle inhale angle dune","master":"90478d31095fcbbaa751055f7d9fc70a75a8dd34ff825f1b4547103e3367ff9c","seed":"0b944522c472688010098bad62a38a173e0184f64710bfc370e8ffd7a3e2383d630202f52b7ab9b8d41948f534b2bdd0e2664ba76f2e460fc62e73fd1684ff16","priv":"e8228b2ba4ccd5a22bddb4e0a3eaebe6a156ffef061779d264b905c90797826b","pub":"039fe65040d933902f33749f3d43cb924c6df298a969b05760bc4c8fdfb27df444","addr":"b0370814a3a0390cb3874600ff1dd48481725ce0"},{"mnemonic":"argue april pattern jungle favorite shed silk adult file cover benefit neutral","master":"3d5f13e3264550f14ba0edb8b693e7ccb5e74789359a7cf9b7f819654542acd2","seed":"f5fa70f943ebf5b941574820d4b91a1ce706fc5f9849219b7e2e0f9fb410c4bf81494beeb390383e1371817a39f2cc7a9552452d973ea8a15ab42b881c7cbebe","priv":"d0d2a3c92a4b1914064826c1a9205ce8bcb076109ab2524a2818d2ecaab08420","pub":"02040f9ca1b771a4692ff543df77d2fa8fbdd9dc5817789b1ac491a9e0908638e7","addr":"0fa135a93523a80e03603c609953a2f5c7b799ca"},{"mnemonic":"oppose describe defense consider long lesson better kit capable taste feature reward","master":"07ef0cb309577396089c024c1b48dd278d0575aed88e63ac99a44d531fc919f8","seed":"c6ab42822e1fc062f5bfa6e5d7d4049a28be293748858bb2062f4b9a3c20cd30dd02e7e86dbaca2c77bd2e1d837247cad63f8009f9f9410a0365ef7bbe647727","priv":"3b82e67931a96b68e6752ce67c1f971e23c317f8829e2573672edf1d80c68836","pub":"0248ad30caf9f25bf49bafb519ebb3d381ee9c95a6da6502e1cfc88a4a1aea3b37","addr":"17fe8e8d5f6a4a10a2b7f0323cb6ba3bdba9fb93"},{"mnemonic":"blouse patient surface urban stand clarify old pipe where spatial cargo shell","master":"8ea8f4837a7a4a3bc100595fb6dde65f319e8928e61f7da3eea2309169b9dde0","seed":"a7ae3795447825e6d51da632bbba6f8d9f5e141e593d2a78e05f7e0914ed063d629f1f84d3427e7803fd1e317ca0359654bf918724705f523e2a896077c39603","priv":"6fad450edfab3300ffdd65133f2973fd0be3daaf7864e2f357598b63416a01d0","pub":"0211cb5c4316de9b5c08e8764027f9dfa0cae026cd9ff9773dcf524c06f76c08df","addr":"2a51a4f2ba38e779b20b7a4bfba78e8267b6d6a2"},{"mnemonic":"moral penalty ladder step panther divorce bus adult math various speed rural","master":"9641e82d742f458ff81d48d486e38cbb8919a56b2a317d822674ab9e4887ea6d","seed":"8b4c57108bbc2c753be29e0b19ab43b06c7c81e2dda243535f74c08222b23789d3aee754e23ae936df99c8728b04cde066b6e6e512b54fcc1dac28f0b0763074","priv":"043dd7b6ec9ac7f52f1af6f3ff95cd99371c251680c04b3c847da42242d152ce","pub":"025f7dd3fc53ceb3ff87c2bfeaabdeac1d5f1c9b8a897bf4a28ac33b95562e4f79","addr":"9a61f1c15e55009122d52a1c3917a8459fa29238"},{"mnemonic":"pony liberty split enact quick arch mammal velvet cart wait arrest burden","master":"e5fbd41b38aaa3aa643a66aba1c3e8a01709b15f5e1e30d639db03dc87151065","seed":"b6a41b697611cccb9e117b5ce798d47bb37ce1e07341cfe972905a4b66c4b7f8596cd0e6c21e0cdd221be33de8c0a5854c5f8618df36f28d95dd1dfb0f31ea1f","priv":"7e98676864a3649911657e32afe07f6ca86dcac164f4a25e48e33cb147ca4401","pub":"03d61b29c9f5775c6d8fddd6babb2b8e77b65fddcfc14b8c8f6db262285f2d1832","addr":"36c7ac440660d8a8642d669022d621ec1e877680"},{"mnemonic":"summer envelope tumble six bar crazy forget very canvas sign inquiry copy","master":"4c8765857e92661d69dd8f64031d43df4e1043c786f1ad7593d9d6cd7967b9eb","seed":"662aadea06a5198cb230ab83449dff0514b2addd644ff618647ca788cadae3872e19becd5e8de5719e3397783cda6ab0e1496e8a204d3ea8ad524ea93a1b71a2","priv":"a1d833122e4bbf53a23695915b9f398fc8681f72cb68644ac78f5b0ed0b0839a","pub":"03620a954c07b3e3060414ee499f68a904a8afe2f7f3ada8a9db2e039302a1ac0d","addr":"9758f18ede0279601ed2cbabdc5a87e0858c0f01"},{"mnemonic":"robot lift decade april style rapid thought modify tenant wild pottery cool","master":"d43dea8679ea3ac6440623974b253ec2355e97697557c8d62b5a79eefbac54a7","seed":"bc1a90f5410aa2fe22248c19110d3bba802378c5fdf2f3a2eb379c767b3d222fc2ed5d4638876d51fc9b44816c229673694b3f3e8052257f574ea50fd6d7a73b","priv":"fa29d04ce0480d48e6793e227e142330aca85e4e91ee9488396b1b2af13aa160","pub":"0342e19701eeb5ce20b17397457db9105c092d00db7250968ba38a551fb47d3491","addr":"c8ae52e691ce5b507a152f47970456570aa6635e"},{"mnemonic":"invite pool cross silent empty jazz change smooth appear snack cloud lawsuit","master":"0ab641828b6b935da8bfd58e4910c6c3fe8cff9d18548f86bdcf7d501875aab5","seed":"4aca0bb1ece15e686bb9f08a0796eee1830b9d926b0daec50aa9e280ea8eb522f546c1668cc2e2a8beab636eeeb992569a8a8b50e2082b5cb6bdf3195a2e8376","priv":"621bb83e46364ea7bb3a1942dd857213f49077ebfd735ef33095843e11866388","pub":"036a6b24125e8cbb887c0e9806e5feb6555f3ad4042460f1ed85e8a5738a02cd54","addr":"24f1dc90e9321c1faa33d3b2fe82665b402d4e47"},{"mnemonic":"current exit average case novel nuclear recall unaware decrease maple bind acquire","master":"a0a9d482c7bddfd3a8bedc54779098ccb0c54829e7949b52969a76f4a67f1ee4","seed":"35f2474be8f9068d91047c19ea9f1471aef87eb868804c5c205692944bdd1a3ac62ab71e052047961946d9c371da2039e89cfd77aef881d23774f10b24c3e16e","priv":"75684bde10654605f673ba3f704edbc2329997c9b15128b5640b6c4e3ca366af","pub":"038617759898bdb797d411a87d1e55024fde8a1a65c6bc0391a8deda099f6f7fb8","addr":"5785b3440fbc82cef8b1fb97c8f8e62a590b1842"},{"mnemonic":"tone engine property lion used spring enhance need choose grid deliver sister","master":"a0b23f0ebfd072c71a27b964ac5ac2a58fd31fbb1b22c044631fae01b27a425e","seed":"e47ac6612dade3bab1613b016b271eae20948c7934b08d8ba5ad0d14da1417b27512550287853c6c71efbf023b8026d015b063696d562850b991664ea8bc29fe","priv":"bd8279824526377e70a20ab1ea2731f815ac8975ec7ba5dca90d54859143f409","pub":"02dc15779fe271cc197da7035bb0886d2b44026292c137f6cfa8c98624665b383b","addr":"8271679fe371b6ecd1e989a2fb2d7c8d981006f4"},{"mnemonic":"nut solve indicate dolphin crush bike puzzle outer mask bring dutch city","master":"0aa08b93b1e497f4e54d6caaccc4769e921cbf9cc155a5b8877beafc43884c5e","seed":"c7c692ed2dba467ca28d1249f4d39a5c0405a54131245312d05597ef2aa31af3bc6791850693123f18cb1c350fd79c1705e53ffee10a501b82d0cb237d256579","priv":"8f9835b154157f65bed179b6008a352b7ef7d5ce8e21227a22c461294a7410c4","pub":"02da01e33c91da079a39cf256db26b1254e132b894abb9f07bf01118b5b6edf486","addr":"3ca1fa508b336a46f89231ad841a5a14d026f5c6"},{"mnemonic":"inmate snap bullet curtain used blast fatal one join owner route absurd","master":"e4003c062456105b608885d8928bbf183aeef12a48d6e3510dc7f183514a5195","seed":"0402d1974747f32f00e4cc90795f28d6e07a12cba21f31e22e0eb269ad1dc5fc0ad5d6ed1b5d5268dc50e31fe78b7145546de0cc1fe7afec7f5e3831863e21c3","priv":"8e55c05a82e8fcfafdba94b07dc54940cb247eebd1c689b51170f4ed10628a82","pub":"03637d8eb1c87329d9367ac73d1f65e482bd13b072d791f5fc6c08fdf262afdc8c","addr":"23d0d3d1abcb6ec683851d8c21a1ccf5941f18d4"},{"mnemonic":"useful panda fold short about copy hurdle vibrant kingdom draft suit cat","master":"9c99df0058969798ccdfef6b053f61af2b6422e4c691213f1f0a59f4792156b4","seed":"4fa3755fab5aee41e0771c00362701451ac578a9d7f8b139d9fdc043b33fe3566576a7942b904047978bf6a6360181187d9f20bb3475c495985e39ac7fcb8987","priv":"2b65da5f7070729879787dea803a4f50e2df1ae69c39263525bad0b5c994f86c","pub":"03a457cb29097644eb4a8eb1713fdea43d3992b2b88dfd41fbb417845e2d373ce5","addr":"901ed83b7220c552c69c43d661dd468ed94ac9c0"},{"mnemonic":"intact pluck author dish garden frozen speed grit bar narrow across loop","master":"548d4844add02811ea1b60ea7a6c337883e818ead83782a7b5a652ac038310c1","seed":"6b3b40cfaf38ae1ef9938c621264cd373b7e15d196bf9c69ed6efe3f7a7a13900b3c89eb915fbc99457347832ef1b816da26cbdaf8bc48c2b8a634fdd8be2346","priv":"eacaee29cf8bae543732278774ef2244e4da49dac3d88fe11fd7ff50875ffe8d","pub":"03d4d894053c398cb5dacd431a03c673a4f883781d951254fb398a24de018c6110","addr":"0b0840f26af38181ca7f65b7fdc0a3309c28fc4a"},{"mnemonic":"equip energy remove soft alter mammal valid van ordinary motor follow buyer","master":"6110f719e36e14190eb39d4ae66ab2b35bd5c3fd2969145fa3881650556c5384","seed":"74163bcc1522e148a87a95c78072359a600b364eeb558d052b722e5db26b6b317a36219edab7558cfdbdaa6d62c7b078c691fcdf2acc493139a75cbd26ea3bd6","priv":"fea286b716369fef22c1c5ea7da50ad612868d81c50f5efdcbc2891e21328a7a","pub":"0269bb65b5d86befde40cd916410790f9a959c2f3aa3beb5efea2eb358eb5047d1","addr":"9ea73e16006fd30dcdfe1ecbfd2792d5001ff8a6"},{"mnemonic":"limb boring random already marriage team useless polar impact equip rely sunset","master":"20c34a5ae5b9f78bf032d7841469e27002583c800d4aee849860d58213210c39","seed":"848bed01605f3574c16480514ca0cac72c21412fb6ec38833f97fb744e4a975fd06135c4761aad05d73280bf2e1c8297769e5cb69299bcd99e638e4dd542c52a","priv":"59f09a8926377ef066a13627f032d2e700795976230ff2e58806d046af0450c6","pub":"026e3e1e7ff239b39eb4a77477b32d492f99cf1f611558885afc7363f3173a8a28","addr":"61dffa0563d51aabb1e2e585bd444f99cad8d54b"},{"mnemonic":"vapor reflect friend jazz chronic supply awkward tongue venue finger island brass","master":"4dff50c5a87bb1f9d2c0392ee7eee59977bceda605a40c0a111ebb46587a0ab8","seed":"e6f70f78b981254b4e3061270fa96d262d2fccaf8dafd752db2d0fb54f943ca99f49eac07d279b5875432dd7c0450a7bbb776e8852e5a5a82886c65803ec1698","priv":"50273043958c3d7cab07f41dba28080c507f460ff920c6b5b135d1c64dc85469","pub":"03ef40a81e58c08d1bcde1116e9e748eacc38906cec057f2984fd4bc91081492ac","addr":"a8aba313467ada95795757ab9a6661395adbbd33"},{"mnemonic":"top base town abuse shiver symptom green thing vast eagle steak warfare","master":"7ae7456584c905376b6e6f6732b8890baf4d768e82dbde95110effd229dabf9b","seed":"f88b915dc5753ee33855b3adfd292bc56f04e8aaca117023209877ac8cda5df3218c969f1491bd0eceba11ac433016a05a9aa68d6bf3fa59b51a5cbb224c902e","priv":"ea68890e0209f3444eb78727cd3f13dca20c886e8bcd6d31689dbba04d000a30","pub":"02030607d8a2bd18f8af9b67f99db31585b7a879d6f08588aafbd18dd95d1cdb7f","addr":"fa202ccc3db92eb55d45cc79891bd4be395fe4f4"},{"mnemonic":"picnic seek ivory unusual text become room artefact rigid unhappy wall harbor","master":"05638878665f27362c8165adf4b73fcba3cedc983be2f0897a333378f53377cd","seed":"8af253d6d848e9737c8b7807d37558e5a1f09d3a14eaf5794c83c9d4f2021166aab7faacb967eee25714553003cbbe0c0eed9487d4499bca430e709f0b8d219a","priv":"1357da6886941f1c50a19bc3b32a174acccb21a0415dd5a736e5d679fe505f0c","pub":"0333d6d3cbce04e1ac26ffc7c2d4323110a038dc33ce293e95d2d34d11bc1d4efb","addr":"c5aca5f8318f75bc143edda3eb89821e751ce0e7"},{"mnemonic":"faith box profit long entry that alley stereo wife nurse tiny assume","master":"67457c024bde2135b9493124ed03d0f5f30a66530c958693f02e463982362395","seed":"4e22fc62d0a60e2de3ac33de2db8d4a884905ef84071b190f8d43f57040686eb3476fff7a90d19b1bec66d8a2e62532501ac7914585ee5272c352197ee0f0ead","priv":"ba198f97576c66c34196a36a04172bde332ea3c6777ba1af203b68aeae3e23d1","pub":"026aefd0f79219acbe5377bb3578a38f71174dcc9f77fa4d1dde3f3aff35ad2f10","addr":"44c4ffa77990259e15f2b9dc59223c5807c85f54"},{"mnemonic":"brother bar food vessel shine object tape acid opinion brand indicate local","master":"23338d7c853f4e76208d97bf0c47db2dc317cd4501cf00c037e60461eb373353","seed":"e32c6c54ca4fef48630e4dd7927634ff1d21c60fc488e6f1b87755d3e79f4845a3d9f86ddfcf185136150b52dc2f721b04f2d61913d63461956764487fec24bc","priv":"3d410ce752789e05c5e02ba5e95c2765f77208c90cf32f289306204f82d6eb77","pub":"02a795076f39164eacecc80ce04d63e5336edb32d183c06dd81f50e330b6102c11","addr":"b2c8079676ea7d98e10b24d9a09e3d4519d32d74"},{"mnemonic":"broom together virus run require inside output spray day hour cruel witness","master":"3ec636201f4b0a0fc7226003f1744766875a0f8a76e19d69c6c352d86c672cb1","seed":"51bbd8710577f0a2eedac3e341727d975b0e79e2a0777766d43b0cad8b66e302d1dfeda04a6a5ae0683db18955692aebc554c4bcaffb5f9be9f4db079a550f78","priv":"9063c803e2075922b916efc668be57b734212ca8ffeaca221b587912426af4b7","pub":"02b66afbfc48ab4d97a0965e7c96582d2c4cdcae965f8aef72ec98f59b31d5eb7f","addr":"b18bf07d9f82f070da34d8a4e58fd6cc4125d51e"},{"mnemonic":"crash knee output divide essence fiber benefit pig recycle patient strategy already","master":"eb84eae9a804895edbc89020995755aca54a04a4e7b59adb96b2ad0a8b465a7d","seed":"4aab7e57401b6f2dd6502dec26ef36e36d712ce328b5190d73b9055a118c5ead12dd5f18829affbb488a71f18cec672093d58452bba1ec3775739c1169901e67","priv":"0d0ebcf8cd5c075d9b8a2d2e404d44701fc1a5dabfc5b3cb50cae523f3c4c149","pub":"0296e9cf1cfe73a4114a1afae2f05a6a92da168113764431fa57c25afe32258d8e","addr":"8aadd8961827385dfdda784993f8f135a6678a47"},{"mnemonic":"shock assist horror regular voyage gadget cook pipe hair boost release stamp","master":"74b514c25d4fa22f3ac95aae2e58824da6ea181962c52944256a8b80cf86e980","seed":"0a13bbed1d4d3d6128d1eb0bcc0595a4c72701c7e9b79ee6110a104e10e20656dbbaf2993a7a06381e9ac424c3db6b0e98be6d5c2817433660256becf295c70a","priv":"75da3f78a45cfc4e9318d5dcaaf6595002ed037605ca196282dcfc18c5e6eef2","pub":"037187c0d2d573d9c28cebed9214ac37fe20c55ac56ba565fbbf7dd79c4eeea519","addr":"4b79f08bc7daf43ea00b5ad88b7642c31fdbdb17"},{"mnemonic":"monitor artwork plug dream sniff sketch oblige prefer dentist rice degree trip","master":"e8211a763f0b7f2f0085047ec1687f9c37910d27d8580696ae843872a7cae0d9","seed":"0a48851384b8dd7f8c99bfdaee23b143479e589bcced7ea423f6fc5bee68bd5e5c45834e3f2a7a1fcb928781e37e2b3078d683c15dbcbb5032ca31d3425dadf1","priv":"8fc0e10b570558eac1349ca8ef4f47b2f6d3f148a07b94bb2f1040dcb9bf21d2","pub":"0341374d25e701d963aaef0316ca0b4f4c15283f6b8b6932d954cdb7d7af4d7bd7","addr":"9a4cc3bcd48d6998280db5cfe856f7ed85d6b4df"},{"mnemonic":"bus deputy eye shell isolate judge nominee later gift mouse leave square","master":"cf814d6a08c10f4f771f670120b52cb26b6265a5510c5035d5bab583bb7f314d","seed":"9974e3131ea54805d6e9cc124ffedf80b0ebf935cd0908c4d8d7a3b777220155c056f12a7cf3c0c6e58b7adef792215cd471c080e9f11ab6cd4776ad86df9544","priv":"ef857601132267606922590b016b10faf2405f7ff92e3d8dd73ee6843f0b3707","pub":"0317f408e6be956b15a8e9706287e6bed905a008e8d4705b6c9b6e7f478bbc57e6","addr":"70cbfc88189721a264c3d21bd01f2eeee8a245bc"},{"mnemonic":"toe present claw afford agent render direct december model skirt tape soon","master":"88f5eca5b3519ed612f9f7b15ced098565559b85db98cc57979dde0ed818bde9","seed":"d776e445d7541e997584381b5d2eb066b99644275814961daf748a76a84898c21942f23837851d387f0fb6557a0f693d98e4d23214ed34630bd74fa808b36668","priv":"6252b6cd338753e5cb6745e7ce92bb661fdd373e56796722d1766def72b93ab6","pub":"03dc54c14b80e91502c400d6a97562975ae0f967ee0a7cc5618ac0330855ebc688","addr":"afdf4a2de468ee8b2d47de70d52ad9a3239b3f42"},{"mnemonic":"save rich wage off orchard unfold call frown idea jungle boat oxygen","master":"dfff9a17815e298cd92e9a2c5d4ccce14d3df12af9b9c69c4aac7bd297639ec3","seed":"7d25dec6c87f92e685124b901b0ad423ca3554c31db8583d205ec4beb3f42c4a14777ff4fccf830f5641ff4c376c772a8a1273060d58c22b95a51f9daa812a2b","priv":"5e962f6e9e6e9ed76b0f3e3174ec9639996027fb2bec3fb47faed79e66c4fd6a","pub":"020b08249515846a566c2c9616894ddd6c2239c58077ccb2f2e7ec5a8a140ef293","addr":"dbcecdea56d7e5da2a6c96c1f36242e87416f221"},{"mnemonic":"claw ketchup mistake lesson drill crunch unaware captain perfect spell endless manage","master":"bc0c9ff880973352267788cd2e1882dbdf5613a8460414df0e570a099321bcbe","seed":"4b9cc68aaff0b0ad24c531e990f9a9b7d7076dda27cc2f21e8e75bce8f65f2daf1ce6228130bd2c8900fc677313ed4cce1c47eecf24fea0c119f70ad6d3d79c2","priv":"e36db8076b37e0d3785c550e47ccc91462388c8249d160df13391ff06f40a30c","pub":"03895e970001fb0b3566d8abcb1a3df46725daf591e6cf981c1f06a81eb202692d","addr":"6548f7cd7b619dcc8685e59456ecddb223c0bc45"},{"mnemonic":"canvas black between chunk wolf resist again joke club moral fix spawn","master":"374f2b9727601f87f72b70014fc10a38c5fea6cedb36246103e0fde2d356f7ab","seed":"217881b165a67d70c9ed44d81a1100cc829f00a0b3782d8ccd8429806b883eea17f900ed32927a7c8fb8df34d75d5264cb5704208d3dc336444c199b9cd4bd1d","priv":"7e6c83d4d58e7a55e9882e6160238c6fffebeaa89e86dc9785fb1626fd22e8e8","pub":"02795b9337e8dbaebd288d1f0d833d51a4969b0ff995ace05c329fb6d20ad82425","addr":"7618cb9305c15c8ba122949bc298b3d6daa43ef1"},{"mnemonic":"dismiss rubber stadium badge enable exercise collect globe another survey own hope","master":"9da347a5c2a00a44e9bd39e50d80c106a9f885f8c84f5c4d90a0a75dfa5d5508","seed":"7038ff726fcba91488e5fec28d436e7a2e7c462b06747769f79b785aac64164eba1ea5c125e6196b9430139d9e21af8cfe10b51a09577ed510453487cc1f39f2","priv":"86b04f6848114854a1b207b44d9475c216e63a9b051c44bdb7be3eea9d24988d","pub":"02c6e822bfe6255d841eae33f62987f9cbeca84eb8dd1dd02b2daf9c7de7f36371","addr":"bd2a4f087a519a3469cbdaed704221385a07acab"},{"mnemonic":"dignity tired drift feature file salmon vivid wife faith title direct toy","master":"ee03e61a429a846453557f202766fcdd8a3b408c00f3430f7b3a1c9bd88a7d11","seed":"baaeb3a06b419a7a9c49a99e712c11e87a7a4bb34b26700b1d57e95177dc9b6b2d590878111e14f6050e73e5c72239a1562062d1b8e4c8ce9ac158aac282c2ad","priv":"d1dc95b42024dd0c10e8b5f0aed5e5f7c9ad0d56636da91bfa910d6af2124969","pub":"02e1f4ba20c8383bf512073e335400e1a1b1a103cce9450864b9087203dbc0e027","addr":"3de51323a7d40ab752f2b0cda1c17d51cc477369"},{"mnemonic":"legal sword liquid clarify utility depend romance cement trash whisper endless parent","master":"7c61e0c0e85873e8bdf532ec5906b8be283a002114b8dd4b8d0154054b6f40b2","seed":"21ca62d84191c141f6b9890627d6d216d5373ee0819e7c618e4027e70395c2a4ea5702aeee5b844a99eee4fedb85bce72f7d5f57c3d670308e1fa484108c4862","priv":"d6ad713c9dc2cff3e55243729c56485fa34ce8a75c4e011f40762ee000dfdcf4","pub":"026c7a44022f2892f2b2b091bc1488e547b8b52c82c2a780dd6603f40261930d3b","addr":"c6c4dcf4763d9908a46ddde925afd86bbffd4719"},{"mnemonic":"tragic inform salon lamp tree deliver sugar robot torch collect choose nurse","master":"77e88aef57f8be3507ce43c1e47dfb86ce0fded4a6d9a5ed6a2c6711a0a83216","seed":"6670f6815a2865591e6f9ff5c1cb775eed9fd45d53d1ff3f65937425c6bb79403862a398b28c7aca032fdfb14f96b238174cf6353776321631bfe338029ac148","priv":"7907a31525b26f89eace8cc0b988a08f8feff4914dd8f692e24199c4134c6fa9","pub":"031af666b3e8d5da1684fe5d585b8638fe46cff1b1fa01bfde3b2b8e2ef2aa3a58","addr":"792001d0cd191121043ef1434855b85b583ecb09"},{"mnemonic":"common oxygen toward security mixture swim elite issue suit welcome ripple online","master":"f4b85ed364ae42dd7453f56df2731c194a203cc06a8bbf71a2498424d7687631","seed":"9f2217e5ef1a8691aa51e914411a5ef5bf70727cfc7d0a932e1a9f7d298a657db8f2f6eeabe881e8f4f4580a2bf1834ae888cf7b3bd32820448007769b310724","priv":"2f98bb40d987f7e50966b15d2bfc89befc72bb6934aaaa2293dbd9bb33923268","pub":"03b89c51d6a32cdc56e334997a0bbd57deb010778d62024f5012ced0ae184e2464","addr":"2ecc6f88d71e3b1344a7fdbbbbe4fa60b5e539eb"},{"mnemonic":"kite warrior idea engine trouble swing route main like burden divide drive","master":"8317ec95801550a748f5215d6e83cb12424635d5b2f6635a78a4a0311cacc56c","seed":"f406f2ef34c3a4bb64622dfc4496a0b6183f1b7c1f58bd28d3ad863ccaffe171bd6164044ff5e940650a6bef6c290279b41d80336cbd9592c1a3b326314d44f9","priv":"4fc699bea9f32362f74b1cb6e445b1a8f3df81dbf1d5333dabcc84305c355e9a","pub":"02f8b8958f9edce19f8c5a50371dd079ec4b4ad6f6a9746451d4024ccd266829c2","addr":"8fc3062dd0b1063eecaccb75e14faf5b06cbb939"},{"mnemonic":"toast health connect merry resemble slim address pioneer crop orphan keep dune","master":"07ff519f3c3fd08b9de16a26197914867d4e42b67222c9ce863ac6b176bb5909","seed":"5e80b7b4b8b388522fc283784f368f5f7875ff7b412af6c3e526ec1426ad4164e0f4921494ff28a258787beade935d472cbad9f48386c2d7e16f8ca76fce769a","priv":"1158d4b986fa7e05db824694ce3379b63f473161c965a39ca997a8e3f3e7664e","pub":"02a3a7b75a8532df2afd58bd2dd434603c21a0aa4081f8ef9798db401372e32bbd","addr":"24c8f405da27ad41be7b0c62db63f80226fd6b58"},{"mnemonic":"cube shaft clever hard fuel review enhance short nose again banana profit","master":"30f3fe7efee7a0c7eea064bdb63f509182f0dba45780dcbebc5f3374d1b878f1","seed":"93774eb188a6ef898e534aaf67c2ec9aba02f716eabc0d193bd5a035ed8e0eebb2e82fd3ae30bcc24c44d697d46296e5d307060420350a4294f3cb639a48e6e3","priv":"857bcd096012a98022b2d30cb926757f0afa9465058c103b70fc931554f2d360","pub":"02ccbe787178d64d347a4f146facea95d2d01cf353ba04cf7cf7325fba6fad3824","addr":"d3dc220b0c09ac018fffe2cfffb220410af0c0b1"},{"mnemonic":"weather surface use rotate entire foil female carbon once kit seek athlete","master":"68614cd2df975347ef5c7efce4e416821a1f1916ac54ba994f6d69f8f2860576","seed":"478f798d52999208d3c8c0feffa78c6d56406d59800a701c996b8c8a9b193494aef1881e2d1f8aee0a5973b722fc3bb3ba007187a377a64b13a81d0560cb090c","priv":"6671cf2b354b61f6410500e26cbc94afe78392d3feecefbecd6e60c6b1a33a31","pub":"032afb4d170e89e8c89c544ebb404678bc6470d26bf68dfaa1c034edaa85a9bb5d","addr":"2bf3d54106897da2427b1c4c85de761e4546564e"},{"mnemonic":"car rubber ocean miracle vault brave goat eager dolphin various infant receive","master":"fa86484b17c9b62008647587f406f4daa107c6b95e708487778865c76a31e330","seed":"ff824d733d160e50a156021b256e4663f9ebebea1530358d70c205da5e7703d64ca4f3d941043787a68fdade5143d993376b1ddc9fd6037a13520e8cfedb790f","priv":"bad6b6ee0a3aa898466552b2e5df05bccd7d0861e3368f206d8cbfd2ec8e47ad","pub":"02ae2706cc6a96f31da9cd46d544ab142a26ebc6259e5e807065fccc251b26c603","addr":"a6ddada02b29a165a86a8bf4a01e783640e5638f"},{"mnemonic":"segment nothing burden boss obvious find kiss join science dinner clip wrong","master":"64a4c932d3cf62f9bcfe86c3b709ead38ada505e944322b93e14022c3ed26e18","seed":"71966dfe2434f4dcb2cd1bec9090ebd20bbeac2ed54dd8d081a548ce7eb57f1b17cee242581cc893292ff9ae4e5526bf9e11034688299753a6d0bab024ae9126","priv":"44ddd6571ce3582ae17ca9c74ed41811a760c7059dfa7ee88f9ef76960e30328","pub":"0288341429320e6e7cc35df266cf3929e93e843e911f8ae0ebb2634132de1a6f49","addr":"4f32c063b84f9895d4411ece5ba0c9d2e94631ed"},{"mnemonic":"cake volume physical initial phrase false pear poverty bonus steak rebel ketchup","master":"8200ce644e28680726ffeaa7d949e23feef136634b58d504e34cf8b2bbaea439","seed":"8f6577cfd936a64de1c2be553f66b8e5991e2cf30c42181c0f7eb527105c19221268e3268aa243f740733748dea3c0ac16320305c401aef7cd0986f3dc6ed978","priv":"ae37947a92ab4e9ab9b4e24b5f26f710725ecf848f0412b583b8701dce4b7730","pub":"02ba33804bdd8733fb5ae1ce1758ca55c8bd9e15245d646e8f737da2d61758ebf2","addr":"1f3833c0eefb3d46c693b0476470d97abf02a792"},{"mnemonic":"outer meadow velvet fetch claim forget token fee gadget alert post pelican","master":"a991420cafd20f348c847780fcc2128888771f4771cc6ea137099616c617b1e7","seed":"35cd93e8d9c4651799471d4cdf2a2fbf083088b93f1c1bce6ba4394ab6239d05c0bfbf8d7f8976be68042e1c8267dfa7ab3008c967f8d1ae0793190c77077fa0","priv":"e4fb166f29590fb4a5c5484729f038a62aba50fef189f1e3769fa290e1800790","pub":"02e123798016f5eb1f79f633588051def8b59c27fd3973a7f2012db1a8fa508ad1","addr":"45a62d3353b39439d002c307c8789ac70adb69ba"},{"mnemonic":"flip expect rule wrap cousin fade example ugly crowd monitor cattle cable","master":"d5c2521cf1c8f3dbbf955477a993552cf7f6f0ce452bb789806daa0a4dcf192a","seed":"b08a8f7dde39c9680c07ec31ffe80377ea915de328fd38b81525e4f694ef0ceb630e7ccc19bd28a03b7061b194f2b7758f802945a7e556d526f25bf2b4d5fb90","priv":"21a41b9d3ca21569e3b8638188633a7be8e9b54397964a65bfeabc3425d5e4bb","pub":"03cacee92e7116a6012c2b3002fe67d00dd062e937393895703e010d5ada98b4cd","addr":"b3a4f2cdb4cdcb64f1434f3f1e4c20bb8b952116"},{"mnemonic":"alone absent senior wisdom sheriff siege harvest coast van skull want quick","master":"74109213fcb3350c4ebe081116bc7570d00bf49cc7cbb90cf3b09f5d532a3d97","seed":"7d111179778ce63cc39879ae303814acc25afca8eff930d3ddfdc640d7b3d8c1140429a75c6db52db96564aba0bf0c8d9e4cf78fcfd703c1d219c09a70d8569b","priv":"96c3356e90906a9b3c523a3ba61d66ec63d9bad5ccd23edf923e3c5e4c995774","pub":"021736b932aa1eb90716bd8bcf3cffaae73392a37ec114b34628367f8ecf1b35b7","addr":"e8951735e9840492e0589a885968f12b044067de"},{"mnemonic":"fall any bamboo energy ripple flag rich arctic argue decline auto pottery","master":"4b3fa55e01aec7bc6d41a890d8aae2d69e617bab49f8529beb38aaf835d15a69","seed":"aea9842051221d0eced61932fd18a5f3e1ed8479159c40d16e886699a0f923807b91df0763a5d9869fe9a159ae0453f8d651302a186bea4ffc120c2902012d3e","priv":"ca5c56fd1b4e7e7bf623032e17a186e20b22fdd49a4d29d9bed5edff206bf26f","pub":"03a8fd0ffee636d66a64cdcc6032214efd1c069491085053808d03c1ae83b9fe96","addr":"ced9d32eea230544e0f8095b39b0a4e18b59937f"},{"mnemonic":"over exhibit wait carpet pencil record post duck gossip vocal all wife","master":"6fbad4c20428a892a365ee50dc66f8eca7773dbc5ecc34f85619fbf1a73822b7","seed":"f998a57ed4eab4d8425d4a71bb1fa451d7a79c8dcad33e18f90d6a4506f93b2adffbf3eb887adda7669c0108e444548a3566306264a76dd4b0955af27cb9dfda","priv":"bdfaebff9d0fc673539d8be5e59907647d0050a9241dcc4aa24c5c26eda0fa60","pub":"02d32a22a05926844a6b0f2f677520bda4c54e6b2c9269ac91127b626159a9dde9","addr":"60862548d4e283f62ff8aeabec3f25891808a439"},{"mnemonic":"spell illness engine habit bike able chimney spoil know nice tunnel weekend","master":"ac366b29da09441f12742ab837cab2a4636e1b50f11680c4e1adb7d337dfd8da","seed":"59e69d46ac9f2a9edd9b1909b1e5ad4b9fd2b401d48e95eb43a0f4f2bec0e6c60bd2a263e58bec77dac6f6ba45db1345cf9d74593c6e0b5ebe3fdc7c5f24014b","priv":"05d077b8eb1163a1fe2e5eb3729ffc7c1327435d4ac48db86c6db5238d5af45a","pub":"0364973fff68be7b91de7858fb35869decac0273ccadd7ccb45b057ad7d7e9baa7","addr":"c59c857a493b2b81957f4769dd9b7b5a934acfc4"},{"mnemonic":"thunder fabric basket stumble file sudden effort congress process essay excuse practice","master":"6c3de9715b71139a3a352a1d0b272aa0152402db4b8429c32654755430623ec5","seed":"eb8d579bad88d416336e6ed882bd8a57474cc5ba30d4a20e426c29a78bcb27255f6a6cb50b6430fcf905111f9b9fe4e3d4920d563887dbba69ec74856ce4b79e","priv":"a38f2fdb79ac8a1d64f613dfb3cad99c9f06554cb05f39b6f60c52eb7ad888d4","pub":"03d548248b4afab15ed5e91699d6e13fc4401d6779ce97b3bbc833c690302d0049","addr":"fd60d97532ce397f4ae9accfa99ac5ed9f5a77d7"},{"mnemonic":"twenty fan benefit benefit life orange crystal matter index drip mobile matter","master":"08a9533038e137f0149a965d12c1c90d7f6846107dd626027164146406c86fc1","seed":"d3f6d9f156c814e0f77fb7e9aba06ac2c9c3ee171b2d0759e2d91fb5d383f862aee8b7dff8c62cf61286d8f7f374ce3aeae7ab36d551f802523dbeb80673e0f3","priv":"08bd659717169756d9d66e79aa2b51d2b539f5c453ac8abadcfce3d29df49e7a","pub":"02e3885a7d4343012cc76314876fe67729e434202a28525bf69ce27a9167a46385","addr":"f3181c18f63bd74c4ddb37a4c32d0985e0af010f"},{"mnemonic":"scissors foil oven finish exercise typical catch dentist lens dolphin flag warfare","master":"9db47325d363c87e509aa52701131ad236317ea04515f4e24ba4f87cf99b2327","seed":"0246e8cd14b6b8f01d35aac9c09f8e526bf9f05393c5e1e77ddec53477275dbef74add79ebeeca7d081e58272f4a1bf1fa8621894a8165dbc681b967d84ed10a","priv":"6e7e4b51346f8d1997d81f63dbb7fc7bf4f022bb3b5ccda9e5d84c4a5c97849c","pub":"029edfb5c989c002795c283f445ef4d673101736c25617500f8fe655e043ab55ed","addr":"2a98038648503b442fd77f4d05a338da2062cc69"},{"mnemonic":"monitor vehicle bench chaos stable cereal acquire shock image purchase sadness hundred","master":"bf5d7680d5ad260a89229451e6ebcf3c45988a83df6740fff9b557eb3afec827","seed":"5bec19e9219360a8de56fa85d593f5330ddb158205d25d00d8a2307f6b420f11916311e104dcadacb638f5434e98efc8551d768586a0d8d9baf2ceb0759ffa98","priv":"470256a6d68f8de27b0aba26684cea4c075f384bcdf8a68bf5418dee37f08dbf","pub":"03a1193ff722ba3b4bf7d257aca5c184fc776540fb139dd9a404d3743d31030971","addr":"5b4796167bc701e5182f16e2119d7e9d491881fb"},{"mnemonic":"never dentist blame parent sell income parent bullet eternal random seven urge","master":"665961de4995f001085ce2f1058422bfe5ba0132cfc5725f0c5c9d827020663c","seed":"79a95f522e50cb551c7fa70d54c0aafa5b794512be4e91de2fe1a2e9c17d76bd55087621a606107f3fb19486f15dffec5947cf16405304914f511dc43844ce97","priv":"88db51c0d63c95730fad0c616e4d4fde5a631dc3d315fc74db688ea1a7ceb5b5","pub":"020ebca88011035818999fdf69ccbf691d93cbb6bda65c68c0f2ca10757d23abe2","addr":"9de8cf2beaffcd389ea6dcd264444aae075a1590"},{"mnemonic":"noble shallow label region age proof remind panda useful session poverty open","master":"a8e1a3cf36520d5ae852890951b03cef3902f9ca168cf53c4ec6289dd802ad8f","seed":"0cf4cdddf1605c5c895c1b81fd523ee83239d42feb4a130105c2d5d1fa371e00cf34030cf02ef51aa53596253e264da2c3ec220b97885202dd73a7b5824b982d","priv":"5ddfdf68cf41919145c9c8624c245ce9d6d8c380f5d0153b6155e92b253b1b22","pub":"037943f2b34206bfcfc1fe236c77f6e844d98cef04671431a12883e23846e8e7a7","addr":"559839fa53e5b7408f3dbd00ae5e80f56042417e"},{"mnemonic":"hope inherit quantum text sadness dizzy glimpse cheap expand legend kiss once","master":"c307e0a3f22db3e59a7b28b931c1ba0daa0a8e8d743660c48b6babb4b9563702","seed":"6fa72118b297f2bcefab29f19ad4b701791f72cad287681e2af3e92595ec6b9f7a15b08771917d1754053d1e74aa1a254fc3d6e27deb78b7b55f35a5154964e0","priv":"1a6b9948bf4b717756a11e43847be38ae87b0f42d718dcfbded3bca1a8852aa8","pub":"02dc42929ebaebe447d089cc702bd8e29457a2619047a1d7c80cc4f2639a82246d","addr":"bdd0fc12beaef99e0ee5b07c9c2f41bd90163bf6"},{"mnemonic":"smile odor upgrade deer mistake bomb friend ability then segment orient nerve","master":"17c87ed5d20e5089408ac7fa68024124053d46bfe32fc04ba06801c45b6e19e7","seed":"f620d852a56ab0eb7d55d271034b767eded17ed740ada7f8330fe6d9affd8d88e44489de06d6d3f7b84b294a847334ea051ca63f0be4742667ccffc79031b5d7","priv":"8f90608bd45f866e9fad2a6a316fed6bb6342815ed79c967c3eb1be727ab8aee","pub":"03b6b746569b0ce4b97c3035634a2b30a519ec23a78402137c7ec395d35c4eedeb","addr":"179277829c7cabca8286a52ce3cb591ab22fc72d"},{"mnemonic":"black ghost quit birth dial helmet custom brain diamond rally local season","master":"8a6f8c836e3e83ba6ed94a9de24e1133d4b04fc436827d810c23ee1ec9406fa4","seed":"6488a47cd4123eddce9bd31a0982eb0ce8208ed5e331081dc18256dc8b5a1718807bfa267ae6a75bf1601b99c784542c3d981a9350f7f268d2666af3bb8e3680","priv":"1e7100a43845319b4bad268d111eb3746f09c9a005e023c45fd1da984d37e49f","pub":"035ed8c0324e4956ef2fd2b5141260cb6dbc0943708b0f83c0bca0e7297a27daa4","addr":"d2d9e9b6ea946a61082fe98d9b0a808f5f0879e7"},{"mnemonic":"advice uncle change position drastic leopard praise rack match toward paper faculty","master":"9583a2771931234cdf27fc8a96d06766d4c76b4bd25247596639dd21da4c95f2","seed":"8fa5760f5f2d36734e05cedd78260e9ec7f837bf5b7edeeaa8f4f3ecab9a1f82ca557fa8d75d7d779e47a29eb7c974264d98d12fe7af6a22a87a70bf0031cecf","priv":"3a69d90701054f78204f1d3c959f128dbfaecf4ff0cf6c29fe5ada13c96186eb","pub":"038241211180ec347d2459f2c22c01b50fcafd8ec1ebb51b4ba648fe291bd71104","addr":"f9c6730eeb7a00027b3deb720d6c541bc6b0aa89"},{"mnemonic":"carry enter invite orphan file grain pact glance ahead grace action mistake","master":"b6b8bb3d43f27c84f1e3fb1ea462c9a88d8544b18b22d9b9c13379954a3546bb","seed":"a0078d2fa9187ecae2b8ad3d4121e2567695c1cf26bcd441536ce95a6e04b4feb41c1ceacb86ae9ea26db4eeeefaac7e0477eab711b22d5390be3eb3daaf97b3","priv":"7503c22dd0cad622d4337dbd7e0bea66a2e8b52427cbda01a9c5959ebe8b5a73","pub":"032c577bb5610ae703c54444865932db4edef3b8c84f88c71a25731a85515eb69b","addr":"f268151a05642b378f8738ec00b2e486e60e284e"},{"mnemonic":"taxi betray parent equip margin snack spell agent talk possible portion lunar","master":"5bba6a340254e9803fb2889beb84d4bc63454beaba3f10cb992d5823b23472cd","seed":"a8b970f56b960fb9888f03013542e90b547f7d60aa91218105808e595a561ed37c13f259692d3dea5d324d0c4142b30e39cdc2e60697ddb5f52a5459469fb31d","priv":"ae63f7802417743bb8bca410ec64380a407373900e0af51e6acd65ec9d54a0f4","pub":"027410f719925fc55875ccb78092d5e6c31b8543e115ff39bdfb9a26f97fca8859","addr":"da9b8ea1879e13bb49e7b9d179e5b56cf6de6537"},{"mnemonic":"sheriff marble regret shrug shoot tornado coast that obscure sense duck noise","master":"e97a0a9cfbcc28b909f7a5a617af10289965c6901fb06af76a6fada22e41876c","seed":"7a231c5b3b91408a19de9571bcd820f17451562063ad2daa85a1164a952aeaf8d6a3c703909a76aa1e1a2818f8fc36d8dee3c87184b59d6340201402384fb7d3","priv":"d3fbcac181c592367cc527d8f09b54e1a31d3b2c3fb5c1cf4f2ea897c483f5a7","pub":"02b3e3765ad7c3c020c6a166b0113b87279e66a53859ccbb9d214181e2be30ca01","addr":"517212232acd318b376fcface8544506a8f76c18"},{"mnemonic":"connect drum once first trip dust trigger duty situate burger toilet half","master":"073fb31a2785afedaea95e67ac7a3219f2f910aa01b054022a5185c5ac99c35d","seed":"fe3d1ba2740ca127dfc5bc22ab6fdbcc930b957185a0b16b1919e4fd5e637c053b3d356b12152cda6d07f7088f16195319075d0b3533e5082b45f1bbdb7d5a74","priv":"6a19f33e357328d40aeaab5323764bf9e12df8b476100baee9d398a0fdbe3970","pub":"03f639ddf3dae4ec84bdbda49149d2fc3461b2309d043c89eea46bd99762b54a0d","addr":"c8a8a454a5aad713670e936b63c519c843874b3f"},{"mnemonic":"shock later journey twelve any ripple soup climb globe impact poem auto","master":"382a7bfaaf7df9ac5cf8ad1f574bcfdb98e185847a92cc36d272b74a14228259","seed":"aa3bbf8521133a0fba514e54147daa2c6fe294b1af8bee3a6fe46ecd480983d72635520db97bc3631d9bdd55787b07e45d81b052522fb7330f4e0f6aa24fca8c","priv":"dabfdd6c702d104e4c17dfea719ed870c783dfbcc66e8987bccee888658bff76","pub":"02efcce52d6c7ae70900d892e1b24ed5af6012c38c15864f2d15067457a2c55f2d","addr":"fb3af390f0137dcf7d98e2630021061d0fbc9e06"},{"mnemonic":"news book language depend fine fabric idle curious depend plate fold sustain","master":"4c28a9f9d854290f4655fde6a91500dacb684417d8dcaa69435e1ab4b8f04e3c","seed":"2839463d79148eacc1d367f9ed0a2ab8ad939643f439c276bb47f0fbdb4cfe8795001ea2e5c24a6a6da9d35cc6759c37e50ce49f34498ea61a74dd11b14a6421","priv":"d6ec69e742e0146c9811de01cfcb07b3de56594fd4e374722ccf81dd143e9a12","pub":"020f5c54b785c5ca65547b2ba32138a47b8b5b462b304e0cd3ef981b407ee73b87","addr":"2850f467f64992626b23e03d366f34f4e6760807"},{"mnemonic":"equal energy inquiry frequent aim wide exotic tail vintage toy marble spice","master":"0fae6d570fbeb343eaad5bcd272d8554fe27a9cde389685263ca1020e65d4a1c","seed":"62aa467a7dd73249fcad8432d188e64a1d0f1591c66912f906eed133ca0c1e99eb068dbcc8ec37947cc846b1ad4f439821324c61bbb385fd91b2e440d6a86e41","priv":"1a254e7f18b0836975e187a72d0cf1d1b69225067167f44dad6aaed6065e60ea","pub":"02ce2f7840d3f69580538517852dfcb2932285caaab4d11adb98ccf335430fa50c","addr":"53117f2a5d41d6e727db2975c9dabb1d28708d19"},{"mnemonic":"recipe prize resource define enact basic glimpse chalk box prison approve fossil","master":"ee8a619974bcf5cfa95af842bb003ce4f5236abac96eacd51ec8f797bed520a8","seed":"b2d4c119da7c72c24542998b036b2e1c501b0fb990154d1b5abba4c5ab9233c4caf1a427948faa62aa862002f43d115f2e4d715b8c9ea3eb662b2514ea06390e","priv":"0d896d53aeb3f2fbe634ed280225bdbfd10116e18651b3c801a3cbebb0f75ed8","pub":"0320fd7d4c9c548c28d08e587f45836902f14c7380cfc9f8119e0b6e36089369d6","addr":"949025151f752888794030aa47854ff5ee407e09"},{"mnemonic":"hunt carbon lady smile luxury old empower pretty memory gentle public pottery","master":"e9542dc3733e40f7c1e5f540e241dde57a09f76d28e889f69dba48d63f0b6445","seed":"ee0dcfd61e0fe95e1e0428f29c78076f302cc5a55db61c13f9e6d84811bb0d57ba3dc109d4d98fc30c1d2e5b25bab1c646623fbb00e5b3719e4bfc58005fcea9","priv":"e846c35be2eb1e3781e8078d8433a9816d8f8701131e69873290689940617de9","pub":"03aed0cae3a1054d184c820d9dcd5118630febfc450d4972b4963e56de2b1005ca","addr":"af41527e26ef2ed7e1692f2897fc48bbf792c8e6"},{"mnemonic":"captain disagree filter crane chef cousin one cherry able scout tip magic","master":"bf4a3d4839793f7d502e24a4ef4e99bb39fb2aaebc53149eb004ffaca0256af7","seed":"3fbd2b4e5c614a29cfe82ff906e94be976849cfffc6831d67fc47bf2dea68ca06fea30de70ea546adebad96d3fa106950545350e0925425f22a0ba1a0abfa3d7","priv":"046eff73ff79adecbc208e64dd7bfdca16c4593a1780261377ee48e44ea06d57","pub":"0374f44a020872df00e0101f61fb61e76038f6fa8a7d50a89757db14b2c95b76f1","addr":"130a585f378df286341fa93925eb5d630adda295"},{"mnemonic":"inform measure recipe evoke make recall volcano girl obtain flash soap prison","master":"3bcbc5c191d8f5fd59988894fb749ec333a07e909b3c22108500fe08cf7edb53","seed":"cedd1141a4c9a1e349435e247349994c909811dee5770ba3642768518cdebbe7d7e5ab0776af835bcee0913fa1bb4b72205e9d38b637196a624f031238bd2bf6","priv":"9c070a30d5ad6301d73ece1e6e71790327c6922521f93d6e8b7c69391a12d37c","pub":"036ebf4e4d5349613dd3c7375703a1025896ec4377a9635e9ddea2a2dc1e7bef22","addr":"74a413291b799fc2866fc7c7ed2d2becee9f15be"},{"mnemonic":"carpet poem piece silent boost trim famous coin fish rule leader oil","master":"ab7b210126590431eb1c09ead09bef99b689a429cd86be65681debd5deeb1ef4","seed":"133b317aa1f56e79697425b4c94aa52d5b7a95c3fa5ab6d437bb1b310bae6baafdc91ebd812c76b721fb45835f3ef0f61730320a8ca6e7cc18291b84af5ed68c","priv":"1863a0b1d15847102e3198549a59921488a67002e38af1cce7ab2c0e055eb498","pub":"03dfd8ee8642ccb78642d0e373ce9b15ce9384d12b36086d2c64601ae8d18325d5","addr":"b70aef2f2dd6e42f909a5840a6cc7e08fffff26a"},{"mnemonic":"liar hold orphan include gravity nothing erosion offer average now ability purity","master":"71b19fdcc0d8e082eea3d92a5e6d36512273095251da9177b7cbd0bc2e5843d9","seed":"e58ade95c1063890ab5296e5d8a07e20ac80a159afeb88c74dcc6bfa8fcff6c85a2f19af8404d3e457492c560e4f04becb6446e290ec1a376564be64ce1c7ec4","priv":"2bdde1157be2917e98549af370aedc6a98fc5d6df99db71650ef29407512912f","pub":"020a188651de8022da9d74bd298d324c54c88e35268eca0907a5f6366f9ceb3287","addr":"9c4c3c19a81d424ffd69bd29802ff155f52e219a"},{"mnemonic":"crisp security increase topple put engine wheel apology north tent front minimum","master":"77288b3b65bd31029a3791d357521172af895f1085c1996668a1a689f4473a93","seed":"af74884da27f1ce251a75244ac945052c4df5fbb59e3b12eaea5e28c8fc26b8ec95bdccbdf5481eba4b74680e642e5e7ab2b0f6a4d0eb41db3c08c01162520ca","priv":"4d1df90eb70f94aede9dc63cd951a30730364379bf9a0f339d59d5970095eb65","pub":"023f2f6cf79a65e2d25fbff8c422ff519603c2e400c5d3b6523a6db06b969c071e","addr":"42bc49b12a7eaf46695fb1ed32db0d32e8e661b9"},{"mnemonic":"switch shy kid child occur salt cage local top blade cheese width","master":"5755daab29ff030dc4b255171f77523530a659fdd70bb5fddb69d150d4e7e1f3","seed":"dab58ef3ea14f3041588a5411f22cd426ead10057616df799cf53907536819056a21faced7e56aacd120181734640821c082daa86fa8ea4b39ddc40b5bc02aad","priv":"e5c1ebc0e3428c9ca42dfe809495dcf7ce2abf2b149664031b5f5a9d5d2f8b4c","pub":"03fc64577364f254c6f919e1a9262740987217fa2c66ea490ee6d3dca1787114f5","addr":"1b83078e35972e3ce3b1bb062b3924665a6e5c5d"},{"mnemonic":"rival notable exhaust climb disorder enemy desk owner again twelve mystery devote","master":"5daf52423aaf7b7ac4d8ff4bad65d81f7e3b15021222d3d9ec788a2d35d074aa","seed":"709afe1cde759d12cdf4fc3a68793b35490cf0261397754a62dd5d40fe528424e8deef620f89337dbab01bf57cf241a6664bb3696bd76c886c57a405170a7b74","priv":"b171a7ea63d6e1b8aeffbb63ce5179edc656e17eaf85609ab0d2680e35a3d64b","pub":"02cffc5dff2f9896d995c9f9b6d11c1cab3e0d40a25dfb9da5aa010b703c80be0d","addr":"cc673e6d2578bda7d7054d2d53b841c26e15dec4"},{"mnemonic":"defy prison walk thrive enforce match turtle venture margin quote must cute","master":"9d747975a6889f2bab69fecae39db2a10df1545ae418596d97152de0e7cce077","seed":"183b5f3d963036b0e22eca9717769422bc515977c0a7fab66d716318de12d41a01f5ce101bb47ce44501f0908f8c1255f8c3078fd2c2084aac32624c20647806","priv":"a871082f9cd061e39987c76e516a7086f82eedc06a20081161e13dcada541f61","pub":"02726bfeeefc2d5ef521c3800ebc7700e11aba3cec88f8be5c9cf3275f4ab254ab","addr":"6d793f4478d2e4980a140b724cc8012b44097446"},{"mnemonic":"lyrics goose draw review manage recall snow lucky mirror swear fish rhythm","master":"b69e9a8960d5cf2b8f457e6a037654bcc72ec1d26e4753ad34512a877cc329af","seed":"47054d3ca54f6038ae500dd6a7f8b5fa3265e87b384c16a4e68560f56dc9f7945d599d6a71b2020618c9f7bab46bc6817062751f19b46c2e05eab7831fda1cb8","priv":"5c0efe877506f2f46bf345c71c8dc31239f9e23a543193d5ac894faf0aea9ddb","pub":"022b90c4806ce022e81c706555ba3cf9597861a3d7e28b9aef6bdf36211eba916f","addr":"a3ebb9a579f22150fd9b7cf62a5f52369fce28f1"},{"mnemonic":"coach silk assist potato gesture hire bullet piece document outdoor husband panda","master":"541e3f3e4e4e9803da42f2264efdce5b9338d410b16b0e7b66611e5dec5bf896","seed":"4368a638c45b7ba4d2f1953eac650631f1a1e3c23c72b545dafe466fcda597a0b97dc3302072e50a298989f94ea255290d3963ada9e42e064ae300173531f273","priv":"b9462f51e3c20b3d805b54adc6b27c669ba07d5a5c97edb0a8cc6199d772097f","pub":"02dc7826d790d013e76765b03447d2dc92a945268e42611c51080b7ae207906bcd","addr":"e59101c16f77cdba771eaac3ecf416232f6dd1cd"},{"mnemonic":"wet problem raven barrel explain long call civil pact swear luxury expire","master":"1e2704a2365215a83dda9aefb1093e095c0c06623f060c2741e8bcb8480c4165","seed":"fd81b59cb8a4abf789c2fd55e2d9366051f8f64f54a3e08d117d344b633f2ffd63c1a6bce7a4bcbb01261b6e41f6330ac5d0b151c36649ad59c0cca7e4b3a820","priv":"bf9f0440cd63148ea0771d0f892efd3cc0638330c428a50436fd048aeedd7ee3","pub":"03d807ec07f4f6eb00f9e3ec69dadafb3201cdca3e878367ce4245af65b8e4490a","addr":"e43aabb2d20275ff60d591dae8d83b938a0138c7"},{"mnemonic":"unique mobile gospel cost genius symbol online rack round canyon front again","master":"ff441298736365bf07856cae35a9dfc2612a9d015592d5326980225c4d4e4e21","seed":"e05899b5a5a94c860cca584b6065284e961625486b1ce1c80340721fe4f89fac7afb7b665464de68b5c5813e48896210a90d44eaf013ec4fa90ace43e3153d3e","priv":"45513cc23e8ad7f7b5932988637cd6aa85f19a481cdd20c220f0407afc69c688","pub":"036080589a5268143509bba4c4f26ae8a3ad7b12ef7295c9ef416cff53b66b39a7","addr":"68456ee838f224959e5c29649f41eed02b56c3a3"},{"mnemonic":"street bleak prison artefact pupil armed blouse pipe eye brother man aim","master":"6e0891146585834da8d83d0e221c88d53770f3c56f68429565d011ac697238aa","seed":"8af79a74ad501d308be613981a1a25342791288f14f05b7cf3b81131ba2146ea63e01ccfd150c4d2bfc42d64adc899158383d82f3bed0eb772851fdab4f901c7","priv":"86c09e2544c86b883e8de233ee297fa704c39bba463e5a8742c4fefc9ebc109c","pub":"03d8cd38cd2311a0360c84cecc58787fa3916c6c2adb5b2baf12a880549a572f7a","addr":"68c1770edaf76cabcf93c6d94f4510162fd36924"},{"mnemonic":"love wear kidney math magnet share mango also dial fabric near destroy","master":"e500e6d3a103eb11414e5ebc9e27eb96456c48e9567155c6250aeb83920df860","seed":"704e740c6f437a9e8b7e8d7e2321ce81d9132c9a6df7a45fdda99cc66a09c9d73350305aceabc0fcbb589bf44911917be71e9f399c401f86246d0aebd4b467f3","priv":"07c906988f937dc841918a7c3092f5df0cc0a6ce4487631774cf3f703e9c2713","pub":"02d131982bdf285fe3a37370ae0175438094cfe3d6fda273bf24320008fbdeb5cd","addr":"df31d832d2d23502cd0198c5947e8297e6f73eff"},{"mnemonic":"nominee connect useless dutch double vehicle rocket exist mango floor educate absurd","master":"0a66acfa6ac891a588255bef6fb1a845f2756ff0a7dee8d2ff33a19a7b22f18f","seed":"4c4e362fbf0dee5928b21652552815edf27a4ba5a11a09dfd83f3b53a44cdcb6acff4c39b16d2cb9ea3250af3743baddbf6ce90ce1e492fc6bb53f79d646a4ea","priv":"e81668360f562929af7e40c5970bc685ef5aaa7d390c1bbe005b028460c79ff9","pub":"020a16c5a1098493bf1f7242de71bed03779c4eab8f35a1c6859035111514284d7","addr":"c8a841f39aced64bbdebf2f8f834ee02ca33a8a1"},{"mnemonic":"sweet leopard loyal problem pupil perfect power flock thumb wage person secret","master":"6fb555e482a1987c2c0f129ffc040fab9c4eeaa3c23a3370db7b4a5ebfd2cdd1","seed":"b20837f8580aebb15a7a4b035639bc04e27bf33e1f600069ba1378a5dfdeff3e95545e6828f339dfc30eaa449c78b046c21fd99b24d819c735e050f6992f898e","priv":"9d06cb0fa2cd01675e038897a14e6b7719ae84ca6002ed6620a557877ec373ee","pub":"03f49f50e673851d74da1fe24aaaeb75c2cedd25116c003fb4a810025192c3186c","addr":"7f61e30a20df85042cfcda5163867bea46b98702"},{"mnemonic":"slender tilt tell faint dumb seminar cycle tongue bundle case swamp author","master":"444b57e7f846dadf73a0bf77fe918e8716454416501c84a48bd78dacfa87b885","seed":"4345b114d1f3a78c5582ec5469430a8cde3a1a866e64b3c3606b84f62ff48bbff48826cee928374a01aac080b79269f89751a11aa086fc1fcfe74cf05674ee04","priv":"7c6d51ee5199457807c66f22e8d9b7a703a4e61a84cc791efc3cdf5f7038d28a","pub":"028b09c16923224208b6ea2ed777a2e4aa2bca5674eb8f0021e9bfc4e9d3fa0a69","addr":"2486b9fb36e8849e09b147749e445fb515591197"},{"mnemonic":"alone oak satoshi diary artefact virus muffin quarter identify car whisper topic","master":"b4c37472c7fec6dc3f3452d4aaa7c306cb65ff940052b0aed224c12104296648","seed":"4dca6ca310d5028c4cff946edda516d55c7de81309109e6e3586927a8fc2c4095215ce471774df2795f04fa01cc2cc528c44a5968320ede4016d68c24e4bbacd","priv":"fde405fb9a8f0e98feed3f4e996b3fb90193800c571a89a2c681c0fb4917afc0","pub":"034bbb553a8525daf361bf0c831c756a56ec476c0c9a52b0c74dd9eef35177a776","addr":"c890e1e83daa169e0295ff2844edc5ca2a7ff346"},{"mnemonic":"noodle hour inquiry know sort review oxygen observe exotic script mimic march","master":"3be52af1a8430ba7c4610dd4bb1ad67d978d40ff7530d712cb5728bc961edd3c","seed":"e803e685c85a1a0a4a382d1358f5fecdb8821564545d8573f3708a01f0f0bc1da54544ca2338cb988e7d6239d18c32bedd38e1cb9bdf1bbb6dc8cbb323055510","priv":"defabd99910867339a4af3a425caaffad76ccd47a43b05a13ad86f3d23887b03","pub":"02609b9ff36c966dff6399576fec7efa83cf0fdb66bade72334ce2ba69161768b7","addr":"abef04d453ccc6d443cd60d6f964d008eb5f08e4"},{"mnemonic":"crumble loan economy dragon vague library slush ticket flip mixed accuse switch","master":"f085484747a4bf869f38da6e6f56b9ed2be60b137536a2333f2c6818d76fcc68","seed":"b0ed9b4d75a17a53b33a73223fb158d79999548d13919599ae7eb71cfe2fcfc06cedc8f94cdcdfb05ea043069c426d2b78e2f67260644109c42a6d9b3f7d5134","priv":"a64c537c561fc49e504e870eb3608e69afdb2cee4c6f177c63fd1ce170a67192","pub":"034f7f99f2699604d3f9869dacf1e6ddb387bce4e0d13fce3f4aa85713c7976048","addr":"4b51a7f925c0e1b428b1ec75dafcb0e4d9852620"},{"mnemonic":"rifle swing confirm response name void scan shoulder lake oxygen uncle south","master":"3560f172b5c2ad665da648cf0809604522eeff5fbb2b1e0ec50e7197bf711dac","seed":"85386f49048f371171ac3ed2bb4f358b7e22ae406a7f2c9b3f494f2f7eade96f2b6f96fe48bff1754894b8b2586013393f0b9f0365c6996cd251e668ee90071b","priv":"c79860b8ae43fa4dfc570b2d20549b457ebc6e18d38865ec9cb1ba571409bf12","pub":"0253d92439ae131722981eb16924b26fe01421e4222152cfd0505744278f963dec","addr":"ace153f8d13e8cee51a2c08fba9f445f50e818c2"},{"mnemonic":"air floor random smile mechanic exile run auction avoid truck expect old","master":"a7cf0d4043dccdf5cdc835419f5bf2665c8c10e7affeaa2d8cb42e3787bcec00","seed":"e4d315f6daa11eeaea17d513f8d6df6ff2dc13dbd2e09158af03f847ee6cdcac2d6b88906ae62e84355d9a0c0956ed465b3f8081837d45eb01cf785223404306","priv":"5f1f737625360db311accae8b8ceca9d4f2aecf15d6e4b91db4c407bf75345bd","pub":"02f467c86cba2d8d6fa258d16e9b4543006b81c61bd357a2b1d79b9010fa30437a","addr":"458f265c275940d726dd9714413a56efb7f8c4e9"},{"mnemonic":"assist right street define hurry section tide museum faculty glance power aunt","master":"49eeea0b9687360576a3f93cb31eaf0edd3521d2cfcfaa37434d6d51a2f3b5f6","seed":"9371c5276808cbae376bf529372c88e6c5c6178a9b469ef25a7558ad68fd6200a8fcfb2c117b7d99e9c7db907bdb8c69632e7ec058f2b8a4ea16518fed9dab82","priv":"936dff8ec25f22522bec8ddf52535a4320327697a581e9304e62240e5d2f4922","pub":"029c518dc7e8261f2a64104ac846ca90439959f4467e69dddc7c902dfd41fc2177","addr":"5a6600220c96af511e6c89dd9c8c80f1a1b0a893"},{"mnemonic":"glare earth tuition dish elevator mom remind arctic enlist excuse vacuum little","master":"a251df0c9b6925fa78489dc803a34839d90aa10dd35216360fef92173e0bea80","seed":"4a543a76deb55a8df2a58d0fdca3ef32e3f3ca74be97789cf004d1b69608763f8d311c6cccfa76bb6c7b04ff8d7ce20ee064d78ce4e2c05d894053e8a5309349","priv":"0aba88dc12cda2d2f267dbd19ebf0eb390483c7384895b6b7669ba821b73953e","pub":"033ca852e0b43e2ed4c7258c43bcc5be47e621bbe6e0bd570176940aa9b371adce","addr":"983a92fccb0350a8371cb5d5effae7125615316b"},{"mnemonic":"tornado group bring crack need pigeon scene quarter affair purse three mule","master":"b4d54df22150e28595aa5e1f6717ec764ffd8d2cc6338e264dbbb46e9155dbc3","seed":"85c281d21f25c14304aeb5402e717b52bcc0e5dbeaf2d155e11913717c545baf79d4d965670d7645bf093ff79f4793d136d794616905c2e24a8c72ba1af44ba8","priv":"c45a9afa0dcbfabbec916a9fba6bbd9cabc1a65b4ae3358e29943dee9d19ef9f","pub":"0272882ee11e688d04b89252ca1000456fa743b5931ae03e1d29934f79980baa41","addr":"860b69d255bf12d5f725e286203f91bdbdd29bfc"},{"mnemonic":"toddler bamboo tornado season total battle urban mule oval steel field case","master":"af9ea8f11f6fa83dbbd4ef32dedeb88070b3fa9fd98d27e1d9b43e66da7d3df7","seed":"4b95b55884e008f340660a6c9ed4f2b23f45a5e45535fb263e880ad8842e845a62e66720b75d94fad7f47fb494bd32ee70b7a339de5b07bb13c7f0533e8cec57","priv":"643eb65f5c87407a18be41f6c660d4d1ae610c9305833c570d785006b92ae354","pub":"03d1c423839d02f40abf0632a36f9739c6ba59622ea56e1085d2ed54504762b43b","addr":"05625426a47e8c11f27fc55a53121bf748c2d05b"},{"mnemonic":"meat endorse bike truth avoid measure injury polar rely water rocket zero","master":"23b56abfa50026840bf19105ea9a02569d1881e2cc447a582b08a6bf6304a33b","seed":"d8de461e4f04d4657de6b5adf8730bdbb85fd175326671886017c09d8081ddb7dac0b8262fb01f2dde477b3e2bd97653a700d373fa29ec7db2161dcbe418627d","priv":"f409c92079cbcbd9f96b2bf0d84f86d495bd8e6bb4859fff2d62c29558a551c1","pub":"0247908ec215a561a41e2da6ce05e0ad08158bffbef9fdf7bae729592e4d17b45f","addr":"e4cb61da62a6176483f967aad232c0fe89a9f16b"},{"mnemonic":"few transfer upon helmet property draw strategy talent awful goose index lesson","master":"c0e538e1e0b819660c63ff668869a81595107458fdad44459f6ec22b251d46e0","seed":"fad56235bc5f3a7dfa666c85e5782871e7c202bc4363da62fe3771d71b36a9a1502d550d668db69264daedefd7375862b891d4193cf958b6d8af9b39a9fb0e3f","priv":"51c8264448b81467c2c86c003765322f7c763e0854903230a4ff3557fb7afc31","pub":"03bd00d092d311add8fbf191abccf181bb5fbf83e26d6e29fb6f4d70055ad5e7fd","addr":"270429d79b582d835fff0b15b0eb21ba1c98b2fb"},{"mnemonic":"can warm add shell obscure ability mushroom discover destroy useless split blush","master":"611e2b107ee76d6f7b415776c7b0c6f03859366c342a56618850c6e3cdcf46c5","seed":"c9f4b2663f8abc8c8872842c41fe06b5911b412fdaa875ba59366d7a18734aa795092d220793867ed43afd1d79882ffefde417ca68c9ed61a9f52437d7e45a53","priv":"af975acc3008d742a37bd6917f4a5c6e9a5e0fcacdf1e74ec489e675905dd9c5","pub":"021152804b2ac5099446aa5e8cf1fff850cab08e225922e3865ae5b280a230ddf0","addr":"d4baf915a1108fabeaee47ba0b03cb241a12e1bb"},{"mnemonic":"critic length shine mimic gorilla rebuild bike security price differ spice average","master":"418d3fa386032d0a22a3b4553ec662d52ca416af47d0963e288a1bd08ad50d20","seed":"c44a2f7e56ffc9850454a03c40be79555c340b8bb2a7559a664a8e295fb34fe1a38074101b431038c207baa219181046805a67977022d61bff2270c1e27b80b9","priv":"117d57d4f3dd6db8a718e025f4fe5009949139f2a41aebd682ab49f96ed152dc","pub":"034af1a0205014cf22dcf328aa9308e255355dfff65a7185aeb180061aeece5084","addr":"f7af8cdd0592983c065c322efc64bf7c25769e2a"},{"mnemonic":"vast resist ticket hedgehog around fatigue rocket rack carry run protect icon","master":"c434c6e478fbf7edaf97e2c90c38369de3033a98696b1ffc793aa349849c629a","seed":"720f1afc198446db8a107105c7398d3bba7675fe0d01de12f933e2eef7d12effea0e9d93099e0256b9e494607bf45d855fefd68543d9beb4b92f3d7779a8616e","priv":"497b2409c651a41ed36e58e977611292bd665e273847d4d413291c386d0d65c4","pub":"03ba0869f55efde74895a6905dd149bfe140fb2ee4e3eb19c959195d93adaed2f7","addr":"2242ceef764c76680a768594f804e218154ae3e0"},{"mnemonic":"neither bunker use enrich liquid borrow time feed mixed clock submit scorpion","master":"a9c4646a10078a9ca6b218b7da25745a76cd7dd9e38d803d8e840863c9b97449","seed":"22cc85d4e408d0a751b854f16e00fd16b018fc26f95aa7d82323084ebd7d7bf3fc2370c1a5e38f88584e8a17977f17987d75e447f704603c2d71b3ccf806afd0","priv":"9801ad0243910e04b7322f493540801628da575ab5eb18a5e0b20b0ffa498e5f","pub":"02c3f726202db7040a250647799f5791d4013b38da6053e44f502d0c8a064124f7","addr":"fb0ef77563764b393003c137da2dd1ee21d92904"},{"mnemonic":"letter violin disagree arch crumble amount car inherit wasp vintage disease orchard","master":"a24fad07da3e4a04fecb2674abf8b4260ae5dd71f003622bbc4a00292dec3cf2","seed":"890b94a33cb176c697b9ca49281c053f88a8e8bb6f52af5f0fab57ce621145ea59624fd9f17bc4d7ff820bd2998cd1d4a2dcf8f89738c150aabe7af5f87a6b1a","priv":"499b6d6e741483ddccb35f917752e51970c5999900b48e18b2d1edb85927b7e6","pub":"03354167051ad5a01e056f7bb655de9af430fb0b3756e1cbbe6dd0cca65d43ff18","addr":"efbe8995bfb51a94b21826bb93937616c5807d94"},{"mnemonic":"elephant shoe quality dutch pepper math between lemon wood below strong grace","master":"7890fde1f36829461985465e7a7ba26ef80bc9908e5cd849517a999f04b02ef9","seed":"077fbcc3c57bca394c393e9852c3b837ab555cfcc5dd0097c058136bf088fea569d18fe0d447a8bbe53b5f22961de7c5cd0000274930db60ef18f049aaba4741","priv":"0af39cbaff322b7b7298b2605fc762bcfa69ff84a50dbb121502ed1e8db963ca","pub":"0221dd6d3d3c597b982093f5ddc4b8403b3d16d0e084aef37db3526f050c9b66d7","addr":"81ee7b181a5d1902b6aaf42ad0225edfbf669498"},{"mnemonic":"powder marine skate good skull correct catalog parade car length fold clown","master":"dca44cfd6a67d213ff365e5dd6bfab6fe63ffbc999c9d38e48b9c8d32d32f914","seed":"91dda0ed96be1b82432b76bb7dac1e80ed0a1c5413096d4a22437081834cc29f6355dc3e79d7ee00cb6bbe50a83fdd3b652259937beccdf11b844ff023269e76","priv":"25ef3009323160687cc6651338320311894b8260596834e6cd05c1b921c7254d","pub":"024b805e8c768c8914ad8c55d8e1898490b9c71fa68ef43d07f3db496f03db11e7","addr":"57c28bc9cb2f4fea177c34e581c95832256090eb"},{"mnemonic":"client wagon legal favorite donor tag describe object camp network tornado immense","master":"4b916d7a10502f4e2ecf295d826a3248fe9bc45a13f1332a46586833b2f1dc05","seed":"e2726352ef940a7cfccbe95172c1fb07c8c25ddfd7ebf5ed532f27abfd33e81041e816e34aff02530525596654111ab3186fd71bf65dd3dddcbc6efa7944c347","priv":"131de6e55bf3b614153557b35c839f0c869cb10d62b8c34c15fa2cf7c32bf97e","pub":"026a3afcb9ce79972ef910d6272613580b199f90a00035ecca637b09397f0624bc","addr":"b2ac8314ecf16da855c5d7b9ae3aa12854ae4a05"},{"mnemonic":"someone tip green vague sudden element beach people route lawn vehicle female","master":"2f7b9ecb854a851e308e944e6a8b39811a286e718b4ebb9a36e8c8570cfa7890","seed":"7653cad23c600649423fd68b0c7d002feb0327551521059362b3914a63f6ca6adcb1409f7f7f1b01f5c489237b25d0dd9b0aa121a60b1af33cccf739d05e32b8","priv":"4b3d50735f027be5ce5a85a739227b4e86590765e34b3608338497fe318cdfc8","pub":"03b47e6036447632c8ee3d2d1e3b177b51ea73bddd30893818c81059cfd3ec6c5e","addr":"10d976ebd58061a7c6ebe2ccbfc85adc617db2ee"},{"mnemonic":"version borrow decade family away zebra one course paper promote man gravity","master":"ca2995d4590ccdfa716b0f27a3e5e93d084df7039116b06ce5b4c5f2bdb18ef1","seed":"97a3f0fd0c7150526375d5cd1ea192dc0f04ed096e5c4895e0a15a6d491b206b59d52800c2c31ac6b512664788ac79663135f450b5198f358dcfdf1e9cc26e12","priv":"cbf04fb7c5c97ab9980cf82625a612919a85e72c0524cd49c0a237c25940b563","pub":"031f04b34f157a07b6bf50fd54ff972b8441a72d6a5d4fe1e54a1867d07fb61cac","addr":"57488105d27e808a39fdd571c895dd06264d3357"},{"mnemonic":"truck zebra tobacco hair monkey pool label produce leader hope misery cost","master":"b42e61efff413779403a9d5ddfad5230412788de3c0c7da4b020c73a72a77569","seed":"1b9c99349d6388e5f7dcbb8d5b87951a614ae7f803b69b30783035ed016cbcab3c42714246d05039bc6121dba51fbb722c13d2f6ca0cda79a0d816bf7e568cb0","priv":"52dad4ba927ba056a1f0a07515f044c3c9dc712c2019879029ee0b37c7f51b64","pub":"020e6af559d2e1115d8ab76e908e3ae778451dfca6250b996c42d4f3044f0f1a27","addr":"1a3e87568d2f20d4480c153cdd82af21382fdf9b"},{"mnemonic":"dizzy capable mutual cage uncover frozen exhibit awake teach grocery juice reveal","master":"54d15b84b003dd74581cc49909d3bd7ad07e00e745f4113aba6facfdb305aa2e","seed":"c4ae35b24c55af14bf590df97843ce1c9bbb324b845f9d2a08f0ead0d0292f6092e261711aae504feeae862bedd7558a092271455d89a5d1629be8ca43710e84","priv":"d5d476790ed6e46ce12e1573a9fedddada0413d5750d1d18e408c125e43c7923","pub":"02f3b58f6cf3533f3731e5ccc6cf094815d52467e39151d517b9f6a425f8743601","addr":"249ffe5709370cbe54520c162a4a7c8db2b28bba"},{"mnemonic":"menu damage flee oven blame vanish olympic scale pretty valid toy write","master":"91c79127f19318ce4594f4f1045f0f2efc8ecb6a3ee9177ea2cbfcc890a781b8","seed":"fc4b72ba3587fc4b35637186959e3f02460262bbb330c3b18e561faf4cb2ea29ae9f92f011d9d78231746dfae33f57d75ed85f96680a6a3f309a3f81cf59831a","priv":"cc7b3e962031f93079b4d6a9152a85bf927ddd2fdb9f84465220e2cc3ccf9ab7","pub":"03eb09eb7f21c9e411e3660fb49907bc9a23e04bbe75151ec732e066e4e0487118","addr":"20bbafa15fe38bfda08c18ed7a65c52daad01614"},{"mnemonic":"remember hamster power document detail pave inspire tongue rookie monkey board tourist","master":"dd1970c96e30be347b4ec8fe789b4cfc29ee073162d4a2e5dbe5c78c80944af2","seed":"561682af8f69fc045f09d43db4f71a3c7706615ac142078d6aaea287bff00b0bc3213537dd50b783d7f5293b4c2d2a1f6f9bfcd5fdf17f19cb10ecc05f854b1e","priv":"79c341d4178a7a8e1fd364d8a847d97b06ee94d9906a269499fafa63730d04bf","pub":"020540cda9e4957f9480aaedcb38379f2ba60648ae487b741c629a45a5b34870a3","addr":"cef7f07d4ae1da5fe3cdbb37d95bed5bbe53e838"},{"mnemonic":"endorse rescue traffic vapor chef movie symbol scene slide eagle youth tide","master":"8e54dbce9b2fba91209dcbbf6bd272d524762ba3ef2ed05297b01f440e6ed597","seed":"2a0ff0a70d82f948b866090a4e77ddc360a2f52b6abded17f13dd66e79e845bccd2c55ada4d4ed3dfb33d5d10700628bee551ea775c7f3342f6d7a0c3005194f","priv":"c58ed547be839e99eefae49479b3b6345fd7c6ddf390104a544b79f5f677016c","pub":"02d795bd4c26b14dd2aa3c04633f5e0ef787533b3ada72e7c83bffdfd4cbdbbc5e","addr":"ee25d8e4187f6a6214662cc4872b7f7cf7204c45"},{"mnemonic":"humble glove resemble slide rib focus naive false snow north strong attitude","master":"e8b826c5d90453d1af3082a0d5f6a625207bef96bf7e168ddc4091d7f865d51e","seed":"b9bc139c6e97339489cab328b3a362546cc19d0cc060e5c5b969206024aff86f1579d230b4b8b3983b33cba32a58d6dbab5f078704f0efc65d6476062c1d41bf","priv":"4085b496b9a18f4ee5a1d79974be1b1729f51d3c63ce347420d08833d2c793a2","pub":"0251ff80d2e90a37efec614d9fe65b6192179941b772a9468440a2380845996846","addr":"4fc115087277fd7dfcea23e089f5a3a6d7e3bcbd"},{"mnemonic":"fiscal truly seat deal crash train labor trigger kangaroo angry today minimum","master":"1770627ca13a66d0fcfdb474a3eef708abbf9d23d211970395308dd6758bf8e7","seed":"a19680de56046e31637ce714778881f1ec6bc08abe9357804062cb881838c2f8387b52f714377b89b6faa07c4e5b6294324081b7dc521190cd43f75f91029c22","priv":"131dc8ce3551842aebd863eb61e07e6d2de40d548dcd28ab0ed6380e469b5d92","pub":"039ac0eeaf7600231c75fc72dac0b2f58418e1f187aefb3491934120b4fc779d18","addr":"fce14c8cded6d2711301a780a58297c68761dd52"},{"mnemonic":"good dust code sell element tilt host valley climb genre asthma bench","master":"106ae0e9582e9db67ff88c1098d3ef651efeef30d44ff60de30bc0c447217ff6","seed":"1b307d8ffce13f7944bfeee6d6b97de257cd31608ef9059bcbe2cef8bdfded91722fcbf325788d48a5072b9f915670d345211006102e5535f7e2a1dd86bfdfd2","priv":"a78bb63f0cf56b81e228b801cfab1706afb073bc2deb8ce1c8c56f2ab564f1a7","pub":"03fb2144ca5e9dc753c2aa46f94806b35f201d942286571a44bbbb879d2e9e3adf","addr":"5d68a2c8fd5486ba93dc18cfb6a04698250a424e"},{"mnemonic":"buzz prevent cover list flock meat that slab crumble melt prison treat","master":"d620abf2e72b47f061594137194e41c33bd6789799d67b712179c5c9e0dccf4f","seed":"331fe2ce10eb19e2ea13c0ff7abac9b49d43de8d937963e8498da172a46e0c4dcf3e9d276d1e4c7dff5926609936f253e59c814bd4c061429cf1408c45d6e5a4","priv":"8e3b30ec2427f34c463f83a500842d4fb73575e261022720276b3fdeeb20f075","pub":"039ed714c28facded3af8fbd8497b17818cee93d26732aa7258ea61c6f8cf542d6","addr":"74b44edf7f993c72dfa53fbcbcc836c99578769f"},{"mnemonic":"domain tone insane visa much reason tip truck travel head finish grow","master":"3b00a9417e07cbca1d0b80b108cce99089c726e49c267b2e5a2a1d3965c7c99d","seed":"3e2c842cb5d267a2ca3fda4c20d674d048873ca2cfe89e02558a0b585475796979e4bef6e835b17593c53a75f5a4b37dacad0977a6b6fd6589d26502db47a048","priv":"cba9d951fdead64920a36afac46d82241c6084b46681902ad37eed1928135db3","pub":"0321db6f62dd27416d94cc22ebd3abe7ccb66d5e5f57641f79de3d9a1c49f8d0e7","addr":"17d65bc69345ab94e3817738981ea5f9289b81a8"},{"mnemonic":"bone earth country lemon great ridge glue neutral vibrant age doctor income","master":"ddaa76dc4405bdd779045a0b113133f51af43c14ac12281260ea2281a21d4704","seed":"c7edb1f4572aaf510b4b79f18cb68a7464d20babe170b3bcebfa7902f2df2a47d404baf1489922bbe2edb46a2a8ab798a99cb5dfc162b315e4e0a83ddcc5614f","priv":"cae3b56916c64b7303c038294cb1a9c15719e3cb8ac0cb2476e5688b6bbdbf50","pub":"03c9565910b4120ab6a62c275ca0127b717116e773f57eb93d1852ba3d0f2b431c","addr":"81b61de28566c226e0153b1e3afd53697c6591e4"},{"mnemonic":"rotate agree figure style cereal best corn box corn actress toy deposit","master":"ddb3592dc43e595f968e906c72be97c03beb78325f00969311f167e7748bfaec","seed":"cebd7cfb74b2ac03a29e6f4d3dba84d6b47730b478d0ec92f90c9a0ca575d17c581e1f3959b4e0ef5d5f51d43a0fa186ea54420cccc8c2fec8a25f36af549e6f","priv":"b3a7e3147640f66d7be8028a23dceeade18f23bead07774fa5d176014627dbec","pub":"020e2c9e9484acdf5f8a574e9fe912cbf6bf9198579107a48b976da5e4dca2ca0f","addr":"eba352793c5a7ed663a5eb33ef9c44ceb0388677"},{"mnemonic":"kit age click judge decade enable trash noble first grit crop decline","master":"bb39f1d6570a42b31a6b1093d6c1d3d469df3d565ceb2064863e50c540cfd986","seed":"9c8471f0ada1f4e4c4b863811b36036e72818432b8e441ef8234ea29446d2978195da3d63aea71aa5d1a7c4e71e131a90e2db598bc4ca2bad1dfccebeacf963e","priv":"83a532c37858e36cbbb325481e7be10beb2166ddb16b7ea19328e8dd712ac178","pub":"0215f7cac31b44b05f1fac2742ed8a0d6353fbecd06a3abe7946e2dad1feb089c2","addr":"a10254f23fb959df76231ea3061cdde854aee99c"},{"mnemonic":"jeans broom faith border sign decline choose black depend camp nest song","master":"01dc6326bc635da075e100217be8553c30be5c3ee66bd4cb8dc0768777b5826e","seed":"5e7d44489c45338978dcb69035addb83625389d15a5a2284ac888682e7499e8b07aca6ccba965201512ecf7da5a5ef6e22d561583e15f4507eb79ca60e525da4","priv":"07e07f2a2d9eaae6ec9ea7f676124dd14e2f29e43095cc8574b67fe5a8de1fc1","pub":"0295a431168b265c62a8885186b7719298c5791a0d73cb5b6e55cdd7200b5dda38","addr":"9328f2fcffe4db6cc6c8c2a5b0e7f78cac1854d5"},{"mnemonic":"narrow federal feature ignore damp sun brave cram blood crash glory cargo","master":"7e5ad0d0325b2bfc0ac8a2d32b13d758b308fad36c5aa4c497ee3fad4c999fa0","seed":"e680df5400ad6c1f8b097a39a4ce9d9c3c48ea4c21b71795fa499ed641137b50b58f78603bcb2bddae78ff5f96079d48fadd175050ff95784092bc93557d0c13","priv":"eb443a6e96330c1d3c2213e9e345b4cd0e4b2562d6bf13bdf9366f0974d0a98a","pub":"02843de6f3e02767908c2692c091df22867fa783f858a39aa7f6dc786ad5b5d2d0","addr":"5a53f850027b3f303ade321198c74d108e24f699"},{"mnemonic":"fringe fault blind lock wreck one kite ozone system come spring amazing","master":"dc2916fd303a02d0d7ce5d5e0ca55b8c504063c3b54d006f0926a89c52e413c9","seed":"ce52cb29528f78b85c003f5bee65b2d3145ba93963fc4ebc023183618cede1c0add4fbeda85df76e8887004fa526769752808977726bfcc838fe9fcbf4019df0","priv":"5b6302f3548c8a8ca594bf67bbfd44ca98ca84b2df134b0d1edf4b28ccac4340","pub":"03846f7ead64dacb85b25d5279681074dfb9a8c363fc48acc6565c6e142380ae3b","addr":"b32324b0f48ace5119e6d6616b9e613438d92184"},{"mnemonic":"rapid donkey deliver soccer between antique pipe youth science angle erupt leave","master":"3ba5a3b9f7badb433f4235e89359801dbc87b6948e74a61e8555b11dd2f6b491","seed":"eae34a8427228c93f754a3a5ead6241684af42b34047f98b12cb7339f3b7390ca9ebd4373a89ef512e75126de78cb72501d2deb575d356d6ba9d64a8d50951a7","priv":"61a6843aba8ade001ff479a2b768008ff5ef996a5a8576956328815755008c06","pub":"020bb75350f98f845d5ae99ad8720b025d7176c00b6a92a9ea7ac14818a7ae6a73","addr":"2cfb35c09a2a5a458519e036d21555571b88fde1"},{"mnemonic":"juice riot brand example type sign crucial warm bread describe rain slab","master":"9de3651516a0c991dac2dcfa0f95265a6100b6ca605a0d577bc9221151306b18","seed":"5ad029a5964c27c295502b40fba611bafb9b9e626cc8f8df5a98394060d16e53ce41ea46421a615c5a3b5b61c20138466dad1a0b9541d57e8ccf7813ef6d9327","priv":"a54d64cedd5e3b3cfddb182a513a13bfa1cd64627db1fcf5c91f398330010741","pub":"03840dfc1f9d210a632dd38f45fec096c9dad11de2a8523adcc79f4f520faab8a4","addr":"1151a84a341b5b24b687abd2083e7fd150ae937c"},{"mnemonic":"air ill huge miss empty force indoor inside young ball wear blind","master":"76dd3f042a76e88b7d63422086fe0b5242a80775c92ba4dc31b31333c6cf367a","seed":"0df5fefa4beba8bcbdc1e6d4b906c91ca66c14261b543280b31be5e1a37b7a91baf9f34e17143a3e3451d3da18534996a4edcfadeec0971b5b7db225d6056fc5","priv":"90ad41d7cdd253fb10da90c1eb6f9c75120553db484c6e1e2d61aa4ca679d5a3","pub":"0229419c442507c123f161277de5a9beb43fd91556f6cbbf194e26bcf4bcbbd4a3","addr":"68ca6d2e8330de386a3dff8acc4f9be6aed6facd"},{"mnemonic":"electric grape tomato average idea shrug slim certain caught know rather poem","master":"4770c9846aaef6f78e326f3aa72fe236564251b0187e3d8cf2dc95187fe348ce","seed":"d054638cfeac9ab3a2150a49d6854c9fad983e7fc91ccba17d6bc210c976b20336c33fb5f8eaa6e54bd6480487491a1f8150d074b29ece6164c2c99c5427d7c1","priv":"0bbedbc6807a1c2b81f7c1f8b9a8380e27d19a0905eb505630156639d0ea4097","pub":"02be715af6a8583fcbc51f4cfed7e78d93313d7fdd047b198abcdb6d0d2271bca8","addr":"0535e0d51a9f99ed22fbb713b2812e4f2fbc680f"},{"mnemonic":"boat tourist proof point giant horse error trash abandon transfer poet legal","master":"5c366956c526671c4e6f9011872b24d76adcd95de54187d81e3c7c2edc749023","seed":"7455f7f31ee2c7729f7a05b4223bb2b335a0ba5b8ca1ee3f632e04e752294a1f0081e94cbb6763391132562a8f8323b0b05cf00961a2d9a4993ef5ff69d52e2d","priv":"ea1f442448650bf1445c5aa13107210280293e9cbe1b1e432327339db7b68624","pub":"03a80a35d7d599be28524a427dc9b3fb593bd12c7cbef3982bc67523ae6c202455","addr":"c12318aa7559ef40d3b56856a2cfcf89d5f5def8"},{"mnemonic":"number oval section onion aspect surprise romance paddle oval reveal business pudding","master":"2b2fb49728bef8d8301af63af35716b2375071a75b1e2e8d4162afe068e6a7b4","seed":"384e57c3ddb0691d55be1d667dac88873719ba4260fb3d26c263d75d8f5cd12b444255daba423821916bd188df5007ad31c6388b0730de258f543c23fcf74923","priv":"26c77883d1bd7a257d55ff87b562a41408544fb727dd98a7aac093b4a70f75a2","pub":"020ee3bed4cfcfcd28ff8d41c96a1b7851ea3ec4f81fee00ef8ed05def21d37e51","addr":"e8447d8d97950c9a15d3d181a3cb00b0541941b4"},{"mnemonic":"shell lunar fragile unveil dinosaur napkin mountain fresh annual jealous check jump","master":"0bc353301fc1edfb08d3ac53efcfcd96699ffae3174bdc83876df3f9a5fb1a90","seed":"4c8a46510fff2ac0d666176cf77fdde3f2dcfee550260e43bef7f9e6127ad807ed335fccbeb49426aefa8c0f1268e5f602124c2487653160f575cad5ad68a571","priv":"2e783a6c7e1e74645f99752d342aa3b6de689af33c5a80e3abf28f7e1ac0c6e4","pub":"03fead7454b48e2bb68c8fbeb1c807dd4a7d05c6c4c9153d4c516b05967ec56853","addr":"0ff9f27bd866673fb10bf741a221cc8cb4a4f95c"},{"mnemonic":"sniff rule decorate expand siege boat people choose resource topple produce coconut","master":"03c9712b2dc0ed358c17478acf1b3b9c8ea9106c01f0e52056856ed212d4b9d2","seed":"a689100267375fcea1ea18ca798c803fbb6e4b9d82f9f4fc96b3a0873f41b7553589c605b021b4dd4a2db9d3dc5b239053ea5a48ed227fd6db264299fc8d0e96","priv":"8eb04249c00506425b0e414b131ee80dbd8db4f5a873be04a0b1d293203544dc","pub":"031e448ffa6e72016fbcdaa4c2790c8e57145ff051de1d99b69cac4df1f8ccfd0e","addr":"edff4f402b7525e5707a9ebb5b13b2bd03d12ee8"},{"mnemonic":"crumble coach clock opinion net churn cinnamon seminar slot upgrade always nose","master":"8af370254a2887d6d8d00364fc824b6565ef750d3b19fca98078281b040f9244","seed":"1c6241635fcbabb70bdd30d827f602169ddd82e36333aa50a7f7f2de4bbc9a581d6f7718cc94c0d63779f38363a8c45042b76b89610f9b3c2e785de234ba5818","priv":"23dc380f4557ecb1cb779d128309012c409c544c906865b06244e49be877db3d","pub":"03261b2261da80af3a33ca8252aeb21edc608b337761a6aa8160721dc202e65b29","addr":"fe0cb66348437ea5dbf8ca79de9db63f0ff51528"},{"mnemonic":"mind fat sort buddy gap glimpse hunt ready library invite mammal repair","master":"01979edaa3aacf38e619e05cd78ac50eb2729d6ca2d8ca5b476677d30a4414f1","seed":"7fe831aaaacfd5895fd3746b45c0cff02d52923fc3ef55842fdabd02de07bb6bbd07dab7f1db1318f97fdb6141e5ab0142d7d06ae92c020d2be760e08f99661c","priv":"10d3729902b4a8c26b88c84ddfd6201048250294f18a2ff0ab4248a5b4085992","pub":"026cc54074748e623153f3bd4b735d0c7df21cd21fc59cac3ba43292cf0ec3230e","addr":"0b7932471403f4769cfaafe834488587349525e0"},{"mnemonic":"area switch resource vibrant prepare write genius danger extra alcohol section company","master":"dc841ed2cf4ceadffcc8f8f6fbc50dc3385e2b438ba5f985f33dc5c68190c69b","seed":"cc2ee2baa8b309ef7e76fbc14a343a2435d6ce0f7da46d1f9a84782c77e84fd7cc40c503db71f75380cd7e2236c9dd0579b528d84b7deb89b0d4a4926c66a360","priv":"b2fb735d798aec932964121a2a00cfee6184f03bc0d7885a84507ffb1a8f97c7","pub":"024cd279a8812efb672200639f718ef89d9996a6bcd6ae9d50c1548da744bdee7a","addr":"4c56a50381b8edb7e02124e205e170979879ac05"},{"mnemonic":"twenty shift viable behind victory napkin cry gasp own dance primary glow","master":"4519e4b46f8279cefb8b261568638b514f8591a60617fd9ef4c0f03c193b345b","seed":"393b214e7d24adf4912b8b6dab2c779c2896816b1f001d80a702a7dd2c44b5a1efbc85e2554e2586eac150a1a2bf1fe12e08735dbab0ca65a746259bf953846a","priv":"a187f775899244b9a57da9a173614ef2992ce1bd2ad6333eea6e796f04ca446e","pub":"02735247ce372948d922ef85da71f424580a46fcb453cc889411722f8984f301e1","addr":"c055c01a09dfa7b360a99d784d05e715dfb1eb37"},{"mnemonic":"jump end chest decline act capital text puppy empty input possible goose","master":"5e8250d4fb78cdfa191efa589fccb98d2a635d091df8352a0aab57fa13be007d","seed":"fe6e62ac192f7f101fca767a1a24421acda2c23d1c232ccc19221eaae7697d9eb0cdf7350272d93ca37d7e10b3deb739ff0b05ee723a4acc754bb6994d2a5b78","priv":"f400703afc057875c9dd11e046fa53c0edee27c78e2905425a74139f3329c1be","pub":"02c98ed539a5905393750276488e60d851163ea5dbccd25e6fbeccf119b22f88e3","addr":"81473d441525a6374665b98ff30f75b43157b29f"},{"mnemonic":"spend course nephew spot nothing girl wink flight wine hotel harsh better","master":"6d62643bea35847c1ec3b6a7273c42a24832d28092402c2dab4df1004df249cb","seed":"5cca26006b3c22da1622ffd07f0478988c9c97c5f128f78b89fe6b89314ad8c37627f02eb630f376574a38c243a3069c5a34dc59a709d5264f42cb1f80740adb","priv":"dce7ae54553f89302b0aa63a500cee7472a4a33967aa8a1ee18e16aa0e78d2af","pub":"036052be2df30dd8ad7bbc35055a4e60bf520fe962d9c7158d1c5e2b45c4c4f841","addr":"1ac0320f22683aa7d67416e24bf59098933a7e4d"},{"mnemonic":"coast grass horn front broccoli artefact also history screen bleak thunder example","master":"c49a459ec914359418504d3d471fde7fb1a82257347a4bd95997df53da47b2ee","seed":"2f528e97791aad4a82a7af1a68007871a2b4917fa238d69137fb93f64ef1f7af2dc036079ec220b8be11365d62ca11be66e83ba0d829671a55a319c441f6c8c9","priv":"06fea4c71f85b7b161ec6edf5ea0b90cb95a410fda9fee0a603fa350f289ef43","pub":"022756af9a6df41e36de4300027a8a6a6a8f6bc7c2b31252153f3d915299a8129e","addr":"6203a9699c5d1b6bb64d1dae86cc741896792266"},{"mnemonic":"shield liberty wash park absurd inherit suit resist garlic cycle ecology mass","master":"a35a147cfb59e738ea4eaf9e6bcf1102c7d4c15e3e59458aaac528a0635d5316","seed":"fdf1adaddf7f8bec833c3054d079be7a240f98fbf08d051892a02c4b1e1392ffabf84422606d7ef333f99773bb8d51f01175c568a94f5317cf8b225991d7a528","priv":"581e1227a6f32dd51a3bf36e7c4f1504b00a528312f3025f3f7fbecb37b88b7c","pub":"03c0e2eb1d83e266c1c25cabbc6a9d46b0d955f70ee83b78ef0348e44fd6e8162e","addr":"18573866de437d48c044002b20fc5b886cd1dff0"},{"mnemonic":"spider cake process model elder electric mosquito rather choice insect crunch pizza","master":"1c95e3db98b4194020be93e3d4791b9aaa2c7eb1c83b02d7f3bdb07183f4c3fa","seed":"d25f0954443b2c18507a0c71923aaa31857d03187b08a649156ab634c20f29a444ae505cc80515e30feb69c05cd4e133f38b18659ae6189ea27b442705b9089b","priv":"5b9cff23b6a19a67864ec0973e3004da548b5b97400f9fdf2dde3db2469b776c","pub":"03829d931e59a87c6ffb4f8d512374ae7981ccf2c08a30acd787b77c628b727d8f","addr":"aa95e7e0c4fc203ea639873f05503a2d5e98b70e"},{"mnemonic":"include yellow off random knife video person monitor height virtual oven derive","master":"92cc90784cb9a58deb578aafd5b6bddf5195bac720c1b27ad575bddb1fe19487","seed":"7e090c19e128ee76d95f7334361fe7eef356bec53a06902c6c5bde0cfbbc7a7adc540eab3fbaf7d1e4c6ef38f4c29054767c115e6160e6825868a91297e2d5d9","priv":"076608b84151c535a295ccafdd1301e8eb82f779fb4aacad5bc2a1f0a699364e","pub":"03581ea3f2b7ec38ad8ad9717b22cf43192a637eb4d4db0b051f2085ccb43d9e5e","addr":"a68d0470048127c2234f1ce4a70f9f04c72c4dc6"},{"mnemonic":"chuckle hybrid seed portion dress move settle pool erupt segment annual demand","master":"fbad7924603e902337c9f58086a9334562d6f3866c798dece4c1761af9914d3c","seed":"ed3ee02d4b90299b11fbdf6fc7698613aca89749352bb2ecdbd5cf0e0436e0ef702a615ad041bd97bddd4e892582ed9037028002e2bd5c58ae7730c47a44e20f","priv":"77c0167a4fbcf6dc7105af046e2978eddf6366e945d8456c28e13c8f3ae4de57","pub":"039a672d56a39e6aa1bf2d51aa0c3525692117ef33a92ff903dc9611f86550b96b","addr":"d4fcea5b95282e1286e412122701e9bf49bab344"},{"mnemonic":"portion upper maid dash where control nuclear post run manual mushroom bleak","master":"66c9b9ac9c75057c18fa94eeb0f75cc73b90c08eaa3aecb1a83577062be3f6fb","seed":"06d6d3e53986a879befffbf87dcfd6b7570321a071e22092e1c88de34bd44d7ec72c76323fa0a7ca040a7ed90ccd686d13ea027ebb06f8c66154a838de229f2e","priv":"f5141661ead9339621deb48ffa15c4569cb2da05467de78a2eb631a327f5a68c","pub":"029a18777158d04ba09a941ac8ae89366a50dc8253319b71647fc1c6e93dab01c2","addr":"f1fa2abc32e5e9aaa843cb07c37dcd549b76485e"},{"mnemonic":"fatal lend tortoise urge topic sweet spend antenna stock nothing doll face","master":"2d03a7cd457dc67949321ed16a2893792e5210cd4bc0f5ac86af83897094507f","seed":"f48146154da92dab72fc0fbe1f6c7524178301502d72ae7c404b67f8b7e102306bc03f339424b011eb22d15977a0f12ad0b25e7adef5661d65b06dd0b5184dcf","priv":"d5908635bebc92518047b79599b90b1048fc2bf2d3eb36a2bfa5a894927675e2","pub":"02309e322a1c103c44ed7195044842250cd757b061430c55bf1fc8f7f10d660bb6","addr":"946728094cdfcc601a6a496ef5dcafd3de9a6488"},{"mnemonic":"blame margin glass dinner worth right require unknown wine settle make aware","master":"7297101c31d8168aee1fcb025bf1ebcd747ca6d5ba19d2bd28514fe3b0e0be18","seed":"e97413449360a70d3d202dc63ca0670a98aafecbec1de44d8c11f1ae90099bca926813685a429d4cefb6f0e29e207732f29e962aef7b6ae82ea3cf2d7617acd0","priv":"b144f77a520ba1ecd94b1fed5f362cc1fdd7ba9bdc355e9d520c2f39c0a20f7a","pub":"021c6773d45e549503e3bd6983655510a46a873e793c6cdc989356f657f3e5bf20","addr":"f259947fedfbb0ac039a44936e901f3622b9323b"},{"mnemonic":"gate make bird oak brave hole elevator tuna gauge type school disease","master":"1c1407749a31dca67aff767e4b78eca5351ab6792dca8aaa3b31a766147207bc","seed":"e079a04be32619bb57910662e11a006f27b02743e4440136ba02d7915502d0fe1590667a555fa76313452747a1384596950affa367c4a3e6f5b179e750018a7a","priv":"4319abffdaef48761ea2bcac50eaf80551baa1404b27b48fa379172f2fe8e1f4","pub":"0229358636cc2b80f63c7256eeb51b9e0bd3e1df0cb5e69ce87f15d71e16fa4a8a","addr":"d0134881f0c1f11cf9938920472f3d37e9365565"},{"mnemonic":"crumble danger tell frozen define mixture sadness strategy village mass junior kiwi","master":"0dc426f3c99fc31a73cd91f5c261fad7b70e2a7738e6312325686c95dd9df2b2","seed":"773955324075bed8d11f971096456a8557f8cf76750e48fa4423bf5e604943b5ad17788fda1afb47f03cbe208c79c8b6c38105538d6028b1ff4359e7f5a122e7","priv":"86f1207640ee12c8175e9b34cdc6fbdf2c200be9e03697fa82f8cf43dd8a6cc6","pub":"022ff8d5a67f1235242e9e143736bb950d391bfebc29173cdee50fd6826ca895f5","addr":"49fb80faca4a0537aab1d0b7ce5674d4490ff8b7"},{"mnemonic":"reflect mass fall habit mountain winner logic box cook between drift donor","master":"350db5a525a544ff7d82978817ce35f33ebb6c148b9ff6a9bdbd357a16373e97","seed":"4511bc8cd2b64472dbd108250e8d0efd825e763790bdbd44f4ab700c5038ab129e417ee574716e1b895cd660c72f9bc4f1a6a2846e7b09c635db2a51c22356c1","priv":"f2e5782037ff1ae1678ca2baebce674b973aec58caf7aa1aff830b372a6d6436","pub":"035d54ecb4a48285dc13346fe46cadd907e443c03e91339363b81c3d1988b09a38","addr":"6e8114f26eb00d95ea09ddc7d4d5cc104bd3ec41"},{"mnemonic":"enrich corn rose chest can figure canoe used pattern margin usage increase","master":"d38a5d82ce728c441f707cbced8d7b08d896ef9f37d0b563476d5500ca0008ef","seed":"ea926f98f2efb3af7bcc514969bdae01680e237424554b732cb37257e0b9f0ca1303af09dad82b0c967ce189ac8173901937ff42d0163310e5fcadfac1710c56","priv":"880b645884e27fd9205d82ad44c18fbfef02f205455ef818fd3beec79ab08e5c","pub":"0229eb380ec659c8964ca2d19196eb59804855b0d4226fbfc48f2373466380e1ad","addr":"ba2ea36646e0806378faea7ae0d1a691d91b54e4"},{"mnemonic":"coffee labor involve dragon upgrade route south guitar uncover enable soup sustain","master":"0dd39ec2f51c819042ad3fed701d1f982f599383049b38ca36da842bf5d3663e","seed":"f81aca2d700fedcc07990f1b9ecbaf194c0df5dbfd240437c06728bebf0022aac77b8b44f7863b13613b4bc5752f0f19e2a21617e5e0578e53f9198c2ae853cc","priv":"12c7b8c875fa9d0117b53e2e539584c9c524fe1519414a13062edb33eb712408","pub":"029b8bea854aa1d99e6564e5f4c9627a95d1fbda000a59ad3049baba92a474a5ee","addr":"eea20101f17d14b6bef65b393a49b9c558f5b87f"},{"mnemonic":"dash clutch smoke chapter lobster quote fat negative desert labor rent basket","master":"a6dae26374b6e165be90ae4f1759fff4dc4da104493a21c4e062d42a50ce1b48","seed":"2c4d251fa5b3a634ddafccb16393730cbdf1a1f20b44ddfa0a25ba2e5b6a48e8338e5e5a8a0b65bafe30ae629126789264c98a4b02ba96da5eb3b15fe5a296a0","priv":"5f7246020bfb4ab5146674df950ccadb3b014cb8956e4bcc3b575f710b4cc4f5","pub":"03f2712cae90744dfdec3a37990221e86063620b7298778ef4cbac6f438764acaa","addr":"7d8dbcba23c0e04ae21d250c585f511ebb825ff1"},{"mnemonic":"toddler juice raise depth club rebel weird portion void minimum game typical","master":"d56bc0aa70e0e583c13ea0edd4df5dd6f3b02a9a0434b0614f5fd9c2ec029b58","seed":"373286db33542c525710b01bb881158a7a1c723512596414370f1547edc08a11738d855569109b2249f927839c53361c8e0c8c468a62421c998b97fee5dab6e6","priv":"3db2ff05ae17ae227e78096b9803281f9332857f555dec941153805377f38520","pub":"031a9ef5c0a80f32c99f8c3af49b8fc51b3902ed13832ffcbd0f9527e057c0d56f","addr":"e5b70525b5b3c325b9a2a044ef05452ea0dd6821"},{"mnemonic":"legal lizard easily dream push business village network bread solve predict surprise","master":"4495fed7ff0239ac3a3ce75f1ec1e81fd3c8f7ac2c3a2a9d94f0f82a31042796","seed":"a709e3741759029624f534c66e8d8e56bb03fd8df960fa4776daee1c61810b96c495bbc3dcff634ebf140dcec9f7da9151e09856ee16ba5106cd7c1088032ebb","priv":"5e3e0925e33311aacc94b1d29f359f449d443cbe618e0a689d0c40cab692af21","pub":"03e2b6a2f99cf742f7c1fd356a6948df231a75fafb3cc471f9ca4ad00ddfad8c2f","addr":"c0980871c3f7b15830fa514167c90999279d496f"},{"mnemonic":"draw boat debris humble cactus method duck ask author soul busy assist","master":"8bbae4af997d4735d14c988cba637bc041b4b0907c5c53ecccc1456b43ea79b3","seed":"f05a91da4ef94c81e0bdd30ed6d9cd09cbff7013c693d6e8261bf2eb3cec9568fd3934551344ca8c768bdfdc44fd1b30a082bffa2c1611654320948883785e05","priv":"659c3413372935b99cc972629253f37305d258459c1a92b7fa81883ceb6dbb54","pub":"025a5af583aa8bf4459c72c9665cac772cad9fd49518b9080f635a4de283542588","addr":"36d01ca7b9f3c37ccd529033c15b1c089b877d8d"},{"mnemonic":"between equal crush suggest spoon material poverty diagram forget click company call","master":"3f2d83ceff7b98467d9cb2523820f55d22abd1700651f4b71ad6856c029ada7f","seed":"34e2764bed365dc73de440475c23b18cd69750977a4197a2efe374ef552a9c56eadd6ccad970c422730cd51e5ab4e051e4c86ef4db2284256186fdfa0ba92434","priv":"62febeb0325ae75eb0c71c4a3ae889a4a274f4ccc361cf0829743d5add3b084f","pub":"026e528216c24173250fb71c73019ac45e6171dd4f9d8fd97b0933fa964b966ac8","addr":"22aeb188b3a21507a27b35d860b583d9d844cb91"},{"mnemonic":"cram palace round input disorder armed wool cram over abuse order grow","master":"5c040bed4bfa8520ccdeaae710403b3ee7b77e069536bd87babd93c09177f9c8","seed":"df3911a2a01087b8826327ae368abf4dfac62258a1a7a91cd4ac64067d926b3ab89deda5a0e5539d8c0071d14815e2aebbb913e2e506c6574ad973f950049d91","priv":"87a97c3f977b1ce0b9dea5f2ca8671ab6830f9dd4b3da8195e603b7549f529cf","pub":"029722cdb8ceb0be8456ce4dcb24a4fafb1028ebb4d35b4af757bf22e8539de367","addr":"eff0f2517523745b0b404f688dc048fee89815de"},{"mnemonic":"donate view volume faculty anxiety degree brother cheap film eternal hurry debris","master":"762647d305701dbcce0a5bb079077eb514ad72981fc8489c6cdbd71991d24179","seed":"566c1fbaf6ce9a0c7352e903069b332aafb438ff086eaeccd1207b6fb8a9f0a0a4279307fa987a905ece60a04a52a59b3db45ec15892ba76b2308cf9db8e36ac","priv":"c0092fbde92e9ad29a52c825b8187f40fc5e4ca7a586f4b5b4a8805f0554a0b7","pub":"0340718652a6d3d2b791e79fa91e96f60eef740d10e3db8c8b206457f31b1a0aee","addr":"315ac67c85646a6ff00192c6752301f11e19e409"},{"mnemonic":"pattern much pilot choose prosper spot shaft camera unknown target wing movie","master":"1d04a744f4e0ca2b180f5f20ed34bfc800d0c874d232b5eee1018142fa612b15","seed":"2e1bed0a31e13e8f13a85a35ec1531a93ef433c96338f3e6533dd13d5bdae15bacdbeb954f9613fd4dfb6a941357fbcb5908520096502ab4f6edbf0c93e6f559","priv":"ec42f7fcebafba29c6d692ba732e8060d7050d7c57ef67c0c9d8ea152494a804","pub":"0295575d1d162b7599175bbb5b213ec3e79d6b632f5e50b6ba84e6a2ca15d70939","addr":"ddaffeebad79dfb4df2e2e35d9b6928900d38179"},{"mnemonic":"cruel tooth rescue step entry shock uncle crash possible inform inmate such","master":"f02e38437185794196a7822f0e4badce8644354fcb5d03e337ecee7ca0241df6","seed":"6dc6d27c01e91879638ef2281c904f2b3b0df18b0231c16f1518b63b39ce53c59335cb858b692f50decbe6fce2617434c927cc09d428a98820563438cda13c50","priv":"339120a922594b577d1f64af46c9dddbe0239a1ebe0187569c4302c035df4996","pub":"023e91521223a9a95c1df315c36ae543e606f426e1dc0b4938b374af5fa4967fff","addr":"c5711e1ffa2cca8f18b9be910c4c31330b8d60d6"},{"mnemonic":"evil height seek edge session require obscure begin skin outer foster able","master":"71495c08143478276d1107b9a496ca0befb1663524e46ae824b65e979b14b22a","seed":"2d209c72dd757b948bae9ac1d69014bda27b76dc890be357f542d994ee79329ea51114a1f721d17751152a1bbdd5c5e836771902ec6113c716fa016e30309a31","priv":"862d6335c9d39a65655c3fb644d71f9e4a902f085741ea4df75cd36afb94b0f5","pub":"03004f2c4133b0ffd92bdb3fef5eedd75bf04b6e7e18c0dea3204989476ad3762c","addr":"5d422b55f2091fa9e350655b2e550d209489318c"},{"mnemonic":"gravity sustain speed quit clock cage cupboard radar injury unlock sheriff alone","master":"44e4470967f781784b98f1e33d8fdd16568d1d43b1de044541a8e0821715060e","seed":"6c58333728b07bcf95ec884cb2ccdae5ec12dd67c3442044f7680a87c47da325429bb280727efbd848ee7f8c5fcdd433da0e9de39b21acb66938427ef6ac47df","priv":"37a9522e106495f859db94f5b6efd4e98d49e352b4e82cb3fd6ccf03bbec4b90","pub":"024b03123748ed0b4fdd8f6a351d1ab6a7167396fdd583aafc15233f5e79e3134e","addr":"62994a9de9dc8b9c9269287b63d847e90f519d59"},{"mnemonic":"fetch uncover sibling unfair brass explain sorry wheat talk web news exotic","master":"1ef8d0946b982a3233328040bb94e8e8cd0d5fc24b345f55535a8e7a92c22b67","seed":"f5b3db4d9c5686aff4eef0b0eee3cf88c4ffecde0e9b1c6772d9071fa433d5ccc9173f2f9e95114b27a37a1d91869227f8cb46b3ba26323e237bdc7a2365761e","priv":"cbb0527d80293daa1ccbf26c5e8f117123a63c0adf772bb80700e2334690ae61","pub":"0271bce67767a922d141970501f7341e7ef0f5d877df908c0c06e66000b94810da","addr":"368f8cd8319772499a4f2f109d440c2e1ea55038"},{"mnemonic":"follow actor noise creek afraid normal exchange universe swap draft cake forward","master":"7a443b3ca6069d981559e8cb1db37aded7d3e25d06f2f5ad35867c2086ae4cbd","seed":"3189fb459fb30288ea67a8cb2a46eecd8854db40b7f5b828254997301dae372d05b3eef58b0c670b510abe11ef7fa506b74a4280be94ebc55dc891776599fa3f","priv":"17ea39b63689ae32dbddaa2bae52e8fbd79d725a6a2ec0b56c432a90a1036bbf","pub":"02c3460e957acd5e228400055e9e1b22fc5fba87b16212382ec78b6131d05060b3","addr":"4e981e57f9e23760cadf381d28eb56d225f8b785"},{"mnemonic":"pulp fire pulp salmon finish question aim unusual casino super label soul","master":"3041f6724fc8fd54913ceac5487cf0b2a1c95e1d2cc65272f99d1d0918d73c20","seed":"424b5c69d42e95405b4d78c60f8c4541fdfe0600214623631154e144cd2ffcb3d6996fdf8838a07947a6b08d9792e6e883820399429d2427eaf4ca3cf2311e89","priv":"19026cc4be5629f8580b7cc5f01e36cea0cdb35a933d9871324b53eb9e4d62cb","pub":"0355a17ad503b793fd459e58e7cd85e13724e155ad487d9bbca7e49f939a89d514","addr":"e26908acb2f197f61f0036aef79f9c2b8e67cbd7"},{"mnemonic":"draft clap afraid census image debate pizza display sweet square today floor","master":"146c029ef74c9c9d00538cb03e70ffded59641ff8cd695e44abcbd71dca0aea0","seed":"a000df2590dc0b74a6b1bdc868079ff3172fcb9f758f7f61e9963aa49bb9ef1715985f3b88b0d1b22fbe5d30b2fa0dc489c19ab2fa42c5e62734585b6b35f212","priv":"4e39817ee6a106cd3b58666b9bd419c246caacd755c302c5440f7ff8b59a3e20","pub":"03532d53d02bdc71b0ffab4f5dd3222bdd8b49117ea8c10eed11882a21d604c72f","addr":"4ca53567a3b12f8bdc8cd66b1338c3760cd9def6"},{"mnemonic":"virtual search upset mushroom bundle vicious soul fine decade reflect basic nurse","master":"1e7e15314e1cac1584fc5d6fc5609db315a3a63c1baa96afa57475c7e05b77c7","seed":"183399406bee3c1b8c11ec94a8528e0c26a7c22926f286e320461809f84976cf31900b436022acf4635066c55bb793659254c75d4f18d692a07e20026d409986","priv":"8a07be43ff390d981394dfb29638f2464bded05d5daeb3bb54a93ee949f2da36","pub":"0336378e1b67b1588c6d5e279fc3fe58115cc24dee0cabb5f728acecc8ac6be8cc","addr":"e12910be135809fb5a6314212975564422d98445"},{"mnemonic":"venture wrong wheat oyster buzz cluster abandon rescue alter frequent way scheme","master":"15d4683cb037b61ab1fc64adbff7bea44f515683352cdc3b7e8c6d97700d66c1","seed":"0ea9eba247cce6f936ca4958c64cd6f8f19c3f68914018ad61ef9042a4fcea4058f32017ecd0f672cc8ace9af4d06b59bf2064983fb4615edf912f73343a734c","priv":"47006c978ed707415ac9da1eba861546e6a6150170db9699b585648dda4c863c","pub":"02dc09d31bdae4560008e82db56cd81fe95b6a6dbb87020117a98ea071753659d6","addr":"4a5c5ff9661ef26136b09a8e6af9d6aae0188e2b"},{"mnemonic":"consider sorry keep source session simple solar acoustic crater model hurdle champion","master":"2c3331a974819d6f38071aa2c790c42ad7e97111f5092b00f972859867cfbc5a","seed":"e4f33149ee0eda7a52f5f64d1c8ea945058b2f3b2cd0a0d8a85fdfaa2aa0b559bec8bdcbdb5703dcf2ac54ba7066f4d6c95b03140680b1f1d30a6305e4cd0b7f","priv":"3030acea65637e530cc39df608f467b4df6a47aba4e241c7579a608d8d53f12f","pub":"0340b77aae056f3e3e7e7bcd670c05a3c8975efed4e7efa0c0932a48031a242778","addr":"5dce4e49e053ec6443fdc36f11f1f9f233644cb4"},{"mnemonic":"salmon allow rebel eyebrow siren remind mango round task ritual exist course","master":"7393e3b637917023a724ff52b1f651f39da8a0d860bf20cb810eb635ca348eff","seed":"657dd9b458793c826944ce50c00f6cb97877543ed7dd6b113cafaa7971704a8ca5896fdb5118aa09c52cfd6b28bced9446a86258cf432339549e31b3abe0e279","priv":"46c0e6f6d527a46ca2b44d0d6892dc6c816bc0f1240b10ab2ec9f33050e35666","pub":"02cc668b114070164065c79990db45a64e4bcc5052ab0ca65a68f0dd3c107e6937","addr":"0da2a43e892435f79c2af7d62cc823adfce0355d"},{"mnemonic":"camera casino cigar harvest prepare satoshi close ill suffer chest parent urban","master":"1f6eeefc59b6600a739364a6606ac2c3a151b4234f1edb6efb97da193865402a","seed":"44388f05937f5cb3b47893b75aaac78ae919e4aba29f0a6934ef15d6c7d1df6e5afe36743320856181b5f0a8bc02e731ca83fec8dd501c9c845a1f0325d74a20","priv":"e6492972ca82c2cd62006bafe541c0ad5c6bbb01257600e8168702de496f3e37","pub":"0219ea8444509e7894ca706edc46a522244acdd643bb09d3856db3d9fb1c9821f2","addr":"593e42b50fa2f4491c831039dc1b4489333531c8"},{"mnemonic":"staff myth increase tornado student scare awesome fever promote vault write head","master":"5ce65c1772d4ee171fc0e843ee7b6124868d25c2cee48eddc73e92b805ea2239","seed":"88c5df5805a91765a045019ad39767a4aae836e8c0f53542c661934c3791f94b9d35cb9b1fdc865deaa6f749e583176ef9f114774fb0b59c0637d1e66dd6694c","priv":"066f7c65cb33bac2ef5229764c316ed587710752d456881dab54bae2b1ae55f5","pub":"0263f5acf96f7e6c02dcf040fa765db8fef8ff317400344cc92fa3f5d58f19755a","addr":"fc00f9a09aa3316fb67dba9e08c66d8569f055e9"},{"mnemonic":"during smooth snow please surprise winter measure weapon bench possible write night","master":"0af6eee6b3acb361f5743fec61f7377ca5db5e90a303484e7f877ade8da1e0ab","seed":"104ab4eb787b2da19876c47e1372bef860de1535ed30deec9887075d8f2c56213647f0e8d6b472b23f5ab6dcdc1f97cc32ed2842a0745589c196883967f2fbc4","priv":"0eab899fad8229fc681fb7c86d8102d4074c68e6503c644790125bee07669d76","pub":"02d13bfe147b234f2a81e3e2ae0e630f6be4bd56fe44dbf59b2336c689024b771a","addr":"86a7e52857c14411ec4bbb6c850822b7bfc8b7bb"},{"mnemonic":"equip clarify march rhythm supply attract dress sell clean galaxy index river","master":"aaa85635e77e16d5393f4ff5c73b5556b36ddea446f41c5cc3fd4cf6da2f324b","seed":"519f319e5c87b49923ef60a172b731c50da1da2eca2dc130ec732beaed5dcf161c2c4c98ec20b539259862456a7ab2c5f63d7789da98dbcf01ed23a3be7c00a7","priv":"b42830645c0a8c5fb59994bb7588e8fa80b6a3b95ec223d459a6652a9f3bd641","pub":"030b9ba15ca8ae95d10eeabb8b203b6253c0d08489c02dbe255221c42b16ecd043","addr":"5ac5bec20480d7b9007c9bd184d064ab6b1c9c75"},{"mnemonic":"session hint oppose damage illness metal combine bomb cargo unaware gun artwork","master":"d6322887157ca3852f75204cb3eb60ff3eec39450913387b03ac973f5ff09ab5","seed":"09900b51d5c10504fe63272bebdec8c2fde49190039916839b106af4b7340595cd5ce7a6be9866df28d0a40618b23d09a6f04bb963b05ff1b7e272bd0f0beced","priv":"3f012cc4faabdba2abbb64b9313d0a574b8b31c1d22f403f1d344d87ba3246c6","pub":"03b4a66483e09364f2fe2d905fe5d0d897ca32752df20ddbed0206e383bbd68810","addr":"0bc20be767a401a01d697c5afbf331fd7b3f4acb"},{"mnemonic":"gate credit cage whale razor come opera net speed dinosaur fold witness","master":"8e48eb7d42fbc6c30601ab45da446ae6c0ac2e9b709ac428fe1f98b5c8adcd28","seed":"be8b77e358eefcb5610dae1b36380d25983f1aa458c208e75a9117b507fed28975787d4531cf87edf366c29798a4a6d8b44d6dbd090da8eefbf6d97477b64ae7","priv":"24ef322d8877b9f5f352f8063498527685de6b7d056ca7776dfb1ee34c0696fa","pub":"03389070a550617f89cf46c1df8269a154bd4811ea7d519445ac1e7e3e3f9ecbf9","addr":"45d1a0a5f79d849577106135f7065782e972ade8"},{"mnemonic":"belt girl tribe accident machine library verb link host wire hurt elbow","master":"d604893e69b68ec73d7abee4d15303863ae766b867400eb6cc0c771e8eaa4a16","seed":"ed3677dc17838f9720d5c574a6c70e80c185a5df1faebf07c63bd64a3cbb43818f7337469d48142df4e6d0254fa73e8a8105c6306568bd8e3a1fffd2c9d85885","priv":"cc6d78f6b72176d96a3425cab46866499fc57a8de3a49d5b30030378982911b2","pub":"02926ca73be56e04b363daa330ad51514595250d48d8983ddf29f74749c1a81797","addr":"00cc426c8061740249ff1219b322f104f548449c"},{"mnemonic":"kitten monster sugar game word lion census purpose defy rich either distance","master":"d697b6319c74c77415f784aaa6b341a84ec08eaac0a3bbe094d5cef9be94f673","seed":"f6bcaac87b81723ee589e635ff4e5a5606cd28113eab6846f1e7d5bcad758c1af1c8c77c111ba1cb502f33418f1436220a0a080ee81c5dfd012be5dfb0bec360","priv":"cdc283846e3c5be0b327e48a83fc72d85521bf51321697f281333b6eb7fa83cf","pub":"03711ad3d292efc08729a820344bdd1efb9cd87b083d0ffd65b49f998d1808e520","addr":"71f678f7808db66273dcaf51fe4875fb4c47c80f"},{"mnemonic":"fury tackle glory welcome gauge rely spice profit east science nominee expose","master":"b04bb080a9192b41dd7ee5f9bbfca1396970ba10c54faa1b7a511950b2ac85f0","seed":"5c6ecf5aec8669d62d5db9e39a5c94167bdb21e9380f8efbfc967420a71e0be1d72553a2b84bac9b8fedcbfaca522b82b7b80b531615b9658379c236cc4bc5bc","priv":"05fd2f8cd2ea1cd0ddfe2acd25e498ebd81b902d51935ad3a094a2f2c9c62ca0","pub":"02c4730d47f1976f2a6412681ae6cceb97b899c4fc514b67b9070bf236e906bdde","addr":"bf3e06c5713080e1eb287d2eadf49de120aae6a6"},{"mnemonic":"young chaos must mom ginger hard symptom ethics father rain join time","master":"d9e68439465f5375de6e132498239c9d0f67f7caf16cede036da3fd1c3905522","seed":"4101de8d7cb1dc3176ac0781e94594a37b894ebccdb9d934bac104d7b22bf68d863fae68df1734ab10302025e53357b33ceec095e59505a1461aa751ca77e5b6","priv":"e8512f2fdfbf6bc1e125323de28f9f35931ab760bfbb2a736f750e3bf116bba1","pub":"032f51ba96193a6e24dffa85d748ed2b86e3677112b22da1d6dd5e2d98f987f0c5","addr":"7adb4deb8d4ee9aeca2dcc4dfcd5d1dffd3a2cf6"},{"mnemonic":"dash ridge ten when erode certain game rural canal race surface envelope","master":"fa20b9bbbaf883069a6a282b30870bbb02c8aeed3c611dd3c931bc217326c210","seed":"276e9b97f203454480976e1d86d4abca6072d05e4bd5b1eb972fba03cd6698afb7212e5fd77ff84bb8e68d45c641063550bc8ca208c00604f609a5770fd69b15","priv":"1d2ddfd078682c4d3950ec841b8555fb37981313d0ef69a7bff16c110171f71e","pub":"03f0d1613f82a900455d6834f6a02e037e3d6d7fbe08b1f3a278b2a5958bd13490","addr":"b190466866cfab3ed499547c88af1372f84ab61a"},{"mnemonic":"spend echo addict brave reason tell valve emotion gaze seminar entire game","master":"3d139abc58b8022d8fb2f0c622531874064a80fb4ad795b024226420f30f8ff5","seed":"d9d04d4207827877636a1a077468d2396dcba6ecd3398cdda7d4c15c1365518a5131fa12caef14a2b23702957b282903dfd96df19419e4ecdccf7c38487a0c9d","priv":"cd5f726ece1eb6653950ae42c9fecb053274b692ce6a58a5f630716fc9cc172b","pub":"03e79f46caaa31bca56700d91cb366428839fb09d027d13001ae723461e8575bb9","addr":"35c04d25b3205e9cdb5283b94f328792466ecbd8"},{"mnemonic":"moon argue laugh point unhappy long bridge water naive suffer curve duty","master":"72c22a1d7ffb152045afab5ab7831efd0910c0a4796b20fe9b741e2a06a0562b","seed":"c77d143d6a040b08fdd3a085c9fa097508137cd801e480752dfc55f776179dddf01199050893ca833af63f6595fd60b4d14944e31cdea626ee30777b681ebb66","priv":"af0e3a2476271d7a31943b44dbe9affb5c04690c2f9e1a559674f028a8cdb9ee","pub":"038beb9938f2f7bd600f8b0b48d85ddb9a09054534ccab4e5a3cfc36523dfbdf74","addr":"a7799a4603c1cad8209f6de4cff709ffb5ad240d"},{"mnemonic":"ceiling mother twice mask pelican glue such giggle session absent sauce copy","master":"1ab59e2748679caf59d4646f51b8cd7cf27c9e62160bce71a2da081d57e90a53","seed":"f46d771930a5a1f69674aa4459b0120ffc52f961d7f05a4f0629e580e3027e9112b81c582a74f92a63a0235d275be17a3ea24e8f3d86d2f460142cc3c075f352","priv":"2dbe6c2f1f3389a29271ed7ddb5d5b6aeb44cd3d762b9c5949f981f130c096d6","pub":"03da1b7e3745edb58ea53dda791d7dabd4945343d471f41b706ef2159f4895b234","addr":"14a8aeb393e7a99b53cc3661717b6a550f4ca30e"},{"mnemonic":"siege welcome clarify bread decline educate off snap canal north glance flash","master":"fd57e9d99aae7bddc7bf2218267db21683280d1c1fcbf1d0713d35c872dab359","seed":"d1771068274d476b8e3953ae1dbbac392157fe72dc01d9c1cb66936f26b07fe9de52c257f1f8a89ad5677a786a32b231bd4415a7fd6dc18ebc70d53c16d91f9d","priv":"8d0c094475b505e3c32bba7ad6817460ac20c5e75e4d5d0899d96fb2dbd8f43d","pub":"02bb4a1051ab8df516ba2b5bf42a99dc1a153127312a81f93b16121d2c60dbba1d","addr":"43b7281f4f0495f6ffcc129e1fe90cf772cdbb00"},{"mnemonic":"total wood brief sail top stomach phone silk soon flag beauty equip","master":"2d3e2c155708e47a76ee013fd8bd3d62b17b467fda08869fa5b474cd622c7e87","seed":"98cb2c832f8a2e59601b5dd85c1321251fa576f5e8b9ac250d18e45dfea7a492c80918d864f32d1fe0f3dc24fa1b8eec3cda8bfc526d4826e94a7ac352edc705","priv":"5de85e11fa81b39f6cbd36182259fa33ecbdcf309e2256a1ce91500a1c28fe91","pub":"02dc14302285378aa1783d6395e45b37aeec4456845bb90dd2436a15c601abf050","addr":"bfac65e04a1d9f0905e0d0cf87ba1531bb49bbf2"},{"mnemonic":"junior side human tomato army twin tired mammal sing evoke tape fall","master":"0a491a1d250b31b44ecf38584c65a733e785d65082d693847ebff6f7b749aadd","seed":"65c7faabd749b66f9f16b234142acf734fdeb1fe7c9170355471c008a3224c40c5c2b77aaf516f91fcf17e73f2905f021354561e56ccf08a9eedbe51ce8e8fc2","priv":"40dc50171a806155da73f7c5cab57f7db270e225c33eaf0665c0067e1d2f7743","pub":"037325819201f9eea88ab9e6856d2e60f02c41d3a07c09fb7161c42e05b9db824a","addr":"9acab1c1329b243a5959cf716dc5f29ff1a9bf33"},{"mnemonic":"fitness wire sun minimum novel scare response ten profit breeze equal wealth","master":"0292d1ccab93ad054ee3ff95f3fde715cbfb9b896894b56193003861f4403763","seed":"ab34f068d14286ef45af4f3339ac19d8704d84a3f4af2c00092f431f919252487759c7aa09511271336b3a40f446087e7a63d1cd5603244124fb746160ffe872","priv":"39ef24672e90e29f268369bdab5aaf09786efd7360b535bb4846035b12d1aa27","pub":"03db46d9a6c338affda7db18355bf17ddeb8519a59e193bfaeab4fa522b4124288","addr":"c3cad6c638d4f7d0a75dbbf9fb2d170f79f1cbf5"},{"mnemonic":"quit present half acoustic uphold buyer measure matrix uniform black play vacant","master":"6f8c86f53dab7d379e621daa00a25f6123d43ef2452ee6b7c20e43dff1379409","seed":"bee800b88e86d04b9e755c63669dd4d324c0640e1c121427cd08d1bff6897fe622320644844fd06bc16fd9bd7b981e473cca7cadebf7f50ebe3f917c0721b988","priv":"6070835567461840e0b216338b4a08313cbc3d8e805cd694f379fa0112975523","pub":"0296271e75096d7bfb7393b449318613c522774e7b2d4e0eed6161e80a9376bb91","addr":"3885ad9e25c274d8e461f4b685ec921aeea25b80"},{"mnemonic":"endless blade swallow bird faculty group rookie betray crucial amused gesture pupil","master":"f62cc9bd1a5d26309ff51867edac4548f63e30630afce94a59d94d77f6df34ee","seed":"f4100b5b36d63b0a87ffc828277c8eb2f0055d2ef500b402572d30cc23418960b831c84566153155d33eeb8ce65ac191882810a1281e87c7748bfb592103582d","priv":"14125462458c4e981d9dd963e67965ee70eaf50af376daefbd7f89a3d0cafffe","pub":"03b64c625b503104cb0f9e8de837c741c4952140348cc5d7d1ff379e35ae37df6c","addr":"64d529a1cc4a11c305c8ccbe24217f52be17a69e"},{"mnemonic":"evil lend heart deposit index prosper mammal vendor expose sun arrow school","master":"d3402de3b79b24291822c2737da8e7d760267adcbcff5af52fa7c33ecf199acf","seed":"5062aebf0c68ec4ae51b8f9bebe4cdca4a07989ed9a96888205a84d749ca90f8d9f2c992862f7fdb4bfc3fb2c590431c5fec415abd9a2d4ad04f7504b90a9081","priv":"ff7fa17496fad3c29afa98d427186cd43fa9aee71e2a81d2640fec87ebca2ffa","pub":"037eb47194d9fb1e61a65e399d06bc7044d02097a0e5939581fa9b15346eea38ea","addr":"8e9b1eef983e035d41aa63ec276454a075c52db7"},{"mnemonic":"various cruel sunny human sponsor seminar stumble romance hire cabin blast rich","master":"25f93ffcc752c263058f195fa4b2f80c46aaa057b399de9241c0fa8cc2d3ec8d","seed":"89ee6d4b8a328ec819556eb043c769007e332ec4ae0309c6b6f82ed70b725e9ac8d64cf1309ce0ebb0053ba515f6e42d1273ac4d0d1b9008b9375844a9e1ed24","priv":"4aa30facb3367721c7e39c3052e7221f0a926a00d00898699c483cbeff39e407","pub":"0312c6e2800eb33da7459a510d02e0fc5c91778c115c535eb429c2c5797675e2a4","addr":"9178f5d44bc450a7a1fc5746d17440670fa0eda8"},{"mnemonic":"kitten rabbit warrior replace dolphin banana aerobic arena elbow leisure slogan panel","master":"28b0f611c4fa230cb47936546853fb9f0e13bd6a4417b5bdfba9c85eb80313a5","seed":"88a78a4f882820e729d42557ec5db0984aad2aa40f535ea33416b0b89d25511fe4b6e37cefd23acf1ab65eed77b0c6ed2e453a2c7e8d509311cd802eb267200f","priv":"3af577c50bf57b6f44686af34c65b683c305496d1799c7c0d9febf9dacecade8","pub":"025901819b5c97d505616f3d1b5be0923564d5aa627885851bbef7b4efbac4f95f","addr":"9898d22edfe40425e714b877a5edf2d9ab5d7172"},{"mnemonic":"shy abstract heavy silly excite response figure math travel use cram dress","master":"558875deb7ade8202aa21350c8a98aa64d383c4b8dc6315a5bc149823398c8f4","seed":"256d310717830704992b0767827ce796310b3f561f5faa152b97c6bd9ca1bd10505049005da5026e64377dfc9b9a23b8f71b2dd8e4ae0644055a04b650a721b0","priv":"80c1b4808495fc23f7fba2bf9ff39a4b084371807c61ffa6f6b60cc863bc8fa8","pub":"02268631554db3ae0b7ac58b2437556d91aee4c2ff2eaac5e4a3fd6ca6d96eb960","addr":"e1b0517748e58df2cde812d45c251492008ae499"},{"mnemonic":"tag aisle unit arrow neck knee border plug order decrease corn hint","master":"67412592e636701931c0b0723451ee325db3b1b7d63938c83ab9b4aa5630be4a","seed":"590e676b0362db643cdac3687e67274fc7f67a2f3a6f274da3e8629893b1f474fc608eb2928fa2be01b9760807055ba11a7ca4b52a28b2f66e05bef7f09845f2","priv":"1cd36df351f7dd9b4746bee1d59c42f12b21ce84b9979e39b3b810ba95d13e56","pub":"0217468adf9b7f74d88b312883787e6baadeacf6436986573371bf19c359ce047c","addr":"a719fcec68779b1f0f92460e511739e3bc704be5"},{"mnemonic":"urge order bomb glance dream diamond cute quit napkin swarm oil taxi","master":"e7c99156c46a51a308bb59a9be9cec9d45a55a8f10908f2294b4a35734c24cdf","seed":"a31e29edd9da883053ab020e2058d482cf2a63b39a7d99f47a5972820820d5558f24bd4d86470f1b8f6d1707c059e2353c65ee69e0e2924376f84f36e77571e0","priv":"e204a5c8377829edb3a8866e028294d6fa34c6dcd76d10cbd857afe41f9f6852","pub":"03de7949f7a90aa8f21731e2979b684c6424537283dd15881f31541f14a0837042","addr":"fa9f6d11bf1fe75282dc336ac24f790086794ca7"},{"mnemonic":"drink combine way human stamp code chaos honey decline reopen candy stumble","master":"902a5423ff40734c67ef9ef008e63a232d1c0e30a8b8b75d911a5e5c31be5725","seed":"c5ee4ef92fab9bdfab9e859bd603a9b293509ae3b99427a3db2b3eccbeca2b2d717ff5d5ce010db0cafcf261e6addc949bc3c0187a121e303a0246125ffc249a","priv":"59e235dd2d86967f6690fe2171eee062c5e786ea6a0060069fab9dcdea5bdeb7","pub":"039c4adb01d0bffdd50a34a458ee58e19ed81d3f22f740af2414594e42447c9de8","addr":"3ae7c41fe8a65e527a850a44a5124597f5e43f6a"},{"mnemonic":"will confirm boy glare draft hospital grit marriage hen radio coach cram","master":"cd54fa9f850f2e90ead19946218c1c03ba1491d1273f6e2e59816e50ad80137c","seed":"1ac5cdf381522c28ff90b993d3a3612e0f91c08b89b11c83315ed78b7d89e7a342621344ed75a7bb1d996487da8b60ffaa75ba3ef504814636471fa017f76b06","priv":"c63babfa6c2e301910bb8cb846259aa0062e25ac8523dee9449354e9f44ab49f","pub":"0272029d11d7a1998e79230a4e82aceadfbe29925639f6ca6dffd237b7c12a6867","addr":"eba6a2907bdcd422c68a04093fc5127ef2945cc8"},{"mnemonic":"sister mouse nose morning remain bike wreck reject flee depend foam oil","master":"480c68e256ac710a18ff386a76b2a3ca50ab4214a23d2e162fd473f40e48ef88","seed":"267c7df08090f9d95d26c130af19c37adeffeb28644cb449a39fdc2038a5a87341fc9fb78a91c9d19b8a4843146e79e57cae43b9d1d65042cdbdc8f97c22f02b","priv":"d6d76df9474b038eb47c93ce8bdee2163ed5906475bfe0d40b31bc19a501a2a8","pub":"02a70a232ec5b59daa30873a4c11a65848d6d90b5775e488b87d8829a368fcd2e5","addr":"dfdf9f283fb3e21240437a994ccf124089782718"},{"mnemonic":"mule parent ritual earn swallow visit jelly give sun family scatter lend","master":"946aee32749e7c2527a9d7066df275f6a58b4d979778f565e87db434a4d82ec0","seed":"919d5d8ecbf7c9ee555aec51c4079aa8a97ba7c6207be27a119b307ecf5433e0e44856f21808b1a7c65ccd7efff25eaccb445cdd3d45c682aaea9d8358fd398b","priv":"1ff4a74557f15dc78cbe8c3fe3b760c23c19c2ffa12e6fcb0c452fac97a8c1c7","pub":"02b880cd243da4622fd4084c0779a34c117cac73c193de6691cfb9783c23a13751","addr":"5157180c3b43d1127614fcee3c772b45f438a73c"},{"mnemonic":"modify puppy army pull trust icon suit submit fade game near machine","master":"5b3dd4912f293341f8e62b55d25a7f01debaafa1a8ae6d7d9e34afce8d534c7b","seed":"e73259b5532099bfdcf2196ba80baa86886343ed2a5a7dc081128e5d94232b52d3914a8fb9ee17fcbbdd0d2199b2febc3ee1fb430729a376f8106439d45718e5","priv":"5a502a6484aa0eb1f7d963d950574d1cc348f3f64b1064f0d6ae8526293b9f89","pub":"0279d6b5231ca7729c450b055d51f350ef370544b83d10e80501ff5063961ec425","addr":"54a6fb03ba980c6efeb0e4e6eefa8d5c06f68dcb"},{"mnemonic":"beauty fetch title weird machine section remove better kind unfold candy risk","master":"b9c854671b0922cd1c27f876e2bb2748e74d7e5c56f71b7bb24e0f121c312c51","seed":"223ad6102e7f9e49ae732fd584519ebb6c139fd5cba630b78d2e5872be280c5c68eb6ed3b5b09fedfde8cbf6dcc1624f3380ae464f1d30c2abcd8d8ff5157e32","priv":"9c0c7cb874257ee95038077d5fb1be111685c5a54c7eae74da353fc2d476766f","pub":"02be94467d1120e497f16254d1840c431ef8254eb6a0b1f8b6e63b9f482ae37981","addr":"1c3965d6dce5a86ed7e176420079ebd2f475871d"},{"mnemonic":"broccoli ring road spell bubble slush cable column boil wisdom glide again","master":"dfe7a6221acf8d8f8b29530792efa9ac33b94e352f64ed3244062651596b0b1b","seed":"518f8503f16e8e5810486d1ea5b70951fe6f17427cec5e7f68584d7c7f101d6670ca755f81501146f3969f1869faf5efc6aa639ce47cf1d337367ff2d5336358","priv":"b7c6e7af8ffb55f9282d13c51736270a9b488191d8e9a4999a2735d5dc27ae5b","pub":"02ad6e0ed23179b9a12019db3afda6555fb3e088f2cb91eaf53db823bb284e7681","addr":"cc65b77303a5d3d42de2ef404a05ffd8b0fb73aa"},{"mnemonic":"settle jar tag talent bridge onion jazz vote certain job high lounge","master":"fd3df0c73c84b19831fb4fef9b6e8dc4eec01c845c38276f369ae73805cd5bbc","seed":"6944f80e097b237b7eb501d2d6d735c644c7d9fe0de4a1d12665b27a1567d3d619d41a9a469622c57f2e7998af4f8784dc1bf30b715b6c867d61902103ffefff","priv":"93d91fee61fa1f6704da23dbd1ee4b5513399d1d7ad52c3a632d5e3ad5884895","pub":"0331248b1a2b3ac8919c5654220fd21a10d2f700b2bca6a16d94ab25cbf60631e6","addr":"8219e185c9dc66aa8ecef927a93e884494251762"},{"mnemonic":"say unhappy visit follow rocket bind capable lunar age erupt depart leisure","master":"bb776f6f57d90a587b76509d6788c1afc54b7a35a06ace60d7d627605e462d9f","seed":"e20ebb6b86a37149a20e0f07a637de61af6d37f76d9bd84c210c8c06f92d23e167acd0098be525e943e2c4e7378903f8b4572190ba1c6b37ed40fc023b355e93","priv":"0bb90cdd4f552b15991e6e9c1546d78b4445af65e60d6cc850b7d4f64a6406d5","pub":"0342b5a2ce673cbf8610f049dba20a0c7d92091b7df857951aca402e56acda8a8b","addr":"1af59207b0004314be04dd208cc2154e06476ed4"},{"mnemonic":"next broccoli cluster someone just you crouch monitor crack tribe slim cloth","master":"87d2484fa935339252c8b0db3b4604f42e12a48ea00d22abccfc8a4ae9afd60d","seed":"abe12329f69d107732e3a3eb4ca9bd693b1ad465a042530031d0cf79e4d32a42185677250418809d0cf7fe7e47e0deeb76c321a8b82060666d36f8a79d68d2b1","priv":"9fe6b21141e8035d253dd8fb9e6009ef14f1680f58629dc880b50fec649bc00e","pub":"03af8824d512a243566015275cc2a8af24fae7acc538fc292806c2c95688797e9b","addr":"02f4e6e52415b7e25431c0af1f43f7dce05b08b7"},{"mnemonic":"scorpion artist craft enough whale maze copy ring search sugar rhythm few","master":"8700b2c3bc7b441f6600850cdfa90caa3fa8e4aa6c3091d9850c42644187c053","seed":"cecd5fef8caf60fdbab007cdcfa920867c0057d0c65b55ee569577427914e0e3227ab8cea26f50c1596fcf79a88a521721257f43dd84ef1d81e2ae4a8b73ebae","priv":"8dbc85572bf9b0f91c5e4f1516f3056c6a3608fd78e6b37e7dad0a0a5e4f6c2b","pub":"02947910def2d55c81ae2fc03727c62440713b0cfbaa854f3c7e9cc5b8f245a2fa","addr":"a77f593385c2e978d99f0a6a3d06e427f01f1c7a"},{"mnemonic":"improve help region hamster then raven eyebrow account sleep cliff copy pull","master":"e479782ba4b1b4f605fe2e892c6449a91a03aa8438668e22df211275a5644c92","seed":"bd788f3b47b98d37521fb5d51e35d42489fb83e21dc4f0fcf55dde6c2e1b561b63ef22f51cff2c190ef8b18cfab7af33df8e83d14d066c6b114404ba809869c5","priv":"a2deecc348654217762f8e5a422b3ab8aeb07738a75c49de9a1aea6ec767f4a6","pub":"025ee0f9bd4bfb85e42f918e91294fd9023831385e73ed06aabbbb7234d1707def","addr":"b80dcc0683ebdefb2a30398b0ba1478de6742050"},{"mnemonic":"bronze fix prison velvet sponsor woman vessel crunch forward sunset similar wedding","master":"608887c856e38875ce02b2bb7e6899698cd395db9ca1e19ebdaa0dea5dbdc1c9","seed":"66a0fc313ac72cc89a85bd4144b69061ca1e65f7d1968824f0cffe10b10380278428af5b6a114d6ce2a88e3626dfae38133acb02096d0b6ba7b9761a8c4a0eac","priv":"47de7838c74b2b1ceb138fdf96d455deaf8fc2550246a479ff98aa706b1d0211","pub":"02202887af1c72f72abe2754b6022a163b2abe5ee9f288126dfd1756067b03b5d7","addr":"8756dc9521ce9ad5e22d2612657e552ced185071"},{"mnemonic":"fame answer typical zoo key rail state chest snap stove urge collect","master":"377482e11aac4f724c3a1f94c8abef488f1807e3ad1a92821d7dc3f6377a2c3d","seed":"ffb372372dce3d525e923ba290828f0b5d12f65b241d5e3c36d431c1e1b3ef737f666abffc9d7e60aac3645a8f385262f2295b05c42a4c2f8bcbc3aba9edf5a7","priv":"bad40853765d64cdc729c94aa5e114fae54ee014517dc5231be8321bf7d93266","pub":"025d64a940c5b4dabfe233b552e43239b69dba164eac66b48a36f4e06915539575","addr":"f67fd1e04384628a47a01b88c399b30df8e5b226"},{"mnemonic":"expand machine nice damage roast slam example resemble tonight enforce salon benefit","master":"2e9614bf212cb179d91a224f1cc36fd4dc0a5be13eb5ef3ec614cd3f5db5be18","seed":"97c59f53a69f280fcf28110dd05e7510fad1d00e26d30847bd1dda99324ea2efa8550e5504f2f2648fef7f9c03ec58b2666b94269b3b5bbef1577f17af22ad1a","priv":"bf9962586c0636a20519a0eac17870ed0fd09862d4ebb563b3f445a179873551","pub":"027eb40d841c1028b75f21d593300ef57c3defdc258d17511ab086988240619261","addr":"d107cca0ed49d72efdde4b9369855d188f37a65c"},{"mnemonic":"debris scatter erosion dad quantum almost zone off bless tuition garden phone","master":"706940b567f1ab966a5f2db1d3e5eb832cb827a89c5bf2d17e9f3628ac6f88ba","seed":"b5caeb5e19c5c3e1e7a1074c3e4f366431d57f5ee5208aad341020fd33b2be38c2a228201949b6812513b28523cd82594a2db67177bbee6472bc5528a0fc01eb","priv":"671bab5dd3060bc813898cbc63828aacf50819c35981793fa9dcbe26c3427dc4","pub":"0283689f70b17659b51e2a5f345ae95e3a23fcc69941a5a842e992167dd958ab7f","addr":"aabde1e66f358e648444fa2a10be7404f1d6094d"},{"mnemonic":"expand fence want silk inhale web seed slide pitch fever online puppy","master":"2f3f69643bf40d05ff4be223ad7f05f0942166b629b6bddfe022df650b52a235","seed":"025608f609aa5f6662cea4323e4a4fdb4115f68d8cfd903886fbd561bf9bea74ec1e0c5d871ba46a1821efc769b2447c6b8d8f242fa0dfec8546c814f97cd120","priv":"26b51c99c8bbd84af26776dfb9a244114a66929f24fb782f195267fa7b35bf89","pub":"028d38aafd513f554facaf66eca4907f01ca8c48807898b6e142b609e93c3521cd","addr":"f5d92901099f9516401d963a0693f4d173cc2138"},{"mnemonic":"pudding mean volcano leader grain general because hockey mask solve frozen canoe","master":"a7a2aa088f904b0c44d1a307a17be86554cd9862f47b08f58205a7f73f93a011","seed":"d4e9852e81f9162b8fd6d1ce152e96a52b70d59289cbb8382cdb7bcbea5e5c5b6649aa6a2d138343092886474816c8e9c9f8c198d77986d2d6f7e1476f1499a1","priv":"31535d53290a02faa05f04894d6381b6edddcb7a374b19f8940d4581f9582cbd","pub":"03f89337767bf64bdbbca6a53184c126fca28f7613f2668a77119f62124f52a0b4","addr":"bd54d3175097fc470fefd66c7e5e63e7aa28cb70"},{"mnemonic":"make protect hungry coach tail female capable swamp alley one nerve nothing","master":"f171811d3c1b278279379244f480bdc165f5b645521749b2bf7b5bccb91e64a6","seed":"f8ebb80407da43b794542cca52f76b053175290dbc00751dfcb4539101bcf34369f76f686642c46728aef4b93f91f5ed2896b2a102aa3cd45e54591fcd0dd919","priv":"ea4ce4340c0eb740a33fec8198c22ec0064d72dcd74f85405f6d7efd1b1d0538","pub":"03e06202e127c7996f8367bcd0b28f779207cf222ec3d5d4190abae78fee5ed57f","addr":"54ef6f20caf4216e10a99ed446c842e3e9d90ed8"},{"mnemonic":"royal behave retreat force stable law cabbage home episode valid similar amused","master":"b2d8324833e37ae4f1a9a70dc33d070223b6313fe60e31a0c240b03f644ab78d","seed":"2448c418181d981fa42c83da24dab9d73b6a89dc0f86f624992ec9a982ab04e84989ff541364f4a289969d458364eabb08d51249c55ea16c29c6b65b5b95d7c7","priv":"473b6c4e1192b52fda7e64be4c34ee0197604c0e4c918d2a61e98f35fbd3f9e0","pub":"023bdc3332835493ed0258dad839d90c8503cd7a2a7097893170c6498dfaa2d534","addr":"d77a39d95f6204755a78c3b996c7bd84d1dc6a42"},{"mnemonic":"major dentist hurt task dinner exhibit soccer disease bullet knife hair nest","master":"9202dd767a3b88e0162803d54fb1e251ae14be8337829efc06770dc83aefa0b6","seed":"4c2d56edca18105e69c59b683d76034ad69006170a595c5648c84237ef0568862d5f95873334769be9937b83c5c96881569f232dec873e3947bdeca6831b1952","priv":"4db6777136a67a8279bfca36d0531a93bdc9e6eac4496fc20acbf78268e35d69","pub":"02d35a568677e4be8cfa051c190e54af69f8124daf5f39a288bd7a0baf1b1b4b13","addr":"6b8223d76a499b98d5bed2b146768569eaa7ab64"},{"mnemonic":"ketchup urban occur rain cheese bean need august autumn clarify kite chuckle","master":"8aa0b8b32ccae13b15ea9c808fe3b1185026c52a9f3b39546b355aab66d7f9a3","seed":"c910c33e6e009667a3d64ef0d10ce9738ff80aef32326d27b8f82bee0abf523e2940fc9ac6dcc27d10ed602fb60a99409688142fc18a9fab36fdadb6d76f1693","priv":"4541e2bafa8a4b3fcd1c9b49f646b3950292e0e18c2f1accda6d53197aca0d02","pub":"0336ad51e9c8d24af44291449aa86d4cb798181b2bdc9a2a6ae6a7c857a5d72c4e","addr":"9a37a2e3c1b6763a580a3b2aea95cf237bddbc68"},{"mnemonic":"shift anger harbor behave icon boring zebra sketch kid human nature learn","master":"139db45e5f8cbe86f23952b1558df3924dc55126119abcab216158285a645f61","seed":"1cea92117d8c90c554ae3ff517be704caa5c0d16369f68eb061154d59fb42ab9a6ea7ddcc62325df2c63ba0349e73a50c291edc1ceb0184012b71f2f5892a4c2","priv":"638fc2fa201498e1d76356acb3f4c5b42984c2c4b8619b0138426183daffb725","pub":"02272782c09fd51800d483c408ade4509c5cb83573293b873663a8492c1bf6711a","addr":"020ca2c2be203a95c0f7eade606d9c27bb572835"},{"mnemonic":"chat grain wisdom yellow rough swap notice range collect maple actor genre","master":"57363529ed9e9ae59ed408390581f344a7b974d130b23fc1da952983604e2cc1","seed":"d4b51a786cceb10f907941092f90be911c3ae2eca9924dade05aec85218baadc6b8137e86f4723b7500189529bc1da0b4cc95d1a8553cada6beceb71b12acaae","priv":"6245ecb65a10ed313dfc02843ac8e848a17aa37f6c3aa64007ff0b54b591e37f","pub":"032c33f1bc81371f8e599fa64736879a9fab286469e271d2fcff6f97b1b4829e46","addr":"4e076a5900d2016f08628257ae798a102c007e94"},{"mnemonic":"feed good spring pulse avocado smile surface conduct copper chaos dizzy describe","master":"003488e5bb876fb831b5ced5126e5c85ff6f98203dce52820acb139e31859ad0","seed":"e71271c88e445005f5bab28a4ed6c9d46f41adc6b646870c4097252e6f01d51ff9720d2960c61b9839cf29b559232b086ee5694252bd1fd73d601a27d78f8787","priv":"7702987362194e4b70c66b9d0d330a383e2710cdf863e5bb472c31815b6d9fef","pub":"02b790b42543e16b9c30a23baa39da3ed1d48402e51920187eaaa6796767ebe49b","addr":"778d3554fd4323ae321b6fdd0d907d28a4f0a886"},{"mnemonic":"brick wool tired another milk slight owner year electric later because response","master":"473c6a0dade946ed832babc01cac18b33ed7ea2303a362dfe6671202448a1f2c","seed":"ef22617d9f1ed62a89eb986d9addcb33c98d3da5e205c4cdca8c9b99f6267e0122d86be0b5f60c46d8c9f4c569c3ebade2376b04901bf8bfee5de83f6f818a21","priv":"7df1f72c7a5cf60268e760c29246e6e43f8168ab56b9c83d23df9923a3e51380","pub":"03de70b3833b9be36c88018dc6296feed7ae17d995af5b6942a67bd39689129498","addr":"27f48112f2be720f42706681bf2e97de964a009b"},{"mnemonic":"poem rifle october destroy castle scrub yellow brown soon this share radio","master":"bd39615405d3b2c25d023095975e07405228878f004b48be0a32fba278394020","seed":"578f2a69d418ed6bbe4a7639c6094396821dff23d1c26ef1a5452e91164e142fdcea44d63ec2eaa8d491f7b3757147f371ddb624fe10d6f7bae502e062671100","priv":"7cb45a918ecb28afef642f002cb9627381e1986ad90cbbe54aebb118724f1417","pub":"02ad197d4780b28d57ca50799d59fcc6956b2bdb24c8e2c2a221d5cf65007d2536","addr":"09c81b6b7dc3d57d239ca18573720e063144916a"},{"mnemonic":"hedgehog october thunder frown game aware reflect art favorite elite urge pluck","master":"0f2082a1d92a2d2ebdd605f33eb470568c7d82d0edf73e2be8a766d060dd61ad","seed":"9ecc3fc4516a37cafa09405c306bf19f53b085088a1d1cb0c54bacab3f21d4edf4adcabfa616137753a427c2269d3b3334a952cc5f4531980034433e4bbeeb9b","priv":"d3e3e9ee84d32091f08d7fed384fe3ec0465ec460f90a2749c69883dde03ec65","pub":"03b5af12849876b7c9c0e64833ea79c5b58f4450e4d67a99a90b3c9ab4ec3c8155","addr":"c5a46d31f9e363e348dc4ce803d44a676ce811de"},{"mnemonic":"goddess wear mail poverty exist pole advice blouse famous inform wrist pelican","master":"8c09d67d7e8691a66d2271093d7f74f5eb37729df23bf98525874b6d600158b5","seed":"093b6596b4986195e484e2d8977c8bdc20529c58527d9181c4d4e993495bba922fad305d8d4f13d9b5ba20c5e375dde147fda5aea8accf634d522e488d163c88","priv":"b028bdd6652a16380c61134fcbb095d372e63a117421fbedc46754266edaf916","pub":"03bb1f45e672d983a8856631fa8193422820747e3f8706e55d761d94bf091d7d6b","addr":"528f7468425b08f67e90058778cfb1efc46182ee"},{"mnemonic":"increase debate symbol swap raccoon crucial noble benefit kingdom prosper proud medal","master":"eb8bfa1409b9b28fb7c826f884d7eebaa6203e7bccecbe133e55df59db2ab8f7","seed":"5521921a26a36b06e62a681e2accb9a1577b6342085e9c9498f5693ce6b79fae98b9addd2da01df263445b5e45d2b4db45621517f96b86cd43b0ed00f7797fe6","priv":"e1927e2b0769daec6f1e7af012f1a14d82d52b89bc83a2fb9d007be1a51be4bc","pub":"02d41fc73e6624af22813b072d72a1d31fd628a66ae61e5d191c374be419c4a586","addr":"cc942c7413a8ea0db73c6cd3e2bd4c5e46ceb395"},{"mnemonic":"upset dutch damage thing maple ramp marine leave audit ugly walnut cricket","master":"012beaf52cd1e042c96753770315d25444e18cc63446a4207d57c2287d6ae028","seed":"dccb359dc9c2c2000e0fc23e100ad2ffcaaa0ea9bc1cf036b14c9c1f1542a4f9747097994ec5dc4071ea6863c01b2a5bfd6f747faea05dae4c3fa03eb2716b14","priv":"391710f6f67f54bb50abc86e349b889d0163a4c91dd1727dd3a6ae0912defc72","pub":"02bdbcdee705f81a4764a8e62de4bf6cd26f748be843fa36acad975980c5ab1b58","addr":"888ac8af30c1372d6c243363f6a8d97d3874eb31"},{"mnemonic":"truck stairs excite range van electric alarm sing provide mesh jazz cloth","master":"ef39accf9d3261de50dc985194a30b1cea9a861e2e48bcb47b8ba4542f855259","seed":"088e1bc0f701ada0c35c77f0d17ac9cdc3fee9747410407a1748b2c7e72bb37f2a9382e1108bcbaac1fa2db5aba2bf34574f47fe46450aaffa7712e5fefdd40b","priv":"e2e2d2973b52c1da6098e31018dd238b02ecc1d22236e631ff9d3009572ab1e7","pub":"03bd54aaf28542c6d155ebd24c032dde7341005e69a5ef67c3de5138b546d9f462","addr":"246b883c299597436993fcc8b22d9154db9d8f1b"},{"mnemonic":"admit penalty clarify isolate decrease draw virtual rhythm trim brief vocal box","master":"4df1d8bb85983df8abb7af56086dd76becdde81861462889c5a0809a470125cd","seed":"4340047ec19d4f318596cbe510ec11f233193b72214487cf3e8dd90c11f1466004810ba433261962b9c412b22c98655b06421b3bfe73ecfb1bd95aae30142cef","priv":"965f07d8304bab4719f071d1e3b656165a70eb31fb57d5cbc27e03780416d304","pub":"02e3a67f5d360f10b1786406cd2f1dab2abbf606fa014502ac9a7bb56616597776","addr":"90c64758c772184848b10adb3f841f14c86096da"},{"mnemonic":"citizen fire fetch luxury tumble analyst pitch van sketch measure effort danger","master":"e3469c68ff7e9f4e68af468ae8be59df246ae039ab8ecbfafc9677d6fa0b3d5e","seed":"bcd37194bce09d9704926235b5c83323ca7a71ca1b3b257c5436267a1e14b7b37fb44ad7fae1b818189240e9006cbd920b36aeb204ac00f98faf9e1b1c2b7034","priv":"d3f4ebbfa161b543e250ef0b52c027e49548d5a36a8bcbd8cecfddf0f1ecf92d","pub":"038f2c2418d2a68827be4807f06bc9c59ca291b34ee5284e860abdeff90197d40a","addr":"a44c929bb81a0dffc76e8659a44f85873578c005"},{"mnemonic":"claw stage toy keep crisp memory donor surround bullet ball innocent faint","master":"1025d24a465ea26b933c44575b283057daa066d0f5f0e12c9411ebaaec29d26d","seed":"effa6fca939b041aeb89550f138159090189a0ab3c96fb9151bd3ef69d29b457946695331804e437353d134f0d069b28092f122f35e74eda8a2d643c3d1a0f31","priv":"a81c4bc682ef7609d7ea9bd370703eef25006557166b9e04e589083bd7cd65c9","pub":"03b4d5e3abb4a6eff0409b20d8a1a88088e591a6ac3e6e25fb66f172303f55e590","addr":"09e4b6c1a32ed0e0b671e0f241708806a46fcd71"},{"mnemonic":"rigid neither track gesture effort venue vital bike spend unlock special swallow","master":"33fb6294ade198c457bb6d318b2eae4d2757977af36b988e042f1c3bb42afb7b","seed":"58b191573da33c6a4d94b8589fb32f8c5af326f5f40ced92973c352295e71d7a07251c8b42355b0360fe3ee2cc42b3217fedb914ebc61faae8a0f8cfe579fa98","priv":"db272ba1dc7e8aef500e29a4acf750dcc6fd92e4ee2f2e4235e7f82034a1857a","pub":"039d506e2c16bffda4127fc073a6e1b43b2c0ec68cd6d86bcffe0f0c4663b5033d","addr":"5485fe5a806040bf059c1e0d90822b49d14a51f2"},{"mnemonic":"sun ankle door drift sustain task home retreat light say wash pretty","master":"b0a3d174b40c1f2a723e3a62f878c1d4d19673c632a19fbea460d4d0c35d14a1","seed":"63e84de6c5f71a4b9dd5fe8998f00d0f8d0f2bf6da159d82bc8fe30475d0e909a939d7498936ac183e8220acdf104aa5dd0f721e65eb06e99baa27e81314a2b2","priv":"7e2d6c88823a8effdb5266c8fe605968ce231150169e0174e140643780bbbfa8","pub":"0280cf1699ed3cd91a57b8520c1173c8e8ff036cf759d4e076df031115c67e62f7","addr":"c31630d1643d32f652d89791c5de3a4b671773a8"},{"mnemonic":"ball symptom nephew dwarf mango crowd radio shift degree envelope science job","master":"449cdf41d10e6dc749aa52839a9c23a74c41cc7be85bd76f7ef0ea8347a76db1","seed":"303c978ed8b692e5e334bd1dfd0ece8615af24457129e7127e2ddc69f783628cc48d0d31ab522ffb6e70761dafb755f5878b45579911d52157c37c1b14b900f5","priv":"f6d3c4eaf86ce6c5c8d640edd4a67ff7dc852b6fcf36918f2b9e36df710b2049","pub":"03b3e239dc04042dc6c83a8ee1973917cacbe375786c73aae74a6b46cddba54773","addr":"f0eabf6d01285343afba4b7005268ed3af052d90"},{"mnemonic":"cactus trend empower board street stick animal replace media unveil recall proud","master":"17b6f0a996810ab534ac366a8890f7618f372ce0168b00655740f9698cb8595e","seed":"6ecace1a5b927d3058a08f1a59bb8943d214ce5e48e3627be8995814640782de30243f5a552e5600a3e1c62b3a46edb558434ac56bd105e4fe23aef8a1c0e4f5","priv":"69bbc1e6bf17262180141a0b00e6c410c3ae5b10b69b20d6321aa3893250cd6b","pub":"03bdb7edf4aa8f5e6bcc5bfd6a898671b0fd687bdfd9f8101f4ca840a183ffb226","addr":"c5fbfa7d4e0356d88cbb5e5bf47a67e877c1b1a6"},{"mnemonic":"source note bundle laptop pistol business only dust bright govern illegal melt","master":"9e7f939a19be0a48a3d9a740d8082b968fbd41065b1f5d425cd20d73d327097a","seed":"22b6512400907bd050684ea2ef220c4bcfd35d59de2c4c5dc3527436c417b68cec186640ea1be40dd00ff27b13884cfe7146c84ee3d568b8f74272f0edd91574","priv":"3f378db3f2004722591ed742f0d802e6c4eb51f357c1d77180a777d083b2ce35","pub":"034c05a98ebddfc54812ccfb797a99f3cc09e525759b7f40746513d58ce8577177","addr":"d920c5b1bd40b6a0c3835e5d32a8c8d5897a18ee"},{"mnemonic":"pride mobile flock dash second emerge seminar theme lift motor pave grant","master":"786638e9248b3b0ed4196533a1a437e1db7c2a83908c71823e9a8cf720b71975","seed":"59bf3e8f03faf407d8427e9b53093cb3708192de0c979c2e0a572a905af89d5ac43c2d1c2480cad58c63e3dcab5b5679a4bc12a4341cc618836d15f27c2ca623","priv":"f7ca55ff74a0f55f08cd8efc515ecc69d9cc6bf2ca389a3116f906d641de1f2b","pub":"03f538159091c45fadcfe4ada5d2a1a3827206bb4fcb756b9573ddd381b39621fc","addr":"14a320df092aafa1fd0a5207b6408daf532072c5"},{"mnemonic":"obvious man chaos alarm symbol novel accident label engine noodle inject empty","master":"df206751043497e26c74fde7e068376bdc0771e3e06a1e8bf17209bb9e1880b5","seed":"2178b8972916ccef4040e2c50cc9dc039a6ef7f799f2287d8d16aae3edb6ec0a20bcc4798299d2569cf6183d7aedcb426dbfca1971aaa31dc4c202f40c906a55","priv":"ab864f86be6e1970df2fa336835986e60fb7040a2edf05a196eed2ea9ff42627","pub":"02c8db2bfc3c7377ba3ec38f9aa7bb1be7d70ed6b15d76d3d5980f983552ef6fdb","addr":"c595c4572aa4b833719c935db03afefc56c0edc2"},{"mnemonic":"client increase remember size asthma source evil venture column truly risk clerk","master":"a0f072fd237c6f30dfa920940d04657e19ebe30e3fee5b0ad8e63cfbb6256d86","seed":"0ecdd247615ecba50ea404632b4f8e2a6babe067cf7d395b038935bcab013f0581c69f2d07ad330cb6c7660feafe8b21af062b474dba193f1121a65f83b71b99","priv":"4b54d2f02c43241d7a45efacbd48616f6293629fc0b539487865dbef626c6789","pub":"0336182aab2751a5399b14e0ac2a856143cc679405fa55141606ec3b2a09c3b1dc","addr":"48d6d2441e609507ca554f8f79e4340f257565b6"},{"mnemonic":"latin scrub oval capable drink common hundred ghost candy avocado stool dial","master":"3c8762364ca16a70f174584f1f276df1c432e0b315e08cffb0d5874760e8c587","seed":"40991c77f0fe52213ce2ccf4844ee6587b3595aee4e79f34cb00ccd0813f78f0955ab8e40a5f369522f7ae3ba0290db31fa1b224baa6ec5a91b57da8ad2b479c","priv":"5242eb4e71fc9715ce4ebf1ce08fd81d362fec9dad2be045ee0d6687e1662df3","pub":"02344bbc8ab1313883fee563a175cf98ba192e8570963fb7c99bd0dbf6368fb656","addr":"3db9be587f22ebc28ae33b4cfa2c86124f450440"},{"mnemonic":"envelope van become minimum electric inflict denial thrive congress visa jelly play","master":"e94c4ca894e31aa091dfb2ef9d7733fbc67f1dd45e5db389a037816e4ae9ebef","seed":"01a5a19c5f75ec7ebc2cf0d96b7665c4c79efa0cd0b7dd5e21c2cf8954f5dc5b1d23daae831a6e18e5157c200a603fb2ffc87a068d1dbfae1d4443eee76a1f53","priv":"7ed896005729b7de5c6c56a19d37f5352ad6329e948c256f11eeefbe8c0c7dd3","pub":"02025c5b38b96fa00b506cb0360cadcfade6aebc6eddddb71dd6efad382b0f6b3f","addr":"1b7ef9f1184a0da787b1231a0f44eaf4035c3ab7"},{"mnemonic":"grocery embody emotion wisdom picnic modify opera lounge impose junk scare ocean","master":"8091cf08fd5f50de4ef91fbd4b9eaaafe8f1c17624fec94cd47de656ce0444ab","seed":"ced20dfaf3a902a7b71ae459781e5013d215567a617a2300b49dac4d3473e624885ba0ca8df6f13c91dfaa9829aaf06c4ffa9ea22f6f17826a1629a597519507","priv":"f0ace0c797c7f3a93bf1f9ae64dae516fad77d18b11c0e32b5d0781d7a231f02","pub":"023c38bcace9489242f81a74168475ec29531c58523f476bd068195d18044f80ce","addr":"859850c7548250084438b5829b4255ebf5fdbe6f"},{"mnemonic":"oil inch eight notice okay gravity dynamic trend neglect bag earth predict","master":"b235b5a4e01f0e64d68b063f09a878c8b0785b84c5106431f4bf9250874e9d38","seed":"96096619deaf5792701545255d539f120ebc2ab8c23ee72de058874b6413e51774b7c2b61be1b1197784fb63fa7e509374449d4c812e7c8f8bccc711c73ba703","priv":"7d05f98b2cfedcb506c68d426b298b3450445a1ac89a3407f4ccef1ddff8def2","pub":"02274745f11a0de371600f1ab8b5ddfab91372f044ceda14c968b7e5bd953dad37","addr":"098fced832e9cc1c962630fdd2dbfe262728f018"},{"mnemonic":"oyster ceiling cupboard quit today neutral repair genius pretty gospel dress rent","master":"e669becb784c8ef38698f778cd27cf0b55ebebb5828531b65330d51ea2b1acc4","seed":"af8030276cfdf70d129e66467a09321eccd9505f662865a4776e1f5a05ba1ff6614b37b54583333e3ce931c9d44378f636efddf5189284f5fa566d8db01801b8","priv":"c0ddfbada817464834555e46ed3eb3d50c1023454f42826463e71754b9e6051d","pub":"039f5c467338b3cf8ac16e6677c8242a67caf89f1201f0f22d99ca1e7beb9f1a32","addr":"53ff0701507c25f97dd1e6721b218184dea2e3d7"},{"mnemonic":"utility angle dynamic fire canal current level trash chase praise witness mix","master":"54ef0de540f88777efd1f3c37929789620eff87bbf98e61f9b2e0783d75450cd","seed":"8701d5ac962b68ab8c34092b44210cb9c11c2332515815223537fcab99909b44a0394436074e60285c7b306917c1165a2f281bca911798b23832723abaf18971","priv":"bb5602644b1af5bfa019f2f81ed0d2475c1492661e55c8e65d8d5e94ddb33e52","pub":"0314f5e5d817f2235e3a6fdc0e86f231825165777c69314de63bd88738e7e7ab46","addr":"6d596a5fa6b1818895ee6fac51915a489da283a0"},{"mnemonic":"cabbage sauce filter identify potato coil bicycle river observe candy maid monster","master":"4e834379e58e480e0cde698f9f8e47b3b6e698b4c1325a995504980e43689706","seed":"a441b8fed73bf3bf06a27aaac9355a79d645f0c7d5d47ec216a8d42d6edf97e6a00dc48de9d9ad9d52279ef26f34990581caaba9d15342935ffe857c10456382","priv":"40e878ef025dc6424f2822e38c7a906b3bc39940e8db21262e6bb99ef3de98a2","pub":"030e41c103c49d2e54e5ba6e40b1dbf04245dca7da0738ce9048d0391da872365c","addr":"9d4e8dd66b5e16369be39000c11b03fd5054e0f8"},{"mnemonic":"method surge demand ginger pigeon chunk because wisdom stadium salad excite stool","master":"b8f4a0a87e42871e927b2d5775fd212dbf911351c525b92f5742ba15650aba63","seed":"3844f4bc75163d8dc39c53cdd0e9ff31182a87ad2d630286897b35b39a14afc5e5ecd3be988c9754ef31f14452290ff04c84faddfd195a3eaea076e48bde47c5","priv":"db0bbe779583c012d78f9b60d6648b72d699c2e6b5e9eb90d293852553649a91","pub":"02bb40395d5649363ec19874f2fdc122bddd8748234c1c1ccb37e38468c6e9da4b","addr":"bf52f59b2e4f01f23b32f502acddf96bda564682"},{"mnemonic":"stuff extra hair depth angry jar drastic jazz diet olympic choose legal","master":"5e09c2cd0aa6504c4a2e8bea31e0dcb7f0b82f040567b681271493e35ca910ec","seed":"ce48715916de04f9c4f9a84e4ca25900ca0292de3a7217a42497c0bab2253693ee8b5425c40ffb2700a65a772e98989a2adf4329a93596a4d6695f6c7f236e64","priv":"7f06d4f3cac1e4b2a7e0951a55f78ba85aa6e6b03872dbc0c930086b8e8e25c4","pub":"02b4ba9df766e58ae8a5164b4be48159901f421b8e8f396593b66dd3a715f268c6","addr":"fb2f7eb9e28187a7b68b02b7f55b5dd46fe9ff49"},{"mnemonic":"leader now arrow loan eternal prosper myself lift limit capital aim twist","master":"8a4e78bbca5c37b40feccb9bf053a24ffd6d0809fc2b89440d467bc903c03244","seed":"25f1e8641b6095446cb3d7f94bdd7d81d92d78ef808b18c48050985564543efcb99f28b94e2e935d31d973a848666b95bd183e05860bd0950cdf0ee8d7e04da7","priv":"a2fdc724702230d79b0c564c34fc4e68e8a10c336ca053278cb3be419313e07e","pub":"02e2206433e526fd4fff47b58ef262eb558e79870c0aad14290d40e912ecde8213","addr":"3389c22a794df27093c11dc80b6096dc3ed0d175"},{"mnemonic":"increase month viable teach spice pause safe mouse allow sound access grace","master":"919d9b6fd918d7f223acf91ea5abd831a1a3568d60fd2e43f0d97e000ec77f47","seed":"f4cec05a2bf6a00a7079213c03c36d765e49914166f497d6e38a522b1cb43fe24260008dbbad00a10d998f7963dc8dc09fd539570f157c9bcff8248987d38626","priv":"f145657458462f994a4e972cbd42ef4de683da47b5b6f95b14ea417b39e702ab","pub":"0289419eb27318299a51fce4f0e65827d0426d72543fa2f05d0c5f21bef86effbe","addr":"cbe298ebb714dd583e7c4d541ec9b38c56710226"},{"mnemonic":"move catch empty dilemma only online ginger rapid enough turtle flee retire","master":"39d365c85d0ae4f31811c665217b718bdb90a4f2d328587bdf430ff622d019e9","seed":"402b62437898f76f87f3e080c3f33f1c6b8ebbb848efd467ee4ae5d3303768c57a15fb1cb03a6befe486b0c02733c5c892ed9878ea7713cefc58b7a616d7b286","priv":"7e54e61877b8413d06251167b239c1a6213ed23e79c1ec8da7408e23928d47a7","pub":"03d25f230b5d12ba142046fa80c23e51198987254bf7f7f8a009b712783d9311aa","addr":"173f71a2ef94e964185c474eb310a363241c4621"},{"mnemonic":"audit energy setup mimic dilemma amateur evoke tornado machine artefact shed artwork","master":"40bd9cc381e632be6f25b822bb13bc7cb5c9697b09d7ec725aa21e13cd3eeff3","seed":"721de71ee0b84620bff8de317edf7c4ddadcc2dfbf19f3cbbbf61bf26157fa07c46119cd2f8387d67fb0cfbb98f62a3e711053a308496a0ccddb944ce517d90b","priv":"825587d79a33405a3c7cbb8a25e89cf1b3975de3763e1928e02c3f4d0cc8d44e","pub":"036ea297692c5bbd85ac06ca8ca238bad6db83d1acdd02fc012325a1369df4447d","addr":"5e45e1683f7c34754771340ecd629014297b72ba"},{"mnemonic":"vast noodle pumpkin sugar time iron screen begin among orphan glimpse deal","master":"cdd2cba6ca23c96a7967d3f3f5739009f2fca93bda0a36b85bf7a1cbe0d8af8b","seed":"6288319e4e2c7471be7088e9b50db78741c1da423892da1bfa289bbc62d4a014a6d9b7cce396cc3471531342a61d92345a3b043224dd271ba46cd716a0952af4","priv":"1a746edca60363f3bb4118e316ac549be3161be28c4151c9fb9cd63728abede8","pub":"03cfc321906acb176564624dbf1855f00188f563b14f07075b1d5c7e4dc25b4419","addr":"5007b4c128af77e8dfcdd85a925044438def1159"},{"mnemonic":"evidence element stereo crunch romance trigger ten ceiling cigar wire first frame","master":"9aa2f09eb1b6094ab52e39873444f04cc682e60305e9fd4f485af27d7c6e85b8","seed":"9adc22bf0cd328df0f54c6da7f5e43e9abb4e9a607aa02c312de24c12d9a18f38945da0188834e149aaa5798c8594fbaa9109d47363deb53e17553f2edfcdd2c","priv":"281e729635633787eb40b08d43d806a5e2ce178abe659b37c91c6c073e720448","pub":"039e0c68668af7289a7ab4c7f9b24347f10d38eca095e991207cd9ee55bf61f0b3","addr":"49b25bd31b9fed1ca7e2c32d663bd414d6c3705c"},{"mnemonic":"labor capable alpha robust suit trial media bottom pig hundred verb hotel","master":"b3e4d6c6bd059bc9548d33f6ce0aa6674160ce38bb231fe354950aab11651403","seed":"e1470e44481471f4c947976fdd4fc9119619571cbcc90d0d419f4a8c4e1102f84246da2c2fd0c02bccb34a23708cb6bfc25b23972c03fb6a70f5018ecc5dd2dd","priv":"9a9501487f7f9844ba521b3ef949b12b30046e927bbd8054c831434a4309131f","pub":"02b25d30e144102b7500d57f3c501093f4dc8708afa3ee2c9d772d5672802bb9fc","addr":"49bc8135a631475412f0b4bb0db7d437ef226243"},{"mnemonic":"resource pencil other subway knee small shield excite forget such annual opera","master":"955fe71377d76742d6bd94d49457e6cb768e57517ed010648edc058f65d6ccd5","seed":"28a7a3080633dd2485cd88b9c1ffe92889eda9d33be7fab5b8aae3448170282decf20587d613cf06f0d3a7da6acaeaf5c9918616b4d22f8f23bb6a17c67bbde8","priv":"ddc57bfd0d27c98a1d088272ab481407ba95f8556f5603245466f4f2d83c3168","pub":"03065ce8033103d6fb42bb382a59053797beb33214c9d16f2b4ec3634cddf857c3","addr":"b0ca9d5f91fa03b1350a40e4ffa84e99167e4115"},{"mnemonic":"dinner tone antique away vivid lesson frame floor rent field monkey race","master":"21cde220eeac2883dbddcc6927f73423af840e675eca3a6cc82bde4a5cfdfa39","seed":"16c220be97967c5fa8ff2176a9e0d748e0aad37c8ad32e590c5a35ba08247e2176369a3561c5eb0cc4ebc9a3d65bd132e31c2640968eea822ae76c6c34d17373","priv":"13366b2855dee63a394c4ba89378a35b75ee07853c78765dd1c5c8927e52d4a6","pub":"03cea336f71a793319bbb298bb3c546046e69b6abdec405302739345047cde8355","addr":"251a5f4b01da75091e938d782ab116e0e4ac37e0"},{"mnemonic":"peanut potato artist define merry brass nose brief dinosaur planet year blame","master":"87c46a1f19cc7d1e59887f445dab57aa835bf116db621e9df97c5f3090517e7a","seed":"f8b6aa2a59e9384933e0a88c76c5fa889ad82238ee7173a41a57638bbc82e51e7d89c97bf3cd2f6031e65edbeafdcad5760cc6d37a527eb0372b03281e7806ad","priv":"a7e43f8b98838fcc06ba6257cc64086fd1b6d0eef12eddf9910181bc6c0ff204","pub":"02db3f433577482b62d057404b61d9d10f25df66b0742c2a3471d2e80380355cda","addr":"571a2abcef5e4f690174e2d81d9ca035742e17af"},{"mnemonic":"orbit have attract dove horn liquid social maximum penalty slight mind mountain","master":"5da625838972cb1684ff4e45326b14bc1d73164f82527934fdf8b7a03b9891c2","seed":"abd2d4cdfc5b8330f58b7757efd4fece7854e461e22c71be5aadd735c144a954594fd8da84df6b8db3ea14c5db03a6952f093346ae94b6495a8635e72e4a38a1","priv":"cfb3afed34d7e53d459cad8623401f0d6071d77f70a96c75baa511179ca59cb3","pub":"02e9e07cdc8d57e321593919431bbb6c0761910d00e4a242ecd85d0b99e9ad3f36","addr":"78099b6cef2d14ad8f3ba7db73bdc9538e382464"},{"mnemonic":"squirrel motion glue best prevent fault goose evolve shoot decrease panic very","master":"2fc7364fc6537a38839ddc9dd41e0e58b2e972072e92ab8ec9fda67360f2a042","seed":"78718bcb53ba532316fc641cbe2027fdf4ea649563b36ae94a95415b5923397585b4d10b1026cfc8a00069cdc02c7ea8c1ebe04364bd68066195c748331104b4","priv":"7d9073ba21f72f91ca39d1f13c05108dc75b56d3b09bd08b7b8843137fba91b2","pub":"027827c957ea1c98f76a076bcb75ab8faf534dbed44beb234ebe9f60086fcee393","addr":"10440fcf67f5b2b6f4e81a0b6fe267941b437811"},{"mnemonic":"pudding tooth market kiss exhaust donor tattoo olympic uncle child bean nominee","master":"34f62b6ae3c01c03d64e0041bd50a9cf7027fbbc0b0fa7d13d08908422f72520","seed":"4f02768404f6da2b7654bef1e4d35a42386bcdbf167d09212194e20a93070030eb0a471945248a36a8d062e80130008cc16a001ecc3c05a27db0aab0f04c6411","priv":"1601556ec13ac16d4b38ee73080065756ef276473e7649c713ea1ce69367c087","pub":"03382cbb99d17b144dec0eaacaa33d1cd2041bd30cb658fb97ef2654e24addbaa4","addr":"e2bdf4c0101d49df4d8aa0782c4a1fc354fdbfaa"},{"mnemonic":"earn shock finish ritual segment post then note dizzy diesel jelly horn","master":"309b4a016a064d4bbbbc220c0fb0727114b0b83b600db73aeb4347a04ce52873","seed":"bee7d3de1274abc8fc05afc839de0b14166b86f1ea0a1f2a6b6484f40654aaa7cc4574a14996812974b905da6eed437576eb7f8fea704afdaca3b146b761f0b8","priv":"a269a409951e783c280a5d8afb0bc232f303618b4d83328ee1196cf86f2d8f04","pub":"03b79d6727f3d6a0c289f2efac4938caa94ee57a36a3ac70e3f8e5f85f7e4f52e3","addr":"8ed4fb10d7b8d66f4244e83d7e6cc89fc75460e3"},{"mnemonic":"venture bitter tongue learn whip palm race pioneer satoshi wait hub genre","master":"e01f7f5ad0a782b56a034b68230df72cc8440f6e4cad89ea0bb9b81a71b430bc","seed":"b6da5129dcad44188c654c9c50ea640543b66c0c98edb29099770eb6d89ff197f5e9fbb7725ada5b3b0191a9cea89ebd8f35698d5ffadcf3ec43f6b92795c1c3","priv":"e3ca3c8028c514ecacde54c73338ef5fc78e0ab05ed8260d4a70553c68390bfd","pub":"03913989f1771a015b6594b60de23017fb31b96a740507873cee53770684fdd5a6","addr":"db8e914a36120702031b4498a27d6bcb8c64da8b"},{"mnemonic":"opera wear actual virus pause topple leave video garden guard obey item","master":"8fa7f1c161b47e625e351c775c662eef0d5cf9d9c229a780ce0adee5fb045ccf","seed":"be4f43f613da6e02ae174310181afc71462ec108601eab58d369f452c4133d14bcbdd05462676d872b7aabae01e7e6e22ad38261ce70a2f107ff9f42ace4411e","priv":"506a98b80534c824f67233bd1840ea968886a57ab500fc0521da20fa4f24fce5","pub":"030a5a585b4db663ea11944e5be0bbb630b6b1f436989c8e7128784f7f59676370","addr":"5ad5c8981762b720bf74b376205f69a91c6f3cfb"},{"mnemonic":"captain tray course secret betray bag disagree boring umbrella liquid door memory","master":"b7974cd18de7e9e6abe2280e567fc51efaf3e80986c98901ae2ab7378eefa08c","seed":"3a3c2b0e7b237e37e7c92c12960ae5b8856a8a5795386d243c6d9eb7dae1b98170489c47b197a794e8f9ed0c323bbd722ca052f76d3cf1ac04db5f7ef6bf5b26","priv":"a13d741052c66e487ee376cd392096d9e56db28d64001cdd807427678b765016","pub":"02fac937135a8b0593c50d06a7b113c372d8c9d02a338673e3e07f267725536417","addr":"e5d9166b331f86253444f3198f707a495055b768"},{"mnemonic":"dizzy guard goddess trouble absorb pupil stove mirror nose couch diamond must","master":"d3bdf420266d0c5824a621cd631ba014a8ea614b85c628cf64bc3a77cd3be3da","seed":"485d06d18708ced0c344c4025d93cc194f7c63e2aaa1d19970a96db8dbd7e2f802d39d319338b0a92faffc2af408f69f1522481fbefdcbd3842ede957c663b0a","priv":"abebb4b15d2d9e3a3dac2afd4423d5da2b2260da49bc45d44d014e8d740ba064","pub":"02e39342b82a9b4bd73b165ea9b309e20b0cf9c8d5ee93756cf82ebad0b00e0cda","addr":"19f6fda807d1a0f99fb730923277d4f36601e2d5"},{"mnemonic":"rescue drink absorb brief unhappy rocket subject receive green echo marriage cactus","master":"a6ce8546f2cb2a62c573b3bb5b1e7437f70a44b7cddd7171a41d2c4c3dccd641","seed":"0605b45920c5894d2d351c091c7c31af1b6f0d77576f73716ac96dd7a22dddbf42155aa19bbc3c2cef3c757ff25c3e7998d0ca536b696a498c9a206bc53e8ee0","priv":"00a6e55ef1853ba31f2b7e76acc7e04649a1a2037a9bc33c74cf82261e956ceb","pub":"03de1a877576f6e77bc06a53e7b2c56afe7b58c460341b74c469e344d2b87f2e62","addr":"a4014c9bd6c662a6d4b20cbfc0524e125a5963a2"},{"mnemonic":"destroy naive mother audit tackle coral crater sponsor viable clump bomb bargain","master":"c0cc3cb63a702200dd06ba3355314b332385c3a0e1ba73bf428243278825a6e5","seed":"fdb9a430d0fce5ee93e6b0ec23506f65e76cae8be1f773605af71687d2f9fc14a9a1bbbb769a5c38f654398024159b48de392cc4a88e29030f4b7699a3ed6824","priv":"8b73cf6e42c216a7978f63a28abf839d0e2174cb10ac2abef6870c9a8b938462","pub":"033257c04174083656be1bee39ddf01b34aaceb538ee86c7df35a9ea4b3a3c282e","addr":"5ced7fca93a8e097cf58cffaf7c89141cc00697c"},{"mnemonic":"paddle image cash sadness barely sport employ slab keen riot solution switch","master":"be10364b52d5cdc0b8eb51215301e8468c82498f0d7b2de44013d382c0441e80","seed":"138194b9dbb5c35fc66755736c385e12ea8783c3208d85c58bc140a5edbbd709779d4b42a2c56b94d82b5edbb9de212f2eb315edeb20a5725f3c24a39ca50f51","priv":"06b0b15085f8af9cb90eb081a7b73d4f8b781467926c2dae68a0d300f2d62a71","pub":"0286afa72dc5ce3416e8996392d0cbd63a0f9b9d60701561d3596a1c9d5fa18499","addr":"bbda492cb736571a6bd62d8f5d8836b0e0c761c9"},{"mnemonic":"gossip choice orbit insane honey hobby split exchange uncle wash tower lyrics","master":"7b39b437bb8d0b66c3989df6debf35846dac9fb69d2f570c4738afe92a57d708","seed":"d0897a14b1958fa31a898e38fc95b6dbb2a9a5019175bf8e503149f9d1ee4958edce3f1f570c3e015b797b475f5eee882ce54f68c7f64e310571e0fc6296da62","priv":"816f5cd94acd51821291561d6aa30951d89221027418ca697aa2b621f733b2ac","pub":"03d4081dc8446919e4a949c323b4c8d6b76282325cc7f35c18791a57200577f082","addr":"fc5a9ef94fc8de5ba7407669ce04d8190864252f"},{"mnemonic":"ceiling shed aim oven emerge year sock achieve ask melt endless lecture","master":"ff1480b11529ec8240e79bd9e35275e1805a3e117a60f9b6b22f66715b4258e7","seed":"1aa288b6bac68936d8d2a89396f5be1659a12fc91a9d7edfbb45446de8bb39327044b6ed7451e820317882f162560fcbb134449e85d517a7f0eace2da2cec272","priv":"216833b820c607646ae504dfa7fe28b364741509047b89eeff48545fee07c11f","pub":"03b3c3ce98ff9d2340849c220a5127d8ebe2bfd320c9db41e94f57b4e067eccf0c","addr":"78e3043b376112452a22ce49f6647a0b1d20180d"},{"mnemonic":"deer defy door jungle sauce summer sea globe crane abstract minimum diet","master":"f7440871bbff95cea261708c1cd06220a5aadae4a86c00f53b6f510a50e8ad56","seed":"a1868d8a30b498e1d397838821bf762c5f448d3d8fb68bf12cb0e2e26cc69f95be698efb101e76ad6ab84447c0c2b2170fb2b201315f5e5023bed35490f43986","priv":"b64d5f61a5503b366e7296a5b060e42d5db420e4bb8c4d0248c07ac25d2a0b60","pub":"02f4e32b1b8f2ed1b75ea26def62a6e69c7cce521788bdc182663ccabe4c1da4e1","addr":"32a90701856a1d942f58f41f6cbad21a64494658"},{"mnemonic":"position course virtual distance fashion oval slice round rely key spawn shy","master":"255409af8fb802395b9433c062310fda250cf8f9df7d79bd16381a7ec7b4d27d","seed":"1dcf6512b003b07fc299098ad2b8d4ab3eb1be11cb8949636ff2dd0baa0081ba78a9fc117ac65666c0854387ce0adbb903b482b85a20b9e591f0ff156a59d30c","priv":"a9157f3dc6ce3889c4d8dd4d2434f0e080090e4a0c0c75cf58bc03b41ea507a8","pub":"021b68e6fc74dbc45d326f9d2c7efe9c718e7c3c1a084e92c1f384c273b2d41513","addr":"21101638d066b561f8c43f6e9061f3959e3f89ef"},{"mnemonic":"model absorb cart athlete helmet next hen indoor involve ladder engine tone","master":"4221074ff1f662276f167017a5d43611b1d6e666c0c5592a35c81d2f5389c93f","seed":"dc9672d8e648fb4da6a5de519d08fb677c0d583a988701f2ac57e1fff273c3c832d31c036fa36d33b029fe0e92e8bbae350c6b96eaec463588f1ee04209add53","priv":"c4662a26101f0dd36e56ab0528a3861547015022b9e8a30ffde845d6207ae8c8","pub":"0285c5ad35fd9063e8cea4d034628244e790261977eb0225d4da90c5a2d11ac25c","addr":"8fc4bfc728a5e5fe2423b8c380aed1f2fcf4d2c4"},{"mnemonic":"armor happy become inner fossil exhaust upon under offer sheriff coach huge","master":"154c74bbf5601f7fd35c183e77ba32c03eadb2fea62563d2221199cc694a5fe2","seed":"db7910b6fb6f406f146f857b5c116033356cda61099165a7b1f782b2201878f9a4104efa15c2bad266db1802f9d15719fdb9953eaf3e245f0aaf9f5b0ff8d296","priv":"ee1d3af46fafe868bc1a89394c068dfe05cfcf7578c10bd57750511276e829db","pub":"03db053e44816be4562be9df13d8ee1853c1336aff0d13cc516b0681521d96a9af","addr":"fa65a0099684906c758eecf10f7a2b6dda7c5767"},{"mnemonic":"long output ketchup question hurt drama bamboo globe manual chest luxury abuse","master":"b180100cbc124ed4a9812ab4ff3c632bd7df77209598d4b26af9d31fdb8bbc28","seed":"61b7b436746323085cda66fb4c0e21079e849bc4d2bcc67cbcfacc97008abeb7ee57c2ce751e5c63fdb676f0cfec68442277d4a0e5db1ecf82236bb2f2c9380c","priv":"1ed983d1024d453e2dfbed2278c3c8ea3abda96836db2462da4738f20ba1d772","pub":"02f9d9ceb9a27e4626d09331f645d40464c99975ab0b7344be3f6cece6cc0de8c9","addr":"d092b8b49065f0698b483e416f4b1b032b416dab"},{"mnemonic":"ecology over output enact system curious want oil denial ivory hamster approve","master":"f304cd809c371db0fc37fca212810e75134773494e5c1d20cd22753399ee6433","seed":"6693bbddb7e758825bc3c2096108aecca0414cd1b523460a14c8dd80c15b27f5f37cf4589e710a39fe663392874a6b17892fbf473da8d00d86af17aa19ab0cb4","priv":"8b13913b6f590abf399aafa87fec44961218fe45ece0f9ee8b22810839c46e5a","pub":"034738f122cf61a102148156d40aeb129bc4c54fc55c5b85462917f4013d7e3024","addr":"1657b328a5f1ddef43968178fd8034c685e9e312"},{"mnemonic":"uncover climb join country march border rack ridge track true master useful","master":"b1f2471d8e6e712e20343f06220f847caef645d9cd9972ed17684b3a44b25de9","seed":"431e56eae671e0f1ae12aeba623fd4ed4c7d3ed102588d3b39b3c0e20c104aa24a435b9ca504799214f95b7639e208dfae17fd866b2f58c0d916cd744b7e5424","priv":"1b0e22bfd60db8880827761411390dec4799efba98348052400deec1838b04d4","pub":"03c6d27aa4dae3b3e5754cb3bf8c4638576f113876cea4da0d915964cdff0cf7c8","addr":"0056ae65805ceceb8c17c3c1246c5f70dde2be6c"},{"mnemonic":"rally cool artwork leopard skate battle shine text ritual rookie sun way","master":"72c5b3c5022b033d71c7abea54feea3d3b37dbeadeea5db4c8847a7cd0e20d3e","seed":"d7fdcb354a8946fc3449107361e4bb3bfc569c0d3617b450484e5a7fcfd5c690cde3a511415e08be23672789d090a3c679a06be36a2a20204172e1d61433268b","priv":"dd57130e658e43c9adde730ca57aa6d43d31efc3697a752075a7cb491a7ff390","pub":"03b7cd7259877064b403af9a65ebce47f210141356a67efee77ce456d46d948db3","addr":"a8db1e5ce299462e4943d0eb05c146591fcc3297"},{"mnemonic":"room vapor anchor forum stage corn credit jelly level cat detail auction","master":"fd531ed5d65637f6031aa02ce031cdb366bc8a07b00fce1104675d1a653e7995","seed":"f42ae529e339d9b204165f2b5556c1637395d9598cf5a59717d048d7d5abf831e60abdd457f3432ed2ced4c13a5a73625f716f235d51bd7892cc16c294925cd4","priv":"c2342924a2792e7c4bb8523045faaac7a669fdd00b2621bd38077f58a32bb0f6","pub":"02df2b027f4597da0a2e8f46932929044dbefbcd5c5ee38c2147dc1ea061dbcf8c","addr":"642b32cbc358915bcb802eb30690951710f597bb"},{"mnemonic":"have offer number egg canvas uphold memory snow know orchard cause wife","master":"8ff4d3e7e6ff972e24682d1f1116c7b83bb94ca8cffed1db9ddb4adf89e2bcb1","seed":"14cc60691b49b9036c0bb64ed24da69478e01deb36184f58049d694ccaabc41d95b1e6734d9d06e7009c394d54d80fbd65cde6ea49165879dc306c0125b44681","priv":"c57093fcc3c593fec4002a9040d90485016346a9f4f7d896a105ac268face5ae","pub":"0252fef0dc82142ec121c4b01275b254d6a78b4600f417dd0f09639fd94a23c0af","addr":"af5cea50c72de4e54216fdcb9334a5f5a8a0393a"},{"mnemonic":"garden nature witness stable over move among pledge woman cotton worry behind","master":"48d57d0dc1abbb7142aad3371d68c41ebf078970c5fdd4bfd7294fb6f8d32b45","seed":"bdca43aa42eb2a34dccfa4fd48202cdc386454683850a12e7eb7eaf9998ebcf57a01a6fb1a6b9cd8aaf2910b160038fa6adb42daaa914c7628e27f912687e52a","priv":"63dfb6b77a4286875868db4877a3d0f3f0ae8c2766b9c5d9225f48071421d832","pub":"031e57ffbf90b85823505710bfe5be2200f1d880171e8480494b50a04462b98795","addr":"a7619c6704a7341472229bb7ace1709b88ddf175"},{"mnemonic":"pizza sting refuse olive final hungry kiss abuse nature junior opera tired","master":"397240e78b72dea36dd17ea2ef3a15f18f8fe64c9e31a30687d2fb013e1ac6ab","seed":"1dfb236c6bbfdaa74b02300a0da7b2d57a2fc2f736a5144186cc89b6f20a23d74ae59338fc04367a27e976e41f1d1bfd4232a3f386cbf74220c9d0c6fc5c7077","priv":"ae5a8c5bfb71adfb89055f61e82a6ef5258f6bae9056313c360ea454bc30c052","pub":"02756acc7cd398fda3d485f6aaa15e7e4e558be8725d9766119e570b2b64486372","addr":"c4c6e359acc30099a524b67223da51dfb6557de3"},{"mnemonic":"deer easily marine thrive author despair puzzle super agent life rebuild soup","master":"7efbef221b4d50acacbd20a10c1197727e9fbef29bf2418f51141fb8a5368618","seed":"2ad829ff702c19a138945f61d1449c32d6b16ebdfa34350dd434bca3899b6eec3f66a3dc8de7243539f7d6d07f85689a66b0e9f6481a4767a5630c2c693c3ec5","priv":"b6321fb4900455eb1986073f5f705d088e795d26ec53c09b6eedadf439fdcb6d","pub":"02e9c7d430122627396412df161a58813327f436bdaba34f3e855263044e1fcc77","addr":"47f0fa963518339112a65e54948c5df8c23daa72"},{"mnemonic":"gate calm appear symbol make can alone wonder cherry couch loan firm","master":"9a727a9574790f29c890079fc9e83b0bfeab84d9e79ae6b273ea8266f4a754e8","seed":"f37c4b52afedefc86a24bf4edadf6a2f151aa9d503fdb3da440d53134fb040f7ed60c29407e4b74a0714f5fde8d650b93d71da52568d0e9b2056412092125c76","priv":"41e13797f2f7c41a44db247f9da73e8d7893c2be4a689fe558145f2bbb88feec","pub":"0242c6981834d9c7a14b96c39c6f902ab0a076e4a7ed29fd7ea559aeba3727da4c","addr":"dad747d0295dfdf151b6267e701f8d889770b4ca"},{"mnemonic":"opinion spare hurt three insane sick place sphere ugly sad mobile icon","master":"e6b6704a86504c2552e7db9928c6333372fa5630983e5a9aff32b0ecf56c8fc8","seed":"bbf2fa3760c82ac61467265053828c9cac4bdfd8aa43ff860ce50a094bdc448468fc6d0e6c53368e42b95aabe4f0098f9af46018595badb4f8cbac787d5c00a5","priv":"496c6fc85e550d78a931b51e6807dbfe843599401dae033db98e308430939d34","pub":"037ed7cca0717526969db9101c62cfa151cf97544ae66408317fd798d705a30138","addr":"a1fc3fc66094cabe3f7edf5b630003a524bdcff7"},{"mnemonic":"include relax onion depend animal stock essence basket local result rocket panic","master":"5830b22230ba22060e22bc4ee3323c8b1e02e5f53caeaf90759f4e846720b3e2","seed":"8fc74e989ab5b4ae04472887a59bf89b501e1813e687cd27a06bbef858c9a63b35531864b177d27841abe4999a7b1901d95303a395f5614a176667abe8aefab4","priv":"99a7444212b0176324718171a318f74fa5721fa46ed18b3677934408b30218b2","pub":"0213e7320395ca9eae0bd4f550f7f5f65a801066c12d95c3f9b443556011b13944","addr":"a4087ec7d05b08362bab9c8fd9406ab3bd88354c"},{"mnemonic":"cushion hover joke lottery gym muscle drop scare purpose share food strike","master":"dcc4792ae42c425fe278db48211f6bf54551f9dc58268282a5a61cd620832d4b","seed":"0bb05d59704318da60a1697d09562a05e4133fbb8f5a4750f378f65a5f0d6b9c0fc668dfe08673d6b10bfc4557250759c9f70aff9df1a5418821756f4017dcd4","priv":"741dcf7d371948cb17723b1b58759d8a0520a341a29d581abd12274014e945cf","pub":"022dd390a8c2d4a826ba8e725f54f5ba65438c97519537701001bd7a68eaef91ff","addr":"931f12464c90ac2bb3b25fc00f13c56ba1c49679"},{"mnemonic":"point action veteran fragile outdoor vote timber cattle cube deer fade razor","master":"ed95f0d3557ecabcc04fa2160560dde68517d4fe7ebf88584d0993a1a861c6ed","seed":"886bd48b9c9e337480538f1119148ac4f0a8d00cc3ba17a34cd7076bfbe85ba2a1a8f410ca44f210d9cbf6751c10bf15b6f52a725979e613f4294813bdf173b8","priv":"c489a82eeab534dac53396b71dfcccdd6880bd441b89386baf9700589d92f169","pub":"03e2e7deb2c03412bb42d4b32cae6591e4e0db745681900436999ee51ef422cd35","addr":"f9f93bbebed5d2859f83fefb58bbfa5f93032837"},{"mnemonic":"ozone pulse whisper cry ordinary benefit enrich cry name bargain muffin case","master":"ddea83ac1fba7d6c79dd073d29c913a767315bbae6c3648617b7fee73a04595f","seed":"ee93e7ea1bfe194ffdf6b0f70c2d5b5759c223620c01647fabdd1e2a94575a61b211b301cd6d4e979761febf15336c9bd1301406e338c9f6c0b8b938863c1cb8","priv":"d344fa49eee22f5cabe1362f36a026bba1b0419c126da13c6cf335759a962d36","pub":"028bb9fefe8418dbf0fca6857526f286d9db3321d12c6a88ffe8e2bab7004b4a29","addr":"b9bbd7d328f0947669fd1c81cf8a842a721206c6"},{"mnemonic":"huge afraid venue bid visit decade hurry put swarm couch gadget book","master":"8755848478c71a1c3345cc855a10962382a6c27e6c639c4a4ed245bf32bbb2d8","seed":"b04392d13e629b759aec3c28ac4cd7eb0b7b846f1e241eb79f862d6c30e79f3a5cf5ed26abcad0dce95ed6d639e8088c169e49bc20df609b5555b0bc3f3e5e6f","priv":"f3ab0ed871c3feb01ee18fd374568aa378651815b6903a2b42eb43dd70edb9d3","pub":"022d2a9a829f992b3d16f9374b6a6946649630bf553c8eb11208a68acd03ec3c7e","addr":"c61f53c2b19de0ef11583048fd19404473065bdf"},{"mnemonic":"update ring situate blade term enough evoke balance absorb pupil wealth era","master":"fc22f89a860ffe871a7a45557fda9f38369f99103e02a2a97066517190d10e0e","seed":"d18f179ae9c4767501a8238182d3fef3f24fa3259d41a07b601179f67fdebb6b47a78ddbb056170c0bddd3e5f5a884a3d4046964c0f4ffbf7b37c3e6debeddbb","priv":"32a6d9270cc30fb5bb11411313af52a3359249c1b5b38b753a83ebf516a1d21c","pub":"03a579f47d1d57202e02e7f445d68d6915a3304b256cc37c5d474e699405deb613","addr":"8501c773ed9240be9fb0f83ac2af1bda6511b1ad"},{"mnemonic":"horn coconut protect box cargo switch ghost among energy easy deposit fly","master":"df4a2a6d35731478a3dfdc0e1595486bcc245f83214a974b31bc20e2c0e637c8","seed":"454ec603e16c8c5c522192885768d941316f0736929046aacda1a93ad1a658e70c21a7e924974583d63567acf26ac15725b1148a75522c6bb26b37d9f92fec22","priv":"447e4c3e530ee519973a63c6ddc63b9e5a474761eae12e8c1fdc6d0cea806604","pub":"0359c72dce4c6c9edd2774af06545c8996e4832ae35cde19fab2f7dde55316de1d","addr":"5a49f88b1672cd9102caa80ce55454030cdaafd7"},{"mnemonic":"price envelope myself under helmet dove uncle below extend gadget limit mammal","master":"abe0fdd5148a6b93ff8b281d084e4bc92277848c964e3698a48e5d50d6503d54","seed":"f8c27b37871dd5aea7f7bf5fef1c561beae9d029b3fd937a961ad39fd09100993efe7b84699f7abadd49b81d16382e0677563d28daeeb08eecbdaed50b27eed2","priv":"8ac79807c2a1bac4cedddb4768fe92b7a51e0cdab5cb79758f5876511a9b09e1","pub":"023277dccb7b0e017b461bf483c2d3a63273e83f3acc4688733776ee3ac0f649ef","addr":"0ad65e63beb8258df8ab0f17ce28afe3bf19a96d"},{"mnemonic":"toy grain guide crisp error then group clock coin civil space paddle","master":"7c02340aafc6a15a7c6accc312960631cb3a92c4a7c6d98c43897a1c4c55e59d","seed":"a08642010ea9779615e7a55b973f014ae8bd492630f9fc134159501e53a12d402842899978c75f553cc78c061b59210ecdb20648a1187ea55d85b7ef1b206c6a","priv":"83ab8e2ebe208b1f32ece9530ddf03e0727d3313903ef13b2d09a3952dded8fc","pub":"028582791e93e6e6b4270353aac091a58922c0067fa440a645dbb4673858e9bf81","addr":"4f37f8c3b16183c245ff4a101bc290c3ea9eafa2"},{"mnemonic":"atom border bubble lift day soft rich rely gather ensure that arrive","master":"e6936ec3f9876ca2c44973ee13fc02a08739655b71a9880b0c7959f9c5c12286","seed":"00fcb87f619a1033adf5c9311bced58ebd5fe56a70b69f65b61228732337ac46cefc48b1e53ed5a6b0ef658b002fc162ce686529120a486230f3845250ca7f70","priv":"4e527b2fbf28914ffc78f84031c462f3b33ad8d2b62357ac816bc4c06c0767d4","pub":"02b77c89d89bc757872025a0933d39ee65f5ae037031359cc1e692dcda3a290c90","addr":"8c8ed73961a3055cbaf4ca0b5ab0b0f56bfbc32f"},{"mnemonic":"require panda tackle valid tenant treat boss oppose where thunder zone rude","master":"fa9c61113d7c7ad38850ebccbdc2301c451ad272d86a7b6ac7b384c4560fbba8","seed":"936d1b0d443630cdbe8c98731761ce80f980728cdb122b95753ca3549670dda6663bd93d03a5cf601edbeb0b835ba3e152f940706aab856682b9de0a772e219b","priv":"9ca97c10d757f03eec5165df506d1809850b1d8f9369a89b0bb118d1ddff91cf","pub":"0368a22ead8cf1ca5b0bd3b6b4a680d47de8342b47d7205f4ed41e85299d2f9260","addr":"f03eaec270d04d368df8a3a5408b9c010f283b8e"},{"mnemonic":"thing gorilla large fog mutual hair gorilla soft venue ahead neck remain","master":"4b3929a08e30aed05400a3a7fcb91fafa085de08402ab546258c10346a21c14b","seed":"af471c7488c0046d2eb29429369a14b2b3bd6de6e89036285dcc9a121389323bdedfd7072ef9bccfc1ea472bf8a9d3f938bce5ff58b303f9c0b24dfe8185d917","priv":"13d5e5fc0f6c184e4dad19c4537603b811186a3a5aaaf272762ee236bc826367","pub":"02ecb5330e932bc89bfaaa8682e044f6a1c64823887aab000b2409b467fa94da4d","addr":"c6d1e41d9fc95706c276d85b5d93d657d59c045b"},{"mnemonic":"ketchup blade myth tackle neck gossip obtain write script grace mountain glass","master":"3d2d55b2b706361eab66a2724609c1ae6e7bde50f3ca78dfa72be5e784798ac4","seed":"ca3ff2b26ce97cdf280654a05e388ba2ce5ff909e3bf253b35c66c4b9f8d630a81c6367537039ad09d05ad7fca337c479db1b34544c26331c5fb860eef84f953","priv":"968bf9c285110ba33def9cfc3f47c82ff8050b854568cee2ac509191885c4c7f","pub":"02d8719b0bf9e5296ff70bd88c8eea612b5161e80be5315a9cbd4ba84eff6dc788","addr":"868855cc81bfbc80fccbe3f1fd2d526db7cfe298"},{"mnemonic":"violin toy phrase advance banana timber viable half nuclear friend bundle injury","master":"494774c8eec7a45b2e54e69d4ca64766ada0b90ab1d2f6913690b7b43f489b52","seed":"d11d7a22d020dd5e4ce9a9c162637f47223a4162d5b1920d7ac83d99d73c40ee6b67fad2c534f8100d2529afbdaedf7d2a8cae2e921e8c6e02e3bb8d7417205c","priv":"57827aa1804ff699ea31602eca3ecdef41b722bc2d321187b48c5780962c0f73","pub":"037fd67f44683a2613f7b049a87f47cdc7710d0a834658091675497600d07b485b","addr":"6b13a26e1a545c77cedafc8592e55363742b55fa"},{"mnemonic":"forest unfold spy harsh pitch alter bottom album renew siren find bomb","master":"f19401a9aea13a1daaec39107b9b860d4159b8c66118bf13bca736937eed4e61","seed":"606f8fd5651b2b7cd9e5d9974ca44c8dbee170e6c60ca3d7a4764bd2a1a31ba79b60d0c32b40f2998a3fbe784edc40f93a917f726d2d0a3a07a3871358bc4f7e","priv":"40bee09d892253ebaaa28579840239123740d952da7bb782e66410998405c2f4","pub":"0310455b5a6e7c5d4d09a3ea71e2dc7aac95e8457e6db3bcd605010e6e8f96fa7b","addr":"5d40749e1f1e8aaf38b91c12907f561668f3c691"},{"mnemonic":"goddess isolate speak arrange tumble ivory give message palm wrist slide drill","master":"424c0dd576d73827d765d558616a5c5abc92ff548c82cd6e5a277a5a316e0245","seed":"36d58066ea3378f1851c1e762f36697248c2799dd98b19d74e69aee16e497e4014244f62f696f34dbca202f78f7b6e21585f91531bfb8c3576f910eaaa64b524","priv":"f0c0691851dc50e5ec0897cb29a8e05032b7d02afd774aad6904ff44088f2850","pub":"031bd47b8bd9a56d24874a1df5c15834ccd5bf553e7858e2cc1df2c045966d5ea6","addr":"eb4f13a437254adfcf46d5cf7fafd4b2a059a99b"},{"mnemonic":"penalty trigger panel ring menu toy behind forget tunnel various giant melody","master":"770d401afbd35db8afb7a1864b794ea5a59f2c65127457d4675128b039638e73","seed":"81256b9fb40b02feaf3228eb300d1b002f9a8c0ef03a2b0db187b265b09baa4fa28ae7992c1ffa893381e572331a5016e6fddcf3871d1d836e92ba94a44d92ab","priv":"380085bbd1a2e2f50eedff2c758fb63f981adfe46a25db54ce7f1d7a68b6b7a5","pub":"0367f233e57390fb166e45ad792a054ba908fdbebf11c20a3c199ddb134244b7d9","addr":"ca1e2a50753d833d16c10ac03551839734b5e3c7"},{"mnemonic":"usage real inform betray ridge call coin warm meadow gossip river predict","master":"8aa38fef2d5a72f6e97cc57244f0baf53b976ab7263373dceef0b46ea52651e7","seed":"9b806b194b9afe0f5f46b4b40c4658198445b53462b6aafb2b1e82e1c98fd29731d193681ee43f3d9d70547a5f512344809e02d15ae441916725da5e63cb3791","priv":"10835079af496655bc2dd80c40c0b10f18788fbb9350a7c3f2abfa3e00ccbb2d","pub":"02a3077b5796d8cab9a90186be1c1456d75b3076760f2720225bf4f38eae7c0e1b","addr":"f7deda6ddbba1cb091c8091d2e43c01408fe0d8a"},{"mnemonic":"mechanic share spawn limit panda quiz glance dinosaur gold skill initial replace","master":"0a84289f0c2aad1de0e750a0312a2a362f99b8f0c7a15b1e11dadab1df18593d","seed":"c45a8faf2b5af3ddf883837378d03bf6566c6369005df0c7995ecc9718e2e1482fd42d3411b58bb4a94a637c41f310a8faa0209117031ffe993c0f04b2878935","priv":"10bb410b31a37b51b19165dba5171d33e826e06f83b8c590a23b9b2c8bf11b45","pub":"0331188abce7c6fc99ddee0d7335e872b7cb2f48a7ba7dcbd9ef093c30fa16a5a6","addr":"d3bd3dd9d928d4bdeaeefedd058ccf7047fe82ef"},{"mnemonic":"velvet renew spread mercy volcano always snap column loyal possible ordinary sock","master":"a2fa675336bc532f8e1c253861eccca1909a195238dd202e45f2f38ff421e721","seed":"89c8378d8a7c2a2ef02bbcbd2da9e39f6ef138db1d02e32cfb492c09a132e726c69268f9743e464a8421fcc0d5a0bbdbd00dad61798736c673df81515330ac17","priv":"ed486dbbabe3def74d052685a75e65d25970d8d134724968941a6b8e94fa2352","pub":"03a06dfdfe1fcdbc8e9ae8d6c55ac974ef4075c8aa0a5783bc87f9d9c2d66fd5b2","addr":"00c4fc7760ae8f7986f35efc66d18401bd352978"},{"mnemonic":"secret weekend fatigue anxiety second ramp tribe employ quality yellow game choice","master":"0f326ef21360ac2929e4f8becc2e8320cb49970ed229f987f15b9f58ad383d96","seed":"a29c1dcb8899cd716ced74d2d81cbfbf81eb8b7ca7ae0214ba270be71e8f4a77d235a607079897f6ba6c5aef44da1005f3ba8195775a562e7d243b2428ea288d","priv":"db24d2fa242ff540009bc15ace40783c1535812bd0c79cb145187e4d648627b3","pub":"02ebf506214798f631572bf5f45321adf084d457de1425c929059bbbc328948c5f","addr":"27b810c5c8307a20b949b3945b82c0ef594bf192"},{"mnemonic":"crouch gentle hip then measure brand enroll camp vibrant lunar still action","master":"f10577e0eeb7b2385b797acad2bb4e4028bf1ae52cd59f0f53ccb6eda0727166","seed":"955eeb623726361c94806c10334bf9b1df08737c2b09fc3bca332d9f8008c5f357dc69e07251fa2cb1330c1099352e76ab445f824361533a8e30175cace06812","priv":"2e0602e9dafe830a4fe783c1b53f9c9b2f7dc0b69a52fe701f0bc6f88beac1ea","pub":"02ca1fad1e6ee189fb124863445fed2a9a923d7ec23348771d3789978d30a275c0","addr":"51cdfbd7d00e618d63a64bc662cacbc183fb2b9a"},{"mnemonic":"cluster slice enlist shift world satoshi mesh disease season ready can strong","master":"74d52d1a33a53a722c7319883ee0f47f2f76f39ff17e26b77ade53d45df83a5e","seed":"cf8c965548281a449796c37a12dfacdbf395e474b5336073985e5d7e794d80ad0ff5059a3df31381d9eade948dbbb898f4fb7ff697d2f398655573170b416329","priv":"5b8824e9f9a0cb0c0fc19f4d06921b32a76e1baf98c249dcf01c77bff2ae59af","pub":"0309e87c2c54481db5cb4f7802d2488872f07fe08dfc3a984b932246155dafb6c8","addr":"dd84fe8fef92aedb045bbf091b93c7abf4f34352"},{"mnemonic":"series element media flight next blur fox impact joke review token emerge","master":"1841af9c8f47747ac1819c178e62673e51e2957292ee608557fa38e2ece61d6c","seed":"02de6354734c96841c8fdff0806fc5a0237d621ac98acb7eabdcfc94e458bd2e7d71a9de2f5107e188e153946798775450aac5c62cc293adda42a03e0f50edb8","priv":"a118a4e3a22a82e48a4847a644c452794946169a39d8919c02f131dc177b4c8c","pub":"037b3f5d214185886313379351ac7e6ed054a7db85b9f5aab74e2bb78abb519a2f","addr":"f70fa3d5dc91e442851e6cbcc827fee336bf267d"},{"mnemonic":"engine surge protect goose warm bottom frozen menu royal fox escape sword","master":"9ed672fb3cc919f26c925be30c6dce07dc101af5baad5b6dc2264f5580819b3e","seed":"21bec398901ec8b5b4bcbae5aa2e261f96190a3e9350c03a0e23da3755a4d36ba0532ac17fb7a41266905e76f2d72e90b577e86bd6b8f7ab62a4b835292a94be","priv":"0c386e0854877e7a34bd8a9c9794f107ac2114e05130861f77353406fe9db555","pub":"03a3740fa2bf35d6248bbb7be20d6c264dc526f382f72696a6c1c28ecd2bf25944","addr":"d59ee54eca22ff7873b68b429be08245b836141d"},{"mnemonic":"dignity almost rebuild habit visit come carry deposit stone page soda room","master":"f4eedac55ceae98a3bb706c442d3ceea7caadde17ea5a2d0c81cefae9af754a0","seed":"5ec26bdfbc0d587473ceea390a99616a9c8c4a03527627983cfc9cca8f7779d1ef7c08abfa0969eab1da7c8128cfe536b6d2d5a07c99cd1afac0052e8a753d7f","priv":"4ecd8b9d596eda21b65ed39c8f53dc6ef2e19726d6eaec60da340095aaa3be91","pub":"0392dd87d441269c56e78939eaef320b6a9c0f0ddf5758e57663f9f268dffccb8b","addr":"eb71c884b8e3c1b215445ca2ab5d5b51a6bc0be5"},{"mnemonic":"input sound bacon tower fun evolve song pear various laugh code sausage","master":"b0cbb2481cc2a131867c6514b194146b937a6e46e497d6b4c329d6146433b13c","seed":"1276370b1081d2b48f45f8df73af1eddececf2076f8425fb0b593557392f3853e5298ab5a55f0e367a578932f8daf640d40d8465ffd33ab4bb6c41fc9a4ec9f4","priv":"c358f0d976f10618d3d0a600c0ae754fb2d0a2a97a385091436178ef4bfa332f","pub":"02b2e45327f09ab88143f72f6bcf5f4fdcab9101d55e015022a5f7b63bc13b1a6c","addr":"ea33c880b7f4cbb849c551f61ba630c4d9b97155"},{"mnemonic":"tool lens message country slim wide fresh front merit science argue cupboard","master":"17e462a6a8c9e854a6a7443f0f903749ab8967d8fb3a42af27ba3c2819d0c750","seed":"506cf27425374254890839b40a5a05218cb5e8d7c143523058f74d2f955c5cfdde30cf034589fb7846b9ba3194bfa9fc1eedbdf2b706b75c9b51719cf7bbc663","priv":"995d94dac98165acbec37aa586c52d9c7f0a65394027e3350338eeb69a801155","pub":"022f8ae9595f1f48654fb99985148c5c041dd4a1da396ed59cfdee3f09d7166e93","addr":"23f909e775cadd631b1b3c75df7027382b702167"},{"mnemonic":"beauty fury random thrive grab merit powder wreck affair bitter style girl","master":"2b5ebd0f07795968a7fe8ba12da106195f1fe540d417190ddaf4b11527e5f2be","seed":"c2df6f955aa168424697c97325016298ad6361c3a197ea9b446e790d0b2e877f03692a86dbba512e4afaaaa975484969c14cf0034cbc3f5571374ade85e6e714","priv":"ba6c8ef770c6258ddf7a395670a13cbf661deccc4edf5601e70bf44d1d40d63b","pub":"032f8907f58fa7592e6a8ac556f605a981b7cc80c94431e78bdd20ba086b22c2d0","addr":"9fc0563bf0185e0e99f266af339220588c655280"},{"mnemonic":"code aerobic tent hero install segment truck foot employ manual dice time","master":"bb99c30775706beb704fb7a7416c778c295b82d93c8919d521ee915468143401","seed":"bbf14d684a22d95920436c3133dcd0748dc6e3a133fc61cd78e9f1bc9aff37c473f0ced555265f961d4b7e70b6151c9c7aedfe6930e6a352d2da531275833a4e","priv":"6b766aad48cd0ac49d4ea1cb1bd9961d0c0d2f38f241c1b1ac2f1a8b1f7f86f7","pub":"038450b54d2d0dff23c557b3c66613605dff4df0afd3a5b22dc1c93711c9718d01","addr":"e50e364ca287feaaafc0a6b1cb1bc8f3f1410a02"},{"mnemonic":"media custom wolf spider bitter require blouse soldier barely pause upon inspire","master":"83ebfa6de22ec8362e519d5430a1479c2185bd44749be80f3f5381cc7051d125","seed":"ec99f944a7043eb3da146ecf22086de374cb1b55c64f436f9489b7f4f1e0ac6adb0f937080bb20405a4b225bad173729abf5517e92c3bb75aeebb516893d54b7","priv":"0771719a4060245c49152ce121c01ca8fefd04eb559a610a5a084a772741141d","pub":"03b17977e89ee44c699e018352461bb244a783c4e2187ed49fdea72a479969e745","addr":"493f3d15f460402da46eea1dbe4b767273eb15a8"},{"mnemonic":"build key hope learn place romance parrot ask spy whale input chimney","master":"d3734ac55147344c1aa411a2a161f42710308a5463ed2183b9cb561a8f1a92bf","seed":"5065c3b0a1b3273acb090c991269ff667513cf41e34a11cb802b8880591fb5f9e89ef614306261b0ae2148e5747649b6d5a375ada3749e75e084c3b28faaae4f","priv":"ed51941c62cb63e1e232dc903894fd4c8797d69f501f41f85e1763745ea7247a","pub":"038ddc7d19d6bee458f791b34d2acdbadbec78a228066a4bd5434ae538597689c3","addr":"ee83ae098ae348e6c5464eff4d177c04e97862c2"},{"mnemonic":"habit pill guard artist void crystal various owner shadow inspire plunge price","master":"c0a23d72eacc59b5a382bbe6b59d4541f5c65abf8840a16255a1610ac56df1f2","seed":"d7d1bc83db47fd6215a4e193f654c8246957f7f62b6f8b4766ce867ee58d69b01e749abebb2de94f607e2c442554047a65570c4ef1e764c56295a8326fefc232","priv":"f2cdd0461e210bbc69f810f796189167a71aef2fdd769487c772135924d35060","pub":"03a0ff432ff63da4b30ad757931bf41927c0311f632715aaffc41f1a39dad92208","addr":"a9fadf07acb53dc1003c0de03f40f73767cf84bc"},{"mnemonic":"miracle chest bind idle bachelor science catch scatter current argue fiction ethics","master":"fb1730aadf636789c12f30bebf66b5c9b7ec1138e126b9280491f61013e094b3","seed":"2139c6cd3f1788ca6f91147c60d14498295daebfcb65f0732d3c2d327a1ec8e01cfa011e840503f5c49c89e9092ac88e5d688d0fa945b604a851fe4f4b48e404","priv":"a4d77dc6678d78fab38419b72857914e5848c4daa7bc8e47e960a74708fc30c1","pub":"03b946212019343e657dd0821422044234507602641f389ce1698256054e6b194e","addr":"c67df9937478387372ada7cde57712ed05e6cfde"},{"mnemonic":"garden box bus under chat pen connect access police mom crunch elder","master":"c49d46b19d0078803cadb2a63572295a9cea729fb31112b48cdddc9311ce874a","seed":"fab44285c884dcb44b1adc9823cc021c0560a92bb9ebe23ddc25a08c68935e64733aa1f7b7a4ed30494d8f74cd8373a77e114884f74e6804696cf94a6b0012f1","priv":"79ea8bec554ff6ad0f20806224d7f0402a07fcac87db0b4f5a6cf84221cec17e","pub":"02492778ff035fab9ee383b424a90d694121df7cab7ca984aa8a665693c44cf726","addr":"2a899dd4387375c42068e42fb90793e5f689d413"},{"mnemonic":"morning street camp meadow moral chalk pluck winner light same grape drill","master":"e5a773479add64869e28f1d1a01fd6200de25fd53debfb000504a6231d2ab263","seed":"5e24f51f1676b996b470c01db9db032958f58e1d22bd7efb2bffc55baf73700d948c5f82eae0f6b82f0b9158141b173187ffbf4fc792e43af194c992884d41cb","priv":"4794fe7f9410adf7f567728f98daed1eeda0248d7d0607e57c4ec184bafd8504","pub":"026145b6582ac105e06921c3856db99ac7ff518621d984214cf34f5c155f0c8736","addr":"f263e7676644a577d7b535df98f7eb6d3f45fcbe"},{"mnemonic":"annual very slight slush tomorrow stage mother girl forget castle emotion move","master":"53725daf3dc76a16b54a2086106ea4eec394802f70741e2895a06655ffb4ad34","seed":"fc6f22026780d6255cc7a21746c7ff48fc773a350784471350837ca92d9131e9bccaf78ddc60a5bd8dfa9838755dca0c22e6efaaa757a5bc4b2ad341e4cf5d15","priv":"5296ceed1517058d022c8fa5c8e076851745b98465e0fbbc834a0aa872222bbb","pub":"028250ee9798cccbba647bf41f7b338ab4d15f7e5dedfea1857213e125fc8795f3","addr":"82e76dc9270c795c2316a618abe828dc2f09c1c8"},{"mnemonic":"novel swap prevent funny lyrics erode wool pilot kite junior alley inner","master":"dd900d54ceda698e6ade447839e3eb3f64cdaf8f006d41ee8e1a2f3b66b55754","seed":"8b6b71539ed5ce60bf33745f1172fe3de811affd5a494050c4672f2acda9b4af9aa57fece9b8981c94b1b9701eb27da0f67b8dd216418ddacfc5b84f0c835c03","priv":"4fa69bc81f76265d4df75bc208294244c5191ba7c8d6350bbbf4445e90b9b4ec","pub":"0281946e059cd4dbf81328a3b01ea285e106a390ec6a1b938327a26b85b3e2432f","addr":"12e1ca832d7826ea5c85db514ca80723f83a59ab"},{"mnemonic":"film erode thank mobile file ball inner wasp unhappy borrow polar mass","master":"61b10af9d2c25aac6bf1b1d4fb2e0899c86e40b5b3aab8a29986d241aaf6d414","seed":"f1be2b5ead5055a4446bf8d608c754f4b112f25780aefc7859e9697954910d827969b8ab2d78582ee6f91985c7f740e3d5d5ad08a7f3db9e265aa977d4ccac58","priv":"816f805d3076c855f114b1f8fbe1a1476fc02a71b7b800d6c5fb9d3b1094adf1","pub":"03f08001ebfdcac89f9d4d4cd52f8529b957a6e1ab500d541edfa086ffaf219054","addr":"ed2fc0f401d326f2ea61375272ab741d648b690e"},{"mnemonic":"aim owner direct pizza enhance range need raven divert marriage gap hair","master":"6ebc5c412f961584572008b5d531c275d45e403f3e3672c12457fcdedab52be6","seed":"b07c83efb4979dc2978756f0457d7a4574f5ca3c06c133f2b9cae206f12282c29b8fee9430b22a347aabca5fa91ba9a742901aa4ffbf2a1fd5a30b7a258e0566","priv":"16e205a55aa370cc54cd05ea3805858561f4213c315a4cc91450097d3bf75d45","pub":"0309613fee96c3c5bd9af994d9805aef90ec3b4da315a2e7731f6aa1c25c28fdc9","addr":"ae3778cc1c0df866034a0ba6fd3e4d9308ed4429"},{"mnemonic":"base effort water actor slush space three tuna walk people proof siege","master":"96ed3fbe9c3d5647a24b899dbb2c67d69a629fde37f4973c6032555a48de4706","seed":"1dfbfe4c352e01a0d72fcbb4cc82645a81e02946ffdebeb465d424f92719dcde887566f784be14784742eafec3925160e87c4861663ac1ff722b554e2b1cbd37","priv":"7abe37156bddcd043fba717f9be6ebe3f9894f6b814390d0556053be00566e84","pub":"035621b9ff867ef93278aa007087ebb30bf8a045ea4bde45d14969bef6054e806f","addr":"b8ac9814855c57ddf5d9dd367af8d74bd7740f67"},{"mnemonic":"violin naive wrap margin glare sustain suffer nasty whip loan tuition car","master":"df6afd71e01d947df8fac4730e6569a23002ddeb2ab53ddc23c35349cfd55fb6","seed":"ad8e656352e03c098c0ddd1a5d9556b92f013ef9853264189968677656f0b12d6afff540bb8b548671ec2ed60a5bd61204c463a80c10e5d44380db05fc9cc4d7","priv":"607de82b3e17947b94b43b0dfef04eebe28acd497e6d5b7773feb983c0067b6f","pub":"02dd39ee3d3456e77be05aead5a1d0b71b03237929a8f085760d2e1496c3914286","addr":"2063185bcca6c0602cefec61b752ca5cd47982af"},{"mnemonic":"rug pulse coconut equal coconut soon helmet trim peace fall please robust","master":"a47a965d564ace3708293df5216eeb7b963ef1c814805acf55f76a9f44372ef5","seed":"e099210b6d5259379dfab4cbddaa188fd5d61cc9bf9354f6546db1eec25eba33a34ff535fa3adf285e7460aac8d724dd5208d08207064ff6d2f794f34c514747","priv":"c8cc7b2a9f01d89708fbebd824fcaf1251fdbe0dd4953f43a9079947cddaa2e1","pub":"030361dd18f40d337500a32de0adcc92a2044481876e17562863dc32412c8b9fae","addr":"90165eae1989ce6ab3edbb2d8d35cf843138eed3"},{"mnemonic":"expire company bean basket weather apology lottery energy column used goose advance","master":"66e2f9149b1c2ac8f5f9b139a52567d1284f8484d9cf338b016c4d361dbeac5d","seed":"a4218fc8ca69a1661bd0cd9d9a458c996c48502cfbfd72b0b018f7432ef41c8431f70cde82e7bed983e49ae7c01bae7de6d7bcc590677e166456e5a6e4ccc137","priv":"d7377837e6f73b9093b13741c27c8b25a0a323aa7046483b3f13e9ebf4d436f0","pub":"0368018fbe6931afeda06980639c2f5b532245eade554f5c2ec73f3a532d056718","addr":"a41364a6daca7cc6536aceb4a32e657f3ad22a84"},{"mnemonic":"track essay chase camp denial ski worth retire expire amused paddle ivory","master":"d764799a1d97bd937a1b9dbf4a0f7cc91bcd06c6d7c1a1dd3d25e2dc8d63b0a9","seed":"e3e62475c7d13f79f2005f61abd2f674bbb1613587b3e694c70f24f6403f0299140b68567608420af5a7d540a3707eb1817fef98aacc3e861c17172e3a6eaf53","priv":"b2369fb324c5ef9e7e7313a87470984de6ada9dbef59def90c594c374cecce93","pub":"036ecd0c3e3312f15b3ad399ca5281546366e33368c00d7066bcc371919df9aa40","addr":"42a6d89451dbd00904633f43389133bf199a090d"},{"mnemonic":"mean hello inhale jungle brown cause curtain arch orphan spy aware deer","master":"a66b0528350e9aab8e3f7985a658d50bc31d3cc88d145817f77f889de8afcd3f","seed":"3e240baee99e3e3c0030af994981ee7c10311faabbdd685cb41b971b647aabda05df165b31954506c1dcbda0d15bc9dfb3837d8561e8b346439d059431552c00","priv":"f516389c1d667c77455bf3ea25789d8fe6cbc52c62fdb54849f857fcd35d7f88","pub":"03fc762324c6a0ad341118a95cae96d737eb0194e05272b92160ad3412482d6fb4","addr":"0ee6e446b5713f87b9a8384c3fe356e45a4d6e49"},{"mnemonic":"clog just stomach title gauge park couch coast fault demise march smoke","master":"f964ec3cea5791c86c3740626bd8316bf3373dc874af01e2ee844c0eab7b9ccd","seed":"8175672d9e9e2c8e9182f0d6520eb1b0ce82a17a56d51019acd5edb9eba0c9abe7ba77a895717eae9bd565ff0312c65209c250ea48965be46292a4cf7c1ec7bc","priv":"445d84baed03c168e29c5167e6257198fb2f7fd6893b4323e692bf3514364719","pub":"03b43255f28016c8961fd0cf5dc49e427105f290b7025b6138ec444491e80e9be3","addr":"633349488a087a2789bd2a99feb62554bb35a4d2"},{"mnemonic":"silent burden donkey napkin churn equip artwork lyrics wage enemy fade sunny","master":"754eecf77fe825d148dd76b15601f36ea3c1a23b1535ebbff1be9695fe293bb3","seed":"c61d6da1ddb2a00797ec94d1bfe43df5d012c75bbb916e0ce42672f043a979e8cbbc4187867ae36edeec02c5526eb540f1ea4b9778c2a0b534d0b0e9d8a42286","priv":"530591f5c65acab37d4a98df46cd6c8ac259dd019dfb9c97fc34b1c9269cb42a","pub":"030e423006cf8ee7ac079b31591ffcd73f6d63b8e26e765a4b9f3dbe1022b2af22","addr":"e4da6fc6965990f17c8c827af0b0c2a2d9d87867"},{"mnemonic":"quick toast trim image exit clinic then leopard slice recipe acoustic meat","master":"068b8703650bc546dfe41908b04a7cc430add80d2c247784d41b4241a321b339","seed":"73126b2fcde7ca4509ee115803d5bcb22162748ba465c71767e32d5b271ac53c63168d2a16032947c1dc87d5e78e5117c0171abb1bcb4912de0331d7a7d7b171","priv":"a9251969a43a62c2b25f10aa0ee4d621cc1d5aac612b6027fab2a505a5dfa0d1","pub":"035a135e39da761bac2346f7b896ee0d2cbceac71d9679a201bf2b75e00ed047f3","addr":"f7f4f03d57d3726337478e5216c680c4543ca9fb"},{"mnemonic":"innocent struggle abuse math try bright craft lucky excuse fly nation include","master":"631066b05d71d61539a24b7cb2aa659f1a8d0e3dc76c5ea28d4702b18546bd71","seed":"6ab66876fdb7658a98dcd39fbaadac319ca73e280cc471ae3954e6899997f35576a4b7a506ce3c2b447ccca6203092a2c47f1018ba6d75ff58c416a3ae693f57","priv":"4c6c4c01ea2511f4ec731546f35cb469d424fe6af5dbd8ef3f4d27b7013e014a","pub":"021d951f161be476c1795f1987deea93eed12181b8b1a251107d83efe2d96c3a01","addr":"eb09dac4658f82aa173e5388281877403b124b85"},{"mnemonic":"weather fine valley envelope convince cheese primary scheme invest rely science pitch","master":"ea23ee8d99adbc168bbc367b10cec018bcc7f15717b19fbd05de7ab502701ff7","seed":"0c485f94abbe0e9ee91dd661eb2c6670588c712d7790e9d6357eb7dcc1f2bced5d0c8db8dd0b7aea72a6a057ac97a12980d753ebba11c2fb627163e729a74a8c","priv":"272a773d44247e0d0579731593d568c31017567d6dc29ee9cb2324598d1d7a6e","pub":"0305d1ee431078056588a2d2e503c40d1ec6070e3b06a78b2deb04c6de9f4b00c2","addr":"bbb37db4d3d3f8cc16178fa777ac23200c05d78e"},{"mnemonic":"portion visual market hurry enroll stuff upper pistol tired question barely surround","master":"997415f4d0711a371b522baa2a003fb6485f4979e170492c3104a18e7fb90cde","seed":"51a7489d52481c5fd36a703c9e832550f10bdf24b06f9ff023bec374c5089de64e6d06d61ecd509fb44972a92094b4cbe1dc13fc1ce1fa6ba04b03ce803305ec","priv":"8c8acc19030ae9e9ede5111a41637a7f69e624be9f098660247cf0154579018f","pub":"02ae3bf3047431b9d799b99d56bead936c5459039b965a612673a70ab9209e87df","addr":"a2d63ec58cafd042ffac57128bf9ed704d9735b5"},{"mnemonic":"intact elder sign valid party enjoy trophy mix hood bachelor near sadness","master":"fd40da840f8bc5eb4fe8e83611c5ffc897dc315583daf95a9e255bb8441e8605","seed":"e9f3376502c9e4506568876341ab89527694bd9f0184650c3f30fed6fe8b8b8705860e0c63276f0d92db398bfc2cdb4b816d58dc48a5b8ce9325139c1b96d682","priv":"bcc54e226725e41f96f81587653d60b736a8da21af6b24d9306bd6b94d1959e5","pub":"023828cc58f153451683a39c3cef165e8f3a5499eefe018f945b63062fe05dc82e","addr":"cbb390ec8ede1eaee76a40100c1b551872eed89a"},{"mnemonic":"unknown order purpose spice master small inch isolate loop frown page nurse","master":"b8b282b74a246171e39a795778958bfed4fce9aa6040c3e9013b1afc712ccb40","seed":"403e11937a99ae4a4aa3ba4e0f682c158dab10cc5cdd3b79be276e5283b0f91fb7478b6b33e30841b356cedd2091417a1fa09925e40c1ed23a9cf54484883129","priv":"c22ff234c4bb00b72005e1e88909dbbfbba148c90305eb81de0671a5d28da59e","pub":"024bfbef04401d5a5938c64619a6c566011b3cde0c1418f2b62c3a921f3d3f14ba","addr":"f0fe3107cd932d601abf273b7547be623bce653e"},{"mnemonic":"angle blouse weapon upgrade enhance frost fine pear install method duck okay","master":"aad7d48511dac2782ad61a97e3ca94352ad24590f1ffca0e9efc3c6ee69297e6","seed":"8651c2d20d4af238121b528fa601c290efc255a569c8db892ca8f77d634fc02f7098efb7a9a45262c7e86d3d71cd92c7239fe4bb780e69ded7782c00b1ee0ca1","priv":"4b8f93833d5896f673ed59c0bd75a34917a61d521cb8b8bdb22814a0da0eef19","pub":"02e17e65c69b471a9fdb75515aadcbba673dac78c0f34df920aa46ad65623400eb","addr":"c404a9b79ebfa5ed9066e06aca8e091c488bb740"},{"mnemonic":"trust huge gauge culture garlic fluid type drop arch camera true claw","master":"b74303ffd6d878d1ed69a0e406741b51bc725887df08a1c8efac15a959b8d0c3","seed":"715486a3cf1e3db172fce32a23868a832fe7d5ac2844990fc14e951a9a357f16e2b5bdc669e415a40efc7ad14020991497496e980395639a68c6c7b037690cb9","priv":"2c0d6847313ed5c928480a302bf3fa0bd9918a5debc3ddff43cbb4c9e3f12802","pub":"02f79fa697f78fbc6b154d7b14a3b28dedb6b746b9de88c0e9982a54904ef124d7","addr":"c15d6b60ea16407697665acca000d5f792fdd3b3"},{"mnemonic":"shadow sister evoke wing radar what trust main improve moment flee erode","master":"cb1d183803a2de896f83834d19c3e1ef518c3fb6382dd68ab310696bd1d69b7f","seed":"444b9c8d29447c024f11e3c6c1618e767d908dbcf380125a062ce18a552f39fa108361fd18561406eea36e63415d286eabe5d5a5fbd23ae5bfa846a3e8bbaecf","priv":"dd1acc9e8972c3bf4363b3411ed96f41477724b4353e514b339baebbb03a65bd","pub":"028658232d2a075b2c68a519c47d2d74636fbdacb8bb31c9af70a967682816ca14","addr":"f8db02ece9c267f8f5b7de9c801432e694e22731"},{"mnemonic":"guess beauty gift repeat desert oblige pistol pottery lemon clutch discover dragon","master":"67ae574f5ec3766b3a0e1699dfc188f0ec78b51e69faaba76dbb08cd3a9e6382","seed":"395674e7b70cdf97f6072be527bd79a6fcbfffcb4322786f8d17611a3bf87947a87fd59146a59e7143a427c4065759ed6973a00f6aa522e6b13058382eb8b080","priv":"170df49f85c0a741bd5a6647d33410f944619de34e9ebbe7387fe8785b470960","pub":"03dbaec7aec40764a0365a6b2b00384c7966e9b2c97432273abbdfd089c519fa4b","addr":"af3c030ae37cd0ce5d3c41012b904738c7905887"},{"mnemonic":"fire duty baby kidney coyote arena bonus convince soft party blossom brave","master":"2054fc16a8c8b5955c76150c43fe447fe7a6d083b323eba70784687f94780a75","seed":"c16d9aa8d945a01871a46a92881c10ffafeebc0b1183e97812169d8f6e4f094e70f82576947917f3f6e551a9b9dec573478180053f6e0d71c5c48eeee95b54af","priv":"fe7f533210200354ea9c5c972cd0a4445fdd8a2e6e6e830cb541fc894e2e0ddb","pub":"02f9fa53e71e4a2a180d6daba5ae9806ed5e338aa680e2bac8fe25ff1a1a151d0f","addr":"2f028ee2adcec5023013e7a3756fe18c9a87b669"},{"mnemonic":"poverty inhale unfold strategy insane usage festival dizzy drop divert august head","master":"148e592f2c22b1db9d693e3777470b27ed0fcb2de1c0ec2d1f9f47421ff98cd9","seed":"412368afe4a71e2a37b1f87b7ce82f64dbef5579b16a6c189fa2ca29759e410b7c1e13a7b591711fb3d5bc8fdcb3292b3c828e52a2c1cd20aa55c830b8506a39","priv":"7e070b5f714cc7e0e031be68dd03e6b3e18673b5966d9c17616554df4e0f3288","pub":"037227c68b192bd6ed034570d5b5d532354dc47891acae0815d0acbd8d0346ac2a","addr":"439c830a56e6f8299c4d859c2cd5fd4a821e6dc7"},{"mnemonic":"gossip quarter proof require develop about olive boss fiction quarter rely build","master":"8b7580ddbbb3b766cd08088792cde2429c003b8b0fa5a9165747275685223a9e","seed":"a3c24f6f125702480e2d8856095a96f3e6d596678f15817414631ffa525472a01bceb58a0790e1df38dbcceefd73dd9b6bbc5bab841503daba8d73033494c254","priv":"5bb1bd6cee64ee4cc9b08f27b34dfd3da9ea263cd7fe7b4d3fc8a6a2db4e0ec2","pub":"03bcbabf0702cd56f459b8cde03db89d3c953faa3c108e90b75c65eca10485b5a4","addr":"c3ba63ce6c961c11bb3f7cfbe7667ef2c1ff19ad"},{"mnemonic":"dash small ensure soda crime wheat future style guide repair diet panda","master":"468770a80bd9e0190ae3a7a695da6a7bf30ac9bede3805c7d1dd4f6052e4d7c4","seed":"59eeaf79145cd625c266dce31faddd42eea93d15e64be3a430b9fbefdabc85cc3366115a07d819bb5ee026e118ddce46a2d906680b59917ff7adcb3314d6b077","priv":"99813e574552f35d2ae337f8754afb37d8387129c5e714461a0b72cdb30d0bd2","pub":"039e8088eabbbe966cfe54264bd1335697ca335eb55d56a89ae6a2af0bcbe2fd60","addr":"b3926244d741397940f6218c6db7a7c71cc012af"},{"mnemonic":"profit brush exist mobile diesel keep oval guitar cover maximum media file","master":"f402407479104621247ca60a34f75391ddffac32511b61e83324d85d873f0da8","seed":"6d538602ce7d97d7cb5469aede489a9a4f8af829d76712c13e7851d9e63077dcea3233ad51a7c311d367d4d982bf963c016c23fe39604cdc3d1dfe25baf1f515","priv":"cadfc276bea3a62afe66fbb5a4d117aaaca562b272aca37a0ddbd5f5a20c95da","pub":"036aaa723e425f879d4b2e731fda45dd95294608daf9d553a40f59fc4cdc37c996","addr":"0b6a4c2a542c624ee95719f53c99e3f6c6f7df19"},{"mnemonic":"oyster twin legend bubble bacon wisdom affair bar search just daring teach","master":"722c8eada15c60706ea1a9fa5aa6225142a623d6f5bd946589b22b3c9e69f56c","seed":"2f3967f0ef31b8d1bfe4b125678ab07328ada854f5bb589b5fd2c5479c3306eba54233f3386409e4b68f95be7f4b20c054f7930ab022f720979c847bbac99b80","priv":"73b2d8daa926db7e9072d4576dfbd511017e1ca7876bfb453112c8308ce70fef","pub":"030a96a78ec8dbcc9d62b9a8ce221b0f740358e75ed7ead277b56a2c56bd93a468","addr":"0ab19ff6566e8294c16e734306415bed696791d0"},{"mnemonic":"say poem daring wild toast force fall bread cup crane next patient","master":"89a87aafde53a9a8fea6b38549b6bfccfc950dacacda40f83b613a6322299164","seed":"b86bdd449d73412f10419a9534fc545a5f062d615ae197b6ce5143a1b00ac838b09e9db2cebd5cb556f469a4eaf883b8d9683b222f9b8843314134bd718b0887","priv":"60b1a4533e8afb1ac5eb5448db1540b859fd3650dd4e7c52b8b1a98ad3eac169","pub":"0255161266504a58a273b413e75fba8ae3c49046a3bf8334b2bf4a203f837ed383","addr":"2c390e3e85f391607962fff3ef9c3a7ca4ab5704"},{"mnemonic":"bone path relax awesome planet exercise road reflect life ability device frozen","master":"fd23233c87545130d43a46064fa11deef11d56a3cbb0a2e52be1aa21eed24f58","seed":"c72634cdc1fb47955eb7d9fd2391b3098d407bb5da35c0a88fcb38746c4d673ea113a96707828b18549271af8cd0f9be51f5caa9718ba31d783a3b26d450e7d4","priv":"d946ac6ec053521443b3d8d2dad6e947dd544b58912fa7b87b0b7b55f8570981","pub":"028b9c6677d3fce87d4b324ad336e486d382f7b56c2a1c8723d993d247ac1e1caa","addr":"6ed322bd71b762e44bf4554937122492e039380e"},{"mnemonic":"true solution afraid clip year symbol burst alcohol orbit village arrest balance","master":"3cdf923de0656e5340979c614d12ca869b97bcb476f8ddac3c10162cd23ceaa9","seed":"13c3eb909b83529db1d166eca7cad6b918e1f58c6be120aae8b7fd2a2c848d29550551ba3d710cb4d4a8597485e20535d6e65a941d206c69774cbdb04113ac17","priv":"1432f702f33b6c318f79d2655da268dfba6075126108cab3c8d88f4de2a6a0e1","pub":"03d100bcb7a2b81bd8e49af05a92c9a874f4aadcc836be590d63ffe8a08b63a0a7","addr":"3527160f146f542703309ee02b4ef783416fc9e6"},{"mnemonic":"family trumpet pact beef stand naive book escape ensure puppy envelope dune","master":"ecc1fb248992b1402eafb7d3120569255268dfa5ace3d04fad48b1917a42c3bb","seed":"f0f55ed35029e7f123dd153df36cfc9bc97c633b9b8752264bbbc2c33bb5932ffbd1d657bad87f8ffd7d4d9a9355226d2155fff92109adfe573ec67a18657f3c","priv":"8cd151b71c1f1424e2f53a35af5d427965f453572a211d8b4315894d370184b6","pub":"022ec5ca227ab19d758ac5941b9e7e7e13a06ee9a59c94d42dd6d013ee7c3d1cf8","addr":"93f08bbc6109187bcba87f2b6bf86e73eef60483"},{"mnemonic":"feel grocery tone drastic clap great pizza artist current true diary suit","master":"cf0614735905c88cc0f2236dbf71fc61accb6fcba39fabbac4ba1275a1ce6e9c","seed":"75bee915c2f3216cd023b878d06aa4d45241a49d10085b851303bacf82c36b392e01478359e59b54c77882948aae3026539d687298b85c3517f31ec0dd80e213","priv":"03e47eec1c8f7d3ddd3bf1997bdec4802a5b997e80a9a9fdaa8ed93f2641b146","pub":"024adba9bba7c596189ff4b057a2329740e03166cf6416612676d68a6df32c56ae","addr":"ee63795d783ab1a27ba8fa2a64665c6a563134f9"},{"mnemonic":"health across rare laptop broccoli verb course bacon offer hockey vendor venue","master":"a80307838f0014f827d55ec51e5384722d7a6a24703d757aabde32dca9f6dcd0","seed":"5fb4a16684f338f15b5fa6ea48975ababb129b3c01c726493abbfea837757fd27ff0a70bcbe2d08a7174fb7848169f7e22f483b8976adb0a4b2600657c9eb912","priv":"255717f5e26bd51d607b059c9a7ddd153d9bab0e832596df648fa671d8535d5b","pub":"03ca70b2fe6fd3def827767c0b26b25534bfe22ac74f77c0c4c05051154a08ea69","addr":"c4029c4186f3e762228f4d43b4d8fe19753b99b5"},{"mnemonic":"begin step squirrel window liar lock endless maze health galaxy swift scrap","master":"53ce62b273658f9ee3ef5b78a4e9d8b9a84f383053492d86825cd9d360763406","seed":"93d7f29ea325b084210dec914666f70ed46b83b7818d2dbd1614352134dcb021d539acfb2f4d916fa5ea48babd11d95f12eee97860c19db1bc2f369c6cc96b93","priv":"50455038499b153d77f388654037cdf614bb85ba5470d8937fb108a123241521","pub":"03f1f12d396494513c14a7508a9ad1dfeb1577af519a250b48798ff59f5efde3c4","addr":"5c46de48e642722b4325afe8446608a60e7ea89d"},{"mnemonic":"snack fall math great upon wing casual acid clown despair cage heavy","master":"c40433c68e968ff1081d3ffdd47249f1bb3cff2214f4e0f19227442f8e7be4ee","seed":"6962c13ba9d9b79b31480c117cd1613f6bb9dd6613e42b17b7434547694c96059026355a2c58b682ebccddc5f84f50c05b60b517e27eb693f1eeff24a038eb0a","priv":"972881fe79c997d86f11440cefc6c52a46a1b3b9953a255da6488e7ac278299d","pub":"0276ddb2041eef2c3b487a4afb36de7cc5ce5ee693461aff375131177dc4d28b40","addr":"17ed4db6f0bd80e929e048d526dc55a74ad58eae"},{"mnemonic":"vibrant valid carbon wish bicycle adult hobby lawsuit problem toast clever lock","master":"903e9b75fb472ad89da3b1bc74937415e877c1973910cb9ddbc85fbb465c18e1","seed":"b175935f86b62ceb93ed1bc1d2f3aee77a628aca7def8f6761df8b624a29d495a150b373d12a5cceec7d394aa91d0e68c5e2464a99820ac5add276d655be28d7","priv":"dd46bb3b1342a5a3c3844ef7fb4bcb247f9a81a48e20722faa1e03ba59808191","pub":"02bacfbf1b8b6d4a6e8a36b913d61831668cdd3dc74710c0ae0851b87c65789edc","addr":"e0520de38f2d2c2d3e461b1e2fd3076af5b9e927"},{"mnemonic":"obscure false outer neglect transfer other index debris bread crawl morning scout","master":"601edf66610cd4b9467bd73418a3dac8b937ef2d08c09ecbc89110443c3c8869","seed":"9d6168c1331c952ba5c2b19a0894bddbcd3d6a0960ccd5fe685db487ab8caab4109e2dda7c487d6161427895a9803ef3fa857fa2106e48083587032c6d30a217","priv":"2389d4e6527d9190a9ad8720debd487a00d47d6ad6228d643e1307aa727d1757","pub":"03bc72643c1c9a13f31de0a61815f950aae5e186328d07bfddf8e1dfe952fa8b49","addr":"add81ed8c06032c52445dea0db02a9f56b738742"},{"mnemonic":"minimum coast chronic damage page antique mechanic material worry alley nose tray","master":"d7f00c2baf2037008e9d1fbc1acee85127db59ce939491aa5cc19033f55f51f0","seed":"0ce817dd3a344f8dcce47336d3bff28da5cb9f5a71fd26e54c4229e9c0bf943077826d72c68e7570804b1992646641d79f8ac1b0fe157b7e12c70413d9625e22","priv":"76e0ffd8727768a428fef6d1e4186459d6b3664fec801ec542608c955dd8974c","pub":"02c0fb2dacc13de0d29fa26144d0974f90b97ed706c16ccdfac02eafbadf9e4e0e","addr":"e28e2564870c7fd74244b111e188dc82c27755da"},{"mnemonic":"evoke example emotion suggest apology uniform giant empower future surround pizza scout","master":"ae3bdaf7acb6660fd151ed30d5d299f82556bae13873f6cd9e65111d991b4d00","seed":"840044591bf305fed33beea796f2c5a8ef72a5005797762ceb8528e1c0343696c02012ef81a8e964548af3293454fc6e3329059e40a95e9225fa254fa901f3fd","priv":"2ae6395640b6827f7b3af5d2a4a0f0df46d4c6c5bf28528eb3a896d60c80e0f3","pub":"0378059ff10a1d3e0ba1876622e9d45a9b75f01216bf14737a68b48138920e7adf","addr":"c1333d4372eb2dea3311829c10c6d12f17437cb9"},{"mnemonic":"endless come happy cause skate short list laugh amount marine glad pear","master":"c1643f331f86b0cbf7297eca946e44d0d1a1b3e704b6dfce6d53d9e9c6eeecfc","seed":"f3901b079e9987dffb0378a76f099e39349cd6abb9c59c23ac3f1cf90b988e82b71bcb3466b7a2f9e04e0b5b27bc945a3b4b714e0272184cb64e9b4f8d6a638b","priv":"e80f64abaa7b55214d94b2bea74d25a45bd6385bb2447fc53adc4be4820edffa","pub":"036d7029b6f83bbbd1238bfe9a2b8ee654ebc1b2ea9d00494345783342705ef7ae","addr":"56fc7b9a42b8dcf74932b92934321f2568606240"},{"mnemonic":"boring math photo park connect wash captain drum kingdom replace exist beef","master":"4853a21045f669f43eddd0df88100e473320d2f76641ce5f9d010d654f4896c9","seed":"65e6412f40852556186217c0ffddd4291b77651f8568d97434f1ce3bafd4784642d9eda0c401f9ec57ffc80c161832afd43ab89080fecdb8d6a2570b27b2f0a1","priv":"67f6f9aed318eaecf6e80b3a89748900f3dad77502893e133024616c15418799","pub":"02b0f15eaa2f0b9c09a03280c9689aad73e3e60e6c971ada22b9352cf381d9a7ea","addr":"741b1795cdbffea0b144b22ead2d466413bc232e"},{"mnemonic":"true also hockey holiday increase humor main lonely invest modify penalty soft","master":"c1716c4c6563885c995c00990cedcf3c90734ec9cd0bcfa327b19349762d1bd1","seed":"e192cb10ec4d6813342e8ae74c60ecba75c8f9f23cd60a92c8abc44211fbabe82f4f11e30bf68bd447c8f0147be7ff9ee9b64cb8c44ac8697f2bd1ba886f8427","priv":"f72b0a757b8ceb4bb80b47704eefcb5e0448a9bcfb7385fa3b6492628c36f2a8","pub":"020584eefaf032c19e853bdaad1d1bb8cea4001b8d5bc919d888b1cd55f6e88b04","addr":"98ff8a4e963a8e8cb4a09e10a83cfb704abf92f7"},{"mnemonic":"inmate mistake detail main sugar find maximum crack soup tumble helmet caught","master":"9b6e9657a31f9baf6f303b2df638d84e549fc35e23f4cd7b8b96ba608c474657","seed":"fea14199acf507de04127191e47dc5d20d60ff473d5aa600ab697b7854a7351bddfc24d99057671273b62111990d5bb6f0088af026b38448609d3a4ac8f58b74","priv":"2800c0aa8490524c5add4d3a2def895d8d54e9608a05fd21a7bb5373f594999e","pub":"03d49899c17ac5c0a8c3720c1a9593950d2a8a591c8a8fc24812d198ec1931b5a9","addr":"e198b4a329be8be7f67e4c7d63bdeedf9ad5b45b"},{"mnemonic":"embody ocean catalog shrug valve extra potato subway casino father denial oven","master":"a24ea5416ed8d137670224056db9656e8c1a70f8e602bf6a49cd2f7e6968fc5a","seed":"447121225f8095e806b284e249c1625d925999fed396dcd7c36d9fbff5339659530fe2df0760a9d1d15dad32e1a4c1577c518bbb378272b305434d138e748831","priv":"548afb052cd083e9504a6d602614d085c7a20f37556030550d13619cc39241c8","pub":"0370f25b9cfe827ca110760fd13eea09082573b534411d1719a12fbc9867982e4b","addr":"e6abb5bdb479ce55759bbe1d0331db6046f1aabc"},{"mnemonic":"brisk present attend rib envelope keen mosquito athlete guess ginger budget interest","master":"8e34652bc5848d8fa141e06899c93928c5bcbfac5e1daa60c77af837d7771b96","seed":"4305389939cf757a57a7ecdcdfcc09f7699c315704a3d23243968932386f01dfc8666b7dcfee1d7ae26a747907c85a949843ffc91c9abf3f98007d394b1ba2ca","priv":"65e554264f67ab679321ab7fa516b5988e6049847de929d6e1949032adf1452a","pub":"0358503d0c6dc10689a3705838741f20b83bd5496c4befd2403f69760533f7b28a","addr":"80b6d095ea92c035fdd56adbc4d38f209de13000"},{"mnemonic":"never gravity problem draw arena very panic patient clutch trick calm topple","master":"a6cf02c1407405402557a745a96019f2516fd7ed03677871da922282358b23ab","seed":"ea44a019240e09c4c642351a7aa04625c309102032b9f77ecefb4d33c25f31179fc52c300b4a2e57603c08b5ecb77600bf9f4f9fbdb07cb0dc7e822f709ba7f6","priv":"38ac40ab37d588c0b7ed4a6f4adb378c9e1a6d8a3cb220853dd56abd7327df4b","pub":"039f5f8a5513c74284314c5c5775ed39c77ec9081b978a3b096af6670630046730","addr":"c6a7dfac1a85311dfb3a3c6191a6124ce8ba39dc"},{"mnemonic":"aerobic slush coffee volcano tip speak across evolve nothing deputy limb arrive","master":"d0b24358e5a1e4cb2fcfbb10d9b32330e02be92f3397e70c8a81b04f065958b8","seed":"927a69f86c0f796ef2a6f89698ebcc6c7d2df24672d1c597c10f2b3dac8123808b46cd63e726eb6f1699b0790f14da3a82d9da2cf0fdd32a9b936c1763db0522","priv":"1d736f96fb08caa2ee8c9d4c1506bbdf235cd3ce076a976f8a7be2bd621e5a23","pub":"03f6d508014c45fedbd92677a8dc94a72a7ada2c893d0e2d508c4c9be4fbc669e0","addr":"7ccbeb5e8927c714b3d4c1047e66757bea289bf9"},{"mnemonic":"aspect glue bronze steel idea trend win collect ceiling puppy gas flat","master":"6320f492fc27070bdd7b99436ebfdb25f462b588f50915e5c79578613b53e41a","seed":"e0c9803520833b770aa6febcf2a0aaaeaafa6d39400141908c6577d99ff4ff26062451a4f1b2ed4dd91eafa345f7efa1d565fa101cf0ded88188e9d07ce62e5f","priv":"f87d3a46e925d395a8c4539469e0474cfc0bbed8005b50d539a28c85e3a44a28","pub":"03343c7d2cf83e568ea0c9b92e766c6e021d4a95ccf169c2c9d085693490d66f0d","addr":"6dba7380eb165ea86e2b07e30c5fe1022e046da7"},{"mnemonic":"curve better narrow reopen vocal gossip fall tornado fossil scrap goddess direct","master":"3fed34f65702bb4cd41a309cf81ae4a8c13b569e1de5420103bea9cb264a0ff5","seed":"c3f0c08138f32640b3fa1e6d9fde51163aab66318a7709933339874fe8bad22e75f6c19004af5196fe84348a1f3eaa37add1b645a320acf8a1fda40fd788b428","priv":"c99eb1a2f56c8ccc3ee2d2bdd3d849b6a60e1e82200f72e55d236ef1b0a9fcc6","pub":"028c3c8e1902ee965f55211362b5277748a5da54b43f0807a216581e6d686158df","addr":"507e551fa72ce7e9da2b19f4258c2ae79793aa2c"},{"mnemonic":"insane screen heavy sphere turn drink direct exhibit turn pattern series pitch","master":"b060bffb238a046de32305be06a806093f62fd0d52d1ff5b44b70ad45f502996","seed":"0f75c0f282ec504aefabcc1cdfea3e4166b4f6d4782771a905683e26b05dd5603178cc3fde6fe4febba6542350b15a3c393927ef1e371ec450af6ae6f4ed5a5d","priv":"3f590738a71a45fb5f111181747b44e342212ad15350db1d3ca475b9ef4914f5","pub":"02e50487e89882de6fe3ff87c7b12542a8a6a8a8cd2b4a08be5071aab04b2d461b","addr":"66284b62f4b7f506c6aa0f935d034b00f35fe66d"},{"mnemonic":"answer mobile swim shrimp jewel smile security shy decade sign physical width","master":"64cb57bff4e190f89d2d7564be94cfd1efa0014ef403cedc6946eb52a4a78813","seed":"3f645e90cbdf7eb6aed9afb802fa22f1c0baf57a79c813fe21478a7f2d658dc83c3498c75b0ee4e01a02cb11609473782065c7656083d7986df7bcb320603691","priv":"12c7e6691ffe251287754234d7b98747f12183b5535be6c886f86268b28e9175","pub":"0375b4071b801b389cbc66de9443623ea5b86d310297369305d869e885e187a0c4","addr":"b6fee98515f241c4ac41fd1382a1d7211dff3af0"},{"mnemonic":"match car rice essence try reopen wrist party choice creek inner comic","master":"60b8c48a8c8cb2d68a92559d1ead30a2cac313df4f5a84f94d0b64a3d5569047","seed":"17a91ddd485e6becbb822434a723c5143a11aaedbe9275b36080f92303fb3ef4d934abc5d36bc51b35946a4a683f932373e4a3276feb0393c499a961b78fc18e","priv":"1d9e0692e0c3e8d06606423fd6fe3d336b893c13b38ae3339aa3d7635e2c0046","pub":"039de765de0080a12871f7a278fd27a21ff6052d864f36a01aab4895a3e20d13ef","addr":"6a1216c843cdbe2010e5f024e265b31aa01592bb"},{"mnemonic":"leopard garlic permit menu opinion kick clinic upper start vote truth okay","master":"9db65a69d3ee0bc07c5ee34244faa0f6e8008c51c5372ccad6b9d54497c27f94","seed":"f125a9285412d9aab52baf0045d628d41e870814cc1ee92746d0cd0fe955bd30e3f5519521c6c7d172d07d53f318cacfc5b9d4b0a4e508f9a1056526df594283","priv":"da4acc9d2c281a03f904b42962e021401602b65c815b9659bc4a344f6f35e934","pub":"02744a41865188a5b3a37032369fa4ef214dd2ad836a35dc738b501736806b6606","addr":"fd86381be60f3ed78fc53abf84a8652b3c84b7b8"},{"mnemonic":"vote divert tower history staff finish lyrics empty bless alien walnut hub","master":"10f25de189ec007f9caa97230456a55ae87a807178e8cf23e84f761ec7c69cb1","seed":"ec42f0f2043a01fa768a6c5e889bdc706747abae60609511755f21b7798b7e3c476d38d0b2894f2519f2fad6e279d77a04e1ffa864c9059697da274b32bf3b88","priv":"4073cbb35009f9e7ad4bb18a0c3c7178ece1b9e07c9df1d595f5142c51a92bb4","pub":"0340a0d2e43896e6cfc4d0a7ff49afb1ac28a5ba112af2882f86510865f84bb8ca","addr":"21e3b66a23dbeb25b3b0e2372e2fc7b64364ccee"},{"mnemonic":"debate between rent foster stove powder truth remain cancel pupil object romance","master":"aeb2d34623bef5822150858dfbc2c0c53986c363297e9c3fe1ea64613c6701c2","seed":"c95a64fd29b7b9f15d9077e6a67a8f754bfa55bb952ee35ab94ca001caaec42b45ea2ae7223fd10492dfb02604fbb87de28b4202c49f72be52b7c55db0c8edf3","priv":"aaa218916efc3fd6ad5b948ffa4a3239984b06592c3e7809df3bce89b7c50465","pub":"0221a21829f0dbd3043b9a7645c182e835cd14c95ce9931c1e17284b9172b77130","addr":"853104a703410c5faf86381d5d2adb4f3254abee"},{"mnemonic":"dismiss fire ghost eyebrow salt report pupil include case east blind filter","master":"636ab989611298c004b6ceca6cf887c25d44df49260a8f755cc159d74fa971a3","seed":"5ac06b4e40354a95bcf97270de3db0ac2c9bcd44d1a83c40e9f2557490cf794dc8ec43e71d3dcf3f13e6a7202d84b835c124405a2dc79119288ebfd6352a1d1c","priv":"ce591b790083433d60e3678d5ae488f6033c8327b494789f457a4a137a99bb33","pub":"02607f14149c2272136dfac3ba34476203424fb3eab4282fa6e81c0bce0357e81e","addr":"9b38671825a0fa55e15833ac583fdaf3fcce3800"},{"mnemonic":"awkward slot wrestle sudden core clutch again pepper private reveal shift baby","master":"868dc5c7376cb2ccca274744e97e1b6f8390c1f2fb669862cb624fda1e8d9408","seed":"065aa8d9dbe5769799f29e7a99e663a6e622f0463c6b8093486728d2ff2e8dfe2d9d30e357ac6416515f043b9c96267f3b0de08f3b88c6bbe9486c3c78cdc44e","priv":"e6d6be1b041e0d52d576fa52f4987cc2c8490d86a49184a231703ca0f3d1fc16","pub":"0375e417a16b94bbb1e8cc1789535fac4abb78b466d2a354045da76405ceb8c35f","addr":"280ab94c67d7bddc3ee6a83571a2941b06c83676"},{"mnemonic":"whip tired like merge crush bird venture verify grow fiction provide coffee","master":"1a1a931d51b74af1b4ba19a4ad97b2d5d8c79396cac5d7dd7883d83d79fa81ae","seed":"a03ee9671bd73e717e93830e97dce58b4b5786321989e9f446daf96a6f328d70f5d5dcc4c40d21b7dd4b27aa6809be2a3aece2f3c2469923b8e3d112c899e3c6","priv":"8bc19d1e811c334e4417013c3c85a2040cea8a3b61c18bec0c7520bab9dc082d","pub":"0224c968015439332e83d1737b7429c7bcece458a00a94cc83aff758c5386e3878","addr":"a069c8ae758f12a39e86b2858865d95e953afc67"},{"mnemonic":"prefer benefit sound knock exact pull clutch cabbage local burden small report","master":"9d8ac0f2bbe4caafc11f2cbd9e644e62ec5f54003701453e9c08ebb5b252aa10","seed":"a6d48540efcd54706017c3a5c47773a4dbade3044bf445f8e811b2b2a1a584230d070c296fec26c59deeef37a7487926783fc96fc593c270e90d7da08766ed38","priv":"bb6d7a3a4717541b7e33146b75789999b5d763d14f0962fc43ac30193e711b38","pub":"0288eee81a2e81977eb56b163ea601470d99b9024b5b99db2af88228842fc6d4db","addr":"62c96ec870a47a2cd540758e27fb19fedb11d9da"},{"mnemonic":"case choice castle monkey awkward kid submit layer bargain reward ahead type","master":"c3da04cb84f0f98ea8723f2b6d7e6a3c83b30e5ab8e0ef75bff51ca0b4a00707","seed":"c65366f8af99f805aad4f87c4f73c074d1c99e69fe65bd2bb0ac6a1062bf9595051133c32d5abf4910cda20b9e8a8cd76e22e692e31c02f9327eb703602a9ff6","priv":"71a0279874cd44a61fffb0e65d7fcfa0f4f7c24db912f18f587d6393f8fc1154","pub":"0265ace29b8dffee0f31e6bb3e42f91d90eceb13357e6d324ee2cbc41528ec1c4c","addr":"cd772b14963185ed989f1085142b2b0ae2e5f980"},{"mnemonic":"educate meadow confirm subject tube urge guess black friend later cement spirit","master":"28cd56e6a857ac35c617c4665c143583e0626dffdd7a5e0ea55ed75215bc45e4","seed":"bec29b984cb4df491eb1154fb2717662606fa63742febe91e10d19057c9134b4d4b8677ae23e006b450d6d485a67ae09a9c34fcf8cee5b22be821dab855cfba9","priv":"fc3c5da684c39ac6ae5a91a3b94f50680f6562187b5a138551d20149113d03f0","pub":"032eda5239cb98993519d44e7838c971f9bd8ef140da2fa4a95a70a2488f78f1ad","addr":"5a9adf7df64dd7f7e9e0d29b9fb90069e8230090"},{"mnemonic":"way butter chimney fantasy rebuild delay shoot toy ugly festival resemble promote","master":"599622e23b3db7ee9a6f8f95f5e39b2562170fbc4dc0d84b6869224b9304f134","seed":"a5e0489af660e70db67649c03622aa66b1a6c57d2593204cea859a146b1676893c94f4390740021a51a3a076b27239c7870db78ab7eea48da0a0177a10b8e16b","priv":"e16a619f8355c4cc276583b67fb2b2616d23d09557539fefbe915c6922e80ae4","pub":"021e6f57790a3250f24b6323cda9f648cd0b1907e5c7a81369d022748af8a9b0d1","addr":"9c7b9192469e256207f7758a906d0ab3c50e4fa2"},{"mnemonic":"sniff rely wine book guitar repeat civil elevator olympic wasp dumb often","master":"43a2904bc971e275f33f12109c2067877acb6b00cec32e3913725114b48bb2d1","seed":"cdb3853a0160f7ff9f3b6a9d10192c11ba3f74d45f4bdd4366c9153728105cee7e117de9e8b13be65d3a284fed6866ef4850898c9c2ac4821f55a9c6415f7e16","priv":"970e0aa6e521b0d938c41143fdd75983f5a315ab51fe0e2c79f5c37053e7dd70","pub":"0378b468aa83eb47cceddd2ec8eca4004a9e99ccca959ede92d9b03ce3e38d5099","addr":"9b285c714fbf2d0d9e39395b08d07e3eb87ed87d"},{"mnemonic":"salad print drop winner chicken despair bleak warm misery buyer clip glory","master":"77c5e3581d686b79e863b82f41e563fa5a487e11a782f609b4559ff5c52fa091","seed":"494e915c3897e9bbce29c8af192e7360865be489b38efb5f6484955a525d7120d7637921f7ce7cfe820fcc996c9d9d0edd76f8376a48549057267fc7193cd66e","priv":"a7e988c4a3e661ec230fb359e8f6f7b9593ef5bf33b9086c1460fabacd162600","pub":"02f91a2b6f0545a45ee7d50d6899de984dc0d29ebe6f75cdb3dd169c696daaa9ff","addr":"8bbb9c4b435d0f42ae033e2819a600ab49f3a21d"},{"mnemonic":"inside alone salt borrow fuel stereo toast hotel want arm happy marine","master":"0bbbbf5948912d5e7243baff26886acf316b6ce9f450ee0d60d262b568200400","seed":"afbec9326da69fa938e71403cac67aece539c5fe1156d34ec737531b6ca38b68e60529d589f887ae24899ed8ae53b9f8329f64d84fb62c95a7cfcad45e83f6c1","priv":"8e2532f0440ecb83316645940e29d0b522adc421fb9aa49a8016b6bb1ad34e16","pub":"030de4b35fe61c0fc2fb4fd295a9352e98c7080cc99a6f70d6f64229745c161be1","addr":"519f731ed0412ac24588381879f050bfa9b01591"},{"mnemonic":"cousin drip gap gift ozone omit road parent square lawn crucial color","master":"742d494238d59034ac2026b9a94ad7cf75df5e1b481de734c440a8507e2236a8","seed":"82a0149396a6cadb670d7286506e1a0fbdd771751b39562eee0531d1a2353d29229940395cfb0e00fa1a6d26c9d117039d2a1738ffc93b34161e29de73ee41ca","priv":"aa04e7953be44feea3ddf077d01644f5b4f1eb85fa89521dafe85c341896104d","pub":"02f0d80a4cef0f71606ef476aa04ccd34182bc12b0c45708b0aac49fc2781fdd35","addr":"4a2358c67e4faad28e0d50066a9da25912c1cc57"},{"mnemonic":"list power fresh cricket must expire globe noble park eternal tongue thought","master":"c5210503dee7e7530a84ebb0ca5ca9f15670dcf987e82d67ab2213ae76275b95","seed":"7e482fcbe082d1e9520fa44c8ad117f4d2fad839c8556ea3aa4096a7b940009021611938b4cd2cd82434f5ea37afb4dfdc3548af496f0afad91bfab3117b241b","priv":"c14825a7bf41e5daf44cd9917f33c682da9fce939bab16421bd7dca1e04644a9","pub":"029a20080d20312ead4612ee0e9cb5a2d641ab929865cfb19c3234c838e6f75c44","addr":"750b5d9c00adb243177506688d9bf4943a3ff666"},{"mnemonic":"bless goat worth boil street wing quality visit honey couple upon sheriff","master":"c66453fb857a3deb4ff276dafe0437ba6dcecdcfa67b095053a060f9d5e67c26","seed":"b29cfcf2aaa980c88ae8e0b151601e40ccd6dceda39b4ae324d6d906bdd3342db7ab0f20ae75c1f1b424bac7b679b252532b4d5990d36d91f7612120a5c22b25","priv":"dd96f23418a459bfe23f676db88839e63d1bce7ab58b76d28e494abb1da9616b","pub":"027f81c68bec50476477e5d5524919b7e40509818a16da7724c62de26f23fc2d65","addr":"8856e5d456716486cc794be572454bf41f013404"},{"mnemonic":"slogan outside park during produce key meadow cricket glow choose pass tree","master":"4d6772450ecb47b86c562d5accee0f78c09b182ffe324fe0078fd324474f94f8","seed":"a050602af53f0857804abe575f05a664c292abe43782589fbee0aafbb9654988b6a46ac26d93ba14166d9c6f887dcc1693c2aab5a782f4277c0f153e3572936d","priv":"92918d979c61e8c6a256548502714cdb0094ab6fbc364891bc094bdee708357c","pub":"03dddebad5131d93de5078fad3a380a717f2d2dcb65743f05a84dcf7f29a26f9c4","addr":"0c34fd5317283be4b9ae5a953f539028a5f201ba"},{"mnemonic":"coil burger alpha grow lyrics check page spirit sea mention course fame","master":"9b4a2e05f533427551d7e44ccef49057b2fa0ea57a5890480133a8cad67319fa","seed":"013af1c7f10ada279b632bcaf0211006d13e62165646ad3af69da3b60f044ce62e9bdc7c1c6758da037664f18f1a1189683db16fc2ed39192a7737154984f417","priv":"1a9a114d594bfc3e41c3f507114ef3b872b70563fba390dae992317f67fa0241","pub":"03c5ce908d87792e067ca19d4fdfc15e3abda1993f3ad1f1c8bc5168c58c3c4e93","addr":"cb513df0682dc11374466aea70d7cd9a45d4fd44"},{"mnemonic":"napkin mystery powder birth crowd fun disorder bike lucky core dance punch","master":"8fb55d8de947c13497a83c9631a4fe9b0b491cca2743a6a056214c1daf5cd87d","seed":"f8c5fa5fb7581ae597edbf214a2755ac2bdd58dda03927c21c983b545674de67d69e258a196ef36e3f3e319863a54b521ee1e23807df9f2432b5004b563c2509","priv":"3846cab8eaa4af163f79dc83e5968ce0a59b7cc2f6f725767f70fc1780c00599","pub":"0399eacd20a2a7426a0946fba205891d22fbc041d264372c6bc981c3e7200995ab","addr":"3fc8f92413e731f59ea2768ca40393a92aa8dbca"},{"mnemonic":"sock real audit mind page price rocket home economy glove water rubber","master":"205d5de977b27ef90aa092c70456b516aedb62bd164fac4e4ff638be56d9b9cc","seed":"129afead267c2a9556c3cd3618a29b659e98d651f52259acb1eb4ffbdd6e61d87ecc487123994fe4eec4f65808d9cab6228f8054f8ba68c59a6de8a1997bf420","priv":"94f20ab0cca31de6ed426a818e8cf11299b8112905d0bbdbed79de137337983c","pub":"02ebd561df3cbc137540c7b9bc0c919021d4c4765a9f602078b028e469dbae397a","addr":"0103fbf9c8f122fd4ac6635f9178154d66b619ad"},{"mnemonic":"option faculty depart orchard foam orient seminar detail castle warm pink pen","master":"90dc715ea43f91c4777eda4e9c1dfc9f909c2cc811b55575410d21c0a9fddf4d","seed":"94c306f3e3aa6e991b0f9a8d42af67d058bd2ef0ee233467ba0d23936bb0e982029a887e6b1f9bb9e537ace50e2235a9976dd79b03555cad90da5e73aa0516ea","priv":"ff6cdb1cd48968c64608ac08be92e28f9808fbaccda86c1f5fd6d905d49dcb5e","pub":"035162c7e9506539401c3a0c181643ca621f5abda005f6aa14792fbaf44b862edb","addr":"d724d1f5b4a987109f0c84cda0ed290d88e7c668"},{"mnemonic":"jacket goat equal source proof congress potato solution rival lend finish bulk","master":"cdef2991efb462f091fd3c4e092f8926a4f5e18d6013c5545224d3ecd8e61821","seed":"01e84e54b7faf2374a4b4bb4e56f07d8b13f0dbb0191c23fd41b4520c8123f26b526a463404ce264283c0f3d41c5927681b6fa388d9a91274fd693fa265fab69","priv":"feebee90172106d859d545187adc06732e188580754c96311d9acd825c1ec9f4","pub":"0305697df9f3fb6796d40145316d8f90ded12e8ca18a5956651ee96ab26e69001d","addr":"d0955fef013a29bc7666f1a4696eed57441e2633"},{"mnemonic":"canoe tiny raw account weasel fork still mechanic cricket address squirrel void","master":"9382c4fa09665993b8803f3cc92913c5564be40b63b1c19c81f8f9dd415ba83a","seed":"5c12270e9fa3ca2a008729b1d5fc1a8dfd52dcc6461969ae71d2f3fe04a7c59dae4faec17f84567afd7bab3c5934382ef3d8bc6dd6879fd3af22bbf30fa84486","priv":"9f1d4cffae3c7ce9fce5f987e1439167273c83b6b2dacf1a11ed66c6053c2091","pub":"030a2c97fc8aa57c7fcf7d21c29fbe00ca0866e58f64fa56a85cba811445e0ff78","addr":"48b6bf075dffc6f03e77c67b3f2f573cad8e28e9"},{"mnemonic":"topple recipe surround useless elephant fan gentle wall since street enough harvest","master":"353c700ba61c0b56bd7a3a65d29d53e17bf99abeec68fb79c747ab006592c331","seed":"9fcd29b6b00decb8c8e2a14d5695941854cb391bc25351d7030587a09f64e92bb409c4bb7429329504c19c7619212c731216fd5568dad8e2a1330fbe6efebc7f","priv":"c900c7134a5b92a2a0d3bb0c117c08dbd67f47f7562cf330d619aa3c64b7ab6e","pub":"03e60ac1d0a9ea441a821a780d894ccae6ffacc207ab39ff905122d435acb17a31","addr":"4202687424a7c883cb1dd96353e7dc4697f35f3d"},{"mnemonic":"any myself dizzy magnet hand drift garbage reopen fiber great stuff burger","master":"74aeb0c2e7a7655668238f6a090ce3657def8df96d7af744ddc52d4900451a6e","seed":"0e0a18cbadc5ab76ef4194f7eb069f266ae34c854933b3fa9603b4fa39dedcf219d73e3b283e08a067fc994d46bc59e1c42c18a6a5609111b8fa690edbcf5d01","priv":"f426009813fdcee2b4cd38966e6214f9559426705621ca8b862d2a4cacbbcd4b","pub":"03b75491e3a05b32aff6972e720bd694ef496f6a753ae309cabf4e9b5adc2fa6f9","addr":"5e8c4290a5ab9cb6af1addd261ef37ebd0e6bdf5"},{"mnemonic":"spirit draft dilemma cause main admit thank slide barely diary humble enroll","master":"cd538c907349401ba6605eb1ca7923df44a30a049d5cb9d5a42f0f66a5cc5f29","seed":"baab841c07bf90c8b1bb82c56e355fd6de5a2c93e86f0f804a897ff9c391712d2ec5281582ec15337aadf1f0e835a8c98c42e86a4869e0e1ec47c063fd19f04d","priv":"cacbe0003d96c8263f09f328663ab1b5c74cd6635504b778ebf2d7d30dbe524c","pub":"03e71d9a3ca15f3d481ceeccafe14e6ce1214cf854aa245bdbe28e2b27d2d40353","addr":"f4b073ca68bc00077027a2793e7d6a24dc4b9434"},{"mnemonic":"state subway clip baby novel broken stand soldier among fringe track wrap","master":"0fc4edec9e5891d61e74dd1ee6b52f9601010cbf2bb8949c1d38339ec428bc88","seed":"46ff0c2553e5494666b6de0fd8fe734a8bf523bf6953dbe8622c66c7e9645670624f85a3ef2e9d090e9b153cb5923460cc1975c481a5c2868e51cddd15a9ca35","priv":"4f92a517fe46051132e74178a69f94a2dcd9a1120a54e09188e7d243bc97db67","pub":"034c0b78b452dd0fe61464dd0a44facac7ba28f126fc2a60b82f82efb8cd153349","addr":"2da2b5a6ccff13b5281582aec90f4c9ef28293b2"},{"mnemonic":"nation shuffle siege easy birth motor also family infant siren upon warrior","master":"506af6e687482c47562e38ac6a41e46e2291d777fa0f7abe53ab698065f03f17","seed":"6a4cfce60d546e03f17f6d977ce6d9dec6f4cf8b6a85dfa3070a34ceaca022c5ca4c6f187f1c23d720078c41d540fd04c56bd5061efd027eafa9dd8e650e745a","priv":"b9354ed6da16a0cc9b4404d3226de88048b546f5a01375466aae09c53af3cbf6","pub":"034c3ef56d2471b16f17ecc3e1d8695e0b44057fc8ccf76625a271487781c735ef","addr":"41b9aff0432990ba791b76ebc13af27c634d4a51"},{"mnemonic":"snake manage joy opera creek dwarf wreck merge oval rule elite coin","master":"02a8c9db54ea6d54186726806f81935dcbf6b5fcb9e91d03ad618fbc9f9d3879","seed":"7d6db7e19c66ac1f54395a5a4f7d878e19c24e0cb720ab2a146e2502b4c6832efca2edc2d3f1351cdeefb53a53d66fe64455790fb687234381c017fcbf692265","priv":"76d273285aceb1d4686167749496ae591df991af93a8c29bd627747bb2dd811a","pub":"0208492167c3478e65f8a31f051961d2ac809faf7777dfa7296c54cc3639de71ff","addr":"b18dde1cccf8095ae14353ff4ea995b5beb01dc5"},{"mnemonic":"edge aspect sleep design jelly vapor car blame dad pizza own possible","master":"7d938db55ab464a9ca1e9bf65fb4de0e25addf0ee2e0faff2fcdccaf209de40e","seed":"2d2530b934297fdab1c193d6aa9b93eaa1ea353e776a8b89118b31273f93c2ae78d7b98f02ce1cdfb8465fec0a97b29b563764409813bb4b893a3683dc9d9bba","priv":"c183cb66c406d72e64eee84dcf330e61514028a82d56c56490c4aa09e26dd987","pub":"03e7b33c7123aea9ee99d349eec2603ec7c32c2863034fcb87df8399b73885c97a","addr":"2e8c251e27ee90d6b8f05fdb2c7c51f92b277f1b"},{"mnemonic":"cancel confirm rent key glow confirm indoor chaos flag curtain indoor float","master":"0b49f5cae01e50cc4c05bc466ad91d84ea13896d93d468f951666726de9ccf1a","seed":"aa4561254b44e01ec6b00048e4346754b6626000cfe8e566180a99cdf8739c0c76e16729ee4c73b055e7c59f5ad30abed0ecbc1499fed87ee75cf0cc89f9a087","priv":"7c4e98bcc55251dee796fe3960a8b842322c51da57fe5cbbccb997714392016b","pub":"02ffec93ac53e470bbdc2dfa89c2389a1db404ae6e57e2586b5e638e1397a85f00","addr":"c69d4ef8ebc35e8a418b00c7263295052191763c"},{"mnemonic":"become search judge nation inherit short history resist luxury moon garlic protect","master":"72a0a669e55a3058f1d20be19571673ad281e965667c6bb7afe83e3e89f0f30b","seed":"75518eca5861396c14bce066dadee8eb5f9a74e7099cde11cc9b0f1cb1fab1df87b5fbdfb675761868c81dc7dfc805bd2e425678b0a562447a6684160eaa6264","priv":"276b9a47745eb9266100e62f8ed8f8fa2ee3e42e36ef8e010109acbfb667c1ea","pub":"03a596424477e9bd2500b20cbd0290feb0d30b755562561c52973edf826bae3324","addr":"933df39b013756091a3455104d61244fd16085eb"},{"mnemonic":"profit execute broom clever wing noise crew purity steak assume april leaf","master":"bc7e3bda0564fd300d6f0033fd13d75f7bec7464ef692bc96f83e7ee9427c6ff","seed":"353344a63ebd9a6e78ded4cbf52a5f29a64cb7c1d90b001d764f5f4fa419f569181c07f8bcca22117c970f65d6f9c06b44e934ad21257e0f1bb500f8a26db987","priv":"9120e0b2f502a6b5b5804fb4eece7754ed92a59fe482a7a1b4190213dfb60457","pub":"025f809c0f6a054c4b875c7bce8791f23cc9daa6a85558d6cd48818f29d6b978aa","addr":"f25a6479cee5506bb53b4b06fb326a508ca77abf"},{"mnemonic":"menu library ten glass coral taxi prevent learn pelican garden magic busy","master":"7f4687dad9ba781a99edc31d78a2c68875f40afced8adc8a66d55efd3f68c169","seed":"607827fdd6fb239229b116e73be3993a6596a09cabfd19dfb9b03482d052568c5443f4572393b0e9d460a05832c5fc41e811311d9bb501c43ec75e234c61785d","priv":"5605ca7fee44c088165aa3474327c53dcc13ffc73d8b4787a8b0dcdcd7fdbf3d","pub":"024d754ca81f064cf6dae96fd1344cab8e917e46ec639f677eea33a21bb34462c9","addr":"663ae3370a5b68058dfb1b2efa62f4a2222b3a89"},{"mnemonic":"green useful pair bulk excuse mixed train talk genre inspire much eyebrow","master":"318169a8d80848ddaaff93bd0fc68b1282aa8f5e6f058044de6ff82c62446005","seed":"2095e4cf4ec5ea142d9300cf431e47c6ad401ab1693a6518d5cf7950d1d5d7e0c6feede5a29b3721924074ccb527cb962ddc5745b46b794dddb4ccfdf31ff1fc","priv":"e9c336d9e59b1f4c822899ec39d256174521097060db24f305e3d4c3b12c35c4","pub":"03f44d7d4269f3aa14466483d80ad483af1307387170f563222e843c554f215b00","addr":"359955417cbda69e538cc001d5aca0bc59a077f2"},{"mnemonic":"follow half desert universe canal guide pony two fuel nuclear pull tag","master":"1f3ffb60e2293ecf146f414b28ca6a81dc6768c34450f2907eeca2851ebd92b8","seed":"e692e2810049aeeb25672c3d07a411940a7a7308e9a2fed2a67210d14dbc1de2258edba62437cdef1f913cbc65cc8040bd52f601c2edc51cc7d4744dc1781147","priv":"3534e3fc0a973dc314ff3610ff02c07a1a9e5f2a2003f8ce754c691acf172565","pub":"03e7f0b65a215a8d78831f05f10db86874dd0d900059bcbd64d83d08b05d8a5f7a","addr":"dd74030f9d82c0c40d2798e731b7c5eec61a0213"},{"mnemonic":"enjoy chief later rebel avoid emotion kid reward find patrol leopard destroy","master":"0c8eadc9ddd4cfe9b2c1759ed1372c513bd5226c1aa4afea02c8273d226182c5","seed":"d522815571acf5953d4bf6894c9bb5274e876a5ecb13310dc3db73f2d55544174d744cbc7d63a6ea07c8b7bf8bdcbcfe161ac57dc0ee488ed9fbe0d21a070d95","priv":"92e9da2b0ffdfca29c83f64a685f6f512eb291b5b130c4c5c506bf713016859e","pub":"036161fd5b9ff9bafb22e61860d1d3130e007839939eb3f609352bc73376552d17","addr":"015b10da504e82eaa290f2f5057a2581db032f51"},{"mnemonic":"giggle medal hat isolate congress else guitar below chase federal absent photo","master":"eb8a28df4360243f9dac597fa92de914aae4133af8f3a18c2506f2fcdaf4945b","seed":"95e8d77d1709418b4ac0b8cbafa302e2019644eedfbe52233ba988b55f5451781583ecaa8b1be51ae18e17ee5bbb35d3826302701588555dfc8c851844161acc","priv":"35da7e9dd8200ed89f461c484e63ff3ab68a9b1cb162bbc3331394f4f2ab8793","pub":"02bb24e03a89e6a6a7d318effa8ab645c46e5dcc4f25c3e4d75308144b5d2a29c2","addr":"2c271833daadd196147eea05df28dc41314a27ff"},{"mnemonic":"use protect bag nut fault off absurd involve ramp cereal symptom biology","master":"0f5a77192d1a941ac59a41773ea7d6b4e87295f4f82fb0f43c5f12d605afd56f","seed":"7d74703c2442bef350254d3dce2303a8a56fe4c96e4ff80ed57756dd7b8266e566ea2cbc3abba9c724deb9c45fe4cbd6a8c8bcc4bcfea2665e5193b781aea933","priv":"18c64949d8fb6fd392fb4846c119eb71a6021cc1c22991706fb776e8843a381b","pub":"02b94512126ed2d6412873f61bf16592f02df176cdd4c29fcd70085fe3d03127f9","addr":"15e94aeca2bbd591e337d57152663e25bc094747"},{"mnemonic":"tool twist jaguar excite borrow social sustain normal echo fork alley hybrid","master":"d6c9dbbbe44afa97a5f6365066a11a8fff48793d4c6720ecc419bfbb81329202","seed":"164785fe64846a802a9c134d094447035eaaa6cef2eec9d5fea9aa74d333ab31433c7cfe4b712b6a3b04048d239101a8dae5cb4ed37699658725bc2186ffbe41","priv":"cc5c6aba1301195af2626001e3d19660043377c75e7990063aa45ebbd30ab266","pub":"02ed0554dd8861043aab2105d7dbc83809193c59952e829421f7b9b6e9e56d6f0e","addr":"7db5745b47c147e40ea9fa2cf54488974d0bbc4b"},{"mnemonic":"approve bright target voice relax control knife again special future anchor crystal","master":"332ed66acc5c24c6a19c450775329c946197872435d77b0ea594d4632adb04eb","seed":"da2c0f3433cdb37ff151465470bad3b227114c46ddb025542133b4c10d942bce6cd34726c85e638fa82c4295d8fe93959069d35253ee528fb1724be1d95447f1","priv":"41a2cdb57b5cf352256bf9c2b155016160c7eeeaaa5a3ab2f06cd1df3e4bd695","pub":"02e76d02ff3fc76c21a995add6962e08bddec4abe23994668770d6cfd02cb82f42","addr":"39dcdc76bbd5c2ad8821cc5df8e816c7293a82b3"},{"mnemonic":"like wet pig pause steak name tornado else limb february secret subject","master":"e7dea9fa8e88520065302d4227d84a3d4226aac4b7c04bc78dc7e68efed73002","seed":"3926c7749d953ea66414c369fbe3f26a7a3f442ca98a277dfb362eb74432cbee32e44a6174f1e3fd16aead63e798c894d88ef260747de219c1e8631d800c13c1","priv":"804cc7215bdd8073b9c7f8e1ea2648724ec3e2593f1c2213875b6e4022513ae7","pub":"02770a43f589045b52ee29065b2cbae37ff65a0ace98c88531b4cf88c94c3f977d","addr":"cf82c749e61e9961ab72a76cbd3f71e0c5a46221"},{"mnemonic":"memory core ice box board flee ivory apology acid warm sugar resist","master":"4ae1d18a2c3cdc0c4b383d20846866f1a2ecb799e7d2c5c125e81c30856a2bfd","seed":"5922aa04496cda9a17e2f474805f095fa2bb70cce0857dcf92acc7737af2978145cdad0aefcf201fcb5aa2666a136b2eeffddb5476d9d49c0cf0d76d14bb332b","priv":"fde667c98a06017967b9169dc380a7393797486d07bba6575629f0661465a67a","pub":"03f8e990fabeba27ea70082b69628f95e5b86cedc033578426995bc1358949466c","addr":"efcaf3eebd6ec30c44fef92eb59327758eee3334"},{"mnemonic":"vintage rocket today version chair avoid mean play decade sport frequent magnet","master":"d167f9af9105ff115790c4d31ca48e4ce5cb3b571b4596b8ee78be5a6290e3c8","seed":"af58c0eb0e62201b926ab4c04d67b942f6ff40147ccdccc02a3df295fe69ca661b2a23fd2cc0f9148c4e92165ca9725014ff0abe5cb7acaeb513cdda359dced1","priv":"33b248b4a292ff6f26455859924eeb646290cd54a2cf587c5527e2f432fcd6d4","pub":"039802bdb2bedaabe4201344c1e9276d1981f403151e2cf179e4cd13861a54d568","addr":"c9ed9bc2778a33e5712b90843f1b0f0252c5c3d6"},{"mnemonic":"crash lazy cruel match youth note deal rack gym robot work pioneer","master":"13a82f0a499ea45154151ad95d52c3f15d84436c21d734b5ea105c902f85559c","seed":"c10e386ea97bef67bd97e59c5da37442ffc968893fb80ade82097b87a76dec5ae128962a4d69737a31eba4f1606e030d4c85df6733dcbb03e209a4b7931660c2","priv":"eac145103c713225ce05ffb862cb921797f9f88d48628321162798117e37494d","pub":"0260d3fc9e0ef5e8c38e3de4da944d59cc575aa530dce9fe8d95fb8eb68d6a4bd6","addr":"07aa44afcad33d8abe6e83da72d6d556a3720924"},{"mnemonic":"distance desert squeeze eyebrow episode enough sorry gym still label mansion thunder","master":"0f686b29302ac0d5532794598b98cfba275e4fa3dd0bef15c0b0866bfa0c9c0c","seed":"9fb57b9bb255323d11b7479bc34dc706e42e6ae8bb3f3af212b0807ebc9fe56a90a36c92bd17eda435fd0ce87a0465cd10a371b44dfb2e1531c14c29cf8ba466","priv":"7a140972fd7e2499dab8e22a52b0cf79c33ef58d1c5df578e30515e627f044a7","pub":"02332ac4729e52ba3ff4344ca262726bb58595670057aa967451302bd19579e8e7","addr":"f7c0cab3704f9ba669e318d17e33b1b5a7b3ac3f"},{"mnemonic":"zebra useless blue insect radar century lumber clock daughter slight quote stadium","master":"1168c3de22b717bd3e840b4ac6334ea707764d25bbf7ac14cd5d63ab127fe2a5","seed":"df9f562a972569f8dde2ba35e53c97c536ca3bffbbdc990df8cdbca812747887904a4f983d661035de0b3a85677d0092edad32ef528c926bf31541ba63b8e019","priv":"282da5f2191001a4bdcdccbd0000317ce62b09c0a48626b4fc2b45da6d7873be","pub":"02790696da42d2b21cb031e9b77bf855e2f5a214f80cd05618181433eec02fefb7","addr":"68f483b9d998b9250d320c43278e423d0394e8cc"},{"mnemonic":"laptop pepper arrest tribe glad keep behind gravity ketchup scrub bottom parade","master":"06a978fb60c517a506d2d8fa17956f144d1a5d57c0c9567320d1b21b8e7871eb","seed":"38c05886932cf2bca3cb7732e92b4086ca0575db2deaa241a0c9295eb79d50765a4bd92a03b76255144f71bf6f197c4b5eb6e3de8dd6e6ddf6d15ad18c90de35","priv":"62c37a4349e0d4edeb293e50adfac737ce73e3e0370439c561d117bd4ef23f19","pub":"027d978c9355669fab1ac4db17cf12a103f7501ca2011e022110d5b4398810039a","addr":"6e0cc4997d42b970855685f8c9a196b97b2d5ace"},{"mnemonic":"alpha slogan usage lemon cancel cruise rice crazy laptop donate city fade","master":"e3bed02bc801909cdfb1c65b6648f4df19b8927199e3d0f069f6713b13f10123","seed":"9b73467192fc857c552d60dc0223e3c4b604cb1cd50adcb61c9aa723d245e3ad44cba7f99f0f24fddd0c78b1bea41a86e682c9c482b115d575b9e3aa27f5650b","priv":"7b8d2c22c398e4a046da94656232cc75cfd6fc0e0f8191b673414383901b724c","pub":"0279989cb1f22fc08f871d023632a379d038bd9fa902a6e46f8bf0a780637b4efa","addr":"a4d3a5579aecfd9790dafc6b4e89972933c46d1e"},{"mnemonic":"chief runway cloth craft depth firm task ready credit multiply program smart","master":"d5d076659b0e0bb061736956cef361aa1a6a0ad6a337a6ccbf4b76a40184f405","seed":"8e60f22168de4f2a6c9db805a6485379d2facd7c99dc36981d0e209746766233d5d5012b03f8556195737bd71b88fc54eaea0f68e4fae4afc19c133f2ca5fba8","priv":"adee70b6b1dfc264606e0b1c848f7b5deb46de4af91c5eea9eac962dd085bb3c","pub":"0226458b01eb1e4f0d7901841662b2046f17e0945230a3b1b2d8a65aaf5ebdbe8c","addr":"c9d9042f15ecfb29595ed4769b1c858d1f627468"},{"mnemonic":"invest glory debris naive pill detail sister cattle physical favorite squeeze rice","master":"2ffaac06321f9aa3783155de5197448783583c027d8aa9d9b787d2a07b7a4c2a","seed":"3016cd4934eca835d3246cd7c05ff35a0ca5e3e0c4b74bc70aa31582a6da334c0f7e91458bc049ba3469a8aa7f216d27d44ec8ca4cc5f376ea366a38106c7fab","priv":"cfa4b9f12156ae24e632f318be54072149006db7a4a611403afa97c978351900","pub":"029e3e54ae265087ab8066bbb7e935af291b3ef5120b00f44019d9dfccec8a4e9b","addr":"3de09d0c1ee046365da74449b6c98ce3205e20e7"},{"mnemonic":"private alcohol loyal depend force sand twist couch beach report miracle abuse","master":"8354e18ddc5b38a6e26f9cfefbfd4b27ce3f65c91174c88143d947104ba91faa","seed":"507df1232f5cddcbee60de019cdba03e9337896ae2fa0b26855d48c34a9a2cdd1e93f2b66e965cf7666bf7c7ad11f00b1ff764b675a5c3df8a1a17b253cb9e54","priv":"d486cc9a23d56e1dd8d865ba042aa5cb9f8ba06107988e1a0d999b14da3b667b","pub":"03b75ef54ae8faa3f3565fd6301ba7a70114ddd184eefc74e716fa2e3c2df6c2af","addr":"2c82b93644c227bc66fc06c922ec1566c3e11c9f"},{"mnemonic":"memory achieve vault hip prevent category cactus aware venue dutch raccoon fresh","master":"16bffabbf3a08959dc9c1780781133e6aa096cef9d9542606c52e8ca2ea0230b","seed":"a4824f3efa0c730e3669acb08b1cadc25f3f63943983bc4f4f1505cba5c85959ec16c2cab98008d10e22f3ed6239e3182bd9b603ae1536755d222fc60f91419e","priv":"7c2b66b79e2e99ef0f794147aa93d3da8e62ebab7ebaad7813b586ea5db28f9e","pub":"03298a67eb59a27d636c2aff41d73ec658c87b136ea53a534ace18fabb76486dd7","addr":"89d5007339cb57fdb72ec629027583b8f3aaa5da"},{"mnemonic":"alien floor comfort six demand helmet light actor distance success buddy burden","master":"36ed5350c3672be815eb365f61ef0d0d42870b178aa34fa5c5b7397cbb7ddcf9","seed":"ff46b78794944b4372affad3f096339f8d9c03631335d9eaf4e4fe68a8fd9d58a6d6f37ba31cc06bf57c5b66aaad6ba64ed28ae4188195227fa07bfa587f2f1e","priv":"3bb1328f115390ade3c08de4f9672ae96bc3d5b783bd9d26d7e4ec12d5818b8f","pub":"02b37bccbe6c7173937b3af482d4a92280b670d715e2619fb1fc906973bcdd4d7e","addr":"935788847e1517096b9f31ccc2ac48c2e5a738ec"},{"mnemonic":"soul upgrade rebel wash hour gain lady side own double immense merry","master":"039c6373307aad9366dbaf9bc17e70ec1b5fedbe382b9bddc55ff606baadc0ae","seed":"37f9cc349c21182a3b34c66ae099de84bdcf30ed20160c7251f43f831279834dccb95745207defbae856c0a38dda3d7bb251b97cd2150c155ec64c680c82ba73","priv":"377f589beeb549285eee37d34e5ca85f4e00af8483027afb655e47ae05d1089d","pub":"0266f715310d9fee40c5c95da1b6a9a9aa51648df99326e29399b10e9cbcc51f7e","addr":"89a2ac362b8804981ecb6043bbea65587c997f97"},{"mnemonic":"stove pyramid vintage defy belt high have leave comic brass online caught","master":"eb9be6fc059732dd9eff612f2e4ed7121093f07889b87e8c66e103b83724e1f1","seed":"2537a9ac9dfe5c31c0f40c69c9fbf6a8ea186d2cd6c6d2134aea2f3ec2f28f5339fe623ff593da08857ee84193c54e204049009f8c86ded026a4cdca633b2b9a","priv":"a8f4ea6ba49c421a7d310b83bec05902cf2f2629a3845e390261c3917af3a17f","pub":"038a6d8d8947723f80f65dee0ef8579dea5678b67bd258ca591d0ce5d2ec060bb6","addr":"38d61629cc3e3ce7a614825cefb125ddec897b59"},{"mnemonic":"uncle seat rate acid ketchup frame marble limit demand exile wealth dinner","master":"fb1b8ac2f5bb56231fc93615bd8e25720818819d3df4ffcaf63dba0e7e7a0815","seed":"8e0bad11dc7784f19715ab90e8846e84155680027997fa0314fe32efdb3c026ae2918740d362744dff754e75b1d54050f5f02237cc4e15aad165ba10cc7b046f","priv":"cd20e39179c66285edeb6df646de54f3510f166bc1821349d779fcc103f13839","pub":"031a9529a2b5da261bb540f43b860b540490262b10aa09d419dc3b96d2e9aacc75","addr":"d1b6e238bc4a7e63e0a15f034deaf1a5b5161928"},{"mnemonic":"human benefit idea stone hospital misery warfare door goose unhappy crowd stadium","master":"b8b5781ae12ea6db767cc01d644cc52179363b72a7b67ee8d7d20fe8ffe4f41f","seed":"fc3f6e420f688e8553a2cf8d3a6a7198c5523aa6e3b00b3e1e4bc352288f0390951bcf698bafc12334522e04979fbcfb36f12fa789a85dada9909304de559193","priv":"ca41478acdd4f0413a843cec85b2abff69aa53b4f900da10918810b89127faa9","pub":"026096644513086624a2ba26daf7da0e4f5c7455bf852336416737fb72dc1137fc","addr":"e57448e2edf9d63574db45ae06510a521bd80522"},{"mnemonic":"violin cave ask subway session gaze settle pledge decorate alley swing evidence","master":"4c099f1692bd7137bf8b50e51d2f6fef0236f88bacfc4c87f83fcdd43a3a1aa8","seed":"2c3cb4cd88a4de52badeb41b1e3e1d61daf61369d5badc36601c4baad611eec459a0a1edb4046cc21ff50f396688ba6bd37fedf24b17ae447b6f7ce4b0a7e81e","priv":"5f1d6278c5d244334eb10d71e4e642017c7d3d63076507b7efc9c63c8c7e5df6","pub":"02c26860be7973c41ef183ad6ffb901d07bac225b5fae444df8abdc605c7a1efa0","addr":"fa055b86c6a1da4666ea4345e9d98ea32198805b"},{"mnemonic":"dance hip come square bread reduce ask riot shift twenty scrub derive","master":"964f2b5fb6c3f11f33ee1bc9db915d820834cb1ddf9cd35c17effe93ab3e3e14","seed":"bd4b3ee7b0042661b560cf39f8a9f8fdb70bb75c7482b09b296cf660e2b6360b52263cc38a1c546d0f935f0a156a36089975a7fd5a65ddbc960e4b6418e1d337","priv":"6f9b31f5247941f3a0e3954b05f77d68c469aaf25f0755293b1fdb17bcba6478","pub":"03a3cffd72d5e6360090e4a0bfc8e1c691add6690614ee5fcc7867780d686259de","addr":"95ed911acfc3d1332ecd9c8b93a4372a27911cb2"},{"mnemonic":"excess route notice shadow post business cram kind ripple odor enhance future","master":"ab1d6e993bb9b533e854f15591af9e8a74bd29d000d5c8e77b98e3e34e96fcd9","seed":"4ab45c5fa427c0c81853c3b5c2754ab1f54873b0bba3710204fe40ac69c13d21ae011fe9c835566db313947749dba53496f84709b71f4dba08a7db209922ee4a","priv":"98e0136920ca7d3844e7fe1cff54db7229be2412de8de831b94235e8ddc2696f","pub":"03714b295b752de7f1cefd195578fa7257d5dd8b47a39e584fc4d2637a8f730d1c","addr":"9019db50e3ad4d56ece94e7d5067b27a33400a4e"},{"mnemonic":"flag maid oil survey first force grant equal brick dog where strike","master":"85c3230463b78c924cb57ca637b5af3f5910d962861ead4b16af5de1b4be274b","seed":"6203eede1ed8164b3ab32049def751b55d82ba6807d97b3eb094b4e6327ce732a54de31a9fc6178266a4fa7e6452b004d89875694ec13ad05475d7ad86ec3241","priv":"1aff198e964909f87d5b15c1693e5d191b9444109a7ea4bb58952752623e77f2","pub":"03921265a585b1ec932828f58cbaea6ae709c7f2af0691ba3f2f0636286119bcca","addr":"7f38e5412e9011a5ca91fdae448bb8b15a6bc4bc"},{"mnemonic":"jaguar panic thought mimic voyage able inch pole vacuum twist velvet pulse","master":"f7ded49975e280cc791687730225a70a89c79f5245ca72a7e538295aac1ac710","seed":"52f058e84e0809ac44c37485ce9da088c1617f05e92553a073378a0a0b3c9cc95aabb6d1dd2c99d084b03afb98024f9381d958f6ee5f516baef2db97c493009c","priv":"615bd1f706f7a88d9816200f4c3085ee2c748f9a42b25b444393f8cf2b46191c","pub":"02635816dcc956bbd8d9d2ebe94fb117ca20907a238c99245a9635287404d30e78","addr":"78105acfd135889bff6f0f70c92c38e0eaad72dd"},{"mnemonic":"pond stairs still avocado rapid peasant direct debris spice cupboard pledge budget","master":"6b5a25d678b4fb67cfa80ca3ab21cd6bd554e5434c4fd362ddb01cb46bdbaff1","seed":"69d5e57322a46cecbfe1f895c1b22e9bf17d418a06b73d49e3fc83012ca2649818bce2310f1b195c5b4873d31d6e797c5edecb8f30377f5e638ba1b4ce2f3823","priv":"9aea611859425145441b6455a0ee206327c2de06e2d26974197873f2ae9366fb","pub":"0236498052412d5c5dc3ef0d195a2a537359fc44246fd9c8fb39478caf29e668cf","addr":"faeac1dc66f281714303d637666c09606504a227"},{"mnemonic":"december cram web moral spell comic tag lawn since helmet moment act","master":"ee67281243cf2f77274bdc4b91a2ff1e660197bbca2fb42d5aee60e6f55ab4ba","seed":"8052120f630a33ce44aba16f1807236b1330ffa6170f985c630532fdd2713aef0e1d681699c4f67a9b9a72fb0432335c243828bea29489c92d1b01d016257ef0","priv":"a98bf3a99fff927ec2b0f208bd8a3a586ccc2571fc6333c57f2f1b7c22d2c8f8","pub":"02743cd05cb536e2384da4e0f110fa4f807abdba3e5e25e426e32fc4b5c65f761e","addr":"a1f0b4bba0be62c6b2497826612303892ed77b05"},{"mnemonic":"basket tool pink steak antenna process accuse brown walk pretty only check","master":"ce30c7daae3e0a5293ece548d66f07852003afcc80874474f5a94eac4a00c928","seed":"9572350a5a22b4c0f95fb2ce61c1f5e5846a3c2fd6e4cdfb2aba0d05e04e5b67f0fb394521b73836bcd4555cdda44acf0ab7ba43b475795868a6056295967822","priv":"edcff07e74dc83738075605d76a0c6923dc475ab122da2789b5a195a421c354d","pub":"02c03e024e6f53a1676dccd7850cbb2bc1f6a9a85b1da7cf0ecbf1c653a60dae1e","addr":"ac3c8907bc31fe66155a47a37306ff7b75905133"},{"mnemonic":"since equal mobile pond island before crew boat clean behave climb good","master":"1d1eca07fe5058a9dd7b26d1afbf2f4f71acf1420dc4ce9d2e3959734c442f36","seed":"4167279cfd447453ee7f46328bc40b4961f814229cd72762af278cf56a8efb18211420cdba43ccb06dfdb207716390df9205fa880cc647bb48455f437ec8e4da","priv":"60622d64880831974cf62d8f65be9e4d89e6579e6e0f1e5351a10b7574f3615a","pub":"03ba031ce6dd8976cfb72a2121165ea4bc0a8cdb14082504a05a917de09bccda29","addr":"50203affa88d87f3b104e237058807366f33c1f2"},{"mnemonic":"inspire immune poet penalty remind mule crawl drill rare fork track creek","master":"7c581d1907fb46fc46e6e9b81d83fbae02a75a2ee50a8d723e24700b530ce917","seed":"3822ac35fca2e3b5904e3284deb5c178b7c64ada6d7dd31347ea302e76ecb46d4bf926158016b76106ca61ae068fdc594808a56aae5e39da7893592310c33d2f","priv":"6f87d364a299b42c40a641d121a255228b62884d6f2d09068a384f7c6b515831","pub":"03f217a49a2068b2807a4f0500a08dbc7bcba6ffd60b0fe3e4f381a089b74506f5","addr":"c4a20e80863522069f8059e91bb1a162a7af7356"},{"mnemonic":"inquiry exile okay attend enroll author forget essence script conduct apology rather","master":"609da212416c631e8701b1fcfda5c412e0758270daa7bc796ac1492045a93a5c","seed":"4a75975cb2852f8dea2ef90535307e0a0063985a1c2347db1edc25bb96dffbd880ae88e8e5a21e91b6c26cdc98673effdf0ca84f416a45950cbb0ec74cb7fbed","priv":"c2e4db33ed61ed9f7a2b1452515b971a1bb20dce3b07efeb9437fe6ed481c9b8","pub":"03fb6407710ca5408d137faa85f2837879c4b0f4df59182a3d5f002e49c34c3bc3","addr":"c5217c9cd9af8ceff8235b2d127ef1cea8e94e35"},{"mnemonic":"entire diary route emerge moment only lounge situate expose hurry hip mosquito","master":"a919ae0bb832affae8e5269efc47936b6bf3e487740f8bbd2c286866a2224762","seed":"e97e0456756e343a7d56b1edf7468419f8b431c6c850299b382d3d957fff7c48f86114eb5640aee13d245c2a34d390850ec43c427bfec555d40a489397376340","priv":"eff22ef90183b533c5267d9c19f29f7a6fc2c44b45dcfd4b440181b977087585","pub":"030cb4259aefba8429f5e3ab0009e080674e887748e51ba2e0a055d2df3bc17589","addr":"d5db282d076f9d474651970abe5d2e3fece873ed"},{"mnemonic":"ginger glad purity aware siege tornado seek orbit sniff spawn process surround","master":"5498d52a17868a0fb5f1d2416277fa1a4220ac3a498f18f15e750d1140c57f86","seed":"3674479b527c4f27b578f0609f800de86a46591eccef6d40d3ac4436ac8c92ff12659e1e404af552f1058e9f17e90efc160903fd985f5b8069c66c9f6708abc0","priv":"5fcf38e09f4a3665256644715fd606ab60d9cd62f4c22962ec94b6fc5fccdfc2","pub":"03da1b1b03fde4241b05adc19515eda3ea96febdd5ea0e8f82dcc7cd98f1b74029","addr":"1186fc924724531d8ccc9f9ffd49701e62056c52"},{"mnemonic":"laundry reform post update crime page snack another boil pet cement primary","master":"3b1c3ee0d63328bab055d691bd29179ce5abb933759fcf83912adb41ff1bd9c9","seed":"60771d2e964301990d7ce6de87becd62e65852a4da9b819ce3fe28d72ab0e4619445d934172c1fc9361d2176f4ccc8d5b9175f4e933fd5e9681d8e8b177fadf6","priv":"755dcf792c67ba8a9d8b0694d21fbd33c51fb7aea67f05d2c8b0f38093ffa7ef","pub":"037118c561ac7773ab212b899b57f5527b77577a39a4f413232c8e7c6a33f9091a","addr":"bc2e19256932b58fdbbe5ad809e30a3ab2b2685a"},{"mnemonic":"pool bean dilemma foster reveal renew exist bar sick spot bulb trim","master":"4d1399a0181de627ea555f388952dd5d2c7a7b83e1a618fe8b07b03c1bed18e3","seed":"d788888f57bc052bf0d35abf7be1175152aa607b901d1040f4a28c8cef343f0fed2031e3bc9e1eff77eeef4e024234466a55f70150388824d6fa10051133a464","priv":"00b7f71d77cf0d4e13e51403c92aa66ba543e9cfaecd810049d17794a4c0ded9","pub":"02319a6d654cb42a231f7d021e2cb7c9ea7624c37d6ee32b218d5ef79a31eaeb46","addr":"f6d78ff49d6f12b82e24bdd77bebb536566a39eb"},{"mnemonic":"poem leaf scrub bag bomb palace discover pear rhythm treat negative system","master":"4bbecc45fde87cb80a4cad7a4b08068265eb8c12d4ed36d1c9a9a7e5e73c39ac","seed":"efb6bca601760ffb2b183bd4cd2e84a864eda3bb4b8b1369095d3df69fa7ead0b8bfdf5a097f37bb4b1ccc452cb8935baa165f7ab039342af64e9e50bfd51b36","priv":"c4988f397df2821ee196f98e62e4a1542e53ca1e46f966a4d13c4e3e389d8937","pub":"038c8e4571f8f411827ba778340beb7bbc29fb47af998a852da29b4f1583d5c600","addr":"67b94e1d532cd8e42e5a74cbf20f7d079f42055f"},{"mnemonic":"punch twin village ostrich frame goose dance history valid mountain volume high","master":"f9ba8580f4d53e34d9bfd3b6a2e17c5d8987c879945df9bd20407d3f8144b108","seed":"07d40cd18ec6abbc351aa23172dfa6582ed83d5bb24d5cd830d7cefd23d8a2ea6272efc6686606e61507d5a793b7fa06f83bf73504a072e32a002750f5f240d0","priv":"10222b81cc386d25eaf5037fb8fbfa9c401c1d192fb715397f6636dd94e9db3d","pub":"038b04836ce19b454a0af260bc1271ec73f1a0998d8659e9cffe38fa5e4d696a77","addr":"55bd4a574aaa1be2c02aa2eb40254f8cdda7a682"},{"mnemonic":"ready embrace photo find orange curious essay pulse frozen earn wild travel","master":"361e9e44283fe7d3bab83395ecb8373dff5d0a4d60274695637cb02955523741","seed":"ab50c5ab74b1ebae85811108c372651ca8d275e7c2b5d0fec9f261966395482f311a76dd297f2d2997c6c59247807506ed20f524a32dff90637956cb7868aaed","priv":"1ffdff9fd05b67d22f10076595e0025800a8d60f022f2bd99ceeba93681372f4","pub":"03b168906d5b255a896509c8ecaac4a8141d22ebe005e6dfb2892f6f12970dba2f","addr":"a7d30e12ff906b2ca0c6df3fc68274e7e30725e1"},{"mnemonic":"pass paper cable blanket meadow talk govern admit busy base hold broccoli","master":"db0e45010140df4a4514284d7ba78ac7a5771ee15820856afb1d15a4e3b0af7a","seed":"521ec955279d92fae9dd8dd43162ee216798f4a0276a2c98b29dec8dec9bb26f17e6a49ce999ec55e061379166f25116c01b8cb48ded23c3b3087dbafbfc5371","priv":"b5bf00005304278d5e4aa792de142a6cb46bd6283ab02222de50cc2f01009e09","pub":"03c188a8581f09d9eb14252f8d1f5cebf1de8189526992889115c6edb1cd180090","addr":"0f8fe4fac4fd85d649d7e19d1773897aa6e75f43"},{"mnemonic":"weekend infant spin powder hurdle pupil disorder always excess unhappy price decide","master":"b1bec76f3cb15f82e5c9c65aa23d0871ec06a590a3823285a412ec9a243b1c1e","seed":"5a8d16dbd0586561cc81273ee320c6c3d51bd90bdf08119ec81596fcab24335193b33fdd621800daefb49e038ee079184e569b941ef5d839987dc1e24f578039","priv":"90ffc2ec625f528045a432ddae8d20017c9b1a883ed22ed403783e10801077e4","pub":"027d4213cf485f4eaf3ea06c61057f92ae8fde8362c3b2f4b167639b74153db673","addr":"c9b1073f122b5ebd155d4904cbc32da4281bed6d"},{"mnemonic":"agent seven dry cheese rhythm raise junior sorry spoil tag opera bench","master":"8cd8ddb8ad3f12fa347780c4614e38198a51c00bc61ecb572616382d6f8388ed","seed":"ad6641ad541b411261101e5f76036fcddd8af62de1966a3b9a1122edd1e6057e38fb5e129c86427a68590c87cf9410fc14ec08dff184742a54461c205018f43a","priv":"f15efc08c8a578f7035a672fb51c2f6929e169e5ff37802ae8b50f1664c025a4","pub":"039926cc43000431dab0f0f4818fa024ddcec0ffe9c483f8ec294cc863f5133574","addr":"89846353e3a3becad919620dae0a2d22d0533559"},{"mnemonic":"floor sting insane slice pistol blush follow muffin acid coral aim make","master":"f65fa0d49225f5f373eed6d7d6f9f8f73f80840c6027c3871645679e51f2dc81","seed":"8782d6395c27d8b9a3b0fe29e44093e5150c9b82bfcb6344e6134e954c1240cb33fe8c9489b3ad3117f5c112f02f0eecb0e30efa36db18b27003df5e542face0","priv":"de11f15f7cfb0038dc07ea2007019c17747e5138cd83b37ad30621c9f41b1799","pub":"02b662800bbc56c144f6b39773bfb4d496c9f1442900b59641aa94c6b50a783fa0","addr":"70b1ee56807b9191f77b1d18ddfd181677e91654"},{"mnemonic":"canal today stadium spell accuse cream chuckle method unfair regret sibling old","master":"90c0af3882fac84793812f44eacb1d4cf13b56863c70ccfd6866bbde1195036e","seed":"c1b4ea5bc074259d2f25ad7338b423c5ccd2083b60f0ecce88f7c5d4cb39806f2da873c05cd52729ee07512cba3af26f21354a3769350d5bdd10868ff46d8e28","priv":"9ff9156b1f137d20b486ea125515fd7a2f057145fa8313203606ead961ebed84","pub":"0225998b8535e9f2e269e86caeca1ed90a86414d8c449011ea2fd9a488b7097528","addr":"40f33af234da7de748b02a01687a5e60429ee07d"},{"mnemonic":"object sure already seat attitude great winner session cool addict direct popular","master":"86a35c7ab59d48a897f6b4a78221c8acd0850010a063ceb912488352fa19048f","seed":"fae4348ff7c42cb1ff8542bd19721823917037d1cb017ffaf64547be8ad4b296212d6e952b2af66db8541c7e881136aa76e17e4fed926064bd5edad8f25e0dcf","priv":"2df0f9c67615ca9370f8ab957db6ad6cbcff1b5353f745dd24125ad36d7c77c3","pub":"0367582dda754c5345514b2618d0844e83f8fb49ca39a70d00537c70c86b6519b9","addr":"128a4f8786a46bb7815e59abbcd85bffb526e953"},{"mnemonic":"sudden more spawn have pig observe embody title collect junior sing bronze","master":"c71aeb48c73d6ecef04597f248dfef9ebaab37e9df625a483db1e883a972a36f","seed":"eb1dcdc3ecd77652223ccccacb85a255f350028a843bed72ff96d4e3de5566f667af1d5fd48aed32d2e580f625bd258cdcf6760d1089ee3f9653375bb1139f9c","priv":"455da9b7df9d00ce53973439b23a26a75463c9ce0bdd73eb16a39e019d7786ae","pub":"0327c673e375a95e13ab6a940c18a35874331db2c0abb283736890b0ed1a09b79e","addr":"d173a47de381e714e3873d1e0ac05ef526b0eeec"},{"mnemonic":"world gown final mind dinosaur stamp unaware apology foot flavor hockey bamboo","master":"040827137019c4a9d29c1d65849cbac940ca0dcdac2ba8def0421c990c90e2e2","seed":"48c5532c17475f0a4d63d76daefe7cf21681b32cbbf4ad8cbb62b6fa872411fd2b8821f8f2ea97cd9004fe4585e5ecfa27ee6c46caab89145c3b0b4b7ef5c073","priv":"d66195156c08032f912a71128635b25750335aab186aec63ec9a83e9b24c55a6","pub":"022d8790106436a60a3b74d10fb07e06cb48b2b13ebfb81a608039d80e9d7c1e64","addr":"fa08eb0d89958302d67d4de8b99fe0c53ddebae7"},{"mnemonic":"bag bridge trip improve blanket machine asset boat mask flash vicious pig","master":"21df138f80902d1ee79948ca3836ecc29a0f9093b06a240b29ac7c3aab89750a","seed":"99cead310304d8ef58b23fd2b9ce7fb71386111ffda2f609898bd59289862b6f464ba261855b1bdbfad8f7ea25e43adce10f7386cb6cbb744ee05772b883d176","priv":"c82490739f0d969706299c3ecd89e4f47d0247471ad2d3f7ebba531b8d6804d4","pub":"03dfb5455095553fe24c1474c5a5dc0fb69aba612b79568486345f73fe27d36205","addr":"020c6ac4996d1c91b2b2894c426dc8e32b083fb2"},{"mnemonic":"auction okay cousin sick accuse steel limb staff tube gold hero add","master":"5bc8d22635bf6ce1494c820527e26a94c57f6987d6cdf6d40825138c3283e6c2","seed":"c7df0872664b4b4b0a7deeb3c26545380bc61fa3734a20a82c96e73707ae975b76b12f31da65e863040b2215c34a4e9f525ef38e555757a9e8a42a20af2f78de","priv":"0bc4a9bd3b88ad78c34a309183da9a0efe4d8e27d098282e3bb248cb960e018e","pub":"0200d5e1fe0707ff11dca2c30a0ac83bfa40ebbb7e51197993c6910312fe91d75c","addr":"72ada6e822ffed23ac5ff5147a22537b984bfca3"},{"mnemonic":"trip below tourist offer burden hungry later grain quantum universe service group","master":"7990e7b10c0c6bc95f45933e8f5be1e758e7b7b2ee39b8caa00e8ca50cc66855","seed":"a96ab2ab3fa2bc2547cb20cdb3e39eab2ce9dedb053277c7802bc0bdc4ba9d08a3860b48325c662de187c935419211bb64ca07448988f903cde04eea9f0f6e68","priv":"6d922bc8eef11400f93de7ce47b55d3e862ffece29fa666ba05c778ffde8d91f","pub":"032567a2ff9a50d1c4e6cc525dfb96da1edefa91fc09c32ddac3ad446056f1ad7c","addr":"abaf696230fd241bfed2c76a0452456bb608c17f"},{"mnemonic":"bacon together open trust hood detail liberty bean spread awkward antique minor","master":"b96abff8fade8664e35d68c78f7609f1c8553a02b80c81857583df0134513370","seed":"772590bec2194f5b552ffdb2eaad756555b22e979ef0463222af6711c53d77623ad9c34abe48b7389e67b10e56aae448e9d064e4be58c5d45c4de16ad56599e1","priv":"532a98d8be2812f88057a91510a20ed4e7fdcad022162e3d3dc14a34104859ce","pub":"020020a4aa457c2944b3c333141e9dccf1c500bb277b846d85a77141f69332a315","addr":"3b5c6eb43438c07d8591e7c4aabe8d4540490bd7"},{"mnemonic":"bulb jewel comic drop copy wreck unit engage meadow hurry acid thrive","master":"c0755ca5e91d4ec8f6dc7b2582d65dc70786a3ea67cd40dd68462ce13535ed61","seed":"e808525cb5c66bf4080ace7b3ff7d6454d07723ec23fa16fc0b3a346d7fdbf71dfe5f383c13d68de5b5f04cae47503ff352ae340700bcb75f2ed6f0eac3b7c5a","priv":"4f592a1d10867d00b28197be6207977e13c9fc551449d05be284642c43597132","pub":"035ec6120eeb601d6b3b444e066252a4c917cefda62c49c0ecd6384c1ca4db826e","addr":"35f84051b0a02090acd509fc801b21864c45ce91"},{"mnemonic":"devote guitar planet kick now above act sponsor account blouse divide horror","master":"1d5329254a9cffc9de60eaedb1735bc8b25c77142a9ea2098e8227ad289b967b","seed":"462b9b3d13f1b1e9e802525e3bd5e22f97a31b352240c9457c1f6d5f194c6e7b7bc37a4fd2607a27adbb77dd837b9114606c8dfc54d78a1a4c8f703889a2e50f","priv":"d5a648822e5c20ee1c56ac5b08a54e561a392d540d3e964499a5a970362c3829","pub":"0381ee04ec2cd440ee26d5a37c3775047e0215b2919736e092c2aaa7152ae448fa","addr":"daf4d242b80955a2269006d530ff6826f718fca8"},{"mnemonic":"youth error panic brisk panel hobby mimic nasty address little original sense","master":"57a151782b47da723e7bc39b13200bb9ee0c3621e839e179a92f99ced03d15ac","seed":"600441626b7035ce2b4e1a90a872ae2279cda57d8f8f44ae3c99edfd0e23ed4afb3e1f4e9b01eb5cba5cafff6a650f2d586d1f0ad85254cc99caa47abab30b4f","priv":"08030c2dd269b5b60f12ee6bb27aad68d3490ef128ca704f390e283ab608203e","pub":"03a38f69571f6187ce334833b798fc0d32065fef197f5812e4c392de54fce4bab1","addr":"02bbd2f05a3c4979db5ac72246d7e620e3edb769"},{"mnemonic":"age excuse wall torch dove enter movie almost build shock blame object","master":"cb4958fe22c8250f41998f6e869eb6cff240550af2db41d0b92e9bb64041469f","seed":"bd585927d17cba54ff5b2b63f2a98267d197ef07caf6a82b3dadc45bc5348d99dc7dac59e45561e55c3513a62ad1942ae2763168562c74ed808f1a59b32a64e3","priv":"7923cba208f6bc84ba7eb134836b96b69bf1f75330caea0be218df31885cbfb1","pub":"0369f14dcd228c164170d5187c21d092b4238386e0c8231a132cbe41e4ba315df1","addr":"93a1e4c78f24c08c48572169fa949001049a6528"},{"mnemonic":"expand shine stairs delay calm soldier deny volume whisper island topple cross","master":"0467b91a321c4326fec8f39cecfbb2d273e628837044815cab899f8debb66376","seed":"0597787fa9ed69ce29f6bfaddfbda091c7b35b6dfec6bcec23957e6a547819c320504afb3ed7a7c5636e4496271d2681891ecafcb9a93ec71bb7b5d9dd06c710","priv":"ab2422cc32992afafc497d2aaf8e4ffb193aa02a5574b0be59cca80566ae8a91","pub":"02348311d8c7310491aaa1f3bfba7945844cff5573ac8b5788872f594e20746830","addr":"a1d27d518ffacde5dcc9a10ade764cff42399996"},{"mnemonic":"sense palace seek enhance hold exotic sense pyramid program fuel deliver heart","master":"715d3a14fdee63848d94f9269d97fa562301f6899487a5ccc9d987c8eccad3ed","seed":"e80766a81744ba87d4faa9199a2b6d1b829256aadfc46f3b647be1788cdf324f8a4ec4ef52af07bef0d60ee090d3c2f45ebad582eb326b688366ebd7390df61a","priv":"7cd5560b3928e4048efe644e39bcc1eaa9e8b783c0f3f0ef5904e030bb6d63bb","pub":"03c7759ec461940a6a3f90b4380286aff6307c2ff6acc234df44aff978fdd7430c","addr":"0d43f6bbde0c5687561d8f5d457bfa78581b407e"},{"mnemonic":"poverty defy mistake begin dizzy behind annual olympic glad behave coin rhythm","master":"eb342d1dc891e285f0d1822af5e00ce3472b869c73102f87c008f73099448ab8","seed":"710a0f8ebbefb347f83eaf54d2977cd64e1f90d4f8de33c8ff041f807d64e5444707432877ffb4697e2e554d1e5bec48ff7428d13ed83433c4200b7aa6bd7c22","priv":"6c36c88b1168a478325ad77e220a77f10a2c8933fd72a2babbc918cd683cb265","pub":"027934c90cc3c75daf4971ccfc56f672fbe33f86c852f648afaf260989961be283","addr":"d60c6edc1bb9b47b0f2baeddeba2723e61aae00a"},{"mnemonic":"artefact vanish security tooth rail claim drive black push ocean special uphold","master":"08d1f1528ad6dd4424ca11825ac1b47111969f21b0285b3bfca9a2e28aef095b","seed":"add463ba53586dcf678b32e6285d40dc5502f91c3dd1128351380f52a28d08b9ba747c28aa85164b342e95b44c1ee03ce9c0d9029979f346ab6d9dc3a614f7bc","priv":"e22dff0eb96c0599766b81a0399e62589bf6e734003e45bbea048ac37c8c9bda","pub":"029954b4e87d373729575ca9b1606c566108753e12080de2739f64ea0a9b881ed7","addr":"0c670a5b8b1fe0a5e43d7efe0a905f67c5ae47c9"},{"mnemonic":"supreme correct virtual guess funny grocery assume dash blush rubber wage chaos","master":"09eb5b5fab562805b57ed0f1a96e66d56b8e132d885f39cc5d76094a4e169d91","seed":"994fbf31e1213b7c113ba0b47563afe37de2acab7bd17ee071c04b1616c6cb50d853bcd5203a9a635fab9dcaa07f0d9d4168a7303fdb53ef41cf5ff15db83704","priv":"1b56d4fd8c5fc994f22d4c7fc856aa18814f269c0f43fe65b52c914a186ec265","pub":"03941aa1d30a3122695e69b6a7f8c94edf030255255a33d82484f90c491dc77f1b","addr":"ebb17b37332f0079728e9de0f2b40951a233a9ac"},{"mnemonic":"pyramid insane eternal man arrange earth predict panther atom fashion claw present","master":"25ad3023a8597a1960b1e6411d75a821d86000ccb3e92a66646017f56dfe65b8","seed":"56231905c46f23f005085a4618005b1851055dc3f639f6b1169189c9bedf1bec6efa219631c333f0cc488e06a0b5babbd781071b7327dd8667bba0467b6630cf","priv":"0a4413be4769217c1f03bddca1fa921ec7935b473e9f13ab78f2b377c08198b6","pub":"02f4e8d8f9f165017e917b9128160fcc8232e03a7d4905583e60a76d3e532bcccf","addr":"d7356ce66dd427267edffbc7d90b1499edb2fb61"},{"mnemonic":"enlist pelican teach loyal like false property ski salon kite thunder gossip","master":"4b0285f521bf09632466c22873be5543b1c228edfdeb25838a3100d72c9bab6b","seed":"9c0e2337f5f02183d2dccc181372e47f8d89c3ba580e144fd6bbcc4d852e49d4f3f093eb1e29e9c0a58f84c6339033b800af15f212b01e7c60f8b89c3525f180","priv":"63a88432a7998b7af6962bff643d46a1d8fd7d4076923eb4a0f76a3038a7f26e","pub":"0284e4cfc7f7513515d97a68efd241f25c47d0b88f57b5308e508141b27b9ef2eb","addr":"2ae41ce0a0a995d865357c09749d94564f91ad65"},{"mnemonic":"congress like unhappy run unusual citizen flush force welcome arena clean student","master":"478229d977380296130a0a3d61be2ed2f8423ee7021544c32372beedf9e8c955","seed":"ee65535652c8733c881553f9ee7b9312a5ffe999ab40e12fe5a7b54101bdf8bc078de75d8dbee815604ebe1fce0eaa7104114780e074d4907297d29c1eeebbbf","priv":"caf650347982b40bd75eaa1830cb5d0089bfc011156c927ddec0fd90b333f590","pub":"037d33ba4e7bafde02969dabfbfe3397bd6744f1552da1313ce129f49eae410396","addr":"a00609d65a4753b3888416518cbd4c25282f355d"},{"mnemonic":"science reject slim wife shove laptop pull hundred genuine method canoe globe","master":"c011d8e6c42749fe6f7d1aea4b04b0d6e618650b0253710c717ece6d31005d05","seed":"40209df29de5baf4dd6b82df091404ec2f1b61f47bfa5e9a23e6d030848d8bd958138192458d82dc60c6c46ec01bf77b5c447e7b2ed0dace4c668d08c86719e3","priv":"058091efb05990cc436342cc3ef6efb2d0f02fed6380370d60255d37a2844939","pub":"034048a3e9bc89ed545de8f2131437838e7fd9477a7c3fba98032e2305732cead0","addr":"dba1207953cdf07ef09213624b99ae24780e8051"},{"mnemonic":"hint where immense cactus sugar entire stool accuse suspect cinnamon pipe car","master":"620259cc620b3b806fec360f2e9b84c4c5b94f9ad34c53b40debd1181e2da675","seed":"3332bd304e7a5b1120a80ce1fb74c1e0554c2fc5d3c007fa58af862c4c2450d9a1fd12c90ca6be5dbf9b69131eac8804fbe0e45ff433bf4d2f634b527319458d","priv":"536ffb48ba8ba6872cd9065c0d76b511a522a7e3b38c84ae16bc3eda2ef49e6f","pub":"038d3d8f70aa9ea108a19076d0e90cdde8d302b709aca1129eaf9ec281672b8aba","addr":"0fcf72bdee5071ce4f241e3c908ab5b0b969a37c"},{"mnemonic":"load loan mail real squirrel gossip fluid wrong amazing own post exclude","master":"c1cfa046473eee67b03ab8be8519a26c8cc72c01324d6a7e6108f3993a76d937","seed":"0f20d1b5e5e93bdb2031411be4c5590f977ca1ccc4550d7c8d8211a62221e6a5c6f34f7f99edf1f785811703a3540bd2f3dcadb15947cd4181b6e80fa988996c","priv":"b0dd0c8d5a07124f574ed87b406f4d51a77491d78f05ff5e80569741c8f044b9","pub":"03c403433ad539d2bfc212628180632b8d860172c6ce4ad46a3e94ddb1657ae889","addr":"145995cd3905204ca68f23c3203d5fb6d6eb8fb7"},{"mnemonic":"attack zoo topic note remind direct inside budget section outside permit inform","master":"ffc2f55b2c123430dc29c09fb431b125b5a3f321ed0ab5f64b179fd3358b0e02","seed":"693b14c3a0b6c0854971fdb5edfe2b5e5d3d37e524a96186d15fb0ab23f6d250b250f5c23a44d28ef9b94210df582d85c17208ce468d09029039ac5dcbd1222a","priv":"76f689bf1d6faf5456946bca3b048cfdefe39b74eb3e0e9d85c2da386db80d26","pub":"021e00bf6a0a71e0a37a8ffac002c5d5cc6350fee3dae6fd197a18ec880309fef1","addr":"7249de82b9250af13b7c309d32688ff19e7ed001"},{"mnemonic":"practice hard harvest gift bracket panic weather crucial have play reveal athlete","master":"cbce18216889b4dd4d2887fc924e98ccb5aae1e9b5d7433c120c79ec3ecc0aea","seed":"02bb9503765066c4e711e1a78be25e7b49689e107f58a2acb252b1c16dbb259db566a06213848fab833a32e34ce565788d7af30f584c21a21f02ef30dd2878e8","priv":"e6e7cedca2c3b1306cb06addcd2a861d04bc383c1579ba9d044a5c752b1b38af","pub":"02b11ef0b566fd9f429f88385507d63575094bd21caf8d3653a8b829c394de0920","addr":"8c0edef9f59b632305c72112f160e9c3616e3ebf"},{"mnemonic":"frown mix normal orient tower hero attend occur blur ship ball motor","master":"87c9a61c0fe1e8760393b18cc556b8f6d1d4bef0355444aabda127b342865d67","seed":"8e35626433f0913c1799adec7b23de7cf6d0689822d3a2f8d1bfb6ab041c80db3e5703c96aa09ed0db4e4f72097cb652e6d01d065bb6ab86f19e498793fb44cc","priv":"47b7699713fc59ddd67a556639c3f1ec0783a3dc3424cdeae4335707a549181f","pub":"0281ee7c3669207a68e189aca625e1b6eaabc909ae611a6eb2072f51a6f26d545b","addr":"ddd6d8013e5c4f99900cb22184075afb7842acdc"},{"mnemonic":"beef apple unable rocket balcony tag tooth spin sunny innocent clinic dice","master":"6b08fb53a185b5da79434bff6de9b10c558fae63beaf5f487c36760da44cb28d","seed":"f06397170fc337caa0278b2324f05095d587887217f5f10b13b04e1286158e4fe6a15da54c7dca729744e268255f4d04530763580ac7d660b323a8e8fe163753","priv":"923e63fa8400088c1f464357746b9e95560c23a755427d792aaffbb73551fbd1","pub":"03046ea68a2e1930e531b00376a4254da2a1ff0ed278aa800af2fa17cac40021d4","addr":"3ed4b79d2755b7d95fe1626d26a2b674a927b3be"},{"mnemonic":"sadness frown tape chase swear cushion eight funny sight dad solar civil","master":"af805962cf1c7bd97d0e4e981d3157834a17d3dce23a426c299b128685f28bec","seed":"a6292e7e8f3a502c4eefa0cdc94fda1d528642e084f45b30840e2ae9e7be636bbf2d67156e3bd352d1bb0750fa4df04dc5b8b6479c7c98c116c05ad5fe2d4d83","priv":"0bc87cd2cbddab83294a804fca193a6bbcaa3a07583bb2dd35619f325b70b7e4","pub":"025811f4948be5336572285ce58c97da84e5a4b7c542180933a1f4b6200ee4ebe6","addr":"9c6867cf41071e1f7d84ace3d2802ee46a1c08ec"},{"mnemonic":"bulk topple anger gift matter soft dune hotel dutch guard cycle close","master":"816ece50d6fbbee470de36fbcf646a83d224dabf5ca206786202f59ee7be8831","seed":"4980fcc86c5112625b63300e007a26287fec1b2a9cac0e254a8f43c91d897c03a3663fee0b351fd877171ce708b3fa471ba67290d6ad32075f0f6be6d3f70ec6","priv":"51cb46ea5db7c500388df8310bc5c8db7bdfb7c797030aa8f4a262b53f82a904","pub":"034e93f88a8da10122de23e2b25eeaf19aa1df514293b1e8fbdae2ad9fc2782779","addr":"c81ba2724c2e99a7168bd74cc79e222dd845187c"},{"mnemonic":"account lobster inhale champion relief scrub poverty tornado romance build amount exile","master":"202f11a0730b769f90d0fa68b81e9fdd78be483e38a9a39c447e8315d8f9fba3","seed":"001ce5c310547070fc2169bf0cb7353b90e824c051ea9f285eca426cb7f2527cca995865b0466c86a0fb3e208dc1ded076d2b985c8557dc7a94af7c6631bdd93","priv":"d142d2616dfe9e3aa43634a94a05707a8f0fa58ae0186bb565ecb87c96f648a2","pub":"02ca5eb73da42320161564c42520ab1a4b5823805bdb4dcb44a4abd88a235c6b2b","addr":"4481e257f1cb7d8105823e54a1b8d0254745874b"},{"mnemonic":"defense knock simple usage cook shoulder alcohol muscle pigeon balance become sister","master":"26df035303f63f356b451e829e154cac27e3f0c1686679c784d405455adfe5a4","seed":"44955b360a1622c1a69d20315b5fbc982502903b45736acea4f146c2cf69632a99630195b1166be96e4c90449abe1cddfacb3be63ff2b7fed02846b0d9244022","priv":"b9dbdb8952ce34d5f575b8b012a5e3041521efb893004f45eef2c01eb4f5fad6","pub":"02e9a6d02ce5cc1c14421c3d6db53d16a048e0421128f1ecc1e3e41d7df9d4e609","addr":"4e78dfe3fc045b8f65760a337ba354e01851d82d"},{"mnemonic":"bonus surface unlock noodle genuine stumble juice purchase grass table call piano","master":"16474b5955a793884279a9936804299a953427a38d5bead30553ec709bf42c74","seed":"da8eae0d3aa27a6ef6637dd17d57fe98e75619837c3dac48b3b546152d5fb1dcc4c59a86f65e8716c82e3014ccde5779e6e33c2a2658c71424f4ff9ea6ca0065","priv":"c9bdbc26bc788147d12c4bc3b13ff3774a7aad1ac66ce45e742c7a96eafa2a5e","pub":"0398102ae1bffc71eaf086b652c9bb847dace83d0b3f87d91ddacfb1702762cbe0","addr":"f0ead6caf66523b7e655b4ffd26a8b35f0b09eb3"},{"mnemonic":"envelope scheme knife muscle museum town valley until quote interest film keep","master":"bc01f4cbe286c6ad87553e0ece0e142f49984c2676ed1fc5142abb75637d47af","seed":"89867eca31ccd75983b064d62a1b4061d1f64c1731e25e08c65259139590490827869749ec30e8218e593e2ecbd4303984dfdb7b15775a487ba0eba84953a940","priv":"b5c899498ecb94655e622f999bd7ef9a2c4d26c3f555ee6888e5b4e1abbce1e9","pub":"0316d5c61149c0f83944192a788b5b64b9e6b1ce49f2604db67e8e4f16416ae153","addr":"b2a48800c35e6592ebe5003a46883a00360e2b44"},{"mnemonic":"also genre defense valid point smile hybrid radar lesson sniff one recipe","master":"3cc6fb6c4ddaa98e3daa2e984189417c55c1bfec4089397855f809659f9316cc","seed":"e962b4cbed0c3d5232f75595e7aa3cb33f1b2e093bcf9a21a4f8c6dd9677aba42161fd8eafe38fd12ca0ce3cb58d4d26fb7d349b1a160bf7f6f6b6c56284ac6f","priv":"420f0121df8cbc367e966344fa28d913bd1c3a1032efe5a3627d94039281e98c","pub":"03a61034ea8ffde7a239db255e414008c8e913a1405a34d9a606108f1943a7fa86","addr":"5976e21c1f85766c535011aac79e8a5f8b0f08a6"},{"mnemonic":"flavor spy elevator parent theme become slender recipe media pudding suspect melt","master":"4ce14ced0d4121d342d2c514755ba73b17eda70cefb20efa5aea71ec27ee47d6","seed":"0040263c29e5d965556054dbe7a738ea35b46775bea5859bc2e5b3872c89574e4f18de3f6fa36df65f47b13417763dc8c020b498ed3e9f11f46f019815bcf9a2","priv":"d2a1436a12fc9e4f2acce77564b8ddd67c1107d525eb6128c1eda078d3d8d845","pub":"03246bd048416493a970d97130d54db7e263af82dff75cc9fd0cf1e061f5d3f8b1","addr":"7eecbc8b6082d62d5fe28846a8ddc20b16e6a9c2"},{"mnemonic":"path number useless federal birth such peanut rate swarm flee current grief","master":"01d57fdf15aae5c1d45349fcb7bda6ab271c15be88429ebd1122336b91937540","seed":"061d0906c096a3338ac0877a102b4bb3b375ec5b34809838dfb47b186051a0a66c98e0d4a4dfac2c02b86266c4574c141f7a7c9365a57449ade60e28aecdbca4","priv":"9eb30cd9489297f0c4793df375a4a497162c5b75c36feb0a979da41000cc842e","pub":"03e036866bb847db7570ce0e2459d009dd1a89eea3fea8c3ce4f1f47c4781e32f1","addr":"139b3c7e7cb476da573548067d0a29b5abc111db"},{"mnemonic":"observe layer grab few fiscal omit clinic manual climb cloud song million","master":"cdaa9864952fa51a5a10de9210ea9e0199875459304876fdce150f042a415583","seed":"fa2c9dc476532ac66ec8e219c69883cb9645129765b4698b7f2010cb4b86b2d25ebd45e6c582a9f886c5fba4cd4d7488e81d705e63508e67c1698b77b8e6a676","priv":"238ae189645958242ffc9b3b868d78bad1be7d1351573298aac47ee78a5dac41","pub":"02ba7dec8131970a8f4a837bc225fe1e8fe20ef90b6363c058946930fe6b8cf629","addr":"4aad44c69095bad1588eacbffcb5ec324dff7563"},{"mnemonic":"solid business era limit engine fringe recycle harbor organ like tiger avocado","master":"afb951280a835f1ed21d00d478a644451e254310701d8a8025f5c716a5843731","seed":"2692dff98bb318f1f583e4f5d87a453b9e1472781b38f3b6a19784f8fd3e9b156ac6a292f8ab56e1da0967e159438b87b73042cbaf3e9886ee2641e7e97dc821","priv":"4b4bb7fa92a26e738da657b31ae57c52f057540f1371066b2570fb247b2862dc","pub":"023ecdde05d734b6ac286c9b14e1577f691f114b6554d0f1b389fdc37e05af9a55","addr":"5402fb7a4751cb34b261a2a2be940d7bdd3608ff"},{"mnemonic":"convince thing assume midnight debate end best cause laugh sweet unusual present","master":"7cf2f1baf94a8487a364a742db15bef15d1d1a7583ea26dc575b0181357e31dc","seed":"1e267ef4dc1099a438a346c7ca4c546149d6a57dc4cc6623ee160677711144583245125cfdbe45629160f3da711fbc57171564c4cbc771b1fd2a21236751eea4","priv":"9eea5ab5b8b22018197fd3c9256cd21be7dc26a111c60bc3d853bd977a19c90c","pub":"03e17aadccfc20dc41e65f7256717c54f9eb3898fe335395f25a65d4a96cbd93c6","addr":"85d9c9992d5351d84d40790e65c29b52b929f7bd"},{"mnemonic":"property youth river offer mention cloth mention pride opera repeat hidden orphan","master":"7e0faa6a216e4ae162547f5c9639530abfd56ff2026b4f18219d1c82934ab2ff","seed":"dd9faf30c2ddece69bb5d937c9ee58172564ec51d760fbdfdebe4dd445f1819bd6cc21a2a4cb70fa94a0d941d994d3ff58331be94f57a16589cd7a93c19ff10c","priv":"fa343044822d07308bc523eaf778bf697302cf8b88a3431bb5a0a51974a43199","pub":"0383e1d8186c1b3d0c567c91966a5c7aee8a1492feba372be735f9a612c1910ed3","addr":"efb2221453dfd951ba456f1c5ac164d3faf08032"},{"mnemonic":"awake virus civil cash clump equal phone wet friend attitude ask act","master":"87a61b5729fc2e294da66541b79085aa3f67c03a3eec40559111e68fe5a80412","seed":"8fa5a84240149f39dd60a5477ac59586aa05d6809adffb8184e4154dad74c2ab9a446f296098c44fac8c839d3405e0a2c1edfc26ba3aad9665e6b6984d320fbd","priv":"726210437d3054875e785b12d1aa23a8cab85a0a809593cafa9c63c62e6e3c55","pub":"025494819085e1d08d8ee2d421e4ca873682c69446ec5a412d7c7a7520900397af","addr":"e26e023a2aa67a3bb5e5988be46ff266722c0153"},{"mnemonic":"snap control problem flip minute huge lady elbow plate fall cabin trouble","master":"931052717250728c04dc605a8cfcc6a49a4c520f9fc343607fce57f5ae7a9e66","seed":"f55dcbed51a9db2ddd39d1164a81049af71116896e79ced722a387e878d00633830ab8cbfe7ee8e16ee612e1e047fa3d3c2a0fe230adc6a84f0178fef6aedc61","priv":"72aedd9eca0a5f17b3c20866d6d1e98bf01a1b8b9225bfb1d93f93c594726ee0","pub":"03c07579c66433d1b676630a0ddd343167fe91419a14a7859092b6b7f81341dcc2","addr":"37b2d898f165d5cca507de65f103231ea5128788"},{"mnemonic":"wine foam depth wise faith parade tuition search demise skill boat survey","master":"5001f6ff67ae2a32088e0ad93a227206bd66f5ccc7be991a27b2809354050b03","seed":"d889ec2bfbc930c78f9a3fc356e0dcef9d636766af361c8492189df1779bf76f4890d738106132cc5202ee97b849c9928a8934fd0b40d610a38f514953e3b02b","priv":"c19f1ce95ac35938d19d41e45d7122e8faa102e219188d681559d4db3f6aa66e","pub":"02331368ed143ec22cb1af2794bea8dd5e5661b9c6b1407bfbbdf1c1a151250b7c","addr":"a70e3677cb94b449a400c870159dbfa448e137cb"},{"mnemonic":"picnic basic you priority gown town oppose penalty various half follow nut","master":"59f5a86a5f6cf3254607f5e9846c7725d7cda493ac9850042de3bc7e8902583a","seed":"85645734c0caad6d0f3be793f71f08f2b87cc92b515e75abf94a202941c45aa78f663b455c91b6d51de40284d9c26a5336d444346b408bc12d8690e541a43583","priv":"17efc82e851c2938c22527638f4f3ccc2ff16ab95c24429c583b6f68d79ac948","pub":"02e534acf511fc86761ccde5eed25d793831cca6069f09694467a3b7434cb3fc95","addr":"d75b0c916f2329006221b040901933b2bc309838"},{"mnemonic":"enroll shaft young ramp moon message echo piano advice time blame mandate","master":"02f99e44bafc4e61bc3afff77696bd72af71ef05c86dffb2bb3bc241dd60861b","seed":"6e1cccef229d10e15ac6f1d2b2a579146ce011411a6e807cd227f3215c32aa394428f9a11900fe21699ecfd09d5ae6e4e1a30f2778bbdc15fe30927e32e1fa5c","priv":"8300a73d51449f909e8d0dfd843aa4cbcc055259f7deb54f40bfcc41acbcbe2a","pub":"0251fabe51d7eaeb45a7c82ee6cdd100f338692d796e7f1effe6a705cfeb21cb71","addr":"ada0f17f1854fcec548021ce617ea90a05a2fc8e"},{"mnemonic":"remind lizard alert mercy badge sustain judge van spike obscure account twice","master":"50a01f4e2adc48491e54c26a8c30c38f451de1d2d8195661eb50f6e5ad6e68ec","seed":"1194a8c42df528afd1b1eb41b2721a9b05f9456b09d042f15884d136c1713788ed8a32dc2153f01b560ad904c93327855450bb93ca8db384cda230eaec68ecbe","priv":"b78c8076bc4378ef0ea80af91addee35557f0fb059c1b434c254ae6c76716ff4","pub":"0251109362a0885fa59ad162e24c8f55cf4895bde354cfdbac7278d69124f77022","addr":"6655b6a665acc146984fd188c3c260668fdeef65"},{"mnemonic":"chief report afraid nation silent tower defy display suspect dice switch finger","master":"472175c2f86fa94d913108eb3842ff03fad950e4c7714cab8ce0c46e8e674968","seed":"c3656bac565a87cf18a1cfd8d488905e4b18436f93d0cf1d61572741b6e0ddfa794ce94a8b05e7796a6c9757edfecc6212e8b0ffba1e71064f67c340829b36e4","priv":"f16f039577d1fd9d6bbc18dc26c03cb37ad303ee1b85468df3de138ad927d098","pub":"024fcbc106c0b515838ce4d32c50ca1ef6134c314668d98a3ee30bf27e18e2fad1","addr":"a88574f43c1bbc38c2db68fae3f73f4244973b3c"},{"mnemonic":"now renew same wolf host minor obvious tape install barrel retreat cash","master":"a75fa702bcff39de09bcdc8f55cd1110c396ffca982d7c48f6d3d2f98ae29938","seed":"6d62aa254ec89ab960c04b4f72b5fd9acc135ad79ce4c9b3fcf25e0caca06ccf05e63d2aa47630b6c7fd3dc274dea540ceb4808eea2032ec3373d8a77b336338","priv":"dd211f6c5037d095da723423be7c1ead08f09d44fe01ffc0b2c0b83cccba6ab8","pub":"02ee58e7d2d8abd00c101024aff3da181d54ab84165e0b5c02e9d53dc336f0d11f","addr":"d9c4235d8222253cf41236382326190cc8f3983c"},{"mnemonic":"bonus message butter logic disease coast transfer explain away swim taste draft","master":"ac79c0b183965a1d918ec19217ce40c6ac1d84e3d57c8d0dd7a0c6ded35f057e","seed":"3fd63c9c7e1745a0f2526a70de96f251f1f61db25e808e3a6ba500e1a1c8e0693b888837cb9ddc1e8d09acc296e908eddb9386b97859bacb10561d12e46056dc","priv":"842e49ff7bc56dc113d532e7d7b4fd4d721f4600af0e67088b6ebbd491dcd4fb","pub":"03176edc37f7b671f46248531479b45b2b6ec77edb92001b46c64c7b88e7e588be","addr":"8170b83efdeca9e923de156cb5da2e3110852c0c"},{"mnemonic":"quit culture vintage misery pilot cheap wealth buzz false donate edit lemon","master":"b2fb8551d9d84f229e26e7874d1ed77ae8066ae80e04abae48ea84f96ae448f2","seed":"2cad64c36d24dc0cb94a2b2dac3ceec1498860ef0faedb78f702efada34c350f6b7f7760b14efc177893797160a838ead20f5a890ab05c477ee70cfa0a5a6c8e","priv":"38d5623053b64b8df44950a9f305288e3af0c411238ae3a89ea45f28f8375c54","pub":"02963af6b3f4add138a3b45b5b8f01bae5e6ba0434d558bed64fff01c6750ac053","addr":"9aecc7332529b0982d8ec14350594438ff5562ac"},{"mnemonic":"paddle mountain rent siege length essence negative amazing soap pitch blame sorry","master":"f179f7a22dd44ee96dc443f7fdccadeef1afaf9deefc8819cf254a554a3332a5","seed":"b408f67dbcdb8089f6ef0b241f026f6cccf85753ae137888e80c47b3267f58902e791675cae2854f556b067915821516fa04e00bfec6cd8e474d29639972741b","priv":"1fd4e1444a9c49ab77235d823e24d70d18b5d37cf9feb550c1e0763c7f9980b2","pub":"02bde455cf78c59409eaa2d98a105b537c9aee34c53486a4247299af90be3cdf38","addr":"46269ed379006a40bd873c79a9526ef076260eeb"},{"mnemonic":"abuse office gather ginger member carbon trash detect mammal shield like wink","master":"bde4ba63249cf7e6ea92a5724ae2f34477e42a8303fbf5c100c85c3d3ab8fc6f","seed":"ca4615dceb4adac1b16195899d537faa0d6e66a243c30accbe4902d26e77004da08873b0899ba21e4233d048c2d171cc8f9e657971f2ba0dc87b843f782ac619","priv":"05d5ce699cfc49b676ee843c9f85e1510f27cd65a76ba4d46eb6db36fc033c47","pub":"03c465fdcfd7441ab8d34244970daacd29a30c0d972b92a961559906f736d4cfb0","addr":"e60e2b02b46ff358acaeba84fadce61d7361f482"},{"mnemonic":"rude depth finger strategy wagon cherry mixed assume sense aim diesel urban","master":"ac83ffb8b0b9bc49758a81e567d179fe060301062d332bb40e353b788bd986ce","seed":"368f7051cfe851c638722e3691048292a1f2a94a83f44ac9e7d6d5a882c822e75ed5116cb059f0a91550b8b2237d32b9a0bfe556217455044b3b44962f4f162c","priv":"4af19a58ee5ea6c6cbaed88cd83c13a57da1c8002b816c833fdda7388adf8662","pub":"021ba0422b1fab7261983106fcaa20a43d8629633c95948e42aee12777181c1efe","addr":"aaccb6d212ff003c8754147b89b0718a58c002c9"},{"mnemonic":"mountain bitter treat hour purity swim panda damp notable beyond rough spider","master":"e48be94ec031c9cc4361550d88facfffaffc67fc0fc5adf495aa18e17c431007","seed":"fce2cfd110d408ed37c75fd0a88fd7513a09a8dc577b38176150f7d2835959f8170438903a78a5d84b32923bbdec6d5069c532621df387c65bbc2a879fe162a7","priv":"dfe58c17756a93be86fd81d3c874bf4ff6c45cbfcf049bbdf999a8e798e448c4","pub":"020d3913b431030aba9c57920708c5648ecdba1fb0111ffcf44f91f67ae92bf176","addr":"1ed6bca6d4080f039a12e3b0e772052231818121"},{"mnemonic":"protect chalk chapter dream icon boost layer couch soccer tool taste congress","master":"c5d0b996ee26e80cd48849482caa435956d87476d3fc5087a900a7e666ef3bdb","seed":"e40c57922c038fbfeb1ea7dce70c0807a55a2c62f58f947d8f05cb66ea7b26131e8b2b81ba9add4185bb8fb72176922190ba2e15de9caf3b4749ad7840ff1acd","priv":"850e9d1840b28dcea6088c9a4837effa1254f48af181d63f660d18f5062964f4","pub":"037859452c974613068cb16147826addb72f11101db03017612d1eed3e5352d010","addr":"3b58443eca15b2061bd5d7b3240b93e012424579"},{"mnemonic":"rubber twelve wire exile shrug will alter violin crucial border drill pattern","master":"15c68b495a571a78a09687a86495141f94b2c015f4c51a9dfbdad96e68c6d871","seed":"ecb81c59dc0464e8ff470db36c567301543b2bd1bdeb94512db63bdfe6632d9c88c1aef02bbbe04176ac7a0789c9579431e732adfbf038c89aca077d14582a8d","priv":"00ec93d9115439212ee358244b5128b48a67645a4f5bf94fdcbff2c8e93cffa2","pub":"02e68bb8dcc584b4e54da27ca229a66d6a222dbce0e187a9330b1740713addb417","addr":"14f8f956d84c53acad6e5eb43e8fd7362d341363"},{"mnemonic":"loud ski diet extra rely melody space canvas humble rain park fossil","master":"1e09a38b1538e950b8ba8472c07b619334973f9075e41732851606645e318d51","seed":"a2d3ffc96f020904af3760c11e9a9e87e8824c1093b07c92a8e6d98c6aec16adaa8ce6995d5d6b58a04824a765d0232ff995183ac38a5cc2bac14f734ca8496c","priv":"18e45a61f9e6ec29019df10abca1878045553d9b924c859fe57621f212133edf","pub":"02a0053e91ce99b2c401fc40cc2892023b30c2db914403ea0da794bb77f69e93e3","addr":"bedc6716f1649fc2ae412516cb0a1d68ec2868e4"},{"mnemonic":"potato tackle almost kiss unveil spring smoke nature agent carbon swallow final","master":"5917e819604fceb3e7c11bfdf6b85809f509f89b3bad6ec7069e8e29258df791","seed":"76d3089d7214660adbbc748f9690b70f7787e9e028fb429086caba19c3b412f931b2768a843ddbdfbb6b6bfdc6349aa0fce1168d124a13d8eda61fe37b407f37","priv":"13c35356aea2324ac57e4c2d605c45020adcd4be336e097dde0b23059499e947","pub":"02e9c1615b710594269b4e86436bae98e4e9c00e7ca0405b89be47c02060705ae1","addr":"e9699c41d2da37635fe657c557f54f51d8e4a503"},{"mnemonic":"innocent cousin jungle elephant speak rent arrow maple danger menu misery breeze","master":"c2dd7273c7f703e2c66974dfd25a1e7091d83a7e6f8ef64954c8b61cfe4e84c5","seed":"32f96dc9661f448f82e2100afa787fa09afe19d90171a3e2d7b5a007316690198a3da22adeb22a2fdea43c3ee98a6ee2bd33baf1e84034d559e6019a30c2e87c","priv":"1e9f48b65f2c57f6af4797a41afba8b017de41ccf6be00bb2a6dad09a72df167","pub":"0268e685815391e6956df39750aa3e9ad8e4e558cba04ed4c136785e2bf82478db","addr":"3ecb6cf97afb26e1e0272df4fbad2e38be15287b"},{"mnemonic":"shoulder lock swamp goddess length trend tongue razor heart donate curious social","master":"c71c518c4d97855fbba7c0d7df9ea8f4e6211962ca9f5378b493c6c1d3b6afc4","seed":"e575bae2e1ee08815052f98f5c4bfb9873f171b0dedf4385e378348310c5c7f6d1cb021696e5913aac6b631ea1951bb977b3bcb548579458807cd565771945a9","priv":"2fea7aaea02fd5d5a5918ebd643bdab939edd18ef406ac5163714fd731e1157a","pub":"0363e2499272df247aa216ab8b274e146fe677bb18e706fc5377f8c921ff1c782a","addr":"de719e1abeaaf11712931d05ee39990e1331055c"},{"mnemonic":"bitter yellow post enable knee tag spend base blur gossip lucky lucky","master":"1af25d9330946339620183b1f1209c4d1ffc0aae754b82d71268400b934ea426","seed":"9e07914810a7e2d91a3ff6d4efb0686c14e59506dd9dd3c357dd5a30925a3f57c0a4983589ff113833abdb7d5cf7dbf79c08172888539126dc286848c1e49ab8","priv":"6e1ca5a3a31b7f805e412f0bcde7f82bb3fd984661a58c07b7967e327e664e47","pub":"03cc8ddeed92731c6b475a964c885865c5a11bf59ba24295d1e1117feb7f1f3e5f","addr":"8b516445842b755f23d0e671f10a5c0b1c2e48f5"},{"mnemonic":"forget organ violin inch panic sword report clean garage sauce math man","master":"29156bb726af212233cbc6c191e59a96d7ce44b6821538ea03053f36d51a919e","seed":"66c639ef4de2dec82b99ad4ab7bc73c0a4fa79d28d06ee393ccdbcc27ee375e9dae7672055dbf6d0d5ed67f2e99d4840614223d85aec64dd35607aa9b266d9da","priv":"f5e49029f7141b33f51703add1f4495e04715674fb62ad2d781f8c66269fd32c","pub":"034132d2bc71934628f435b93a9d161a3ce242e7d82dcda0a3a8c2f304e3057500","addr":"cb0a4d79fadb82d7b947889b26f8515db8fe46e6"},{"mnemonic":"under depend door lens retire faith scheme dolphin orange maid carry disease","master":"62ecf318e91f233b59acdb4000665338c8d61539b7b079716c85ceadcbd6300a","seed":"30ec1c26fb1dd7e41c5959ef7a3615e6d4e5bc21fd8af5efe1f8c0634e765f63462d7017d5a62c1e992bbb626ffcaed002208ac5f8867a97e454c1bf0bcad8ce","priv":"2babdc8642c9c9beeeafb728e948bc8531dd066679b85a9b58676c0b4247cd89","pub":"037f9e2241008d25844a96272632255802c7cd3866c5a83bffb3e2f724eb59d385","addr":"10eba132bdc71c162058500af51c53074ea1947f"},{"mnemonic":"swim topic sunny exist exhibit nurse ozone guitar trend page machine pitch","master":"5a30155bbaea42d54e9a27fa7587c712a19ad6c1c31052f68418f235b7bd5de9","seed":"673d936ed3502149d68172a22785c2aa2bbb3707d319fb692fdc6a4ace39ec3596fc406b60720ab5993af07227f42608b5a43e8e732c72d8ddfc82e680428925","priv":"e6759f20947caed563dad40d46206c67599d4d622502e46199fde1e17dc3d76e","pub":"02dd5474a52b623514948319697c646b519ac6e63581d27b01f0780af8af085e66","addr":"85fb1118593dd8c12acb0c2104438faba5dc236d"},{"mnemonic":"dragon square define chronic round romance scrub gaze powder visa please symbol","master":"1f1a35ac699063a47220536ddc3e988c055cee5e08303b867fdc16d5488861fe","seed":"dc2037120b143c919a3f0d71c6822f29b9b0ea098d286f8d4e40b3240bc9d19d4f45da3bdb983f49c304c083f534c7a26471296211845c13b49df97be61055a4","priv":"d99a6b75adef1455ff85fc94e8a4ad400a326662e01e9c0152c797b842c060e7","pub":"02eb2aa36f19bb90fca43f34316a18bb80053faeaa909cd6222128286af6c18bac","addr":"d24f7932d14e493a54a5384dcba3682e3d6c55be"},{"mnemonic":"first knife erode dice talk coconut act example sudden garment scene income","master":"1214f622b52ddf15c146c74bb0843b653117459901214a8a198a0eb59b4153ae","seed":"eebdecdd33e9ed6dd2e825c12a73e4325593aa14a7faecaea48d6764e6ee6d9d4140ed9e105247b2ccc0a1bda976fe7fc7ef8483c58f465cf393c4f833e86d94","priv":"ad3894b4f558a2e7fe5f0685e4ccd63f57aead98863617b081ac620cd25ffc4f","pub":"039de7903629baa0b6ef2cfa85dbdcb51af3fc9218b01bc57bb1f7eeba5267a858","addr":"fe6dde2516232383dc3382a75e86be3b82d2d8c9"},{"mnemonic":"danger expand toe talk course mask quit virtual reflect vital address artwork","master":"54c66d5d95de00c23ccdbe2defb6cfe78d809d55e457a0b35407ca74ed33eda0","seed":"060b5853c7f3bbd7bfc7b5d532f39b74137c2b6273a30682f768ad62800744e1c6a1db920d151d7e553553cd908b2878a31fc6c682caa05af62eace45a897b19","priv":"0ab2d63d607a2c56041fd953d9be60f5f7ff5e50f3c3a606dbf54bd799e64190","pub":"03f8b555aa7005be93d03e98b6f2a8870b9cd4ef654299be64b13b89ad839038b8","addr":"526ec814ef1712329c1cd43244e92d3c1d5aef91"},{"mnemonic":"custom flock clock grain absorb danger universe achieve decade habit phrase together","master":"ffc14bb5a243dc703a5afb1f904f8aa4f21790b470c9e05fc21cf872bdfce41c","seed":"71a82a4221bf48e1e97c8e144de80e80a9dc5808d579da185e75f6b88bb81038d88210c252921a2d72dd38c5bcb4edd442d2b481dc1d857965012d9249f77477","priv":"d9bab16080df04ffe43c57fa80c441a65b4e49a4425a0db06f52d6db77595d38","pub":"021f074f1e14552ea091e14e680814661b1a75148f8bd149fb8f6a13f6f5e7ffdc","addr":"d63213b298b92b726178855680001d79ece9271d"},{"mnemonic":"spare absurd book liar green humor alarm income sadness shoot radio indoor","master":"f9056445390a09170334e8a225d62719fb259a0c159685c29ec39e348b742510","seed":"a023662c39608142068683c030ad51321ecae6bf954b72465dfa8feb34f1e8ace0d46a072b855e33f7c5e8be70420a4f3baf7ec3ba370e975da88890d4cbb2fb","priv":"e5b8369724ab9aafb2bb44a1d3cceb2568fb0350b45f123a7cd0f26a27e70b2a","pub":"03b9196b842ae4db2b2409389a0747407baef8b19d502156a809ae02161cb0de38","addr":"658f62b688afb4773a0dc4c81925d7914dad5d22"},{"mnemonic":"anxiety salon have exclude build airport decrease unable measure reunion monkey private","master":"4f708611377bee900ca76817926b905bbca28bccced3ad0e211c7609c0562fef","seed":"cdabd5c6b9a64c302fdde1e7cc5e6ca15811e52e432e7019a81945264b3e52d89456171be0e24d4dffea0136a12a6204f2958c303f8c61af84f4b5ed135685cb","priv":"7086136c92846f7deeafe05dddd8461028edf62e947fda55b4f1ac584a78c5be","pub":"03227f8b0d42ee20d3c5cb4524686d19ed43bfa5595debe2ac4840eeeb92f3a411","addr":"6d11946752473bad3a3d593f85e97bb4664c2984"},{"mnemonic":"frog youth swear now annual mushroom stuff business excuse frost cause athlete","master":"0390c3c986b8d724d344395860504caf17a7a347d10aed2f4a0ae7ebc0e07f13","seed":"25b6bc7a888b35e1246bf8c7a289a79ba589cbd949047ba6690b47bbcb12d8c87a4d14d585fc0721217891396ce0b0f75852187a9fea4feacf320f9ae4eba3b5","priv":"ccd3755ba9b7638c2ad6815d34a03869650bc1c35b75c8e1a1cc9c2ad71d983e","pub":"0284806c57cb6013ca5ac1027a07784d05b23bfc4e6facaef108bc5af7ec20e026","addr":"d512ff91fe37ab6bfc605cf5470ff684d6dad743"},{"mnemonic":"bridge rate pen range tip web bunker magnet blue rocket dune evoke","master":"38d760387d07ffba1ebd6ef9fa9737eabb311bead38560cc464c7585b90d6915","seed":"953c78a493fa99014a542b2740b5eb2623f0fbaa765a5aa79e61a5344867dade60e05c4293df4076e218ad61c66b1112f54aaf7bdc6000b059b2c88558f582b9","priv":"d6d617aacf6ac20090788e43a7eeb58d1b44c36ecd4fbdc9ba287c8bc7f3b24c","pub":"03ee39cb612e75ef609467ed6250b602b90ee94b25ae43be9593d2cf34b3cdb938","addr":"dcfbe07630e2a9156f0787ad4e96de1bec09b3f9"},{"mnemonic":"volcano exact weapon couple logic cactus carpet raccoon state rigid ball tent","master":"8c60a1a859b5684bc6aa996738801f47adb8392ca3f92865b2f2b3a48c69425c","seed":"fc6ede285bb6e6fad778234a5f6c5bfdc23dffa2975667dda6c5470c70122f8aca9c63bd77c8811c43b4d4b2ab4ca55db7b4d457f393436ca1626ae6fbde03e2","priv":"74a1b74d0f11c8297f0d315f9556a96ec5e880bc59fecaa1283ec2a693cd9ef6","pub":"03f62cef4ff1147df7ca38cf1231c48632c4c4b2618e6c7d2bd001e10509f68f05","addr":"8b8e006c70eba973ef8945d89e33b6a5422e5742"},{"mnemonic":"match quote pet worry pizza stock flee tip kidney tomorrow giant ship","master":"02f8e676d2c4dec8e6a8430c22f8adeaf3b25054c8d22dded7e2bb6af5327a63","seed":"4d29deced03c572a5fddf55539a735228b59cbcfa80381a54c5a69dae73f56484318e511fcf46123dd8f390e2527de882252f3c0b69f49b9dc83c7059e876767","priv":"049f7fa5733f1c674a29721a025d410bf35891984608ce1eebc7ab48626ec3d0","pub":"026912ef70835b247c3fee238937842fefebdebf046b7f2afdd4f350152765fd26","addr":"4d221f1336ccedb6b2a9850a15bbd13c62ce0fd5"},{"mnemonic":"swap amateur unaware glove biology frown vintage dream prison bulk gauge bacon","master":"8c370390691fe152f7d6f5220704c9fe6b27009c1218a07d529768f40fac692f","seed":"5e3c155797cecf5509151218e30101e33da6058dad04f89dcbeaba0d1d2310482b278dc747298284bbf7e29a71cf4a869e0c2755f6144cd2a5f58fd581551b48","priv":"708a814272dd4efdf60665c491730ddb73d3d5eae3d74ba8ae632183ed014569","pub":"02e06b607086808b325b7629a95ba7b945e611c3062f967402f04966bf87111a23","addr":"d343acd452e5118b6e4c1a83cb08a521735f2a39"},{"mnemonic":"shallow chapter special riot dial sweet armed imitate rotate south cliff shoot","master":"bbd697f9078e47816c986596fd2af08818e0e84f3c2bf52ff52cf72974add88f","seed":"bd24f3a066e4a994bbd613d12f88268d16d2439f9331932a9b30da17c7fee4fbf5aba4f2f333103c6bc1d0bb600be1c86db54e323b6e9e9394b93eee35a65359","priv":"1ff3375c7c35230fdb97b8b8a2401a59278b383c355dfc1773024fe38acb4a42","pub":"02d3fa09d1e5929fa37218d16448800c9eec188e31614396648b65f3303bb3ce80","addr":"8c3027c978b9be60970e98790b073f62cd3615da"},{"mnemonic":"illegal hospital witness leader wagon appear trick mixture refuse kidney total lizard","master":"9fdb13cb834e01260d56ad2bb7c8db55b768bd0e76464d52dccb77ab806a1258","seed":"a96e21fc0177a251d86cb6ffa4057890112cafd32a7c270e782616b407cda51dcd914ba2bda90c80acebf8969825e8044ec77965e264e085ee6ce78fcc698f61","priv":"17804874b6872c2df6c5da2ae45830f752a159dd03ab0b2ef22c64018e91c14a","pub":"0221388d8dfb7416ae88426999f1e07d41aca9668b10262e995cce20448e315e54","addr":"4feb63cb3ca2d1f6b0add8ce1bb2db5661dbdeb1"},{"mnemonic":"unknown update couple lunch demise sick brisk market area kid service again","master":"26f5f1d04e6f20ae2a9cf5631a1fda6f119e3c14dfb35ff75ced5091ddd072ac","seed":"72e5f09a5c9e56832ae400cc69b98932067a81edc9c0bd0d97d385b0cd7b04f70e51f496054c7d28af2853064982c9625a4fe745ccfe8bf4d690ffe9368867c4","priv":"e59d9190fa1f4f5b37842807ec8c886c9850c7946520f6fc764c232222500f9f","pub":"03da97ef93bfdd16433aad5ae6cde252c062a9875063fa3b7ed2615077e4446c34","addr":"4302a5c24f1ef5cbcc1e286f498140769f3fd667"},{"mnemonic":"leg damp bulb final remain off lion fold run buyer help safe","master":"4b64059f74a801c81a66d7ab2e25597a3f3c97fffe760d5ca70a8857fcc5fa55","seed":"24141973b3a7aae69d48656fc4e535d1a2e094d9ae5d6325f54d6288827dd32602b128ef414240fd88c9a72f790f8fef560efc023a6695f133d8b46eed51cb1c","priv":"13e840acfed4b533303974eb1223a9d4fd400902041be3994101ca517aedeb6b","pub":"03ed7c577c28dd6936bff7eba4569d681abf5bd59fb97ba5d793a3f65ad54f8d21","addr":"3e404c844010458e56726cf7d0881a1c4047ffa0"},{"mnemonic":"observe budget library column blade soldier apart panda express frame version coast","master":"dfb6154ae9a50d8853f5fb0fac07d98cdbdf00fc4511f6f940490e48ec1858da","seed":"a16b567cc1e2c96ef202c9d49b9d14cb5ff14c7c514c8e2bfb214a9e6371fb6f4eff3dbee51e7de2e781dbd815d1e76af525d9766504208949475866abe29766","priv":"b16e831a50e39788755684d0b96f9e4f11b9e637d9e43c27cdd5242091c0a8ac","pub":"030ee1b1e2c7afccfe7f667ba52dcef130de06b35655deeb33291ce6118eb0a31a","addr":"c72adab4e3d6d5d8a9a72e36bd2614d0b4b6e78b"},{"mnemonic":"exit pulse poverty scrap relax umbrella rug clump cruise biology magnet area","master":"0d00e0698a0958ab8ac891db675471b3f7a998f4947115313bdbfb189a8d2308","seed":"a2831c38659377da9fcb2b76d62b76a7f23d59083f33f8c6778eabd804331d46f2f0f4e167b013e16b2b6ce066816641b2bcf47dce75522cd3d1e6d9fffdb28b","priv":"d0c7f92739b274899883175525b6443c265c288e0835233428b97f6f912263c4","pub":"03740d02a36387dc52d66d96357240ec0e185007bbb4457b3598d96680de6309ac","addr":"c4dcba01a757bdf253ed47a41a49c996657d7f16"},{"mnemonic":"impact random cancel imitate base purity devote panel vintage group pool twist","master":"ae715a39fbf43bf9d848024d3eb93d9ca4313c384374fbeb3508077a29017462","seed":"da887f0a16dbc3fed38134acb53466bf1c1d18d179c2f857573fd4a43b8e52b16e598306dc199fa2414700b350174ffcbf4508951c765680f4b3dc7255270efd","priv":"512494ad5290d4dbb69d9247e563188a8705dbeab8dc319db39743c319389535","pub":"03a4eb5469006a29621ea5321f35e8ed8d839a9be99be7efb9caf5e5389dc708e6","addr":"4ab6b8d6bdce81c88b093698870645e7a1f92370"},{"mnemonic":"egg usual identify trap involve winter card eternal subject unknown obscure scrub","master":"6b54ed0110635ad73c4439e189e594cadb02f22d84bdbc7b94027edef2658a83","seed":"f23aee9d83ccd474ac819ce7dc8a57cc57ce082f8032c242511ccd96a395ba8c769d07a7115d25b53cee1d12d6a703f1c0204ee152bedaec1b8c15d5d5b78edd","priv":"0f1f52768a3bc3ce2810109ad40da0126ca5527c494b226048382a9513e11be1","pub":"031d08dd21c95576d1a1a028ba2938537d1c604679fc6e59cd13ef08e62e566a4b","addr":"a0c1e6d5d63341a8707be1673a0dc34fc054a14d"},{"mnemonic":"crunch drive cereal switch sketch gym hint fortune install approve device gesture","master":"4b4f8682bfb429ef36e7ea355276981be015fb78b90c50c19665b6804f7954ef","seed":"6ca97b6725834344247fe5dd5fa0d2a20c31130d6b9c60047578181867650f8e734cafab2158f57b64a92c3f77672352dd71d9df03dd6d592a137cd19e67f3c5","priv":"fac29029531fdccaf85476aae13bb3c3c9f0083265fe6d5e6e612386f3be3ec5","pub":"03683e7d7472d8fe91cc67bea096aac18dd00ae858b8912ca9b172207b89639b80","addr":"aced36c9dad879576f5904d67f504e704726a21a"},{"mnemonic":"congress nurse found frog crane toy pact write manual version repair embark","master":"157ac37c0bbc0732a71858377479fe8bb236664322016fdfd62786ae716f9ef1","seed":"8f8269a5211027a2c6480e9a9d910c385c2e772e12cb756802931b169b602d0eb7da4c603b901f55d4f5c5cb67d7fded0b71f5f9120ee1ce08e74c3bee1f745d","priv":"ae12502606695e34c1a97dbf15b70e1637c4d537cdb0a21896cbdb17277181ab","pub":"031077cb5bd6bea01a470524322478cb5997c06fc77d7154c92f3b7273a36c739b","addr":"6ef29aad62d003f9927be9daea218167fe14822f"},{"mnemonic":"verify service fashion camera deposit expect snack memory proud opera flower casual","master":"7df339fc4837633a008a512dfd0ebe4f9a1236f048839025d33c574c4af0cc42","seed":"151551954b5b4719de472d6a96d5222c1eb688c476f190bc263d7370baebd0740e58f2c3fa00e3cb4615389bd306ed994d3da60808d1d08dd005c5292d3038d0","priv":"771fbf2a2c24130bb356f2490ca67799ea8be2d37b3f291323d5e9b079681cbc","pub":"02f6c6d95852798faa803021107d6a12d56bedcfbccb8110fee698b800931aa2dd","addr":"00b958acb44eb87590ec60f63bf352ec8248fecb"},{"mnemonic":"artist gaze ginger just pride royal strong absent wash figure adapt decide","master":"ddebae65962a513c384bd902b230fdb48f6315d6645a947d79b63c4d45cb6023","seed":"8f7914ef479cab13a658b773db99f56a3ebc267675e1a91a3b595c2f0616f2793cb862cf6038858d363576f994c28c630eaa54299480f168f05d7564261a2693","priv":"b416f93bfe3495ae2ea2dfcae8e587bf19650ee08194962b43ff97deb85c1bcd","pub":"03c12fd1c2e653e3990d15b59d64cd3c34f3f248fc2f1d52946fb218d3e94912cc","addr":"06c7ac564ab51a452c3fe76c0cab37541ae1b3ab"},{"mnemonic":"case mandate call napkin cash test ripple bounce page dilemma usage stay","master":"101248d364cc296423da1839cc3d0774ed090bd9e73f55f355963272129cc184","seed":"b5aa29ba3342da94663315038e9b6c2d61acde2e4cd7d08971d79576224d12af8478abe891de819771a6ddee37269a71b13c825f8ea056f7596d301b00a9c0c5","priv":"4b97318dbb30a0b86d6497a97f3138db00d268ac6165a0fb80f5b8e5d714e619","pub":"022487dbfb8e3061c3a342d75ceb25ad9a6acc6b8df0b224f3f521c8105a4036ab","addr":"984ecec7727a1f812b63b6a6899979b36bff2e9e"},{"mnemonic":"neither divorce grocery stadium narrow electric observe that six diagram hero toss","master":"59cb4dd0ccefad583b8c79c8dc1c5e1d1d77149cac9fb26674076287105a0936","seed":"9c5e31547f43116891fba52294c90c80a583c0375ed100d69e2b72e1453b591b1072ac402d24e011ffacfecd2c8fea1c2b1cf93a435996df42e1c8b19aaa3fb2","priv":"f490ea8e2e8011d7f9b9c57d9143606d470ff00bd51ca69a44c2107d7de7123a","pub":"03fe9d9451c9505075629309bca9b361edb59483e417f07a2759aad704143ad778","addr":"65b28d0f6e78c0743903e41e915de6231603eb5d"},{"mnemonic":"van lucky present hobby property front toy document report switch strong say","master":"5517d9a3e2996bdc9e317a447f0506c33dc20c3c36e6565dd8af76ac2a0158e0","seed":"779e44dd0d1401cdd9d84061044158fa4036d66192c5059bb7f33810e776de434e24518477bd4092a0c775bf7801887a72fd94f0d6bb46757ecc3764f8e17e93","priv":"bbb4c89a597315ac9524df42b17498d334d93b8d48f19188f5ed2327fc2800b5","pub":"022e2a217432ce25ef42196530550d177aff02cdf91332e4a86c8d1fc4f34b07e1","addr":"ad5ea6aa0d47a084f1d01c547165eb51d067871b"},{"mnemonic":"swing shell april silk tenant swim clown beyond under tool envelope private","master":"bee0c171d74d809a83d0a7f70ec1d8ef320efd80541127c9e3b2dca85e344ece","seed":"da69d4582287e64756d8bc49979952716991ebc878764f7c8f93649f5b721c35f5496e7e81f5f21cc987315f53a747911363a58790eade4c43c7c24911cf8b89","priv":"a6c35d6f727685419b4c3717f0dc31d33340536319963186c64f18932bb3d921","pub":"023465c95f48753fd4546f6be7b3c5959ac2de74445c2352e14d0c57b058ab0ae6","addr":"7959735517d011fc100b56f25b6115982d2299e3"},{"mnemonic":"carpet sketch depart tenant immense sock because caught close canoe insect crack","master":"ab35e8379ede1615b44bf8b1a8dbcc3ce88b6d6d0980cd63ea4f783340a1c372","seed":"379373dd202ad95fca8046f17a5f989268cbacd2697a02ee5efc2f022f9019580e7fc452c551d97c9aa2247c566313e454768e38d6585ad9561a09710a279ef2","priv":"a7165228a05945d4b01a1ad12911666504f8fea8c8819df414995bc1eaa9068f","pub":"025a7afe792c05bb3d94c7996bf5ce1fbb02bbf716593b2049f6e42a0328311f2b","addr":"1fe2d6a254c104cc38f1466355501890d370b30b"},{"mnemonic":"world sweet evolve club speed desk double verify gentle account youth column","master":"b2309b5c1e0a5c590859c5ec3bad4b94aaee3e2e7ef21080cfe0780617eff220","seed":"efa3dba671c0c4e35072d8958b4d7af280d8e20d3b6752b34a6b1e561d0f44bfa7829a5d540b52e02dc1b06735dfe18b2073a784aa307253dad71b9146024bda","priv":"a2a6288f9feff9b408fd6b056309dcde5cbc40489afb85413202443d7c283466","pub":"0307429d4171f929f79c8532cec5970c17d6f92ae014e14d99fb1f8fbc0637c9e5","addr":"1ae1b848027b0d1276a85ec2946bb7096755017a"},{"mnemonic":"patch cave blush omit calm habit autumn load focus tobacco barely switch","master":"972320ebeadc9ce9da0a447dd469c95bdcbbda09e6887f64dc9c6fcb8d6c91ac","seed":"dedd6610c32b2e5a3fb93de12f758d92041b0d1aee0bb2626dc0e6e8cebb8ecfdf87e25dcdc4f9646f2e37fcc071ff4137d914df7133a6e22fe8669ccfa7cbb7","priv":"17cfca7dd65152e0a3c77a2bf4a15b0a99b7e889dda49174acefc06d390bb255","pub":"0286d1e4ac0c7df1e1e6ebbe1b7aea5f0e0cef8ff3336a1c2f61c80d135a382234","addr":"b184ce8d18aa006e93ce901fbe879d3d8d6e6417"},{"mnemonic":"extend install wolf token genuine mother swift pencil scrub annual wealth hip","master":"4ef0a071d94253f9a60bffa7443918f43865f131a579ccf93d2ee16a518af2b8","seed":"f66926e6837305237316d7a69fbe18911f73a4f98278a2f6e6b1a8e06adfc1d189875ca401387b74c0198741619030187368c2a58e6b844aacd45fe89fcb6a93","priv":"f4c00a2ce7e9217e5e5e3f5398114cfde57f25833e920f14989e450645087bc1","pub":"02fb09ad3c161919060141c50b70c144cb991a553a57b25b2688e56ad163c3bcb1","addr":"556ed45bf7463ad502fc2fc07ac05fc073badbec"},{"mnemonic":"canal pink undo modify apart bachelor movie coach december exclude scale despair","master":"ebef42622df1bc744290f0c5d930aeefe2764dca7efba491b78ec958a5acc171","seed":"056347f396399c75761136da001671c6097fe21adcc920952db079afa5debb60d1c3612742d96af16de34a44c792da1ad995757e6a25e62953116d3016639c86","priv":"6a83065d2777eb4674e19f33a08b46c44753cce58902a41cdc3b8e3f0883050b","pub":"03a928c2c2aafeedb59d1588a86c42428b70171eed39b94f68f2097d9cdaa4c283","addr":"28053af43e4d7e35b32f9d174bd205206f94028a"},{"mnemonic":"brisk clip brass tunnel credit hip clock deputy dial hole song soda","master":"965fc6288cf02a8aa3081de292a513fd7b23fd010d373045e2a5cb37f38b2393","seed":"553cbc6a6599410913b6304461c1cc8b4a2c09c8bc1091c231d7167d27892ffb84b89c3c001ad40d4740d97224062c974ab01ea2dedfe1a3322f1a041964fb46","priv":"c9fe5b03317f7e7496f8824f24b782c09b5b801b3ba7a08d5bab508005f88aea","pub":"02ecf7641a4b3436c91ff3fe5b9f700cecf8cc3769945c665ff6129f6a60e77a7c","addr":"e578b715e9e84da6beac28486ed9492bea16435f"},{"mnemonic":"senior example flock banner pumpkin salt silk soda funny input puzzle ready","master":"7b0b3ad8cec24080ad6fcb9b1ba4b745820543666d362a188f4aafa52cddbfad","seed":"367a466ca4069c50df5571db657cf4394e843973e5801db4d7072c51453ce04b574b01e07ee8ef0836448f7fa220863e6cc7e6180618efaa3868e78b807b4b74","priv":"31f5e11528a372d7948cbdfb0519f974168d568128e441a5840a02c1ebc71f50","pub":"03b507120d46abde399656100fb664c736a2476a588f2c893d4be9a5f9acb0460a","addr":"941deb14e567c6d60446fe5767a0bb780be7fd0b"},{"mnemonic":"say leg next pelican brand topple blame plate snow month van cherry","master":"82a9d68ae21ace7c2e5d7d8ff58e4f0cc3c7e5db8031d4f83008d06088c477dc","seed":"69956cc226c79bca915b24c65112962205eeb161b79f66246b493d53eb7e1dc56f9dbe475d9650c0e72d7befc0b899f75f7bb3b3c100f7d6128b21cb4cd88396","priv":"cc512c35a0edcc0efc15ca9659bb536b3957420f00b32cd9e3a0d0e1cad5360a","pub":"03c4c82df36b093deca7eabe03ede5c5ed3639dd37ce8598ab8a6342b86142b07a","addr":"d0ae8f85e8c95b4906de99ed528331173f251e85"},{"mnemonic":"develop odor front thank mobile subject then cupboard human high crumble rabbit","master":"73704bde13f4867719c71fac5b37f16f30b69581a53e7f09118ed1368610b1c9","seed":"88f30341bc3ab214f1aaf379a8fbe498825029793d4ed2b50d12ef666fe45f06e39f68583c4cea8ca6a88e5ea62d8aacb499da4814fe346e020a78bc636a3cbb","priv":"53f91608a0b1825b05ae68992f97fbec8dd7adf877c085d1f30981d6f5262653","pub":"025f5e6339f5b651038512ddb5073eaf10c962f6e82bd2bd94c117cd4cf4de4fc6","addr":"d24cd460bc42f5222b18d5632d53163b648c982c"},{"mnemonic":"toward weasel copper blush mammal window weekend exhibit pizza element impulse valley","master":"3fba4e4716bc0b0f99f44a2bc7df34bdf60bbc5c1e2b76ff4295f21428465dd4","seed":"8051dd06bf13a9b79d82138ee3e5cd3e417c6d203ad0f6ceb81f38890d4c18b56d29c93ba76591c499c9cbcce1bdd205b26ab792d506d4903d90104a226422e2","priv":"0379555ca3e00311dc6949659afba1cf6019ab5690f14fe8368f0fd07b90a44d","pub":"032446f977ee3324c946b0d6409a4b7401becffbfcb868827e6639cb686bb2140f","addr":"87bf7d0cff36c282a9140657a4420f67b7b7433e"},{"mnemonic":"lift piece elevator remain horse virtual fragile dynamic whip lecture perfect fine","master":"bd16309fe9a58eb87ddf1b8338ad0ffe4b39706c4d568cfdf6f5ddb79064ecdf","seed":"8433dee7ff8aa73f785d23b09d8ce7f4e1e5cbcc7c20133d81f87c1d47b94f733631d5406c01f756ba7bbfbdca900eb2fa03f6b0a0bc1f06b9f3c3c9ea4d6d61","priv":"c4ce940b7e5cc0606f023daa3dd724d773e886d48af58c785fef7605b2524a16","pub":"03c89852febcb140ba3d5e9c95ba6ee843666ccaa69492ede61dec94e4e6f73949","addr":"3c04769875dca7cb3c6faddbf1960e1738118d7e"},{"mnemonic":"dash output lesson topic butter run ancient claw enlist approve chief observe","master":"8d37dc9da62db3dab7a0f209d8997dab75793704d6c18056f02b6768db414121","seed":"6ca57fc186a6eddbb0e8ac6dea4c1eb5d8361ca08d7b909a8e863284b38180cf8ddd2d9590f7611a5cb80bf1abcb679adde5646e69f62208557ab1a37e80394c","priv":"db5742d8734235964645a018fc4cead9402a113a60de0d7f55ab3816c9780e8e","pub":"03710b31603eef3e10abe51c57c62818ae65fc7f0aa4a91cba5f178a0cbdb313cb","addr":"742d17ad66f51524f28deadb3366859f14cf02ff"},{"mnemonic":"blouse maid inflict jungle yellow believe arrange cruise seat dust endless benefit","master":"d13daac6580c68186cb049fbb63c05bf2282919865c4018acd8446828dbf07fd","seed":"5b4132806e12b669813f1ab295ec58fc472fdb46769ea7181faf6e6b48f3cf4d8280e8ed5951306ed71b40d016afa3ecb71476a23f455ab6e41233ec2929ff0e","priv":"a8b701c1abda145e723d92fb246b692e44693704b52198ba33128267bba63155","pub":"032c532be31e8394d98571f3623372abafce8bdd0ef02c198544d0dc6a6fbc3cf4","addr":"4675d51ea6dddfd9b296532f3f2c101229cee094"},{"mnemonic":"only enlist indicate practice safe romance orient gallery cousin silk eager what","master":"2bee5e0de945af3aed16b2a06423d3447dc0c91af3ab8fb20b4fc0dfdd74bad6","seed":"92a6a62d9b145dfac6f66b7dbdc7bcd7b9ac10163541cb95e18e77742e3f2ce1773d74b0b290e40ecda2aff147bf81fa8997eb02668891a68912cf42cc666fc4","priv":"6a8e812a13716f00c5139220f1afc9a7ac584ed7553fbe8a13c50add54e5446c","pub":"0341a641547fc87d6a44abe879aef7b9f7c36e3491f221f667d10c568eee0fe99f","addr":"0fbd95b59a63b2a4238d6703ff49746a5950db8b"},{"mnemonic":"oppose fan kit prosper message pass fiction machine duty antenna planet ribbon","master":"6464d66007d3609d21971ad05877316fd8fc73a4b61d971676fcbdd32eec832f","seed":"36f65f329a478fc6cf1c9be171f9de9255affd1434ccc3420660a156b6cc0a85a10d5eb1547bdb5849325f5972b332afea7973449dee8a72db256479301337d4","priv":"94c741202799e22867b197c900c11e25855196e9e10e2f74f1939aefb7ddb233","pub":"020b86916271d84b2ea8f8b83ffded3b8f2bfbcb4ac17da7fd59c9ede27c00926a","addr":"d26eefcc75de9069e99c2e98699823b45effa9d9"},{"mnemonic":"acid summer coach step inform jewel secret tornado abuse kit shell guide","master":"4a10d5e6783e00d6f3453d8948dc5b39776de5690775aaa0a8429b2f11679ea0","seed":"46c698780417975feae4b6607e7728a00600e0e8e225d5d8f36ca076521238761c5b910759f70498e7dbda012d4325f3fe81011ca762c2eaa06649a18b79fc74","priv":"7d6a286693fdf1e51c26a64e5e5f8763b328934540b18001898537afa49e8b1c","pub":"0319013f6935be2eea7cdfe0544145708d24ffe9742a64b1a2d22f24bc5e380bf0","addr":"d53d22924ffcad0359a177345c32723e6260c7c4"},{"mnemonic":"general shed quick sea amused piece air infant jeans page eternal lens","master":"7b435a6cead581f339c1008061cadc687c40156312a8201c823158a6028cdb93","seed":"0843ac840c79c9c7dd85cadcea3496bc7a376592b07d233c35bdcfdd09725eff59f0ebc1d0cf255035ab5c7344adc3581dc543b134a5e70eca410b46596ee8c5","priv":"e61236f6e4557b45a6e39058b8606b7e3041de297cb0d39ad06c2e5414199d78","pub":"0241be261330b87c2388ab4077fbd4fab3a66e7d039d3ce4faad319c42b8e886e6","addr":"29777a50646b5f08eb7a428805a9778851d3116d"},{"mnemonic":"view hood trigger weapon dress roast load artefact dumb biology sadness receive","master":"a619455307c5edc87edfda01059cfdbb6c356e9f639b16b80b78e2421f1989c0","seed":"d89adefef230e418d7462194e5e1a817a0ade01435763ac5030ffe94fcf4b1f9d8a06090ff8a742d22d7a78e4a6392e35e8c318f5d0e495d0f8773ff126ab56c","priv":"1f9c2085c35b5fbf1a096174e7f11537b4f6d6327018dbf3b3311488865e5135","pub":"0208e02b8410833b43ab7674e25efd7081d6516aada029588f72a5478fa5c0aa20","addr":"cf4138b64094d8a9f58cb9068305a69ac50c4f0a"},{"mnemonic":"salon diary era brain chat panel design lawsuit behind practice please budget","master":"fce0a096c14774cc4bb44a4e9c65cf075a2ef5eebf96f08cb684455218f4dbe1","seed":"b154f70e78908ca26852b659a6f6252d83f3bbc4261cb1b9faa4ea80dbf1feb27958164163bf7ad82de0ff8b1af07c60f23b376910a24608c8af4b88aa0065ec","priv":"156d45c8db9bb83613334020e9b9486eafe16c1341aa05f4ed2095ff5a11dd66","pub":"0389bab1175f1cdd60a54828f8684c99c603d6b877597d1ab0349ce6a974fb9e68","addr":"f60cdc064ba139ed5ddcb6cfdf6c89ebdc378962"},{"mnemonic":"text horror panda eight mention victory wonder orange error few you illegal","master":"fd6c8375c6c3458be159f4c2fea8d25688163c7d306e17aa2dc32951eec2342d","seed":"ff314a8722d3291744c0ba07d569373771357795f72307366b0ee0c84b71ebd60a54d6f1c1c974bad1150e85415658f5d30fe76062d80468786fcc20ee8ee903","priv":"943fb32cbdd79c2e34ea72a9c31cddc3ebfb1a353808e471b77f54cd108f487c","pub":"02d17d74fcab59fac7d1cbea2838d5db3ecb1c24219b0b086ea1ea69559b8c2099","addr":"996916a8fe8dd544c1906a0afe4b48df43abb409"},{"mnemonic":"apart beach sibling debris chat hope toy happy bean same auction brother","master":"9eb93023f619ad35b6aba1051b791dbde9618bb74059632813b4e0f72b16c773","seed":"4fa270abbc1443fe7f593af42da0b40c17773eb7b9efc09c621b59424f84be65ed1ac755b88d71632a5a384c6dd679887c021dd91aa06fd9547f5c52bac8618f","priv":"3adc47b4297474a18744bf61f18e3030bbf58d68eccd4b0f9a207fc513edb851","pub":"037f6fe821009e2e043e66b167e7708d9534a543391b3ea17abf449f2807931462","addr":"6b9668671f23172dd08382e8db996dc9df687f80"},{"mnemonic":"tag bright bitter hedgehog stable level outside alter uncle hold have voice","master":"63157c3bb0a525d611de7539718f3b8de9f4f7a61bc9884d2f03ae0d30e7c5e7","seed":"e40b20a383e582f304c7feb315ae1bb405e9a5e12797706042d82918a19cada05fd28ca8615d929dfe7ea331d588ae3506cc3cae09f560bc13d544607e075ba9","priv":"8675ee046186c61b46576c02a8a7e5dea1d307667ceba7f6a56bca72fcd5452a","pub":"03654985961e5509210a31d1f54b15b37ff975717ef1f5ea7c2aafc76ced1b6326","addr":"972e9f2582e7ed35767b1b23ee73af4daeaf0b3e"},{"mnemonic":"wave fiction coral polar enough gauge whale magnet science second squirrel answer","master":"e2f288c51ea9bb3befc3245bc0739998db6199615869b4f27db9b613aa443549","seed":"2d9a178a3292c3f3987c35d44a3fdef2d849630ff49343bc5c3456a6701310c56cb0688d7a4bb7c3d58c40472d8a71121fb54f0108f6d682c648694f9ee85aa8","priv":"4a4d6db92c8cae67cb80b4f8fc7e63c94d3ce9ea67026c2544325c7c14c8318a","pub":"023cca73403af0fa0a0faba0545c21472996381917db6e481de9fc0de210dd4458","addr":"fdf8fbd1473714cc6dbac873822a7e0c7ffee153"},{"mnemonic":"process visa stuff pulse shop ability test aspect royal pipe protect fiscal","master":"742d13461d14c18707e2828f69b8deae3e13a9d6c90895993a788bf51f5f8eff","seed":"fc0ffaec77037a17923401aea05d7e37f09d2e7d35e9ad26a5dfa3de6e5da7c4b8c1d16e5ff6ca18570b069e1e8e49ef9ef475665e00cf189eef652e40d3553c","priv":"ef5da20d14c6d948536faf4ebfec5f11e430795986086371afb5a239befc3410","pub":"03a03b2dfd694a9d95ce1fd0f9c97f3db35c02aa001d26dc313c269f8a97bc1688","addr":"0d76c54b8af88721dcc4968dbe47607d7040d3cf"},{"mnemonic":"jar draft slab quarter during hawk grass monkey mandate prosper hour fortune","master":"98e2ccbe3470de355e090d69247d6506ee9bf82473d83fb98c20506543dc4fa7","seed":"e6bae0e46c8e66bbaedd465ed2669f9ca5b2bb68d829d237a1846763129932588a1aa4e69979a4eb3f73010d7c093b20a542efa2fddeaa00032abb847cc7bffd","priv":"9d1e402404867001cb24a3f501b676effb69865045e6ac2b0fcfdc34f9df494e","pub":"03f0bc42295a11b4ccf18b44659cb6d0e0eca3d2034c98f485f5ae43e07a82d90d","addr":"e1c21227bfe3c09188066ae189c7d499d855a600"},{"mnemonic":"camp vocal absent ostrich sleep version puzzle afraid execute clog eyebrow tissue","master":"fdabda4c563e3d7caec47b62f4f06ca53015f98b498676116e7b3df18a4b4412","seed":"b752500a4695f6cd66edb640021b2f590e85f4df2af298388f042cf7b665f0d6e643827bf705d3d1d9786e64bb5e184fb16e270ebffe0ce4ff7f37c285d28db0","priv":"32ade388afcf551e5b9195941ee3d290a39ab041dc9a2b748cc36c53cd43061e","pub":"0346e927eeb5549f8f38fa6280c0932947ef78f63b55410e872e0bf6988e64d03a","addr":"462344dcf5eb679f62d6470927d227365b208524"},{"mnemonic":"kite slogan all win burden staff actual oak cave bamboo advance uniform","master":"43888096d253b010da1f0369f75bc0d6a3b5f14dfbe5bccf7c8fe9bd78242205","seed":"b770074f2868e3aa42bfb76b444f782e4a109f2ed51677a79a69bda83dbdbff3a64b9ee163c57859f143a726d10aa73b223f0cdcdde6497fb95e0fc4a810f583","priv":"26533617dd8d7399f399d59f0f8a50c798668f04f44b52bf50728f20959c68e1","pub":"035ce21f82a71a8580d4bff49e520ab9815ac4d5b6cdcf6eaafefa4457dd9dea27","addr":"178918f829f9cd67d701c9a64b5bfba373a7c820"},{"mnemonic":"bind fire final soon dilemma analyst train ecology say drive slot bacon","master":"9aaeaa7f7a7deb8a976783f523695466b78117462804405e200ad1677e547125","seed":"155349996ca5a6fadb151c9ec425ca1e39df10509a8577f6e63096681c13b3980285777e515176feb7e4aba096b4d9d81a26b4d3477409432629a862669bef40","priv":"a890f151c33c87340a9021d3186c4df062822a3088fb7447bb419bbe5dbeb53f","pub":"0253d42cb2ab28f7fcdb2011e547dc88902e1e4d588e9261aff0869b118bcd4dc1","addr":"19b05c71780f27ec2e44ecab4c426108ea5a0f6c"},{"mnemonic":"image wool rug little visa embark poverty shop shield parent odor farm","master":"c68aae9896977ce21f5f547a4d0ea9995c9641c2a5f2cf89fd5a804485ec0e23","seed":"5c6885f90dfc1286f17b0079ed90dfc3974ce6b60d4193784b9668ec93725328ee5c0d027df1d551541a62fe2d87cc19cbdeed9a235a4510b738930dd3eb4eaf","priv":"d807cdd58fa84e4bda7fa998c8bbea12b7ecb5147c5edf841dcbce2c8663be43","pub":"0259b24a008d6ff4ce4d589e081ff100c28c3f8eb5440c8643257881f10da3658b","addr":"a20d7d609e6b2c855b9da18dea5f7ab3d091aee8"},{"mnemonic":"enrich soup all neither easily combine police ordinary review room keep swarm","master":"8265329602cac11df40567d54c8d4759bd9013c7a325c3d628b81640e95af3ce","seed":"3998bb700715a777bab05afae33a6e6553af17bf8c35eb67c7d4afcc38d6f35875c12f8602f381f797157102334f9c01c483f8fb41abb5f439ebefb76fe260c7","priv":"8956ffbb87e45ba0ac8f4142e179e6f934ca9b88d754fd5347c340a598878088","pub":"02af92f546047de11b15fb4a4c13c77ec6034248b84835f421826a44a68477fec6","addr":"7a6dbb8c88319d3076eb0b387dd2a9e4209b3229"},{"mnemonic":"tribe unfair track nephew erosion spike machine exist wine banner horn document","master":"c8e67f2accc6f9d543e1619dfda891664d349f11eae5617d32a9132c015b964a","seed":"ee1bddbc1eded07dbaf52feac014380400de9e006bbbb74f0c12095b381ba01a696ee3c3f62eaf4324e49b397755cef44667762ec46321f5762ef0e269dc9cc2","priv":"4caaf1ce46e2a6bf8e058fbf063da8683aaea07af831456522ae501d4d09d517","pub":"03df708621a45e5d5fa1108caebb51c513ed1616529aa6f89e3442a840aa37d73a","addr":"4d5e8ec1737a693fb2820994f4dd69291c5224d9"},{"mnemonic":"assume wet effort damp similar original salon aunt grant peasant fatal toast","master":"ea31d3203ecc33935024caac7c319223ff0f4b694cf011538521b318716cbdb3","seed":"11b227c8cf099bde463f72b505add695254eb9fc4714231e09e337f1499791ee2441bd5a148862265b6b5414d47f767398fa97a392a82a0c70648b4a52c1c2a7","priv":"f96a9c148945df0490611dfd06ca16f485a153e96857d746de0f2817cd2412c9","pub":"02b7b1c5e504b37104fd92465cdfda7261a60aad61b7b19b040d074fd07ec8ea39","addr":"036687e670428aab8b8057483c02ca0ea8dcc8eb"},{"mnemonic":"celery inspire ritual apart bring pause sugar monkey leaf tunnel minute alarm","master":"fd42c88307af74bce721f71af73cdc15eba0a186923fb9ff122d86597c1578ee","seed":"46042a350e5932c11cf735b60382d9a331a21f199cc484cdb9df4d8b9be0400c94d58ba1bc4d41826e605c625c7301bbc61e71f3da650d2928e83e07de6a9097","priv":"23c351e14d35d01f62da3cab73dacdc1c0ca052a76a41b58ae9d5c0a242e5fed","pub":"027ef3a78f366db4396cf1da6d124e31b254e90ad0c517267fb5a20a0f4034fc93","addr":"64a202ed14304b5f143d5d10a08167decc68fc53"},{"mnemonic":"text blanket lake damp doll guilt select torch midnight tumble toast dove","master":"c9653205120cceaf6cc768674a6389ee961403a4364e96220134acceed105299","seed":"79d5619f5dfeedd623bfdcd7d201f58ba55a2fbfd0424f32b9a220b4a39cd048e5cc82686e578b420cc35924e8fa31f1a4a29307dcedb35a4c69567da300b07f","priv":"7a7205d096a658f41be1d4d6b8a8644bf370c34a10a55f4a63ce1117d71715e6","pub":"029b2f32b98281d644232c4d603aaf89a98083edbc75b61f8aa5ad2c7ca910079d","addr":"ee416c1d1471a6d06b755fc92535f0bf1a2e3f4b"},{"mnemonic":"crime level shadow chronic rotate era reunion fossil boat shrug patient artefact","master":"fe8df8e3413387b50476e0ae97fe9f3851d5645f90b0bcf0b47b18d16387c057","seed":"0be8bda7509b72cc2d39c38609510fee439dc03600883e39f596cfc30cc2f48dbf14860ca33b7b7dd6f5f41f3d2fa71d20fe3995a698599605c5ea23b95917ce","priv":"4462e7a144223c97450b5d6728c6d017ed953490f7e762563993fa309152ddb0","pub":"0278a9fcb45bb02944c9cff032c013168943c6e0193c6ba6299af4397e8113a340","addr":"a925672e895976c8783d48180cedd09b2edd6108"},{"mnemonic":"chest flat tissue cousin defense ramp burst once rocket time super retreat","master":"7a8c847ca8357ab65fe99b5cca5d0b70bc8da05adc747c4c2f201fa1e22d753b","seed":"96003a7547f32ae6d8e5ce1bfbd5e580cc8c81d3eca4397e5e1453824b672a6d966d97fdd462ee8c0553d832c28c42fe61e78f01d056b2952a6589273ad57514","priv":"e4847fb09c9438d765da59b51c3dd825726ade929294007f9ccab300c100a2a6","pub":"032ebdaeaa817d8b8bd206839e18d17a85bc44ff4d7f0a5367c4f48098b511b43d","addr":"449402b089274c0b78b40e6f45e8297badfc1bc1"},{"mnemonic":"elegant dune all subject country diet flag universe gap ability hello torch","master":"fba87eced090b1d991c077467db81d22e2691f9b15ea2e8ccf03a51a556ee13e","seed":"1f1cd5b090411b96728a6959a4639e3b2bd68d4ea5c6ceb801a5849af109650237d2a6727ac80e7b317c625faa593d7a8caefae3ffbb55f110bd66672cf516e5","priv":"31cf4c4c7e75e35e16e01071e2db66a51758c8cc2b5df3377462046e4d87f3d2","pub":"03722bc559c95cdd7baf08a6965a47a7762fb974a854d290295bd853f6be0a83cb","addr":"b7f0dfb1c5136bd9bc267e9c7b33c047d6a1429e"},{"mnemonic":"give citizen chief eagle horse alien below flip vanish eye sniff bus","master":"c3dc631ea1b0226bfa3572fe9b95d72d08bd160cdd5fbc2fc96866adaa49a431","seed":"196d5c0aa7839623842c51f2e5593695ddb596bcd839c70af2940e8d00f31dd68b45876ae7aeefc6032e8b939b4feb8114ce9c403e4b83e28a49ea69a97360ca","priv":"9fbb966c19808bb2b7d07c420f4aa59f7a41cce08499c4da2bc216d857ce86d0","pub":"02650905aba484a16f7c1a2b1bcd0ed4f16f45d1770cce32ed127bc046d5f2c3e0","addr":"1441b38310ffb1135c2c48269746894accf627a0"},{"mnemonic":"gym term crawl benefit kite various pepper noble into slim try then","master":"e5826174e32bce315c7baa21ca97c613b4eb095d74651867671afd3848343668","seed":"198b6d6de96c726477cf8cdde784fc43a89dd46ee8fea27933ab8daf09826ad0d7bdaa0c50f8d5c574f6f2e6ef7adabd9c2382feaae061c9cb10a3ba22c5dcac","priv":"ec23afe15c13d5f0c86a47b18ca81761976442cd7c07975c88d6ad475771694f","pub":"0331ddb4db50ff58ac1709986111cbacada08344bab6210da4a2f23b0c3208e100","addr":"625e5b098af6c98677a9a2cba960e84c11dfcee1"},{"mnemonic":"pause web there legal eight plug wheat convince adapt radar rely inquiry","master":"b13d46f4a0c6ef2cac56cb9c522dc35b8d02f4ed4f09f524d206e9ea6e6e6082","seed":"5f34196fb26a7bf0a9063284f702d934c03eb2ac10f3dc230a999e9566d3561b9dc0a61d199e7d9642b06474c08f9e12e618ac5cc1d805ec9cb9489d460f377f","priv":"b410cd330abf2a25f36b24fcbf72f73e5c62786cb5c0c24fdbc3cdf6ceb892f6","pub":"03755fa255c3f111f778c270f991a5cc0fc24c0068d78355ce340258aa7a3b81ce","addr":"170438465b203b844f98cf54b49cdf17094afd80"},{"mnemonic":"thought morning dad seat payment ball club goat man urge forget remain","master":"af52a1f224909be5cd5e7be0b960a995c1d25652cc0c6791060b98e1aab4ca9e","seed":"1e9bd47b5411fcdb8145b9eb1e7092eb218774c85da6efa3756e9a55e5ddc2153eeb568139c638af44cfe6cdc2a570451ed68c801dc2ff726b45ed43e8fd0691","priv":"5e42b1c08965620e1e647e89fe87c9079060121f5a0b65a5ca8cc462fdd13b20","pub":"03a7ca8e9445a67a6884f58e0e79b1571b34b90dad6df4c0b8dfd103e500bcb20d","addr":"f44393294c3f1369012836ab432386f1af2cce44"},{"mnemonic":"twenty memory ten own runway grocery polar dog curious program gap country","master":"f08104e81f54a7bdb17ee647c06009667d4d1ac6efe286495bcf2327c229adcd","seed":"10d3111f871ce9bda4a790e148657f6dae8586d0d80379d40e56cbf180876ef7ea5f2a66f006a8a8a46c7de99a4e4f8f5fa4cd1a3756a38a71971298af917d21","priv":"db3cc8657599d42858ee1f1a7480e68ee8cfecc0fbcca01556c1fe5e8f3a0025","pub":"02add58efeceddf43db9f3d12b54dcc1f1369f152d427a7ad5e3c8de5de23a16e3","addr":"eb30fff2557ca87addcffc02d3a237fd28511799"},{"mnemonic":"elevator sock worry budget skull bitter faith taste skill physical mass heavy","master":"bb2b406a20bc8b38709251d1cabf4631428e2ac053154db69e2f1c6d236c4716","seed":"71fd4f050ec95c4147aed32ea34bc065e67635315b1077a0e9453d883b0a4519015ebd5de2ad0f2a628c20881567532f3b679541e23892eca14d5ebf4456a8b0","priv":"ae56d8b12dd0cc788ec4d5eed7153b108aad7606d2f3653ba5c61bae06dd1cf2","pub":"0347f3d0ed7552ac8d667036f4403911b7a98f71cc1730223e74fee4194d0aeebf","addr":"98198786f5e46f72ac47e88168ede1378404ee70"},{"mnemonic":"message power uncle glimpse repair coin wasp flower alpha claim federal tourist","master":"28f596f188bfd9a0f1ba2729260fc20ecc1c1b67a20bc8a4f7bc0e810a625ec5","seed":"5a23114eb877a016fcbc82146957d2b9880ac79582776fecad126fd6b5aa81343cdc69c46f29ad17e19411f0f4e78817338a9fd39a72efcbad31ab965f8782ea","priv":"1376caa21630e355fe38924afbacded452c9552eafbd5b60dbf090fedae3d793","pub":"02713f022ea80f4807af048cd254ed4dc5a1276c21e4a7436306f83731843a5402","addr":"8a1cdab91bb44b089a51f0a736e914a37cdf20e0"},{"mnemonic":"infant walk right wave helmet punch alone path since output fashion isolate","master":"0de852a741c097122fccfc397d9ec55223ec1a6ef395c1848097a45aa6a4f0c5","seed":"d1fbf777f64ac5ab0375876dab5e934794782c73e84dfcb19a291a6a083d6aa6d0d3de7e8c804a8c02875ea5fa54a06159538f98f9174bc6cf69ec94e3bc682c","priv":"0fa223b1f217baf7a296e483ded5e6ee97facd5841fb85c78b5ecc4db7681838","pub":"0276da67ef9f098a2ee3a3a18d4ca17705448694f895c6ffc97959fd6507e904cc","addr":"02aacee8fb5e56f4b39fcbf7253b7a1302b0d8d6"},{"mnemonic":"type squeeze vocal monkey baby scale behind knife cherry luggage struggle what","master":"1e156273aae1d8c0b58558726d2f19924b1d06659adbe3539134f58a8a1ff82a","seed":"333847666190d4b5c9535920c47a6f68c586aa3f587cb7349542c0a30950f7208b3467ed437cd815007b11a4326f20b34f45335ba64cf9bcf17ef71aa10b9b86","priv":"c307afbc58b3561c7d276502e1b81de8b01c196bbdc1ccbde5855e00707f58ca","pub":"031a16f0dfd054f5d97233ce07cf647ad598a84177baa82d2f89a7f23cd0f2a0d7","addr":"3b1d109cab9545dbbe82631dd4f903b43cd79bcd"},{"mnemonic":"elder shallow catch anchor slice hundred kangaroo stereo myth proud clarify open","master":"babfd17c1c9647175a7b2739eb700c3385be4948f97d1dcd50cd17fbd605d6d2","seed":"eeb063599bfcd2520f7f07b3eb885cb83953ef9931926db8d1e76b689954ca902c6edb785af6d579ffe89f9253f5864cf21d3f7373986a6c1259e4bd0bd16437","priv":"652f38771bbddf64d2040c1300c317c42739f50839b604cc8f34e050b4590a95","pub":"02608acfabfda5579dae5d9efd4a191925864aa656e55b039da9736a874d46b8cc","addr":"f14a9e2a34c1cd6b95fdd473ddd799429fc03def"},{"mnemonic":"screen slim squirrel fox stairs still close club day satisfy either sentence","master":"a0101753f4e05c8ab9bfb6224120ef9c1f99ebaebc31c5aae114f68387676f5a","seed":"c1ec85f49b1928ed7ac6dc781703a66ef39692ba39f5296d9da33f93fd68cd85b0eb57cfb6ea115ceba67df15e4d835d813e3bbeea0363ef513220b98768316e","priv":"91af59d9bb62c2a2f0bf1b5c8729f2be88cc82e141fa045e59748f2b156b9a03","pub":"03a76d83455b42964c021906265a4e006d2c81555c8591a641ac0c495cd0d05cdf","addr":"093ad2a9be7153222002d94eefadef04ca7ea811"},{"mnemonic":"insect deer physical dog aunt metal super soda antenna broken undo athlete","master":"d3a4a655aafd0dd18e196b2f4e57bd4b1d27fe521f9312104ab75ac92ad92e62","seed":"9975a73239f3e2543108bec6d75c5c9a24261c9b2ffd0e088f6bc8369804b70ce99ddbced3c4cc2e1cd955be824f5d881af09e5ed403d7da2a533c73d9d82df8","priv":"0a313ab091f7fda44e92ba2482b8fe1294646bc9d27865bfb34ccd702376328e","pub":"02ff6999ead46c520026b1faa27004851fe1b2295e5f8b79ee1e87b330c45216d5","addr":"e3ba9de7fc81b75eaf4c6ff126b434dfda0a5008"},{"mnemonic":"layer embody trade slice odor deny please small clerk device ceiling right","master":"2b39b4a5aa164609c2734c00c1029534c5d7f3bc6b94268758acb506bb139608","seed":"1bd10cd1d50db3dd8f9e76ecf39b846d3a2aa44be383868921b155c03ed3485d52236c49783f5334c60e473458be3b3f588b9ac3e814d144128d96fbc002393a","priv":"5953e09dbaa56a12eb5e69231835924c0e38d5c322a43c354152a0333f26756a","pub":"02254c4d6976965f7c6122efdd52f65ee9e25b87549789499b72bf5d7213829d04","addr":"603d5b893cc41223eff641fc1a374a3ce97138a7"},{"mnemonic":"token heavy lazy little dry glass riot hobby keen blur wise okay","master":"7d84cf25bd5f7dabbdb7beae83d1fd128390b3a0fbf2d56b44fd34a7e0d11539","seed":"8f144bce2e5c73f44e5dd62ef4695c6e3457ddc37f64d1552e5b46a771120ccac23cd592b27a135c3593f8f21eff22625ca7bae8581f4f8ed223e813f5d98a6d","priv":"37d2c3993b275606241307c7b2339e304180555df260f18f524abcc75abfb0f3","pub":"02aa996bf4d889c9b37aacbd07d8ac3ea69e535c065a4b4258844b10c2a08eab8d","addr":"4a3860dc280c75a00382f3d8f11cfa01fda90188"},{"mnemonic":"tray drink color across armor spawn vast skin debate huge surround play","master":"e0cb1eb09b82bcd37fa63260e49222cf13b0b07cc1568aeb8849b538bda65a1f","seed":"faab52fca3060d1903e861706b57ca50ca71befd2d5363031128235cbb80e53ec943362f2288fcd1c850e94cf4e7c38029dff1880dc3f8c8bd440b14ed15fd01","priv":"747aaf84f110aefb34026ca0492894ccb8e0d1b34c5b0f9a9027320289914b52","pub":"022d3e35a5f51a6be1d0aff686e66e2fe282e42a51044ddca65b8a7659b6386f3c","addr":"43057d3d99231163cca42fe248b9d350ad7ae146"},{"mnemonic":"ring act drill burden sunny someone riot spawn uncover sauce today jeans","master":"676a5a20f35054b4f7ceb22d38226df0b2fa192b6bbdce9a96fba2b51845322d","seed":"979a3caac9130fab128a59243447f5add05251ad385f0c0ecca60920cc954ec516479aaf4def728770606db840088242a8bd5c3758f1ecfa7d3f8d54beb5cd6e","priv":"0e3f2306a70147cb332877343ff260e18c37d807d1ada3db3545dc21cb7adf71","pub":"03374f7d18335d1677902e2fb7c7afb6c3646ab18bc76d12793b86e0097d2b79fe","addr":"4f65a8364edc65cc430f4916af41cbf339c34a4f"},{"mnemonic":"title reopen welcome pottery stand safe scrap little razor rate oval rabbit","master":"600c330dca29a426ecae0e5e6dfcb13e004efcfcab0fcecab676e42462caded3","seed":"7554d02d091605c47acf117773dfb96821e28c551c2c5e855803f79f7ec9b9e5a4a7273c605c2a53771e045bcada466d3b4a88d03a7fcc1644d990a8dcb21ff8","priv":"79621755dac86e6026853bcd0d4c032b48b7c5eabf81cbf8ca4e9d056fcec5a8","pub":"03f63693949fdc2b62cabc47059e8b1d9ba748800bf08a30001e19aee33627d189","addr":"ae0c6ad31b94b29d502a846e1e371356a96a4f2d"},{"mnemonic":"hat stereo gold maple advance wreck poet dawn excite midnight kind type","master":"661d8b63856089b6f3d6bb37558d4deba395c7ea7797d022db398c3224696316","seed":"b13cc53d42e9726cdd9fda4279a660d987dc3d302409a0ccc844731ae1b138495200bd1ddee3912124dbe826e62567a9b9fb57a33b638cbc4a56f8b55df3182f","priv":"548da8b9469029522189b9d4e30f6b58c75f234f18b99d4f4dffd027b6e022ed","pub":"032df4ae6e9e3ed444bc1fe3eba670f2d877de7e579309fe3e7a8ea3b5176999e1","addr":"f94c66a0851fbdb52cb7b6774c736cfe4f99edae"},{"mnemonic":"image wolf among domain where post bicycle perfect cloth october bonus plug","master":"1751c464935d8be5b1f43188a61f14d0f509cbe289d5e586f1c5057299c05d56","seed":"80bc37cd3dacb7020735655be8a001ea26bd8a5a74d950a5ba3f31603bd929531d6da39d06499927e5acaaef4845b3403e73e3bbc7a43434242dd2b432f17529","priv":"38db8c107323379d07ec59fa7b76ceb436a5430468562fbabdecf4bd0a06d58a","pub":"02c5e7d3d224db89285ff2f71c27a68b267f9fd799f05ee334084edd4b91d4071c","addr":"40551f9071d46824a15fba194d98425698145795"},{"mnemonic":"squirrel grit cross witness wagon defense marriage tonight absurd organ load sing","master":"d5739288f3d99e1759690e2d68e5ba543151cd58a0d55d0be52f0a4cfcdc2a3d","seed":"a3e09aa4755d4a4c48f4611a7a8c22040feca1694415b2a6976d2ce161102557f5e855d5195b0132c9e7f23e01b825465eaa10b19ed323647ea5beac8a635e75","priv":"055f00180e4bf6548ba7b525236f63444808c0052fabc4eb14cdad2debf499a7","pub":"03f9831a1213aedf436bdd9e898f1d571ed6a7858f0168d60afce7ac389dc27d86","addr":"8a1289c49f8d83275e4c2201c87ded060ab38a36"},{"mnemonic":"cloth diamond test stay also risk music unit beauty escape trip draw","master":"6d16a7ccf9577b8948afab2ac83cb12ea124e9cf86506e6d08f3fd685ba97a71","seed":"d67dbc3d1e00b7703a7a44b91ddb891d89128f59d2f298b2a48f464aaea9852b97fd3002569d9e4b8a1cebf0d7eef3b708a944b1cb745844fc01b71829bbb2ac","priv":"d52b78224b5e2b9d074b4141dba1956b33f66ec7e8e271a20786d04136d1755a","pub":"020fd792486b8d8777b9910bcb1c28c52fdbaf239e07885b94ebf85edca05f3609","addr":"f571651ea3de2e84b53da4af619b1c51acdf9c13"},{"mnemonic":"vanish slush budget question demise bargain inner push weasel clay project project","master":"11828853c3e89d3515ac8c838d2a5107079c93695c430e2d5383fff8a0a98de2","seed":"9f838e1b4140cefd6857ecda55690fdf36bf4bf0247833801a481130844a89d0483b05e9cd1042a855714f67298a3f9d8cc093e6bf9e86b4c7bf16223f4f89d8","priv":"2e5945a384de4ed1030a299e8dddd2c9ca20aff939641e3cdbb00f5619b186f0","pub":"03a52a0f153c92a5fcde0f004c4ab3166f040b6e7e609afee6c2d0e494c18e7a75","addr":"09e3386e3636e365d8bfd15e822b0cb50136b5ba"},{"mnemonic":"blind desk mobile debate orchard nerve crack tower little scrub twist fantasy","master":"4d677a558cc1d0911ccea1c14c817b8fea57668f9a81af43ed036a1bbbd8b6ba","seed":"eb67d96512b6136ce060c7b7800fe48a8fc2ebf50a6051f4be4255a5e974fa0443f0c5ce1efb0b0a87f227b0da5d740452313d86561a42262e5681864b529054","priv":"d54dea50a4dbc94530ed3c04771c6f4c71487cf3562e89b79684fd6ab7843846","pub":"032622eaf55666e30dc53d73a88517f24a08f6ad703f02db30e87368c5344cbb17","addr":"eaf15d884294d6b72b618c55206db3685e1b0532"},{"mnemonic":"thumb nurse there alcohol legal agent abandon sight pill street speed catalog","master":"1a041414d1258b30a589e61e6d8ba19a34ca2b2e8bca68962c0c9dad5863f5a4","seed":"1b539679974f7355ee02c9d6609640acdae476ea23bc7d5982604e20009bf3ec153f9ec82fcae5de92570d2bf94672047557a36b3ad3f3ec03b910038658b816","priv":"5ee3c0258920c32da893a0fa051593544fd3547c6e37123ef9d6edaea940dfc3","pub":"03e8714f4d3e9c3e342dae646deb62c31cf3a4bda119a820b0ff6810b8e3d85383","addr":"a3eeef1bfc965df2fe15abf7cbf19b381a458478"},{"mnemonic":"crew venture wall front gesture jaguar often arm fly scare lunar guide","master":"656a72d27ab1a5fb50e27fb598037dc2ebf60b1b9f0bf7612a8490c1efed6b39","seed":"1cd2a5e644dfe51e367da6784848ec64ab3c4965818dd3529f00efdc102388b02dedb2207052bfaabb32a4039f76594b006aec871dbe9856f2b71fe6f426d75b","priv":"67cc3ba8f7d83c6d08737e1b56dfe469c21500f20fac09e8bc096a091682ae73","pub":"03ca0d6eac7a2663451d29012c25bcf469d12c556f30a57a34fe6d66d27d506db4","addr":"5acc54542938330e6961c6ee770760c135ede717"},{"mnemonic":"survey never crew section reward cotton praise ketchup treat suit knock text","master":"7175659726fd0ffbbd37fd2c7e309589d32b271672ca5459b7e1daf5f2daa105","seed":"a5a37f251e3c745169bed474c8ae6599da847ea473da32b8ff922f2c710a3c31034dfc45dee514af90246bbb1317e21669ccaa0666d3c88c8f729fddfb95d240","priv":"fdd98704f53d7ad0e43ae71437626048fe23f71c24a67f31b9491b60c4db3c9e","pub":"026936de280e31c060bcbc777bf28ed1ccd0128be0c25f9d074378f72db1de0f4a","addr":"997434efd190bbf98541832fc48283ff736a067e"},{"mnemonic":"lonely physical plastic final cool beef cloth chaos dizzy enough whale farm","master":"79842f02a7d39d8f19373fb1ca3c73f1961c916628279a00c96a980cdeade871","seed":"f957d8197386bd4ed6c5000bbbd02f70d6b4b76953dc6a3e36f021d488cec54293198f64fe6d46c52041bd34efbceb1e6cce3184a42c8fd37903b924112ba2f6","priv":"d58df19dab225b29ea77bfbcda84c2f1982ccb6e1eb79011bde7adcc03b95050","pub":"024ed971b9763ad9aa8be27d9b75d9ff2f443594da5e3e0b7a598c71f6c2e0d759","addr":"f4d72185f769724b50be932caf960a1a3951ea84"},{"mnemonic":"can three trend breeze spatial puzzle stool cherry raccoon sauce bounce balcony","master":"e76d9d768fe3ead9a6c1b561649b292d8659a6778442f9451a8fdd52e35637d7","seed":"85aae0e7a3e2efd67741cb0d752a078b250deb53927bea3f384d72661889409389188f267d7be61629c6a85aa7dc5b2607a066f32ac39a2c5efc4720b4a72e7e","priv":"57a934f4fdbb619a40394cda13acd1fc61ed9f17e4b4fcbcac2248b5703eb71e","pub":"02004c3736772a2cb507231b7ab75bfc7c1d35ca9e49523f1076e7d0925acce8ce","addr":"859915a9f70f142a41b0d169e7ec342061fbebdf"},{"mnemonic":"gaze example quote much tourist pitch victory common lazy message random glad","master":"6fdb41e8f54d6f123c75856c1c13caccb01bbd7e84b1c3385fb5fdb885f72f09","seed":"bdb5196003c1d1d272367b12affaa4d0cb37fb3aeea88bde6992dfd3519af34e94729ebc9e8057b9e462c064292a7cac18eeb838ec0f71b082cfd66bece3c5e4","priv":"1f264f1e86de3b28ea8f4827dee679787e60e34e81271139a8e74870518bce27","pub":"035e75a0beff3188c9d5aea7a760b879413ef712d98354b702aedc3385d58c903d","addr":"67c21921fa2c47c5657ae2434c29f447511fbab2"},{"mnemonic":"taste panda wreck guard trend blush armor giant innocent palm trouble silly","master":"8f3c32829998fdb3355b3a88caf484eaf7d67122c991c2402d77eb3e5e4f8416","seed":"fcf9f308ac99d81e74329f60787fd311848a2e56384202c37c025bafeb7022e4b47ca24a680d07d073566c487f39c8c0dc4bf43569b73f30ba4a2c260ce98e28","priv":"463194496ba851f6455e8298a0d4c118341bb0183c73c2d7739ef2c5bee38e0e","pub":"034a87ade739d3da37c8f15928db9b064bd1d1af0c10ffbb9f2027f42061c9bdf2","addr":"b0afd62cbf962672d092732872a6ab2795c9132c"},{"mnemonic":"tragic enter actress believe nominee floor vehicle dinner bulb useful case bamboo","master":"66f8cb0425dd278236de1352e9b2e47fbb8662d1de9d31227c4f18873b6aaf4d","seed":"5f0f5113b93be9036f009972fc49d9fa444c0dc4f89ad2e5d590f33b2aee250194494bfff047f8c9cc0261208d0d842f4c8a320d68f852c0938b6dd472a9c819","priv":"3fcea63ea530b9539af1ea66f5ceca1acc508fcf21a0d5ac21a378af5aabfb37","pub":"0256ac4246f19dbd12af232b2fe00efd158624ea48728b3a647c8237b7b9c1fe56","addr":"13804f3f5f0ba3c8f769b2e3428962f4ae88e4b0"},{"mnemonic":"between grocery tool polar already roast cash budget fatigue museum obvious notable","master":"c13b5bb1840f804c9b1da51fdb788f9262fad64b4c576370ede2d9c4001de2fe","seed":"1e5a866e10ee3ed7e727f59673328eae03808cfdb1bd3c9f155a1ce8f7c9bee61fd8d68d6b995588c0264400780467313ba92a9c359edc48ca59dcfff62567c4","priv":"08d7d4fa44f89fddc836ea265b71e9985363cf4e9ba0cb5b1ef0bfcbd00e0aa4","pub":"03514e8e0c990a6a60b1138351255827c7c46e15c3bc25f55946276b5fc56d9068","addr":"0c759c31f5f142dac57e712c7a09c99a3a0875ba"},{"mnemonic":"combine unique pig mind pair area chase idea abstract grow into result","master":"e7d06819461fbfccd1e05b6d63507b179854fd75fe7fcce2cd04ad6eb89fd11d","seed":"a1863842b2a6d82dca20ece807c12c58f6c4d2d1fcfc2577baa368a3a45a7ccb0650009ab558bc8350b77f9a03f6155e8c35f76ebf9b30133dc732ef5abe69cb","priv":"a545f01810112491c613a35c829157cc6a3dbd30b4b51f1d1eaa53fefb61e09b","pub":"02008752e98ab20e0fc8c9859884f97423c2315f5f35d1d757907b0affda7da9de","addr":"353ac98ae22d3161ce81bed93d7a0d77abd9e11a"},{"mnemonic":"bonus voyage inject they glory wreck soldier anchor also job cattle random","master":"cc5593732d2681a1aed33672cfe74f24238443d1b118235550834e14bc720235","seed":"ae6175dae17f8ab7481092eac1ee7d4c08d9ffeb69850745a1507c63426aaee1ef3bc6ae7fad3152d9bcb58e77a14a9570a4c550078c963991b215db64a2e9eb","priv":"45118b84fd5c7802b71fead3d78e5953e1841ccb4d4cddc20aa154e9fbfcf467","pub":"02a0378a67714f50eb383b47f7ab67b32c2adc2b8376b12da9e656ef11da9172c7","addr":"aa4e5ff5d78486413eef80525d20fc0a46befd5c"},{"mnemonic":"axis grace advance retreat fence prison traffic shield visual evoke upper they","master":"b0f1e554c9c4c38355939ec8641548df255dc8260ee2beb02eea8436359731fe","seed":"42d47d86e0eba00ac90f92e464cb034b25e3e261618ccb7893524e6103b8ab8edac9262e7417ca55cec0e5b90f0405d6b43b920317597d8b67c34f909b308ad9","priv":"0e986b99de5e1403218a3d6e64eda2c6e980002fc9345795464c6e100c4d214f","pub":"028193d72358fde04b71d553794171a3f6800d2d20d1d4821c2d411d9dcab044f0","addr":"68ef0232b6199e173a31b522f73b8740807e7991"},{"mnemonic":"speed advice script dynamic company foam mimic conduct wasp soft stick insane","master":"b0f61b56e248b14dc116231490779949a829920a9caf582fe25df4459e65108d","seed":"7b8b72a1bff2551f2e704e68f364b8d578e24bd6c51fead9805c2c33bf463dd462c793f73b88ca6353e8385a5baeba2c91e4efd6ccc2b80351cfed9d9a6d7738","priv":"32e5a08edf79a3192b221f978e209fee7f7d64f83c28ff57f47ff5757b727b14","pub":"02fa4ba71ba618ce2f1508b0386ceb0e09e202722353d9724a597cd680130c53e3","addr":"713ae3fbba6df605c843147183dfbf3a3fdd86c4"},{"mnemonic":"punch fame nasty actual betray melt find wink cross hobby double there","master":"a7bb2a4a7cc93d7dc12efe29071329febba1c999c4e7766172d9e53fe29cb0c8","seed":"6876d29989880fd1bae26463cd01cb148c68ea842603822657d0bdc708a8987cd33453087febfeda2f3ea53f2fcd65ee1c5f89b0cfd8aefefee2c81ed32c91e0","priv":"731b30c783b7cfeb7458db1e0c0db2586216b6ba661f1adff761977c782d24ef","pub":"03ee75f400c95ecc4b852cd1ea2b434f5cbdd2f6eb8a881f0f24a3d1098a6ce778","addr":"96ce0c791931f867dc4fddd2f091a552f1e57d26"},{"mnemonic":"feed session repair glad envelope pepper faculty earn hour slender cost boat","master":"d8507e0bbacaa494dd65a38d82c02f00d168ec8bdff9991f78ed5fc13ba81d38","seed":"aa9ac398fd8c94bef20e9b9a94bdb81fcafaec2453efaa2929730145528495515d7632de9cf558313a35d50c0428a15f01efc831379a696f632705bba7394ce8","priv":"ef95d3d563a0e774c8d486adeb2d22f4fcf4cddd80cd2a05471b691c12cfe0fd","pub":"026b711c8ed8ea414276c9d7c7a92739a350cbf01372d41c2160c046e1459223be","addr":"72da6e869b7d435ff2507e658acb26e0a50e6303"},{"mnemonic":"person affair gesture cherry intact day wrestle crew okay express throw large","master":"84a10e3f12a6d24e76cd66e934116f9478d8b1bf912fc61c9e00058f7c489f6a","seed":"5dbd3c2fe715a4dd9ca5129df8fddac1f699429636a58bcc2379791af11dcd77bd9b84f3d62539bf5eb41eb8fc966304cf334cc46133b7e42104a18733514777","priv":"337a826c33caf41a74b465c6981986d629c13a71aeef4c0e7c2b78fc3dff613b","pub":"03edadf784d13c4e22b33b61222e20348cc68e245d8b143dde09d37963e9e01eef","addr":"916fd4d732155d78fd412b4cd78abb49bac56c19"},{"mnemonic":"nose talent woman drip regular endless bar resemble friend mean frog cage","master":"1beb38f144a90141600a34813e98ac3cca43009e23c542b3009f3e22988b9705","seed":"aa324508ec3951c30fa4b32ca7a4ea48773c572652076a2a7e6aadec3faee23c3388663002b086483f39a1b08fd50ff233ddefded05f583211686d0323dd4d64","priv":"67109cb296022e46fbd12569cbbaeecec1843479bc716f7ed07ff996561f8196","pub":"03239409138ec1b5a60e5d72f894e95d599be18978d9f43bf201c85bc20210b473","addr":"580cdfe5a38f37a644204cd1d4b0094dffb982d6"},{"mnemonic":"undo thrive relax ancient menu milk sand race bargain evidence steak tomorrow","master":"1db1b33c9f26783cf9743ec719022a1280c8257ba11b2b03f35455cdfeb10ddb","seed":"b9905331927ef09ae2dbf5bec382cf3f18bd9cc03bbd4d21e8f63cbde32cd22abf07bdea578a201558f2a1f09f2fec8e3c7557f731a57439f1e348bd7530d9f3","priv":"c91c34d1a5218ecbfb63990b636d8bcbf6d7ba4723b70c960597f1b4ffb2854b","pub":"03c7d4b726c2ef316d8e60f0941e2af09c0cc1a9967aed825c322b629f74ebbab0","addr":"cbc5acf5001cb4d88fe88404cf3d1a919b127aa5"},{"mnemonic":"relax owner update nice speak office assault pottery uphold clump since ball","master":"5540b4c874952470d93f8a94689bd58c03c8bff373c74890e70b63caf9b5fe48","seed":"c3e8c04ce0d472761c468cdc13d04cd8fee5333a806259657923aad79d9bab8333329353e69cd3fc67833a7041a2c49f3c2b0654a4d243415f3f2761a4f7fa29","priv":"882ea08c9157b6bbfd686007ad668de373f34dbeb08e5d983a447a12c9efad3e","pub":"022f8b50589f2413d294e33de8fcac751c4c6ae54b359ba428c4a1ae28cd2ff57f","addr":"6ec1ae2736cb2a9e1dae6b5d5c7d408347db2dce"},{"mnemonic":"immune find story sadness depend debris popular swallow egg gauge firm drop","master":"fa46f28a8f32770393d3a3fd934141823d48ae561d8952ef3ac87839867840c7","seed":"6b5234df2c1b9ecb85d8493849e66186f98a828287e133cffc210140d63bee412ec58ede1968c2999485ef80710a83a99e7ffe205c404c5bda7346369c16f6fa","priv":"77cc4d765ee74267ea50ce3637ff9916370802a4940bffc8f7b76aac869ef80d","pub":"037d1e64685d2229c9b49baf2245511b3dc26733e1275c36f60555e2eeee32aead","addr":"80d9e410145ca65c65f143804e7e13f0572693af"},{"mnemonic":"airport refuse lake shuffle borrow depend agree oven huge hen brand reward","master":"b21a47b26023f1ed1963f81a2ec424c88520055cb2d69c329c76e6a354cccf91","seed":"7ae802a81c37abaf146f9c7606409640c53a3502da921347dbc260fc4fa5a164ec458480038ac10a3dc2c5ec15c600e72e011392413e13b9daeea82c2e9ef611","priv":"748f3e6cb6caafe5a188d528557ec1c1e817f990394bea8a011e3cbf6d00a3ec","pub":"029f0f4e5bf957c569e9cbb814295acaa1bb8bbdd549844246f86656ab700cd35f","addr":"005b3c2696248d3e45b43c88e258b2dee69ae542"},{"mnemonic":"slim trap alone fetch people skate middle since yard frown during smile","master":"1db54486ad20e5fd82e7c5bcab652cd01632014d66ccf0f7d6c39bc0a337fd77","seed":"30c3948e518b8ca06625fd7a1318984997ff587aa865207b54d5c9c469386e66e06656fe020665501a1f0a07636a250ddf5c127d5bd9ec497052b9e4ff2dc37d","priv":"0ce3645a3f7a1ae02535852fbfee9c59609eeb226a975ae24c94b7a13acb4d85","pub":"03b3f40812780bd4f8a596c0131ced87b9b981e4950f5217f44de7f777b4d29b35","addr":"7777090b6e5ae18d4a146a0c9c17a1a34cde74da"},{"mnemonic":"vague melody fine buffalo spread nation reduce spirit humor fruit spin diary","master":"7a5951d167793eb5d42307c68a3997fec7c34d56562dcab752c2559b97507e3c","seed":"aeb4a2ee7a25712bb76b26c654f5a79b4e92c25689799de2a11283a668aabc3d967d111e2bd98691dc2b72adb66188888999e0ce03ab2bf1b18e8d5d7f8c528d","priv":"d2dd273a93786422dc68e61e67dc0c48402af5964f85d5d785476bbcc68e99c5","pub":"0347a23bf9c802d6d826367a34219ff155a720b068bb0cc4f9c679d350f35a978a","addr":"88679cd2c43e562c21738ba5ffc8bff82575bc6d"},{"mnemonic":"ahead glad fame hip era kite pyramid endless sponsor tissue winner kite","master":"eafe3d2af7a63b644668dfd23b7f0868a1d6527b630860f79838fc520896e64e","seed":"91f06eed5517fa2367c272a18362085775cc9d8f13b2358ab32d0c626abd87aefb8ffdd1f37712d4c39fb625ff4aa56cfe06a3054e162bb62fb03755a19f970a","priv":"c8d580087355904e691ad5292775989853e59ce1d41d224f97d2d4b96f8514d1","pub":"0342c4be0ea075609aa181fb83ffa189ec9744c2a7c54f7d3fa2273ba01ae127e8","addr":"ebd946e96a89c8932ec788d66f3fe8c482622831"},{"mnemonic":"clump earth diary ostrich section column practice rapid hotel mom client adjust","master":"c6be4ea8b2810f07731b7258f2a2cf4a4bd0722e43081957bd74ccb5955bed55","seed":"04c2178510fe5f7afe60cf8718bc5240da95cc2a79d28fb2bce756a2fb0995f25c5921addae1932dcc4b62ee68b330d3abfe190f212f809816ee7c6d5b816095","priv":"d2ecfc9fffd24c8299647fc2f23a16a2e5b35ec6092563ae731d4737159ce03d","pub":"027c615b33b69f5599cb800a85073582bb2180f20bedd1bb3e8384bada13ab8f92","addr":"df913518315ba257805f9ea9f78c859428d101d9"},{"mnemonic":"teach salt dinner dinner escape cheap gate major bind armor dash gallery","master":"954d52c8574645c888e4eea6ca661fd1ca4764ca9e4243bc75610571a24ec5ac","seed":"7c3753fb498e2a48af89e5a39153382eb9591eb8a5bb2cc5b8bf690bb6d1365162bccfbc9d5e3688f48352f1f8915c376dfacc3c3cad9315fa60cb303161ac77","priv":"c3a850ce632a7ab061e378596cb4c66a6880d41f6b09b0868d8c7e96bde490fe","pub":"02a615c68dd2bb66d3cc9d7e46a0fa00510542471a19b1d48fe05355acf38903b6","addr":"db50721f5b6e0907490990182793ae796756bc7b"},{"mnemonic":"cement casino erupt clever gasp benefit response invest diet banner month hill","master":"97c777e73bebf40d39c4efe8fb74db3cedcf2e1ebd366520515ee2823a9c4d28","seed":"9344a709e0d53322b928e3128d1bc707216eb0e1ebb137f74fbde6cd066f88b86088793a5794df8cfbd6efb12c843399e8ccb958446fa558573b013d33236436","priv":"96464373c492c388bc4a2c421ed0f5017fb426ac95e55f0f322703b28012cf90","pub":"03e71c89b2629c032b6c9a35b46d572dd0db3dde47bd5919bed8457885553148b1","addr":"493af641ce946561f6cb3116a135fe6e6b1b0f13"},{"mnemonic":"supreme news pyramid sheriff attract volume zone innocent hat grunt gorilla mango","master":"2ba0cd68329e2b19d5c24c1d3fca44513151fc4a634e52756290967989883b52","seed":"efbf7e16af697b4dd62a876f62f08698e29531c05018bb6da7ce441340b0278353d5d08a88cb93c4fd9bdb14fb85ab857ea3e8ef13b49dabb20beae2f13af3fa","priv":"15b89635f69b28cee0aa00d0609b99f1a1dd3c83e3bd57032987146cd47cebb8","pub":"021ae715a05c4849519acbe8dbf7ff4031d18f57de1bcf9cb1a06d50e5ebdbf661","addr":"e3087b309db8490b23629cbe4d113c1ea5bb525e"},{"mnemonic":"way chat van put negative minute tail dress spawn crunch beef moment","master":"e0dff85e10808c3ac560957a46f5f86abbfc62251c8fd4c61cb5e089a0841e7a","seed":"eb14b38f90886c1a1d47ac42205b564a649a0cf6edbd88cda1c488ee700aae8b735d7e947efc5711e2cc02b2254690ff4a69d149d2e13affd6d9a3915ac9dceb","priv":"7fb5464c8bc2e1583105d34c6850fb332a578fea35dff9528422c8b7f3156242","pub":"02745f0fbe0b23688e9691f9c4a088bf1342100fe3b9f7e405df79bddd57f8e6e1","addr":"66d90273421fadbab93fb9b05ea6e572f8af7050"},{"mnemonic":"tattoo strong tool weapon blue cricket kick holiday medal club stage reason","master":"bc82d196675dbad1c24d78f4e400a8956297c6113d4004356963ca88617597b3","seed":"9cf6193178f1a6391105c79cc6d3d2e2a4fe97f44738f8f716fb5b17a3eacd4061f9bb7f0411b08d77dc10b16b9599e45e8ffa55ff7f8e5c9274bab71bfe120f","priv":"5925547ee089b4638743f0fabe33f925780772a65b87b8315acf7f523d044482","pub":"03bba775f325b1ad28ec0adf66c8e15f90d70368fa021be5db199a5188c0621eb4","addr":"1f63ff4af01b5b5f33e60b82646a39917b6a7305"},{"mnemonic":"rug diagram spend zebra occur neglect choose relax face when spell stem","master":"d7932ffb8f6b751543caed7158318a05f4686646e636b5725b9b0419fb66912b","seed":"b73957a412d9e4c677edef4cb3a376c7355f78bba347a61f44c85f76b2c8a3d8ac2bd6c3b70643bf19b8487dcdce3055aaf86921e29e5e6f89700e0e2bf00546","priv":"c827dfe5f1880d9c462985b915ff78a1ab615ff0840f3f125f618cef25e14a5c","pub":"031bfd2158660168795f38f980951921f6fa1d522ad460ac5f93dfc4a2eac91f7d","addr":"b866f1e9b5b7b00fbb6076915a0a2931cba6e029"},{"mnemonic":"faith bless there mountain stand cannon sick abstract fiscal theory begin easy","master":"9af948584294b3951e6c664423a12fdfe29a31d41546b911f3fcdf664399aa48","seed":"17b6451f4b9765fdc3ed280fb5a6141b8003c8c9d8c73afce3192e15012fd18431850ebcaa07fa08da2c648f0f97f45e33ebdea6c99f2f23a9e244a297596499","priv":"e759b35d18e8b60726e882a11ea830e30ddff6752a19bec6983fdecf655726b0","pub":"03151da31179657f296184543a1360bcb92983a12788b268db0c20d895e6c449b1","addr":"54ec389ea177e1a4fe2f98cd83f27cce218b9081"},{"mnemonic":"combine fine crowd enter check mule toward damage fortune bless topple source","master":"b831b7a1b85edf1945c892dd332419e7f3a5125229cdfe1c73cc0e964abb4b5c","seed":"d9456b80f01787607d9c3adecdd6fa299132d748ae4fab843b3802c798ea1bc0395f9a1dc29e1badccc742f3c4fa081bdd7b6f9ca8980009b75c892438020b9f","priv":"d9d037b9baf0796d8a151935c172b1f775c1875b3811bcfd6c3f477e74c5c54e","pub":"03c720f00c921ab13307d3790f742f0a40436fad9d999087c267107ce50f8fe2b9","addr":"4b5a1c53f8442c375e9af35937ff0471155c0bee"},{"mnemonic":"shift nut floor scorpion property sun either total follow glide special apology","master":"1a4520e80df55ad59d95fca8dfab5f09753f6e26f7f38f654f32e4fa6f3ff963","seed":"a9df829ec832270d1ef0b0b04542e351ab9145baf086231fbe9636120c18c8d545ed138c37c0612d296c915340f982b1d83bd408301de79c08e4580ce0ce8fdd","priv":"27b1742305c3921c0cc041dc79d6e3c83112828f3fd49e18f31cb0b422bc1c80","pub":"032b322eedf502edf5e6c24ad80ad4bde37e04de012b9bf9c8caa41151a9ccf74f","addr":"2ce4a3aeb7e0fc52c31121651346959d1cfcc1be"}] diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go new file mode 100644 index 0000000000..ad086b13c6 --- /dev/null +++ b/crypto/keys/keybase.go @@ -0,0 +1,364 @@ +package keys + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/pkg/errors" + tcrypto "github.com/tendermint/tendermint/crypto" + dbm "github.com/tendermint/tmlibs/db" + + "github.com/cosmos/cosmos-sdk/crypto" + "github.com/cosmos/cosmos-sdk/crypto/keys/bip39" + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" +) + +var _ Keybase = dbKeybase{} + +// Language is a language to create the BIP 39 mnemonic in. +// Currently, only english is supported though. +// Find a list of all supported languages in the BIP 39 spec (word lists). +type Language int + +const ( + // English is the default language to create a mnemonic. + // It is the only supported language by this package. + English Language = iota + 1 + // Japanese is currently not supported. + Japanese + // Korean is currently not supported. + Korean + // Spanish is currently not supported. + Spanish + // ChineseSimplified is currently not supported. + ChineseSimplified + // ChineseTraditional is currently not supported. + ChineseTraditional + // French is currently not supported. + French + // Italian is currently not supported. + Italian +) + +var ( + // ErrUnsupportedSigningAlgo is raised when the caller tries to use a different signing scheme than secp256k1. + ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo: only secp256k1 is supported") + // ErrUnsupportedLanguage is raised when the caller tries to use a different language than english for creating + // a mnemonic sentence. + ErrUnsupportedLanguage = errors.New("unsupported language: only english is supported") +) + +// dbKeybase combines encryption and storage implementation to provide +// a full-featured key manager +type dbKeybase struct { + db dbm.DB +} + +// New creates a new keybase instance using the passed DB for reading and writing keys. +func New(db dbm.DB) Keybase { + return dbKeybase{ + db: db, + } +} + +// CreateMnemonic generates a new key and persists it to storage, encrypted +// using the provided password. +// It returns the generated mnemonic and the key Info. +// It returns an error if it fails to +// generate a key for the given algo type, or if another key is +// already stored under the same name. +func (kb dbKeybase) CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, mnemonic string, err error) { + if language != English { + return nil, "", ErrUnsupportedLanguage + } + if algo != Secp256k1 { + err = ErrUnsupportedSigningAlgo + return + } + + // default number of words (24): + mnemonicS, err := bip39.NewMnemonic(bip39.FreshKey) + if err != nil { + return + } + mnemonic = strings.Join(mnemonicS, " ") + seed := bip39.MnemonicToSeed(mnemonic) + info, err = kb.persistDerivedKey(seed, passwd, name, hd.FullFundraiserPath) + return +} + +// CreateFundraiserKey converts a mnemonic to a private key and persists it, +// encrypted with the given password. +// TODO(ismail) +func (kb dbKeybase) CreateFundraiserKey(name, mnemonic, passwd string) (info Info, err error) { + words := strings.Split(mnemonic, " ") + if len(words) != 12 { + err = fmt.Errorf("recovering only works with 12 word (fundraiser) mnemonics, got: %v words", len(words)) + return + } + seed, err := bip39.MnemonicToSeedWithErrChecking(mnemonic) + if err != nil { + return + } + info, err = kb.persistDerivedKey(seed, passwd, name, hd.FullFundraiserPath) + return +} + +func (kb dbKeybase) Derive(name, mnemonic, passwd string, params hd.BIP44Params) (info Info, err error) { + seed, err := bip39.MnemonicToSeedWithErrChecking(mnemonic) + if err != nil { + return + } + info, err = kb.persistDerivedKey(seed, passwd, name, params.String()) + + return +} + +// CreateLedger creates a new locally-stored reference to a Ledger keypair +// It returns the created key info and an error if the Ledger could not be queried +func (kb dbKeybase) CreateLedger(name string, path crypto.DerivationPath, algo SigningAlgo) (Info, error) { + if algo != Secp256k1 { + return nil, ErrUnsupportedSigningAlgo + } + priv, err := crypto.NewPrivKeyLedgerSecp256k1(path) + if err != nil { + return nil, err + } + pub := priv.PubKey() + return kb.writeLedgerKey(pub, path, name), nil +} + +// CreateOffline creates a new reference to an offline keypair +// It returns the created key info +func (kb dbKeybase) CreateOffline(name string, pub tcrypto.PubKey) (Info, error) { + return kb.writeOfflineKey(pub, name), nil +} + +func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (info Info, err error) { + // create master key and derive first key: + masterPriv, ch := hd.ComputeMastersFromSeed(seed) + derivedPriv, err := hd.DerivePrivateKeyForPath(masterPriv, ch, fullHdPath) + if err != nil { + return + } + + // if we have a password, use it to encrypt the private key and store it + // else store the public key only + if passwd != "" { + info = kb.writeLocalKey(tcrypto.PrivKeySecp256k1(derivedPriv), name, passwd) + } else { + pubk := tcrypto.PrivKeySecp256k1(derivedPriv).PubKey() + info = kb.writeOfflineKey(pubk, name) + } + return +} + +// List returns the keys from storage in alphabetical order. +func (kb dbKeybase) List() ([]Info, error) { + var res []Info + iter := kb.db.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + info, err := readInfo(iter.Value()) + if err != nil { + return nil, err + } + res = append(res, info) + } + return res, nil +} + +// Get returns the public information about one key. +func (kb dbKeybase) Get(name string) (Info, error) { + bs := kb.db.Get(infoKey(name)) + return readInfo(bs) +} + +// Sign signs the msg with the named key. +// It returns an error if the key doesn't exist or the decryption fails. +func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig tcrypto.Signature, pub tcrypto.PubKey, err error) { + info, err := kb.Get(name) + if err != nil { + return + } + var priv tcrypto.PrivKey + switch info.(type) { + case localInfo: + linfo := info.(localInfo) + if linfo.PrivKeyArmor == "" { + err = fmt.Errorf("private key not available") + return + } + priv, err = unarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase) + if err != nil { + return nil, nil, err + } + case ledgerInfo: + linfo := info.(ledgerInfo) + priv, err = crypto.NewPrivKeyLedgerSecp256k1(linfo.Path) + if err != nil { + return + } + case offlineInfo: + linfo := info.(offlineInfo) + fmt.Printf("Bytes to sign:\n%s", msg) + buf := bufio.NewReader(os.Stdin) + fmt.Printf("\nEnter Amino-encoded signature:\n") + // Will block until user inputs the signature + signed, err := buf.ReadString('\n') + if err != nil { + return nil, nil, err + } + cdc.MustUnmarshalBinary([]byte(signed), sig) + return sig, linfo.GetPubKey(), nil + } + sig, err = priv.Sign(msg) + if err != nil { + return nil, nil, err + } + pub = priv.PubKey() + return sig, pub, nil +} + +func (kb dbKeybase) Export(name string) (armor string, err error) { + bz := kb.db.Get(infoKey(name)) + if bz == nil { + return "", fmt.Errorf("no key to export with name %s", name) + } + return armorInfoBytes(bz), nil +} + +// ExportPubKey returns public keys in ASCII armored format. +// Retrieve a Info object by its name and return the public key in +// a portable format. +func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) { + bz := kb.db.Get(infoKey(name)) + if bz == nil { + return "", fmt.Errorf("no key to export with name %s", name) + } + info, err := readInfo(bz) + if err != nil { + return + } + return armorPubKeyBytes(info.GetPubKey().Bytes()), nil +} + +func (kb dbKeybase) Import(name string, armor string) (err error) { + bz := kb.db.Get(infoKey(name)) + if len(bz) > 0 { + return errors.New("Cannot overwrite data for name " + name) + } + infoBytes, err := unarmorInfoBytes(armor) + if err != nil { + return + } + kb.db.Set(infoKey(name), infoBytes) + return nil +} + +// ImportPubKey imports ASCII-armored public keys. +// Store a new Info object holding a public key only, i.e. it will +// not be possible to sign with it as it lacks the secret key. +func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) { + bz := kb.db.Get(infoKey(name)) + if len(bz) > 0 { + return errors.New("Cannot overwrite data for name " + name) + } + pubBytes, err := unarmorPubKeyBytes(armor) + if err != nil { + return + } + pubKey, err := tcrypto.PubKeyFromBytes(pubBytes) + if err != nil { + return + } + kb.writeOfflineKey(pubKey, name) + return +} + +// Delete removes key forever, but we must present the +// proper passphrase before deleting it (for security). +// A passphrase of 'yes' is used to delete stored +// references to offline and Ledger / HW wallet keys +func (kb dbKeybase) Delete(name, passphrase string) error { + // verify we have the proper password before deleting + info, err := kb.Get(name) + if err != nil { + return err + } + switch info.(type) { + case localInfo: + linfo := info.(localInfo) + _, err = unarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase) + if err != nil { + return err + } + kb.db.DeleteSync(infoKey(name)) + return nil + case ledgerInfo: + case offlineInfo: + if passphrase != "yes" { + return fmt.Errorf("enter 'yes' exactly to delete the key - this cannot be undone") + } + kb.db.DeleteSync(infoKey(name)) + return nil + } + return nil +} + +// Update changes the passphrase with which an already stored key is +// encrypted. +// +// oldpass must be the current passphrase used for encryption, +// newpass will be the only valid passphrase from this time forward. +func (kb dbKeybase) Update(name, oldpass, newpass string) error { + info, err := kb.Get(name) + if err != nil { + return err + } + switch info.(type) { + case localInfo: + linfo := info.(localInfo) + key, err := unarmorDecryptPrivKey(linfo.PrivKeyArmor, oldpass) + if err != nil { + return err + } + kb.writeLocalKey(key, name, newpass) + return nil + default: + return fmt.Errorf("locally stored key required") + } +} + +func (kb dbKeybase) writeLocalKey(priv tcrypto.PrivKey, name, passphrase string) Info { + // encrypt private key using passphrase + privArmor := encryptArmorPrivKey(priv, passphrase) + // make Info + pub := priv.PubKey() + info := newLocalInfo(name, pub, privArmor) + kb.writeInfo(info, name) + return info +} + +func (kb dbKeybase) writeLedgerKey(pub tcrypto.PubKey, path crypto.DerivationPath, name string) Info { + info := newLedgerInfo(name, pub, path) + kb.writeInfo(info, name) + return info +} + +func (kb dbKeybase) writeOfflineKey(pub tcrypto.PubKey, name string) Info { + info := newOfflineInfo(name, pub) + kb.writeInfo(info, name) + return info +} + +func (kb dbKeybase) writeInfo(info Info, name string) { + // write the info by key + kb.db.SetSync(infoKey(name), writeInfo(info)) +} + +func infoKey(name string) []byte { + return []byte(fmt.Sprintf("%s.info", name)) +} diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go new file mode 100644 index 0000000000..d2f093bf2d --- /dev/null +++ b/crypto/keys/keybase_test.go @@ -0,0 +1,382 @@ +package keys + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto" + + dbm "github.com/tendermint/tmlibs/db" +) + +// TestKeyManagement makes sure we can manipulate these keys well +func TestKeyManagement(t *testing.T) { + // make the storage with reasonable defaults + cstore := New( + dbm.NewMemDB(), + ) + + algo := Secp256k1 + n1, n2, n3 := "personal", "business", "other" + p1, p2 := "1234", "really-secure!@#$" + + // Check empty state + l, err := cstore.List() + require.Nil(t, err) + assert.Empty(t, l) + + _, _, err = cstore.CreateMnemonic(n1, English, p1, Ed25519) + assert.Error(t, err, "ed25519 keys are currently not supported by keybase") + + // create some keys + _, err = cstore.Get(n1) + assert.Error(t, err) + i, _, err := cstore.CreateMnemonic(n1, English, p1, algo) + + require.NoError(t, err) + require.Equal(t, n1, i.GetName()) + _, _, err = cstore.CreateMnemonic(n2, English, p2, algo) + require.NoError(t, err) + + // we can get these keys + i2, err := cstore.Get(n2) + assert.NoError(t, err) + _, err = cstore.Get(n3) + assert.NotNil(t, err) + + // list shows them in order + keyS, err := cstore.List() + require.NoError(t, err) + require.Equal(t, 2, len(keyS)) + // note these are in alphabetical order + assert.Equal(t, n2, keyS[0].GetName()) + assert.Equal(t, n1, keyS[1].GetName()) + assert.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) + + // deleting a key removes it + err = cstore.Delete("bad name", "foo") + require.NotNil(t, err) + err = cstore.Delete(n1, p1) + require.NoError(t, err) + keyS, err = cstore.List() + require.NoError(t, err) + assert.Equal(t, 1, len(keyS)) + _, err = cstore.Get(n1) + assert.Error(t, err) + + // create an offline key + o1 := "offline" + priv1 := crypto.GenPrivKeyEd25519() + pub1 := priv1.PubKey() + i, err = cstore.CreateOffline(o1, pub1) + require.Nil(t, err) + require.Equal(t, pub1, i.GetPubKey()) + require.Equal(t, o1, i.GetName()) + keyS, err = cstore.List() + require.NoError(t, err) + require.Equal(t, 2, len(keyS)) + + // delete the offline key + err = cstore.Delete(o1, "no") + require.NotNil(t, err) + err = cstore.Delete(o1, "yes") + require.NoError(t, err) + keyS, err = cstore.List() + require.NoError(t, err) + require.Equal(t, 1, len(keyS)) +} + +// TestSignVerify does some detailed checks on how we sign and validate +// signatures +func TestSignVerify(t *testing.T) { + cstore := New( + dbm.NewMemDB(), + ) + algo := Secp256k1 + + n1, n2, n3 := "some dude", "a dudette", "dude-ish" + p1, p2, p3 := "1234", "foobar", "foobar" + + // create two users and get their info + i1, _, err := cstore.CreateMnemonic(n1, English, p1, algo) + require.Nil(t, err) + + i2, _, err := cstore.CreateMnemonic(n2, English, p2, algo) + require.Nil(t, err) + + // Import a public key + armor, err := cstore.ExportPubKey(n2) + require.Nil(t, err) + cstore.ImportPubKey(n3, armor) + i3, err := cstore.Get(n3) + require.NoError(t, err) + require.Equal(t, i3.GetName(), n3) + + // let's try to sign some messages + d1 := []byte("my first message") + d2 := []byte("some other important info!") + d3 := []byte("feels like I forgot something...") + + // try signing both data with both .. + s11, pub1, err := cstore.Sign(n1, p1, d1) + require.Nil(t, err) + require.Equal(t, i1.GetPubKey(), pub1) + + s12, pub1, err := cstore.Sign(n1, p1, d2) + require.Nil(t, err) + require.Equal(t, i1.GetPubKey(), pub1) + + s21, pub2, err := cstore.Sign(n2, p2, d1) + require.Nil(t, err) + require.Equal(t, i2.GetPubKey(), pub2) + + s22, pub2, err := cstore.Sign(n2, p2, d2) + require.Nil(t, err) + require.Equal(t, i2.GetPubKey(), pub2) + + // let's try to validate and make sure it only works when everything is proper + cases := []struct { + key crypto.PubKey + data []byte + sig crypto.Signature + valid bool + }{ + // proper matches + {i1.GetPubKey(), d1, s11, true}, + // change data, pubkey, or signature leads to fail + {i1.GetPubKey(), d2, s11, false}, + {i2.GetPubKey(), d1, s11, false}, + {i1.GetPubKey(), d1, s21, false}, + // make sure other successes + {i1.GetPubKey(), d2, s12, true}, + {i2.GetPubKey(), d1, s21, true}, + {i2.GetPubKey(), d2, s22, true}, + } + + for i, tc := range cases { + valid := tc.key.VerifyBytes(tc.data, tc.sig) + assert.Equal(t, tc.valid, valid, "%d", i) + } + + // Now try to sign data with a secret-less key + _, _, err = cstore.Sign(n3, p3, d3) + assert.NotNil(t, err) +} + +func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) { + err := cstore.Update(name, badpass, pass) + assert.NotNil(t, err) + err = cstore.Update(name, pass, pass) + assert.Nil(t, err, "%+v", err) +} + +// TestExportImport tests exporting and importing +func TestExportImport(t *testing.T) { + + // make the storage with reasonable defaults + db := dbm.NewMemDB() + cstore := New( + db, + ) + + info, _, err := cstore.CreateMnemonic("john", English, "secretcpw", Secp256k1) + assert.NoError(t, err) + assert.Equal(t, info.GetName(), "john") + + john, err := cstore.Get("john") + assert.NoError(t, err) + assert.Equal(t, info.GetName(), "john") + johnAddr := info.GetPubKey().Address() + + armor, err := cstore.Export("john") + assert.NoError(t, err) + + err = cstore.Import("john2", armor) + assert.NoError(t, err) + + john2, err := cstore.Get("john2") + assert.NoError(t, err) + + assert.Equal(t, john.GetPubKey().Address(), johnAddr) + assert.Equal(t, john.GetName(), "john") + assert.Equal(t, john, john2) +} + +// +func TestExportImportPubKey(t *testing.T) { + // make the storage with reasonable defaults + db := dbm.NewMemDB() + cstore := New( + db, + ) + + // CreateMnemonic a private-public key pair and ensure consistency + notPasswd := "n9y25ah7" + info, _, err := cstore.CreateMnemonic("john", English, notPasswd, Secp256k1) + assert.Nil(t, err) + assert.NotEqual(t, info, "") + assert.Equal(t, info.GetName(), "john") + addr := info.GetPubKey().Address() + john, err := cstore.Get("john") + assert.NoError(t, err) + assert.Equal(t, john.GetName(), "john") + assert.Equal(t, john.GetPubKey().Address(), addr) + + // Export the public key only + armor, err := cstore.ExportPubKey("john") + assert.NoError(t, err) + // Import it under a different name + err = cstore.ImportPubKey("john-pubkey-only", armor) + assert.NoError(t, err) + // Ensure consistency + john2, err := cstore.Get("john-pubkey-only") + assert.NoError(t, err) + // Compare the public keys + assert.True(t, john.GetPubKey().Equals(john2.GetPubKey())) + // Ensure the original key hasn't changed + john, err = cstore.Get("john") + assert.NoError(t, err) + assert.Equal(t, john.GetPubKey().Address(), addr) + assert.Equal(t, john.GetName(), "john") + + // Ensure keys cannot be overwritten + err = cstore.ImportPubKey("john-pubkey-only", armor) + assert.NotNil(t, err) +} + +// TestAdvancedKeyManagement verifies update, import, export functionality +func TestAdvancedKeyManagement(t *testing.T) { + + // make the storage with reasonable defaults + cstore := New( + dbm.NewMemDB(), + ) + + algo := Secp256k1 + n1, n2 := "old-name", "new name" + p1, p2 := "1234", "foobar" + + // make sure key works with initial password + _, _, err := cstore.CreateMnemonic(n1, English, p1, algo) + require.Nil(t, err, "%+v", err) + assertPassword(t, cstore, n1, p1, p2) + + // update password requires the existing password + err = cstore.Update(n1, "jkkgkg", p2) + assert.NotNil(t, err) + assertPassword(t, cstore, n1, p1, p2) + + // then it changes the password when correct + err = cstore.Update(n1, p1, p2) + assert.NoError(t, err) + // p2 is now the proper one! + assertPassword(t, cstore, n1, p2, p1) + + // exporting requires the proper name and passphrase + _, err = cstore.Export(n1 + ".notreal") + assert.NotNil(t, err) + _, err = cstore.Export(" " + n1) + assert.NotNil(t, err) + _, err = cstore.Export(n1 + " ") + assert.NotNil(t, err) + _, err = cstore.Export("") + assert.NotNil(t, err) + exported, err := cstore.Export(n1) + require.Nil(t, err, "%+v", err) + + // import succeeds + err = cstore.Import(n2, exported) + assert.NoError(t, err) + + // second import fails + err = cstore.Import(n2, exported) + assert.NotNil(t, err) +} + +// TestSeedPhrase verifies restoring from a seed phrase +func TestSeedPhrase(t *testing.T) { + + // make the storage with reasonable defaults + cstore := New( + dbm.NewMemDB(), + ) + + algo := Secp256k1 + n1, n2 := "lost-key", "found-again" + p1, p2 := "1234", "foobar" + + // make sure key works with initial password + info, mnemonic, err := cstore.CreateMnemonic(n1, English, p1, algo) + require.Nil(t, err, "%+v", err) + assert.Equal(t, n1, info.GetName()) + assert.NotEmpty(t, mnemonic) + + // now, let us delete this key + err = cstore.Delete(n1, p1) + require.Nil(t, err, "%+v", err) + _, err = cstore.Get(n1) + require.NotNil(t, err) + + // let us re-create it from the mnemonic-phrase + params := *hd.NewFundraiserParams(0, 0) + newInfo, err := cstore.Derive(n2, mnemonic, p2, params) + require.NoError(t, err) + assert.Equal(t, n2, newInfo.GetName()) + assert.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) + assert.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) +} + +func ExampleNew() { + // Select the encryption and storage for your cryptostore + cstore := New( + dbm.NewMemDB(), + ) + + sec := Secp256k1 + + // Add keys and see they return in alphabetical order + bob, _, err := cstore.CreateMnemonic("Bob", English, "friend", sec) + if err != nil { + // this should never happen + fmt.Println(err) + } else { + // return info here just like in List + fmt.Println(bob.GetName()) + } + cstore.CreateMnemonic("Alice", English, "secret", sec) + cstore.CreateMnemonic("Carl", English, "mitm", sec) + info, _ := cstore.List() + for _, i := range info { + fmt.Println(i.GetName()) + } + + // We need to use passphrase to generate a signature + tx := []byte("deadbeef") + sig, pub, err := cstore.Sign("Bob", "friend", tx) + if err != nil { + fmt.Println("don't accept real passphrase") + } + + // and we can validate the signature with publicly available info + binfo, _ := cstore.Get("Bob") + if !binfo.GetPubKey().Equals(bob.GetPubKey()) { + fmt.Println("Get and Create return different keys") + } + + if pub.Equals(binfo.GetPubKey()) { + fmt.Println("signed by Bob") + } + if !pub.VerifyBytes(tx, sig) { + fmt.Println("invalid signature") + } + + // Output: + // Bob + // Alice + // Bob + // Carl + // signed by Bob +} diff --git a/crypto/keys/keys.go b/crypto/keys/keys.go new file mode 100644 index 0000000000..58a58a95be --- /dev/null +++ b/crypto/keys/keys.go @@ -0,0 +1,12 @@ +package keys + +// SigningAlgo defines an algorithm to derive key-pairs which can be used for cryptographic signing. +type SigningAlgo string + +const ( + // Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters. + Secp256k1 = SigningAlgo("secp256k1") + // Ed25519 represents the Ed25519 signature system. + // It is currently not supported for end-user keys (wallets/ledgers). + Ed25519 = SigningAlgo("ed25519") +) diff --git a/crypto/keys/keys.toml b/crypto/keys/keys.toml new file mode 100644 index 0000000000..f9eb95e1c9 --- /dev/null +++ b/crypto/keys/keys.toml @@ -0,0 +1,2 @@ +output = "text" +keydir = ".mykeys" diff --git a/crypto/keys/mintkey.go b/crypto/keys/mintkey.go new file mode 100644 index 0000000000..9ec0d10458 --- /dev/null +++ b/crypto/keys/mintkey.go @@ -0,0 +1,115 @@ +package keys + +import ( + "encoding/hex" + "fmt" + + cmn "github.com/tendermint/tmlibs/common" + + "github.com/cosmos/cosmos-sdk/crypto/keys/bcrypt" + "github.com/tendermint/tendermint/crypto" +) + +const ( + blockTypePrivKey = "TENDERMINT PRIVATE KEY" + blockTypeKeyInfo = "TENDERMINT KEY INFO" + blockTypePubKey = "TENDERMINT PUBLIC KEY" +) + +func armorInfoBytes(bz []byte) string { + return armorBytes(bz, blockTypeKeyInfo) +} + +func armorPubKeyBytes(bz []byte) string { + return armorBytes(bz, blockTypePubKey) +} + +func armorBytes(bz []byte, blockType string) string { + header := map[string]string{ + "type": "Info", + "version": "0.0.0", + } + return crypto.EncodeArmor(blockType, header, bz) +} + +func unarmorInfoBytes(armorStr string) (bz []byte, err error) { + return unarmorBytes(armorStr, blockTypeKeyInfo) +} + +func unarmorPubKeyBytes(armorStr string) (bz []byte, err error) { + return unarmorBytes(armorStr, blockTypePubKey) +} + +func unarmorBytes(armorStr, blockType string) (bz []byte, err error) { + bType, header, bz, err := crypto.DecodeArmor(armorStr) + if err != nil { + return + } + if bType != blockType { + err = fmt.Errorf("Unrecognized armor type %q, expected: %q", bType, blockType) + return + } + if header["version"] != "0.0.0" { + err = fmt.Errorf("Unrecognized version: %v", header["version"]) + return + } + return +} + +func encryptArmorPrivKey(privKey crypto.PrivKey, passphrase string) string { + saltBytes, encBytes := encryptPrivKey(privKey, passphrase) + header := map[string]string{ + "kdf": "bcrypt", + "salt": fmt.Sprintf("%X", saltBytes), + } + armorStr := crypto.EncodeArmor(blockTypePrivKey, header, encBytes) + return armorStr +} + +func unarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey, error) { + var privKey crypto.PrivKey + blockType, header, encBytes, err := crypto.DecodeArmor(armorStr) + if err != nil { + return privKey, err + } + if blockType != blockTypePrivKey { + return privKey, fmt.Errorf("Unrecognized armor type: %v", blockType) + } + if header["kdf"] != "bcrypt" { + return privKey, fmt.Errorf("Unrecognized KDF type: %v", header["KDF"]) + } + if header["salt"] == "" { + return privKey, fmt.Errorf("Missing salt bytes") + } + saltBytes, err := hex.DecodeString(header["salt"]) + if err != nil { + return privKey, fmt.Errorf("Error decoding salt: %v", err.Error()) + } + privKey, err = decryptPrivKey(saltBytes, encBytes, passphrase) + return privKey, err +} + +func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) { + saltBytes = crypto.CRandBytes(16) + key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016) + if err != nil { + cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error()) + } + key = crypto.Sha256(key) // Get 32 bytes + privKeyBytes := privKey.Bytes() + return saltBytes, crypto.EncryptSymmetric(privKeyBytes, key) +} + +func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) { + key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016) + if err != nil { + cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error()) + } + key = crypto.Sha256(key) // Get 32 bytes + privKeyBytes, err := crypto.DecryptSymmetric(encBytes, key) + if err != nil { + return privKey, err + } + privKey, err = crypto.PrivKeyFromBytes(privKeyBytes) + return privKey, err +} diff --git a/crypto/keys/types.go b/crypto/keys/types.go new file mode 100644 index 0000000000..e143ed63d0 --- /dev/null +++ b/crypto/keys/types.go @@ -0,0 +1,144 @@ +package keys + +import ( + ccrypto "github.com/cosmos/cosmos-sdk/crypto" + "github.com/tendermint/tendermint/crypto" + + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" +) + +// Keybase exposes operations on a generic keystore +type Keybase interface { + + // CRUD on the keystore + List() ([]Info, error) + Get(name string) (Info, error) + Delete(name, passphrase string) error + + // Sign some bytes, looking up the private key to use + Sign(name, passphrase string, msg []byte) (crypto.Signature, crypto.PubKey, error) + + // CreateMnemonic creates a new mnemonic, and derives a hierarchical deterministic + // key from that. + CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) + // CreateFundraiserKey takes a mnemonic and derives, a password + CreateFundraiserKey(name, mnemonic, passwd string) (info Info, err error) + // Derive derives a key from the passed mnemonic using a BIP44 path. + Derive(name, mnemonic, passwd string, params hd.BIP44Params) (Info, error) + // Create, store, and return a new Ledger key reference + CreateLedger(name string, path ccrypto.DerivationPath, algo SigningAlgo) (info Info, err error) + + // Create, store, and return a new offline key reference + CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) + + // The following operations will *only* work on locally-stored keys + Update(name, oldpass, newpass string) error + Import(name string, armor string) (err error) + ImportPubKey(name string, armor string) (err error) + Export(name string) (armor string, err error) + ExportPubKey(name string) (armor string, err error) +} + +// Info is the publicly exposed information about a keypair +type Info interface { + // Human-readable type for key listing + GetType() string + // Name of the key + GetName() string + // Public key + GetPubKey() crypto.PubKey +} + +var _ Info = &localInfo{} +var _ Info = &ledgerInfo{} +var _ Info = &offlineInfo{} + +// localInfo is the public information about a locally stored key +type localInfo struct { + Name string `json:"name"` + PubKey crypto.PubKey `json:"pubkey"` + PrivKeyArmor string `json:"privkey.armor"` +} + +func newLocalInfo(name string, pub crypto.PubKey, privArmor string) Info { + return &localInfo{ + Name: name, + PubKey: pub, + PrivKeyArmor: privArmor, + } +} + +func (i localInfo) GetType() string { + return "local" +} + +func (i localInfo) GetName() string { + return i.Name +} + +func (i localInfo) GetPubKey() crypto.PubKey { + return i.PubKey +} + +// ledgerInfo is the public information about a Ledger key +type ledgerInfo struct { + Name string `json:"name"` + PubKey crypto.PubKey `json:"pubkey"` + Path ccrypto.DerivationPath `json:"path"` +} + +func newLedgerInfo(name string, pub crypto.PubKey, path ccrypto.DerivationPath) Info { + return &ledgerInfo{ + Name: name, + PubKey: pub, + Path: path, + } +} + +func (i ledgerInfo) GetType() string { + return "ledger" +} + +func (i ledgerInfo) GetName() string { + return i.Name +} + +func (i ledgerInfo) GetPubKey() crypto.PubKey { + return i.PubKey +} + +// offlineInfo is the public information about an offline key +type offlineInfo struct { + Name string `json:"name"` + PubKey crypto.PubKey `json:"pubkey"` +} + +func newOfflineInfo(name string, pub crypto.PubKey) Info { + return &offlineInfo{ + Name: name, + PubKey: pub, + } +} + +func (i offlineInfo) GetType() string { + return "offline" +} + +func (i offlineInfo) GetName() string { + return i.Name +} + +func (i offlineInfo) GetPubKey() crypto.PubKey { + return i.PubKey +} + +// encoding info +func writeInfo(i Info) []byte { + return cdc.MustMarshalBinary(i) +} + +// decoding info +func readInfo(bz []byte) (info Info, err error) { + err = cdc.UnmarshalBinary(bz, &info) + return +} diff --git a/crypto/keys/wire.go b/crypto/keys/wire.go new file mode 100644 index 0000000000..18e8e0f17f --- /dev/null +++ b/crypto/keys/wire.go @@ -0,0 +1,19 @@ +package keys + +import ( + ccrypto "github.com/cosmos/cosmos-sdk/crypto" + amino "github.com/tendermint/go-amino" + tcrypto "github.com/tendermint/tendermint/crypto" +) + +var cdc = amino.NewCodec() + +func init() { + tcrypto.RegisterAmino(cdc) + cdc.RegisterInterface((*Info)(nil), nil) + cdc.RegisterConcrete(ccrypto.PrivKeyLedgerSecp256k1{}, + "tendermint/PrivKeyLedgerSecp256k1", nil) + cdc.RegisterConcrete(localInfo{}, "crypto/keys/localInfo", nil) + cdc.RegisterConcrete(ledgerInfo{}, "crypto/keys/ledgerInfo", nil) + cdc.RegisterConcrete(offlineInfo{}, "crypto/keys/offlineInfo", nil) +} diff --git a/crypto/ledger_common.go b/crypto/ledger_common.go new file mode 100644 index 0000000000..39f15464a7 --- /dev/null +++ b/crypto/ledger_common.go @@ -0,0 +1,19 @@ +package crypto + +import ( + ledger "github.com/zondax/ledger-goclient" +) + +var device *ledger.Ledger + +// Ledger derivation path +type DerivationPath = []uint32 + +// getLedger gets a copy of the device, and caches it +func getLedger() (*ledger.Ledger, error) { + var err error + if device == nil { + device, err = ledger.FindLedger() + } + return device, err +} diff --git a/crypto/ledger_secp256k1.go b/crypto/ledger_secp256k1.go new file mode 100644 index 0000000000..1ba36f69df --- /dev/null +++ b/crypto/ledger_secp256k1.go @@ -0,0 +1,126 @@ +package crypto + +import ( + "fmt" + + secp256k1 "github.com/btcsuite/btcd/btcec" + ledger "github.com/zondax/ledger-goclient" + + tcrypto "github.com/tendermint/tendermint/crypto" +) + +func pubkeyLedgerSecp256k1(device *ledger.Ledger, path DerivationPath) (pub tcrypto.PubKey, err error) { + key, err := device.GetPublicKeySECP256K1(path) + if err != nil { + return nil, fmt.Errorf("error fetching public key: %v", err) + } + var p tcrypto.PubKeySecp256k1 + // Reserialize in the 33-byte compressed format + cmp, err := secp256k1.ParsePubKey(key[:], secp256k1.S256()) + copy(p[:], cmp.SerializeCompressed()) + pub = p + return +} + +func signLedgerSecp256k1(device *ledger.Ledger, path DerivationPath, msg []byte) (sig tcrypto.Signature, err error) { + bsig, err := device.SignSECP256K1(path, msg) + if err != nil { + return sig, err + } + sig = tcrypto.SignatureSecp256k1FromBytes(bsig) + return +} + +// PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano +// we cache the PubKey from the first call to use it later +type PrivKeyLedgerSecp256k1 struct { + // PubKey should be private, but we want to encode it via go-amino + // so we can view the address later, even without having the ledger + // attached + CachedPubKey tcrypto.PubKey + Path DerivationPath +} + +// NewPrivKeyLedgerSecp256k1 will generate a new key and store the +// public key for later use. +func NewPrivKeyLedgerSecp256k1(path DerivationPath) (tcrypto.PrivKey, error) { + var pk PrivKeyLedgerSecp256k1 + pk.Path = path + // cache the pubkey for later use + pubKey, err := pk.getPubKey() + if err != nil { + return nil, err + } + pk.CachedPubKey = pubKey + return &pk, err +} + +// ValidateKey allows us to verify the sanity of a key +// after loading it from disk +func (pk PrivKeyLedgerSecp256k1) ValidateKey() error { + // getPubKey will return an error if the ledger is not + pub, err := pk.getPubKey() + if err != nil { + return err + } + // verify this matches cached address + if !pub.Equals(pk.CachedPubKey) { + return fmt.Errorf("cached key does not match retrieved key") + } + return nil +} + +// AssertIsPrivKeyInner fulfils PrivKey Interface +func (pk *PrivKeyLedgerSecp256k1) AssertIsPrivKeyInner() {} + +// Bytes fulfils PrivKey Interface - but it stores the cached pubkey so we can verify +// the same key when we reconnect to a ledger +func (pk PrivKeyLedgerSecp256k1) Bytes() []byte { + return cdc.MustMarshalBinaryBare(pk) +} + +// Sign calls the ledger and stores the PubKey for future use +// +// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, +// returning an error, so this should only trigger if the privkey is held +// in memory for a while before use. +func (pk PrivKeyLedgerSecp256k1) Sign(msg []byte) (tcrypto.Signature, error) { + dev, err := getLedger() + if err != nil { + return nil, err + } + sig, err := signLedgerSecp256k1(dev, pk.Path, msg) + if err != nil { + return nil, err + } + return sig, nil +} + +// PubKey returns the stored PubKey +func (pk PrivKeyLedgerSecp256k1) PubKey() tcrypto.PubKey { + return pk.CachedPubKey +} + +// getPubKey reads the pubkey the ledger itself +// since this involves IO, it may return an error, which is not exposed +// in the PubKey interface, so this function allows better error handling +func (pk PrivKeyLedgerSecp256k1) getPubKey() (key tcrypto.PubKey, err error) { + dev, err := getLedger() + if err != nil { + return key, fmt.Errorf("cannot connect to Ledger device - error: %v", err) + } + key, err = pubkeyLedgerSecp256k1(dev, pk.Path) + if err != nil { + return key, fmt.Errorf("please open Cosmos app on the Ledger device - error: %v", err) + } + return key, err +} + +// Equals fulfils PrivKey Interface - makes sure both keys refer to the +// same +func (pk PrivKeyLedgerSecp256k1) Equals(other tcrypto.PrivKey) bool { + if ledger, ok := other.(*PrivKeyLedgerSecp256k1); ok { + return pk.CachedPubKey.Equals(ledger.CachedPubKey) + } + return false +} diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go new file mode 100644 index 0000000000..072d846473 --- /dev/null +++ b/crypto/ledger_test.go @@ -0,0 +1,65 @@ +package crypto + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + tcrypto "github.com/tendermint/tendermint/crypto" +) + +func TestRealLedgerSecp256k1(t *testing.T) { + + if os.Getenv("WITH_LEDGER") == "" { + t.Skip("Set WITH_LEDGER to run code on real ledger") + } + msg := []byte("kuhehfeohg") + + path := DerivationPath{44, 60, 0, 0, 0} + + priv, err := NewPrivKeyLedgerSecp256k1(path) + require.Nil(t, err, "%+v", err) + pub := priv.PubKey() + sig, err := priv.Sign(msg) + require.Nil(t, err) + + valid := pub.VerifyBytes(msg, sig) + assert.True(t, valid) + + // now, let's serialize the key and make sure it still works + bs := priv.Bytes() + priv2, err := tcrypto.PrivKeyFromBytes(bs) + require.Nil(t, err, "%+v", err) + + // make sure we get the same pubkey when we load from disk + pub2 := priv2.PubKey() + require.Equal(t, pub, pub2) + + // signing with the loaded key should match the original pubkey + sig, err = priv2.Sign(msg) + require.Nil(t, err) + valid = pub.VerifyBytes(msg, sig) + assert.True(t, valid) + + // make sure pubkeys serialize properly as well + bs = pub.Bytes() + bpub, err := tcrypto.PubKeyFromBytes(bs) + require.NoError(t, err) + assert.Equal(t, pub, bpub) +} + +// TestRealLedgerErrorHandling calls. These tests assume +// the ledger is not plugged in.... +func TestRealLedgerErrorHandling(t *testing.T) { + if os.Getenv("WITH_LEDGER") != "" { + t.Skip("Skipping on WITH_LEDGER as it tests unplugged cases") + } + + // first, try to generate a key, must return an error + // (no panic) + path := DerivationPath{44, 60, 0, 0, 0} + _, err := NewPrivKeyLedgerSecp256k1(path) + require.Error(t, err) +} diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index dea4f26a28..de29a1316b 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -3,7 +3,7 @@ package app import ( "encoding/json" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 81ed40f21a..539a52c731 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -1,7 +1,6 @@ package app import ( - "encoding/json" "fmt" "os" "testing" @@ -16,8 +15,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake" gen "github.com/cosmos/cosmos-sdk/x/stake/types" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" ) @@ -76,7 +75,7 @@ func TestGenesis(t *testing.T) { bapp = NewBasecoinApp(logger, db) // Initialize stake data with default genesis state stakedata := gen.DefaultGenesisState() - genState, err := json.Marshal(stakedata) + genState, err := bapp.cdc.MarshalJSON(stakedata) if err != nil { panic(err) } diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 3665aedba4..f3f3de519a 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -6,7 +6,7 @@ import ( "github.com/spf13/cobra" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index dc7c3c9d8e..a87dc15e44 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -3,7 +3,7 @@ package app import ( "encoding/json" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index a75eee0f38..d67e4f7064 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -1,7 +1,6 @@ package app import ( - "encoding/json" "os" "testing" @@ -9,15 +8,41 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/examples/democoin/types" + "github.com/cosmos/cosmos-sdk/examples/democoin/x/cool" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" ) +func setGenesis(bapp *DemocoinApp, trend string, accs ...auth.BaseAccount) error { + genaccs := make([]*types.GenesisAccount, len(accs)) + for i, acc := range accs { + genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, "foobart"}) + } + + genesisState := types.GenesisState{ + Accounts: genaccs, + CoolGenesis: cool.Genesis{trend}, + } + + stateBytes, err := wire.MarshalJSONIndent(bapp.cdc, genesisState) + if err != nil { + return err + } + + // Initialize the chain + vals := []abci.Validator{} + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) + bapp.Commit() + + return nil +} + func TestGenesis(t *testing.T) { logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") db := dbm.NewMemDB() @@ -34,21 +59,8 @@ func TestGenesis(t *testing.T) { } acc := &types.AppAccount{baseAcc, "foobart"} - genesisState := map[string]interface{}{ - "accounts": []*types.GenesisAccount{ - types.NewGenesisAccount(acc), - }, - "cool": map[string]string{ - "trend": "ice-cold", - }, - } - stateBytes, err := json.MarshalIndent(genesisState, "", "\t") + err = setGenesis(bapp, "ice-cold", baseAcc) require.Nil(t, err) - - vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) - bapp.Commit() - // A checkTx context ctx := bapp.BaseApp.NewContext(true, abci.Header{}) res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address) diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 58b9af06a7..92f9618b04 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -6,7 +6,7 @@ import ( "github.com/spf13/cobra" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" diff --git a/examples/democoin/mock/validator.go b/examples/democoin/mock/validator.go index 29cdd8b165..869c48dcb6 100644 --- a/examples/democoin/mock/validator.go +++ b/examples/democoin/mock/validator.go @@ -4,7 +4,7 @@ import ( "bytes" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) // Validator implements sdk.Validator diff --git a/examples/democoin/x/assoc/validator_set_test.go b/examples/democoin/x/assoc/validator_set_test.go index 014f5650c6..289604149b 100644 --- a/examples/democoin/x/assoc/validator_set_test.go +++ b/examples/democoin/x/assoc/validator_set_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/cosmos/cosmos-sdk/examples/democoin/mock" diff --git a/examples/democoin/x/cool/app_test.go b/examples/democoin/x/cool/app_test.go index 5ac7a55a1c..efcc6c1bf2 100644 --- a/examples/democoin/x/cool/app_test.go +++ b/examples/democoin/x/cool/app_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -16,8 +16,9 @@ import ( ) var ( - priv1 = crypto.GenPrivKeyEd25519() - addr1 = priv1.PubKey().Address() + priv1 = crypto.GenPrivKeyEd25519() + pubKey = priv1.PubKey() + addr1 = pubKey.Address() quizMsg1 = MsgQuiz{ Sender: addr1, diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index 9aca3cc2a0..3dfad91f13 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/cosmos/cosmos-sdk/store" diff --git a/examples/democoin/x/cool/types.go b/examples/democoin/x/cool/types.go index b8640b2110..77f49a0ba3 100644 --- a/examples/democoin/x/cool/types.go +++ b/examples/democoin/x/cool/types.go @@ -41,13 +41,13 @@ func (msg MsgSetTrend) String() string { // Validate Basic is used to quickly disqualify obviously invalid messages quickly func (msg MsgSetTrend) ValidateBasic() sdk.Error { if len(msg.Sender) == 0 { - return sdk.ErrUnknownAddress(msg.Sender.String()).Trace("") + return sdk.ErrUnknownAddress(msg.Sender.String()).TraceSDK("") } if strings.Contains(msg.Cool, "hot") { - return sdk.ErrUnauthorized("").Trace("hot is not cool") + return sdk.ErrUnauthorized("").TraceSDK("hot is not cool") } if strings.Contains(msg.Cool, "warm") { - return sdk.ErrUnauthorized("").Trace("warm is not very cool") + return sdk.ErrUnauthorized("").TraceSDK("warm is not very cool") } return nil } @@ -91,7 +91,7 @@ func (msg MsgQuiz) String() string { // Validate Basic is used to quickly disqualify obviously invalid messages quickly func (msg MsgQuiz) ValidateBasic() sdk.Error { if len(msg.Sender) == 0 { - return sdk.ErrUnknownAddress(msg.Sender.String()).Trace("") + return sdk.ErrUnknownAddress(msg.Sender.String()).TraceSDK("") } return nil } diff --git a/examples/democoin/x/oracle/oracle_test.go b/examples/democoin/x/oracle/oracle_test.go index 1cd73b1c1c..01885e0d5e 100644 --- a/examples/democoin/x/oracle/oracle_test.go +++ b/examples/democoin/x/oracle/oracle_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/cosmos/cosmos-sdk/examples/democoin/mock" @@ -89,7 +89,7 @@ func handleSeqOracle(ctx sdk.Context, key sdk.StoreKey, o seqOracle) sdk.Error { seq := getSequence(ctx, key) if seq != o.Seq { - return sdk.NewError(sdk.CodespaceUndefined, 1, "") + return sdk.NewError(sdk.CodespaceRoot, 1, "") } bz := wire.NewCodec().MustMarshalBinary(seq + 1) @@ -119,7 +119,7 @@ func TestOracle(t *testing.T) { ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz}) ork := NewKeeper(sdk.NewPrefixStoreGetter(key, []byte("oracle")), cdc, valset, sdk.NewRat(2, 3), 100) - h := seqHandler(ork, key, sdk.CodespaceUndefined) + h := seqHandler(ork, key, sdk.CodespaceRoot) // Nonmock.Validator signed, transaction failed msg := Msg{seqOracle{0, 0}, []byte("randomguy")} diff --git a/examples/democoin/x/pow/app_test.go b/examples/democoin/x/pow/app_test.go index e8e3ed12f6..6dab193886 100644 --- a/examples/democoin/x/pow/app_test.go +++ b/examples/democoin/x/pow/app_test.go @@ -11,8 +11,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/bank" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" ) var ( diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index fe33d7e1d3..5aaba48bbb 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tmlibs/log" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index 16a0d4e7c4..53c3e83b4b 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/examples/democoin/x/pow/mine.go b/examples/democoin/x/pow/mine.go index 21d389a1d4..b4b536a525 100644 --- a/examples/democoin/x/pow/mine.go +++ b/examples/democoin/x/pow/mine.go @@ -6,7 +6,7 @@ import ( "strconv" sdk "github.com/cosmos/cosmos-sdk/types" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) // generate the mine message diff --git a/examples/democoin/x/pow/types.go b/examples/democoin/x/pow/types.go index 039f57d446..cd77a68af5 100644 --- a/examples/democoin/x/pow/types.go +++ b/examples/democoin/x/pow/types.go @@ -8,7 +8,7 @@ import ( "math" "strconv" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/examples/democoin/x/simplestake/client/cli/commands.go b/examples/democoin/x/simplestake/client/cli/commands.go index 895384454d..fcd0c84b45 100644 --- a/examples/democoin/x/simplestake/client/cli/commands.go +++ b/examples/democoin/x/simplestake/client/cli/commands.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/examples/democoin/x/simplestake/keeper.go b/examples/democoin/x/simplestake/keeper.go index c75ccff07b..122b44bfed 100644 --- a/examples/democoin/x/simplestake/keeper.go +++ b/examples/democoin/x/simplestake/keeper.go @@ -1,7 +1,7 @@ package simplestake import ( - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index 9315a7ccf6..9cb02afd7d 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/examples/democoin/x/simplestake/msgs.go b/examples/democoin/x/simplestake/msgs.go index 605f6f4e23..564e0d9796 100644 --- a/examples/democoin/x/simplestake/msgs.go +++ b/examples/democoin/x/simplestake/msgs.go @@ -3,7 +3,7 @@ package simplestake import ( "encoding/json" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/examples/democoin/x/simplestake/msgs_test.go b/examples/democoin/x/simplestake/msgs_test.go index 55d98a9fdf..188a4ec3a8 100644 --- a/examples/democoin/x/simplestake/msgs_test.go +++ b/examples/democoin/x/simplestake/msgs_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/examples/democoin/x/simplestake/types.go b/examples/democoin/x/simplestake/types.go index 3371fc977f..937d36d650 100644 --- a/examples/democoin/x/simplestake/types.go +++ b/examples/democoin/x/simplestake/types.go @@ -1,6 +1,6 @@ package simplestake -import crypto "github.com/tendermint/go-crypto" +import "github.com/tendermint/tendermint/crypto" type bondInfo struct { PubKey crypto.PubKey diff --git a/examples/kvstore/kvstore b/examples/kvstore/kvstore index 76da38d402cdeb4ba3b9fb1d552f777eb45fa614..43c7dc61c4edc75e557360b14ad97b03036c2a63 100755 GIT binary patch delta 44016 zcmaJ~cX*V=^M4LVyX4Z7%cavhgiutZsi1%~u@{OBD_}1uf_jLG6bq~(Fjx_hqFjj5 zf(;d=s9ymk2nfUip`#-0H#@WYzPs<;^ZR4(x%tfOY_IRU^S<)g!K7nn4<(Hc`@(g? zb;I?-apCxILO3y;6!wRc!ztlFI5nIWP7h~~KyvHyjM-g+t-|a6z~*Tof)2 zmxN2h^}`Lq4a1GXjl)gCO~cK?&BHCiEyJzCt;21?ZNp{ZcH#1H`*4SF$8e|cIpK4| z=Y>0m&kuJAcMW$7cMtanUl6`9d{MY(xL5e%@Fn5i;XdKM;Y-8)!u`Vo!UMyD!k2{y zhc6Fb5xz2fRru=gHQ{T+*M+YS-w+-W9vU7N8NTXvF}Lk^$(5^aAHFl5{))*(70DCd z8$BGujTmmia5IKmFx-k^1cuu%+>YT640mF<3&Y(QMq(I+VKjz&Fx-pbJ`DF`cmTtL z7#_m#Fos7kJc?lqhQ}~Gj$tf@Coqh|FdoB`7@orLG=?yS2^gNiFcHJE7@ouMJcdaa zUcfLJ!xRitF-*hoB8HbRyo})$4AU{pz#uTZis3a3Gcml5VHSqj80KIA40AEOf#FRI zZ((>F!#fz>#V`-Udl=?pcpt+83?E=vh+z?i#Tb@g_z=TKmG6ySdehTXw{ZHqkS_pb zndQC=(d_8bH=|Hk@_xt{FAf}CI?Lp3$}aciiiO9PE;Lcn17~u|eSY!O@uf?mcw*4s zOP5EZ&Hh>XQ4|Vu7lnKY;_N?57ew*I*Z462&mH!|LX`KSLL;ieH%PNe>ILlVq=tQ?!*1z+R| zSDHAYNu5a8#h~nPCtsZStWM-vF9=od$;!N=Zsa*)!N~l4Un!iqtK63&it9x_FwwM+ zL%vk8AwJSr6vahU3kS}Id^ymgU%4+wMo1U+;v;i7mdi>KYvLonF*@WNnL_vFAxvRI zf=+=@F*7l;(~P_6wsKzrOu1dFn*a3_gv8|5SeMvP+TSJW=9}0$w0;UR7*;frI~a#?CetR3yR}ukqK_BY%wK0VhogQ z(JjNK4|wP~nKpkwmQA0rX=wXJ$d@m^&W=1~qzX$AEfiyNRDYsjoh?#xEnSd?ISz>} zxvGbeR7l((jDV{vBwFT0<{31ke;)G;IkN(7+l8610+^BYI%D`BZPTm0I@ zs#-CnsZDolX43~e^ql54e?W`KD{h&y1=0!Pbc@JzF9_4x;>;lqC45v*9J&O{^;t{1 z(Pd01L!o3b;3b^H9&DvMXl+?JcAf0jkr}L%=`U;=5^l8hKi4Mmq#+Moe+i-Lwr%xb zky;vy9S%+P1H-q4a7CF~7J1ny0HMin5P6AW+ccbSuV|;{H14r1Ao9mYazuQ&n%Ybj zoI2Mj*r(+>V{Vc-N1ul?iMYLe!{-r zA9n1Jlek;q13Kx9F@NYzSs_%{N$2P+F{`A5oRmI1M^Czp4s0*WaLc)oXN+vX^3r@? zmMA>WM#rOuRI%|qUE8EVJla`jxqqi}UxBEZ7|9ivo*$XW3K^_DU-urOVaGXk!+z97 zcN~`Q-&Kz-NjDUMZo1=0x>zjfrt5|2JElg`#BJU6WWr!#kH|}$iG}+@zEV*zEs`WY zc^UiRrXD&vap1roa?))(Ad(^`Ul18Bz8j4lDbfI}%kGeSWHph49B+>Q~s~ZaxN)kI_fm3@&UN@t6 z>thXTSlmKxwEpR1>4SrZWe@sgRwPTT>}wAQV!_Tsb{8CVsqTW@^;v2dsiBV8yr1rf zu0V#^*iUyOMwc9u6YC@Wb(0w=q#c#bGw2;`p7RGp#u)fbK4a8Zm94 zy=cm~*<$b@wL?)0)qz1)H3_5>VdHU`g8}bj4nDlhDh~69|7};w&4aCMl8`tvSkJQ~ z>*f1`F!~?4m=%1wC`EjJxgIaX5e5Z82zwNw?)l^@m0td4WJ~3UgQFwKu=564 z#NMOzKz3MaGGZF;(M5Ln$#5nuU$0(c?$vWC^V9CrlNr-h9(wfsHoxQno8I_XcY$b~ z)v@r1)kG|LLXQtRa)~>~>Fo#8xY>Etl`l1SIDd`T4KfzbX${5XCv~^#=sX&H z-pfpQMz074>-zfnyrD@HJtpe;7xXe_pfGHN%=)d9 zb!8Yl5kDnH46!UGI%29NE7GRf!wcyYG3EkX#A>ElxfA1FjFyA}EmRv?!|mWpmMER~ zlf;sjBX1gmQla;}V$C-SEuF6WI~P>m7$k|UG0|x=Vrl3hVxfm(qH|x3B|GS~80d_d zF+i~-COZ6eT?oFf$e*Rpl}zJaO`Re5mSc4Le5?1tY&~k2e-QaK9VpFD`m1k|(}-*BXvu*gRVj=>QD4R$do&eotqbyT;-!`Myl? z=X-h2`y!T-o&~5MA+WVX@jZ-x_Jx%G3*1q zEpMG#?rS7+7wQ2g>0+4NBOeFy#)Ud@MoTZSn||^lUGu~jWs7xJV)>GQoT!d3wxwQO zqTA1vN)&@W)TrE32gJb-b)`6TvbdxYhkV6HdM;;9_occOl%$7-h^-0f3~^0`o{&|f z3N5t#L3!;5%X9@XjVY_+J<|tm8oFXEb921-V_of1zCiT?~fX+s|MPNR<8a&Q*F;6ARW1lD#c$wUrBn zR;|`$H)U_DiiM`FiPn$|O9o2q>(=No;p$0-ZkTd{xc5`5J}BjM5&X<50HMiZ`Df92 zPl47Uc>!_P=lY~$q#^uY=#7DiF883*E|*)K`@W2kOOd%&&x(OZbGrn=wG}1ln>U`XvcUc#i zq827X4O+!-{W=|Hd%c~ zg2r7!fP`T95Lp>ZzFCsM=gov4^pK)NME4)@I54-M9G8fBKR5-Z$pcyH#KZY1yGhpI zi68Z8%0%fb{KfzDG-|M*b%wps8ugP?Pcj)`wMm=xF4&D55Gyy^RU%~ru;50Skx^Tm zN_6yOi-ue6u1hh*7h7ZK5qJNr4w+&|o9Yyi`%7dGH84HPfkJ%ZQYad3i|}I@y7VoC zL$}CQ|71_3XhwBJJ%f^Gv_cquujFj2j%?&!!f5H!@)5C^)_Q&R?h+8yDC zRjMqTM&{$)%JMytO@=&d8kLV%PNe#Odn3z;MHK|AN6X{&tQrLxHIf30?~xPG*#nVm zfls8=m6}^I*~}X8hu$K)wUfoHj(^&*WbI^#gMaF6hK$e}7Txb8^V?r~0%KjWqH<;nbin1xlZg?RMMWdc2ru;2%|sveR>l@?Wud^k0>Eey&({LN$a#rd0lS zA~IfGIdq*7^rb;nU0g6LUpWOHZr@Ml)`sPDM&J~-^ zM$RWGeiXW7a?qDGy?MpY98=1qi%eg|AFifC*m$}fE?32MD%9ghslO0fpJ|7Ev9?ad zc2jnoPcCf->Q+Qdbok65%6?g|LJcq0kdCq;@l{;KQI_qG1#2#L$5(7I;)((36^WI< zCRDUCN?S;%Xp>ZN0gKAY&VeaYWHOVID!7P1sMwZN(aVq$9sLzOT)IF^^V{+}{kDAP zWSf2^*^Hk9m%bRp4a~7*TT9OrD{o?EN<~jM)f{;Ir65++$rLMA<)wj&-&JE%9aUoK z8*#yrI{7#p{b(JL{i1Gc@>%BkIahuI6>mTnzw>D)E~{Nc+x;+ zuStPJ*j3_1es%>v_XbuqD5oL-``-@YXj+|J5jJBX>m`#u-XZ|&XCcjYpU09(W z`(vf5$rt|>OdMKVfngbjN(>)k_yogp3@a*!7O$N09i>9HFQRDCI(#yevZ{wT)a6hq zV_g@nOYvfVELfLeU}!?)7nj!iHdX99u<|M~cg;#PP>|Tt{VQ)|^+XoeuDsbLCr+we ziD4Cn)flQUtikXphR-m3j^PUoUt(B`;VTSZS5B(^X0V!Vq_s{Z=A^INnUV$O)<{BN z5*cE}!gW{Mh2*PN&Ld_jwesgh>)yHC&6+o!&V8y#toto*<~Z{29llEw&j-I~I^)o~ zA!5mbt+|9x#LB?%9ftK7HelF@VH1Y$G5mnxM-2bN@Kfcb^)|1%m(qrjqdWP6l_d{t z9@?HWGj{&wcbu%Jh_d!aQbgzXH+Qo!znJp==01$!9Gol$Zr_zAk~%zHl`ilW+mu4-75Eq1o3i4*gemUYYN4mN4Au4XQ2WNjc6_wK1)o?tVt4&Rcz)Aa00;!Eg};T_jE#$ zk==Fsaw0!CGONz5DRL80)i8OPRzax@ORSC)`zR{vm+!k2t)UD@^NEwHNCV#>%iWUKWDd&&D=gKH5Vgi<2qBFAQr5&>e;tSi%>nM zJ#<5&_~jD2o>$m1qne-^=xxh9u-ekIarI`a&$X@Ed>7XNaB$8qr^_JDMSG`eTb4yA%z#R!OiEEwTEEj6b)iIf10F`*X{6u70usOAs6W z+@i)9#g+zNV(ecgMrK`?i3j#s$!yrSg|8sRs@g5N;(`5JRNpRoPTr;bxL+qt?54Gf z&C+8{5|;+FxMW821D4!4oBYWpTOQPDj(kbppFC;NdE)1TDi6T?)`x8Qrw?s$r^ifj zD5n}9V*T%EKT&pA6%}T0@8r8l{H$rYmn;zHAJNr=WTx18WD7qrklai$JPjwKrdv?W zj-$H9h*6qRQ%`g`X2sp$ul9?5Ha6|}7Jecl)@N1c!wtX6rkwJ(rK`44O@cV^x20?J zwxd^yKmJjfQDvU_uU+Ot9{S=FHh-3fKH{N!|EJ|A3t8uLJoGUS-S?y|Ki5P5?Vd#dRa+{d5dqD{ zk((@bzP2r1tO?jM!&B`NEK9ZGjGwtJNxXg>(;k*)r@b`Ij+m5gMVyjSoi0YEn~CL# zv<%%s{WG=>(l zhn&RzF(liH`=P_7xCuF0n6qG$OI}oA+5S?f64g7WaNspkd_UJu*XG*m=XLq}%MN$2&>Rg5Yf)gjz--_X948K%Ps=uu-8}rbmj2u^d zVZmhCOpC-3#7Qz2Nx#@WbDNr}u=nSRw{BU{*%=I(V(jahEB7+W9R0`Fw{>?XV+FRD zWr5NhK0!Pk3#^{Cjqf2GgLuE#*#lQ{H*J|%<*&21HN2kF!F^;<wzc{f? zZI|Q@BUeBGHw`8KZR66=wj)=J{!gh;^cVlBNCJ-=MdJPwN?ej5@xV!4cp|?&sngfH zl6cYJlp~^cD)Hix7}$nWIxcSJ)kwmBdE&9tS^<&YpVo4EgOem$o^f&|)4)wnoOt|< zj;7_%Qtgb6EBEa3c;gqX&uTdrdo~8P`>c+O`U*u^Ha3S*8;DJRwc6eJ7EV7>t-1gn zw2H(4pJoy{-zMwT(ZZBj+}+_@1-V!XD+Sv2C5ew?2xr!LYgZ$Jcv*W7O(ZRfZy)#awVl061VtGu|AFqpv$rXrO;;Yq2LNX{S z;&pzB^e0$FqM!T&&cuT-N-^dh5CW{WqI;UDBSxikfq9qGloHN8eQ%+&M zQjEBSUB<0P?L8$>og|KWL?qTLU`Gp7t0@mpswLuhKsO4K1)^`N7AEqoR9#BSE*=R| zW~Au|8cGybr0G~L_CcDCN)>b_O(&~KzqmPFM{}{&={g#zO3TpEH0c-jXXt1ywmw5g zLsfLbcCQnNOcYOL>S$UdQB-H@Xm}1P5cf34QQkRA7m%>2Svne$>THX3LpMV4;(~0= zb+OlCV287HLX>Ab2PTLqv)AFHp0DIq)+riyL#bqtO9MR@}q z&BZ1+FyhkHn7Z^r5hCM7w}wWvY%#52wVHdS7PS?sZK%6q>qgZ>xIyq=iJ0F=M}mQW2*% ztM-dsO|8g;b#3Ow)Lc)w#49epINr?ApDpN0Z&34SY(WexzJ<;P4xLglqJ?fRBn!pL z7CLbvb6c89=^i>>jE)6<9Sf}AN~cA6U)1)dc(Ji34)JlVbgC}nhgL>fS%QRHwAKn} zBHP(3dMC5KwT?z2#cec+JAb~6<(ty)9mcBNyRt>2wz{B1K4g<$Yf|0OHYiilihjII zr-F&n5j#Pww=vpg)Ng0W(E|LqgW)M4Q>=GLQY9DLiKXS$7`9{h6~hh;J1a}ecYXW5 zu`1*9kaQ8heV4maq-P`pydocK5q=UQ0>7##ioWUBUHvHz(fX0fCQC}AZFlVAck1M& zZcuF7p;ITaY^Oy|*tzQp&J1!>1U{8P`|h2))Lz!bdhd$DDq+{IJAE9Pnx|;@E;aCo zd{~nck*r*``?u}JLpP?A6DA**&IC&{|~P)T~!CVeeb4#sJ@VX0O`06Ue8+lh5pZ*N|jz#l*dA%we1g zUwL-#JFcL7LE2w=)pL7C@B>@<2rDRlOs-K28j&qiYA)p{L{3goTy@~1Q{kT}HC;$X zf#(NmxQDtzN+q2NPY0AZp9%-3>J*Tx1~ZLvyrzy9scALtQH8Fq)e_>0taL>1$X6)x z(zSXz0p6Wnqh@#FUS6WPqyP_p=3bxAf*CbDSY$iX`7lZB$2wL3msc~Iqq!n&LrTOt z{EZDMWfroh-zXf|?PWBWfQy z4Yn=R`dsYULfs!-Y`-H%6-dXwi;DC>ak1BnYS_?&yAH`UD%NtOkB)>-#lUtJ*Qf)T zD>tA-$E7sz448(yJYCU*ohhkNxAv~cN2ONrX+=t|UvsO`j)c8XUsnmnRma5C21b&I z$ur>14eYoQt8P%kMsHljBsaF9u1-A8sH-OYS0LIq(nAW#5&?~@BH+2uy++FvNTLOM zV=tB>DjMr(R6}?sOcm`5y_jFz)ucw5nrJzyCOjCXigTKJF~6AF)Jm7+{&D0` z9~}o%>~z%;aX~XR@5z}|$%UHhH1rWs4{v#5{I+>bKW-GwttUFQ&@r&C)H(5m7DmMq zrfdydk$x?;2o;cyi0{O}&a|v?cN6qTF+p6}O2@@jMV%8rYNh*ui>0@&8N}Ijv9YbS z9G%ke@lQbPXswGtSlc!=YLnoKyxm5NkSaPSo{qxe#Nf7i`qpx4z9v;kWi@I!Ao9jC zJ%or{>u@P99{tRXJ)H!fXr~9e7V(SU+v%*)aj;9dt{fsqr0M!2a=*i+;~*Uo`?S{z z2z$M~)A`jYQeB&2l5|8&5<@!Z7=(S$L60q0#8PR)%@`Y|s>0sy=4|g`Asl(#>&Q@!osfAy3I^U4fd#C5muTfh;JQy|<2OSwYC-&{4 zyD@QBbul&Yu`$?HH#%jSj*Sm?HM*iYUT!z#=wO&4x^^@4sl(#*Zn_UptKgwBMYvlL znT9$*UejIYoCN8x_;Gh5GueVLoa0hOqaJ$fxx!EPFoelH4m}M}Ydy*7qhy>hi@A)M z7wFb>F+6w13IBz zCAx0ugfYt|4_%_OLEM48YxroOj+5{AR=O0O&_^r780BMhkaJ zU!5;JPF&8_PFmzLT&Hs@(XOzjIZW%_5g**_yna_bv8cQ{aiZ_i8VtW<_yfbA82-Yr z55xXS-=(!P9x@cs$@8O6Yu(K^ojlV;;ImryT3TWEepaiBN``>qtIuk=qSf)U~65w9ic`ef&J~dF>L;2c0)R`9f!b$n-C3)w3=lSA1DJ%n??{&+@fOEn5N7k#y49 z+OIrvm3MwsTc<9A)L!G))vC3a$ek8BvB$Ty7!FkS`1at7?Kl=yxIEoWtT}bCvgXvG z>C>2jog3%%$%p?kw7)RruzB9BnR56>L-@L>ht2z+Wm6CDFt~VDjjvoZ?eL|%rQ%Ah zOy7U_X0@K7wdHN%m+~WO5~X7|T12XIg(m%CR{JAYvR=yj|6^@=TZbd6TTyJR#37<# zM{fdt@pQ){s?yw4_Qt?2=@czDKL(b3PPE*}bBtV*$z?xLdalkNZne~2sHoeKBJta~ zN7OD_Z;ed5OA>keJT2nPLaMj2J>rPYS~pFAUc1ZI=UeR9c9#boAw1Mtc9)cekGfb{ zh_bu9zpG9I4|}HFCB`1bEl68ikI5zJKHJUI9oyvci|$%KuGrBgmy>#EHl<>lTnb8M zzy&%L67gDGqD-;Kx$ubEF5=PKw74V<|GQ9Ykh`R4i_2Fo(wV?!uq-Zb=xK0hYY@ZY zvZR+5k{L8DE-CezUQX(^#U*j)U#z(pnRfD~#U+W1yhMvoFNtY!*{-+F1Ifg+xcu9e z@mgH2>T~32V=6$4%YFj-ngem-@xDhYkM}+LP zOMLW4TYlS*XuC*epjdCNDJF1X*b1}HPrCdlLsppmMBU8>M)xsSid8nI?J-%GbL&)3 zRBt(IV%ik5pV+CvyJM7%C)7&3);*}W%0TkggT{E(=9;C4bnCM{=J-Qeh;Av- zTyv1=Oa8Xw%>UbpgU1H4+3Y87{l`o!Pkg0mfyR+}qWQnN?eS=lAtwKO zl#`L%TyalJ9O7M19QBxvXcNxb6G}Hr_y13~7)4%elNl#97fm=-pCP%Q90rl+oYHbc zzGjmrT~b<74ms@zOR~x)>z}c>Put{PO)BfnK4+cMNL};K8jI))q?h1z66U5h)`CU@B61@$c9w=}72Bje)~ThVt| zbVzK7Q-xFfw(++7OCI{ThrTAkmS5q}j_GEKXq$NKJ)SAZesg!?F}@{KX%0xTb$qC4 zaXRVP%^Z>JHy`#NoA|K*IEKG5{Da|N3@0%Bhv6iKQy5NTID_Hrq=)^!sTkx>9r;sN z{?wB{aq=f#{v^nsMER2>e<((>{Ffqs0`ezS{-nvDborAZe=_Aymi)<9W3$mbpW{w!Z&)3lQ#U!C>CDSWGzAIC8Y zH=r<&MFP||nN$dTdDah&rv-g#A!ig{q4mQH9u)pWKs_Pm^yQnhyeCvCEk!^*)nkcV zd~4Q7nqQ+;$9zr--=OtZ?L)D;YJXw8G+mYWO3)XtaDK@Z-+#@9vgtwJ6s`zD`Q2&Q zfiT}Jf>g4OCFmXLs-Ot^G7U}YEotcgYS4GLt4h5l4b=#LV#4&EG<@<}&}Y2JitY{Y zMd|lVIeJGLy1(uuPcKPB`K+L?%8=vtq46#0gsQ^XL0=a$XU@CQ@l{XF3HlzdDy?>kp{`Z5vdtI?&cnyIET;N6bZ!xUI3|Kn* ze-QMk$96b6gRmKCt~N4(m^x}9w(zKhdA_y(k{d^Dr2D1Z@C(}(vwIC8qe2a zz>XIuxq$LDBE8weafD}c#h9>kXFtb;$&)?YyCCG7XTpXnd+6~&$oFm(Q~I*^L+Zkq z5r0H@aa0s?X}>TUzH4#FXTgR$d+4zwM(Tx-_F>5PLA0u$5ne_xKe;66>=s+=~a`xjS2J{p9%@9on&M`%7wQP;M)iCUYkqqd8Pp<)QPh4wHSne}#Z5 zwFH{L;2jr^ERqXYS5co9*xSCME#Xk25(CO`6V zu*`$Pg}*z!LdGkGpAb-c9QOKt2Re*bnPWhDkXP-@0QrrFX@5HTVwl{;L+W2n#w6Sj z-bCPjZU6$LulNM$jy%=O5}joVptJaF7{A{UpiUya!KXn+t!E^Wk9c$(p8&5Q%j`Jh zJ|0RAIL+^Uu6bj*HF!`+R@lh|>fnEPcgWi5VW^VKFkz$wIl0FGWZ2R+2K#Q$~`~e|sui zfllDf;<>Kj%>-SC@Mhs05AezGJNk-ORmy(3r5||JnHboIfKtf-d47lRzfSHMmJZ)l zzU8iiJ-n+$kpPi*H7?SH|2gp(Mepu;Fx!K&k9R0K=@CZ%?uGEC2PH4>W=iDSogG#H z=Y>4FLmPD7u4-Ju?9E*t6=j~K5BEaobjA|Pm7d%SV7ZMh;TDl)&u6dgunSeF^_bw< z6Y}+{&0^ARyIP3JV>@g|z>Fc#WxF3H)p1aA+z##P=KEeU(<9IAup40`_F_XqdTmdH zZgG}CK9KKr*zbj<^Y)jG*g!7Zp=W{>UHNQ>V+gCw2rcPV(rJ5ZbCEawwO9R?ljDcY6SqB5Eas9^A8_Po^g!^y8iZpCPJ7kfWEqxj)KP%Bc3? z9uI$Jd6Gm{D%_RrNfQ0JXG5JFPm<`>Jrf>BR1aEoU0wi*_^Ssk{#AWUIu|bx=+Zp^ zjf0LJM$xf*3IL*Nn?NYE$jjF^2`q;G-IHN0qN+AnOnP}&J6IP;fqxKI_Ym@kGePwz z`kq#1LB2DKNPssT5kytf@u7&mVgu!cPWi}xJFG?EepW{g-eGu=lO>iojDV7mSz;IO z5H7arh0rHdwp=Ol><$aiDZI{$%aab>RW~y9$}NRa0V*}=!QJX|e6%`>uxcFY3d%1# zIc|r?8aM?pndGz`G8;NsGMLg=dosL$JhR&=t)WIv8<ZOyS_e> z<50mH5PsO`!3rj)?QnaOn5vE-93#$zrZM5XX8F#o4^05*s67)Z5mgHtl|Z_4Pl0oq zJN<`Iblo0;Ul3JoX2?nh?p8bOKtQdaTq*2S5}mil!-ST0a;^*a1W0P-DJ924NA3Z5 z6M1IR91pTud(!48=+8Y7Dv)Q@Kl9M5dm{8{6O)I&-4mcXHV-|#C&E2#W5z>2?*T|E zi^W54@8}3OCQJH!PlOKbVnu^B2&;VnUp`z}?(}O0enG&Jkj~%LzJn#Cw|CVt5@-lh zIyl3YfkquYz;Xomk`7oxx_MV4T>|9cJpm3Ps_IsvuW`ra7@>2m7!6@D0!pXqOm9ch z;o|e`o*>ZGdnSB`s5q9uI@j$GbT)4A<|f+PQbjC^;|^y}DZ+ly7vTvv)I(>P81$yeGl9?oLjn zv-L)hj*i_`itK$|dU{uBF(941t0pEudUa2R`G~5?iN(mbJM_BHDJ{d_BcSemT{-gZ zo&XPBcPQ=eN!0QD9uM=8rwYs&VjlW`Pk=@PV#R}b2%Fi^j^x*1pJ_VK&IY@0 zCui_#b#hZ-Kk#NTNm?!KrrcGR+0{XE%Kba+N2VHmMjYw?Jr%|ej>$tW@M(~9xrZlx z!K?j%p$M8^;jVk=g}oS7BcMkxxn(Cu@X+N-N1x*aJ^&jL)dQG>$rU{Gy2`01*A2Yh zYLcAv0I#2>5Fnkut7Vz}uur(gnYtNBy4I~G{98g!-*rnN@H+Qc7AD{B@WpjbrVZ!r zaLe^BEQc*f@9xHZ8M|wjKHU@G_8V+j>B&6@{zX)kn<~@w@2=)8g*p!1;RO1AH``G< zdryb(P#a|j?2t6fEjwk9{IbIYgsl$6FgbOH;^B6dTwm_V@G|nu`Gj}@D8A8Ibht~9 zgLZQ1uG+?hjnh55i4VYcH^quBJ-KJVoj2=($+w?VU=PyQQUlRL40h-aBW}@BhX3+k zxgF_gJUeoSe{Rk9{b0i6$sG=l@W9ef`EFOP4SrZC-}k)>C=c$i{|-+?a^Vht+-XZo z_w8x0=PnN_ow&nqcY9Pw2kv{!q@)}2-w5C;kRIFBb9647bYIWT+NYcGr0@DSO+Xel z3)9k1s>AjxRA~ITv!h}~YEye0m%ZPR2OLE{{Z~%d;pMT;jOfD8k(}(L_yFb!Ex`0mDr=dE`mq+;(#B-&3-ChnJ5rF^>3u{r$GJ`%AX?nQ!IZ< zEV9DDGw?i?#~`pZYN34_E*@V>e;@h$b}Hba$V>agRL|y zK)SKNz?66%f$jz%osY-EK17XzD-!@u;fmpXELS%-a((a=sdzSipVQP1%dj98AT2)h z$}6oFK$?n}S$6F?U>~xKTq(Es(hLL!)rn@M!!i#_1}6!S{dEWY_@Z=U4${8lW-fti zIn&Dpav{H-qnT`B;1&dwHGzB~1C}ApMPhT3&o6K1JC9vB>lZfg#haJPd~I#e4+F~D z`r3KHvvK9VE|dX&xkkF(hEwG+B)=17(a{T^i6OcE@7B?hAAGMR>3N>9PgUjTwcpvH z4&qudQ2O8zq<_#}I>biD?yjCJC`odv&4_V7qN@8bdQct{rrhF@rDMX?RUW+u<$>T7 zZqQX9U=4J5_|spmJ0hcWD2d7$e!40H7Cz+BfM_!Oo$TbyI9v@+ab%4{6Rbg46~l%3 z-6LQij33zQ$rZ)`eWA;&D+v!ZCFsjuumoYVeCGDYTTjHxhJLrkh!TJmX}Vu>yYOa- zw>6E^V@7!tVKq9b8rA-azKsLbvEumYQ#`8ZZXCQ=$1n7#Nz#OS-qPCFiMqVb6xzvL zW%Mjyo0qo{R*OK$6Izv@(jYNPjKed0Z*RDqMDXIc?BzTJsFWv)K|M8HyD#ipY4Lt zF`0bc+8C1u_47QH%ZZIa*s3WBr^7D@TXiI1KJ8gmLP`XkvT^r(Ur<)l>zu+Dl_Bm=c>$Z!sjFJ3_>TYROnl`jhfBXl&8O) zl>i?UTH15j;->om3k|VZNGX1;*T_jed{Sh!Kq=%GTM{7{iGb0ELa+`2Bi|utP+~O~ zTe!r-#g{p2o~*+VY(Y6IqO@qSRKI|LF@!^G33CupBhw)m(bE!BmPekN%Z0v=bi_|W z(xNLfz!pmhFrcZGuUs;2NrP^WcGOF>`}|z3OZ=dmo`X+p=wyaa*n@y76^qgH^!|-3 zu{L-YY5}G6wRbg(ae5Eo=igP~8K6(a!*+y?(&MY=@-yu8#JsGxhec1!XEpJl6al~6 z9@XWuu`bGe{EjMhE2W&C->*QHm9G3cx%{v=8cEuHE8Bez9i4>arNXvmF_iJA&Y^UW z%~Ox^>9g+OEg~^9;AHcdap;5b-hrJ>CIiaAT6TnNl|rbc)%UYu6auE4ARD4z5w$9U ztdKmtP1!O1JgL2}m#RuKVVZJ{9huDl41Cqj z>FEqyTfm^sB0Z#E&dX24903pCL(ON@wmGNv*C!e z$52hffHdS#>mmcsA)wY62Bb|#612nxRn1HccfZgRQQD+fE3q^=;oC%D>yyD3IYWbW zNb3{T9SLBo6=Mx%F=GvuKoF$ikm|JzNL!um3T#GHRXL&R`EFxeP}SHmU_sA! zr@4!*$)o4Hhhp>abJ__ou#cTtPKut>uDx3y(bdf!-@MV|-ED(oMHBQ`xa;LHdGt7W zbKjUediLwBH}y0eKeQMR9nZG(6^VNW?`~%11@>cAtDfhUdLR!y7f2HH)ZE(wNX6?h&#dDu^3FUn>R8oA5WLU4&2?SF2&EQFS*RAQ3mFFfn;oYb;l(o zT7uC}B%mIO8$E;-(I?Wu=o}2s#NJ}4YX~P1P;E+I<%Ho^IDLjMjaMSTuJ-7$Jim&N z0%PYp_ajnuDU7?)8S@M*Z{bWH3>bSX0_YtEqmrop1esbHTL?zcgo{nBlEK)6F^^2P zy!}m((HC!7Sd8qwj6E2m@+l(V5)l4>S#(sqC#spfSSsO#PCVLdGo7G;70cmfR0>63T z?!%o;9IGR1wK12q*Hz9a8NeCYWSw{5mQyccx%eSk=wIzro0L#CUDE!`+GZL&V-snh z(h4lqJj@w9X=$ccKsSxGh#Fa;l+&TLdjUz+&GuJp{N-&5Wt+7Jqo|5AqQIB9%T${M z0~U*3K$DLJw>qUZcpz=U5+P|sOr|sevzA7(a}#7^7PYvr4P59pXA@~A^GGaMRgf!} z1RZa8W*ZmgH=3;ZniG@8b5TkXz}O?3N~9fLbZJ1o5M?efu6?4K64>sr8i$~oDH-T? zmj&F&3n9logFKaA0-`q25^Z8`pE+L3kxmvFknfI}nUm$o1!?4LJO&KHHKUx(vXp2G zRrgvAn#=aiQ79Q|N1+dUfUN|GG1^In>b*ytu6;xMXU^dEGr#Ob6eZU!l4E&CO>J`%bCI`CWuWES-6u@l! zRijn{ddrM|(E_>BzDkh-IfBfDjGKN!;nYJ;N^H-uA4{c|9Wvk8aFv{cRz2*t9l>dj zxMPX{Y4_oWcaxm?&oCx2=0AyEqxNSMPa2_cS>^Ln^%CU#$8~Z9l2HNQiPNK4a$D$! zsbloc!9}^g`GGCH@Osf>j(+R8 ztQ_Ri^DJofq}E`->YL`UaDs}6MAMvZLqKthz zSFrr6KIR^!2&9cd0B#uX(d3#gBt*xdkJiU19@<0DXW3&!kv0zjIE6KWPsF4LCN7yK}+c$Tz;)ySgg(sm&OW+G~eu|-34{f3>p6i%DIQy-nSw7STI?%w7xj4`~b z1%3=H1=60es*vA3gu7#)0jNS$4O^L)6d_+ogf7q88t5H`yeJjw#fHrjZ5_t@4(cJS z?4aPjAnb?0Zk+(zEJz-{zWBRF$t{*L;vu7+uij{n_pbE!yXSOruCYrz6hE)yGJ40G z?a>N?Muz1%1Q8UcRN%kDU!XM87LQ}tXLKmVrgURZd8 z%?pBmvM2TsFR;W5)Scpq(lpUZFbH=$fc%162+m*(H9JT@ATV&M)P{K+rc>Fsc6_L&7m zGjs+BQ1?sZWDB-$bRKXsu=1}qO1p~P)p>%hfG!_*&@I4GieAwfP!glPz<1s#r`zi? z0QtXy>pyXnGB7FCsdfhTc_pr&;Uvov3%$TuFOa;#N=4NK$9~=B;X{^M#~=XfIR|cd zzLl?>EfI(wKDLcTFR|%4PuT38ujxG_x%7g$9{wQ@-D8{`f0~Eh>C)1N6^tLR8&1ei zmBN52t+X`-@k^i7d{{V3-!ckft#MdPr=u~EvbiAsa1Xu2rsq6uiw|;W_JIWly+HS{ zj-e!`dVw8YpzQ=tlyP2QqZjD@hSNdFITnn5#?ryfPwu8*_(Xl_M=qma5z?v(q_-zH z~tawM4jp@L< zHa*NkUtg%>lT#^Obg8PzmwHf0Re3Ofo-?0OQg;>UsGQWL?>R|H?@=(@qVwRq;!f(Z zq#*v}wT^zGU!HHr-|L~zdEe$g=b^WG=++A?`KjZO#-H}`r-QF*+=7n21E14Qqe{93 zPP&!;3+b#Dw*Rk_dYHh5MAE^m38FhTcA^GLsvSwkN1F-K3M)UxJBQWN8i#I>*(Djj zpUA7>!0o%zL~;lH!E>1>b~?0(mvYBa+Cp7$yZ9fylgfijIUplFGAZ2v=N*{eK zJ4#Z1)quW-9nEpR>h0Ao>ZstemTTUgT7xKV7|FR#g_gOBv$YStuy=wqI~!5zg>p5Zs3Kh~&7(#2{NC=Xjg zdTBK|(lsP>tL>y-AQsZIBkV(3bs%yb>G*|IpmYfdT@N}!GNZ5q>6f_|QpO!elxA`y zDbI53ID}7ujvHE~9);9#S$bX`=IA7+`3VAg>#^!#laqLLD)+F2?LgPm8Ou|%$&cZ} z*JRs%pbZXq+&3#$EU(5c%jt|9HTq4XII8o7wCdJy5$cN)r`JKR~_ceu*p;Si$Tou0uTr683i%ToN-kP@91olt`G-UFedw19M^2m%69y^4jVlu;>z4H2a%dkNBl zUFj-cLR(^c7)O^3?FXk`q zFX1og5Alck!~CWE;rYj=!$IoEMhw2UBV0T^I5#=(@|fH`AtL*MK*XZ` zlX8)UAq_`*1Zf1)NTg9nqmjlSjYS%VG#=?uqzOn9ktQKcMtTfs3er@h$C0KXO-Gu6 z^aRpOq*+L_k)A}FgESXu9@2cI1xO2#oRu%lMr+EGSsACzg86y0y^Sm($@ zY|)O_nUgselB{@fv1rE@M=NU#&9uVBr+@9(?#fDEOoHs~zdbTB|K^Sll$Y(7lB`5A z{GT1~Iypq6f3+61IOK@e56rY8#JyWPwmBm4-G4iF)3AsTZ{OY#5J!%mjFJP7QXS^r z+3^l*@|xe>5oZzkCH<6H)!N=Bns+Mji8#xCMo|Zdy1esrIZ?W}9VsRkvllq*5~31C zesTL*rsSM+Nmi(Mtc3lXSU1a#6YHO|BShtr_AX}S`m0G+k|>CYHm9V2Rm+UvD+;<`*LTG>_&qiSuoGvuv5lZ#qoM}n5Y?JKdscqW9+pu^-hu%Cl;5n*C9 z^3K=U4xmy#<*aq0JyT1w@6tHqn%zpYXRAgW%dktzW8*We5FwN7S6rbO`!$dHda_ZcTRwEo7b*5z9`*86TukoTWyO5RJvJ>UckOho7E}Sz{!xsIG8wjX zJlGCZQcf!Avr38WJW7=sHc=qo5%Rm3Ha>gdC@y;j+d$ZJ)}7M2p^LGW-f zuX18FyQ(FY^upMkTpi`_e!yPsuxlKuq^MiNqbMnU4`w&kv{%d2GCo|n;kE1~ij?bO zd>BiqwY8v{8aJ0})8!#sxgWm~VrgqTO1x3Wep()xmubbzfn`bBWx8EjJW?07O8UxN z>ig35>}5(I^6S~JYI0VlA?1)cG(g+cw_l(xN*DjuSJ#p!p>#Pb-e*OrdMs{e``Jde zc!peW_;7oeNI#5D=+y}KJm^TogPkF&w#UF@YE*B#oG97BoMx8JYn3UNNgo=MUQD1& z>uRrXSvmdz=W-tFX3zC#avq~=IzQX=6>_U7OyuUEVVAp`Tb$YLJ=AqZ!*c95l^asX zm}%Ngl<3e?jS9Ajkn^Ak5jT6HM{xUWr=K*rzcw{&!!|4&Gke?flyFcTr;?5OpnKW! z!I|XvY9D)<;-9bU!%FpjUp?i@;uq_%IvS_-Jcc@z6u|BE`$}l{9zw`lG&a58HEDT3M8Cf^l{5VJFw* zff)O>8nJ^xnye)*55?##G1#8Xs(7(sFm6J!ikHVe%|u~rFl&f0kTpKXI;EsdhT7A$ z?X<=|C7rANEY3B4gs*);xUBP0rd3X5dvq993{}KBNPS9Lb2yd>CEeacI|~!P4%bB_ z$jP5Lwr@OQ&(OBVn)SU$?$ zsL6q&?X66vi~3_QCvXn&?-(sjk?F1IBAy)UWR~N!&L>ls(g2t<-hM;p!_=?5`Q+_3 zROs0Zba3?vSX-6j-zOLYv40{e!IxBKw5Pda)g=2Hp4WZi=vP}K^Io28zp5tvs(B-( z*u&JM@5}q`al5uf!AZQ_zJ+3=w$tsGz5JL(7-2~>a1%R532G8KIm1Rg=;V|I?@DtRH@6+H-eHsnA zPZ}w{f12hX)K!Iz>z<(%+^{m|0Nt9C7I{NUy?oVumZo9HvfIAk3vu^Zbs^X=r zM|Z&Zm(6H9Hr9t|yVy6FBkR9H>mckkEa6i*P(JsPy-gYKh|T>RDyIt9fcJw zN_3a@LY9`7%ONc(tPNN{$*hXlYsm6q%4-OgNLpUhdL3lyE16aeasFLQE4N;!*c*H$ zvGEP`EL+J|kNM#2kvFxo@*?RiTku1NIQe3*FcJzNIP-DivO zQ+lhKN8-iuZ5Xsiw^BTfX@}TXnUXQHu?neKYwUJ)wUo7Vmfa{(=Y3j6X})UpBp%De z)%Ud}^O0i12ljebA1TJ~K)Aw>QhJEk_H&xQXxl3^DFcR-XYoX*NA{GR2;wMj6;UOR zh8rHM<@|oMN}kJ8fk~8%0bfR}-DPuFrua0~ibp?GVVO3PR~9;fbLMUubL3CuKeOAL zzl?Z!PcRRCm^|;N(KdXq3g?h@5&4VRr=lgzuYZP&_I`{pe{vr!2wVtR%38ghTlt0k zv@94^ytutVelWDODjpEz0i zd0myoil1=MDSyrUx)emjaWt8&a)NzT1e2`x{JR zsYfzVw8U?SX!ooS+E?s>*5vA2@-!sth$>aau6k^5@M%mHtoD6D%W~5Ktow91#pLrC3BMMoM-9!sc}6{IC{`AXbcWocXZ7_|`NGe6 z@SF&j$GN<1YhM@sG`?i+UJ6%^Uq?`@ z>QsB5&x#S>->^@pMtoXi?^PTZTM{Lf{cXRkZP5~2>!=Zl zBIh5(=4>ob|1zTHzxKP#t42i2+;1tYV8_*Nae#x~qV~ipVX6N(F7a9Q6o2VI+`ro4 zZBs{XPm(g&b_Xl5+o%L3U4EAyKJq+*u`We@qCFuzBp2`sEim{GO$Wf@gad1X(zO-I2L-UlsFO+c*Dc4 z4h_7m_BMxB9vUG=g#|XaY+jvGfd$2AUp-Rp>Vmz=y#GZ6=327(=>$9`)jpVj`DT7p z;BzGq(Hb?8%=(c6lkx>D!xD~O+Mo@wsQZc3AmHK`DaH{rIU3(BSF99fEI}NlTAKZ8tx-R zN{ZGci#djjlh>dtC7ynNm&w;GHPBZ1%#*2spSe?0@=*6mmfZJU0`8^D9GqA{P_2NwF!_1Aaw)VJKPWJoUxU%7GZMxJF=#QioLu zloeSu4ST$%$v3+em4d5QUPM<5M2W_=15e8db+QnY$vT0O;-}hyHHu#Z9%(019?~wP z50Q2w?a7mM_O3WgMMa2${DbAh+Khdz#Qcvj(X;IH+k1y8s`;J0qiD#5i(Pm2KBB0) zccEq353z@$#ehqD`!c&I?cQFbeMtL}@{tZ8eT4Ke(kDotB7KJRInozMU*@IV`>NM| zr>rvKw=xIYh?qSm)5Smg4xUnq!uVea zIa0hDcjzU>qAk&jdc+?>I*fD#=_t}Mq~l0mBYlJPEz$|3|K;_FKe_EOaU|h-LSDwR zCx_JME*>qe?K#;(L>)L8FM8}f*-BB{_nz!brC>*O-^nhN2S*+IP7b1KM~Y*AUXB!3 z_nlm(jOBivZFRoMKg^*%)>J=b>puX;G~>u)4YRCnqR~euI}#r&)_#O)V2Ud(4t#tv za`nebUQWoKg(2ej$m>lVWpA;sVL_~zn_Unh7x&DvSd$`N{p4gvxvo!^HGnKr#Q0C) z0+w+yt#_8izEecjXU1=xgo2Xt*ETx4DpeHwT;++CbNgmlt(2o;<-Vk%{`jO51aB&Prlw#71HX6kqsGH7%sLSQH7+4 zvPZQ-7NAPH;pa$*i&IYQt6fk^WFHHv($-@}d$&eGsJz!AxGQHLSL%MADs}!EvMu8a zQ&vw`*E2;VeFG6+&w1aRY@=%Vi;>BkUb=q}p5x3-9_>JbX6cEOEo5r9Oe=QL?? z{eI%R|Ej9ddi(Zw1DrLglx*39%)hwvT??g7zWd$7>KO0UyWg!)hB(G6B@X>}qnp@p z@4Jp9OB73P-{`ig->Hsd8!K8(Dl92-?!Y3-I)#ES;uJzWYMpAuPUYltsE9b}su~tM z)k<5fcFCJAIiR>>@S#ikN;uNlAjJ`@C{dg(ajFGT@uGQ2C5sp99qL}mQ=P?<-i3)` ze8{O4YUv(Qq9{j<4@Kq8!oHR%8PhDw>MPEKox)wxB+Gh4yi`gX$=s${R*vWpZZe(u zW_Y;heCT9dv7zdzl+_VNp3}Clq&x^e-9*34Qf(Oq-PBe5wpXKx`|3r zCg1sN+#anWAUhLv3e}aauAiZ|M&4t3R` zauSU8{e)9p)QFpNbC9QZ#iT@Z)0yU&r;cZ5S-r&rNw`9nyJT6hG6%ms#90W)AVCaC zLKm*^8NHB=3c}?6u5>-JlVQZ?(&w9CVw>EJgvC>|>1eSx1zo`n^QEdP#fv9XRb%7D z8HZ|-W@OS(tJ95Wm_vQ6DNO4br{aY_!O#S7(&x~;B& z8%Sw~R?ynjm5WNsSL)FSELYJ{PpJqs!qvf|VkJkou#%gnzi3?9QHaW>sEPLJ5OKTm zspoYuZ&%UvNfhB#(M4RJoX0U9Cs%chlB+qDezKbJwDp0481Z{G$7uBfs*Q2t?+0)x z+0pp`O1oDbS7lRm)4w4#jJ8#uf-o_$#;NC3$0yb_V_~L4{oqhdYZ>iYhq~iXLuwms zzC&fyF|q{?b-|(9)-~EU9jatKBOB#VUpQ2?Orw2{s51?5VSmp=qnYYf-%wi|D!PG@ zO>(H?4ppzA(Y~aqe#%v!MtY`85IbEmG0Tz8a>)XhY|&U7B#GA>YaoFIxl=wur~ zq#*25Go@%Y8>qSw`P9c4d^g~`$v(sIlP*)ja zN8;%F+|G1VZ=WL=(C(1|M~K!uBYX{yAs ziXD*-J2RQZh_BM2HEef>iV-hnXgiwL#Gn?KXo@mWEZMTCb9r1GhkLs`T^4#O53N8I zA!@io?W=&QYugBsR?&4GA?5~gXDg!fxjq<^;i6?Faz>XD!DNV7-Ue5DVm|shYr>Yw}X3qz+&1;wnAxI4quh%e*2HQdP z5G%&jgq<6|90_LY)(XL|Oi zioID!)ihZQs%xl^9I8q^)04S5g;8R8J#{V1;)Mi^uxs^>3A;;uoa zSaEj%`mRzFRMoH{BBP0_3~NKgQ%z8oiG|uZREX%*6m~`tA~rWwb&3^X&5ZkT4t2O0 zZcT(;iK2dUWMgWjruwVG>A?>7xbed5C&6s>mbh?SBsS4-(Oa4tF#At1JEWCyb@f?z z{w$cS**ZwOqBT4_abu{sMQRV9+a{R*ybbKR&#I3=7uIQOy71YyXecXwZ;P3Lm#9AN zOj&qPj1c?UnGR;Qa{C~5NqZP`8&gLYmKOiEhi7IH=|+e_9ZZv%{iK8Oj0e6@QLSST zyCj&s-Vt@is`#*~U)`~|jXv#UDh@VWRPAi)!tBz{rY^K*iob}(6K8pm+XdM`rHYTc zAO};`x?*voP&--FeN?Yen!oO<`gb!Ohb@Otv9FscklFIt9=3z?#26xeC53r_3=!SB z2eI3_qhgq$%Zi8|h8pcqpAhA2hKOo8$jj{foPw^R`QMjg#cw2Is$)+>y-C#Np6D*# z0h!nfUU*U9xaFY3@*43#Z=;>tyC6r|aiH?MQ7poYigX6)EYdlo^LefM{CHxsvOf36 zG^%R*h&K15TCHiulu+Z^)KS7%g1 zs6Q61xcHO!ZRhEDVPCx1MrDY*bdm3ea^i_g7j-Ch_R>ZDpw+fe%kthSytp*q)6;!6 zUOMh!TfcotUkC2^4R2rK7t|vJv(+{kE%&~E)1`hY@3l>rI;gwx;dd^*uBeR7Fy=7v z>CKnkQdG{nm-eXpjfZ^w_n_e0kJz1CE{$4911(lOU8j&kz*zB1ox<))*0-*bl@&Yd z7V0PH8dC1Q!+Pb)FB$jkbN=>yON!&Eg`-rSj9RODAU4EiCDn+d#Eh)M9u6BV z)?{fvDrmfug_=-ViXG9ou)l}>v9YS>U==2Q@E}|vV8p8uO^g?WiFn=8%Z7`aO$vqb z!rBj;!kF(sJOamv(DAPzu79h-hg{v)tqR+yTJUhJ-@0&=>NGcWG*>`}ljYl(3vWz# zSm=Q9MjJGP`xOD>42KF4zqM70a)Lw0UhSyXbg`J-)2^_mhi%YaX?3i)Hkd8Zq3}87 znFC9^gJ}Xsh^ZY5N2(Sv`%Xu+h%W-OjXLR`QSsyIPR5wyM_=c{CCZrD&pVqsbC_7O zOAz}~7Ytl(0&7clh1Lxs$96?QE_<|VA#c{{EwZNFO!GNve6ySJ%xq+~8M@3qm94ZK zEAkN6QDe{Uh5Dg|L(EURtHGHps`OCqlf{xA%2l!`mZM}GHR{Ne1IA-Hh22zla&+0g zr}Dz_quv4LSTUlPveSX({9dp_15?FCO(ltTy$d;Xe27+T9X0asVfKkWsEbjw(qSG# z$IhDMQ1L+D!mh3=N@VpzG04QBBi_hx*qi+@5x9y8{W16O#+mrCe_=aK))-LOQo+Tz$iahzd2X)EC?P&|AXv83>z%4pddd zw-5s{WwNW!2dcKliUxxqu9uC zG_J6@iX^X*g5$?N<53VO^$^5CWNRL4$wE9@IA4<-TD~#B^bbdkZ%!~hz-;(L+*sUa z%sx30S~qn3(aYv|6oE;wQ z(5);xI;Bt_88w)yvZaW%Q(9>Z1A6 z3Xy(B`UUA%q~DN!NBSdg{4 zw!)RmIiB!x{gun;7JYgdCnBz1-mU}7f~%MD766|)x43qBl_ra>UC#9cl~4SM@=c8S ztwTlSeSZD2Rh)VXGu&U7Iapys*!`!DCztO2Q{TN&d;aX~*x@X2&!0ai7Qtso-i*C}b{&|9R?X_b)gCQA z9CE#jI$y0c^g52I=rH%iq1X9D`@SRGI58#ndT*yGe2&{wJUGlacypL>P-eKH<~r2x zno1N8KVoux_6Q21p{I{@pBe%G;Jrt>8y>$NEe4Lfu2=Z`&U9H@e-yOl76>}njTn8s zxA$Q87w}{mbg+A1j4G9b(V&A}_WsIP?cIB@J9!-PAgJ>m?6P(CcvDlvk=}z{)>eDe z)b##?-Qp8e&0?kJVD~%;(H|TQIA98`)P5)hI^EhAZQkGR9<%L;dDZ{mUBdr$q5tXWeo| z*@{}{P~ovgb|Cv^h?o;w)KQsabiY|r{2E)-NwGcSjNN{Rsu6EwFUJ@4Q)3aKiT5~n zcmn#*iKBXpYKgco-s9X~As_=j&Xqbe^_=8R_Ce24j^`vdGg*5XEp8?kVX~(q>R~CW zHu2(EifVDZXqIZIcN{7{&B&f|sA~>2I9+KI#o=`2IbLLCm>h3{(nqOf%42Bqf^W`q zS8Gk13R*)Crur4e6-t5Bvf;dYIP+7H82|37h)Vf^X(?4 z)il@XTun1-y45n&hYnSxwvnwc)ap7$G{K>MaHx)Tjn;Ok^7V{tsYCteP-8NU_J0o5 zroNGFbEuRCknw5n^9?Wnn7ZjuBN`gn*ACU9k&(UYP>ESa_OzxFMNt+ygZ&L{tf#{S zal|E?KIll_amj=xj`V3mCW*hA;3BER-(gK1gJVQGhrf}cd$XcV6z)a}oB)T5gyv4B zrz zqo3mRQ-Xd<(oYEegwjtK{gk4gaQca$pGf+NqMvB`DNR2y^izg@%F<6c`iZ5VIQogV z@(;I2uzp=YQCvj+p#uq4Q${U_;8$wD((kU~<aNtUnN)}-uH!9s~1n@uXuNOBnPN+zM->Zzwr``sO zuLg%n>sW&I0%cB-J3ww$B)=gn*Bwu=4zfVt72znk=IaD2U-9&!aQ<`OBv@^^h!jBr zdQ&(g-#U?CJ*nQwC25SbPbOG*`NiB3y2c$&C0MgG&F|yN%aBag5`H09F8bb;r2LRz zO=oSg+yz?YU9Miol{fJQwaUxy4<|bz+{BV{or{6K!Ih*+Gmq2{ak}+EJnTsp7o5G z5h7y&m!Wt@&d8>ZFJc+^Kp`*4A~H~)yYiQ~-N?cNKq9}#=ehV^)d*kxG0DP5T3{K1 zWS^^H^by(WrzDH95|j^uA9>%gA>@%T`6pxy?+_&ke`LR-mZC7pa_~%&<&2-bz8HZ- z_WUKude6;K<<}%@r&=a}K@uhJfuBVol|~|wYkngEuOomWiOO&MJ3uq|)=rjF|46cC zlCDgC*ySYaHU3OjeH$uITuH)E=Z_8vQ)B~wucwhjC^EgbFfN8v+X?SuO?&h%qEY zkcrxma6oh>LjOpS^=~_dgaMKy^Bn=cHzG_DNgyB-G)>SS9&8U8elN*drkcRu9`X|i z`1?FHF4y6UNUbMy4^LJBV2^NF2%$2U1n;5xNI`i3*&{;sE^hQ{m|G=$mPTCw-bZQq z5qM8=jPRiW4j7Px!98TH5XTDW9%bau;Foz|JOnU4!t>t@#W!FY>4Ts@67mbed{(jI zUPIu0gvhW+pLLsH2NdXsd?3n)3EA+GayR&i4$s&hQS#wvAFi!2Vg!%~c?QDAT%nv= z+Ghb}r3`_4l#PK`4-&{Ure}MgKb~Y<3kCQwR?`ggA+ME14YXulIiEE`(E>mprDeHT z6snaB_aSXaCel?*m)+v1Eg-APpFmDfQiA=+RV0Ib$kGW^ampcp@ew9J0IzL3C;Bi+ z66i>}{0;O-P0vj7S<^JlU>~xw4_%@p0^dbP$Sn}4npKcplYQ1yR#ulcK&$3xtPi<9 z#Yi;RhinIM4`ow72tfx_duiJOcT%t`V7BowM10)S^T|ftRO%S*}9t3Gz0JvD*p$et|=Q4%m-gS zor%FcGUYdEeA$VaF=1fl7K96M1?u1PIXO?Lo4AX;lLYYb1Q+CDdxXe3^?cS) zk5mRA&~qw7fGBhiIV96mlXGi44>`R)n&`#ykR=+Rjx3p>4kZ zXzY?;zQV&G{EkFf2!Rr76c71WmMdWd4`~6h!`Kjd$0Y3lz#U04?Li-6N=D=Gz<0>4 z5Su&<-65MbaU}%Xp}c6Y4mq%?t0kb0S9MT8a2zW&9tMy&O3H4{F*R!Cf1sB$oh}0{ zT=|HWCX<5Xcu6||8b^pMXyqC*CWl#0%Xp9g9 zM-aNkuAVxxf#U%DMyTxCOZ(AM2H{|DO2BXt9>9$dS-KAmbq57wrb{Zsja-j_a5f_4 zM}2*WdYv4Mwh<N2F59|KdwhX@^--DF9pQYtw&Onowu{Y*(VGO&mfa;zhs}H6kK~|L? zf#eotFy;n#M21>Xt^tGNG0q@>w^2??AVq0YLfv>$hjXVvkJR+&VKnC|3=D?ckTJvQ zW>OM{+mNduc}zCd$wbPYYM2tI?sVsvf+B#kin!Z<30@ib($@fcz{ z5+*>6X_{s%4LR^p>IM&(hP(g?M*IXIWGEmF=?6WLB`dXj-$bmEnjScbmNtgbkR>LQ zB|~V)*FaCzHiV&J=yRZ_sNnm_Db!L9$s?!I9nB;mXy9Cl0`;uNY0U;%QT_;Wsv;Lo z(_~dybvkt(8+-y%8!&E$oH)bLF>r<~`-CId3Q`;Qn8_!?a8^bENbQa#fUat1@uC=d+>&4`!LbEt6gsGv0DI}l9Oj}qRJ$H1_wntivSWvl-%$X*VQ%4^6PclW2OKzjQd3dUjVF(5IOg0w-zKN#0;;M!pV?t zLCi4*T*3@^NL(EIagZ?{zfT%2hdt|7jcgS(hP=&UfLSEV<0#tz#Sv z)9q-5$pZ9?c-em$TF96aaq<#qgxV{Bhatx;M=_cv6pUO=6ZQoj8epRkFQzM+z%H;E z@se?tC;)j;QucwJ@($cN&O?|NGZfr~th~x-6D8qY%+bC8brB|qtags4RDa#*-^UV-N}jfG-_<3waU(Od70YfD8H9tB!;aE=tLW zH4rG2iZ?)xB(jQpaIKLFAYDYsv*3FxD~7s|qt?;YH82-ZGJ3tqAQ|jJe#inEd5l^i zJ4$ly@`u5zv8(iqcOfTkFc;Oqx`>pQA)M@FRfrc;9X>`Tzs_v}R7I+MA2j+3bb`!$ zgD$IrumI>qlspLm`ihkdeIfh3Nw>QP$wFR+WQvw7c*|$u0g~+r_yXvlOfx`++zW}Z zBncifusbY&1^EyIUTCZf8S#$KI*X+WNDd5kaZb^Ka4uwpcYT&YonW8~S@S(dLLd=k zW!4s-^)=^FC=usXenz>F?Y0@~>ay#0L#GJBxsZL|cLWOKLgs$pN*Lrqj@QC+w%NndmfGJ>Q4zJAhbJ zme)b9WIPMG;{c=z&_YiC$Y%+KXd#<@?6YtpiT57mO^|rYmB>|}_$8BR`)TW<0^i$W$-}GfYD_-pr z`(($qnb@RP=o+-g+(y%kv?2FE(nL#q0Dx$%Y1(^ksp-I}+Ezn;RfYx0vJ223+A@uB zvjaIGJcx%_qPLzWpKS<)9>P@6P96ekLrb-h%rzpilH85TH6b!hrnbw(=i^L115(@m z;gW7OlpBVQkh81?%0r5*gsQNI6tzLUoT{d5$D%qlb#+jYfl5ld`}{_WJ_Goxf~hp? z-MxIdy_0dpLYdSVUF8_XNdGybm)Bht9~O)T#tGL#onLgKT#+)NE3S$n>3||eeokfz zwL^|wP{*pHI-EXM&*ArSW(Bzv>_($H{h0ZKuYCs4PZ zuC$E21pz)k<#meIxb~j)D_kChq)E^!R(n9Eg->6dbuCst{@wjHPff04saI6B;qZsh zEt)>$(EYV!HJqu-Ls0H?a?ze^NSrzZdF6Huz*E(2Xs0>~`9191T#}*NWj0{oRR>XK zMuo>~glIUkiGwlWxU3&+D`piyyli~;{$i5l&>_YnpT8u?FC78nHW&*zaH;hd>ZGF=MLCMQFh$vdt@#g9XWyC#g5CO`8? z7$Z%_kHmn{wPUd@QX1t~~>k%j(OG6`tyY3urtpD1$mgc?&}BfLK06iICM_as-U2 zF27t^%hLn8as<}SEsm9R{M4E2p#bdVdI+@3n;>~m0_cMdPts2~s|Rgss}1bq@4#Md zQ41hY$I5OC9D&?F5ta7rXot#8a~haslL4%ix!N07Qz!43KRKCd$mGu;bx-n^Hf>?+ zo(ErAJ`Ff&RbjO+&dAp8G^{tiS57faW-9?WY;0*yH(3?xvz#bw!=6aMkOCm7VCVBI_UB=v0w-0ch<|c@{!^dTLIb2tGbS zE_>d&sE$UioI(BK@Ps>WRwG9!$34OQs@+A(|CV??rSU!mJ5k&2;gauvcaPrVv675@ zPuESucgridRG5>?I0*G}=xigYrtfd1t@$MC;W^?8m78%FVjRsQcnm(QavQ0n3{c-$ zTL8kojF~Vf3q#+B%NBsT*G?pzhhfTtHeE*8hE_*J(ehcym8Ci%GsjC4=Nowi`9IJY zy|6S#O?qszPddr!sQsS`P;*pSFD!J20bu48X1qI9@j;Y2SW@>t1H{W?0Fl?Dn2(t1 z`>~j*`*Jx*p4!xLRcz3}p%NxM?G79Qw&z2x8oAyvn$A%DJQ~yGmS=Pg(`Di!eT%2- zJz6JxNtb^^$K$n%T)&liMg36)A0FpC=L-1n*dvhqFA>s})b-H(M;Gy40iQDaf+YM0 z7(o*L^NSz}|Jy~7g#YQnD-nDkuIiys-1$Vu4YBm`1RY+q*YqOLcz|F;^DCh7xWF_6 zi>p~&NdzCF1ZY*)0zTQ`8C>UK1a#Rb%-mvHd;&9jE2i;40p}X+T=HbDYy=;$@MNwt zJ%@=M4>?>HMp~DHI+_d2=O&f(?V!$3_N|~Y6ira|tvzQerM(lmvtgVdc_#PlAgf*C z$*Xu^2Jb7IX~4-HDb zt=0oAq4z;Lc{WtrGhJEkd5ua@8?F4uFfuydk*K{`zK67ljio|ATBp6!l)H=oFcUYb90TJcn|JL!g z1w(AlO9f~l7hOBE(NbCl*8P06xo6VEzy;^tYLVC%u5#ysY1krUcztfljlSar+?o5_NoB5 zAErjHN2*Wto_U{!k?V)W*&c!5qrwSusFyuvjQ6kW>5A!Z0zzcV9YMwsvUV0-0hnc| z^_WR@ILE85QZXdHjtbe9!1T=sVF53;WL#AT4et3|d)_Tekqm+_)A`v&Y3UfPozki^ zxm7n%8*Scq7ft%gkk02?Yr4vZE=?zMZMB>M^1TzV+M^q>o2De92Wmt5YpD*JrW3`E znhxJf)3YkD5*BLpot6^NKTk#9cO!WYOnLC>qtcMZ&dtrEDQ$nIm954R|80R>2Lay} z+Cec)RUO#CdoHWje2hmW)eFDF)0wUwul&DUp32?-zCyMVNP1JDkEZ$WLgew!P!%oV zKO6B#YI$h&9)rq@zg-!G!x~Rk^{$0S!2g)iQ~TwAL1v=;Vme)AeSJBhc{aax8Dou$YdV z@R1vxNvXXUmNII)+J^BQi0B7i_gDlwB6J|4jz9EfhjT*Gj+Oefg|WsFaI;oDOFJ)D zwo{naYJ<-6j_QNQsQLW*>dPSY*R=e4s#5Wn7~mu2xZ_x8X{R_*{jr-IgPVYnPW1b$ z(`%Z|1R$xN#$?giSaCrOf=_YI95l4yi%dF?)lf}5uM)@N0h zUs^Tsw*>SA&w_d$2RKfkgNOqsj7Jufkx#&(%Fc-1QSvMJP#Zg{Dju|KuRGqmj|r;t z71Y0{%A^p%|36OiFV_iisq(7jZN>L}%Y9}K(g^&!;( zP1I@E2}!gQ0gSjvSp)&LemWASIsG3Rzbh#R72GG~7b6b@OA}=EGscYnS0~()&nNr8 z>jXvQzKXJ@k&!H~G^bU9Ugnia=V;!ccYgVMv+nAIWYg{X3bHm*RzJ_{A)QsdQQ5d; zEBdk_RGx!ggG|s@aRURaN`)N^lKgJGG}T%H*|cG{rHQ{ij22cF8r5 zHnOTIkZra))UdXdsgE$o!S2L{LHe{Cj+fakdCDb!Nb+Wgmz%$J+K2+;<+UPe5|i0~ zIpn?vYn$T@R^2)goa^u;Z@c2B9vV6w@jK1Gua|A9`^uY6~U z(1NQTWw(D_!*@LNnHHv8&eTh1J#fo4PyNrOXA!Nszx0vdjvaa*zx=k-vG?v%^*9=w zRo=&6y^n8sEZBb8ef+um_!`rL$H4#YIaS#atXj9Mz8+5N{xFp6Y&qmcmkfO(*lBJt z$7&yw^zoQXE{+k;-;v2DTyoG%bKR6GvxH-{%q9PD$<8GmgN=qvl+|Z7(z~|oW?61X zeG5Mg=%=BTpBvK1y7CF54&+Zh*vPs*f?vzrU@M%HTGW*Xk~{} z-$t%ble77VvYTr{h%{mHZe|ufDj)~J=<9JZsey6keirG;Z9YoW9{Cesf>~dtj>Ch$ z{#E&0cp8Fic4X@7W5tpi{^XYtoINr^n)a}S1I;XdhP;u>WEiIviX{B$msL%i&y97> za8TdZ@x*vQcmOa^@G`e0wHnnZC+`0souJ~q`ul(d?pNRUwR^DIi&qe=@j#e+3;Vwi zVs2#?AIkjJY$#)}s>LQ8}23zW=*IN@gX{x5(>DjXmNkI;hw;gz~D z3?AwIe-WTnJO?;mC#w#_OD=;I#advmsPCPX?0nljCB;1XQ?xkM{)f)X_6@{%*f+2- z{XA&p?;F^}ihEXn)pz5kCfG{jyPIE>8GMm=9!B{f0c?fWY4WRGYGU0Tr?Yg-X^JQ7 b;4GnXVDF~bg>o{+XaQ$m*t4lM<;wp9W{{-t diff --git a/examples/kvstore/main.go b/examples/kvstore/main.go index 459099b687..c2c56eba5f 100644 --- a/examples/kvstore/main.go +++ b/examples/kvstore/main.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/viper" - "github.com/tendermint/abci/server" + "github.com/tendermint/tendermint/abci/server" "github.com/tendermint/tmlibs/cli" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" diff --git a/server/constructors.go b/server/constructors.go index c91c67a18d..79e1558c4b 100644 --- a/server/constructors.go +++ b/server/constructors.go @@ -4,7 +4,7 @@ import ( "encoding/json" "path/filepath" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/server/init.go b/server/init.go index 7558a9779c..3bfe06e5fb 100644 --- a/server/init.go +++ b/server/init.go @@ -14,9 +14,9 @@ import ( "github.com/spf13/pflag" "github.com/spf13/viper" - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/go-crypto/keys" - "github.com/tendermint/go-crypto/keys/words" + "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/tendermint/tendermint/crypto" + cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" @@ -459,22 +459,17 @@ func SimpleAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState j func GenerateCoinKey() (sdk.Address, string, error) { // construct an in-memory key store - codec, err := words.LoadCodec("english") - if err != nil { - return nil, "", err - } keybase := keys.New( dbm.NewMemDB(), - codec, ) // generate a private key, with recovery phrase - info, secret, err := keybase.Create("name", "pass", keys.AlgoEd25519) + info, secret, err := keybase.CreateMnemonic("name", keys.English, "pass", keys.Secp256k1) if err != nil { return nil, "", err } - addr := info.PubKey.Address() - return addr, secret, nil + addr := info.GetPubKey().Address() + return sdk.Address(addr), secret, nil } // GenerateSaveCoinKey returns the address of a public key, along with the secret @@ -496,10 +491,10 @@ func GenerateSaveCoinKey(clientRoot, keyName, keyPass string, overwrite bool) (s } // generate a private key, with recovery phrase - info, secret, err := keybase.Create(keyName, keyPass, keys.AlgoEd25519) + info, secret, err := keybase.CreateMnemonic(keyName, keys.English, keyPass, keys.Secp256k1) if err != nil { return nil, "", err } - addr := info.PubKey.Address() - return addr, secret, nil + addr := info.GetPubKey().Address() + return sdk.Address(addr), secret, nil } diff --git a/server/mock/app.go b/server/mock/app.go index 42e8cf4b52..b2d19e2e9e 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -5,8 +5,8 @@ import ( "fmt" "path/filepath" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/server/mock/app_test.go b/server/mock/app_test.go index be1d778295..7c0b70da25 100644 --- a/server/mock/app_test.go +++ b/server/mock/app_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ) // TestInitApp makes sure we can initialize this thing without an error diff --git a/server/mock/helpers.go b/server/mock/helpers.go index a7a0001730..4510f4e905 100644 --- a/server/mock/helpers.go +++ b/server/mock/helpers.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "os" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tmlibs/log" ) diff --git a/server/start.go b/server/start.go index 82fcca08bb..a2cd57f929 100644 --- a/server/start.go +++ b/server/start.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/abci/server" + "github.com/tendermint/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" "github.com/tendermint/tendermint/node" @@ -88,6 +88,7 @@ func startInProcess(ctx *Context, appCreator AppCreator) error { proxy.NewLocalClientCreator(app), node.DefaultGenesisDocProviderFunc(cfg), node.DefaultDBProvider, + node.DefaultMetricsProvider, ctx.Logger.With("module", "node")) if err != nil { return err diff --git a/server/start_test.go b/server/start_test.go index c024546f5f..278c793cbd 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/server/mock" "github.com/cosmos/cosmos-sdk/wire" - "github.com/tendermint/abci/server" + "github.com/tendermint/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" "github.com/tendermint/tmlibs/log" ) diff --git a/store/iavlstore.go b/store/iavlstore.go index 865a22f0f3..31463e977e 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -4,8 +4,9 @@ import ( "fmt" "sync" - abci "github.com/tendermint/abci/types" + "github.com/tendermint/go-amino" "github.com/tendermint/iavl" + abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -171,7 +172,13 @@ func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) { break } res.Value = value - res.Proof = proof.Bytes() + cdc := amino.NewCodec() + p, err := cdc.MarshalBinary(proof) + if err != nil { + res.Log = err.Error() + break + } + res.Proof = p } else { _, res.Value = tree.GetVersioned(key, height) } diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index 25e8724c9a..25e08aefd9 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" "github.com/tendermint/iavl" + abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 4a97f0e288..11e089182f 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -6,7 +6,7 @@ import ( "golang.org/x/crypto/ripemd160" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/merkle" diff --git a/store/rootmultistore_test.go b/store/rootmultistore_test.go index f4164f0b54..89d40f761c 100644 --- a/store/rootmultistore_test.go +++ b/store/rootmultistore_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/merkle" diff --git a/types/abci.go b/types/abci.go index a46e797ebe..0646d21e32 100644 --- a/types/abci.go +++ b/types/abci.go @@ -1,6 +1,6 @@ package types -import abci "github.com/tendermint/abci/types" +import abci "github.com/tendermint/tendermint/abci/types" // initialize application state at genesis type InitChainer func(ctx Context, req abci.RequestInitChain) abci.ResponseInitChain diff --git a/types/account.go b/types/account.go index cbaf87beb8..bd7cbb29cd 100644 --- a/types/account.go +++ b/types/account.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tmlibs/bech32" cmn "github.com/tendermint/tmlibs/common" ) diff --git a/types/context.go b/types/context.go index 4184911526..276a664803 100644 --- a/types/context.go +++ b/types/context.go @@ -6,7 +6,7 @@ import ( "github.com/golang/protobuf/proto" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tmlibs/log" ) diff --git a/types/context_test.go b/types/context_test.go index f352fcf1ba..e5b31a9a74 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ) type MockLogger struct { diff --git a/types/errors.go b/types/errors.go index c818084270..392a954d16 100644 --- a/types/errors.go +++ b/types/errors.go @@ -5,7 +5,7 @@ import ( cmn "github.com/tendermint/tmlibs/common" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ) // ABCICodeType - combined codetype / codespace @@ -147,49 +147,80 @@ func ErrMemoTooLarge(msg string) Error { //---------------------------------------- // Error & sdkError +type cmnError = cmn.Error + // sdk Error type type Error interface { - Error() string + // Implements cmn.Error + // Error() string + // Stacktrace() cmn.Error + // Trace(offset int, format string, args ...interface{}) cmn.Error + // Data() interface{} + cmnError + + // convenience + TraceSDK(format string, args ...interface{}) Error + + // set codespace + WithDefaultCodespace(CodespaceType) Error + Code() CodeType Codespace() CodespaceType ABCILog() string ABCICode() ABCICodeType - WithDefaultCodespace(codespace CodespaceType) Error - Trace(msg string) Error - T() interface{} Result() Result QueryResult() abci.ResponseQuery } -// NewError - create an error -func NewError(codespace CodespaceType, code CodeType, msg string) Error { - return newError(codespace, code, msg) +// NewError - create an error. +func NewError(codespace CodespaceType, code CodeType, format string, args ...interface{}) Error { + return newError(codespace, code, format, args...) } -func newErrorWithRootCodespace(code CodeType, msg string) *sdkError { - return newError(CodespaceRoot, code, msg) +func newErrorWithRootCodespace(code CodeType, format string, args ...interface{}) *sdkError { + return newError(CodespaceRoot, code, format, args...) } -func newError(codespace CodespaceType, code CodeType, msg string) *sdkError { - if msg == "" { - msg = CodeToDefaultMsg(code) +func newError(codespace CodespaceType, code CodeType, format string, args ...interface{}) *sdkError { + if format == "" { + format = CodeToDefaultMsg(code) } return &sdkError{ codespace: codespace, code: code, - err: cmn.NewErrorWithT(code, msg), + cmnError: cmn.NewError(format, args...), } } type sdkError struct { codespace CodespaceType code CodeType - err cmn.Error + cmnError +} + +// Implements Error. +func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error { + codespace := err.codespace + if codespace == CodespaceUndefined { + codespace = cs + } + return &sdkError{ + codespace: cs, + code: err.code, + cmnError: err.cmnError, + } } // Implements ABCIError. +func (err *sdkError) TraceSDK(format string, args ...interface{}) Error { + err.Trace(1, format, args...) + return err +} + +// Implements ABCIError. +// Overrides err.Error.Error(). func (err *sdkError) Error() string { - return fmt.Sprintf("error{%d:%d,%#v}", err.codespace, err.code, err.err) + return fmt.Sprintf("Error{%d:%d,%#v}", err.codespace, err.code, err.cmnError) } // Implements ABCIError. @@ -215,33 +246,7 @@ Code: %v ABCICode: %v Error: %#v === /ABCI Log === -`, err.codespace, err.code, err.ABCICode(), err.err) -} - -// Add tracing information with msg. -func (err *sdkError) Trace(msg string) Error { - return &sdkError{ - codespace: err.codespace, - code: err.code, - err: err.err.Trace(msg), - } -} - -// Implements Error. -func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error { - codespace := err.codespace - if codespace == CodespaceUndefined { - codespace = cs - } - return &sdkError{ - codespace: codespace, - code: err.code, - err: err.err, - } -} - -func (err *sdkError) T() interface{} { - return err.err.T() +`, err.codespace, err.code, err.ABCICode(), err.cmnError) } func (err *sdkError) Result() Result { diff --git a/types/int.go b/types/int.go index 7d47070c3b..760fc607b5 100644 --- a/types/int.go +++ b/types/int.go @@ -1,6 +1,8 @@ package types import ( + "encoding/json" + "math/big" ) @@ -46,14 +48,25 @@ func unmarshalAmino(i *big.Int, text string) (err error) { return i.UnmarshalText([]byte(text)) } -// MarshalJSON for custom encodig scheme +// MarshalJSON for custom encoding scheme +// Must be encoded as a string for JSON precision func marshalJSON(i *big.Int) ([]byte, error) { - return i.MarshalText() + text, err := i.MarshalText() + if err != nil { + return nil, err + } + return json.Marshal(string(text)) } // UnmarshalJSON for custom decoding scheme +// Must be encoded as a string for JSON precision func unmarshalJSON(i *big.Int, bz []byte) error { - return i.UnmarshalText(bz) + var text string + err := json.Unmarshal(bz, &text) + if err != nil { + return err + } + return i.UnmarshalText([]byte(text)) } // Int wraps integer with 256 bit range bound diff --git a/types/lib/linear_test.go b/types/lib/linear_test.go index 26e5471b7a..8ee3276b5a 100644 --- a/types/lib/linear_test.go +++ b/types/lib/linear_test.go @@ -9,7 +9,7 @@ import ( dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/types/stake.go b/types/stake.go index d4e3b79ca9..0f0855b37f 100644 --- a/types/stake.go +++ b/types/stake.go @@ -1,8 +1,8 @@ package types import ( - abci "github.com/tendermint/abci/types" - "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" ) diff --git a/types/store.go b/types/store.go index 899b57015b..5aecd7d093 100644 --- a/types/store.go +++ b/types/store.go @@ -3,7 +3,7 @@ package types import ( "fmt" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" ) diff --git a/wire/wire.go b/wire/wire.go index d8420e8fa9..1d5291f860 100644 --- a/wire/wire.go +++ b/wire/wire.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/json" - "github.com/tendermint/go-amino" - "github.com/tendermint/go-crypto" + amino "github.com/tendermint/go-amino" + "github.com/tendermint/tendermint/crypto" ) // amino codec to marshal/unmarshal diff --git a/x/auth/account.go b/x/auth/account.go index 77966b8e74..2cee668688 100644 --- a/x/auth/account.go +++ b/x/auth/account.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) // Account is a standard account using a sequence number for replay protection diff --git a/x/auth/account_test.go b/x/auth/account_test.go index 150bc3ae59..55cef7cda5 100644 --- a/x/auth/account_test.go +++ b/x/auth/account_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index 417e10f2a1..2ddb96872e 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tmlibs/log" sdk "github.com/cosmos/cosmos-sdk/types" @@ -69,7 +69,11 @@ func newTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums sigs := make([]StdSignature, len(privs)) for i, priv := range privs { signBytes := StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, "") - sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), AccountNumber: accNums[i], Sequence: seqs[i]} + sig, err := priv.Sign(signBytes) + if err != nil { + panic(err) + } + sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig, AccountNumber: accNums[i], Sequence: seqs[i]} } tx := NewStdTx(msgs, fee, sigs, "") return tx @@ -79,7 +83,11 @@ func newTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, sigs := make([]StdSignature, len(privs)) for i, priv := range privs { signBytes := StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, memo) - sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), AccountNumber: accNums[i], Sequence: seqs[i]} + sig, err := priv.Sign(signBytes) + if err != nil { + panic(err) + } + sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig, AccountNumber: accNums[i], Sequence: seqs[i]} } tx := NewStdTx(msgs, fee, sigs, memo) return tx @@ -89,7 +97,11 @@ func newTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, func newTestTxWithSignBytes(msgs []sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee, signBytes []byte, memo string) sdk.Tx { sigs := make([]StdSignature, len(privs)) for i, priv := range privs { - sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), AccountNumber: accNums[i], Sequence: seqs[i]} + sig, err := priv.Sign(signBytes) + if err != nil { + panic(err) + } + sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig, AccountNumber: accNums[i], Sequence: seqs[i]} } tx := NewStdTx(msgs, fee, sigs, memo) return tx @@ -356,7 +368,7 @@ func TestAnteHandlerMemoGas(t *testing.T) { checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeOutOfGas) // tx with memo doesn't have enough gas - fee = NewStdFee(1001, sdk.NewCoin("atom", 0)) + fee = NewStdFee(801, sdk.NewCoin("atom", 0)) tx = newTestTxWithMemo(ctx, []sdk.Msg{msg}, privs, accnums, seqs, fee, "abcininasidniandsinasindiansdiansdinaisndiasndiadninsd") checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeOutOfGas) diff --git a/x/auth/context_test.go b/x/auth/context_test.go index f3ec278014..53ff7b1db6 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tmlibs/log" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/auth/feekeeper_test.go b/x/auth/feekeeper_test.go index 3b47277cee..a6ce8e3e5a 100644 --- a/x/auth/feekeeper_test.go +++ b/x/auth/feekeeper_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tmlibs/log" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/auth/mapper.go b/x/auth/mapper.go index 8ceba3e506..ae6a19137b 100644 --- a/x/auth/mapper.go +++ b/x/auth/mapper.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) var globalAccountNumberKey = []byte("globalAccountNumber") diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index 546f7ec92f..a5f96d5e90 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/x/auth/mock/app.go b/x/auth/mock/app.go index 880b5153e7..9c672b5a78 100644 --- a/x/auth/mock/app.go +++ b/x/auth/mock/app.go @@ -3,8 +3,8 @@ package mock import ( "os" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/x/auth/mock/auth_app_test.go b/x/auth/mock/auth_app_test.go index 8da93c9670..0a7a03534d 100644 --- a/x/auth/mock/auth_app_test.go +++ b/x/auth/mock/auth_app_test.go @@ -9,8 +9,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" ) // A mock transaction that has a validation which can fail. diff --git a/x/auth/mock/simulate_block.go b/x/auth/mock/simulate_block.go index 7e8f508433..00ffc30df1 100644 --- a/x/auth/mock/simulate_block.go +++ b/x/auth/mock/simulate_block.go @@ -8,9 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ) var chainID = "" // TODO @@ -44,9 +44,13 @@ func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyE sigs := make([]auth.StdSignature, len(priv)) memo := "testmemotestmemo" for i, p := range priv { + sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo)) + if err != nil { + panic(err) + } sigs[i] = auth.StdSignature{ PubKey: p.PubKey(), - Signature: p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo)), + Signature: sig, AccountNumber: accnums[i], Sequence: seq[i], } diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index 07b8671b7c..fd55eebb95 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -4,7 +4,7 @@ import ( "encoding/json" sdk "github.com/cosmos/cosmos-sdk/types" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) var _ sdk.Tx = (*StdTx)(nil) @@ -110,28 +110,32 @@ func (fee StdFee) Bytes() []byte { // and the Sequence numbers for each signature (prevent // inchain replay and enforce tx ordering per account). type StdSignDoc struct { - ChainID string `json:"chain_id"` - AccountNumber int64 `json:"account_number"` - Sequence int64 `json:"sequence"` - FeeBytes []byte `json:"fee_bytes"` - MsgsBytes []byte `json:"msg_bytes"` - Memo string `json:"memo"` + ChainID string `json:"chain_id"` + AccountNumber int64 `json:"account_number"` + Sequence int64 `json:"sequence"` + FeeBytes json.RawMessage `json:"fee_bytes"` + MsgsBytes json.RawMessage `json:"msg_bytes"` + Memo string `json:"memo"` } // StdSignBytes returns the bytes to sign for a transaction. // TODO: change the API to just take a chainID and StdTx ? func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs []sdk.Msg, memo string) []byte { - var msgBytes []byte + var msgsBytes []json.RawMessage for _, msg := range msgs { - msgBytes = append(msgBytes, msg.GetSignBytes()...) + msgsBytes = append(msgsBytes, json.RawMessage(msg.GetSignBytes())) + } + msgBytes, err := msgCdc.MarshalJSON(msgsBytes) + if err != nil { + panic(err) } - bz, err := json.Marshal(StdSignDoc{ + bz, err := msgCdc.MarshalJSON(StdSignDoc{ ChainID: chainID, AccountNumber: accnum, Sequence: sequence, - FeeBytes: fee.Bytes(), - MsgsBytes: msgBytes, + FeeBytes: json.RawMessage(fee.Bytes()), + MsgsBytes: json.RawMessage(msgBytes), Memo: memo, }) if err != nil { diff --git a/x/auth/stdtx_test.go b/x/auth/stdtx_test.go index e39459d39c..43712e5a5e 100644 --- a/x/auth/stdtx_test.go +++ b/x/auth/stdtx_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/bank/app_test.go b/x/bank/app_test.go index b38ef4a45d..2d6efc3ca1 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -10,8 +10,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/mock" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" ) // test bank module in a mock application diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index 97a5c45262..dce4d8fa95 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/mock" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ) func BenchmarkOneBankSendTxPerBlock(b *testing.B) { diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index 4598f07212..3dd7656ccc 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -1,12 +1,11 @@ package rest import ( - "encoding/json" "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/gorilla/mux" - "github.com/tendermint/go-crypto/keys" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" @@ -81,7 +80,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont } // build message - msg := client.BuildMsg(info.PubKey.Address(), to, m.Amount) + msg := client.BuildMsg(info.GetPubKey().Address(), to, m.Amount) if err != nil { // XXX rechecking same error ? w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) @@ -111,7 +110,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont return } - output, err := json.MarshalIndent(res, "", " ") + output, err := wire.MarshalJSONIndent(cdc, res) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index 4f8a75e1a5..2eae4e815c 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/x/bank/msgs.go b/x/bank/msgs.go index 48e62d8350..1a871979e2 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -27,28 +27,28 @@ func (msg MsgSend) ValidateBasic() sdk.Error { // this just makes sure all the inputs and outputs are properly formatted, // not that they actually have the money inside if len(msg.Inputs) == 0 { - return ErrNoInputs(DefaultCodespace).Trace("") + return ErrNoInputs(DefaultCodespace).TraceSDK("") } if len(msg.Outputs) == 0 { - return ErrNoOutputs(DefaultCodespace).Trace("") + return ErrNoOutputs(DefaultCodespace).TraceSDK("") } // make sure all inputs and outputs are individually valid var totalIn, totalOut sdk.Coins for _, in := range msg.Inputs { if err := in.ValidateBasic(); err != nil { - return err.Trace("") + return err.TraceSDK("") } totalIn = totalIn.Plus(in.Coins) } for _, out := range msg.Outputs { if err := out.ValidateBasic(); err != nil { - return err.Trace("") + return err.TraceSDK("") } totalOut = totalOut.Plus(out.Coins) } // make sure inputs and outputs match if !totalIn.IsEqual(totalOut) { - return sdk.ErrInvalidCoins(totalIn.String()).Trace("inputs and outputs don't match") + return sdk.ErrInvalidCoins(totalIn.String()).TraceSDK("inputs and outputs don't match") } return nil } @@ -107,11 +107,11 @@ func (msg MsgIssue) Type() string { return "bank" } // TODO: "bank/issue" func (msg MsgIssue) ValidateBasic() sdk.Error { // XXX if len(msg.Outputs) == 0 { - return ErrNoOutputs(DefaultCodespace).Trace("") + return ErrNoOutputs(DefaultCodespace).TraceSDK("") } for _, out := range msg.Outputs { if err := out.ValidateBasic(); err != nil { - return err.Trace("") + return err.TraceSDK("") } } return nil diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index e5cb759079..350a51d7aa 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -187,7 +187,7 @@ func TestMsgSendGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"denom":"atom","amount":10}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"denom":"atom","amount":10}]}]}` + expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"denom":"atom","amount":"10"}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"denom":"atom","amount":"10"}]}]}` assert.Equal(t, expected, string(res)) } @@ -257,7 +257,7 @@ func TestMsgIssueGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"denom":"atom","amount":10}]}]}` + expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"denom":"atom","amount":"10"}]}]}` assert.Equal(t, expected, string(res)) } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index f065ca616a..a47823ab32 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -6,12 +6,12 @@ import ( "strconv" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/gorilla/mux" "github.com/pkg/errors" - "github.com/tendermint/go-crypto/keys" ) // REST Variable names @@ -59,7 +59,7 @@ type voteReq struct { func postProposalHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req postProposalReq - err := buildReq(w, r, &req) + err := buildReq(w, r, cdc, &req) if err != nil { return } @@ -113,7 +113,7 @@ func depositHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) } var req depositReq - err = buildReq(w, r, &req) + err = buildReq(w, r, cdc, &req) if err != nil { return } @@ -161,7 +161,7 @@ func voteHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) ht } var req voteReq - err = buildReq(w, r, &req) + err = buildReq(w, r, cdc, &req) if err != nil { return } diff --git a/x/gov/client/rest/util.go b/x/gov/client/rest/util.go index 15af9038a0..341f0b0577 100644 --- a/x/gov/client/rest/util.go +++ b/x/gov/client/rest/util.go @@ -1,7 +1,6 @@ package rest import ( - "encoding/json" "io/ioutil" "net/http" @@ -20,13 +19,13 @@ type baseReq struct { Gas int64 `json:"gas"` } -func buildReq(w http.ResponseWriter, r *http.Request, req interface{}) error { +func buildReq(w http.ResponseWriter, r *http.Request, cdc *wire.Codec, req interface{}) error { body, err := ioutil.ReadAll(r.Body) if err != nil { writeErr(&w, http.StatusBadRequest, err.Error()) return err } - err = json.Unmarshal(body, &req) + err = cdc.UnmarshalJSON(body, req) if err != nil { writeErr(&w, http.StatusBadRequest, err.Error()) return err @@ -90,7 +89,7 @@ func signAndBuild(w http.ResponseWriter, ctx context.CoreContext, baseReq baseRe return } - output, err := json.MarshalIndent(res, "", " ") + output, err := wire.MarshalJSONIndent(cdc, res) if err != nil { writeErr(&w, http.StatusInternalServerError, err.Error()) return diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 96aa1e5e40..4aeac9417e 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ) func TestTickExpiredDepositPeriod(t *testing.T) { diff --git a/x/gov/keeper_test.go b/x/gov/keeper_test.go index fc8a632cc6..1033600e65 100644 --- a/x/gov/keeper_test.go +++ b/x/gov/keeper_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index ca5919dc22..171a2e2e9c 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/x/stake" ) diff --git a/x/gov/test_common.go b/x/gov/test_common.go index d602aad15e..743c5b6392 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/mock" diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go index 3e2e2fa120..077bc87bb6 100644 --- a/x/ibc/app_test.go +++ b/x/ibc/app_test.go @@ -11,8 +11,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/bank" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" ) // initialize the mock application for this module diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index 23b82923eb..cac0ca80b1 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -5,8 +5,8 @@ import ( "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/gorilla/mux" - "github.com/tendermint/go-crypto/keys" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" @@ -76,7 +76,7 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core to := sdk.Address(bz) // build message - packet := ibc.NewIBCPacket(info.PubKey.Address(), to, m.Amount, m.SrcChainID, destChainID) + packet := ibc.NewIBCPacket(info.GetPubKey().Address(), to, m.Amount, m.SrcChainID, destChainID) msg := ibc.IBCTransferMsg{packet} // add gas to context diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index a01dd51245..f292fabfe8 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/x/ibc/types.go b/x/ibc/types.go index 4924aec4b7..a311b98698 100644 --- a/x/ibc/types.go +++ b/x/ibc/types.go @@ -65,7 +65,7 @@ func (p IBCPacket) GetSignBytes() []byte { // validator the ibc packey func (p IBCPacket) ValidateBasic() sdk.Error { if p.SrcChain == p.DestChain { - return ErrIdenticalChains(DefaultCodespace).Trace("") + return ErrIdenticalChains(DefaultCodespace).TraceSDK("") } if !p.Coins.IsValid() { return sdk.ErrInvalidCoins("") diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 8d98cefe3e..52dd947493 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/x/stake" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" ) var ( diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index d5ae09ef22..1d62e6daff 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) // Keeper of the slashing store diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index fc0d3bc16a..2a722a2bad 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake" diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 0f3ee3f10c..2d192c54df 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/x/slashing/tick.go b/x/slashing/tick.go index eed083b9a9..43ffdb947c 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -5,7 +5,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" ) diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 9f1fa11200..a5cf47de50 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 41195f31b3..2b02533092 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" ) var ( diff --git a/x/stake/client/rest/rest.go b/x/stake/client/rest/rest.go index 1f3a2957d5..3528d45e4c 100644 --- a/x/stake/client/rest/rest.go +++ b/x/stake/client/rest/rest.go @@ -1,8 +1,8 @@ package rest import ( + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/gorilla/mux" - "github.com/tendermint/go-crypto/keys" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/wire" diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 47860318cb..1d85476622 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -2,13 +2,12 @@ package rest import ( "bytes" - "encoding/json" "fmt" "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/gorilla/mux" - "github.com/tendermint/go-crypto/keys" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/cosmos/cosmos-sdk/client/context" @@ -74,7 +73,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(err.Error())) return } - err = json.Unmarshal(body, &m) + err = cdc.UnmarshalJSON(body, &m) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) @@ -109,7 +108,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - if !bytes.Equal(info.Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return @@ -129,7 +128,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) return } - if !bytes.Equal(info.Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return @@ -180,7 +179,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - if !bytes.Equal(info.Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return @@ -200,7 +199,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) return } - if !bytes.Equal(info.Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return @@ -238,7 +237,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - if !bytes.Equal(info.Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return @@ -285,7 +284,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte results[i] = res } - output, err := json.MarshalIndent(results[:], "", " ") + output, err := wire.MarshalJSONIndent(cdc, results[:]) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) diff --git a/x/stake/handler.go b/x/stake/handler.go index 9555d270e6..15d52ea9c9 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -1,12 +1,11 @@ package stake import ( - abci "github.com/tendermint/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/keeper" "github.com/cosmos/cosmos-sdk/x/stake/tags" "github.com/cosmos/cosmos-sdk/x/stake/types" + abci "github.com/tendermint/tendermint/abci/types" ) func NewHandler(k keeper.Keeper) sdk.Handler { diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 80225fd510..61acc94d7f 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" keep "github.com/cosmos/cosmos-sdk/x/stake/keeper" diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 87dc511d61..667f5f681e 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -3,7 +3,7 @@ package keeper import ( "encoding/binary" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index dda6530eab..3abfe455cd 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -4,7 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) // NOTE the current slash functionality doesn't take into consideration unbonding/rebonding records diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 8460f78bcb..5a51a0e29f 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index b018aea449..75797c868c 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -4,8 +4,8 @@ import ( "bytes" "fmt" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index d5a568c39e..f8b8e67170 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -2,7 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) // name to idetify transaction types diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index e02ed8c97a..343ceb79f3 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) var ( diff --git a/x/stake/types/test_common.go b/x/stake/types/test_common.go index d98deaeb5e..1ecb10d6b9 100644 --- a/x/stake/types/test_common.go +++ b/x/stake/types/test_common.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" ) var ( diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index a9561a05fb..fcc7bf3925 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -4,8 +4,8 @@ import ( "bytes" "fmt" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" From c333050b59fa315dcd782bd5db555594de9780df Mon Sep 17 00:00:00 2001 From: Yanqing Yang Date: Fri, 29 Jun 2018 08:14:06 +0700 Subject: [PATCH 45/77] Repair link of QuickStart->Documentation which was broken by #1289 (#1444) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b4ebfde26..0383fded2a 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ See the [install instructions](/docs/install.md) ## Quick Start -- [Documentation](/docs/sdk) +- [Documentation](/docs) - [Examples](/examples) ## Disambiguation From 1d4d9e922fce76cbc99f3abd4a6b170ae7adb43a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 28 Jun 2018 23:21:43 -0400 Subject: [PATCH 46/77] simplify and complete app3 --- docs/core/app3.md | 87 ++++++++++++++++++++------- docs/core/examples/app3.go | 119 ++----------------------------------- 2 files changed, 70 insertions(+), 136 deletions(-) diff --git a/docs/core/app3.md b/docs/core/app3.md index 3dd2fdcf26..eeaddda9e6 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -15,14 +15,13 @@ working with accounts in the store. The `x/bank` module implements `Msg` and `Handler` - it has everything we need to transfer coins between accounts. -Applications that use `x/auth` and `x/bank` thus significantly reduce the amount -of work they have to do so they can focus on their application specific logic in -their own modules. +Here, we'll introduce the important types from `x/auth` and `x/bank`, and use +them to build `App3`, our shortest app yet. The complete code can be found in +[app3.go](examples/app3.go), and at the end of this section. -Here, we'll introduce the important types from `x/auth` and `x/bank`, and show -how to make `App3` by using them. The complete code can be found in [app3.go](examples/app3.go). For more details, see the -[x/auth](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth) and [x/bank](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank) API documentation. +[x/auth](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth) and +[x/bank](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank) API documentation. ## Accounts @@ -260,8 +259,8 @@ the same message could be executed over and over again. The PubKey is required for signature verification, but it is only required in the StdSignature once. From that point on, it will be stored in the account. -The fee is paid by the first address returned by `msg.GetSigners()` for the first `Msg`. -The convenience function `FeePayer(tx Tx) sdk.Address` is provided to return this. +The fee is paid by the first address returned by `msg.GetSigners()` for the first `Msg`, +as provided by the `FeePayer(tx Tx) sdk.Address` function. ## CoinKeeper @@ -269,10 +268,10 @@ Now that we've seen the `auth.AccountMapper` and how its used to build a complete AnteHandler, it's time to look at how to build higher-level abstractions for taking action on accounts. -Earlier, we noted that `Mappers` abstactions over a KVStore that handles marshalling and unmarshalling a -particular data type to and from the underlying store. We can build another -abstraction on top of `Mappers` that we call `Keepers`, which expose only -limitted functionality on the underlying types stored by the `Mapper`. +Earlier, we noted that `Mappers` are abstactions over KVStores that handle +marshalling and unmarshalling data types to and from underlying stores. +We can build another abstraction on top of `Mappers` that we call `Keepers`, +which expose only limitted functionality on the underlying types stored by the `Mapper`. For instance, the `x/bank` module defines the canonical versions of `MsgSend` and `MsgIssue` for the SDK, as well as a `Handler` for processing them. However, @@ -303,23 +302,69 @@ See the [bank.Keeper API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#Keeper) for the full set of methods. Note we can refine the `bank.Keeper` by restricting it's method set. For -instance, the `bank.ViewKeeper` is a read-only version, while the -`bank.SendKeeper` only executes transfers of coins from input accounts to output +instance, the +[bank.ViewKeeper](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#ViewKeeper) +is a read-only version, while the +[bank.SendKeeper](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#SendKeeper) +only executes transfers of coins from input accounts to output accounts. We use this `Keeper` paradigm extensively in the SDK as the way to define what kind of functionality each module gets access to. In particular, we try to -follow the *principle of least authority*, where modules only get access to the -absolutely narrowest set of functionality they need to get the job done. Hence, -rather than providing full blown access to the `KVStore` or the `AccountMapper`, +follow the *principle of least authority*. +Rather than providing full blown access to the `KVStore` or the `AccountMapper`, we restrict access to a small number of functions that do very specific things. ## App3 -Armed with an understanding of mappers and keepers, in particular the -`auth.AccountMapper` and the `bank.Keeper`, we're now ready to build `App3` -using the `x/auth` and `x/bank` modules to do all the heavy lifting: +With the `auth.AccountMapper` and `bank.Keeper` in hand, +we're now ready to build `App3`. +The `x/auth` and `x/bank` modules do all the heavy lifting: ```go -TODO +func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { + + // Create the codec with registered Msg types + cdc := NewCodec() + + // Create the base application object. + app := bapp.NewBaseApp(app3Name, cdc, logger, db) + + // Create a key for accessing the account store. + keyAccount := sdk.NewKVStoreKey("acc") + keyFees := sdk.NewKVStoreKey("fee") // TODO + + // Set various mappers/keepers to interact easily with underlying stores + accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) + coinKeeper := bank.NewKeeper(accountMapper) + feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) + + app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) + + // Register message routes. + // Note the handler gets access to + app.Router(). + AddRoute("send", bank.NewHandler(coinKeeper)) + + // Mount stores and load the latest state. + app.MountStoresIAVL(keyAccount, keyFees) + err := app.LoadLatestVersion(keyAccount) + if err != nil { + cmn.Exit(err.Error()) + } + return app +} ``` + +Note we use `bank.NewHandler`, which handles only `bank.MsgSend`, +and receives only the `bank.Keeper`. See the +[x/bank API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank) +for more details. + +## Conclusion + +Armed with native modules for authentication and coin transfer, +emboldened by the paradigm of mappers and keepers, +and ever invigorated by the desire to build secure state-machines, +we find ourselves here with a full-blown, all-checks-in-place, multi-asset +cryptocurrency - the beating heart of the Cosmos-SDK. diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index d916d235e5..d871a1cfd3 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -1,10 +1,6 @@ package app import ( - "bytes" - "encoding/json" - "fmt" - cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -29,132 +25,25 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") - keyMain := sdk.NewKVStoreKey("main") - keyFees := sdk.NewKVStoreKey("fee") + keyFees := sdk.NewKVStoreKey("fee") // TODO // Set various mappers/keepers to interact easily with underlying stores - // TODO: Need to register Account interface or use different Codec accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) coinKeeper := bank.NewKeeper(accountMapper) - infoMapper := newCoinInfoMapper(keyMain) feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) // Register message routes. - // Note the handler gets access to the account store. + // Note the handler gets access to app.Router(). - AddRoute("send", handleMsgSendWithKeeper(coinKeeper)). - AddRoute("issue", handleMsgIssueWithInfoMapper(infoMapper, coinKeeper)) + AddRoute("send", bank.NewHandler(coinKeeper)) // Mount stores and load the latest state. - app.MountStoresIAVL(keyAccount, keyMain, keyFees) + app.MountStoresIAVL(keyAccount, keyFees) err := app.LoadLatestVersion(keyAccount) if err != nil { cmn.Exit(err.Error()) } return app } - -func handleMsgSendWithKeeper(coinKeeper bank.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - sendMsg, ok := msg.(MsgSend) - if !ok { - return sdk.NewError(2, 1, "Send Message Malformed").Result() - } - - // Subtract coins from sender account - _, _, err := coinKeeper.SubtractCoins(ctx, sendMsg.From, sendMsg.Amount) - if err != nil { - // if error, return its result - return err.Result() - } - - // Add coins to receiver account - _, _, err = coinKeeper.AddCoins(ctx, sendMsg.To, sendMsg.Amount) - if err != nil { - // if error, return its result - return err.Result() - } - - return sdk.Result{ - Tags: sendMsg.Tags(), - } - } -} - -func handleMsgIssueWithInfoMapper(infoMapper coinInfoMapper, coinKeeper bank.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - issueMsg, ok := msg.(MsgIssue) - if !ok { - return sdk.NewError(2, 1, "Issue Message Malformed").Result() - } - - // Handle updating metadata - if res := handleCoinInfoWithMapper(ctx, infoMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { - return res - } - - // Add newly issued coins to output address - _, _, err := coinKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}) - if err != nil { - return err.Result() - } - - return sdk.Result{ - Tags: issueMsg.Tags(), - } - } -} - -func handleCoinInfoWithMapper(ctx sdk.Context, infoMapper CoinInfoMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result { - coinInfo := infoMapper.GetInfo(ctx, coin.Denom) - - // Metadata was created fresh, should set issuer to msg issuer - if len(coinInfo.Issuer) == 0 { - coinInfo.Issuer = issuer - } - - // Msg Issuer is not authorized to issue these coins - if !bytes.Equal(coinInfo.Issuer, issuer) { - return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() - } - - return sdk.Result{} -} - -//------------------------------------------------------------------ -// Mapper for CoinInfo - -// Example of a very simple user-defined read-only mapper interface. -type CoinInfoMapper interface { - GetInfo(sdk.Context, string) coinInfo -} - -// Implements CoinInfoMapper. -type coinInfoMapper struct { - key *sdk.KVStoreKey -} - -// Construct new CoinInfoMapper. -func newCoinInfoMapper(key *sdk.KVStoreKey) coinInfoMapper { - return coinInfoMapper{key: key} -} - -// Implements CoinInfoMapper. Returns info for coin. -func (cim coinInfoMapper) GetInfo(ctx sdk.Context, denom string) coinInfo { - store := ctx.KVStore(cim.key) - - infoBytes := store.Get([]byte(denom)) - if infoBytes == nil { - // TODO - } - - var coinInfo coinInfo - err := json.Unmarshal(infoBytes, &coinInfo) - if err != nil { - panic(err) - } - - return coinInfo -} From f405bdf76152469d30db440f71a58a20e7e7b013 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 29 Jun 2018 00:41:44 -0400 Subject: [PATCH 47/77] template app4.md. simplify app4.go --- docs/README.md | 18 +++-- docs/core/app1.md | 20 +++-- docs/core/app4.md | 73 +++++++++++++++++ docs/core/examples/app4.go | 162 +++---------------------------------- 4 files changed, 107 insertions(+), 166 deletions(-) diff --git a/docs/README.md b/docs/README.md index 341000a941..219166e904 100644 --- a/docs/README.md +++ b/docs/README.md @@ -31,13 +31,17 @@ NOTE: This documentation is a work-in-progress! verifies `StdTx`, manages accounts, and deducts fees - [bank.CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin transfers on an underlying AccountMapper - - [App4 - Validator Set Changes](core/app4.md) - - [InitChain](core/app4.md#init-chain) - Initialize the application - state - - [BeginBlock](core/app4.md#begin-block) - BeginBlock logic runs at the - beginning of every block - - [EndBlock](core/app4.md#end-block) - EndBlock logic runs at the - end of every block + - [App4 - ABCI](core/app4.md) + - [ABCI](core/app4.md#abci) - ABCI is the interface between Tendermint + and the Cosmos-SDK + - [InitChain](core/app4.md#initchain) - Initialize the application + store + - [BeginBlock](core/app4.md#beginblock) - BeginBlock runs at the + beginning of every block and updates the app about validator behaviour + - [EndBlock](core/app4.md#endblock) - EndBlock runs at the + end of every block and lets the app change the validator set. + - [Query](core/app4.md#query) - Query the application store + - [CheckTx](core/app4.md#checktx) - CheckTx only runs the AnteHandler - [App5 - Basecoin](core/app5.md) - - [Directory Structure](core/app5.md#directory-structure) - Keep your application code organized diff --git a/docs/core/app1.md b/docs/core/app1.md index ef56b50813..ac07e4755d 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -464,14 +464,18 @@ Since we only have one store, we only mount one. ## Execution -We're now done the core logic of the app! From here, we could write transactions -in Go and execute them against the application using the `app.DeliverTx` method. -In a real setup, the app would run as an ABCI application and -would be driven by blocks of transactions from the Tendermint consensus engine. -Later in the tutorial, we'll connect our app to a complete suite of components -for running and using a live blockchain application. For complete details on -how ABCI applications work, see the [ABCI -documentation](https://github.com/tendermint/abci/blob/master/specification.md). +We're now done the core logic of the app! From here, we can write tests in Go +that initialize the store with accounts and execute transactions by calling +the `app.DeliverTx` method. + +In a real setup, the app would run as an ABCI application on top of the +Tendermint consensus engine. It would be initialized by a Genesis file, and it +would be driven by blocks of transactions committed by the underlying Tendermint +consensus. We'll talk more about ABCI and how this all works a bit later, but +feel free to check the +[specification](https://github.com/tendermint/abci/blob/master/specification.md). +We'll also see how to connect our app to a complete suite of components +for running and using a live blockchain application. For now, we note the follow sequence of events occurs when a transaction is received (through `app.DeliverTx`): diff --git a/docs/core/app4.md b/docs/core/app4.md index e69de29bb2..d5d70bc3f4 100644 --- a/docs/core/app4.md +++ b/docs/core/app4.md @@ -0,0 +1,73 @@ +# ABCI + +The Application BlockChain Interface, or ABCI, is a powerfully +delineated boundary between the Cosmos-SDK and Tendermint. +It separates the logical state transition machine of your application from +its secure replication across many physical machines. + +By providing a clear, language agnostic boundary between applications and consensus, +ABCI provides tremendous developer flexibility and [support in many +languages](https://tendermint.com/ecosystem). That said, it is still quite a low-level protocol, and +requires frameworks to be built to abstract over that low-level componentry. +The Cosmos-SDK is one such framework. + +While we've already seen `DeliverTx`, the workhorse of any ABCI application, +here we will introduce the other ABCI requests sent by Tendermint, and +how we can use them to build more advanced applications. For a more complete +depiction of the ABCI and how its used, see +[the +specification](https://github.com/tendermint/abci/blob/master/specification.md) + +## InitChain + +In our previous apps, we built out all the core logic, but we never specified +how the store should be initialized. For that, we use the `app.InitChain` method, +which is called once by Tendermint the very first time the application boots up. + +The InitChain request contains a variety of Tendermint information, like the consensus +parameters and an initial validator set, but it also contains an opaque blob of +application specific bytes - typically JSON encoded. +Apps can decide what to do with all of this information by calling the +`app.SetInitChainer` method. + +For instance, let's introduce a `GenesisAccount` struct that can be JSON encoded +and part of a genesis file. Then we can populate the store with such accounts +during InitChain: + +```go +TODO +``` + +If we include a correctly formatted `GenesisAccount` in our Tendermint +genesis.json file, the store will be initialized with those accounts and they'll +be able to send transactions! + +## BeginBlock + +BeginBlock is called at the beginning of each block, before processing any +transactions with DeliverTx. +It contains information on what validators have signed. + +## EndBlock + +EndBlock is called at the end of each block, after processing all transactions +with DeliverTx. +It allows the application to return updates to the validator set. + +## Commit + +Commit is called after EndBlock. It persists the application state and returns +the Merkle root hash to be included in the next Tendermint block. The root hash +can be in Query for Merkle proofs of the state. + +## Query + +Query allows queries into the application store according to a path. + +## CheckTx + +CheckTx is used for the mempool. It only runs the AnteHandler. This is so +potentially expensive message handling doesn't begin until the transaction has +actually been committed in a block. The AnteHandler authenticates the sender and +ensures they have enough to pay the fee for the transaction. If the transaction +later fails, the sender still pays the fee. diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index 5494e1bd2d..0b27688549 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -1,11 +1,6 @@ package app import ( - "bytes" - "encoding/json" - "fmt" - "reflect" - abci "github.com/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -31,28 +26,27 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") - keyMain := sdk.NewKVStoreKey("main") - keyFees := sdk.NewKVStoreKey("fee") // Set various mappers/keepers to interact easily with underlying stores accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) - accountKeeper := bank.NewKeeper(accountMapper) - metadataMapper := NewApp4MetaDataMapper(keyMain) + coinKeeper := bank.NewKeeper(accountMapper) + + // TODO + keyFees := sdk.NewKVStoreKey("fee") feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper)) // Set InitChainer - app.SetInitChainer(NewInitChainer(cdc, accountMapper, metadataMapper)) + app.SetInitChainer(NewInitChainer(cdc, accountMapper)) // Register message routes. // Note the handler gets access to the account store. app.Router(). - AddRoute("send", betterHandleMsgSend(accountKeeper)). - AddRoute("issue", evenBetterHandleMsgIssue(metadataMapper, accountKeeper)) + AddRoute("send", bank.NewHandler(coinKeeper)) // Mount stores and load the latest state. - app.MountStoresIAVL(keyAccount, keyMain, keyFees) + app.MountStoresIAVL(keyAccount, keyFees) err := app.LoadLatestVersion(keyAccount) if err != nil { cmn.Exit(err.Error()) @@ -60,10 +54,9 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { return app } -// Application state at Genesis has accounts with starting balances and coins with starting metadata +// Application state at Genesis has accounts with starting balances type GenesisState struct { Accounts []*GenesisAccount `json:"accounts"` - Coins []*GenesisCoin `json:"coins"` } // GenesisAccount doesn't need pubkey or sequence @@ -81,160 +74,27 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount, err error) { return &baseAcc, nil } -// GenesisCoin enforces CurrentSupply is 0 at genesis. -type GenesisCoin struct { - Denom string `json:"denom"` - Issuer sdk.Address `json:"issuer"` - TotalSupply sdk.Int `json:"total_supply` - Decimal uint64 `json:"decimals"` -} - -// Converts GenesisCoin to its denom and metadata for storage in main store -func (gc *GenesisCoin) ToMetaData() (string, CoinMetadata) { - return gc.Denom, CoinMetadata{ - Issuer: gc.Issuer, - TotalSupply: gc.TotalSupply, - Decimal: gc.Decimal, - } -} - // InitChainer will set initial balances for accounts as well as initial coin metadata // MsgIssue can no longer be used to create new coin -func NewInitChainer(cdc *wire.Codec, accountMapper auth.AccountMapper, metadataMapper MetaDataMapper) sdk.InitChainer { +func NewInitChainer(cdc *wire.Codec, accountMapper auth.AccountMapper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { stateJSON := req.AppStateBytes genesisState := new(GenesisState) err := cdc.UnmarshalJSON(stateJSON, genesisState) if err != nil { - panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 - // return sdk.ErrGenesisParse("").TraceCause(err, "") + panic(err) } for _, gacc := range genesisState.Accounts { acc, err := gacc.ToAccount() if err != nil { - panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 - // return sdk.ErrGenesisParse("").TraceCause(err, "") + panic(err) } acc.AccountNumber = accountMapper.GetNextAccountNumber(ctx) accountMapper.SetAccount(ctx, acc) } - // Initialize coin metadata. - for _, gc := range genesisState.Coins { - denom, metadata := gc.ToMetaData() - metadataMapper.SetMetaData(ctx, denom, metadata) - } - return abci.ResponseInitChain{} - } } - -//--------------------------------------------------------------------------------------------- -// Now that initializing coin metadata is done in InitChainer we can simplify handleMsgIssue - -// New MsgIssue handler will no longer generate coin metadata on the fly. -// Allows issuers (permissioned at genesis) to issue coin to receiver. -func evenBetterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - issueMsg, ok := msg.(MsgIssue) - if !ok { - return sdk.NewError(2, 1, "Issue Message Malformed").Result() - } - - // Handle updating metadata - if res := evenBetterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() { - return res - } - - // Add newly issued coins to output address - _, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}) - if err != nil { - return err.Result() - } - - return sdk.Result{ - // Return result with Issue msg tags - Tags: issueMsg.Tags(), - } - } -} - -// No longer generates metadata on the fly. -// Returns error result when it cannot find coin metadata -func evenBetterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result { - metadata := metadataMapper.GetMetaData(ctx, coin.Denom) - - // Coin metadata does not exist in store - if reflect.DeepEqual(metadata, CoinMetadata{}) { - return sdk.ErrInvalidCoins(fmt.Sprintf("Cannot find metadata for coin: %s", coin.Denom)).Result() - } - - // Msg Issuer not authorized to issue these coins - if !bytes.Equal(metadata.Issuer, issuer) { - return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result() - } - - // Update current circulating supply - metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount) - - // Current supply cannot exceed total supply - if metadata.TotalSupply.LT(metadata.CurrentSupply) { - return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result() - } - - metadataMapper.SetMetaData(ctx, coin.Denom, metadata) - return sdk.Result{} -} - -//--------------------------------------------------------------------------------------------- -// Simpler MetaDataMapper no longer able to initialize default CoinMetaData - -// Implements MetaDataMapper -type App4MetaDataMapper struct { - mainKey *sdk.KVStoreKey -} - -// Constructs new App4MetaDataMapper -func NewApp4MetaDataMapper(key *sdk.KVStoreKey) App4MetaDataMapper { - return App4MetaDataMapper{mainKey: key} -} - -// Returns coin Metadata. If metadata not found in store, function returns empty struct. -func (mdm App4MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata { - store := ctx.KVStore(mdm.mainKey) - - bz := store.Get([]byte(denom)) - if bz == nil { - // Coin metadata doesn't exist, create new metadata with default params - return CoinMetadata{} - } - - var metadata CoinMetadata - err := json.Unmarshal(bz, &metadata) - if err != nil { - panic(err) - } - - return metadata -} - -// Sets metadata in store with key equal to coin denom. Same behavior as App3 implementation. -func (mdm App4MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) { - store := ctx.KVStore(mdm.mainKey) - - val, err := json.Marshal(metadata) - if err != nil { - panic(err) - } - - store.Set([]byte(denom), val) -} - -//------------------------------------------------------------------ -// AccountMapper - -//------------------------------------------------------------------ -// CoinsKeeper From 12a180786ad5dc2661f3fd193f88bdea8edb48e1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 29 Jun 2018 01:31:06 -0400 Subject: [PATCH 48/77] started app5 --- docs/README.md | 6 ++-- docs/core/app5.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 docs/core/app5.md diff --git a/docs/README.md b/docs/README.md index 219166e904..cf4494003a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -29,7 +29,7 @@ NOTE: This documentation is a work-in-progress! information - [auth.AnteHandler](core/app3.md#antehandler) - The `AnteHandler` verifies `StdTx`, manages accounts, and deducts fees - - [bank.CoinKeeper](core/app3.md#coin-keeper) - CoinKeeper allows for coin + - [bank.CoinKeeper](core/app3.md#coinkeeper) - CoinKeeper allows for coin transfers on an underlying AccountMapper - [App4 - ABCI](core/app4.md) - [ABCI](core/app4.md#abci) - ABCI is the interface between Tendermint @@ -45,7 +45,9 @@ NOTE: This documentation is a work-in-progress! - [App5 - Basecoin](core/app5.md) - - [Directory Structure](core/app5.md#directory-structure) - Keep your application code organized - - [Clients](core/app5.md#clients) - Hook up your app to standard CLI and REST + - [Tendermint Node](core/app5.md#tendermint-node) - Run a full + blockchain node with your app + - [Clients](core/app5.md#clients) - Hook up your app to CLI and REST interfaces for clients to use! - [Modules](modules) diff --git a/docs/core/app5.md b/docs/core/app5.md new file mode 100644 index 0000000000..c6011f0425 --- /dev/null +++ b/docs/core/app5.md @@ -0,0 +1,72 @@ +# App5 - Basecoin + +As we've seen, the SDK provides a flexible yet comprehensive framework for building state +machines and defining their transitions, including authenticating transactions, +executing messages, controlling access to stores, and updating the validator set. + +Until now, we have focused on building only isolated ABCI applications to +demonstrate and explain the various features and flexibilities of the SDK. +Here, we'll connect our ABCI application to Tendermint so we can run a full +blockchain node, and introduce command line and HTTP interfaces for interacting with it. + +But first, let's talk about how source code should be laid out. + +## Directory Structure + +TODO + +## Tendermint Node + +Since the Cosmos-SDK is written in Go, Cosmos-SDK applications can be compiled +with Tendermint into a single binary. Of course, like any ABCI application, they +can also run as separate processes that communicate with Tendermint via socket. + +For more details on what's involved in starting a Tendermint full node, see the +[NewNode](https://godoc.org/github.com/tendermint/tendermint/node#NewNode) +function in `github.com/tendermint/tendermint/node`. + +The `server` package in the Cosmos-SDK simplifies +connecting an application with a Tendermint node. +For instance, the following `main.go` file will give us a complete full node +using the Basecoin application we built: + +```go +//TODO imports + +func main() { + cdc := app.MakeCodec() + ctx := server.NewDefaultContext() + + rootCmd := &cobra.Command{ + Use: "basecoind", + Short: "Basecoin Daemon (server)", + PersistentPreRunE: server.PersistentPreRunEFn(ctx), + } + + server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, + server.ConstructAppCreator(newApp, "basecoin")) + + // prepare and add flags + rootDir := os.ExpandEnv("$HOME/.basecoind") + executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) + executor.Execute() +} + +func newApp(logger log.Logger, db dbm.DB) abci.Application { + return app.NewBasecoinApp(logger, db) +} +``` + +Note we utilize the popular [cobra library](https://github.com/spf13/cobra) +for the CLI, in concert with the [viper library](https://github.com/spf13/library) +for managing configuration. See our [cli library](https://github.com/tendermint/tmlibs/blob/master/cli/setup.go) +for more details. + +TODO: compile and run the binary + +Options for running the `basecoind` binary are effectively the same as for `tendermint`. +See [Using Tendermint](TODO) for more details. + +## Clients + +TODO From 822ebdb5019de7fa4c5ffe22c16beebcf8c4bb83 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 29 Jun 2018 01:53:43 -0400 Subject: [PATCH 49/77] cleanup _attic --- docs/_attic/basecoin/basics.rst | 289 --------------- docs/_attic/basecoin/extensions.rst | 215 ----------- docs/_attic/glossary.rst | 230 ------------ docs/_attic/ibc.rst | 424 ---------------------- docs/_attic/keys.md | 119 ------ docs/_attic/replay-protection.rst | 38 -- docs/_attic/staking/intro.rst | 402 ++++++++++++++++++++ docs/_attic/staking/key-management.rst | 204 ----------- docs/_attic/staking/local-testnet.rst | 83 ----- docs/_attic/staking/overview.md | 216 +++++++++++ docs/_attic/staking/public-testnet.rst | 64 ---- docs/_attic/{ => staking}/stakingSpec1.md | 0 docs/_attic/{ => staking}/stakingSpec2.md | 0 docs/_attic/staking/testnet.md | 94 +++++ 14 files changed, 712 insertions(+), 1666 deletions(-) delete mode 100644 docs/_attic/basecoin/basics.rst delete mode 100644 docs/_attic/basecoin/extensions.rst delete mode 100644 docs/_attic/glossary.rst delete mode 100644 docs/_attic/ibc.rst delete mode 100644 docs/_attic/keys.md delete mode 100644 docs/_attic/replay-protection.rst create mode 100644 docs/_attic/staking/intro.rst delete mode 100644 docs/_attic/staking/key-management.rst delete mode 100644 docs/_attic/staking/local-testnet.rst create mode 100644 docs/_attic/staking/overview.md delete mode 100644 docs/_attic/staking/public-testnet.rst rename docs/_attic/{ => staking}/stakingSpec1.md (100%) rename docs/_attic/{ => staking}/stakingSpec2.md (100%) create mode 100644 docs/_attic/staking/testnet.md diff --git a/docs/_attic/basecoin/basics.rst b/docs/_attic/basecoin/basics.rst deleted file mode 100644 index 3b61dd6e55..0000000000 --- a/docs/_attic/basecoin/basics.rst +++ /dev/null @@ -1,289 +0,0 @@ -Basecoin Basics -=============== - -Here we explain how to get started with a basic Basecoin blockchain, how -to send transactions between accounts using the ``basecoin`` tool, and -what is happening under the hood. - -Install -------- - -With go, it's one command: - -:: - - go get -u github.com/cosmos/cosmos-sdk - -If you have trouble, see the `installation guide <./install.html>`__. - -TODO: update all the below - -Generate some keys -~~~~~~~~~~~~~~~~~~ - -Let's generate two keys, one to receive an initial allocation of coins, -and one to send some coins to later: - -:: - - basecli keys new cool - basecli keys new friend - -You'll need to enter passwords. You can view your key names and -addresses with ``basecli keys list``, or see a particular key's address -with ``basecli keys get ``. - -Initialize Basecoin -------------------- - -To initialize a new Basecoin blockchain, run: - -:: - - basecoin init
- -If you prefer not to copy-paste, you can provide the address -programatically: - -:: - - basecoin init $(basecli keys get cool | awk '{print $2}') - -This will create the necessary files for a Basecoin blockchain with one -validator and one account (corresponding to your key) in -``~/.basecoin``. For more options on setup, see the `guide to using the -Basecoin tool `__. - -If you like, you can manually add some more accounts to the blockchain -by generating keys and editing the ``~/.basecoin/genesis.json``. - -Start Basecoin -~~~~~~~~~~~~~~ - -Now we can start Basecoin: - -:: - - basecoin start - -You should see blocks start streaming in! - -Initialize Light-Client ------------------------ - -Now that Basecoin is running we can initialize ``basecli``, the -light-client utility. Basecli is used for sending transactions and -querying the state. Leave Basecoin running and open a new terminal -window. Here run: - -:: - - basecli init --node=tcp://localhost:26657 --genesis=$HOME/.basecoin/genesis.json - -If you provide the genesis file to basecli, it can calculate the proper -chainID and validator hash. Basecli needs to get this information from -some trusted source, so all queries done with ``basecli`` can be -cryptographically proven to be correct according to a known validator -set. - -Note: that ``--genesis`` only works if there have been no validator set -changes since genesis. If there are validator set changes, you need to -find the current set through some other method. - -Send transactions -~~~~~~~~~~~~~~~~~ - -Now we are ready to send some transactions. First Let's check the -balance of the two accounts we setup earlier: - -:: - - ME=$(basecli keys get cool | awk '{print $2}') - YOU=$(basecli keys get friend | awk '{print $2}') - basecli query account $ME - basecli query account $YOU - -The first account is flush with cash, while the second account doesn't -exist. Let's send funds from the first account to the second: - -:: - - basecli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1 - -Now if we check the second account, it should have ``1000`` 'mycoin' -coins! - -:: - - basecli query account $YOU - -We can send some of these coins back like so: - -:: - - basecli tx send --name=friend --amount=500mycoin --to=$ME --sequence=1 - -Note how we use the ``--name`` flag to select a different account to -send from. - -If we try to send too much, we'll get an error: - -:: - - basecli tx send --name=friend --amount=500000mycoin --to=$ME --sequence=2 - -Let's send another transaction: - -:: - - basecli tx send --name=cool --amount=2345mycoin --to=$YOU --sequence=2 - -Note the ``hash`` value in the response - this is the hash of the -transaction. We can query for the transaction by this hash: - -:: - - basecli query tx - -See ``basecli tx send --help`` for additional details. - -Proof ------ - -Even if you don't see it in the UI, the result of every query comes with -a proof. This is a Merkle proof that the result of the query is actually -contained in the state. And the state's Merkle root is contained in a -recent block header. Behind the scenes, ``countercli`` will not only -verify that this state matches the header, but also that the header is -properly signed by the known validator set. It will even update the -validator set as needed, so long as there have not been major changes -and it is secure to do so. So, if you wonder why the query may take a -second... there is a lot of work going on in the background to make sure -even a lying full node can't trick your client. - -Accounts and Transactions -------------------------- - -For a better understanding of how to further use the tools, it helps to -understand the underlying data structures. - -Accounts -~~~~~~~~ - -The Basecoin state consists entirely of a set of accounts. Each account -contains a public key, a balance in many different coin denominations, -and a strictly increasing sequence number for replay protection. This -type of account was directly inspired by accounts in Ethereum, and is -unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). Note -Basecoin is a multi-asset cryptocurrency, so each account can have many -different kinds of tokens. - -:: - - type Account struct { - PubKey crypto.PubKey `json:"pub_key"` // May be nil, if not known. - Sequence int `json:"sequence"` - Balance Coins `json:"coins"` - } - - type Coins []Coin - - type Coin struct { - Denom string `json:"denom"` - Amount int64 `json:"amount"` - } - -If you want to add more coins to a blockchain, you can do so manually in -the ``~/.basecoin/genesis.json`` before you start the blockchain for the -first time. - -Accounts are serialized and stored in a Merkle tree under the key -``base/a/
``, where ``
`` is the address of the account. -Typically, the address of the account is the 20-byte ``RIPEMD160`` hash -of the public key, but other formats are acceptable as well, as defined -in the `Tendermint crypto -library `__. The Merkle tree -used in Basecoin is a balanced, binary search tree, which we call an -`IAVL tree `__. - -Transactions -~~~~~~~~~~~~ - -Basecoin defines a transaction type, the ``SendTx``, which allows tokens -to be sent to other accounts. The ``SendTx`` takes a list of inputs and -a list of outputs, and transfers all the tokens listed in the inputs -from their corresponding accounts to the accounts listed in the output. -The ``SendTx`` is structured as follows: - -:: - - type SendTx struct { - Gas int64 `json:"gas"` - Fee Coin `json:"fee"` - Inputs []TxInput `json:"inputs"` - Outputs []TxOutput `json:"outputs"` - } - - type TxInput struct { - Address []byte `json:"address"` // Hash of the PubKey - Coins Coins `json:"coins"` // - Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput - Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx - PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0 - } - - type TxOutput struct { - Address []byte `json:"address"` // Hash of the PubKey - Coins Coins `json:"coins"` // - } - -Note the ``SendTx`` includes a field for ``Gas`` and ``Fee``. The -``Gas`` limits the total amount of computation that can be done by the -transaction, while the ``Fee`` refers to the total amount paid in fees. -This is slightly different from Ethereum's concept of ``Gas`` and -``GasPrice``, where ``Fee = Gas x GasPrice``. In Basecoin, the ``Gas`` -and ``Fee`` are independent, and the ``GasPrice`` is implicit. - -In Basecoin, the ``Fee`` is meant to be used by the validators to inform -the ordering of transactions, like in Bitcoin. And the ``Gas`` is meant -to be used by the application plugin to control its execution. There is -currently no means to pass ``Fee`` information to the Tendermint -validators, but it will come soon... - -Note also that the ``PubKey`` only needs to be sent for -``Sequence == 0``. After that, it is stored under the account in the -Merkle tree and subsequent transactions can exclude it, using only the -``Address`` to refer to the sender. Ethereum does not require public -keys to be sent in transactions as it uses a different elliptic curve -scheme which enables the public key to be derived from the signature -itself. - -Finally, note that the use of multiple inputs and multiple outputs -allows us to send many different types of tokens between many different -accounts at once in an atomic transaction. Thus, the ``SendTx`` can -serve as a basic unit of decentralized exchange. When using multiple -inputs and outputs, you must make sure that the sum of coins of the -inputs equals the sum of coins of the outputs (no creating money), and -that all accounts that provide inputs have signed the transaction. - -Clean Up --------- - -**WARNING:** Running these commands will wipe out any existing -information in both the ``~/.basecli`` and ``~/.basecoin`` directories, -including private keys. - -To remove all the files created and refresh your environment (e.g., if -starting this tutorial again or trying something new), the following -commands are run: - -:: - - basecli reset_all - rm -rf ~/.basecoin - -In this guide, we introduced the ``basecoin`` and ``basecli`` tools, -demonstrated how to start a new basecoin blockchain and how to send -tokens between accounts, and discussed the underlying data types for -accounts and transactions, specifically the ``Account`` and the -``SendTx``. diff --git a/docs/_attic/basecoin/extensions.rst b/docs/_attic/basecoin/extensions.rst deleted file mode 100644 index 6f31222def..0000000000 --- a/docs/_attic/basecoin/extensions.rst +++ /dev/null @@ -1,215 +0,0 @@ -Basecoin Extensions -=================== - -TODO: re-write for extensions - -In the `previous guide `__, we saw how to use the -``basecoin`` tool to start a blockchain and the ``basecli`` tools to -send transactions. We also learned about ``Account`` and ``SendTx``, the -basic data types giving us a multi-asset cryptocurrency. Here, we will -demonstrate how to extend the tools to use another transaction type, the -``AppTx``, so we can send data to a custom plugin. In this example we -explore a simple plugin named ``counter``. - -Example Plugin --------------- - -The design of the ``basecoin`` tool makes it easy to extend for custom -functionality. The Counter plugin is bundled with basecoin, so if you -have already `installed basecoin `__ and run -``make install`` then you should be able to run a full node with -``counter`` and the a light-client ``countercli`` from terminal. The -Counter plugin is just like the ``basecoin`` tool. They both use the -same library of commands, including one for signing and broadcasting -``SendTx``. - -Counter transactions take two custom inputs, a boolean argument named -``valid``, and a coin amount named ``countfee``. The transaction is only -accepted if both ``valid`` is set to true and the transaction input -coins is greater than ``countfee`` that the user provides. - -A new blockchain can be initialized and started just like in the -`previous guide `__: - -:: - - # WARNING: this wipes out data - but counter is only for demos... - rm -rf ~/.counter - countercli reset_all - - countercli keys new cool - countercli keys new friend - - counter init $(countercli keys get cool | awk '{print $2}') - - counter start - -The default files are stored in ``~/.counter``. In another window we can -initialize the light-client and send a transaction: - -:: - - countercli init --node=tcp://localhost:26657 --genesis=$HOME/.counter/genesis.json - - YOU=$(countercli keys get friend | awk '{print $2}') - countercli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1 - -But the Counter has an additional command, ``countercli tx counter``, -which crafts an ``AppTx`` specifically for this plugin: - -:: - - countercli tx counter --name cool - countercli tx counter --name cool --valid - -The first transaction is rejected by the plugin because it was not -marked as valid, while the second transaction passes. We can build -plugins that take many arguments of different types, and easily extend -the tool to accomodate them. Of course, we can also expose queries on -our plugin: - -:: - - countercli query counter - -Tada! We can now see that our custom counter plugin transactions went -through. You should see a Counter value of 1 representing the number of -valid transactions. If we send another transaction, and then query -again, we will see the value increment. Note that we need the sequence -number here to send the coins (it didn't increment when we just pinged -the counter) - -:: - - countercli tx counter --name cool --countfee=2mycoin --sequence=2 --valid - countercli query counter - -The Counter value should be 2, because we sent a second valid -transaction. And this time, since we sent a countfee (which must be less -than or equal to the total amount sent with the tx), it stores the -``TotalFees`` on the counter as well. - -Keep it mind that, just like with ``basecli``, the ``countercli`` -verifies a proof that the query response is correct and up-to-date. - -Now, before we implement our own plugin and tooling, it helps to -understand the ``AppTx`` and the design of the plugin system. - -AppTx ------ - -The ``AppTx`` is similar to the ``SendTx``, but instead of sending coins -from inputs to outputs, it sends coins from one input to a plugin, and -can also send some data. - -:: - - type AppTx struct { - Gas int64 `json:"gas"` - Fee Coin `json:"fee"` - Input TxInput `json:"input"` - Name string `json:"type"` // Name of the plugin - Data []byte `json:"data"` // Data for the plugin to process - } - -The ``AppTx`` enables Basecoin to be extended with arbitrary additional -functionality through the use of plugins. The ``Name`` field in the -``AppTx`` refers to the particular plugin which should process the -transaction, and the ``Data`` field of the ``AppTx`` is the data to be -forwarded to the plugin for processing. - -Note the ``AppTx`` also has a ``Gas`` and ``Fee``, with the same meaning -as for the ``SendTx``. It also includes a single ``TxInput``, which -specifies the sender of the transaction, and some coins that can be -forwarded to the plugin as well. - -Plugins -------- - -A plugin is simply a Go package that implements the ``Plugin`` -interface: - -:: - - type Plugin interface { - - // Name of this plugin, should be short. - Name() string - - // Run a transaction from ABCI DeliverTx - RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result) - - // Other ABCI message handlers - SetOption(store KVStore, key string, value string) (log string) - InitChain(store KVStore, vals []*abci.Validator) - BeginBlock(store KVStore, hash []byte, header *abci.Header) - EndBlock(store KVStore, height uint64) (res abci.ResponseEndBlock) - } - - type CallContext struct { - CallerAddress []byte // Caller's Address (hash of PubKey) - CallerAccount *Account // Caller's Account, w/ fee & TxInputs deducted - Coins Coins // The coins that the caller wishes to spend, excluding fees - } - -The workhorse of the plugin is ``RunTx``, which is called when an -``AppTx`` is processed. The ``Data`` from the ``AppTx`` is passed in as -the ``txBytes``, while the ``Input`` from the ``AppTx`` is used to -populate the ``CallContext``. - -Note that ``RunTx`` also takes a ``KVStore`` - this is an abstraction -for the underlying Merkle tree which stores the account data. By passing -this to the plugin, we enable plugins to update accounts in the Basecoin -state directly, and also to store arbitrary other information in the -state. In this way, the functionality and state of a Basecoin-derived -cryptocurrency can be greatly extended. One could imagine going so far -as to implement the Ethereum Virtual Machine as a plugin! - -For details on how to initialize the state using ``SetOption``, see the -`guide to using the basecoin tool `__. - -Implement your own ------------------- - -To implement your own plugin and tooling, make a copy of -``docs/guide/counter``, and modify the code accordingly. Here, we will -briefly describe the design and the changes to be made, but see the code -for more details. - -First is the ``cmd/counter/main.go``, which drives the program. It can -be left alone, but you should change any occurrences of ``counter`` to -whatever your plugin tool is going to be called. You must also register -your plugin(s) with the basecoin app with ``RegisterStartPlugin``. - -The light-client is located in ``cmd/countercli/main.go`` and allows for -transaction and query commands. This file can also be left mostly alone -besides replacing the application name and adding references to new -plugin commands. - -Next is the custom commands in ``cmd/countercli/commands/``. These files -are where we extend the tool with any new commands and flags we need to -send transactions or queries to our plugin. You define custom ``tx`` and -``query`` subcommands, which are registered in ``main.go`` (avoiding -``init()`` auto-registration, for less magic and more control in the -main executable). - -Finally is ``plugins/counter/counter.go``, where we provide an -implementation of the ``Plugin`` interface. The most important part of -the implementation is the ``RunTx`` method, which determines the meaning -of the data sent along in the ``AppTx``. In our example, we define a new -transaction type, the ``CounterTx``, which we expect to be encoded in -the ``AppTx.Data``, and thus to be decoded in the ``RunTx`` method, and -used to update the plugin state. - -For more examples and inspiration, see our `repository of example -plugins `__. - -Conclusion ----------- - -In this guide, we demonstrated how to create a new plugin and how to -extend the ``basecoin`` tool to start a blockchain with the plugin -enabled and send transactions to it. In the next guide, we introduce a -`plugin for Inter Blockchain Communication `__, which allows us -to publish proofs of the state of one blockchain to another, and thus to -transfer tokens and data between them. diff --git a/docs/_attic/glossary.rst b/docs/_attic/glossary.rst deleted file mode 100644 index faf682da45..0000000000 --- a/docs/_attic/glossary.rst +++ /dev/null @@ -1,230 +0,0 @@ -Glossary -======== - -This glossary defines many terms used throughout documentation of Quark. -If there is every a concept that seems unclear, check here. This is -mainly to provide a background and general understanding of the -different words and concepts that are used. Other documents will explain -in more detail how to combine these concepts to build a particular -application. - -Transaction ------------ - -A transaction is a packet of binary data that contains all information -to validate and perform an action on the blockchain. The only other data -that it interacts with is the current state of the chain (key-value -store), and it must have a deterministic action. The transaction is the -main piece of one request. - -We currently make heavy use of -`go-amino `__ to -provide binary and json encodings and decodings for ``struct`` or -interface\ ``objects. Here, encoding and decoding operations are designed to operate with interfaces nested any amount times (like an onion!). There is one public``\ TxMapper\` -in the basecoin root package, and all modules can register their own -transaction types there. This allows us to deserialize the entire -transaction in one location (even with types defined in other repos), to -easily embed an arbitrary transaction inside another without specifying -the type, and provide an automatic json representation allowing for -users (or apps) to inspect the chain. - -Note how we can wrap any other transaction, add a fee level, and not -worry about the encoding in our module any more? - -:: - - type Fee struct { - Fee coin.Coin `json:"fee"` - Payer basecoin.Actor `json:"payer"` // the address who pays the fee - Tx basecoin.Tx `json:"tx"` - } - -Context (ctx) -------------- - -As a request passes through the system, it may pick up information such -as the block height the request runs at. In order to carry this information -between modules it is saved to the context. Further, all information -must be deterministic from the context in which the request runs (based -on the transaction and the block it was included in) and can be used to -validate the transaction. - -Data Store ----------- - -In order to provide proofs to Tendermint, we keep all data in one -key-value (kv) store which is indexed with a merkle tree. This allows -for the easy generation of a root hash and proofs for queries without -requiring complex logic inside each module. Standardization of this -process also allows powerful light-client tooling as any store data may -be verified on the fly. - -The largest limitation of the current implemenation of the kv-store is -that interface that the application must use can only ``Get`` and -``Set`` single data points. That said, there are some data structures -like queues and range queries that are available in ``state`` package. -These provide higher-level functionality in a standard format, but have -not yet been integrated into the kv-store interface. - -Isolation ---------- - -One of the main arguments for blockchain is security. So while we -encourage the use of third-party modules, all developers must be -vigilant against security holes. If you use the -`stack `__ -package, it will provide two different types of compartmentalization -security. - -The first is to limit the working kv-store space of each module. When -``DeliverTx`` is called for a module, it is never given the entire data -store, but rather only its own prefixed subset of the store. This is -achieved by prefixing all keys transparently with -`` + 0x0``, using the null byte as a separator. Since the -module name must be a string, no malicious naming scheme can ever lead -to a collision. Inside a module, we can write using any key value we -desire without the possibility that we have modified data belonging to -separate module. - -The second is to add permissions to the transaction context. The -transaction context can specify that the tx has been signed by one or -multiple specific actors. - -A transactions will only be executed if the permission requirements have -been fulfilled. For example the sender of funds must have signed, or 2 -out of 3 multi-signature actors must have signed a joint account. To -prevent the forgery of account signatures from unintended modules each -permission is associated with the module that granted it (in this case -`auth `__), -and if a module tries to add a permission for another module, it will -panic. There is also protection if a module creates a brand new fake -context to trick the downstream modules. Each context enforces the rules -on how to make child contexts, and the stack builder enforces -that the context passed from one level to the next is a valid child of -the original one. - -These security measures ensure that modules can confidently write to -their local section of the database and trust the permissions associated -with the context, without concern of interference from other modules. -(Okay, if you see a bunch of C-code in the module traversing through all -the memory space of the application, then get worried....) - -Handler -------- - -The ABCI interface is handled by ``app``, which translates these data -structures into an internal format that is more convenient, but unable -to travel over the wire. The basic interface for any code that modifies -state is the ``Handler`` interface, which provides four methods: - -:: - - Name() string - CheckTx(ctx Context, store state.KVStore, tx Tx) (Result, error) - DeliverTx(ctx Context, store state.KVStore, tx Tx) (Result, error) - SetOption(l log.Logger, store state.KVStore, module, key, value string) (string, error) - -Note the ``Context``, ``KVStore``, and ``Tx`` as principal carriers of -information. And that Result is always success, and we have a second -error return for errors (which is much more standard golang that -``res.IsErr()``) - -The ``Handler`` interface is designed to be the basis for all modules -that execute transactions, and this can provide a large degree of code -interoperability, much like ``http.Handler`` does in golang web -development. - -Modules -------- - -TODO: update (s/Modules/handlers+mappers+stores/g) & add Msg + Tx (a signed message) - -A module is a set of functionality which should be typically designed as -self-sufficient. Common elements of a module are: - -- transaction types (either end transactions, or transaction wrappers) -- custom error codes -- data models (to persist in the kv-store) -- handler (to handle any end transactions) - -Dispatcher ----------- - -We usually will want to have multiple modules working together, and need -to make sure the correct transactions get to the correct module. So we -have ``coin`` sending money, ``roles`` to create multi-sig accounts, and -``ibc`` for following other chains all working together without -interference. - -We can then register a ``Dispatcher``, which -also implements the ``Handler`` interface. We then register a list of -modules with the dispatcher. Every module has a unique ``Name()``, which -is used for isolating its state space. We use this same name for routing -transactions. Each transaction implementation must be registed with -go-amino via ``TxMapper``, so we just look at the registered name of this -transaction, which should be of the form ``/xxx``. The -dispatcher grabs the appropriate module name from the tx name and routes -it if the module is present. - -This all seems like a bit of magic, but really we're just making use of -go-amino magic that we are already using, rather than add another layer. -For all the transactions to be properly routed, the only thing you need -to remember is to use the following pattern: - -:: - - const ( - NameCoin = "coin" - TypeSend = NameCoin + "/send" - ) - -Permissions ------------ - -TODO: replaces perms with object capabilities/object capability keys -- get rid of IPC - -IPC requires a more complex permissioning system to allow the modules to -have limited access to each other and also to allow more types of -permissions than simple public key signatures. Rather than just use an -address to identify who is performing an action, we can use a more -complex structure: - -:: - - type Actor struct { - ChainID string `json:"chain"` // this is empty unless it comes from a different chain - App string `json:"app"` // the app that the actor belongs to - Address data.Bytes `json:"addr"` // arbitrary app-specific unique id - } - -Here, the ``Actor`` abstracts any address that can authorize actions, -hold funds, or initiate any sort of transaction. It doesn't just have to -be a pubkey on this chain, it could stem from another app (such as -multi-sig account), or even another chain (via IBC) - -``ChainID`` is for IBC, discussed below. Let's focus on ``App`` and -``Address``. For a signature, the App is ``auth``, and any modules can -check to see if a specific public key address signed like this -``ctx.HasPermission(auth.SigPerm(addr))``. However, we can also -authorize a tx with ``roles``, which handles multi-sig accounts, it -checks if there were enough signatures by checking as above, then it can -add the role permission like -``ctx= ctx.WithPermissions(NewPerm(assume.Role))`` - -In addition to the permissions schema, the Actors are addresses just -like public key addresses. So one can create a mulit-sig role, then send -coin there, which can only be moved upon meeting the authorization -requirements from that module. ``coin`` doesn't even know the existence -of ``roles`` and one could build any other sort of module to provide -permissions (like bind the outcome of an election to move coins or to -modify the accounts on a role). - -One idea - not yet implemented - is to provide scopes on the -permissions. Currently, if I sign a transaction to one module, it can -pass it on to any other module over IPC with the same permissions. It -could move coins, vote in an election, or anything else. Ideally, when -signing, one could also specify the scope(s) that this signature -authorizes. The `oauth -protocol `__ also has to deal -with a similar problem, and maybe could provide some inspiration. diff --git a/docs/_attic/ibc.rst b/docs/_attic/ibc.rst deleted file mode 100644 index 30b9a16faf..0000000000 --- a/docs/_attic/ibc.rst +++ /dev/null @@ -1,424 +0,0 @@ -IBC -=== - -TODO: update in light of latest SDK (this document is currently out of date) - -One of the most exciting elements of the Cosmos Network is the -InterBlockchain Communication (IBC) protocol, which enables -interoperability across different blockchains. We implemented IBC as a -basecoin plugin, and we'll show you how to use it to send tokens across -blockchains! - -Please note: this tutorial assumes familiarity with the Cosmos SDK. - -The IBC plugin defines a new set of transactions as subtypes of the -``AppTx``. The plugin's functionality is accessed by setting the -``AppTx.Name`` field to ``"IBC"``, and setting the ``Data`` field to the -serialized IBC transaction type. - -We'll demonstrate exactly how this works below. - -Inter BlockChain Communication ------------------------------- - -Let's review the IBC protocol. The purpose of IBC is to enable one -blockchain to function as a light-client of another. Since we are using -a classical Byzantine Fault Tolerant consensus algorithm, light-client -verification is cheap and easy: all we have to do is check validator -signatures on the latest block, and verify a Merkle proof of the state. - -In Tendermint, validators agree on a block before processing it. This -means that the signatures and state root for that block aren't included -until the next block. Thus, each block contains a field called -``LastCommit``, which contains the votes responsible for committing the -previous block, and a field in the block header called ``AppHash``, -which refers to the Merkle root hash of the application after processing -the transactions from the previous block. So, if we want to verify the -``AppHash`` from height H, we need the signatures from ``LastCommit`` at -height H+1. (And remember that this ``AppHash`` only contains the -results from all transactions up to and including block H-1) - -Unlike Proof-of-Work, the light-client protocol does not need to -download and check all the headers in the blockchain - the client can -always jump straight to the latest header available, so long as the -validator set has not changed much. If the validator set is changing, -the client needs to track these changes, which requires downloading -headers for each block in which there is a significant change. Here, we -will assume the validator set is constant, and postpone handling -validator set changes for another time. - -Now we can describe exactly how IBC works. Suppose we have two -blockchains, ``chain1`` and ``chain2``, and we want to send some data -from ``chain1`` to ``chain2``. We need to do the following: 1. Register -the details (ie. chain ID and genesis configuration) of ``chain1`` on -``chain2`` 2. Within ``chain1``, broadcast a transaction that creates an -outgoing IBC packet destined for ``chain2`` 3. Broadcast a transaction -to ``chain2`` informing it of the latest state (ie. header and commit -signatures) of ``chain1`` 4. Post the outgoing packet from ``chain1`` to -``chain2``, including the proof that it was indeed committed on -``chain1``. Note ``chain2`` can only verify this proof because it has a -recent header and commit. - -Each of these steps involves a separate IBC transaction type. Let's take -them up in turn. - -IBCRegisterChainTx -~~~~~~~~~~~~~~~~~~ - -The ``IBCRegisterChainTx`` is used to register one chain on another. It -contains the chain ID and genesis configuration of the chain to -register: - -:: - - type IBCRegisterChainTx struct { BlockchainGenesis } - - type BlockchainGenesis struct { ChainID string Genesis string } - -This transaction should only be sent once for a given chain ID, and -successive sends will return an error. - -IBCUpdateChainTx -~~~~~~~~~~~~~~~~ - -The ``IBCUpdateChainTx`` is used to update the state of one chain on -another. It contains the header and commit signatures for some block in -the chain: - -:: - - type IBCUpdateChainTx struct { - Header tm.Header - Commit tm.Commit - } - -In the future, it needs to be updated to include changes to the -validator set as well. Anyone can relay an ``IBCUpdateChainTx``, and -they only need to do so as frequently as packets are being sent or the -validator set is changing. - -IBCPacketCreateTx -~~~~~~~~~~~~~~~~~ - -The ``IBCPacketCreateTx`` is used to create an outgoing packet on one -chain. The packet itself contains the source and destination chain IDs, -a sequence number (i.e. an integer that increments with every message -sent between this pair of chains), a packet type (e.g. coin, data, -etc.), and a payload. - -:: - - type IBCPacketCreateTx struct { - Packet - } - - type Packet struct { - SrcChainID string - DstChainID string - Sequence uint64 - Type string - Payload []byte - } - -We have yet to define the format for the payload, so, for now, it's just -arbitrary bytes. - -One way to think about this is that ``chain2`` has an account on -``chain1``. With a ``IBCPacketCreateTx`` on ``chain1``, we send funds to -that account. Then we can prove to ``chain2`` that there are funds -locked up for it in it's account on ``chain1``. Those funds can only be -unlocked with corresponding IBC messages back from ``chain2`` to -``chain1`` sending the locked funds to another account on ``chain1``. - -IBCPacketPostTx -~~~~~~~~~~~~~~~ - -The ``IBCPacketPostTx`` is used to post an outgoing packet from one -chain to another. It contains the packet and a proof that the packet was -committed into the state of the sending chain: - -:: - - type IBCPacketPostTx struct { - FromChainID string // The immediate source of the packet, not always Packet.SrcChainID - FromChainHeight uint64 // The block height in which Packet was committed, to check Proof Packet - Proof *merkle.IAVLProof - } - -The proof is a Merkle proof in an IAVL tree, our implementation of a -balanced, Merklized binary search tree. It contains a list of nodes in -the tree, which can be hashed together to get the Merkle root hash. This -hash must match the ``AppHash`` contained in the header at -``FromChainHeight + 1`` - -- note the ``+ 1`` is necessary since ``FromChainHeight`` is the height - in which the packet was committed, and the resulting state root is - not included until the next block. - -IBC State -~~~~~~~~~ - -Now that we've seen all the transaction types, let's talk about the -state. Each chain stores some IBC state in its Merkle tree. For each -chain being tracked by our chain, we store: - -- Genesis configuration -- Latest state -- Headers for recent heights - -We also store all incoming (ingress) and outgoing (egress) packets. - -The state of a chain is updated every time an ``IBCUpdateChainTx`` is -committed. New packets are added to the egress state upon -``IBCPacketCreateTx``. New packets are added to the ingress state upon -``IBCPacketPostTx``, assuming the proof checks out. - -Merkle Queries --------------- - -The Basecoin application uses a single Merkle tree that is shared across -all its state, including the built-in accounts state and all plugin -state. For this reason, it's important to use explicit key names and/or -hashes to ensure there are no collisions. - -We can query the Merkle tree using the ABCI Query method. If we pass in -the correct key, it will return the corresponding value, as well as a -proof that the key and value are contained in the Merkle tree. - -The results of a query can thus be used as proof in an -``IBCPacketPostTx``. - -Relay ------ - -While we need all these packet types internally to keep track of all the -proofs on both chains in a secure manner, for the normal work-flow, we -can run a relay node that handles the cross-chain interaction. - -In this case, there are only two steps. First ``basecoin relay init``, -which must be run once to register each chain with the other one, and -make sure they are ready to send and recieve. And then -``basecoin relay start``, which is a long-running process polling the -queue on each side, and relaying all new message to the other block. - -This requires that the relay has access to accounts with some funds on -both chains to pay for all the ibc packets it will be forwarding. - -Try it out ----------- - -Now that we have all the background knowledge, let's actually walk -through the tutorial. - -Make sure you have installed `basecoin and -basecli `__. - -Basecoin is a framework for creating new cryptocurrency applications. It -comes with an ``IBC`` plugin enabled by default. - -You will also want to install the -`jq `__ for handling JSON at the command -line. - -If you have any trouble with this, you can also look at the `test -scripts `__ or just run ``make test_cli`` in basecoin -repo. Otherwise, open up 5 (yes 5!) terminal tabs.... - -Preliminaries -~~~~~~~~~~~~~ - -:: - - # first, clean up any old garbage for a fresh slate... - rm -rf ~/.ibcdemo/ - -Let's start by setting up some environment variables and aliases: - -:: - - export BCHOME1_CLIENT=~/.ibcdemo/chain1/client - export BCHOME1_SERVER=~/.ibcdemo/chain1/server - export BCHOME2_CLIENT=~/.ibcdemo/chain2/client - export BCHOME2_SERVER=~/.ibcdemo/chain2/server - alias basecli1="basecli --home $BCHOME1_CLIENT" - alias basecli2="basecli --home $BCHOME2_CLIENT" - alias basecoin1="basecoin --home $BCHOME1_SERVER" - alias basecoin2="basecoin --home $BCHOME2_SERVER" - -This will give us some new commands to use instead of raw ``basecli`` -and ``basecoin`` to ensure we're using the right configuration for the -chain we want to talk to. - -We also want to set some chain IDs: - -:: - - export CHAINID1="test-chain-1" - export CHAINID2="test-chain-2" - -And since we will run two different chains on one machine, we need to -maintain different sets of ports: - -:: - - export PORT_PREFIX1=1234 - export PORT_PREFIX2=2345 - export RPC_PORT1=${PORT_PREFIX1}7 - export RPC_PORT2=${PORT_PREFIX2}7 - -Setup Chain 1 -~~~~~~~~~~~~~ - -Now, let's create some keys that we can use for accounts on -test-chain-1: - -:: - - basecli1 keys new money - basecli1 keys new gotnone - export MONEY=$(basecli1 keys get money | awk '{print $2}') - export GOTNONE=$(basecli1 keys get gotnone | awk '{print $2}') - -and create an initial configuration giving lots of coins to the $MONEY -key: - -:: - - basecoin1 init --chain-id $CHAINID1 $MONEY - -Now start basecoin: - -:: - - sed -ie "s/4665/$PORT_PREFIX1/" $BCHOME1_SERVER/config.toml - - basecoin1 start &> basecoin1.log & - -Note the ``sed`` command to replace the ports in the config file. You -can follow the logs with ``tail -f basecoin1.log`` - -Now we can attach the client to the chain and verify the state. The -first account should have money, the second none: - -:: - - basecli1 init --node=tcp://localhost:${RPC_PORT1} --genesis=${BCHOME1_SERVER}/genesis.json - basecli1 query account $MONEY - basecli1 query account $GOTNONE - -Setup Chain 2 -~~~~~~~~~~~~~ - -This is the same as above, except with ``basecli2``, ``basecoin2``, and -``$CHAINID2``. We will also need to change the ports, since we're -running another chain on the same local machine. - -Let's create new keys for test-chain-2: - -:: - - basecli2 keys new moremoney - basecli2 keys new broke - MOREMONEY=$(basecli2 keys get moremoney | awk '{print $2}') - BROKE=$(basecli2 keys get broke | awk '{print $2}') - -And prepare the genesis block, and start the server: - -:: - - basecoin2 init --chain-id $CHAINID2 $(basecli2 keys get moremoney | awk '{print $2}') - - sed -ie "s/4665/$PORT_PREFIX2/" $BCHOME2_SERVER/config.toml - - basecoin2 start &> basecoin2.log & - -Now attach the client to the chain and verify the state. The first -account should have money, the second none: - -:: - - basecli2 init --node=tcp://localhost:${RPC_PORT2} --genesis=${BCHOME2_SERVER}/genesis.json - basecli2 query account $MOREMONEY - basecli2 query account $BROKE - -Connect these chains -~~~~~~~~~~~~~~~~~~~~ - -OK! So we have two chains running on your local machine, with different -keys on each. Let's hook them up together by starting a relay process to -forward messages from one chain to the other. - -The relay account needs some money in it to pay for the ibc messages, so -for now, we have to transfer some cash from the rich accounts before we -start the actual relay. - -:: - - # note that this key.json file is a hardcoded demo for all chains, this will - # be updated in a future release - RELAY_KEY=$BCHOME1_SERVER/key.json - RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") - - basecli1 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR--name=money - basecli1 query account $RELAY_ADDR - - basecli2 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=moremoney - basecli2 query account $RELAY_ADDR - -Now we can start the relay process. - -:: - - basecoin relay init --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 \ - --chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} \ - --genesis1=${BCHOME1_SERVER}/genesis.json --genesis2=${BCHOME2_SERVER}/genesis.json \ - --from=$RELAY_KEY - - basecoin relay start --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 \ - --chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} \ - --from=$RELAY_KEY &> relay.log & - -This should start up the relay, and assuming no error messages came out, -the two chains are now fully connected over IBC. Let's use this to send -our first tx accross the chains... - -Sending cross-chain payments -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The hard part is over, we set up two blockchains, a few private keys, -and a secure relay between them. Now we can enjoy the fruits of our -labor... - -:: - - # Here's an empty account on test-chain-2 - basecli2 query account $BROKE - -:: - - # Let's send some funds from test-chain-1 - basecli1 tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$BROKE --name=money - -:: - - # give it time to arrive... - sleep 2 - # now you should see 12345 coins! - basecli2 query account $BROKE - -You're no longer broke! Cool, huh? Now have fun exploring and sending -coins across the chains. And making more accounts as you want to. - -Conclusion ----------- - -In this tutorial we explained how IBC works, and demonstrated how to use -it to communicate between two chains. We did the simplest communciation -possible: a one way transfer of data from chain1 to chain2. The most -important part was that we updated chain2 with the latest state (i.e. -header and commit) of chain1, and then were able to post a proof to -chain2 that a packet was committed to the outgoing state of chain1. - -In a future tutorial, we will demonstrate how to use IBC to actually -transfer tokens between two blockchains, but we'll do it with real -testnets deployed across multiple nodes on the network. Stay tuned! diff --git a/docs/_attic/keys.md b/docs/_attic/keys.md deleted file mode 100644 index 029508ad5f..0000000000 --- a/docs/_attic/keys.md +++ /dev/null @@ -1,119 +0,0 @@ -# Keys CLI - -**WARNING: out-of-date and parts are wrong.... please update** - -This is as much an example how to expose cobra/viper, as for a cli itself -(I think this code is overkill for what go-keys needs). But please look at -the commands, and give feedback and changes. - -`RootCmd` calls some initialization functions (`cobra.OnInitialize` and `RootCmd.PersistentPreRunE`) which serve to connect environmental variables and cobra flags, as well as load the config file. It also validates the flags registered on root and creates the cryptomanager, which will be used by all subcommands. - -## Help info - -``` -# keys help - -Keys allows you to manage your local keystore for tendermint. - -These keys may be in any format supported by go-crypto and can be -used by light-clients, full nodes, or any other application that -needs to sign with a private key. - -Usage: - keys [command] - -Available Commands: - get Get details of one key - list List all keys - new Create a new public/private key pair - serve Run the key manager as an http server - update Change the password for a private key - -Flags: - --keydir string Directory to store private keys (subdir of root) (default "keys") - -o, --output string Output format (text|json) (default "text") - -r, --root string root directory for config and data (default "/Users/ethan/.tlc") - -Use "keys [command] --help" for more information about a command. -``` - -## Getting the config file - -The first step is to load in root, by checking the following in order: - -* -r, --root command line flag -* TM_ROOT environmental variable -* default ($HOME/.tlc evaluated at runtime) - -Once the `rootDir` is established, the script looks for a config file named `keys.{json,toml,yaml,hcl}` in that directory and parses it. These values will provide defaults for flags of the same name. - -There is an example config file for testing out locally, which writes keys to `./.mykeys`. You can - -## Getting/Setting variables - -When we want to get the value of a user-defined variable (eg. `output`), we can call `viper.GetString("output")`, which will do the following checks, until it finds a match: - -* Is `--output` command line flag present? -* Is `TM_OUTPUT` environmental variable set? -* Was a config file found and does it have an `output` variable? -* Is there a default set on the command line flag? - -If no variable is set and there was no default, we get back "". - -This setup allows us to have powerful command line flags, but use env variables or config files (local or 12-factor style) to avoid passing these arguments every time. - -## Nesting structures - -Sometimes we don't just need key-value pairs, but actually a multi-level config file, like - -``` -[mail] -from = "no-reply@example.com" -server = "mail.example.com" -port = 567 -password = "XXXXXX" -``` - -This CLI is too simple to warant such a structure, but I think eg. tendermint could benefit from such an approach. Here are some pointers: - -* [Accessing nested keys from config files](https://github.com/spf13/viper#accessing-nested-keys) -* [Overriding nested values with envvars](https://www.netlify.com/blog/2016/09/06/creating-a-microservice-boilerplate-in-go/#nested-config-values) - the mentioned outstanding PR is already merged into master! -* Overriding nested values with cli flags? (use `--log_config.level=info` ??) - -I'd love to see an example of this fully worked out in a more complex CLI. - -## Have your cake and eat it too - -It's easy to render data different ways. Some better for viewing, some better for importing to other programs. You can just add some global (persistent) flags to control the output formatting, and everyone gets what they want. - -``` -# keys list -e hex -All keys: -betty d0789984492b1674e276b590d56b7ae077f81adc -john b77f4720b220d1411a649b6c7f1151eb6b1c226a - -# keys list -e btc -All keys: -betty 3uTF4r29CbtnzsNHZoPSYsE4BDwH -john 3ZGp2Md35iw4XVtRvZDUaAEkCUZP - -# keys list -e b64 -o json -[ - { - "name": "betty", - "address": "0HiZhEkrFnTidrWQ1Wt64Hf4Gtw=", - "pubkey": { - "type": "secp256k1", - "data": "F83WvhT0KwttSoqQqd_0_r2ztUUaQix5EXdO8AZyREoV31Og780NW59HsqTAb2O4hZ-w-j0Z-4b2IjfdqqfhVQ==" - } - }, - { - "name": "john", - "address": "t39HILIg0UEaZJtsfxFR62scImo=", - "pubkey": { - "type": "ed25519", - "data": "t1LFmbg_8UTwj-n1wkqmnTp6NfaOivokEhlYySlGYCY=" - } - } -] -``` diff --git a/docs/_attic/replay-protection.rst b/docs/_attic/replay-protection.rst deleted file mode 100644 index d262add974..0000000000 --- a/docs/_attic/replay-protection.rst +++ /dev/null @@ -1,38 +0,0 @@ -Replay Protection ------------------ - -In order to prevent `replay -attacks `__ a multi account -nonce system has been constructed as a module, which can be found in -``modules/nonce``. By adding the nonce module to the stack, each -transaction is verified for authenticity against replay attacks. This is -achieved by requiring that a new signed copy of the sequence number -which must be exactly 1 greater than the sequence number of the previous -transaction. A distinct sequence number is assigned per chain-id, -application, and group of signers. Each sequence number is tracked as a -nonce-store entry where the key is the marshaled list of actors after -having been sorted by chain, app, and address. - -.. code:: golang - - // Tx - Nonce transaction structure, contains list of signers and current sequence number - type Tx struct { - Sequence uint32 `json:"sequence"` - Signers []basecoin.Actor `json:"signers"` - Tx basecoin.Tx `json:"tx"` - } - -By distinguishing sequence numbers across groups of Signers, -multi-signature Actors need not lock up use of their Address while -waiting for all the members of a multi-sig transaction to occur. Instead -only the multi-sig account will be locked, while other accounts -belonging to that signer can be used and signed with other sequence -numbers. - -By abstracting out the nonce module in the stack, entire series of -transactions can occur without needing to verify the nonce for each -member of the series. An common example is a stack which will send coins -and charge a fee. Within the SDK this can be achieved using separate -modules in a stack, one to send the coins and the other to charge the -fee, however both modules do not need to check the nonce. This can occur -as a separate module earlier in the stack. diff --git a/docs/_attic/staking/intro.rst b/docs/_attic/staking/intro.rst new file mode 100644 index 0000000000..3ed20852b4 --- /dev/null +++ b/docs/_attic/staking/intro.rst @@ -0,0 +1,402 @@ +Using The Staking Module +======================== + +This project is a demonstration of the Cosmos Hub staking functionality; it is +designed to get validator acquianted with staking concepts and procedures. + +Potential validators will be declaring their candidacy, after which users can +delegate and, if they so wish, unbond. This can be practiced using a local or +public testnet. + +This example covers initial setup of a two-node testnet between a server in the cloud and a local machine. Begin this tutorial from a cloud machine that you've ``ssh``'d into. + +Install +------- + +The ``gaiad`` and ``gaiacli`` binaries: + +:: + + go get github.com/cosmos/cosmos-sdk + cd $GOPATH/src/github.com/cosmos/cosmos-sdk + make get_vendor_deps + make install + +Let's jump right into it. First, we initialize some default files: + +:: + + gaiad init + +which will output: + +:: + + I[03-30|11:20:13.365] Found private validator module=main path=/root/.gaiad/config/priv_validator.json + I[03-30|11:20:13.365] Found genesis file module=main path=/root/.gaiad/config/genesis.json + Secret phrase to access coins: + citizen hungry tennis noise park hire glory exercise link glow dolphin labor design grit apple abandon + +This tell us we have a ``priv_validator.json`` and ``genesis.json`` in the ``~/.gaiad/config`` directory. A ``config.toml`` was also created in the same directory. It is a good idea to get familiar with those files. Write down the seed. + +The next thing we'll need to is add the key from ``priv_validator.json`` to the ``gaiacli`` key manager. For this we need a seed and a password: + +:: + + gaiacli keys add alice --recover + +which will give you three prompts: + +:: + + Enter a passphrase for your key: + Repeat the passphrase: + Enter your recovery seed phrase: + +create a password and copy in your seed phrase. The name and address of the key will be output: + +:: + NAME: ADDRESS: PUBKEY: + alice 67997DD03D527EB439B7193F2B813B05B219CC02 1624DE6220BB89786C1D597050438C728202436552C6226AB67453CDB2A4D2703402FB52B6 + +You can see all available keys with: + +:: + + gaiacli keys list + +Setup Testnet +------------- + +Next, we start the daemon (do this in another window): + +:: + + gaiad start + +and you'll see blocks start streaming through. + +For this example, we're doing the above on a cloud machine. The next steps should be done on your local machine or another server in the cloud, which will join the running testnet then bond/unbond. + +Accounts +-------- + +We have: + +- ``alice`` the initial validator (in the cloud) +- ``bob`` receives tokens from ``alice`` then declares candidacy (from local machine) +- ``charlie`` will bond and unbond to ``bob`` (from local machine) + +Remember that ``alice`` was already created. On your second machine, install the binaries and create two new keys: + +:: + + gaiacli keys add bob + gaiacli keys add charlie + +both of which will prompt you for a password. Now we need to copy the ``genesis.json`` and ``config.toml`` from the first machine (with ``alice``) to the second machine. This is a good time to look at both these files. + +The ``genesis.json`` should look something like: + +:: + + { + "app_state": { + "accounts": [ + { + "address": "1D9B2356CAADF46D3EE3488E3CCE3028B4283DEE", + "coins": [ + { + "denom": "steak", + "amount": 100000 + } + ] + } + ], + "stake": { + "pool": { + "total_supply": 0, + "bonded_shares": { + "num": 0, + "denom": 1 + }, + "unbonded_shares": { + "num": 0, + "denom": 1 + }, + "bonded_pool": 0, + "unbonded_pool": 0, + "inflation_last_time": 0, + "inflation": { + "num": 7, + "denom": 100 + } + }, + "params": { + "inflation_rate_change": { + "num": 13, + "denom": 100 + }, + "inflation_max": { + "num": 20, + "denom": 100 + }, + "inflation_min": { + "num": 7, + "denom": 100 + }, + "goal_bonded": { + "num": 67, + "denom": 100 + }, + "max_validators": 100, + "bond_denom": "steak" + } + } + }, + "validators": [ + { + "pub_key": { + "type": "AC26791624DE60", + "value": "rgpc/ctVld6RpSfwN5yxGBF17R1PwMTdhQ9gKVUZp5g=" + }, + "power": 10, + "name": "" + } + ], + "app_hash": "", + "genesis_time": "0001-01-01T00:00:00Z", + "chain_id": "test-chain-Uv1EVU" + } + + +To notice is that the ``accounts`` field has a an address and a whole bunch of "mycoin". This is ``alice``'s address (todo: dbl check). Under ``validators`` we see the ``pub_key.data`` field, which will match the same field in the ``priv_validator.json`` file. + +The ``config.toml`` is long so let's focus on one field: + +:: + + # Comma separated list of seed nodes to connect to + seeds = "" + +On the ``alice`` cloud machine, we don't need to do anything here. Instead, we need its IP address. After copying this file (and the ``genesis.json`` to your local machine, you'll want to put the IP in the ``seeds = "138.197.161.74"`` field, in this case, we have a made-up IP. For joining testnets with many nodes, you can add more comma-seperated IPs to the list. + + +Now that your files are all setup, it's time to join the network. On your local machine, run: + +:: + + gaiad start + +and your new node will connect to the running validator (``alice``). + +Sending Tokens +-------------- + +We'll have ``alice`` send some ``mycoin`` to ``bob``, who has now joined the network: + +:: + + gaiacli send --amount=1000mycoin --sequence=0 --name=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU + +where the ``--sequence`` flag is to be incremented for each transaction, the ``--name`` flag is the sender (alice), and the ``--to`` flag takes ``bob``'s address. You'll see something like: + +:: + + Please enter passphrase for alice: + { + "check_tx": { + "gas": 30 + }, + "deliver_tx": { + "tags": [ + { + "key": "height", + "value_type": 1, + "value_int": 2963 + }, + { + "key": "coin.sender", + "value_string": "5D93A6059B6592833CBC8FA3DA90EE0382198985" + }, + { + "key": "coin.receiver", + "value_string": "5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6" + } + ] + }, + "hash": "423BD7EA3C4B36AF8AFCCA381C0771F8A698BA77", + "height": 2963 + } + +TODO: check the above with current actual output. + +Check out ``bob``'s account, which should now have 1000 mycoin: + +:: + + gaiacli account 5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 + +Adding a Second Validator +------------------------- + +**This section is wrong/needs to be updated** + +Next, let's add the second node as a validator. + +First, we need the pub_key data: + +** need to make bob a priv_Val above? + +:: + + cat $HOME/.gaia2/priv_validator.json + +the first part will look like: + +:: + + {"address":"7B78527942C831E16907F10C3263D5ED933F7E99","pub_key":{"type":"ed25519","data":"96864CE7085B2E342B0F96F2E92B54B18C6CC700186238810D5AA7DFDAFDD3B2"}, + +and you want the ``pub_key`` ``data`` that starts with ``96864CE``. + +Now ``bob`` can create a validator with that pubkey. + +:: + + gaiacli stake create-validator --amount=10mycoin --name=bob --address-validator=
--pub-key= --moniker=bobby + +with an output like: + +:: + + Please enter passphrase for bob: + { + "check_tx": { + "gas": 30 + }, + "deliver_tx": {}, + "hash": "2A2A61FFBA1D7A59138E0068C82CC830E5103799", + "height": 4075 + } + + +We should see ``bob``'s account balance decrease by 10 mycoin: + +:: + + gaiacli account 5D93A6059B6592833CBC8FA3DA90EE0382198985 + +To confirm for certain the new validator is active, ask the tendermint node: + +:: + + curl localhost:26657/validators + +If you now kill either node, blocks will stop streaming in, because +there aren't enough validators online. Turn it back on and they will +start streaming again. + +Now that ``bob`` has declared candidacy, which essentially bonded 10 mycoin and made him a validator, we're going to get ``charlie`` to delegate some coins to ``bob``. + +Delegating +---------- + +First let's have ``alice`` send some coins to ``charlie``: + +:: + + gaiacli send --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF + +Then ``charlie`` will delegate some mycoin to ``bob``: + +:: + + gaiacli stake delegate --amount=10mycoin --address-delegator= --address-validator= --name=charlie + +You'll see output like: + +:: + + Please enter passphrase for charlie: + { + "check_tx": { + "gas": 30 + }, + "deliver_tx": {}, + "hash": "C3443BA30FCCC1F6E3A3D6AAAEE885244F8554F0", + "height": 51585 + } + +And that's it. You can query ``charlie``'s account to see the decrease in mycoin. + +To get more information about the candidate, try: + +:: + + gaiacli stake validator
+ +and you'll see output similar to: + +:: + + { + "height": 51899, + "data": { + "pub_key": { + "type": "ed25519", + "data": "52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B" + }, + "owner": { + "chain": "", + "app": "sigs", + "addr": "5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6" + }, + "shares": 20, + "voting_power": 20, + "description": { + "moniker": "bobby", + "identity": "", + "website": "", + "details": "" + } + } + } + +It's also possible the query the delegator's bond like so: + +:: + + gaiacli stake delegation --address-delegator=
--address-validator=
+ +with an output similar to: + +:: + + { + "height": 325782, + "data": { + "PubKey": { + "type": "ed25519", + "data": "52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B" + }, + "Shares": 20 + } + } + + +where the ``--address-delegator`` is ``charlie``'s address and the ``--address-validator`` is ``bob``'s address. + + +Unbonding +--------- + +Finally, to relinquish your voting power, unbond some coins. You should see +your VotingPower reduce and your account balance increase. + +:: + + gaiacli stake unbond --amount=5mycoin --name=charlie --address-delegator=
--address-validator=
+ gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF + +See the bond decrease with ``gaiacli stake delegation`` like above. diff --git a/docs/_attic/staking/key-management.rst b/docs/_attic/staking/key-management.rst deleted file mode 100644 index ebeca0e445..0000000000 --- a/docs/_attic/staking/key-management.rst +++ /dev/null @@ -1,204 +0,0 @@ -Key Management -============== - -Here we explain a bit how to work with your keys, using the -``gaia client keys`` subcommand. - -**Note:** This keys tooling is not considered production ready and is -for dev only. - -We'll look at what you can do using the six sub-commands of -``gaia client keys``: - -:: - - new - list - get - delete - recover - update - -Create keys ------------ - -``gaia client keys new`` has two inputs (name, password) and two outputs -(address, seed). - -First, we name our key: - -:: - - gaia client keys new alice - -This will prompt (10 character minimum) password entry which must be -re-typed. You'll see: - -:: - - Enter a passphrase: - Repeat the passphrase: - alice A159C96AE911F68913E715ED889D211C02EC7D70 - **Important** write this seed phrase in a safe place. - It is the only way to recover your account if you ever forget your password. - - pelican amateur empower assist awkward claim brave process cliff save album pigeon intact asset - -which shows the address of your key named ``alice``, and its recovery -seed. We'll use these shortly. - -Adding the ``--output json`` flag to the above command would give this -output: - -:: - - Enter a passphrase: - Repeat the passphrase: - { - "key": { - "name": "alice", - "address": "A159C96AE911F68913E715ED889D211C02EC7D70", - "pubkey": { - "type": "ed25519", - "data": "4BF22554B0F0BF2181187E5E5456E3BF3D96DB4C416A91F07F03A9C36F712B77" - } - }, - "seed": "pelican amateur empower assist awkward claim brave process cliff save album pigeon intact asset" - } - -To avoid the prompt, it's possible to pipe the password into the -command, e.g.: - -:: - - echo 1234567890 | gaia client keys new fred --output json - -After trying each of the three ways to create a key, look at them, use: - -:: - - gaia client keys list - -to list all the keys: - -:: - - All keys: - alice 6FEA9C99E2565B44FCC3C539A293A1378CDA7609 - bob A159C96AE911F68913E715ED889D211C02EC7D70 - charlie 784D623E0C15DE79043C126FA6449B68311339E5 - -Again, we can use the ``--output json`` flag: - -:: - - [ - { - "name": "alice", - "address": "6FEA9C99E2565B44FCC3C539A293A1378CDA7609", - "pubkey": { - "type": "ed25519", - "data": "878B297F1E863CC30CAD71E04A8B3C23DB71C18F449F39E35B954EDB2276D32D" - } - }, - { - "name": "bob", - "address": "A159C96AE911F68913E715ED889D211C02EC7D70", - "pubkey": { - "type": "ed25519", - "data": "2127CAAB96C08E3042C5B33C8B5A820079AAE8DD50642DCFCC1E8B74821B2BB9" - } - }, - { - "name": "charlie", - "address": "784D623E0C15DE79043C126FA6449B68311339E5", - "pubkey": { - "type": "ed25519", - "data": "4BF22554B0F0BF2181187E5E5456E3BF3D96DB4C416A91F07F03A9C36F712B77" - } - }, - ] - -to get machine readable output. - -If we want information about one specific key, then: - -:: - - gaia client keys get charlie --output json - -will, for example, return the info for only the "charlie" key returned -from the previous ``gaia client keys list`` command. - -The keys tooling can support different types of keys with a flag: - -:: - - gaia client keys new bit --type secp256k1 - -and you'll see the difference in the ``"type": field from``\ gaia client -keys get\` - -Before moving on, let's set an enviroment variable to make -``--output json`` the default. - -Either run or put in your ``~/.bash_profile`` the following line: - -:: - - export BC_OUTPUT=json - -Recover a key -------------- - -Let's say, for whatever reason, you lose a key or forget the password. -On creation, you were given a seed. We'll use it to recover a lost key. - -First, let's simulate the loss by deleting a key: - -:: - - gaia client keys delete alice - -which prompts for your current password, now rendered obsolete, and -gives a warning message. The only way you can recover your key now is -using the 12 word seed given on initial creation of the key. Let's try -it: - -:: - - gaia client keys recover alice-again - -which prompts for a new password then the seed: - -:: - - Enter the new passphrase: - Enter your recovery seed phrase: - strike alien praise vendor term left market practice junior better deputy divert front calm - alice-again CBF5D9CE6DDCC32806162979495D07B851C53451 - -and voila! You've recovered your key. Note that the seed can be typed -out, pasted in, or piped into the command alongside the password. - -To change the password of a key, we can: - -:: - - gaia client keys update alice-again - -and follow the prompts. - -That covers most features of the keys sub command. - -.. raw:: html - - diff --git a/docs/_attic/staking/local-testnet.rst b/docs/_attic/staking/local-testnet.rst deleted file mode 100644 index 830830a6fc..0000000000 --- a/docs/_attic/staking/local-testnet.rst +++ /dev/null @@ -1,83 +0,0 @@ -Local Testnet -============= - -This tutorial demonstrates the basics of setting up a gaia -testnet locally. - -If you haven't already made a key, make one now: - -:: - - gaia client keys new alice - -otherwise, use an existing key. - -Initialize The Chain --------------------- - -Now initialize a gaia chain, using ``alice``'s address: - -:: - - gaia node init 5D93A6059B6592833CBC8FA3DA90EE0382198985 --home=$HOME/.gaia1 --chain-id=gaia-test - -This will create all the files necessary to run a single node chain in -``$HOME/.gaia1``: a ``priv_validator.json`` file with the validators -private key, and a ``genesis.json`` file with the list of validators and -accounts. - -We'll add a second node on our local machine by initiating a node in a -new directory, with the same address, and copying in the genesis: - -:: - - gaia node init 5D93A6059B6592833CBC8FA3DA90EE0382198985 --home=$HOME/.gaia2 --chain-id=gaia-test - cp $HOME/.gaia1/genesis.json $HOME/.gaia2/genesis.json - -We also need to modify ``$HOME/.gaia2/config.toml`` to set new seeds -and ports. It should look like: - -:: - - proxy_app = "tcp://127.0.0.1:26668" - moniker = "anonymous" - fast_sync = true - db_backend = "leveldb" - log_level = "state:info,*:error" - - [rpc] - laddr = "tcp://0.0.0.0:26667" - - [p2p] - laddr = "tcp://0.0.0.0:26666" - seeds = "0.0.0.0:26656" - -Start Nodes ------------ - -Now that we've initialized the chains, we can start both nodes: - -NOTE: each command below must be started in separate terminal windows. Alternatively, to run this testnet across multiple machines, you'd replace the ``seeds = "0.0.0.0"`` in ``~/.gaia2.config.toml`` with the IP of the first node, and could skip the modifications we made to the config file above because port conflicts would be avoided. - -:: - - gaia node start --home=$HOME/.gaia1 - gaia node start --home=$HOME/.gaia2 - -Now we can initialize a client for the first node, and look up our -account: - -:: - - gaia client init --chain-id=gaia-test --node=tcp://localhost:26657 - gaia client query account 5D93A6059B6592833CBC8FA3DA90EE0382198985 - -To see what tendermint considers the validator set is, use: - -:: - - curl localhost:26657/validators - -and compare the information in this file: ``~/.gaia1/priv_validator.json``. The ``address`` and ``pub_key`` fields should match. - -To add a second validator on your testnet, you'll need to bond some tokens be declaring candidacy. diff --git a/docs/_attic/staking/overview.md b/docs/_attic/staking/overview.md new file mode 100644 index 0000000000..79033fe1ea --- /dev/null +++ b/docs/_attic/staking/overview.md @@ -0,0 +1,216 @@ +//TODO update .rst + +# Staking Module + +## Overview + +The Cosmos Hub is a Tendermint-based Delegated Proof of Stake (DPos) blockchain +system that serves as a backbone of the Cosmos ecosystem. It is operated and +secured by an open and globally decentralized set of validators. Tendermint is +a Byzantine fault-tolerant distributed protocol for consensus among distrusting +parties, in this case the group of validators which produce the blocks for the +Cosmos Hub. To avoid the nothing-at-stake problem, a validator in Tendermint +needs to lock up coins in a bond deposit. Each bond's atoms are illiquid, they +cannot be transferred - in order to become liquid, they must be unbonded, a +process which will take 3 weeks by default at Cosmos Hub launch. Tendermint +protocol messages are signed by the validator's private key and are therefor +attributable. Validators acting outside protocol specifications can be made +accountable through punishing by slashing (burning) their bonded Atoms. On the +other hand, validators are rewarded for their service of securing blockchain +network by the inflationary provisions and transactions fees. This incentivizes +correct behavior of the validators and provides the economic security of the +network. + +The native token of the Cosmos Hub is called the Atom; becoming a validator of the +Cosmos Hub requires holding Atoms. However, not all Atom holders are validators +of the Cosmos Hub. More precisely, there is a selection process that determines +the validator set as a subset of all validators (Atom holders that +want to become a validator). The other option for Atom holders is to delegate +their atoms to validators, i.e., being a delegator. A delegator is an Atom +holder that has put its Atoms at stake by delegating it to a validator. By bonding +Atoms to secure the network (and taking a risk of being slashed in case of +misbehaviour), a user is rewarded with inflationary provisions and transaction +fees proportional to the amount of its bonded Atoms. The Cosmos Hub is +designed to efficiently facilitate a small numbers of validators (hundreds), +and large numbers of delegators (tens of thousands). More precisely, it is the +role of the Staking module of the Cosmos Hub to support various staking +functionality including validator set selection, delegating, bonding and +withdrawing Atoms, and the distribution of inflationary provisions and +transaction fees. + +## Basic Terms and Definitions + +* Cosmsos Hub - a Tendermint-based Delegated Proof of Stake (DPos) + blockchain system +* Atom - native token of the Cosmsos Hub +* Atom holder - an entity that holds some amount of Atoms +* Pool - Global object within the Cosmos Hub which accounts global state + including the total amount of bonded, unbonding, and unbonded atoms +* Validator Share - Share which a validator holds to represent its portion of + bonded, unbonding or unbonded atoms in the pool +* Delegation Share - Shares which a delegation bond holds to represent its + portion of bonded, unbonding or unbonded shares in a validator +* Bond Atoms - a process of locking Atoms in a delegation share which holds them + under protocol control. +* Slash Atoms - the process of burning atoms in the pool and assoiated + validator shares of a misbehaving validator, (not behaving according to the + protocol specification). This process devalues the worth of delegation shares + of the given validator +* Unbond Shares - Process of retrieving atoms from shares. If the shares are + bonded the shares must first remain in an inbetween unbonding state for the + duration of the unbonding period +* Redelegating Shares - Process of redelegating atoms from one validator to + another. This process is instantaneous, but the redelegated atoms are + retrospecively slashable if the old validator is found to misbehave for any + blocks before the redelegation. These atoms are simultaniously slashable + for any new blocks which the new validator misbehavess +* Validator - entity with atoms which is either actively validating the Tendermint + protocol (bonded validator) or vying to validate . +* Bonded Validator - a validator whose atoms are currently bonded and liable to + be slashed. These validators are to be able to sign protocol messages for + Tendermint consensus. At Cosmos Hub genesis there is a maximum of 100 + bonded validator positions. Only Bonded Validators receive atom provisions + and fee rewards. +* Delegator - an Atom holder that has bonded Atoms to a validator +* Unbonding period - time required in the unbonding state when unbonding + shares. Time slashable to old validator after a redelegation. Time for which + validators can be slashed after an infraction. To provide the requisite + cryptoeconomic security guarantees, all of these must be equal. +* Atom provisions - The process of increasing the Atom supply. Atoms are + periodically created on the Cosmos Hub and issued to bonded Atom holders. + The goal of inflation is to incentize most of the Atoms in existence to be + bonded. Atoms are distributed unbonded and using the fee_distribution mechanism +* Transaction fees - transaction fee is a fee that is included in a Cosmsos Hub + transaction. The fees are collected by the current validator set and + distributed among validators and delegators in proportion to their bonded + Atom share +* Commission fee - a fee taken from the transaction fees by a validator for + their service + +## The pool and the share + +At the core of the Staking module is the concept of a pool which denotes a +collection of Atoms contributed by different Atom holders. There are three +pools in the Staking module: the bonded, unbonding, and unbonded pool. Bonded +Atoms are part of the global bonded pool. If a validator or delegator wants to +unbond its shares, these Shares are moved to the the unbonding pool for the +duration of the unbonding period. From here normally Atoms will be moved +directly into the delegators wallet, however under the situation thatn an +entire validator gets unbonded, the Atoms of the delegations will remain with +the validator and moved to the unbonded pool. For each pool, the total amount +of bonded, unbonding, or unbonded Atoms are tracked as well as the current +amount of issued pool-shares, the specific holdings of these shares by +validators are tracked in protocol by the validator object. + +A share is a unit of Atom distribution and the value of the share +(share-to-atom exchange rate) can change during system execution. The +share-to-atom exchange rate can be computed as: + +`share-to-atom-exchange-rate = size of the pool / ammount of issued shares` + +Then for each validator (in a per validator data structure) the protocol keeps +track of the amount of shares the validator owns in a pool. At any point in +time, the exact amount of Atoms a validator has in the pool can be computed as +the number of shares it owns multiplied with the current share-to-atom exchange +rate: + +`validator-coins = validator.Shares * share-to-atom-exchange-rate` + +The benefit of such accounting of the pool resources is the fact that a +modification to the pool from bonding/unbonding/slashing of Atoms affects only +global data (size of the pool and the number of shares) and not the related +validator data structure, i.e., the data structure of other validators do not +need to be modified. This has the advantage that modifying global data is much +cheaper computationally than modifying data of every validator. Let's explain +this further with several small examples: + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXX TODO make way less verbose lets use bullet points to describe the example +XXX Also need to update to not include bonded atom provisions all atoms are +XXX redistributed with the fee pool now + +We consider initially 4 validators p1, p2, p3 and p4, and that each validator +has bonded 10 Atoms to the bonded pool. Furthermore, let's assume that we have +issued initially 40 shares (note that the initial distribution of the shares, +i.e., share-to-atom exchange rate can be set to any meaningful value), i.e., +share-to-atom-ex-rate = 1 atom per share. Then at the global pool level we +have, the size of the pool is 40 Atoms, and the amount of issued shares is +equal to 40. And for each validator we store in their corresponding data +structure that each has 10 shares of the bonded pool. Now lets assume that the +validator p4 starts process of unbonding of 5 shares. Then the total size of +the pool is decreased and now it will be 35 shares and the amount of Atoms is +35 . Note that the only change in other data structures needed is reducing the +number of shares for a validator p4 from 10 to 5. + +Let's consider now the case where a validator p1 wants to bond 15 more atoms to +the pool. Now the size of the pool is 50, and as the exchange rate hasn't +changed (1 share is still worth 1 Atom), we need to create more shares, i.e. we +now have 50 shares in the pool in total. Validators p2, p3 and p4 still have +(correspondingly) 10, 10 and 5 shares each worth of 1 atom per share, so we +don't need to modify anything in their corresponding data structures. But p1 +now has 25 shares, so we update the amount of shares owned by p1 in its +data structure. Note that apart from the size of the pool that is in Atoms, all +other data structures refer only to shares. + +Finally, let's consider what happens when new Atoms are created and added to +the pool due to inflation. Let's assume that the inflation rate is 10 percent +and that it is applied to the current state of the pool. This means that 5 +Atoms are created and added to the pool and that each validator now +proportionally increase it's Atom count. Let's analyse how this change is +reflected in the data structures. First, the size of the pool is increased and +is now 55 atoms. As a share of each validator in the pool hasn't changed, this +means that the total number of shares stay the same (50) and that the amount of +shares of each validator stays the same (correspondingly 25, 10, 10, 5). But +the exchange rate has changed and each share is now worth 55/50 Atoms per +share, so each validator has effectively increased amount of Atoms it has. So +validators now have (correspondingly) 55/2, 55/5, 55/5 and 55/10 Atoms. + +The concepts of the pool and its shares is at the core of the accounting in the +Staking module. It is used for managing the global pools (such as bonding and +unbonding pool), but also for distribution of Atoms between validator and its +delegators (we will explain this in section X). + +#### Delegator shares + +A validator is, depending on its status, contributing Atoms to either the +unbonding or unbonded pool - the validator in turn holds some amount of pool +shares. Not all of a validator's Atoms (and respective shares) are necessarily +owned by the validator, some may be owned by delegators to that validator. The +mechanism for distribution of Atoms (and shares) between a validator and its +delegators is based on a notion of delegator shares. More precisely, every +validator is issuing (local) delegator shares +(`Validator.IssuedDelegatorShares`) that represents some portion of global +shares managed by the validator (`Validator.GlobalStakeShares`). The principle +behind managing delegator shares is the same as described in [Section](#The +pool and the share). We now illustrate it with an example. + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXX TODO make way less verbose lets use bullet points to describe the example +XXX Also need to update to not include bonded atom provisions all atoms are +XXX redistributed with the fee pool now + +Let's consider 4 validators p1, p2, p3 and p4, and assume that each validator +has bonded 10 Atoms to the bonded pool. Furthermore, let's assume that we have +issued initially 40 global shares, i.e., that +`share-to-atom-exchange-rate = 1 atom per share`. So we will set +`GlobalState.BondedPool = 40` and `GlobalState.BondedShares = 40` and in the +Validator data structure of each validator `Validator.GlobalStakeShares = 10`. +Furthermore, each validator issued 10 delegator shares which are initially +owned by itself, i.e., `Validator.IssuedDelegatorShares = 10`, where +`delegator-share-to-global-share-ex-rate = 1 global share per delegator share`. +Now lets assume that a delegator d1 delegates 5 atoms to a validator p1 and +consider what are the updates we need to make to the data structures. First, +`GlobalState.BondedPool = 45` and `GlobalState.BondedShares = 45`. Then, for +validator p1 we have `Validator.GlobalStakeShares = 15`, but we also need to +issue also additional delegator shares, i.e., +`Validator.IssuedDelegatorShares = 15` as the delegator d1 now owns 5 delegator +shares of validator p1, where each delegator share is worth 1 global shares, +i.e, 1 Atom. Lets see now what happens after 5 new Atoms are created due to +inflation. In that case, we only need to update `GlobalState.BondedPool` which +is now equal to 50 Atoms as created Atoms are added to the bonded pool. Note +that the amount of global and delegator shares stay the same but they are now +worth more as share-to-atom-exchange-rate is now worth 50/45 Atoms per share. +Therefore, a delegator d1 now owns: + +`delegatorCoins = 5 (delegator shares) * 1 (delegator-share-to-global-share-ex-rate) * 50/45 (share-to-atom-ex-rate) = 5.55 Atoms` + diff --git a/docs/_attic/staking/public-testnet.rst b/docs/_attic/staking/public-testnet.rst deleted file mode 100644 index 587c025b17..0000000000 --- a/docs/_attic/staking/public-testnet.rst +++ /dev/null @@ -1,64 +0,0 @@ -Public Testnets -=============== - -Here we'll cover the basics of joining a public testnet. These testnets -come and go with various names are we release new versions of tendermint -core. This tutorial covers joining the ``gaia-1`` testnet. To join -other testnets, choose different initialization files, described below. - -Get Tokens ----------- - -If you haven't already `created a key <../key-management.html>`__, -do so now. Copy your key's address and enter it into -`this utility `__ which will send you -some ``steak`` testnet tokens. - -Get Files ---------- - -Now, to sync with the testnet, we need the genesis file and seeds. The -easiest way to get them is to clone and navigate to the tendermint -testnet repo: - -:: - - git clone https://github.com/tendermint/testnets ~/testnets - cd ~/testnets/gaia-1/gaia - -NOTE: to join a different testnet, change the ``gaia-1/gaia`` filepath -to another directory with testnet inititalization files *and* an -active testnet. - -Start Node ----------- - -Now we can start a new node:it may take awhile to sync with the -existing testnet. - -:: - - gaia node start --home=$HOME/testnets/gaia-1/gaia - -Once blocks slow down to about one per second, you're all caught up. - -The ``gaia node start`` command will automaticaly generate a validator -private key found in ``~/testnets/gaia-1/gaia/priv_validator.json``. - -Finally, let's initialize the gaia client to interact with the testnet: - -:: - - gaia client init --chain-id=gaia-1 --node=tcp://localhost:26657 - -and check our balance: - -:: - - gaia client query account $MYADDR - -Where ``$MYADDR`` is the address originally generated by ``gaia keys new bob``. - -You are now ready to declare candidacy or delegate some steaks. See the -`staking module overview <./staking-module.html>`__ for more information -on using the ``gaia client``. diff --git a/docs/_attic/stakingSpec1.md b/docs/_attic/staking/stakingSpec1.md similarity index 100% rename from docs/_attic/stakingSpec1.md rename to docs/_attic/staking/stakingSpec1.md diff --git a/docs/_attic/stakingSpec2.md b/docs/_attic/staking/stakingSpec2.md similarity index 100% rename from docs/_attic/stakingSpec2.md rename to docs/_attic/staking/stakingSpec2.md diff --git a/docs/_attic/staking/testnet.md b/docs/_attic/staking/testnet.md new file mode 100644 index 0000000000..b2bbd8f1a3 --- /dev/null +++ b/docs/_attic/staking/testnet.md @@ -0,0 +1,94 @@ +# Testnet Setup + +**Note:** This document is incomplete and may not be up-to-date with the +state of the code. + +See the [installation guide](../sdk/install.html) for details on +installation. + +Here is a quick example to get you off your feet: + +First, generate a couple of genesis transactions to be incorporated into +the genesis file, this will create two keys with the password +`1234567890`: + +``` +gaiad init gen-tx --name=foo --home=$HOME/.gaiad1 +gaiad init gen-tx --name=bar --home=$HOME/.gaiad2 +gaiacli keys list +``` + +**Note:** If you've already run these tests you may need to overwrite +keys using the `--owk` flag When you list the keys you should see two +addresses, we'll need these later so take note. Now let's actually +create the genesis files for both nodes: + +``` +cp -a ~/.gaiad2/config/gentx/. ~/.gaiad1/config/gentx/ +cp -a ~/.gaiad1/config/gentx/. ~/.gaiad2/config/gentx/ +gaiad init --gen-txs --home=$HOME/.gaiad1 --chain-id=test-chain +gaiad init --gen-txs --home=$HOME/.gaiad2 --chain-id=test-chain +``` + +**Note:** If you've already run these tests you may need to overwrite +genesis using the `-o` flag. What we just did is copy the genesis +transactions between each of the nodes so there is a common genesis +transaction set; then we created both genesis files independently from +each home directory. Importantly both nodes have independently created +their `genesis.json` and `config.toml` files, which should be identical +between nodes. + +Great, now that we've initialized the chains, we can start both nodes in +the background: + +``` +gaiad start --home=$HOME/.gaiad1 &> gaia1.log & +NODE1_PID=$! +gaia start --home=$HOME/.gaiad2 &> gaia2.log & +NODE2_PID=$! +``` + +Note that we save the PID so we can later kill the processes. You can +peak at your logs with `tail gaia1.log`, or follow them for a bit with +`tail -f gaia1.log`. + +Nice. We can also lookup the validator set: + +``` +gaiacli validatorset +``` + +Then, we try to transfer some `steak` to another account: + +``` +gaiacli account +gaiacli account +gaiacli send --amount=10steak --to= --name=foo --chain-id=test-chain +``` + +**Note:** We need to be careful with the `chain-id` and `sequence` + +Check the balance & sequence with: + +``` +gaiacli account +``` + +To confirm for certain the new validator is active, check tendermint: + +``` +curl localhost:46657/validators +``` + +Finally, to relinquish all your power, unbond some coins. You should see +your VotingPower reduce and your account balance increase. + +``` +gaiacli unbond --chain-id= --name=test +``` + +That's it! + +**Note:** TODO demonstrate edit-candidacy **Note:** TODO demonstrate +delegation **Note:** TODO demonstrate unbond of delegation **Note:** +TODO demonstrate unbond candidate From 4e87cdf4443fc4b16697eff993dac0626d44fcfb Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 29 Jun 2018 01:59:52 -0400 Subject: [PATCH 50/77] add links for modules and clients --- docs/README.md | 14 ++++++------ docs/clients/cli.md | 6 +++++ docs/clients/keys.md | 6 +++++ docs/clients/node.md | 10 +++++++++ docs/clients/rest.md | 6 +++++ docs/modules/README.md | 51 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 docs/clients/cli.md create mode 100644 docs/clients/keys.md create mode 100644 docs/clients/node.md create mode 100644 docs/clients/rest.md create mode 100644 docs/modules/README.md diff --git a/docs/README.md b/docs/README.md index cf4494003a..f47fafa114 100644 --- a/docs/README.md +++ b/docs/README.md @@ -51,16 +51,16 @@ NOTE: This documentation is a work-in-progress! interfaces for clients to use! - [Modules](modules) - - [Bank](modules/bank.md) - - [Staking](modules/staking.md) - - [Slashing](modules/slashing.md) - - [Provisions](modules/provisions.md) - - [Governance](modules/governance.md) - - [IBC](modules/ibc.md) + - [Bank](modules/README.md#bank) + - [Staking](modules/README.md#stake) + - [Slashing](modules/README.md#slashing) + - [Provisions](modules/README.md#provisions) + - [Governance](modules/README.md#governance) + - [IBC](modules/README.md#ibc) - [Clients](clients) - [Running a Node](clients/node.md) - Run a full node! - [Key Management](clients/keys.md) - Managing user keys - [CLI](clients/cli.md) - Queries and transactions via command line - - [Light Client Daemon](clients/lcd.md) - Queries and transactions via REST + - [REST](clients/rest.md) - Queries and transactions via REST API diff --git a/docs/clients/cli.md b/docs/clients/cli.md new file mode 100644 index 0000000000..46490cad91 --- /dev/null +++ b/docs/clients/cli.md @@ -0,0 +1,6 @@ +# CLI + +See `gaiacli --help` for more details. + +Also see the [testnet +tutorial](https://github.com/cosmos/cosmos-sdk/tree/develop/cmd/gaia/testnets). diff --git a/docs/clients/keys.md b/docs/clients/keys.md new file mode 100644 index 0000000000..4b5a17cb3a --- /dev/null +++ b/docs/clients/keys.md @@ -0,0 +1,6 @@ +# Keys + +See `gaiacli keys --help`. + +Also see the [testnet +tutorial](https://github.com/cosmos/cosmos-sdk/tree/develop/cmd/gaia/testnets). diff --git a/docs/clients/node.md b/docs/clients/node.md new file mode 100644 index 0000000000..71d4846fd9 --- /dev/null +++ b/docs/clients/node.md @@ -0,0 +1,10 @@ +# Running a Node + +TODO: document `gaiad` + +Options for running the `gaiad` binary are effectively the same as for `tendermint`. +See `gaiad --help` and the +[guide to using Tendermint](https://github.com/tendermint/tendermint/blob/master/docs/using-tendermint.md) +for more details. + + diff --git a/docs/clients/rest.md b/docs/clients/rest.md new file mode 100644 index 0000000000..190eeb1f34 --- /dev/null +++ b/docs/clients/rest.md @@ -0,0 +1,6 @@ +# REST + +See `gaiacli advanced rest-server --help` for more. + +Also see the +[work in progress API specification](https://github.com/cosmos/cosmos-sdk/pull/1314) diff --git a/docs/modules/README.md b/docs/modules/README.md new file mode 100644 index 0000000000..53e02687ea --- /dev/null +++ b/docs/modules/README.md @@ -0,0 +1,51 @@ +# Bank + +The `x/bank` module is for transferring coins between accounts. + +See the [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank). + +# Stake + +The `x/stake` module is for Cosmos Delegated-Proof-of-Stake. + +See the [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/stake). + +See the +[specification](https://github.com/cosmos/cosmos-sdk/tree/develop/docs/spec/staking) + +# Slashing + +The `x/slashing` module is for Cosmos Delegated-Proof-of-Stake. + +See the [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/slashing) + +See the +[specification](https://github.com/cosmos/cosmos-sdk/tree/develop/docs/spec/slashing) + +# Provisions + +The `x/provisions` module is for distributing fees and inflation across bonded +stakeholders. + +See the [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/provisions) + +See the +[specification](https://github.com/cosmos/cosmos-sdk/tree/develop/docs/spec/provisions) + +# Governance + +The `x/gov` module is for bonded stakeholders to make proposals and vote on them. + +See the [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/gov) + +See the +[specification](https://github.com/cosmos/cosmos-sdk/tree/develop/docs/spec/governance) + +# IBC + +The `x/ibc` module is for InterBlockchain Communication. + +See the [API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/ibc) + +See the +[specification](https://github.com/cosmos/cosmos-sdk/tree/develop/docs/spec/ibc) From a7cdea59312dd9b1f22d4d60821360471be692bb Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 29 Jun 2018 02:03:59 -0400 Subject: [PATCH 51/77] minor fix --- docs/README.md | 2 +- docs/clients/cli.md | 2 ++ docs/clients/key-management.md | 7 ------- docs/clients/keys.md | 4 ++++ 4 files changed, 7 insertions(+), 8 deletions(-) delete mode 100644 docs/clients/key-management.md diff --git a/docs/README.md b/docs/README.md index f47fafa114..77dfd1f3ff 100644 --- a/docs/README.md +++ b/docs/README.md @@ -62,5 +62,5 @@ NOTE: This documentation is a work-in-progress! - [Running a Node](clients/node.md) - Run a full node! - [Key Management](clients/keys.md) - Managing user keys - [CLI](clients/cli.md) - Queries and transactions via command line - - [REST](clients/rest.md) - Queries and transactions via REST + - [REST Light Client Daemon](clients/rest.md) - Queries and transactions via REST API diff --git a/docs/clients/cli.md b/docs/clients/cli.md index 46490cad91..dbd234d372 100644 --- a/docs/clients/cli.md +++ b/docs/clients/cli.md @@ -4,3 +4,5 @@ See `gaiacli --help` for more details. Also see the [testnet tutorial](https://github.com/cosmos/cosmos-sdk/tree/develop/cmd/gaia/testnets). + +TODO: cleanup the UX and document this properly. diff --git a/docs/clients/key-management.md b/docs/clients/key-management.md deleted file mode 100644 index 1474989b93..0000000000 --- a/docs/clients/key-management.md +++ /dev/null @@ -1,7 +0,0 @@ -# Key Management - -Here we cover many aspects of handling keys within the Cosmos SDK -framework. - -// TODO add relevant key discussion -(related https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography) diff --git a/docs/clients/keys.md b/docs/clients/keys.md index 4b5a17cb3a..6d9732868d 100644 --- a/docs/clients/keys.md +++ b/docs/clients/keys.md @@ -1,6 +1,10 @@ # Keys +See the [Tendermint specification](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography) for how we work with keys. + See `gaiacli keys --help`. Also see the [testnet tutorial](https://github.com/cosmos/cosmos-sdk/tree/develop/cmd/gaia/testnets). + +TODO: cleanup the UX and document this properly From b4e70e356e9f341c66d52d12d8533c719f9cee31 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 00:06:49 -0700 Subject: [PATCH 52/77] Merge PR #1453: Fix build error on develop --- docs/core/examples/app4.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index 0b27688549..007d2842bc 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -1,7 +1,7 @@ package app import ( - abci "github.com/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" From 337e87b22899b9089ffe625df7a2baa9ac42ee38 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 00:22:06 -0700 Subject: [PATCH 53/77] Merge PR #1449: crypto/keys: make bcrypt security param a var This is done so that the time spent on bcrypt during test cases can be reduced. This change reduces the amount of time lcd tests spend on bcrypt from 76% to 40%. (We need to reduce the number of calls to bcrypt in a seperate PR, along with fixing other sources of slowness) Making the bcrypt security parameter a var shouldn't be a security issue: One can't verify an invalid key by maliciously changing the bcrypt parameter during a runtime vulnerability. The main security threat this then exposes would be something that changes this during runtime before the user creates their key. This vulnerability must succeed to update this to that same value before every subsequent call to gaiacli keys in future startups / or the attacker must get access to the filesystem. However, with this same threat model (changing variables in runtime), one can cause the user to sign a different tx than what they see, which is a significantly cheaper attack then breaking a bcrypt hash. (Recall that the nonce still exists to break rainbow tables) --- client/lcd/lcd_test.go | 4 ++++ crypto/keys/mintkey.go | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index feaadc922d..e3b19c999d 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -29,6 +29,10 @@ import ( stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest" ) +func init() { + cryptoKeys.BcryptSecurityParameter = 1 +} + func TestKeys(t *testing.T) { name, password := "test", "1234567890" addr, seed := CreateAddr(t, "test", password, GetKB(t)) diff --git a/crypto/keys/mintkey.go b/crypto/keys/mintkey.go index 9ec0d10458..8b0a1870bb 100644 --- a/crypto/keys/mintkey.go +++ b/crypto/keys/mintkey.go @@ -16,6 +16,21 @@ const ( blockTypePubKey = "TENDERMINT PUBLIC KEY" ) +// Make bcrypt security parameter var, so it can be changed within the lcd test +// Making the bcrypt security parameter a var shouldn't be a security issue: +// One can't verify an invalid key by maliciously changing the bcrypt +// parameter during a runtime vulnerability. The main security +// threat this then exposes would be something that changes this during +// runtime before the user creates their key. This vulnerability must +// succeed to update this to that same value before every subsequent call +// to gaiacli keys in future startups / or the attacker must get access +// to the filesystem. However, with a similar threat model (changing +// variables in runtime), one can cause the user to sign a different tx +// than what they see, which is a significantly cheaper attack then breaking +// a bcrypt hash. (Recall that the nonce still exists to break rainbow tables) +// TODO: Consider increasing default +var BcryptSecurityParameter = 12 + func armorInfoBytes(bz []byte) string { return armorBytes(bz, blockTypeKeyInfo) } @@ -91,7 +106,7 @@ func unarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey, func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) { saltBytes = crypto.CRandBytes(16) - key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016) + key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error()) } @@ -101,7 +116,7 @@ func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte } func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) { - key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016) + key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter) if err != nil { cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error()) } From b66a5cc85377b0ae260a2c88e6f864ac39d46285 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 00:37:16 -0700 Subject: [PATCH 54/77] Merge PR #1455: tools: Add make format This adds a command to automatically fix gofmt and misspell errors. --- CHANGELOG.md | 1 + Makefile | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ff5efbfb3..0b48c46a16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ FEATURES * unconvert * ineffassign * errcheck +* [tools] Add `make format` command to automate fixing misspell and gofmt errors. * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates * [tests] Add WaitForNextNBlocksTM helper method * [types] Switches internal representation of Int/Uint/Rat to use pointers diff --git a/Makefile b/Makefile index 46dd5dae5e..cc70aa6f72 100644 --- a/Makefile +++ b/Makefile @@ -112,6 +112,10 @@ test_lint: !(gometalinter.v2 --disable-all --enable='errcheck' --vendor ./... | grep -v "client/") find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s +format: + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -w -s + find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs misspell -w + benchmark: @go test -bench=. $(PACKAGES_NOCLITEST) @@ -183,4 +187,4 @@ remotenet-status: # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html -.PHONY: build build_examples install install_examples install_debug dist check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update build-linux build-docker-gaiadnode localnet-start localnet-stop remotenet-start remotenet-stop remotenet-status +.PHONY: build build_examples install install_examples install_debug dist check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update build-linux build-docker-gaiadnode localnet-start localnet-stop remotenet-start remotenet-stop remotenet-status format From 24a68d3bdf7adb1096af7a9aa2c422de8f712c5b Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 00:52:32 -0700 Subject: [PATCH 55/77] Merge PR #1451: crypto/keys: move checksum size into constants Closes #1410 --- crypto/encode_test.go | 2 +- crypto/keys/bip39/wordcodec.go | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/crypto/encode_test.go b/crypto/encode_test.go index f0627d4c4a..f9ab851b40 100644 --- a/crypto/encode_test.go +++ b/crypto/encode_test.go @@ -60,7 +60,7 @@ func ExamplePrintRegisteredTypes() { func TestKeyEncodings(t *testing.T) { cases := []struct { privKey tcrypto.PrivKey - privSize, pubSize int // binary sizes + privSize, pubSize int // binary sizes with the amino overhead }{ { privKey: tcrypto.GenPrivKeyEd25519(), diff --git a/crypto/keys/bip39/wordcodec.go b/crypto/keys/bip39/wordcodec.go index d874fe58cb..074d1393c0 100644 --- a/crypto/keys/bip39/wordcodec.go +++ b/crypto/keys/bip39/wordcodec.go @@ -12,8 +12,12 @@ type ValidSentenceLen uint8 const ( // FundRaiser is the sentence length used during the cosmos fundraiser (12 words). FundRaiser ValidSentenceLen = 12 + // Size of the checksum employed for the fundraiser + FundRaiserChecksumSize = 4 // FreshKey is the sentence length used for newly created keys (24 words). FreshKey ValidSentenceLen = 24 + // Size of the checksum employed for new keys + FreshKeyChecksumSize = 8 ) // NewMnemonic will return a string consisting of the mnemonic words for @@ -23,9 +27,11 @@ func NewMnemonic(len ValidSentenceLen) (words []string, err error) { var entropySize int switch len { case FundRaiser: - entropySize = 128 + // entropySize = 128 + entropySize = int(len)*11 - FundRaiserChecksumSize case FreshKey: - entropySize = 256 + // entropySize = 256 + entropySize = int(len)*11 - FreshKeyChecksumSize } var entropy []byte entropy, err = bip39.NewEntropy(entropySize) From 0d28eda1464a00ddecf356215c2677411516d54e Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 13:02:45 -0700 Subject: [PATCH 56/77] Merge PR #1463: docs: Fix dependencies, from monorepo merge Closes #1456 --- docs/core/app1.md | 60 ++++++++++++++++----------------- docs/core/app4.md | 10 +++--- docs/core/examples/app2.go | 2 +- docs/spec/slashing/end_block.md | 10 +++--- examples/README.md | 39 +++++++++++---------- 5 files changed, 60 insertions(+), 61 deletions(-) diff --git a/docs/core/app1.md b/docs/core/app1.md index ac07e4755d..91e75966a7 100644 --- a/docs/core/app1.md +++ b/docs/core/app1.md @@ -1,7 +1,7 @@ # The Basics Here we introduce the basic components of an SDK by building `App1`, a simple bank. -Users have an account address and an account, and they can send coins around. +Users have an account address and an account, and they can send coins around. It has no authentication, and just uses JSON for serialization. The complete code can be found in [app1.go](examples/app1.go). @@ -22,11 +22,11 @@ type Msg interface { // ValidateBasic does a simple validation check that // doesn't require access to any other information. ValidateBasic() error - + // Get the canonical byte representation of the Msg. // This is what is signed. GetSignBytes() []byte - + // Signers returns the addrs of signers that must sign. // CONTRACT: All signatures must be present to be valid. // CONTRACT: Returns addrs in some deterministic order. @@ -38,7 +38,7 @@ type Msg interface { The `Msg` interface allows messages to define basic validity checks, as well as what needs to be signed and who needs to sign it. -For instance, take the simple token sending message type from app1.go: +For instance, take the simple token sending message type from app1.go: ```go // MsgSend to send coins from Input to Output @@ -134,7 +134,7 @@ type KVStore interface { Note it is unforgiving - it panics on nil keys! -The primary implementation of the KVStore is currently the IAVL store. In the future, we plan to support other Merkle KVStores, +The primary implementation of the KVStore is currently the IAVL store. In the future, we plan to support other Merkle KVStores, like Ethereum's radix trie. As we'll soon see, apps have many distinct KVStores, each with a different name and for a different concern. @@ -157,7 +157,7 @@ Only handlers which were given explict access to a store's key will be able to a ### Context -The SDK uses a `Context` to propogate common information across functions. +The SDK uses a `Context` to propogate common information across functions. Most importantly, the `Context` restricts access to KVStores based on object-capability keys. Only handlers which have been given explicit access to a key will be able to access the corresponding store. @@ -177,10 +177,10 @@ func newFooHandler(key sdk.StoreKey) sdk.Handler { [context.Context](https://golang.org/pkg/context/), which has become ubiquitous in networking middleware and routing applications as a means to easily propogate request context through handler functions. -Many methods on SDK objects receive a context as the first argument. +Many methods on SDK objects receive a context as the first argument. -The Context also contains the -[block header](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#header), +The Context also contains the +[block header](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#header), which includes the latest timestamp from the blockchain and other information about the latest block. See the [Context API @@ -189,7 +189,7 @@ docs](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Context) for more det ### Result Handler takes a Context and Msg and returns a Result. -Result is motivated by the corresponding [ABCI result](https://github.com/tendermint/abci/blob/master/types/types.proto#L165). +Result is motivated by the corresponding [ABCI result](https://github.com/tendermint/tendermint/abci/blob/master/types/types.proto#L165). It contains return values, error information, logs, and meta data about the transaction: ```go @@ -268,7 +268,7 @@ type appAccount struct { } ``` -Coins is a useful type provided by the SDK for multi-asset accounts. +Coins is a useful type provided by the SDK for multi-asset accounts. We could just use an integer here for a single coin type, but it's worth [getting to know Coins](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Coins). @@ -349,7 +349,7 @@ func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result { ``` The handler is straight forward. We first load the KVStore from the context using the granted capability key. -Then we make two state transitions: one for the sender, one for the receiver. +Then we make two state transitions: one for the sender, one for the receiver. Each one involves JSON unmarshalling the account bytes from the store, mutating the `Coins`, and JSON marshalling back into the store. @@ -359,7 +359,7 @@ And that's that! The final piece before putting it all together is the `Tx`. While `Msg` contains the content for particular functionality in the application, the actual input -provided by the user is a serialized `Tx`. Applications may have many implementations of the `Msg` interface, +provided by the user is a serialized `Tx`. Applications may have many implementations of the `Msg` interface, but they should have only a single implementation of `Tx`: @@ -371,7 +371,7 @@ type Tx interface { } ``` -The `Tx` just wraps a `[]Msg`, and may include additional authentication data, like signatures and account nonces. +The `Tx` just wraps a `[]Msg`, and may include additional authentication data, like signatures and account nonces. Applications must specify how their `Tx` is decoded, as this is the ultimate input into the application. We'll talk more about `Tx` types later, specifically when we introduce the `StdTx`. @@ -409,11 +409,11 @@ func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { Finally, we stitch it all together using the `BaseApp`. The BaseApp is an abstraction over the [Tendermint -ABCI](https://github.com/tendermint/abci) that +ABCI](https://github.com/tendermint/tendermint/abci) that simplifies application development by handling common low-level concerns. It serves as the mediator between the two key components of an SDK app: the store and the message handlers. The BaseApp implements the -[`abci.Application`](https://godoc.org/github.com/tendermint/abci/types#Application) interface. +[`abci.Application`](https://godoc.org/github.com/tendermint/tendermint/abci/types#Application) interface. See the [BaseApp API documentation](https://godoc.org/github.com/cosmos/cosmos-sdk/baseapp) for more details. @@ -422,22 +422,22 @@ Here is the complete setup for App1: ```go func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { cdc := wire.NewCodec() - + // Create the base application object. app := bapp.NewBaseApp(app1Name, cdc, logger, db) - + // Create a capability key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") - + // Determine how transactions are decoded. app.SetTxDecoder(txDecoder) - + // Register message routes. // Note the handler receives the keyAccount and thus // gets access to the account store. app.Router(). AddRoute("bank", NewApp1Handler(keyAccount)) - + // Mount stores and load the latest state. app.MountStoresIAVL(keyAccount) err := app.LoadLatestVersion(keyAccount) @@ -450,8 +450,8 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { Every app will have such a function that defines the setup of the app. It will typically be contained in an `app.go` file. -We'll talk about how to connect this app object with the CLI, a REST API, -the logger, and the filesystem later in the tutorial. For now, note that this is where we +We'll talk about how to connect this app object with the CLI, a REST API, +the logger, and the filesystem later in the tutorial. For now, note that this is where we register handlers for messages and grant them access to stores. Here, we have only a single Msg type, `bank`, a single store for accounts, and a single handler. @@ -465,30 +465,30 @@ Since we only have one store, we only mount one. ## Execution We're now done the core logic of the app! From here, we can write tests in Go -that initialize the store with accounts and execute transactions by calling +that initialize the store with accounts and execute transactions by calling the `app.DeliverTx` method. In a real setup, the app would run as an ABCI application on top of the Tendermint consensus engine. It would be initialized by a Genesis file, and it -would be driven by blocks of transactions committed by the underlying Tendermint +would be driven by blocks of transactions committed by the underlying Tendermint consensus. We'll talk more about ABCI and how this all works a bit later, but -feel free to check the -[specification](https://github.com/tendermint/abci/blob/master/specification.md). +feel free to check the +[specification](https://github.com/tendermint/tendermint/abci/blob/master/specification.md). We'll also see how to connect our app to a complete suite of components -for running and using a live blockchain application. +for running and using a live blockchain application. For now, we note the follow sequence of events occurs when a transaction is received (through `app.DeliverTx`): - serialized transaction is received by `app.DeliverTx` - transaction is deserialized using `TxDecoder` -- for each message in the transaction, run `msg.ValidateBasic()` +- for each message in the transaction, run `msg.ValidateBasic()` - for each message in the transaction, load the appropriate handler and execute it with the message ## Conclusion -We now have a complete implementation of a simple app! +We now have a complete implementation of a simple app! In the next section, we'll add another Msg type and another store. Once we have multiple message types we'll need a better way of decoding transactions, since we'll need to decode diff --git a/docs/core/app4.md b/docs/core/app4.md index d5d70bc3f4..d7226b4666 100644 --- a/docs/core/app4.md +++ b/docs/core/app4.md @@ -5,7 +5,7 @@ delineated boundary between the Cosmos-SDK and Tendermint. It separates the logical state transition machine of your application from its secure replication across many physical machines. -By providing a clear, language agnostic boundary between applications and consensus, +By providing a clear, language agnostic boundary between applications and consensus, ABCI provides tremendous developer flexibility and [support in many languages](https://tendermint.com/ecosystem). That said, it is still quite a low-level protocol, and requires frameworks to be built to abstract over that low-level componentry. @@ -14,9 +14,9 @@ The Cosmos-SDK is one such framework. While we've already seen `DeliverTx`, the workhorse of any ABCI application, here we will introduce the other ABCI requests sent by Tendermint, and how we can use them to build more advanced applications. For a more complete -depiction of the ABCI and how its used, see +depiction of the ABCI and how its used, see [the -specification](https://github.com/tendermint/abci/blob/master/specification.md) +specification](https://github.com/tendermint/tendermint/abci/blob/master/specification.md) ## InitChain @@ -26,8 +26,8 @@ which is called once by Tendermint the very first time the application boots up. The InitChain request contains a variety of Tendermint information, like the consensus parameters and an initial validator set, but it also contains an opaque blob of -application specific bytes - typically JSON encoded. -Apps can decide what to do with all of this information by calling the +application specific bytes - typically JSON encoded. +Apps can decide what to do with all of this information by calling the `app.SetInitChainer` method. For instance, let's introduce a `GenesisAccount` struct that can be JSON encoded diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index ff9baa7bcd..d7490765e5 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" - "github.com/tendermint/go-crypto" + "github.com/tendermint/tendermint/crypto" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" diff --git a/docs/spec/slashing/end_block.md b/docs/spec/slashing/end_block.md index 5958d0a215..6ac24138ba 100644 --- a/docs/spec/slashing/end_block.md +++ b/docs/spec/slashing/end_block.md @@ -1,4 +1,4 @@ -# End-Block +# End-Block ## Slashing @@ -6,16 +6,16 @@ Tendermint blocks can include [Evidence](https://github.com/tendermint/tendermint/blob/develop/docs/spec/blockchain/blockchain.md#evidence), which indicates that a validator committed malicious behaviour. The relevant information is forwarded to the application as [ABCI -Evidence](https://github.com/tendermint/abci/blob/develop/types/types.proto#L259), so the validator an be accordingly punished. +Evidence](https://github.com/tendermint/tendermint/abci/blob/develop/types/types.proto#L259), so the validator an be accordingly punished. -For some `evidence` to be valid, it must satisfy: +For some `evidence` to be valid, it must satisfy: `evidence.Timestamp >= block.Timestamp - MAX_EVIDENCE_AGE` where `evidence.Timestamp` is the timestamp in the block at height `evidence.Height` and `block.Timestamp` is the current block timestamp. -If valid evidence is included in a block, the validator's stake is reduced by `SLASH_PROPORTION` of +If valid evidence is included in a block, the validator's stake is reduced by `SLASH_PROPORTION` of what their stake was when the equivocation occurred (rather than when the evidence was discovered): ``` @@ -89,7 +89,7 @@ for val in block.Validators: // else previous == val not in block.AbsentValidators, no change // validator must be active for at least SIGNED_BLOCKS_WINDOW - // before they can be automatically unbonded for failing to be + // before they can be automatically unbonded for failing to be // included in 50% of the recent LastCommits minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW minSigned = SIGNED_BLOCKS_WINDOW / 2 diff --git a/examples/README.md b/examples/README.md index 55db606c4c..3f45e025cf 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,7 +6,7 @@ what is happening under the hood. ## Setup and Install -You will need to have go installed on your computer. Please refer to the [cosmos testnet tutorial](https://cosmos.network/validators/tutorial), which will always have the most updated instructions on how to get setup with go and the cosmos repository. +You will need to have go installed on your computer. Please refer to the [cosmos testnet tutorial](https://cosmos.network/validators/tutorial), which will always have the most updated instructions on how to get setup with go and the cosmos repository. Once you have go installed, run the command: @@ -27,7 +27,7 @@ make get_tools // run make update_tools if you already had it installed make get_vendor_deps make install_examples ``` -Then run `make install_examples`, which creates binaries for `basecli` and `basecoind`. You can look at the Makefile if you want to see the details on what these make commands are doing. +Then run `make install_examples`, which creates binaries for `basecli` and `basecoind`. You can look at the Makefile if you want to see the details on what these make commands are doing. ## Using basecli and basecoind @@ -40,7 +40,7 @@ basecoind version They should read something like `0.17.1-5d18d5f`, but the versions will be constantly updating so don't worry if your version is higher that 0.17.1. That's a good thing. -Note that you can always check help in the terminal by running `basecli -h` or `basecoind -h`. It is good to check these out if you are stuck, because updates to the code base might slightly change the commands, and you might find the correct command in there. +Note that you can always check help in the terminal by running `basecli -h` or `basecoind -h`. It is good to check these out if you are stuck, because updates to the code base might slightly change the commands, and you might find the correct command in there. Let's start by initializing the basecoind daemon. Run the command @@ -60,7 +60,7 @@ And you should see something like this: } ``` -This creates the `~/.basecoind folder`, which has config.toml, genesis.json, node_key.json, priv_validator.json. Take some time to review what is contained in these files if you want to understand what is going on at a deeper level. +This creates the `~/.basecoind folder`, which has config.toml, genesis.json, node_key.json, priv_validator.json. Take some time to review what is contained in these files if you want to understand what is going on at a deeper level. ## Generating keys @@ -79,7 +79,7 @@ Repeat the passphrase: Enter your recovery seed phrase: ``` -You just created your first locally stored key, under the name alice, and this account is linked to the private key that is running the basecoind validator node. Once you do this, the ~/.basecli folder is created, which will hold the alice key and any other keys you make. Now that you have the key for alice, you can start up the blockchain by running +You just created your first locally stored key, under the name alice, and this account is linked to the private key that is running the basecoind validator node. Once you do this, the ~/.basecli folder is created, which will hold the alice key and any other keys you make. Now that you have the key for alice, you can start up the blockchain by running ``` basecoind start @@ -100,7 +100,7 @@ You can see your keys with the command: basecli keys list ``` -You should now see alice, bob and charlie's account all show up. +You should now see alice, bob and charlie's account all show up. ``` NAME: ADDRESS: PUBKEY: @@ -123,11 +123,11 @@ Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alice's address we got from The following command will send coins from alice, to bob: ``` -basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D +basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D --sequence=0 --chain-id=test-chain-AE4XQo ``` -Flag Descriptions: +Flag Descriptions: - `name` is the name you gave your key - `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file - `sequence` is a tally of how many transactions have been made by this account. Since this is the first tx on this account, it is 0 @@ -142,7 +142,7 @@ basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail: ``` -basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E +basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E --sequence=0 --chain-id=test-chain-AE4XQo ``` @@ -151,7 +151,7 @@ Note how we use the ``--name`` flag to select a different account to send from. Lets now try to send from bob back to alice: ``` -basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD +basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD --sequence=1 --chain-id=test-chain-AE4XQo ``` @@ -171,8 +171,8 @@ That is the basic implementation of basecoin! **WARNING:** Running these commands will wipe out any existing information in both the ``~/.basecli`` and ``~/.basecoind`` directories, including private keys. This should be no problem considering that basecoin -is just an example, but it is always good to pay extra attention when -you are removing private keys, in any scenario involving a blockchain. +is just an example, but it is always good to pay extra attention when +you are removing private keys, in any scenario involving a blockchain. To remove all the files created and refresh your environment (e.g., if starting this tutorial again or trying something new), the following @@ -212,7 +212,7 @@ The Basecoin state consists entirely of a set of accounts. Each account contains an address, a public key, a balance in many different coin denominations, and a strictly increasing sequence number for replay protection. This type of account was directly inspired by accounts in Ethereum, and is -unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). +unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). ``` type BaseAccount struct { @@ -225,7 +225,7 @@ type BaseAccount struct { You can also add more fields to accounts, and basecoin actually does so. Basecoin adds a Name field in order to show how easily the base account structure can be -modified to suit any applications needs. It takes the `auth.BaseAccount` we see above, +modified to suit any applications needs. It takes the `auth.BaseAccount` we see above, and extends it with `Name`. ``` @@ -256,7 +256,7 @@ Accounts are serialized and stored in a Merkle tree under the key Typically, the address of the account is the 20-byte ``RIPEMD160`` hash of the public key, but other formats are acceptable as well, as defined in the `Tendermint crypto -library `__. The Merkle tree +library `__. The Merkle tree used in Basecoin is a balanced, binary search tree, which we call an `IAVL tree `__. @@ -293,15 +293,15 @@ Note the `SendTx` includes a field for `Gas` and `Fee`. The transaction, while the `Fee` refers to the total amount paid in fees. This is slightly different from Ethereum's concept of `Gas` and `GasPrice`, where `Fee = Gas x GasPrice`. In Basecoin, the `Gas` -and `Fee` are independent, and the `GasPrice` is implicit. +and `Fee` are independent, and the `GasPrice` is implicit. In Basecoin, the `Fee` is meant to be used by the validators to inform the ordering of transactions, like in Bitcoin. And the `Gas` is meant to be used by the application plugin to control its execution. There is currently no means to pass `Fee` information to the Tendermint -validators, but it will come soon... so this version of Basecoin does -not actually fully implement fees and gas, but it still allows us -to send transactions between accounts. +validators, but it will come soon... so this version of Basecoin does +not actually fully implement fees and gas, but it still allows us +to send transactions between accounts. Note also that the `PubKey` only needs to be sent for `Sequence == 0`. After that, it is stored under the account in the @@ -318,4 +318,3 @@ serve as a basic unit of decentralized exchange. When using multiple inputs and outputs, you must make sure that the sum of coins of the inputs equals the sum of coins of the outputs (no creating money), and that all accounts that provide inputs have signed the transaction. - From 47e4682d9f73b74a59ebf15f0ebbf7d8009379d8 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 13:30:12 -0700 Subject: [PATCH 57/77] Merge PR #1415: x/stake: Limit the size of rationals from user input * x/stake: Limit the size of rationals from user input This commit sets the maximum number of decimal points that can be passed in from messages. This is enforced on the validate basic of MsgBeginUnbonding and MsgBeginRedelegation. The cli has been updated to truncate the user input to the specified precision. This also updates types/rational to return big ints for Num() and Den(). Closes #887 * Switch NewFromDecimal to error instead of truncating --- CHANGELOG.md | 1 + types/int.go | 4 ++++ types/rational.go | 29 ++++++++++++++++++++++------- types/rational_test.go | 25 ++++++++++++++++--------- x/stake/client/cli/tx.go | 5 +++-- x/stake/client/rest/tx.go | 5 +++-- x/stake/types/errors.go | 6 ++++++ x/stake/types/msg.go | 17 ++++++++++++++++- 8 files changed, 71 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b48c46a16..d62e3eed1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ FIXES * \#1367 - set ChainID in InitChain * \#1353 - CLI: Show pool shares fractions in human-readable format * \#1258 - printing big.rat's can no longer overflow int64 +* \#887 - limit the size of rationals that can be passed in from user input IMPROVEMENTS * bank module uses go-wire codec instead of 'encoding/json' diff --git a/types/int.go b/types/int.go index 760fc607b5..d04c6a80cd 100644 --- a/types/int.go +++ b/types/int.go @@ -227,6 +227,10 @@ func (i Int) Neg() (res Int) { return Int{neg(i.i)} } +func (i Int) String() string { + return i.i.String() +} + // MarshalAmino defines custom encoding scheme func (i Int) MarshalAmino() (string, error) { if i.i == nil { // Necessary since default Uint initialization has i.i as nil diff --git a/types/rational.go b/types/rational.go index a192aa316f..f24831f89e 100644 --- a/types/rational.go +++ b/types/rational.go @@ -38,8 +38,8 @@ func NewRat(Numerator int64, Denominator ...int64) Rat { } // create a rational from decimal string or integer string -func NewRatFromDecimal(decimalStr string) (f Rat, err Error) { - +// precision is the number of values after the decimal point which should be read +func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) { // first extract any negative symbol neg := false if string(decimalStr[0]) == "-" { @@ -61,6 +61,9 @@ func NewRatFromDecimal(decimalStr string) (f Rat, err Error) { if len(str[0]) == 0 || len(str[1]) == 0 { return f, ErrUnknownRequest("not a decimal string") } + if len(str[1]) > prec { + return f, ErrUnknownRequest("string has too many decimals") + } numStr = str[0] + str[1] len := int64(len(str[1])) denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64() @@ -69,8 +72,20 @@ func NewRatFromDecimal(decimalStr string) (f Rat, err Error) { } num, errConv := strconv.Atoi(numStr) - if errConv != nil { - return f, ErrUnknownRequest(errConv.Error()) + if errConv != nil && strings.HasSuffix(errConv.Error(), "value out of range") { + // resort to big int, don't make this default option for efficiency + numBig, success := new(big.Int).SetString(numStr, 10) + if success != true { + return f, ErrUnknownRequest("not a decimal string") + } + + if neg { + numBig.Neg(numBig) + } + + return NewRatFromBigInt(numBig, big.NewInt(denom)), nil + } else if errConv != nil { + return f, ErrUnknownRequest("not a decimal string") } if neg { @@ -105,9 +120,9 @@ func NewRatFromInt(num Int, denom ...Int) Rat { } //nolint -func (r Rat) Num() int64 { return r.Rat.Num().Int64() } // Num - return the numerator -func (r Rat) Denom() int64 { return r.Rat.Denom().Int64() } // Denom - return the denominator -func (r Rat) IsZero() bool { return r.Num() == 0 } // IsZero - Is the Rat equal to zero +func (r Rat) Num() Int { return Int{r.Rat.Num()} } // Num - return the numerator +func (r Rat) Denom() Int { return Int{r.Rat.Denom()} } // Denom - return the denominator +func (r Rat) IsZero() bool { return r.Num().IsZero() } // IsZero - Is the Rat equal to zero func (r Rat) Equal(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == 0 } func (r Rat) GT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == 1 } // greater than func (r Rat) GTE(r2 Rat) bool { return !r.LT(r2) } // greater than or equal diff --git a/types/rational_test.go b/types/rational_test.go index 43c9ddd575..a137ca498e 100644 --- a/types/rational_test.go +++ b/types/rational_test.go @@ -21,6 +21,8 @@ func TestNew(t *testing.T) { } func TestNewFromDecimal(t *testing.T) { + largeBigInt, success := new(big.Int).SetString("3109736052979742687701388262607869", 10) + require.True(t, success) tests := []struct { decimalStr string expErr bool @@ -31,7 +33,13 @@ func TestNewFromDecimal(t *testing.T) { {"1.1", false, NewRat(11, 10)}, {"0.75", false, NewRat(3, 4)}, {"0.8", false, NewRat(4, 5)}, - {"0.11111", false, NewRat(11111, 100000)}, + {"0.11111", true, NewRat(1111, 10000)}, + {"628240629832763.5738930323617075341", true, NewRat(3141203149163817869, 5000)}, + {"621947210595948537540277652521.5738930323617075341", + true, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, + {"628240629832763.5738", false, NewRat(3141203149163817869, 5000)}, + {"621947210595948537540277652521.5738", + false, NewRatFromBigInt(largeBigInt, big.NewInt(5000))}, {".", true, Rat{}}, {".0", true, Rat{}}, {"1.", true, Rat{}}, @@ -41,22 +49,21 @@ func TestNewFromDecimal(t *testing.T) { } for _, tc := range tests { - - res, err := NewRatFromDecimal(tc.decimalStr) + res, err := NewRatFromDecimal(tc.decimalStr, 4) if tc.expErr { assert.NotNil(t, err, tc.decimalStr) } else { - assert.Nil(t, err) - assert.True(t, res.Equal(tc.exp)) + require.Nil(t, err, tc.decimalStr) + require.True(t, res.Equal(tc.exp), tc.decimalStr) } // negative tc - res, err = NewRatFromDecimal("-" + tc.decimalStr) + res, err = NewRatFromDecimal("-"+tc.decimalStr, 4) if tc.expErr { assert.NotNil(t, err, tc.decimalStr) } else { - assert.Nil(t, err) - assert.True(t, res.Equal(tc.exp.Mul(NewRat(-1)))) + assert.Nil(t, err, tc.decimalStr) + assert.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr) } } } @@ -133,7 +140,7 @@ func TestArithmetic(t *testing.T) { assert.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) assert.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) - if tc.r2.Num() == 0 { // panic for divide by zero + if tc.r2.Num().IsZero() { // panic for divide by zero assert.Panics(t, func() { tc.r1.Quo(tc.r2) }) } else { assert.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index b7941e2bb8..b0fa2e524a 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/types" ) // create create validator command @@ -219,7 +220,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent case sharesAmountStr == "" && sharesPercentStr == "": return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both") case sharesAmountStr != "": - sharesAmount, err = sdk.NewRatFromDecimal(sharesAmountStr) + sharesAmount, err = sdk.NewRatFromDecimal(sharesAmountStr, types.MaxBondDenominatorPrecision) if err != nil { return sharesAmount, err } @@ -228,7 +229,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent } case sharesPercentStr != "": var sharesPercent sdk.Rat - sharesPercent, err = sdk.NewRatFromDecimal(sharesPercentStr) + sharesPercent, err = sdk.NewRatFromDecimal(sharesPercentStr, types.MaxBondDenominatorPrecision) if err != nil { return sharesAmount, err } diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 1d85476622..51a854528d 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -14,6 +14,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/types" ) func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { @@ -145,7 +146,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - shares, err := sdk.NewRatFromDecimal(msg.SharesAmount) + shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) @@ -210,7 +211,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - shares, err := sdk.NewRatFromDecimal(msg.SharesAmount) + shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))) diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index 622bd0e1a9..2914741f45 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -79,6 +79,12 @@ func ErrNotEnoughDelegationShares(codespace sdk.CodespaceType, shares string) sd func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0") } +func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidDelegation, + fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points", + maximumBondingRationalDenominator.String()), + ) +} func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") } diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index f8b8e67170..878c1ba17b 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -1,6 +1,8 @@ package types import ( + "math" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" ) @@ -8,11 +10,18 @@ import ( // name to idetify transaction types const MsgType = "stake" -//Verify interface at compile time +// Maximum amount of decimal points in the decimal representation of rationals +// used in MsgBeginUnbonding / MsgBeginRedelegate +const MaxBondDenominatorPrecision = 8 + +// Verify interface at compile time var _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{} var _, _ sdk.Msg = &MsgBeginUnbonding{}, &MsgCompleteUnbonding{} var _, _ sdk.Msg = &MsgBeginRedelegate{}, &MsgCompleteRedelegate{} +// Initialize Int for the denominator +var maximumBondingRationalDenominator sdk.Int = sdk.NewInt(int64(math.Pow10(MaxBondDenominatorPrecision))) + //______________________________________________________________________ // MsgCreateValidator - struct for unbonding transactions @@ -234,6 +243,9 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { if msg.SharesAmount.LTE(sdk.ZeroRat()) { return ErrBadSharesAmount(DefaultCodespace) } + if msg.SharesAmount.Denom().GT(maximumBondingRationalDenominator) { + return ErrBadSharesPrecision(DefaultCodespace) + } return nil } @@ -340,6 +352,9 @@ func (msg MsgBeginUnbonding) ValidateBasic() sdk.Error { if msg.SharesAmount.LTE(sdk.ZeroRat()) { return ErrBadSharesAmount(DefaultCodespace) } + if msg.SharesAmount.Denom().GT(maximumBondingRationalDenominator) { + return ErrBadSharesPrecision(DefaultCodespace) + } return nil } From 097dd8a164c797a9c454c47416b91297838d4d51 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 15:22:24 -0700 Subject: [PATCH 58/77] tools: Add unparam linter (#1443) * tools: Add unparam linter unparam detects unused parameters in functions, and a parameter to a function which only ever takes on one value. The latter is an indication that more tests are required. There are many nolints in this PR, as I believe that writing tests to fix alot of these situations is out of scope for this PR / it will be changed in future commits. There are some nolints for when we have to comply to normal api's. * crypto/keys no longer used by x/gov/client/rest/rest.go --- CHANGELOG.md | 1 + Makefile | 2 +- client/lcd/root.go | 4 +-- client/lcd/test_helpers.go | 2 +- client/lcd/version.go | 3 +- cmd/gaia/app/app.go | 1 + cmd/gaia/app/genesis.go | 4 +-- cmd/gaia/cmd/gaiadebug/hack.go | 1 + examples/basecoin/app/app.go | 1 + examples/democoin/app/app.go | 1 + examples/democoin/x/simplestake/errors.go | 1 + examples/democoin/x/simplestake/handler.go | 10 +++---- server/init.go | 4 +-- server/mock/store.go | 2 +- server/mock/store_test.go | 2 +- store/iavlstore.go | 2 ++ tools/Makefile | 21 ++++++++++++-- x/auth/mock/simulate_block.go | 2 +- x/gov/client/rest/rest.go | 32 +++++++++++----------- x/gov/handler.go | 6 ++-- x/gov/keeper.go | 8 +++--- x/gov/tally.go | 2 +- x/ibc/client/cli/relay.go | 1 + x/ibc/errors.go | 1 + x/slashing/app_test.go | 2 +- x/stake/client/rest/query.go | 18 ++++++------ x/stake/keeper/test_common.go | 2 ++ x/stake/keeper/validator.go | 8 +++--- x/stake/keeper/validator_test.go | 22 +++++++-------- x/stake/types/test_common.go | 3 ++ x/stake/types/validator.go | 5 ++-- 31 files changed, 102 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d62e3eed1e..6393dd4d53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ FEATURES * unconvert * ineffassign * errcheck + * unparam * [tools] Add `make format` command to automate fixing misspell and gofmt errors. * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates * [tests] Add WaitForNextNBlocksTM helper method diff --git a/Makefile b/Makefile index cc70aa6f72..96ffb47a2c 100644 --- a/Makefile +++ b/Makefile @@ -108,7 +108,7 @@ test_cover: @bash tests/test_cover.sh test_lint: - gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --enable='unconvert' --enable='ineffassign' --linter='vet:go vet -composites=false:PATH:LINE:MESSAGE' --enable='vet' --deadline=500s --vendor ./... + gometalinter.v2 --disable-all --enable='golint' --enable='misspell' --enable='unparam' --enable='unconvert' --enable='ineffassign' --linter='vet:go vet -composites=false:PATH:LINE:MESSAGE' --enable='vet' --deadline=500s --vendor ./... !(gometalinter.v2 --disable-all --enable='errcheck' --vendor ./... | grep -v "client/") find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s diff --git a/client/lcd/root.go b/client/lcd/root.go index f9c30de861..d84e7d9f1c 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -76,7 +76,7 @@ func createHandler(cdc *wire.Codec) http.Handler { // TODO make more functional? aka r = keys.RegisterRoutes(r) r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET") - r.HandleFunc("/node_version", NodeVersionRequestHandler(cdc, ctx)).Methods("GET") + r.HandleFunc("/node_version", NodeVersionRequestHandler(ctx)).Methods("GET") keys.RegisterRoutes(r) rpc.RegisterRoutes(ctx, r) tx.RegisterRoutes(ctx, r, cdc) @@ -84,6 +84,6 @@ func createHandler(cdc *wire.Codec) http.Handler { bank.RegisterRoutes(ctx, r, cdc, kb) ibc.RegisterRoutes(ctx, r, cdc, kb) stake.RegisterRoutes(ctx, r, cdc, kb) - gov.RegisterRoutes(ctx, r, cdc, kb) + gov.RegisterRoutes(ctx, r, cdc) return r } diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 0d5d7cad2f..ecf6748a57 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -132,7 +132,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.Address) ( for _, gdValidator := range genDoc.Validators { pk := gdValidator.PubKey validatorsPKs = append(validatorsPKs, pk) // append keys for output - appGenTx, _, _, err := gapp.GaiaAppGenTxNF(cdc, pk, pk.Address(), "test_val1", true) + appGenTx, _, _, err := gapp.GaiaAppGenTxNF(cdc, pk, pk.Address(), "test_val1") require.NoError(t, err) appGenTxs = append(appGenTxs, appGenTx) } diff --git a/client/lcd/version.go b/client/lcd/version.go index be097393e0..4e328b7a0b 100644 --- a/client/lcd/version.go +++ b/client/lcd/version.go @@ -6,7 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/wire" ) // cli version REST handler endpoint @@ -16,7 +15,7 @@ func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) { } // connected node version REST handler endpoint -func NodeVersionRequestHandler(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { +func NodeVersionRequestHandler(ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { version, err := ctx.Query("/app/version") if err != nil { diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index bdb2d3a2d0..399c816830 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -129,6 +129,7 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab } // application updates every end block +// nolint: unparam func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index ce4b6ccfca..805c6d4f79 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -103,12 +103,12 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey, genTxConfig config.GenTx) ( cliPrint = json.RawMessage(bz) - appGenTx, _, validator, err = GaiaAppGenTxNF(cdc, pk, addr, genTxConfig.Name, genTxConfig.Overwrite) + appGenTx, _, validator, err = GaiaAppGenTxNF(cdc, pk, addr, genTxConfig.Name) return } // Generate a gaia genesis transaction without flags -func GaiaAppGenTxNF(cdc *wire.Codec, pk crypto.PubKey, addr sdk.Address, name string, overwrite bool) ( +func GaiaAppGenTxNF(cdc *wire.Codec, pk crypto.PubKey, addr sdk.Address, name string) ( appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { var bz []byte diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 0cb1160f5b..74b42adb38 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -210,6 +210,7 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab } // application updates every end block +// nolint: unparam func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index de29a1316b..089d1ca23c 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -120,6 +120,7 @@ func (app *BasecoinApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock } // application updates every end block +// nolint: unparam func (app *BasecoinApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index a87dc15e44..195af0c9ea 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -117,6 +117,7 @@ func MakeCodec() *wire.Codec { } // custom logic for democoin initialization +// nolint: unparam func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { stateJSON := req.AppStateBytes diff --git a/examples/democoin/x/simplestake/errors.go b/examples/democoin/x/simplestake/errors.go index 0effba9c0a..8125e57aab 100644 --- a/examples/democoin/x/simplestake/errors.go +++ b/examples/democoin/x/simplestake/errors.go @@ -32,6 +32,7 @@ func ErrEmptyStake(codespace sdk.CodespaceType) sdk.Error { // ----------------------------- // Helpers +// nolint: unparam func newError(codespace sdk.CodespaceType, code sdk.CodeType, msg string) sdk.Error { return sdk.NewError(codespace, code, msg) } diff --git a/examples/democoin/x/simplestake/handler.go b/examples/democoin/x/simplestake/handler.go index 6b21879e92..114f066436 100644 --- a/examples/democoin/x/simplestake/handler.go +++ b/examples/democoin/x/simplestake/handler.go @@ -7,18 +7,18 @@ import ( // NewHandler returns a handler for "simplestake" type messages. func NewHandler(k Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { + switch msg.(type) { case MsgBond: - return handleMsgBond(ctx, k, msg) + return handleMsgBond() case MsgUnbond: - return handleMsgUnbond(ctx, k, msg) + return handleMsgUnbond() default: return sdk.ErrUnknownRequest("No match for message type.").Result() } } } -func handleMsgBond(ctx sdk.Context, k Keeper, msg MsgBond) sdk.Result { +func handleMsgBond() sdk.Result { // Removed ValidatorSet from result because it does not get used. // TODO: Implement correct bond/unbond handling return sdk.Result{ @@ -26,7 +26,7 @@ func handleMsgBond(ctx sdk.Context, k Keeper, msg MsgBond) sdk.Result { } } -func handleMsgUnbond(ctx sdk.Context, k Keeper, msg MsgUnbond) sdk.Result { +func handleMsgUnbond() sdk.Result { return sdk.Result{ Code: sdk.ABCICodeOK, } diff --git a/server/init.go b/server/init.go index 3bfe06e5fb..ed1727e35e 100644 --- a/server/init.go +++ b/server/init.go @@ -226,7 +226,7 @@ func initWithConfig(cdc *wire.Codec, appInit AppInit, config *cfg.Config, initCo var persistentPeers string if initConfig.GenTxs { - validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc, appInit) + validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc) if err != nil { return } @@ -263,7 +263,7 @@ func initWithConfig(cdc *wire.Codec, appInit AppInit, config *cfg.Config, initCo } // append a genesis-piece -func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) ( +func processGenTxs(genTxsDir string, cdc *wire.Codec) ( validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) { var fos []os.FileInfo diff --git a/server/mock/store.go b/server/mock/store.go index f00c4dd8d0..9dca581596 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -115,6 +115,6 @@ func (kv kvStore) ReverseSubspaceIterator(prefix []byte) sdk.Iterator { panic("not implemented") } -func NewCommitMultiStore(db dbm.DB) sdk.CommitMultiStore { +func NewCommitMultiStore() sdk.CommitMultiStore { return multiStore{kv: make(map[sdk.StoreKey]kvStore)} } diff --git a/server/mock/store_test.go b/server/mock/store_test.go index e920609476..bd01244667 100644 --- a/server/mock/store_test.go +++ b/server/mock/store_test.go @@ -12,7 +12,7 @@ import ( func TestStore(t *testing.T) { db := dbm.NewMemDB() - cms := NewCommitMultiStore(db) + cms := NewCommitMultiStore() key := sdk.NewKVStoreKey("test") cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) diff --git a/store/iavlstore.go b/store/iavlstore.go index 31463e977e..5758802c6e 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -47,6 +47,8 @@ type iavlStore struct { } // CONTRACT: tree should be fully loaded. +// TODO: use more numHistory's, so the below nolint can be removed +// nolint: unparam func newIAVLStore(tree *iavl.VersionedTree, numHistory int64) *iavlStore { st := &iavlStore{ tree: tree, diff --git a/tools/Makefile b/tools/Makefile index 516de1a426..195e67aa52 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -11,6 +11,7 @@ UNCONVERT = github.com/mdempsky/unconvert INEFFASSIGN = github.com/gordonklaus/ineffassign MISSPELL = github.com/client9/misspell/cmd/misspell ERRCHECK = github.com/kisielk/errcheck +UNPARAM = mvdan.cc/unparam DEP_CHECK := $(shell command -v dep 2> /dev/null) GOLINT_CHECK := $(shell command -v golint 2> /dev/null) @@ -19,6 +20,7 @@ UNCONVERT_CHECK := $(shell command -v unconvert 2> /dev/null) INEFFASSIGN_CHECK := $(shell command -v ineffassign 2> /dev/null) MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null) ERRCHECK_CHECK := $(shell command -v errcheck 2> /dev/null) +UNPARAM_CHECK := $(shell command -v unparam 2> /dev/null) check_tools: ifndef DEP_CHECK @@ -51,11 +53,16 @@ ifndef MISSPELL_CHECK else @echo "Found misspell in path." endif -ifndef MISSPELL_CHECK +ifndef ERRCHECK_CHECK @echo "No errcheck in path. Install with 'make get_tools'." else @echo "Found errcheck in path." endif +ifndef UNPARAM_CHECK + @echo "No unparam in path. Install with 'make get_tools'." +else + @echo "Found unparam in path." +endif get_tools: ifdef DEP_CHECK @@ -95,11 +102,17 @@ else go get -v $(MISSPELL) endif ifdef ERRCHECK_CHECK - @echo "misspell is already installed. Run 'make update_tools' to update." + @echo "errcheck is already installed. Run 'make update_tools' to update." else - @echo "Installing misspell" + @echo "Installing errcheck" go get -v $(ERRCHECK) endif +ifdef UNPARAM_CHECK + @echo "unparam is already installed. Run 'make update_tools' to update." +else + @echo "Installing unparam" + go get -v $(UNPARAM) +endif update_tools: @echo "Updating dep" @@ -116,6 +129,8 @@ update_tools: go get -u -v $(MISSPELL) @echo "Updating errcheck" go get -u -v $(ERRCHECK) + @echo "Updating unparam" + go get -u -v $(UNPARAM) # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. diff --git a/x/auth/mock/simulate_block.go b/x/auth/mock/simulate_block.go index 00ffc30df1..a047fbf4b6 100644 --- a/x/auth/mock/simulate_block.go +++ b/x/auth/mock/simulate_block.go @@ -76,7 +76,7 @@ func incrementAllSequenceNumbers(initSeqNums []int64) { } // check a transaction result -func SignCheck(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.Result { +func SignCheck(app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.Result { tx := GenTx(msgs, accnums, seq, priv...) res := app.Check(tx) return res diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index a47823ab32..3e185dc914 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -6,7 +6,6 @@ import ( "strconv" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/gov" @@ -20,19 +19,20 @@ const ( RestProposalID = "proposalID" RestDepositer = "depositer" RestVoter = "voter" + storeName = "gov" ) // RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - r.HandleFunc("/gov/proposals", postProposalHandlerFn(cdc, kb, ctx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, kb, ctx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, kb, ctx)).Methods("POST") +func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { + r.HandleFunc("/gov/proposals", postProposalHandlerFn(cdc, ctx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, ctx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, ctx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn("gov", cdc, kb, ctx)).Methods("GET") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn("gov", cdc, kb, ctx)).Methods("GET") - r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn("gov", cdc, kb, ctx)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn(cdc)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn(cdc)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn(cdc)).Methods("GET") - r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn("gov", cdc, kb, ctx)).Methods("GET") + r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn(cdc)).Methods("GET") } type postProposalReq struct { @@ -56,7 +56,7 @@ type voteReq struct { Option string `json:"option"` // option from OptionSet chosen by the voter } -func postProposalHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func postProposalHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req postProposalReq err := buildReq(w, r, cdc, &req) @@ -93,7 +93,7 @@ func postProposalHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCon } } -func depositHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -141,7 +141,7 @@ func depositHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) } } -func voteHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func voteHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -195,7 +195,7 @@ func voteHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) ht } } -func queryProposalHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -236,7 +236,7 @@ func queryProposalHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, } } -func queryDepositHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -302,7 +302,7 @@ func queryDepositHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, c } } -func queryVoteHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) strProposalID := vars[RestProposalID] @@ -369,7 +369,7 @@ func queryVoteHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx } } -func queryProposalsWithParameterFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { bechVoterAddr := r.URL.Query().Get(RestVoter) bechDepositerAddr := r.URL.Query().Get(RestDepositer) diff --git a/x/gov/handler.go b/x/gov/handler.go index 1d9545948a..dc218953ae 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -114,7 +114,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (tags sdk.Tags, nonVotingVals [] for shouldPopActiveProposalQueue(ctx, keeper) { activeProposal := keeper.ActiveProposalQueuePop(ctx) - if ctx.BlockHeight() >= activeProposal.GetVotingStartBlock()+keeper.GetVotingProcedure(ctx).VotingPeriod { + if ctx.BlockHeight() >= activeProposal.GetVotingStartBlock()+keeper.GetVotingProcedure().VotingPeriod { passes, nonVotingVals = tally(ctx, keeper, activeProposal) proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(activeProposal.GetProposalID()) if passes { @@ -136,7 +136,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (tags sdk.Tags, nonVotingVals [] return tags, nonVotingVals } func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { - depositProcedure := keeper.GetDepositProcedure(ctx) + depositProcedure := keeper.GetDepositProcedure() peekProposal := keeper.InactiveProposalQueuePeek(ctx) if peekProposal == nil { @@ -150,7 +150,7 @@ func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { } func shouldPopActiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { - votingProcedure := keeper.GetVotingProcedure(ctx) + votingProcedure := keeper.GetVotingProcedure() peekProposal := keeper.ActiveProposalQueuePeek(ctx) if peekProposal == nil { diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 7d0eb04067..c22cd3dfe7 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -129,7 +129,7 @@ func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) { // Procedures // Gets procedure from store. TODO: move to global param store and allow for updating of this -func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure { +func (keeper Keeper) GetDepositProcedure() DepositProcedure { return DepositProcedure{ MinDeposit: sdk.Coins{sdk.NewCoin("steak", 10)}, MaxDepositPeriod: 200, @@ -137,14 +137,14 @@ func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure { } // Gets procedure from store. TODO: move to global param store and allow for updating of this -func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure { +func (keeper Keeper) GetVotingProcedure() VotingProcedure { return VotingProcedure{ VotingPeriod: 200, } } // Gets procedure from store. TODO: move to global param store and allow for updating of this -func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure { +func (keeper Keeper) GetTallyingProcedure() TallyingProcedure { return TallyingProcedure{ Threshold: sdk.NewRat(1, 2), Veto: sdk.NewRat(1, 3), @@ -256,7 +256,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr // Check if deposit tipped proposal into voting period // Active voting period if so activatedVotingPeriod := false - if proposal.GetStatus() == StatusDepositPeriod && proposal.GetTotalDeposit().IsGTE(keeper.GetDepositProcedure(ctx).MinDeposit) { + if proposal.GetStatus() == StatusDepositPeriod && proposal.GetTotalDeposit().IsGTE(keeper.GetDepositProcedure().MinDeposit) { keeper.activateVotingPeriod(ctx, proposal) activatedVotingPeriod = true } diff --git a/x/gov/tally.go b/x/gov/tally.go index 2e70ac24cc..c5e0ec763b 100644 --- a/x/gov/tally.go +++ b/x/gov/tally.go @@ -81,7 +81,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonV totalVotingPower = totalVotingPower.Add(votingPower) } - tallyingProcedure := keeper.GetTallyingProcedure(ctx) + tallyingProcedure := keeper.GetTallyingProcedure() // If no one votes, proposal fails if totalVotingPower.Sub(results[OptionAbstain]).Equal(sdk.ZeroRat()) { diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go index 07ee4ae999..2dc3129c6e 100644 --- a/x/ibc/client/cli/relay.go +++ b/x/ibc/client/cli/relay.go @@ -71,6 +71,7 @@ func IBCRelayCmd(cdc *wire.Codec) *cobra.Command { return cmd } +// nolint: unparam func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) { fromChainID := viper.GetString(FlagFromChainID) fromChainNode := viper.GetString(FlagFromChainNode) diff --git a/x/ibc/errors.go b/x/ibc/errors.go index f7beb0e1db..7a3194baf1 100644 --- a/x/ibc/errors.go +++ b/x/ibc/errors.go @@ -36,6 +36,7 @@ func ErrIdenticalChains(codespace sdk.CodespaceType) sdk.Error { // ------------------------- // Helpers +// nolint: unparam func newError(codespace sdk.CodespaceType, code sdk.CodeType, msg string) sdk.Error { msg = msgOrDefaultMsg(msg, code) return sdk.NewError(codespace, code, msg) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 52dd947493..2120e75b68 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -108,6 +108,6 @@ func TestSlashingMsgs(t *testing.T) { checkValidatorSigningInfo(t, mapp, keeper, addr1, false) // unrevoke should fail with unknown validator - res := mock.SignCheck(t, mapp.BaseApp, []sdk.Msg{unrevokeMsg}, []int64{0}, []int64{1}, priv1) + res := mock.SignCheck(mapp.BaseApp, []sdk.Msg{unrevokeMsg}, []int64{0}, []int64{1}, priv1) require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeInvalidValidator), res.Code) } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index fd213382b4..afa9e3bf0c 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -12,31 +12,33 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake" ) +const storeName = "stake" + func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { r.HandleFunc( "/stake/{delegator}/delegation/{validator}", - delegationHandlerFn(ctx, "stake", cdc), + delegationHandlerFn(ctx, cdc), ).Methods("GET") r.HandleFunc( "/stake/{delegator}/ubd/{validator}", - ubdHandlerFn(ctx, "stake", cdc), + ubdHandlerFn(ctx, cdc), ).Methods("GET") r.HandleFunc( "/stake/{delegator}/red/{validator_src}/{validator_dst}", - redHandlerFn(ctx, "stake", cdc), + redHandlerFn(ctx, cdc), ).Methods("GET") r.HandleFunc( "/stake/validators", - validatorsHandlerFn(ctx, "stake", cdc), + validatorsHandlerFn(ctx, cdc), ).Methods("GET") } // http request handler to query a delegation -func delegationHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { +func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // read parameters @@ -93,7 +95,7 @@ func delegationHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Co } // http request handler to query an unbonding-delegation -func ubdHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { +func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // read parameters @@ -150,7 +152,7 @@ func ubdHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) ht } // http request handler to query an redelegation -func redHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { +func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // read parameters @@ -271,7 +273,7 @@ func bech32StakeValidatorOutput(validator stake.Validator) (StakeValidatorOutput // TODO bech32 // http request handler to query list of validators -func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { +func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { kvs, err := ctx.QuerySubspace(cdc, stake.ValidatorsKey, storeName) if err != nil { diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 5a51a0e29f..17b21c6346 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -162,6 +162,7 @@ func TestAddr(addr string, bech string) sdk.Address { return res } +// nolint: unparam func createTestAddrs(numAddrs int) []sdk.Address { var addresses []sdk.Address var buffer bytes.Buffer @@ -180,6 +181,7 @@ func createTestAddrs(numAddrs int) []sdk.Address { return addresses } +// nolint: unparam func createTestPubKeys(numPubKeys int) []crypto.PubKey { var publicKeys []crypto.PubKey var buffer bytes.Buffer diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 75797c868c..0d556f7dc4 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -247,7 +247,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type // efficiency case: // if already bonded and power increasing only need to update tendermint if powerIncreasing && !validator.Revoked && oldValidator.Status() == sdk.Bonded { - bz := k.cdc.MustMarshalBinary(validator.ABCIValidator(k.cdc)) + bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) store.Set(GetTendermintUpdatesKey(ownerAddr), bz) return validator } @@ -445,7 +445,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) type store.Set(GetValidatorKey(validator.Owner), bzVal) // add to accumulated changes for tendermint - bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero(k.cdc)) + bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) store.Set(GetTendermintUpdatesKey(validator.Owner), bzABCI) // also remove from the Bonded types.Validators Store @@ -474,7 +474,7 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner) // add to accumulated changes for tendermint - bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator(k.cdc)) + bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) store.Set(GetTendermintUpdatesKey(validator.Owner), bzABCI) return validator @@ -503,7 +503,7 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.Address) { } store.Delete(GetValidatorsBondedIndexKey(validator.Owner)) - bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero(k.cdc)) + bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) store.Set(GetTendermintUpdatesKey(address), bz) } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 3bbcee94c0..098c17e75f 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -46,7 +46,7 @@ func TestSetValidator(t *testing.T) { updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) - assert.Equal(t, validator.ABCIValidator(keeper.cdc), updates[0]) + assert.Equal(t, validator.ABCIValidator(), updates[0]) } @@ -494,8 +494,8 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) { updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(updates)) - assert.Equal(t, validators[0].ABCIValidator(keeper.cdc), updates[0]) - assert.Equal(t, validators[1].ABCIValidator(keeper.cdc), updates[1]) + assert.Equal(t, validators[0].ABCIValidator(), updates[0]) + assert.Equal(t, validators[1].ABCIValidator(), updates[1]) // test from something to nothing // tendermintUpdate set: {} -> {c1, c2, c3, c4} @@ -560,7 +560,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) - assert.Equal(t, validators[0].ABCIValidator(keeper.cdc), updates[0]) + assert.Equal(t, validators[0].ABCIValidator(), updates[0]) } func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { @@ -590,8 +590,8 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(updates)) - require.Equal(t, validators[0].ABCIValidator(keeper.cdc), updates[0]) - require.Equal(t, validators[1].ABCIValidator(keeper.cdc), updates[1]) + require.Equal(t, validators[0].ABCIValidator(), updates[0]) + require.Equal(t, validators[1].ABCIValidator(), updates[1]) } func TestGetTendermintUpdatesInserted(t *testing.T) { @@ -615,7 +615,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { validators[2] = keeper.UpdateValidator(ctx, validators[2]) updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) - require.Equal(t, validators[2].ABCIValidator(keeper.cdc), updates[0]) + require.Equal(t, validators[2].ABCIValidator(), updates[0]) // test validtor added at the beginning // tendermintUpdate set: {} -> {c0} @@ -623,7 +623,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { validators[3] = keeper.UpdateValidator(ctx, validators[3]) updates = keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) - require.Equal(t, validators[3].ABCIValidator(keeper.cdc), updates[0]) + require.Equal(t, validators[3].ABCIValidator(), updates[0]) // test validtor added at the end // tendermintUpdate set: {} -> {c0} @@ -631,7 +631,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { validators[4] = keeper.UpdateValidator(ctx, validators[4]) updates = keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) - require.Equal(t, validators[4].ABCIValidator(keeper.cdc), updates[0]) + require.Equal(t, validators[4].ABCIValidator(), updates[0]) } func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) { @@ -671,6 +671,6 @@ func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) { updates = keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(updates), "%v", updates) - require.Equal(t, validators[0].ABCIValidatorZero(keeper.cdc), updates[0]) - require.Equal(t, validators[2].ABCIValidator(keeper.cdc), updates[1]) + require.Equal(t, validators[0].ABCIValidatorZero(), updates[0]) + require.Equal(t, validators[2].ABCIValidator(), updates[1]) } diff --git a/x/stake/types/test_common.go b/x/stake/types/test_common.go index 1ecb10d6b9..5edb5568d8 100644 --- a/x/stake/types/test_common.go +++ b/x/stake/types/test_common.go @@ -31,6 +31,7 @@ var ( type Operation func(r *rand.Rand, pool Pool, c Validator) (Pool, Validator, int64, string) // operation: bond or unbond a validator depending on current status +// nolint: unparam func OpBondOrUnbond(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) { var msg string var newStatus sdk.BondStatus @@ -89,6 +90,7 @@ func RandomOperation(r *rand.Rand) Operation { } // ensure invariants that should always be true are true +// nolint: unparam func AssertInvariants(t *testing.T, msg string, pOrig Pool, cOrig []Validator, pMod Pool, vMods []Validator, tokens int64) { @@ -161,6 +163,7 @@ func AssertInvariants(t *testing.T, msg string, // TODO refactor this random setup // generate a random validator +// nolint: unparam func randomValidator(r *rand.Rand, i int) Validator { poolSharesAmt := sdk.NewRat(int64(r.Int31n(10000))) diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index fcc7bf3925..652fd9e6e8 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -9,7 +9,6 @@ import ( tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" ) // Validator defines the total amount of bond shares and their exchange rate to @@ -135,7 +134,7 @@ func (d Description) EnsureLength() (Description, sdk.Error) { } // abci validator from stake validator type -func (v Validator) ABCIValidator(cdc *wire.Codec) abci.Validator { +func (v Validator) ABCIValidator() abci.Validator { return abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(v.PubKey), Power: v.PoolShares.Bonded().Evaluate(), @@ -144,7 +143,7 @@ func (v Validator) ABCIValidator(cdc *wire.Codec) abci.Validator { // abci validator from stake validator type // with zero power used for validator updates -func (v Validator) ABCIValidatorZero(cdc *wire.Codec) abci.Validator { +func (v Validator) ABCIValidatorZero() abci.Validator { return abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(v.PubKey), Power: 0, From fc3dd56281a392dd921467990a500aff9cb1ce96 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 15:47:09 -0700 Subject: [PATCH 59/77] Merge PR #1477: gaiacli: Make recovery allow new keys * gaiacli: Make recovery allow new keys * Move create key to a temporary method, restore create fundraiser key --- client/keys/add.go | 2 +- crypto/keys/keybase.go | 17 ++++++++++++++++- crypto/keys/types.go | 2 ++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index f0055366ac..a39a374c82 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -104,7 +104,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { if err != nil { return err } - info, err := kb.CreateFundraiserKey(name, seed, pass) + info, err := kb.CreateKey(name, seed, pass) if err != nil { return err } diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index ad086b13c6..396bb57821 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -89,13 +89,28 @@ func (kb dbKeybase) CreateMnemonic(name string, language Language, passwd string return } +// TEMPORARY METHOD UNTIL WE FIGURE OUT USER FACING HD DERIVATION API +func (kb dbKeybase) CreateKey(name, mnemonic, passwd string) (info Info, err error) { + words := strings.Split(mnemonic, " ") + if len(words) != 12 && len(words) != 24 { + err = fmt.Errorf("recovering only works with 12 word (fundraiser) or 24 word mnemonics, got: %v words", len(words)) + return + } + seed, err := bip39.MnemonicToSeedWithErrChecking(mnemonic) + if err != nil { + return + } + info, err = kb.persistDerivedKey(seed, passwd, name, hd.FullFundraiserPath) + return +} + // CreateFundraiserKey converts a mnemonic to a private key and persists it, // encrypted with the given password. // TODO(ismail) func (kb dbKeybase) CreateFundraiserKey(name, mnemonic, passwd string) (info Info, err error) { words := strings.Split(mnemonic, " ") if len(words) != 12 { - err = fmt.Errorf("recovering only works with 12 word (fundraiser) mnemonics, got: %v words", len(words)) + err = fmt.Errorf("recovering only works with 12 word (fundraiser), got: %v words", len(words)) return } seed, err := bip39.MnemonicToSeedWithErrChecking(mnemonic) diff --git a/crypto/keys/types.go b/crypto/keys/types.go index e143ed63d0..0e77725c31 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -21,6 +21,8 @@ type Keybase interface { // CreateMnemonic creates a new mnemonic, and derives a hierarchical deterministic // key from that. CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) + // CreateKey takes a mnemonic and derives, a password. This method is temporary + CreateKey(name, mnemonic, passwd string) (info Info, err error) // CreateFundraiserKey takes a mnemonic and derives, a password CreateFundraiserKey(name, mnemonic, passwd string) (info Info, err error) // Derive derives a key from the passed mnemonic using a BIP44 path. From 955a0c9af70d5f8a8a799f17f73f754625cf858a Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 29 Jun 2018 18:10:15 -0700 Subject: [PATCH 60/77] Switch asserts to require (#1483) * meta: Switch the majority of asserts to require Switch most assert statements to require, to ease debugging. Closes #1418 * Fix imports --- baseapp/baseapp_test.go | 132 ++++++------- client/lcd/lcd_test.go | 136 ++++++------- cmd/gaia/app/genesis_test.go | 4 +- cmd/gaia/cli_test/cli_test.go | 43 +++-- crypto/encode_test.go | 31 ++- crypto/keys/bip39/wordcodec_test.go | 6 +- crypto/keys/hd/fundraiser_test.go | 14 +- crypto/keys/keybase_test.go | 98 +++++----- crypto/ledger_test.go | 7 +- examples/basecoin/app/app_test.go | 5 +- examples/democoin/app/app_test.go | 5 +- .../democoin/x/assoc/validator_set_test.go | 34 ++-- examples/democoin/x/cool/app_test.go | 3 +- examples/democoin/x/cool/keeper_test.go | 12 +- examples/democoin/x/oracle/oracle_test.go | 59 +++--- examples/democoin/x/pow/app_test.go | 3 +- examples/democoin/x/pow/handler_test.go | 16 +- examples/democoin/x/pow/keeper_test.go | 16 +- examples/democoin/x/pow/types_test.go | 20 +- .../democoin/x/simplestake/keeper_test.go | 19 +- examples/democoin/x/simplestake/msgs_test.go | 6 +- server/mock/app_test.go | 5 +- server/mock/store_test.go | 14 +- server/util_test.go | 3 +- store/cachekvstore_test.go | 51 +++-- store/iavlstore_test.go | 124 ++++++------ store/prefixstore_test.go | 7 +- store/rootmultistore_test.go | 62 +++--- types/coin_test.go | 47 ++--- types/context_test.go | 15 +- types/errors_test.go | 10 +- types/int_test.go | 104 +++++----- types/lib/linear_test.go | 42 ++--- types/rational_test.go | 73 ++++--- types/store_test.go | 6 +- x/auth/account_test.go | 44 ++--- x/auth/ante_test.go | 23 ++- x/auth/context_test.go | 12 +- x/auth/feekeeper_test.go | 16 +- x/auth/mapper_test.go | 18 +- x/auth/mock/auth_app_test.go | 7 +- x/auth/mock/simulate_block.go | 3 +- x/auth/stdtx_test.go | 8 +- x/bank/app_test.go | 5 +- x/bank/keeper_test.go | 93 ++++----- x/bank/msgs_test.go | 28 +-- x/fee_distribution/keeper_test.go | 6 +- x/gov/endblocker_test.go | 114 +++++------ x/gov/keeper_test.go | 178 +++++++++--------- x/gov/msgs_test.go | 14 +- x/gov/tally_test.go | 100 +++++----- x/ibc/app_test.go | 3 +- x/ibc/ibc_test.go | 30 +-- x/ibc/types_test.go | 18 +- x/slashing/app_test.go | 5 +- x/slashing/msg_test.go | 4 +- x/stake/app_test.go | 6 +- x/stake/handler_test.go | 55 +++--- x/stake/keeper/delegation_test.go | 79 ++++---- x/stake/keeper/inflation_test.go | 39 ++-- x/stake/keeper/keeper_test.go | 10 +- x/stake/keeper/validator_test.go | 72 +++---- x/stake/types/msg_test.go | 17 +- x/stake/types/pool_test.go | 41 ++-- x/stake/types/validator_test.go | 72 +++---- 65 files changed, 1156 insertions(+), 1196 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 9d567c6bff..0d0b226265 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -37,26 +37,26 @@ func newBaseApp(name string) *BaseApp { func TestMountStores(t *testing.T) { name := t.Name() app := newBaseApp(name) - assert.Equal(t, name, app.Name()) + require.Equal(t, name, app.Name()) // make some cap keys capKey1 := sdk.NewKVStoreKey("key1") capKey2 := sdk.NewKVStoreKey("key2") // no stores are mounted - assert.Panics(t, func() { app.LoadLatestVersion(capKey1) }) + require.Panics(t, func() { app.LoadLatestVersion(capKey1) }) app.MountStoresIAVL(capKey1, capKey2) // stores are mounted err := app.LoadLatestVersion(capKey1) - assert.Nil(t, err) + require.Nil(t, err) // check both stores store1 := app.cms.GetCommitKVStore(capKey1) - assert.NotNil(t, store1) + require.NotNil(t, store1) store2 := app.cms.GetCommitKVStore(capKey2) - assert.NotNil(t, store2) + require.NotNil(t, store2) } // Test that we can make commits and then reload old versions. @@ -71,14 +71,14 @@ func TestLoadVersion(t *testing.T) { capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) emptyCommitID := sdk.CommitID{} lastHeight := app.LastBlockHeight() lastID := app.LastCommitID() - assert.Equal(t, int64(0), lastHeight) - assert.Equal(t, emptyCommitID, lastID) + require.Equal(t, int64(0), lastHeight) + require.Equal(t, emptyCommitID, lastID) // execute some blocks header := abci.Header{Height: 1} @@ -94,7 +94,7 @@ func TestLoadVersion(t *testing.T) { app = NewBaseApp(name, nil, logger, db) app.MountStoresIAVL(capKey) err = app.LoadLatestVersion(capKey) - assert.Nil(t, err) + require.Nil(t, err) testLoadVersionHelper(t, app, int64(2), commitID2) // reload with LoadVersion, see if you can commit the same block and get @@ -102,7 +102,7 @@ func TestLoadVersion(t *testing.T) { app = NewBaseApp(name, nil, logger, db) app.MountStoresIAVL(capKey) err = app.LoadVersion(1, capKey) - assert.Nil(t, err) + require.Nil(t, err) testLoadVersionHelper(t, app, int64(1), commitID1) app.BeginBlock(abci.RequestBeginBlock{Header: header}) app.Commit() @@ -112,8 +112,8 @@ func TestLoadVersion(t *testing.T) { func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID sdk.CommitID) { lastHeight := app.LastBlockHeight() lastID := app.LastCommitID() - assert.Equal(t, expectedHeight, lastHeight) - assert.Equal(t, expectedID, lastID) + require.Equal(t, expectedHeight, lastHeight) + require.Equal(t, expectedID, lastID) } // Test that the app hash is static @@ -125,7 +125,7 @@ func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, exp capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) // execute some blocks header := abci.Header{Height: 1} @@ -138,7 +138,7 @@ func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, exp res = app.Commit() commitID2 := sdk.CommitID{2, res.Data} - assert.Equal(t, commitID1.Hash, commitID2.Hash) + require.Equal(t, commitID1.Hash, commitID2.Hash) } */ @@ -160,7 +160,7 @@ func TestInfo(t *testing.T) { assert.Equal(t, "", res.Version) assert.Equal(t, t.Name(), res.GetData()) assert.Equal(t, int64(0), res.LastBlockHeight) - assert.Equal(t, []uint8(nil), res.LastBlockAppHash) + require.Equal(t, []uint8(nil), res.LastBlockAppHash) // ----- test a proper response ------- // TODO @@ -179,7 +179,7 @@ func TestInitChainer(t *testing.T) { capKey2 := sdk.NewKVStoreKey("key2") app.MountStoresIAVL(capKey, capKey2) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) key, value := []byte("hello"), []byte("goodbye") @@ -198,7 +198,7 @@ func TestInitChainer(t *testing.T) { // initChainer is nil - nothing happens app.InitChain(abci.RequestInitChain{}) res := app.Query(query) - assert.Equal(t, 0, len(res.Value)) + require.Equal(t, 0, len(res.Value)) // set initChainer and try again - should see the value app.SetInitChainer(initChainer) @@ -206,31 +206,31 @@ func TestInitChainer(t *testing.T) { // assert that chainID is set correctly in InitChain chainID := app.deliverState.ctx.ChainID() - assert.Equal(t, "test-chain-id", chainID, "ChainID in deliverState not set correctly in InitChain") + require.Equal(t, "test-chain-id", chainID, "ChainID in deliverState not set correctly in InitChain") chainID = app.checkState.ctx.ChainID() - assert.Equal(t, "test-chain-id", chainID, "ChainID in checkState not set correctly in InitChain") + require.Equal(t, "test-chain-id", chainID, "ChainID in checkState not set correctly in InitChain") app.Commit() res = app.Query(query) - assert.Equal(t, value, res.Value) + require.Equal(t, value, res.Value) // reload app app = NewBaseApp(name, nil, logger, db) app.MountStoresIAVL(capKey, capKey2) err = app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) app.SetInitChainer(initChainer) // ensure we can still query after reloading res = app.Query(query) - assert.Equal(t, value, res.Value) + require.Equal(t, value, res.Value) // commit and ensure we can still query app.BeginBlock(abci.RequestBeginBlock{}) app.Commit() res = app.Query(query) - assert.Equal(t, value, res.Value) + require.Equal(t, value, res.Value) } func getStateCheckingHandler(t *testing.T, capKey *sdk.KVStoreKey, txPerHeight int, checkHeader bool) func(ctx sdk.Context, msg sdk.Msg) sdk.Result { @@ -243,7 +243,7 @@ func getStateCheckingHandler(t *testing.T, capKey *sdk.KVStoreKey, txPerHeight i // check previous value in store counterBytes := []byte{byte(counter - 1)} prevBytes := store.Get(counterBytes) - assert.Equal(t, counterBytes, prevBytes) + require.Equal(t, counterBytes, prevBytes) } // set the current counter in the store @@ -255,7 +255,7 @@ func getStateCheckingHandler(t *testing.T, capKey *sdk.KVStoreKey, txPerHeight i if checkHeader { thisHeader := ctx.BlockHeader() height := int64((counter / txPerHeight) + 1) - assert.Equal(t, height, thisHeader.Height) + require.Equal(t, height, thisHeader.Height) } counter++ @@ -293,7 +293,7 @@ func TestCheckTx(t *testing.T) { capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return }) txPerHeight := 3 @@ -317,7 +317,7 @@ func TestCheckTx(t *testing.T) { checkStateStore := app.checkState.ctx.KVStore(capKey) for i := 0; i < txPerHeight; i++ { storedValue := checkStateStore.Get([]byte{byte(i)}) - assert.Nil(t, storedValue) + require.Nil(t, storedValue) } } @@ -330,7 +330,7 @@ func TestDeliverTx(t *testing.T) { capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) txPerHeight := 2 app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return }) @@ -359,7 +359,7 @@ func TestSimulateTx(t *testing.T) { capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) counter := 0 app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return }) @@ -372,7 +372,7 @@ func TestSimulateTx(t *testing.T) { // check we can see the current header thisHeader := ctx.BlockHeader() height := int64(counter) - assert.Equal(t, height, thisHeader.Height) + require.Equal(t, height, thisHeader.Height) counter++ return sdk.Result{} }) @@ -421,18 +421,18 @@ func TestRunInvalidTransaction(t *testing.T) { capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return }) app.Router().AddRoute(msgType2, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) app.BeginBlock(abci.RequestBeginBlock{}) // Transaction where validate fails invalidTx := testTx{-1} err1 := app.Deliver(invalidTx) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeTxDecode), err1.Code) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeTxDecode), err1.Code) // Transaction with no known route unknownRouteTx := testUpdatePowerTx{} err2 := app.Deliver(unknownRouteTx) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), err2.Code) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), err2.Code) } // Test that transactions exceeding gas limits fail @@ -445,7 +445,7 @@ func TestTxGasLimits(t *testing.T) { capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { newCtx = ctx.WithGasMeter(sdk.NewGasMeter(0)) @@ -461,7 +461,7 @@ func TestTxGasLimits(t *testing.T) { app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Deliver(tx) - assert.Equal(t, res.Code, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOutOfGas), "Expected transaction to run out of gas") + require.Equal(t, res.Code, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOutOfGas), "Expected transaction to run out of gas") app.EndBlock(abci.RequestEndBlock{}) app.Commit() } @@ -474,7 +474,7 @@ func TestQuery(t *testing.T) { capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) key, value := []byte("hello"), []byte("goodbye") @@ -492,25 +492,25 @@ func TestQuery(t *testing.T) { // query is empty before we do anything res := app.Query(query) - assert.Equal(t, 0, len(res.Value)) + require.Equal(t, 0, len(res.Value)) tx := testUpdatePowerTx{} // doesn't matter // query is still empty after a CheckTx app.Check(tx) res = app.Query(query) - assert.Equal(t, 0, len(res.Value)) + require.Equal(t, 0, len(res.Value)) // query is still empty after a DeliverTx before we commit app.BeginBlock(abci.RequestBeginBlock{}) app.Deliver(tx) res = app.Query(query) - assert.Equal(t, 0, len(res.Value)) + require.Equal(t, 0, len(res.Value)) // query returns correct value after Commit app.Commit() res = app.Query(query) - assert.Equal(t, value, res.Value) + require.Equal(t, value, res.Value) } // Test p2p filter queries @@ -521,7 +521,7 @@ func TestP2PQuery(t *testing.T) { capKey := sdk.NewKVStoreKey("main") app.MountStoresIAVL(capKey) err := app.LoadLatestVersion(capKey) // needed to make stores non-nil - assert.Nil(t, err) + require.Nil(t, err) app.SetAddrPeerFilter(func(addrport string) abci.ResponseQuery { require.Equal(t, "1.1.1.1:8000", addrport) @@ -585,8 +585,8 @@ func TestValidatorChange(t *testing.T) { // Load latest state, which should be empty. err := app.LoadLatestVersion(capKey) - assert.Nil(t, err) - assert.Equal(t, app.LastBlockHeight(), int64(0)) + require.Nil(t, err) + require.Equal(t, app.LastBlockHeight(), int64(0)) // Create the validators var numVals = 3 @@ -611,7 +611,7 @@ func TestValidatorChange(t *testing.T) { } txBytes := toJSON(tx) res := app.DeliverTx(txBytes) - assert.True(t, res.IsOK(), "%#v\nABCI log: %s", res, res.Log) + require.True(t, res.IsOK(), "%#v\nABCI log: %s", res, res.Log) } // Simulate the end of a block. @@ -624,18 +624,18 @@ func TestValidatorChange(t *testing.T) { pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey) // Sanity - assert.Nil(t, err) + require.Nil(t, err) // Find matching update and splice it out. for j := 0; j < len(valUpdates); j++ { valUpdate := valUpdates[j] updatePubkey, err := tmtypes.PB2TM.PubKey(valUpdate.PubKey) - assert.Nil(t, err) + require.Nil(t, err) // Matched. if updatePubkey.Equals(pubkey) { - assert.Equal(t, valUpdate.Power, val.Power+1) + require.Equal(t, valUpdate.Power, val.Power+1) if j < len(valUpdates)-1 { // Splice it out. valUpdates = append(valUpdates[:j], valUpdates[j+1:]...) @@ -646,7 +646,7 @@ func TestValidatorChange(t *testing.T) { // Not matched. } } - assert.Equal(t, len(valUpdates), 0, "Some validator updates were unexpected") + require.Equal(t, len(valUpdates), 0, "Some validator updates were unexpected") } //---------------------------------------- @@ -808,15 +808,15 @@ func TestMultipleBurn(t *testing.T) { addr := priv.PubKey().Address() app.accountKeeper.AddCoins(app.deliverState.ctx, addr, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) - assert.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr), "Balance did not update") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr), "Balance did not update") msg := testBurnMsg{addr, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} tx := GenTx(t.Name(), []sdk.Msg{msg, msg}, []int64{0}, []int64{0}, priv) res := app.Deliver(tx) - assert.Equal(t, true, res.IsOK(), res.Log) - assert.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr), "Double burn did not work") + require.Equal(t, true, res.IsOK(), res.Log) + require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr), "Double burn did not work") } // tests multiples msgs of same type from different addresses in single tx @@ -861,8 +861,8 @@ func TestBurnMultipleOwners(t *testing.T) { app.accountKeeper.AddCoins(app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) app.accountKeeper.AddCoins(app.deliverState.ctx, addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}}) - assert.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not update") - assert.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not update") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not update") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not update") msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}} msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}}} @@ -871,19 +871,19 @@ func TestBurnMultipleOwners(t *testing.T) { tx := GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 0}, []int64{0, 0}, priv1, priv1) res := app.Deliver(tx) - assert.Equal(t, sdk.ABCICodeType(0x10003), res.Code, "Wrong signatures passed") + require.Equal(t, sdk.ABCICodeType(0x10003), res.Code, "Wrong signatures passed") - assert.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 changed after invalid sig") - assert.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 changed after invalid sig") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 changed after invalid sig") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 changed after invalid sig") // test valid tx tx = GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 1}, []int64{1, 0}, priv1, priv2) res = app.Deliver(tx) - assert.Equal(t, true, res.IsOK(), res.Log) + require.Equal(t, true, res.IsOK(), res.Log) - assert.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not change after valid tx") - assert.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not change after valid tx") + require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not change after valid tx") + require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not change after valid tx") } // tests different msg types in single tx with different addresses @@ -929,7 +929,7 @@ func TestSendBurn(t *testing.T) { acc := app.accountMapper.NewAccountWithAddress(app.deliverState.ctx, addr2) app.accountMapper.SetAccount(app.deliverState.ctx, acc) - assert.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not update") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not update") sendMsg := testSendMsg{addr1, addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}} @@ -940,10 +940,10 @@ func TestSendBurn(t *testing.T) { tx := GenTx(t.Name(), []sdk.Msg{sendMsg, msg2, msg1}, []int64{0, 1}, []int64{0, 0}, priv1, priv2) res := app.Deliver(tx) - assert.Equal(t, true, res.IsOK(), res.Log) + require.Equal(t, true, res.IsOK(), res.Log) - assert.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not change after valid tx") - assert.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not change after valid tx") + require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not change after valid tx") + require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not change after valid tx") // Check that state is only updated if all msgs in tx pass. app.accountKeeper.AddCoins(app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}}) @@ -960,10 +960,10 @@ func TestSendBurn(t *testing.T) { app.BeginBlock(abci.RequestBeginBlock{}) app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name()) - assert.Equal(t, sdk.ABCICodeType(0x1000a), res.Code, "Allowed tx to pass with insufficient funds") + require.Equal(t, sdk.ABCICodeType(0x1000a), res.Code, "Allowed tx to pass with insufficient funds") - assert.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(50)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Allowed valid msg to pass in invalid tx") - assert.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 changed after invalid tx") + require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(50)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Allowed valid msg to pass in invalid tx") + require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 changed after invalid tx") } //---------------------------------------- diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index e3b19c999d..37d7e91916 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -46,7 +46,7 @@ func TestKeys(t *testing.T) { reg, err := regexp.Compile(`([a-z]+ ){12}`) require.Nil(t, err) match := reg.MatchString(seed) - assert.True(t, match, "Returned seed has wrong format", seed) + require.True(t, match, "Returned seed has wrong format", seed) newName := "test_newname" newPassword := "0987654321" @@ -74,10 +74,10 @@ func TestKeys(t *testing.T) { addr2Bech32 := sdk.MustBech32ifyAcc(addr2Acc) addrBech32 := sdk.MustBech32ifyAcc(addr) - assert.Equal(t, name, m[0].Name, "Did not serve keys name correctly") - assert.Equal(t, addrBech32, m[0].Address, "Did not serve keys Address correctly") - assert.Equal(t, newName, m[1].Name, "Did not serve keys name correctly") - assert.Equal(t, addr2Bech32, m[1].Address, "Did not serve keys Address correctly") + require.Equal(t, name, m[0].Name, "Did not serve keys name correctly") + require.Equal(t, addrBech32, m[0].Address, "Did not serve keys Address correctly") + require.Equal(t, newName, m[1].Name, "Did not serve keys name correctly") + require.Equal(t, addr2Bech32, m[1].Address, "Did not serve keys Address correctly") // select key keyEndpoint := fmt.Sprintf("/keys/%s", newName) @@ -87,8 +87,8 @@ func TestKeys(t *testing.T) { err = cdc.UnmarshalJSON([]byte(body), &m2) require.Nil(t, err) - assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly") - assert.Equal(t, addr2Bech32, m2.Address, "Did not serve keys Address correctly") + require.Equal(t, newName, m2.Name, "Did not serve keys name correctly") + require.Equal(t, addr2Bech32, m2.Address, "Did not serve keys Address correctly") // update key jsonStr = []byte(fmt.Sprintf(`{ @@ -120,7 +120,7 @@ func TestVersion(t *testing.T) { reg, err := regexp.Compile(`\d+\.\d+\.\d+(-dev)?`) require.Nil(t, err) match := reg.MatchString(body) - assert.True(t, match, body) + require.True(t, match, body) // node info res, body = Request(t, port, "GET", "/node_version", nil) @@ -129,7 +129,7 @@ func TestVersion(t *testing.T) { reg, err = regexp.Compile(`\d+\.\d+\.\d+(-dev)?`) require.Nil(t, err) match = reg.MatchString(body) - assert.True(t, match, body) + require.True(t, match, body) } func TestNodeStatus(t *testing.T) { @@ -144,14 +144,14 @@ func TestNodeStatus(t *testing.T) { err := cdc.UnmarshalJSON([]byte(body), &nodeInfo) require.Nil(t, err, "Couldn't parse node info") - assert.NotEqual(t, p2p.NodeInfo{}, nodeInfo, "res: %v", res) + require.NotEqual(t, p2p.NodeInfo{}, nodeInfo, "res: %v", res) // syncing res, body = Request(t, port, "GET", "/syncing", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) // we expect that there is no other node running so the syncing state is "false" - assert.Equal(t, "false", body) + require.Equal(t, "false", body) } func TestBlock(t *testing.T) { @@ -166,7 +166,7 @@ func TestBlock(t *testing.T) { err := cdc.UnmarshalJSON([]byte(body), &resultBlock) require.Nil(t, err, "Couldn't parse block") - assert.NotEqual(t, ctypes.ResultBlock{}, resultBlock) + require.NotEqual(t, ctypes.ResultBlock{}, resultBlock) // -- @@ -176,7 +176,7 @@ func TestBlock(t *testing.T) { err = wire.Cdc.UnmarshalJSON([]byte(body), &resultBlock) require.Nil(t, err, "Couldn't parse block") - assert.NotEqual(t, ctypes.ResultBlock{}, resultBlock) + require.NotEqual(t, ctypes.ResultBlock{}, resultBlock) // -- @@ -196,10 +196,10 @@ func TestValidators(t *testing.T) { err := cdc.UnmarshalJSON([]byte(body), &resultVals) require.Nil(t, err, "Couldn't parse validatorset") - assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals) + require.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals) - assert.Contains(t, resultVals.Validators[0].Address, "cosmosvaladdr") - assert.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub") + require.Contains(t, resultVals.Validators[0].Address, "cosmosvaladdr") + require.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub") // -- @@ -209,7 +209,7 @@ func TestValidators(t *testing.T) { err = cdc.UnmarshalJSON([]byte(body), &resultVals) require.Nil(t, err, "Couldn't parse validatorset") - assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals) + require.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals) // -- @@ -239,24 +239,24 @@ func TestCoinSend(t *testing.T) { tests.WaitForHeight(resultTx.Height+1, port) // check if tx was committed - assert.Equal(t, uint32(0), resultTx.CheckTx.Code) - assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + require.Equal(t, uint32(0), resultTx.CheckTx.Code) + require.Equal(t, uint32(0), resultTx.DeliverTx.Code) // query sender acc = getAccount(t, port, addr) coins := acc.GetCoins() mycoins := coins[0] - assert.Equal(t, "steak", mycoins.Denom) - assert.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount) + require.Equal(t, "steak", mycoins.Denom) + require.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount) // query receiver acc = getAccount(t, port, receiveAddr) coins = acc.GetCoins() mycoins = coins[0] - assert.Equal(t, "steak", mycoins.Denom) - assert.Equal(t, int64(1), mycoins.Amount.Int64()) + require.Equal(t, "steak", mycoins.Denom) + require.Equal(t, int64(1), mycoins.Amount.Int64()) } func TestIBCTransfer(t *testing.T) { @@ -274,16 +274,16 @@ func TestIBCTransfer(t *testing.T) { tests.WaitForHeight(resultTx.Height+1, port) // check if tx was committed - assert.Equal(t, uint32(0), resultTx.CheckTx.Code) - assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + require.Equal(t, uint32(0), resultTx.CheckTx.Code) + require.Equal(t, uint32(0), resultTx.DeliverTx.Code) // query sender acc = getAccount(t, port, addr) coins := acc.GetCoins() mycoins := coins[0] - assert.Equal(t, "steak", mycoins.Denom) - assert.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount) + require.Equal(t, "steak", mycoins.Denom) + require.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount) // TODO: query ibc egress packet state } @@ -301,7 +301,7 @@ func TestTxs(t *testing.T) { // query empty res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3"), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - assert.Equal(t, "[]", body) + require.Equal(t, "[]", body) // create TX receiveAddr, resultTx := doSend(t, port, seed, name, password, addr) @@ -323,15 +323,15 @@ func TestTxs(t *testing.T) { // check if tx is queryable res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=tx.hash='%s'", resultTx.Hash), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - assert.NotEqual(t, "[]", body) + require.NotEqual(t, "[]", body) err := cdc.UnmarshalJSON([]byte(body), &indexedTxs) require.NoError(t, err) - assert.Equal(t, 1, len(indexedTxs)) + require.Equal(t, 1, len(indexedTxs)) // XXX should this move into some other testfile for txs in general? // test if created TX hash is the correct hash - assert.Equal(t, resultTx.Hash, indexedTxs[0].Hash) + require.Equal(t, resultTx.Hash, indexedTxs[0].Hash) // query sender // also tests url decoding @@ -342,7 +342,7 @@ func TestTxs(t *testing.T) { err = cdc.UnmarshalJSON([]byte(body), &indexedTxs) require.NoError(t, err) require.Equal(t, 1, len(indexedTxs), "%v", indexedTxs) // there are 2 txs created with doSend - assert.Equal(t, resultTx.Height, indexedTxs[0].Height) + require.Equal(t, resultTx.Height, indexedTxs[0].Height) // query recipient receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr) @@ -352,7 +352,7 @@ func TestTxs(t *testing.T) { err = cdc.UnmarshalJSON([]byte(body), &indexedTxs) require.NoError(t, err) require.Equal(t, 1, len(indexedTxs)) - assert.Equal(t, resultTx.Height, indexedTxs[0].Height) + require.Equal(t, resultTx.Height, indexedTxs[0].Height) } func TestValidatorsQuery(t *testing.T) { @@ -361,7 +361,7 @@ func TestValidatorsQuery(t *testing.T) { require.Equal(t, 2, len(pks)) validators := getValidators(t, port) - assert.Equal(t, len(validators), 2) + require.Equal(t, len(validators), 2) // make sure all the validators were found (order unknown because sorted by owner addr) foundVal1, foundVal2 := false, false @@ -373,8 +373,8 @@ func TestValidatorsQuery(t *testing.T) { if validators[0].PubKey == pk2Bech || validators[1].PubKey == pk2Bech { foundVal2 = true } - assert.True(t, foundVal1, "pk1Bech %v, owner1 %v, owner2 %v", pk1Bech, validators[0].Owner, validators[1].Owner) - assert.True(t, foundVal2, "pk2Bech %v, owner1 %v, owner2 %v", pk2Bech, validators[0].Owner, validators[1].Owner) + require.True(t, foundVal1, "pk1Bech %v, owner1 %v, owner2 %v", pk1Bech, validators[0].Owner, validators[1].Owner) + require.True(t, foundVal2, "pk2Bech %v, owner1 %v, owner2 %v", pk2Bech, validators[0].Owner, validators[1].Owner) } func TestBonding(t *testing.T) { @@ -390,18 +390,18 @@ func TestBonding(t *testing.T) { tests.WaitForHeight(resultTx.Height+1, port) // check if tx was committed - assert.Equal(t, uint32(0), resultTx.CheckTx.Code) - assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + require.Equal(t, uint32(0), resultTx.CheckTx.Code) + require.Equal(t, uint32(0), resultTx.DeliverTx.Code) // query sender acc := getAccount(t, port, addr) coins := acc.GetCoins() - assert.Equal(t, int64(40), coins.AmountOf(denom).Int64()) + require.Equal(t, int64(40), coins.AmountOf(denom).Int64()) // query validator bond := getDelegation(t, port, addr, validator1Owner) - assert.Equal(t, "60/1", bond.Shares.String()) + require.Equal(t, "60/1", bond.Shares.String()) ////////////////////// // testing unbonding @@ -412,17 +412,17 @@ func TestBonding(t *testing.T) { // query validator bond = getDelegation(t, port, addr, validator1Owner) - assert.Equal(t, "30/1", bond.Shares.String()) + require.Equal(t, "30/1", bond.Shares.String()) // check if tx was committed - assert.Equal(t, uint32(0), resultTx.CheckTx.Code) - assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + require.Equal(t, uint32(0), resultTx.CheckTx.Code) + require.Equal(t, uint32(0), resultTx.DeliverTx.Code) // should the sender should have not received any coins as the unbonding has only just begun // query sender acc = getAccount(t, port, addr) coins = acc.GetCoins() - assert.Equal(t, int64(40), coins.AmountOf("steak").Int64()) + require.Equal(t, int64(40), coins.AmountOf("steak").Int64()) // TODO add redelegation, need more complex capabilities such to mock context and } @@ -438,15 +438,15 @@ func TestSubmitProposal(t *testing.T) { tests.WaitForHeight(resultTx.Height+1, port) // check if tx was committed - assert.Equal(t, uint32(0), resultTx.CheckTx.Code) - assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + require.Equal(t, uint32(0), resultTx.CheckTx.Code) + require.Equal(t, uint32(0), resultTx.DeliverTx.Code) var proposalID int64 cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID) // query proposal proposal := getProposal(t, port, proposalID) - assert.Equal(t, "Test", proposal.Title) + require.Equal(t, "Test", proposal.Title) } func TestDeposit(t *testing.T) { @@ -460,15 +460,15 @@ func TestDeposit(t *testing.T) { tests.WaitForHeight(resultTx.Height+1, port) // check if tx was committed - assert.Equal(t, uint32(0), resultTx.CheckTx.Code) - assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + require.Equal(t, uint32(0), resultTx.CheckTx.Code) + require.Equal(t, uint32(0), resultTx.DeliverTx.Code) var proposalID int64 cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID) // query proposal proposal := getProposal(t, port, proposalID) - assert.Equal(t, "Test", proposal.Title) + require.Equal(t, "Test", proposal.Title) // create SubmitProposal TX resultTx = doDeposit(t, port, seed, name, password, addr, proposalID) @@ -476,11 +476,11 @@ func TestDeposit(t *testing.T) { // query proposal proposal = getProposal(t, port, proposalID) - assert.True(t, proposal.TotalDeposit.IsEqual(sdk.Coins{sdk.NewCoin("steak", 10)})) + require.True(t, proposal.TotalDeposit.IsEqual(sdk.Coins{sdk.NewCoin("steak", 10)})) // query deposit deposit := getDeposit(t, port, proposalID, addr) - assert.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewCoin("steak", 10)})) + require.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewCoin("steak", 10)})) } func TestVote(t *testing.T) { @@ -494,15 +494,15 @@ func TestVote(t *testing.T) { tests.WaitForHeight(resultTx.Height+1, port) // check if tx was committed - assert.Equal(t, uint32(0), resultTx.CheckTx.Code) - assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + require.Equal(t, uint32(0), resultTx.CheckTx.Code) + require.Equal(t, uint32(0), resultTx.DeliverTx.Code) var proposalID int64 cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID) // query proposal proposal := getProposal(t, port, proposalID) - assert.Equal(t, "Test", proposal.Title) + require.Equal(t, "Test", proposal.Title) // create SubmitProposal TX resultTx = doDeposit(t, port, seed, name, password, addr, proposalID) @@ -510,15 +510,15 @@ func TestVote(t *testing.T) { // query proposal proposal = getProposal(t, port, proposalID) - assert.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal.Status) + require.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal.Status) // create SubmitProposal TX resultTx = doVote(t, port, seed, name, password, addr, proposalID) tests.WaitForHeight(resultTx.Height+1, port) vote := getVote(t, port, proposalID, addr) - assert.Equal(t, proposalID, vote.ProposalID) - assert.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option) + require.Equal(t, proposalID, vote.ProposalID) + require.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option) } func TestProposalsQuery(t *testing.T) { @@ -563,31 +563,31 @@ func TestProposalsQuery(t *testing.T) { // Test query all proposals proposals := getProposalsAll(t, port) - assert.Equal(t, proposalID1, (proposals[0]).ProposalID) - assert.Equal(t, proposalID2, (proposals[1]).ProposalID) - assert.Equal(t, proposalID3, (proposals[2]).ProposalID) + require.Equal(t, proposalID1, (proposals[0]).ProposalID) + require.Equal(t, proposalID2, (proposals[1]).ProposalID) + require.Equal(t, proposalID3, (proposals[2]).ProposalID) // Test query deposited by addr1 proposals = getProposalsFilterDepositer(t, port, addr) - assert.Equal(t, proposalID1, (proposals[0]).ProposalID) + require.Equal(t, proposalID1, (proposals[0]).ProposalID) // Test query deposited by addr2 proposals = getProposalsFilterDepositer(t, port, addr2) - assert.Equal(t, proposalID2, (proposals[0]).ProposalID) - assert.Equal(t, proposalID3, (proposals[1]).ProposalID) + require.Equal(t, proposalID2, (proposals[0]).ProposalID) + require.Equal(t, proposalID3, (proposals[1]).ProposalID) // Test query voted by addr1 proposals = getProposalsFilterVoter(t, port, addr) - assert.Equal(t, proposalID2, (proposals[0]).ProposalID) - assert.Equal(t, proposalID3, (proposals[1]).ProposalID) + require.Equal(t, proposalID2, (proposals[0]).ProposalID) + require.Equal(t, proposalID3, (proposals[1]).ProposalID) // Test query voted by addr2 proposals = getProposalsFilterVoter(t, port, addr2) - assert.Equal(t, proposalID3, (proposals[0]).ProposalID) + require.Equal(t, proposalID3, (proposals[0]).ProposalID) // Test query voted and deposited by addr1 proposals = getProposalsFilterVoterDepositer(t, port, addr, addr) - assert.Equal(t, proposalID2, (proposals[0]).ProposalID) + require.Equal(t, proposalID2, (proposals[0]).ProposalID) } //_____________________________________________________________________________ diff --git a/cmd/gaia/app/genesis_test.go b/cmd/gaia/app/genesis_test.go index 90677e8ff1..7f0da29901 100644 --- a/cmd/gaia/app/genesis_test.go +++ b/cmd/gaia/app/genesis_test.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" ) @@ -14,7 +14,7 @@ func TestToAccount(t *testing.T) { addr := sdk.Address(priv.PubKey().Address()) authAcc := auth.NewBaseAccountWithAddress(addr) genAcc := NewGenesisAccount(&authAcc) - assert.Equal(t, authAcc, *genAcc.ToAccount()) + require.Equal(t, authAcc, *genAcc.ToAccount()) } func TestGaiaAppGenTx(t *testing.T) { diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index f8937c42dc..62fe0631a3 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -5,7 +5,6 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/keys" @@ -47,33 +46,33 @@ func TestGaiaCLISend(t *testing.T) { require.NoError(t, err) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) - assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) - assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64()) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) - assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) // test autosequencing executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) - assert.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak").Int64()) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) - assert.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64()) // test memo executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo --memo 'testmemo'", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) - assert.Equal(t, int64(30), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(30), barAcc.GetCoins().AmountOf("steak").Int64()) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) - assert.Equal(t, int64(20), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(20), fooAcc.GetCoins().AmountOf("steak").Int64()) } func TestGaiaCLICreateValidator(t *testing.T) { @@ -108,9 +107,9 @@ func TestGaiaCLICreateValidator(t *testing.T) { tests.WaitForNextHeightTM(port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) - assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64()) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) - assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) // create validator cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags) @@ -127,8 +126,8 @@ func TestGaiaCLICreateValidator(t *testing.T) { require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc) validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %v --output=json %v", barCech, flags)) - assert.Equal(t, validator.Owner, barAddr) - assert.Equal(t, "2/1", validator.PoolShares.Amount.String()) + require.Equal(t, validator.Owner, barAddr) + require.Equal(t, "2/1", validator.PoolShares.Amount.String()) // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond %v", flags) @@ -145,7 +144,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc) validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %v --output=json %v", barCech, flags)) - assert.Equal(t, "1/1", validator.PoolShares.Amount.String()) + require.Equal(t, "1/1", validator.PoolShares.Amount.String()) } func TestGaiaCLISubmitProposal(t *testing.T) { @@ -172,33 +171,33 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.NoError(t, err) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) - assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) executeWrite(t, fmt.Sprintf("gaiacli gov submitproposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --name=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) - assert.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64()) proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposalID=1 --output=json %v", flags)) - assert.Equal(t, int64(1), proposal1.ProposalID) - assert.Equal(t, gov.StatusToString(gov.StatusDepositPeriod), proposal1.Status) + require.Equal(t, int64(1), proposal1.ProposalID) + require.Equal(t, gov.StatusToString(gov.StatusDepositPeriod), proposal1.Status) executeWrite(t, fmt.Sprintf("gaiacli gov deposit %v --depositer=%v --deposit=10steak --proposalID=1 --name=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) - assert.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64()) proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposalID=1 --output=json %v", flags)) - assert.Equal(t, int64(1), proposal1.ProposalID) - assert.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal1.Status) + require.Equal(t, int64(1), proposal1.ProposalID) + require.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal1.Status) executeWrite(t, fmt.Sprintf("gaiacli gov vote %v --proposalID=1 --voter=%v --option=Yes --name=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposalID=1 --voter=%v --output=json %v", fooCech, flags)) - assert.Equal(t, int64(1), vote.ProposalID) - assert.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option) + require.Equal(t, int64(1), vote.ProposalID) + require.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option) } //___________________________________________________________________________________ diff --git a/crypto/encode_test.go b/crypto/encode_test.go index f9ab851b40..99dd727cf7 100644 --- a/crypto/encode_test.go +++ b/crypto/encode_test.go @@ -1,7 +1,6 @@ package crypto import ( - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "os" "testing" @@ -18,10 +17,10 @@ func checkAminoBinary(t *testing.T, src byter, dst interface{}, size int) { bz, err := cdc.MarshalBinaryBare(src) require.Nil(t, err, "%+v", err) // Make sure this is compatible with current (Bytes()) encoding. - assert.Equal(t, src.Bytes(), bz, "Amino binary vs Bytes() mismatch") + require.Equal(t, src.Bytes(), bz, "Amino binary vs Bytes() mismatch") // Make sure we have the expected length. if size != -1 { - assert.Equal(t, size, len(bz), "Amino binary size mismatch") + require.Equal(t, size, len(bz), "Amino binary size mismatch") } // Unmarshal. err = cdc.UnmarshalBinaryBare(bz, dst) @@ -33,10 +32,10 @@ func checkAminoJSON(t *testing.T, src interface{}, dst interface{}, isNil bool) js, err := cdc.MarshalJSON(src) require.Nil(t, err, "%+v", err) if isNil { - assert.Equal(t, string(js), `null`) + require.Equal(t, string(js), `null`) } else { - assert.Contains(t, string(js), `"type":`) - assert.Contains(t, string(js), `"value":`) + require.Contains(t, string(js), `"type":`) + require.Contains(t, string(js), `"value":`) } // Unmarshal. err = cdc.UnmarshalJSON(js, dst) @@ -79,26 +78,26 @@ func TestKeyEncodings(t *testing.T) { // Check (de/en)codings of PrivKeys. var priv2, priv3 tcrypto.PrivKey checkAminoBinary(t, tc.privKey, &priv2, tc.privSize) - assert.EqualValues(t, tc.privKey, priv2) + require.EqualValues(t, tc.privKey, priv2) checkAminoJSON(t, tc.privKey, &priv3, false) // TODO also check Prefix bytes. - assert.EqualValues(t, tc.privKey, priv3) + require.EqualValues(t, tc.privKey, priv3) // Check (de/en)codings of Signatures. var sig1, sig2, sig3 tcrypto.Signature sig1, err := tc.privKey.Sign([]byte("something")) - assert.NoError(t, err) + require.NoError(t, err) checkAminoBinary(t, sig1, &sig2, -1) // Signature size changes for Secp anyways. - assert.EqualValues(t, sig1, sig2) + require.EqualValues(t, sig1, sig2) checkAminoJSON(t, sig1, &sig3, false) // TODO also check Prefix bytes. - assert.EqualValues(t, sig1, sig3) + require.EqualValues(t, sig1, sig3) // Check (de/en)codings of PubKeys. pubKey := tc.privKey.PubKey() var pub2, pub3 tcrypto.PubKey checkAminoBinary(t, pubKey, &pub2, tc.pubSize) - assert.EqualValues(t, pubKey, pub2) + require.EqualValues(t, pubKey, pub2) checkAminoJSON(t, pubKey, &pub3, false) // TODO also check Prefix bytes. - assert.EqualValues(t, pubKey, pub3) + require.EqualValues(t, pubKey, pub3) } } @@ -107,16 +106,16 @@ func TestNilEncodings(t *testing.T) { // Check nil Signature. var a, b tcrypto.Signature checkAminoJSON(t, &a, &b, true) - assert.EqualValues(t, a, b) + require.EqualValues(t, a, b) // Check nil PubKey. var c, d tcrypto.PubKey checkAminoJSON(t, &c, &d, true) - assert.EqualValues(t, c, d) + require.EqualValues(t, c, d) // Check nil PrivKey. var e, f tcrypto.PrivKey checkAminoJSON(t, &e, &f, true) - assert.EqualValues(t, e, f) + require.EqualValues(t, e, f) } diff --git a/crypto/keys/bip39/wordcodec_test.go b/crypto/keys/bip39/wordcodec_test.go index dbc5c0d020..a821239d7b 100644 --- a/crypto/keys/bip39/wordcodec_test.go +++ b/crypto/keys/bip39/wordcodec_test.go @@ -3,13 +3,13 @@ package bip39 import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestWordCodec_NewMnemonic(t *testing.T) { _, err := NewMnemonic(FundRaiser) - assert.NoError(t, err, "unexpected error generating fundraiser mnemonic") + require.NoError(t, err, "unexpected error generating fundraiser mnemonic") _, err = NewMnemonic(FreshKey) - assert.NoError(t, err, "unexpected error generating new 24-word mnemonic") + require.NoError(t, err, "unexpected error generating new 24-word mnemonic") } diff --git a/crypto/keys/hd/fundraiser_test.go b/crypto/keys/hd/fundraiser_test.go index 3e45de7e2d..f4112d958b 100644 --- a/crypto/keys/hd/fundraiser_test.go +++ b/crypto/keys/hd/fundraiser_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/bartekn/go-bip39" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" ) @@ -56,7 +56,7 @@ func TestFundraiserCompatibility(t *testing.T) { master, ch := ComputeMastersFromSeed(seed) priv, err := DerivePrivateKeyForPath(master, ch, "44'/118'/0'/0/0") - assert.NoError(t, err) + require.NoError(t, err) pub := crypto.PrivKeySecp256k1(priv).PubKey() t.Log("\tNODEJS GOLANG\n") @@ -65,16 +65,16 @@ func TestFundraiserCompatibility(t *testing.T) { t.Logf("PRIV \t%X %X\n", privB, priv) t.Logf("PUB \t%X %X\n", pubB, pub) - assert.Equal(t, seedB, seed) - assert.Equal(t, master[:], masterB, fmt.Sprintf("Expected masters to match for %d", i)) - assert.Equal(t, priv[:], privB, "Expected priv keys to match") + require.Equal(t, seedB, seed) + require.Equal(t, master[:], masterB, fmt.Sprintf("Expected masters to match for %d", i)) + require.Equal(t, priv[:], privB, "Expected priv keys to match") var pubBFixed [33]byte copy(pubBFixed[:], pubB) - assert.Equal(t, pub, crypto.PubKeySecp256k1(pubBFixed), fmt.Sprintf("Expected pub keys to match for %d", i)) + require.Equal(t, pub, crypto.PubKeySecp256k1(pubBFixed), fmt.Sprintf("Expected pub keys to match for %d", i)) addr := pub.Address() t.Logf("ADDR \t%X %X\n", addrB, addr) - assert.Equal(t, addr, crypto.Address(addrB), fmt.Sprintf("Expected addresses to match %d", i)) + require.Equal(t, addr, crypto.Address(addrB), fmt.Sprintf("Expected addresses to match %d", i)) } } diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index d2f093bf2d..ac0f7fa4da 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -29,11 +29,11 @@ func TestKeyManagement(t *testing.T) { assert.Empty(t, l) _, _, err = cstore.CreateMnemonic(n1, English, p1, Ed25519) - assert.Error(t, err, "ed25519 keys are currently not supported by keybase") + require.Error(t, err, "ed25519 keys are currently not supported by keybase") // create some keys _, err = cstore.Get(n1) - assert.Error(t, err) + require.Error(t, err) i, _, err := cstore.CreateMnemonic(n1, English, p1, algo) require.NoError(t, err) @@ -43,18 +43,18 @@ func TestKeyManagement(t *testing.T) { // we can get these keys i2, err := cstore.Get(n2) - assert.NoError(t, err) + require.NoError(t, err) _, err = cstore.Get(n3) - assert.NotNil(t, err) + require.NotNil(t, err) // list shows them in order keyS, err := cstore.List() require.NoError(t, err) require.Equal(t, 2, len(keyS)) // note these are in alphabetical order - assert.Equal(t, n2, keyS[0].GetName()) - assert.Equal(t, n1, keyS[1].GetName()) - assert.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) + require.Equal(t, n2, keyS[0].GetName()) + require.Equal(t, n1, keyS[1].GetName()) + require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) // deleting a key removes it err = cstore.Delete("bad name", "foo") @@ -63,9 +63,9 @@ func TestKeyManagement(t *testing.T) { require.NoError(t, err) keyS, err = cstore.List() require.NoError(t, err) - assert.Equal(t, 1, len(keyS)) + require.Equal(t, 1, len(keyS)) _, err = cstore.Get(n1) - assert.Error(t, err) + require.Error(t, err) // create an offline key o1 := "offline" @@ -158,19 +158,19 @@ func TestSignVerify(t *testing.T) { for i, tc := range cases { valid := tc.key.VerifyBytes(tc.data, tc.sig) - assert.Equal(t, tc.valid, valid, "%d", i) + require.Equal(t, tc.valid, valid, "%d", i) } // Now try to sign data with a secret-less key _, _, err = cstore.Sign(n3, p3, d3) - assert.NotNil(t, err) + require.NotNil(t, err) } func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) { err := cstore.Update(name, badpass, pass) - assert.NotNil(t, err) + require.NotNil(t, err) err = cstore.Update(name, pass, pass) - assert.Nil(t, err, "%+v", err) + require.Nil(t, err, "%+v", err) } // TestExportImport tests exporting and importing @@ -183,26 +183,26 @@ func TestExportImport(t *testing.T) { ) info, _, err := cstore.CreateMnemonic("john", English, "secretcpw", Secp256k1) - assert.NoError(t, err) - assert.Equal(t, info.GetName(), "john") + require.NoError(t, err) + require.Equal(t, info.GetName(), "john") john, err := cstore.Get("john") - assert.NoError(t, err) - assert.Equal(t, info.GetName(), "john") + require.NoError(t, err) + require.Equal(t, info.GetName(), "john") johnAddr := info.GetPubKey().Address() armor, err := cstore.Export("john") - assert.NoError(t, err) + require.NoError(t, err) err = cstore.Import("john2", armor) - assert.NoError(t, err) + require.NoError(t, err) john2, err := cstore.Get("john2") - assert.NoError(t, err) + require.NoError(t, err) - assert.Equal(t, john.GetPubKey().Address(), johnAddr) - assert.Equal(t, john.GetName(), "john") - assert.Equal(t, john, john2) + require.Equal(t, john.GetPubKey().Address(), johnAddr) + require.Equal(t, john.GetName(), "john") + require.Equal(t, john, john2) } // @@ -216,35 +216,35 @@ func TestExportImportPubKey(t *testing.T) { // CreateMnemonic a private-public key pair and ensure consistency notPasswd := "n9y25ah7" info, _, err := cstore.CreateMnemonic("john", English, notPasswd, Secp256k1) - assert.Nil(t, err) - assert.NotEqual(t, info, "") - assert.Equal(t, info.GetName(), "john") + require.Nil(t, err) + require.NotEqual(t, info, "") + require.Equal(t, info.GetName(), "john") addr := info.GetPubKey().Address() john, err := cstore.Get("john") - assert.NoError(t, err) - assert.Equal(t, john.GetName(), "john") - assert.Equal(t, john.GetPubKey().Address(), addr) + require.NoError(t, err) + require.Equal(t, john.GetName(), "john") + require.Equal(t, john.GetPubKey().Address(), addr) // Export the public key only armor, err := cstore.ExportPubKey("john") - assert.NoError(t, err) + require.NoError(t, err) // Import it under a different name err = cstore.ImportPubKey("john-pubkey-only", armor) - assert.NoError(t, err) + require.NoError(t, err) // Ensure consistency john2, err := cstore.Get("john-pubkey-only") - assert.NoError(t, err) + require.NoError(t, err) // Compare the public keys - assert.True(t, john.GetPubKey().Equals(john2.GetPubKey())) + require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) // Ensure the original key hasn't changed john, err = cstore.Get("john") - assert.NoError(t, err) - assert.Equal(t, john.GetPubKey().Address(), addr) - assert.Equal(t, john.GetName(), "john") + require.NoError(t, err) + require.Equal(t, john.GetPubKey().Address(), addr) + require.Equal(t, john.GetName(), "john") // Ensure keys cannot be overwritten err = cstore.ImportPubKey("john-pubkey-only", armor) - assert.NotNil(t, err) + require.NotNil(t, err) } // TestAdvancedKeyManagement verifies update, import, export functionality @@ -266,34 +266,34 @@ func TestAdvancedKeyManagement(t *testing.T) { // update password requires the existing password err = cstore.Update(n1, "jkkgkg", p2) - assert.NotNil(t, err) + require.NotNil(t, err) assertPassword(t, cstore, n1, p1, p2) // then it changes the password when correct err = cstore.Update(n1, p1, p2) - assert.NoError(t, err) + require.NoError(t, err) // p2 is now the proper one! assertPassword(t, cstore, n1, p2, p1) // exporting requires the proper name and passphrase _, err = cstore.Export(n1 + ".notreal") - assert.NotNil(t, err) + require.NotNil(t, err) _, err = cstore.Export(" " + n1) - assert.NotNil(t, err) + require.NotNil(t, err) _, err = cstore.Export(n1 + " ") - assert.NotNil(t, err) + require.NotNil(t, err) _, err = cstore.Export("") - assert.NotNil(t, err) + require.NotNil(t, err) exported, err := cstore.Export(n1) require.Nil(t, err, "%+v", err) // import succeeds err = cstore.Import(n2, exported) - assert.NoError(t, err) + require.NoError(t, err) // second import fails err = cstore.Import(n2, exported) - assert.NotNil(t, err) + require.NotNil(t, err) } // TestSeedPhrase verifies restoring from a seed phrase @@ -311,7 +311,7 @@ func TestSeedPhrase(t *testing.T) { // make sure key works with initial password info, mnemonic, err := cstore.CreateMnemonic(n1, English, p1, algo) require.Nil(t, err, "%+v", err) - assert.Equal(t, n1, info.GetName()) + require.Equal(t, n1, info.GetName()) assert.NotEmpty(t, mnemonic) // now, let us delete this key @@ -324,9 +324,9 @@ func TestSeedPhrase(t *testing.T) { params := *hd.NewFundraiserParams(0, 0) newInfo, err := cstore.Derive(n2, mnemonic, p2, params) require.NoError(t, err) - assert.Equal(t, n2, newInfo.GetName()) - assert.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) - assert.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) + require.Equal(t, n2, newInfo.GetName()) + require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) + require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) } func ExampleNew() { diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go index 072d846473..997dfbc3bc 100644 --- a/crypto/ledger_test.go +++ b/crypto/ledger_test.go @@ -4,7 +4,6 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" tcrypto "github.com/tendermint/tendermint/crypto" @@ -26,7 +25,7 @@ func TestRealLedgerSecp256k1(t *testing.T) { require.Nil(t, err) valid := pub.VerifyBytes(msg, sig) - assert.True(t, valid) + require.True(t, valid) // now, let's serialize the key and make sure it still works bs := priv.Bytes() @@ -41,13 +40,13 @@ func TestRealLedgerSecp256k1(t *testing.T) { sig, err = priv2.Sign(msg) require.Nil(t, err) valid = pub.VerifyBytes(msg, sig) - assert.True(t, valid) + require.True(t, valid) // make sure pubkeys serialize properly as well bs = pub.Bytes() bpub, err := tcrypto.PubKeyFromBytes(bs) require.NoError(t, err) - assert.Equal(t, pub, bpub) + require.Equal(t, pub, bpub) } // TestRealLedgerErrorHandling calls. These tests assume diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 539a52c731..499c0e4082 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -5,7 +5,6 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/examples/basecoin/types" @@ -69,7 +68,7 @@ func TestGenesis(t *testing.T) { // A checkTx context ctx := bapp.BaseApp.NewContext(true, abci.Header{}) res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address) - assert.Equal(t, acc, res1) + require.Equal(t, acc, res1) // reload app and ensure the account is still there bapp = NewBasecoinApp(logger, db) @@ -85,5 +84,5 @@ func TestGenesis(t *testing.T) { ctx = bapp.BaseApp.NewContext(true, abci.Header{}) res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address) - assert.Equal(t, acc, res1) + require.Equal(t, acc, res1) } diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index d67e4f7064..36aca760f1 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -4,7 +4,6 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/examples/democoin/types" @@ -64,12 +63,12 @@ func TestGenesis(t *testing.T) { // A checkTx context ctx := bapp.BaseApp.NewContext(true, abci.Header{}) res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address) - assert.Equal(t, acc, res1) + require.Equal(t, acc, res1) // reload app and ensure the account is still there bapp = NewDemocoinApp(logger, db) bapp.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}")}) ctx = bapp.BaseApp.NewContext(true, abci.Header{}) res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address) - assert.Equal(t, acc, res1) + require.Equal(t, acc, res1) } diff --git a/examples/democoin/x/assoc/validator_set_test.go b/examples/democoin/x/assoc/validator_set_test.go index 289604149b..c20aeb8571 100644 --- a/examples/democoin/x/assoc/validator_set_test.go +++ b/examples/democoin/x/assoc/validator_set_test.go @@ -4,7 +4,7 @@ import ( "bytes" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" @@ -38,34 +38,34 @@ func TestValidatorSet(t *testing.T) { valset := NewValidatorSet(wire.NewCodec(), sdk.NewPrefixStoreGetter(key, []byte("assoc")), base, 1, 5) - assert.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1)) - assert.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2)) + require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1)) + require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2)) assoc1 := []byte("asso1") assoc2 := []byte("asso2") - assert.True(t, valset.Associate(ctx, addr1, assoc1)) - assert.True(t, valset.Associate(ctx, addr2, assoc2)) + require.True(t, valset.Associate(ctx, addr1, assoc1)) + require.True(t, valset.Associate(ctx, addr2, assoc2)) - assert.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, assoc1)) - assert.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, assoc2)) + require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, assoc1)) + require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, assoc2)) - assert.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1)) - assert.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2)) + require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1)) + require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2)) assocs := valset.Associations(ctx, addr1) - assert.Equal(t, 1, len(assocs)) - assert.True(t, bytes.Equal(assoc1, assocs[0])) + require.Equal(t, 1, len(assocs)) + require.True(t, bytes.Equal(assoc1, assocs[0])) - assert.False(t, valset.Associate(ctx, addr1, assoc2)) - assert.False(t, valset.Associate(ctx, addr2, assoc1)) + require.False(t, valset.Associate(ctx, addr1, assoc2)) + require.False(t, valset.Associate(ctx, addr2, assoc1)) valset.Dissociate(ctx, addr1, assoc1) valset.Dissociate(ctx, addr2, assoc2) - assert.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1)) - assert.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2)) + require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1)) + require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2)) - assert.Nil(t, valset.Validator(ctx, assoc1)) - assert.Nil(t, valset.Validator(ctx, assoc2)) + require.Nil(t, valset.Validator(ctx, assoc1)) + require.Nil(t, valset.Validator(ctx, assoc2)) } diff --git a/examples/democoin/x/cool/app_test.go b/examples/democoin/x/cool/app_test.go index efcc6c1bf2..e93f6d99c5 100644 --- a/examples/democoin/x/cool/app_test.go +++ b/examples/democoin/x/cool/app_test.go @@ -3,7 +3,6 @@ package cool import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -88,7 +87,7 @@ func TestMsgQuiz(t *testing.T) { // A checkTx context (true) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) - assert.Equal(t, acc1, res1) + require.Equal(t, acc1, res1) // Set the trend, submit a really cool quiz and check for reward mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []int64{0}, []int64{0}, true, priv1) diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index 3dfad91f13..ee2e529f26 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -3,7 +3,7 @@ package cool import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" @@ -35,16 +35,16 @@ func TestCoolKeeper(t *testing.T) { keeper := NewKeeper(capKey, ck, DefaultCodespace) err := InitGenesis(ctx, keeper, Genesis{"icy"}) - assert.Nil(t, err) + require.Nil(t, err) genesis := WriteGenesis(ctx, keeper) - assert.Nil(t, err) - assert.Equal(t, genesis, Genesis{"icy"}) + require.Nil(t, err) + require.Equal(t, genesis, Genesis{"icy"}) res := keeper.GetTrend(ctx) - assert.Equal(t, res, "icy") + require.Equal(t, res, "icy") keeper.setTrend(ctx, "fiery") res = keeper.GetTrend(ctx) - assert.Equal(t, res, "fiery") + require.Equal(t, res, "fiery") } diff --git a/examples/democoin/x/oracle/oracle_test.go b/examples/democoin/x/oracle/oracle_test.go index 01885e0d5e..228378c34a 100644 --- a/examples/democoin/x/oracle/oracle_test.go +++ b/examples/democoin/x/oracle/oracle_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -124,50 +123,50 @@ func TestOracle(t *testing.T) { // Nonmock.Validator signed, transaction failed msg := Msg{seqOracle{0, 0}, []byte("randomguy")} res := h(ctx, msg) - assert.False(t, res.IsOK()) - assert.Equal(t, 0, getSequence(ctx, key)) + require.False(t, res.IsOK()) + require.Equal(t, 0, getSequence(ctx, key)) // Less than 2/3 signed, msg not processed msg.Signer = addr1 res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 0, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 0, getSequence(ctx, key)) // Double signed, transaction failed res = h(ctx, msg) - assert.False(t, res.IsOK()) - assert.Equal(t, 0, getSequence(ctx, key)) + require.False(t, res.IsOK()) + require.Equal(t, 0, getSequence(ctx, key)) // More than 2/3 signed, msg processed msg.Signer = addr2 res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 1, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 1, getSequence(ctx, key)) // Already processed, transaction failed msg.Signer = addr3 res = h(ctx, msg) - assert.False(t, res.IsOK()) - assert.Equal(t, 1, getSequence(ctx, key)) + require.False(t, res.IsOK()) + require.Equal(t, 1, getSequence(ctx, key)) // Less than 2/3 signed, msg not processed msg = Msg{seqOracle{100, 1}, addr1} res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 1, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 1, getSequence(ctx, key)) // More than 2/3 signed but payload is invalid msg.Signer = addr2 res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.NotEqual(t, "", res.Log) - assert.Equal(t, 1, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.NotEqual(t, "", res.Log) + require.Equal(t, 1, getSequence(ctx, key)) // Already processed, transaction failed msg.Signer = addr3 res = h(ctx, msg) - assert.False(t, res.IsOK()) - assert.Equal(t, 1, getSequence(ctx, key)) + require.False(t, res.IsOK()) + require.Equal(t, 1, getSequence(ctx, key)) // Should handle mock.Validator set change valset.AddValidator(mock.Validator{addr4, sdk.NewRat(12)}) @@ -178,28 +177,28 @@ func TestOracle(t *testing.T) { // Less than 2/3 signed, msg not processed msg = Msg{seqOracle{1, 2}, addr1} res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 1, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 1, getSequence(ctx, key)) // Less than 2/3 signed, msg not processed msg.Signer = addr2 res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 1, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 1, getSequence(ctx, key)) // More than 2/3 signed, msg processed msg.Signer = addr4 res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 2, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 2, getSequence(ctx, key)) // Should handle mock.Validator set change while oracle process is happening msg = Msg{seqOracle{2, 3}, addr4} // Less than 2/3 signed, msg not processed res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 2, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 2, getSequence(ctx, key)) // Signed mock.Validator is kicked out valset.RemoveValidator(addr4) @@ -210,12 +209,12 @@ func TestOracle(t *testing.T) { // Less than 2/3 signed, msg not processed msg.Signer = addr1 res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 2, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 2, getSequence(ctx, key)) // More than 2/3 signed, msg processed msg.Signer = addr2 res = h(ctx, msg) - assert.True(t, res.IsOK()) - assert.Equal(t, 3, getSequence(ctx, key)) + require.True(t, res.IsOK()) + require.Equal(t, 3, getSequence(ctx, key)) } diff --git a/examples/democoin/x/pow/app_test.go b/examples/democoin/x/pow/app_test.go index 6dab193886..d223a1f107 100644 --- a/examples/democoin/x/pow/app_test.go +++ b/examples/democoin/x/pow/app_test.go @@ -3,7 +3,6 @@ package pow import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -68,7 +67,7 @@ func TestMsgMine(t *testing.T) { // A checkTx context (true) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) - assert.Equal(t, acc1, res1) + require.Equal(t, acc1, res1) // Mine and check for reward mineMsg1 := GenerateMsgMine(addr1, 1, 2) diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index 5aaba48bbb..77a22057bc 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -3,7 +3,7 @@ package pow import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tmlibs/log" @@ -32,21 +32,21 @@ func TestPowHandler(t *testing.T) { difficulty := uint64(2) err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)}) - assert.Nil(t, err) + require.Nil(t, err) nonce, proof := mine(addr, count, difficulty) msg := NewMsgMine(addr, difficulty, count, nonce, proof) result := handler(ctx, msg) - assert.Equal(t, result, sdk.Result{}) + require.Equal(t, result, sdk.Result{}) newDiff, err := keeper.GetLastDifficulty(ctx) - assert.Nil(t, err) - assert.Equal(t, newDiff, uint64(2)) + require.Nil(t, err) + require.Equal(t, newDiff, uint64(2)) newCount, err := keeper.GetLastCount(ctx) - assert.Nil(t, err) - assert.Equal(t, newCount, uint64(1)) + require.Nil(t, err) + require.Equal(t, newCount, uint64(1)) // todo assert correct coin change, awaiting https://github.com/cosmos/cosmos-sdk/pull/691 @@ -55,5 +55,5 @@ func TestPowHandler(t *testing.T) { msg = NewMsgMine(addr, difficulty, count, nonce, proof) result = handler(ctx, msg) - assert.NotEqual(t, result, sdk.Result{}) + require.NotEqual(t, result, sdk.Result{}) } diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index 53c3e83b4b..31ad2fc121 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -3,7 +3,7 @@ package pow import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" @@ -39,19 +39,19 @@ func TestPowKeeperGetSet(t *testing.T) { keeper := NewKeeper(capKey, config, ck, DefaultCodespace) err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)}) - assert.Nil(t, err) + require.Nil(t, err) genesis := WriteGenesis(ctx, keeper) - assert.Nil(t, err) - assert.Equal(t, genesis, Genesis{uint64(1), uint64(0)}) + require.Nil(t, err) + require.Equal(t, genesis, Genesis{uint64(1), uint64(0)}) res, err := keeper.GetLastDifficulty(ctx) - assert.Nil(t, err) - assert.Equal(t, res, uint64(1)) + require.Nil(t, err) + require.Equal(t, res, uint64(1)) keeper.SetLastDifficulty(ctx, 2) res, err = keeper.GetLastDifficulty(ctx) - assert.Nil(t, err) - assert.Equal(t, res, uint64(2)) + require.Nil(t, err) + require.Equal(t, res, uint64(2)) } diff --git a/examples/democoin/x/pow/types_test.go b/examples/democoin/x/pow/types_test.go index e69e595592..9ed5dc102c 100644 --- a/examples/democoin/x/pow/types_test.go +++ b/examples/democoin/x/pow/types_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,13 +13,13 @@ func TestNewMsgMine(t *testing.T) { addr := sdk.Address([]byte("sender")) msg := MsgMine{addr, 0, 0, 0, []byte("")} equiv := NewMsgMine(addr, 0, 0, 0, []byte("")) - assert.Equal(t, msg, equiv, "%s != %s", msg, equiv) + require.Equal(t, msg, equiv, "%s != %s", msg, equiv) } func TestMsgMineType(t *testing.T) { addr := sdk.Address([]byte("sender")) msg := MsgMine{addr, 0, 0, 0, []byte("")} - assert.Equal(t, msg.Type(), "pow") + require.Equal(t, msg.Type(), "pow") } func TestMsgMineValidation(t *testing.T) { @@ -33,21 +33,21 @@ func TestMsgMineValidation(t *testing.T) { nonce, proof := mine(addr, count, difficulty) msg := MsgMine{addr, difficulty, count, nonce, proof} err := msg.ValidateBasic() - assert.Nil(t, err, "error with difficulty %d - %+v", difficulty, err) + require.Nil(t, err, "error with difficulty %d - %+v", difficulty, err) msg.Count++ err = msg.ValidateBasic() - assert.NotNil(t, err, "count was wrong, should have thrown error with msg %s", msg) + require.NotNil(t, err, "count was wrong, should have thrown error with msg %s", msg) msg.Count-- msg.Nonce++ err = msg.ValidateBasic() - assert.NotNil(t, err, "nonce was wrong, should have thrown error with msg %s", msg) + require.NotNil(t, err, "nonce was wrong, should have thrown error with msg %s", msg) msg.Nonce-- msg.Sender = otherAddr err = msg.ValidateBasic() - assert.NotNil(t, err, "sender was wrong, should have thrown error with msg %s", msg) + require.NotNil(t, err, "sender was wrong, should have thrown error with msg %s", msg) } } @@ -55,19 +55,19 @@ func TestMsgMineString(t *testing.T) { addr := sdk.Address([]byte("sender")) msg := MsgMine{addr, 0, 0, 0, []byte("abc")} res := msg.String() - assert.Equal(t, res, "MsgMine{Sender: 73656E646572, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}") + require.Equal(t, res, "MsgMine{Sender: 73656E646572, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}") } func TestMsgMineGetSignBytes(t *testing.T) { addr := sdk.Address([]byte("sender")) msg := MsgMine{addr, 1, 1, 1, []byte("abc")} res := msg.GetSignBytes() - assert.Equal(t, string(res), `{"sender":"73656E646572","difficulty":1,"count":1,"nonce":1,"proof":"YWJj"}`) + require.Equal(t, string(res), `{"sender":"73656E646572","difficulty":1,"count":1,"nonce":1,"proof":"YWJj"}`) } func TestMsgMineGetSigners(t *testing.T) { addr := sdk.Address([]byte("sender")) msg := MsgMine{addr, 1, 1, 1, []byte("abc")} res := msg.GetSigners() - assert.Equal(t, fmt.Sprintf("%v", res), "[73656E646572]") + require.Equal(t, fmt.Sprintf("%v", res), "[73656E646572]") } diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index 9cb02afd7d..be8e335e2b 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -5,7 +5,6 @@ import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -42,7 +41,7 @@ func TestKeeperGetSet(t *testing.T) { addr := sdk.Address([]byte("some-address")) bi := stakeKeeper.getBondInfo(ctx, addr) - assert.Equal(t, bi, bondInfo{}) + require.Equal(t, bi, bondInfo{}) privKey := crypto.GenPrivKeyEd25519() @@ -54,9 +53,9 @@ func TestKeeperGetSet(t *testing.T) { stakeKeeper.setBondInfo(ctx, addr, bi) savedBi := stakeKeeper.getBondInfo(ctx, addr) - assert.NotNil(t, savedBi) + require.NotNil(t, savedBi) fmt.Printf("Bond Info: %v\n", savedBi) - assert.Equal(t, int64(10), savedBi.Power) + require.Equal(t, int64(10), savedBi.Power) } func TestBonding(t *testing.T) { @@ -74,19 +73,19 @@ func TestBonding(t *testing.T) { pubKey := privKey.PubKey() _, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr) - assert.Equal(t, err, ErrInvalidUnbond(DefaultCodespace)) + require.Equal(t, err, ErrInvalidUnbond(DefaultCodespace)) _, err = stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewCoin("steak", 10)) - assert.Nil(t, err) + require.Nil(t, err) power, err := stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewCoin("steak", 10)) require.Nil(t, err) - assert.Equal(t, int64(20), power) + require.Equal(t, int64(20), power) pk, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr) - assert.Nil(t, err) - assert.Equal(t, pubKey, pk) + require.Nil(t, err) + require.Equal(t, pubKey, pk) _, _, err = stakeKeeper.unbondWithoutCoins(ctx, addr) - assert.Equal(t, err, ErrInvalidUnbond(DefaultCodespace)) + require.Equal(t, err, ErrInvalidUnbond(DefaultCodespace)) } diff --git a/examples/democoin/x/simplestake/msgs_test.go b/examples/democoin/x/simplestake/msgs_test.go index 188a4ec3a8..9baf0dd1a9 100644 --- a/examples/democoin/x/simplestake/msgs_test.go +++ b/examples/democoin/x/simplestake/msgs_test.go @@ -3,7 +3,7 @@ package simplestake import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" @@ -23,9 +23,9 @@ func TestBondMsgValidation(t *testing.T) { for i, tc := range cases { err := tc.msgBond.ValidateBasic() if tc.valid { - assert.Nil(t, err, "%d: %+v", i, err) + require.Nil(t, err, "%d: %+v", i, err) } else { - assert.NotNil(t, err, "%d", i) + require.NotNil(t, err, "%d", i) } } } diff --git a/server/mock/app_test.go b/server/mock/app_test.go index 7c0b70da25..05ec865219 100644 --- a/server/mock/app_test.go +++ b/server/mock/app_test.go @@ -3,7 +3,6 @@ package mock import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -38,7 +37,7 @@ func TestInitApp(t *testing.T) { } qres := app.Query(query) require.Equal(t, uint32(0), qres.Code, qres.Log) - assert.Equal(t, []byte("bar"), qres.Value) + require.Equal(t, []byte("bar"), qres.Value) } // TextDeliverTx ensures we can write a tx @@ -74,5 +73,5 @@ func TestDeliverTx(t *testing.T) { } qres := app.Query(query) require.Equal(t, uint32(0), qres.Code, qres.Log) - assert.Equal(t, []byte(value), qres.Value) + require.Equal(t, []byte(value), qres.Value) } diff --git a/server/mock/store_test.go b/server/mock/store_test.go index bd01244667..bf6a1007b6 100644 --- a/server/mock/store_test.go +++ b/server/mock/store_test.go @@ -3,7 +3,7 @@ package mock import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" dbm "github.com/tendermint/tmlibs/db" @@ -17,17 +17,17 @@ func TestStore(t *testing.T) { key := sdk.NewKVStoreKey("test") cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) err := cms.LoadLatestVersion() - assert.Nil(t, err) + require.Nil(t, err) store := cms.GetKVStore(key) - assert.NotNil(t, store) + require.NotNil(t, store) k := []byte("hello") v := []byte("world") - assert.False(t, store.Has(k)) + require.False(t, store.Has(k)) store.Set(k, v) - assert.True(t, store.Has(k)) - assert.Equal(t, v, store.Get(k)) + require.True(t, store.Has(k)) + require.Equal(t, v, store.Get(k)) store.Delete(k) - assert.False(t, store.Has(k)) + require.False(t, store.Has(k)) } diff --git a/server/util_test.go b/server/util_test.go index 13f8ad5dbc..8f1ab21dbc 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/cosmos/cosmos-sdk/wire" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -37,5 +36,5 @@ func TestAppendJSON(t *testing.T) { err = cdc.UnmarshalJSON(appended["barOuter"], &resBar) require.NoError(t, err) - assert.Equal(t, bar, resBar, "appended: %v", appended) + require.Equal(t, bar, resBar, "appended: %v", appended) } diff --git a/store/cachekvstore_test.go b/store/cachekvstore_test.go index 0c88ca27d0..f9be76dae3 100644 --- a/store/cachekvstore_test.go +++ b/store/cachekvstore_test.go @@ -3,7 +3,6 @@ package store import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -103,11 +102,11 @@ func TestCacheKVIteratorBounds(t *testing.T) { var i = 0 for ; itr.Valid(); itr.Next() { k, v := itr.Key(), itr.Value() - assert.Equal(t, keyFmt(i), k) - assert.Equal(t, valFmt(i), v) + require.Equal(t, keyFmt(i), k) + require.Equal(t, valFmt(i), v) i++ } - assert.Equal(t, nItems, i) + require.Equal(t, nItems, i) // iterate over none itr = st.Iterator(bz("money"), nil) @@ -115,29 +114,29 @@ func TestCacheKVIteratorBounds(t *testing.T) { for ; itr.Valid(); itr.Next() { i++ } - assert.Equal(t, 0, i) + require.Equal(t, 0, i) // iterate over lower itr = st.Iterator(keyFmt(0), keyFmt(3)) i = 0 for ; itr.Valid(); itr.Next() { k, v := itr.Key(), itr.Value() - assert.Equal(t, keyFmt(i), k) - assert.Equal(t, valFmt(i), v) + require.Equal(t, keyFmt(i), k) + require.Equal(t, valFmt(i), v) i++ } - assert.Equal(t, 3, i) + require.Equal(t, 3, i) // iterate over upper itr = st.Iterator(keyFmt(2), keyFmt(4)) i = 2 for ; itr.Valid(); itr.Next() { k, v := itr.Key(), itr.Value() - assert.Equal(t, keyFmt(i), k) - assert.Equal(t, valFmt(i), v) + require.Equal(t, keyFmt(i), k) + require.Equal(t, valFmt(i), v) i++ } - assert.Equal(t, 4, i) + require.Equal(t, 4, i) } func TestCacheKVMergeIteratorBasics(t *testing.T) { @@ -367,11 +366,11 @@ func assertIterateDomain(t *testing.T, st KVStore, expectedN int) { var i = 0 for ; itr.Valid(); itr.Next() { k, v := itr.Key(), itr.Value() - assert.Equal(t, keyFmt(i), k) - assert.Equal(t, valFmt(i), v) + require.Equal(t, keyFmt(i), k) + require.Equal(t, valFmt(i), v) i++ } - assert.Equal(t, expectedN, i) + require.Equal(t, expectedN, i) } func assertIterateDomainCheck(t *testing.T, st KVStore, mem dbm.DB, r []keyRange) { @@ -383,25 +382,25 @@ func assertIterateDomainCheck(t *testing.T, st KVStore, mem dbm.DB, r []keyRange i := 0 for ; krc.valid(); krc.next() { - assert.True(t, itr.Valid()) - assert.True(t, itr2.Valid()) + require.True(t, itr.Valid()) + require.True(t, itr2.Valid()) // check the key/val matches the ground truth k, v := itr.Key(), itr.Value() k2, v2 := itr2.Key(), itr2.Value() - assert.Equal(t, k, k2) - assert.Equal(t, v, v2) + require.Equal(t, k, k2) + require.Equal(t, v, v2) // check they match the counter - assert.Equal(t, k, keyFmt(krc.key())) + require.Equal(t, k, keyFmt(krc.key())) itr.Next() itr2.Next() i++ } - assert.False(t, itr.Valid()) - assert.False(t, itr2.Valid()) + require.False(t, itr.Valid()) + require.False(t, itr2.Valid()) } func assertIterateDomainCompare(t *testing.T, st KVStore, mem dbm.DB) { @@ -414,15 +413,15 @@ func assertIterateDomainCompare(t *testing.T, st KVStore, mem dbm.DB) { func checkIterators(t *testing.T, itr, itr2 Iterator) { for ; itr.Valid(); itr.Next() { - assert.True(t, itr2.Valid()) + require.True(t, itr2.Valid()) k, v := itr.Key(), itr.Value() k2, v2 := itr2.Key(), itr2.Value() - assert.Equal(t, k, k2) - assert.Equal(t, v, v2) + require.Equal(t, k, k2) + require.Equal(t, v, v2) itr2.Next() } - assert.False(t, itr.Valid()) - assert.False(t, itr2.Valid()) + require.False(t, itr.Valid()) + require.False(t, itr2.Valid()) } //-------------------------------------------------------- diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index 25e08aefd9..b23f04e5cd 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -3,7 +3,7 @@ package store import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/iavl" abci "github.com/tendermint/tendermint/abci/types" @@ -38,7 +38,7 @@ func newTree(t *testing.T, db dbm.DB) (*iavl.VersionedTree, CommitID) { tree.Set(key, value) } hash, ver, err := tree.SaveVersion() - assert.Nil(t, err) + require.Nil(t, err) return tree, CommitID{ver, hash} } @@ -50,21 +50,21 @@ func TestIAVLStoreGetSetHasDelete(t *testing.T) { key := "hello" exists := iavlStore.Has([]byte(key)) - assert.True(t, exists) + require.True(t, exists) value := iavlStore.Get([]byte(key)) - assert.EqualValues(t, value, treeData[key]) + require.EqualValues(t, value, treeData[key]) value2 := "notgoodbye" iavlStore.Set([]byte(key), []byte(value2)) value = iavlStore.Get([]byte(key)) - assert.EqualValues(t, value, value2) + require.EqualValues(t, value, value2) iavlStore.Delete([]byte(key)) exists = iavlStore.Has([]byte(key)) - assert.False(t, exists) + require.False(t, exists) } func TestIAVLIterator(t *testing.T) { @@ -78,66 +78,66 @@ func TestIAVLIterator(t *testing.T) { for i = 0; iter.Valid(); iter.Next() { expectedKey := expected[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, treeData[expectedKey]) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, treeData[expectedKey]) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = iavlStore.Iterator([]byte("golang"), []byte("rocks")) expected = []string{"hello"} for i = 0; iter.Valid(); iter.Next() { expectedKey := expected[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, treeData[expectedKey]) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, treeData[expectedKey]) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = iavlStore.Iterator(nil, []byte("golang")) expected = []string{"aloha"} for i = 0; iter.Valid(); iter.Next() { expectedKey := expected[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, treeData[expectedKey]) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, treeData[expectedKey]) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = iavlStore.Iterator(nil, []byte("shalom")) expected = []string{"aloha", "hello"} for i = 0; iter.Valid(); iter.Next() { expectedKey := expected[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, treeData[expectedKey]) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, treeData[expectedKey]) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = iavlStore.Iterator(nil, nil) expected = []string{"aloha", "hello"} for i = 0; iter.Valid(); iter.Next() { expectedKey := expected[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, treeData[expectedKey]) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, treeData[expectedKey]) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = iavlStore.Iterator([]byte("golang"), nil) expected = []string{"hello"} for i = 0; iter.Valid(); iter.Next() { expectedKey := expected[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, treeData[expectedKey]) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, treeData[expectedKey]) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) } func TestIAVLSubspaceIterator(t *testing.T) { @@ -162,11 +162,11 @@ func TestIAVLSubspaceIterator(t *testing.T) { for i = 0; iter.Valid(); iter.Next() { expectedKey := expected[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, expectedKey) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, expectedKey) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = sdk.KVStorePrefixIterator(iavlStore, []byte{byte(55), byte(255), byte(255)}) expected2 := [][]byte{ @@ -177,11 +177,11 @@ func TestIAVLSubspaceIterator(t *testing.T) { for i = 0; iter.Valid(); iter.Next() { expectedKey := expected2[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, []byte("test4")) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, []byte("test4")) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = sdk.KVStorePrefixIterator(iavlStore, []byte{byte(255), byte(255)}) expected2 = [][]byte{ @@ -192,11 +192,11 @@ func TestIAVLSubspaceIterator(t *testing.T) { for i = 0; iter.Valid(); iter.Next() { expectedKey := expected2[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, []byte("test4")) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, []byte("test4")) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) } func TestIAVLReverseSubspaceIterator(t *testing.T) { @@ -221,11 +221,11 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) { for i = 0; iter.Valid(); iter.Next() { expectedKey := expected[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, expectedKey) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, expectedKey) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = sdk.KVStoreReversePrefixIterator(iavlStore, []byte{byte(55), byte(255), byte(255)}) expected2 := [][]byte{ @@ -236,11 +236,11 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) { for i = 0; iter.Valid(); iter.Next() { expectedKey := expected2[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, []byte("test4")) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, []byte("test4")) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) iter = sdk.KVStoreReversePrefixIterator(iavlStore, []byte{byte(255), byte(255)}) expected2 = [][]byte{ @@ -251,11 +251,11 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) { for i = 0; iter.Valid(); iter.Next() { expectedKey := expected2[i] key, value := iter.Key(), iter.Value() - assert.EqualValues(t, key, expectedKey) - assert.EqualValues(t, value, []byte("test4")) + require.EqualValues(t, key, expectedKey) + require.EqualValues(t, value, []byte("test4")) i++ } - assert.Equal(t, len(expected), i) + require.Equal(t, len(expected), i) } func TestIAVLStoreQuery(t *testing.T) { @@ -288,8 +288,8 @@ func TestIAVLStoreQuery(t *testing.T) { // query subspace before anything set qres := iavlStore.Query(querySub) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Equal(t, valExpSubEmpty, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Equal(t, valExpSubEmpty, qres.Value) // set data iavlStore.Set(k1, v1) @@ -297,25 +297,25 @@ func TestIAVLStoreQuery(t *testing.T) { // set data without commit, doesn't show up qres = iavlStore.Query(query) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Nil(t, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Nil(t, qres.Value) // commit it, but still don't see on old version cid = iavlStore.Commit() qres = iavlStore.Query(query) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Nil(t, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Nil(t, qres.Value) // but yes on the new version query.Height = cid.Version qres = iavlStore.Query(query) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Equal(t, v1, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Equal(t, v1, qres.Value) // and for the subspace qres = iavlStore.Query(querySub) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Equal(t, valExpSub1, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Equal(t, valExpSub1, qres.Value) // modify iavlStore.Set(k1, v3) @@ -323,26 +323,26 @@ func TestIAVLStoreQuery(t *testing.T) { // query will return old values, as height is fixed qres = iavlStore.Query(query) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Equal(t, v1, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Equal(t, v1, qres.Value) // update to latest in the query and we are happy query.Height = cid.Version qres = iavlStore.Query(query) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Equal(t, v3, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Equal(t, v3, qres.Value) query2 := abci.RequestQuery{Path: "/key", Data: k2, Height: cid.Version} qres = iavlStore.Query(query2) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Equal(t, v2, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Equal(t, v2, qres.Value) // and for the subspace qres = iavlStore.Query(querySub) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Equal(t, valExpSub2, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Equal(t, valExpSub2, qres.Value) // default (height 0) will show latest -1 query0 := abci.RequestQuery{Path: "/store", Data: k1} qres = iavlStore.Query(query0) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) - assert.Equal(t, v1, qres.Value) + require.Equal(t, uint32(sdk.CodeOK), qres.Code) + require.Equal(t, v1, qres.Value) } diff --git a/store/prefixstore_test.go b/store/prefixstore_test.go index d41d120553..76fb7f481f 100644 --- a/store/prefixstore_test.go +++ b/store/prefixstore_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/iavl" dbm "github.com/tendermint/tmlibs/db" @@ -96,14 +97,14 @@ func TestPrefixStoreIterate(t *testing.T) { pIter := sdk.KVStorePrefixIterator(prefixStore, nil) for bIter.Valid() && pIter.Valid() { - assert.Equal(t, bIter.Key(), append(prefix, pIter.Key()...)) - assert.Equal(t, bIter.Value(), pIter.Value()) + require.Equal(t, bIter.Key(), append(prefix, pIter.Key()...)) + require.Equal(t, bIter.Value(), pIter.Value()) bIter.Next() pIter.Next() } - assert.Equal(t, bIter.Valid(), pIter.Valid()) + require.Equal(t, bIter.Valid(), pIter.Valid()) bIter.Close() pIter.Close() } diff --git a/store/rootmultistore_test.go b/store/rootmultistore_test.go index 89d40f761c..197726f4ac 100644 --- a/store/rootmultistore_test.go +++ b/store/rootmultistore_test.go @@ -3,7 +3,7 @@ package store import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/merkle" @@ -20,7 +20,7 @@ func TestMultistoreCommitLoad(t *testing.T) { } store := newMultiStoreWithMounts(db) err := store.LoadLatestVersion() - assert.Nil(t, err) + require.Nil(t, err) // New store has empty last commit. commitID := CommitID{} @@ -28,11 +28,11 @@ func TestMultistoreCommitLoad(t *testing.T) { // Make sure we can get stores by name. s1 := store.getStoreByName("store1") - assert.NotNil(t, s1) + require.NotNil(t, s1) s3 := store.getStoreByName("store3") - assert.NotNil(t, s3) + require.NotNil(t, s3) s77 := store.getStoreByName("store77") - assert.Nil(t, s77) + require.Nil(t, s77) // Make a few commits and check them. nCommits := int64(3) @@ -45,7 +45,7 @@ func TestMultistoreCommitLoad(t *testing.T) { // Load the latest multistore again and check version. store = newMultiStoreWithMounts(db) err = store.LoadLatestVersion() - assert.Nil(t, err) + require.Nil(t, err) commitID = getExpectedCommitID(store, nCommits) checkStore(t, store, commitID, commitID) @@ -58,7 +58,7 @@ func TestMultistoreCommitLoad(t *testing.T) { ver := nCommits - 1 store = newMultiStoreWithMounts(db) err = store.LoadVersion(ver) - assert.Nil(t, err) + require.Nil(t, err) commitID = getExpectedCommitID(store, ver) checkStore(t, store, commitID, commitID) @@ -71,29 +71,29 @@ func TestMultistoreCommitLoad(t *testing.T) { // LatestVersion store = newMultiStoreWithMounts(db) err = store.LoadLatestVersion() - assert.Nil(t, err) + require.Nil(t, err) commitID = getExpectedCommitID(store, ver+1) checkStore(t, store, commitID, commitID) } func TestParsePath(t *testing.T) { _, _, err := parsePath("foo") - assert.Error(t, err) + require.Error(t, err) store, subpath, err := parsePath("/foo") - assert.NoError(t, err) - assert.Equal(t, store, "foo") - assert.Equal(t, subpath, "") + require.NoError(t, err) + require.Equal(t, store, "foo") + require.Equal(t, subpath, "") store, subpath, err = parsePath("/fizz/bang/baz") - assert.NoError(t, err) - assert.Equal(t, store, "fizz") - assert.Equal(t, subpath, "/bang/baz") + require.NoError(t, err) + require.Equal(t, store, "fizz") + require.Equal(t, subpath, "/bang/baz") substore, subsubpath, err := parsePath(subpath) - assert.NoError(t, err) - assert.Equal(t, substore, "bang") - assert.Equal(t, subsubpath, "/baz") + require.NoError(t, err) + require.Equal(t, substore, "bang") + require.Equal(t, subsubpath, "/baz") } @@ -101,7 +101,7 @@ func TestMultiStoreQuery(t *testing.T) { db := dbm.NewMemDB() multi := newMultiStoreWithMounts(db) err := multi.LoadLatestVersion() - assert.Nil(t, err) + require.Nil(t, err) k, v := []byte("wind"), []byte("blows") k2, v2 := []byte("water"), []byte("flows") @@ -111,7 +111,7 @@ func TestMultiStoreQuery(t *testing.T) { // Make sure we can get by name. garbage := multi.getStoreByName("bad-name") - assert.Nil(t, garbage) + require.Nil(t, garbage) // Set and commit data in one store. store1 := multi.getStoreByName("store1").(KVStore) @@ -128,35 +128,35 @@ func TestMultiStoreQuery(t *testing.T) { // Test bad path. query := abci.RequestQuery{Path: "/key", Data: k, Height: ver} qres := multi.Query(query) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) query.Path = "h897fy32890rf63296r92" qres = multi.Query(query) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) // Test invalid store name. query.Path = "/garbage/key" qres = multi.Query(query) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) // Test valid query with data. query.Path = "/store1/key" qres = multi.Query(query) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) - assert.Equal(t, v, qres.Value) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) + require.Equal(t, v, qres.Value) // Test valid but empty query. query.Path = "/store2/key" query.Prove = true qres = multi.Query(query) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) - assert.Nil(t, qres.Value) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) + require.Nil(t, qres.Value) // Test store2 data. query.Data = k2 qres = multi.Query(query) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) - assert.Equal(t, v2, qres.Value) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) + require.Equal(t, v2, qres.Value) } //----------------------------------------------------------------------- @@ -174,8 +174,8 @@ func newMultiStoreWithMounts(db dbm.DB) *rootMultiStore { } func checkStore(t *testing.T, store *rootMultiStore, expect, got CommitID) { - assert.Equal(t, expect, got) - assert.Equal(t, expect, store.LastCommitID()) + require.Equal(t, expect, got) + require.Equal(t, expect, store.LastCommitID()) } diff --git a/types/coin_test.go b/types/coin_test.go index 5f5c82087b..c7ccc5746c 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -4,11 +4,10 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestIsPositiveCoin(t *testing.T) { - assert := assert.New(t) - cases := []struct { inputOne Coin expected bool @@ -20,13 +19,11 @@ func TestIsPositiveCoin(t *testing.T) { for _, tc := range cases { res := tc.inputOne.IsPositive() - assert.Equal(tc.expected, res) + require.Equal(t, tc.expected, res) } } func TestIsNotNegativeCoin(t *testing.T) { - assert := assert.New(t) - cases := []struct { inputOne Coin expected bool @@ -38,13 +35,11 @@ func TestIsNotNegativeCoin(t *testing.T) { for _, tc := range cases { res := tc.inputOne.IsNotNegative() - assert.Equal(tc.expected, res) + require.Equal(t, tc.expected, res) } } func TestSameDenomAsCoin(t *testing.T) { - assert := assert.New(t) - cases := []struct { inputOne Coin inputTwo Coin @@ -59,13 +54,11 @@ func TestSameDenomAsCoin(t *testing.T) { for _, tc := range cases { res := tc.inputOne.SameDenomAs(tc.inputTwo) - assert.Equal(tc.expected, res) + require.Equal(t, tc.expected, res) } } func TestIsGTECoin(t *testing.T) { - assert := assert.New(t) - cases := []struct { inputOne Coin inputTwo Coin @@ -79,13 +72,11 @@ func TestIsGTECoin(t *testing.T) { for _, tc := range cases { res := tc.inputOne.IsGTE(tc.inputTwo) - assert.Equal(tc.expected, res) + require.Equal(t, tc.expected, res) } } func TestIsEqualCoin(t *testing.T) { - assert := assert.New(t) - cases := []struct { inputOne Coin inputTwo Coin @@ -100,13 +91,11 @@ func TestIsEqualCoin(t *testing.T) { for _, tc := range cases { res := tc.inputOne.IsEqual(tc.inputTwo) - assert.Equal(tc.expected, res) + require.Equal(t, tc.expected, res) } } func TestPlusCoin(t *testing.T) { - assert := assert.New(t) - cases := []struct { inputOne Coin inputTwo Coin @@ -119,7 +108,7 @@ func TestPlusCoin(t *testing.T) { for _, tc := range cases { res := tc.inputOne.Plus(tc.inputTwo) - assert.Equal(tc.expected, res) + require.Equal(t, tc.expected, res) } tc := struct { @@ -128,12 +117,10 @@ func TestPlusCoin(t *testing.T) { expected int64 }{NewCoin("asdf", -1), NewCoin("asdf", 1), 0} res := tc.inputOne.Plus(tc.inputTwo) - assert.Equal(tc.expected, res.Amount.Int64()) + require.Equal(t, tc.expected, res.Amount.Int64()) } func TestMinusCoin(t *testing.T) { - assert := assert.New(t) - cases := []struct { inputOne Coin inputTwo Coin @@ -147,7 +134,7 @@ func TestMinusCoin(t *testing.T) { for _, tc := range cases { res := tc.inputOne.Minus(tc.inputTwo) - assert.Equal(tc.expected, res) + require.Equal(t, tc.expected, res) } tc := struct { @@ -156,7 +143,7 @@ func TestMinusCoin(t *testing.T) { expected int64 }{NewCoin("A", 1), NewCoin("A", 1), 0} res := tc.inputOne.Minus(tc.inputTwo) - assert.Equal(tc.expected, res.Amount.Int64()) + require.Equal(t, tc.expected, res.Amount.Int64()) } @@ -208,8 +195,6 @@ func TestCoins(t *testing.T) { } func TestPlusCoins(t *testing.T) { - assert := assert.New(t) - one := NewInt(1) zero := NewInt(0) negone := NewInt(-1) @@ -229,8 +214,8 @@ func TestPlusCoins(t *testing.T) { for _, tc := range cases { res := tc.inputOne.Plus(tc.inputTwo) - assert.True(res.IsValid()) - assert.Equal(tc.expected, res) + assert.True(t, res.IsValid()) + require.Equal(t, tc.expected, res) } } @@ -260,9 +245,9 @@ func TestParse(t *testing.T) { for _, tc := range cases { res, err := ParseCoins(tc.input) if !tc.valid { - assert.NotNil(t, err, "%s: %#v", tc.input, res) + require.NotNil(t, err, "%s: %#v", tc.input, res) } else if assert.Nil(t, err, "%s: %+v", tc.input, err) { - assert.Equal(t, tc.expected, res) + require.Equal(t, tc.expected, res) } } @@ -312,9 +297,9 @@ func TestSortCoins(t *testing.T) { } for _, tc := range cases { - assert.Equal(t, tc.before, tc.coins.IsValid()) + require.Equal(t, tc.before, tc.coins.IsValid()) tc.coins.Sort() - assert.Equal(t, tc.after, tc.coins.IsValid()) + require.Equal(t, tc.after, tc.coins.IsValid()) } } diff --git a/types/context_test.go b/types/context_test.go index e5b31a9a74..cad2076640 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -3,7 +3,6 @@ package types_test import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tmlibs/db" @@ -72,21 +71,21 @@ func TestCacheContext(t *testing.T) { ctx := defaultContext(key) store := ctx.KVStore(key) store.Set(k1, v1) - assert.Equal(t, v1, store.Get(k1)) - assert.Nil(t, store.Get(k2)) + require.Equal(t, v1, store.Get(k1)) + require.Nil(t, store.Get(k2)) cctx, write := ctx.CacheContext() cstore := cctx.KVStore(key) - assert.Equal(t, v1, cstore.Get(k1)) - assert.Nil(t, cstore.Get(k2)) + require.Equal(t, v1, cstore.Get(k1)) + require.Nil(t, cstore.Get(k2)) cstore.Set(k2, v2) - assert.Equal(t, v2, cstore.Get(k2)) - assert.Nil(t, store.Get(k2)) + require.Equal(t, v2, cstore.Get(k2)) + require.Nil(t, store.Get(k2)) write() - assert.Equal(t, v2, store.Get(k2)) + require.Equal(t, v2, store.Get(k2)) } func TestLogContext(t *testing.T) { diff --git a/types/errors_test.go b/types/errors_test.go index 798eafefcb..959f059d00 100644 --- a/types/errors_test.go +++ b/types/errors_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var codeTypes = []CodeType{ @@ -32,11 +32,11 @@ var errFns = []errFn{ } func TestCodeType(t *testing.T) { - assert.True(t, ABCICodeOK.IsOK()) + require.True(t, ABCICodeOK.IsOK()) for _, c := range codeTypes { msg := CodeToDefaultMsg(c) - assert.False(t, strings.HasPrefix(msg, "Unknown code")) + require.False(t, strings.HasPrefix(msg, "Unknown code")) } } @@ -44,7 +44,7 @@ func TestErrFn(t *testing.T) { for i, errFn := range errFns { err := errFn("") codeType := codeTypes[i] - assert.Equal(t, err.Code(), codeType) - assert.Equal(t, err.Result().Code, ToABCICode(CodespaceRoot, codeType)) + require.Equal(t, err.Code(), codeType) + require.Equal(t, err.Result().Code, ToABCICode(CodespaceRoot, codeType)) } } diff --git a/types/int_test.go b/types/int_test.go index 310325133b..e81bd6d7ed 100644 --- a/types/int_test.go +++ b/types/int_test.go @@ -5,107 +5,107 @@ import ( "math/rand" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestFromInt64(t *testing.T) { for n := 0; n < 20; n++ { r := rand.Int63() - assert.Equal(t, r, NewInt(r).Int64()) + require.Equal(t, r, NewInt(r).Int64()) } } func TestInt(t *testing.T) { // Max Int = 2^255-1 = 5.789e+76 // Min Int = -(2^255-1) = -5.789e+76 - assert.NotPanics(t, func() { NewIntWithDecimal(1, 76) }) + require.NotPanics(t, func() { NewIntWithDecimal(1, 76) }) i1 := NewIntWithDecimal(1, 76) - assert.NotPanics(t, func() { NewIntWithDecimal(2, 76) }) + require.NotPanics(t, func() { NewIntWithDecimal(2, 76) }) i2 := NewIntWithDecimal(2, 76) - assert.NotPanics(t, func() { NewIntWithDecimal(3, 76) }) + require.NotPanics(t, func() { NewIntWithDecimal(3, 76) }) i3 := NewIntWithDecimal(3, 76) - assert.Panics(t, func() { NewIntWithDecimal(6, 76) }) - assert.Panics(t, func() { NewIntWithDecimal(9, 80) }) + require.Panics(t, func() { NewIntWithDecimal(6, 76) }) + require.Panics(t, func() { NewIntWithDecimal(9, 80) }) // Overflow check - assert.NotPanics(t, func() { i1.Add(i1) }) - assert.NotPanics(t, func() { i2.Add(i2) }) - assert.Panics(t, func() { i3.Add(i3) }) + require.NotPanics(t, func() { i1.Add(i1) }) + require.NotPanics(t, func() { i2.Add(i2) }) + require.Panics(t, func() { i3.Add(i3) }) - assert.NotPanics(t, func() { i1.Sub(i1.Neg()) }) - assert.NotPanics(t, func() { i2.Sub(i2.Neg()) }) - assert.Panics(t, func() { i3.Sub(i3.Neg()) }) + require.NotPanics(t, func() { i1.Sub(i1.Neg()) }) + require.NotPanics(t, func() { i2.Sub(i2.Neg()) }) + require.Panics(t, func() { i3.Sub(i3.Neg()) }) - assert.Panics(t, func() { i1.Mul(i1) }) - assert.Panics(t, func() { i2.Mul(i2) }) - assert.Panics(t, func() { i3.Mul(i3) }) + require.Panics(t, func() { i1.Mul(i1) }) + require.Panics(t, func() { i2.Mul(i2) }) + require.Panics(t, func() { i3.Mul(i3) }) - assert.Panics(t, func() { i1.Neg().Mul(i1.Neg()) }) - assert.Panics(t, func() { i2.Neg().Mul(i2.Neg()) }) - assert.Panics(t, func() { i3.Neg().Mul(i3.Neg()) }) + require.Panics(t, func() { i1.Neg().Mul(i1.Neg()) }) + require.Panics(t, func() { i2.Neg().Mul(i2.Neg()) }) + require.Panics(t, func() { i3.Neg().Mul(i3.Neg()) }) // Underflow check i3n := i3.Neg() - assert.NotPanics(t, func() { i3n.Sub(i1) }) - assert.NotPanics(t, func() { i3n.Sub(i2) }) - assert.Panics(t, func() { i3n.Sub(i3) }) + require.NotPanics(t, func() { i3n.Sub(i1) }) + require.NotPanics(t, func() { i3n.Sub(i2) }) + require.Panics(t, func() { i3n.Sub(i3) }) - assert.NotPanics(t, func() { i3n.Add(i1.Neg()) }) - assert.NotPanics(t, func() { i3n.Add(i2.Neg()) }) - assert.Panics(t, func() { i3n.Add(i3.Neg()) }) + require.NotPanics(t, func() { i3n.Add(i1.Neg()) }) + require.NotPanics(t, func() { i3n.Add(i2.Neg()) }) + require.Panics(t, func() { i3n.Add(i3.Neg()) }) - assert.Panics(t, func() { i1.Mul(i1.Neg()) }) - assert.Panics(t, func() { i2.Mul(i2.Neg()) }) - assert.Panics(t, func() { i3.Mul(i3.Neg()) }) + require.Panics(t, func() { i1.Mul(i1.Neg()) }) + require.Panics(t, func() { i2.Mul(i2.Neg()) }) + require.Panics(t, func() { i3.Mul(i3.Neg()) }) // Bound check intmax := NewIntFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(255), nil), big.NewInt(1))) intmin := intmax.Neg() - assert.NotPanics(t, func() { intmax.Add(ZeroInt()) }) - assert.NotPanics(t, func() { intmin.Sub(ZeroInt()) }) - assert.Panics(t, func() { intmax.Add(OneInt()) }) - assert.Panics(t, func() { intmin.Sub(OneInt()) }) + require.NotPanics(t, func() { intmax.Add(ZeroInt()) }) + require.NotPanics(t, func() { intmin.Sub(ZeroInt()) }) + require.Panics(t, func() { intmax.Add(OneInt()) }) + require.Panics(t, func() { intmin.Sub(OneInt()) }) // Division-by-zero check - assert.Panics(t, func() { i1.Div(NewInt(0)) }) + require.Panics(t, func() { i1.Div(NewInt(0)) }) } func TestUint(t *testing.T) { // Max Uint = 1.15e+77 // Min Uint = 0 - assert.NotPanics(t, func() { NewUintWithDecimal(5, 76) }) + require.NotPanics(t, func() { NewUintWithDecimal(5, 76) }) i1 := NewUintWithDecimal(5, 76) - assert.NotPanics(t, func() { NewUintWithDecimal(10, 76) }) + require.NotPanics(t, func() { NewUintWithDecimal(10, 76) }) i2 := NewUintWithDecimal(10, 76) - assert.NotPanics(t, func() { NewUintWithDecimal(11, 76) }) + require.NotPanics(t, func() { NewUintWithDecimal(11, 76) }) i3 := NewUintWithDecimal(11, 76) - assert.Panics(t, func() { NewUintWithDecimal(12, 76) }) - assert.Panics(t, func() { NewUintWithDecimal(1, 80) }) + require.Panics(t, func() { NewUintWithDecimal(12, 76) }) + require.Panics(t, func() { NewUintWithDecimal(1, 80) }) // Overflow check - assert.NotPanics(t, func() { i1.Add(i1) }) - assert.Panics(t, func() { i2.Add(i2) }) - assert.Panics(t, func() { i3.Add(i3) }) + require.NotPanics(t, func() { i1.Add(i1) }) + require.Panics(t, func() { i2.Add(i2) }) + require.Panics(t, func() { i3.Add(i3) }) - assert.Panics(t, func() { i1.Mul(i1) }) - assert.Panics(t, func() { i2.Mul(i2) }) - assert.Panics(t, func() { i3.Mul(i3) }) + require.Panics(t, func() { i1.Mul(i1) }) + require.Panics(t, func() { i2.Mul(i2) }) + require.Panics(t, func() { i3.Mul(i3) }) // Underflow check - assert.NotPanics(t, func() { i2.Sub(i1) }) - assert.NotPanics(t, func() { i2.Sub(i2) }) - assert.Panics(t, func() { i2.Sub(i3) }) + require.NotPanics(t, func() { i2.Sub(i1) }) + require.NotPanics(t, func() { i2.Sub(i2) }) + require.Panics(t, func() { i2.Sub(i3) }) // Bound check uintmax := NewUintFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))) uintmin := NewUint(0) - assert.NotPanics(t, func() { uintmax.Add(ZeroUint()) }) - assert.NotPanics(t, func() { uintmin.Sub(ZeroUint()) }) - assert.Panics(t, func() { uintmax.Add(OneUint()) }) - assert.Panics(t, func() { uintmin.Sub(OneUint()) }) + require.NotPanics(t, func() { uintmax.Add(ZeroUint()) }) + require.NotPanics(t, func() { uintmin.Sub(ZeroUint()) }) + require.Panics(t, func() { uintmax.Add(OneUint()) }) + require.Panics(t, func() { uintmin.Sub(OneUint()) }) // Division-by-zero check - assert.Panics(t, func() { i1.Div(uintmin) }) + require.Panics(t, func() { i1.Div(uintmin) }) } diff --git a/types/lib/linear_test.go b/types/lib/linear_test.go index 8ee3276b5a..8b5a63fd41 100644 --- a/types/lib/linear_test.go +++ b/types/lib/linear_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -41,30 +41,30 @@ func TestList(t *testing.T) { var res S lm.Push(val) - assert.Equal(t, uint64(1), lm.Len()) + require.Equal(t, uint64(1), lm.Len()) lm.Get(uint64(0), &res) - assert.Equal(t, val, res) + require.Equal(t, val, res) val = S{2, false} lm.Set(uint64(0), val) lm.Get(uint64(0), &res) - assert.Equal(t, val, res) + require.Equal(t, val, res) val = S{100, false} lm.Push(val) - assert.Equal(t, uint64(2), lm.Len()) + require.Equal(t, uint64(2), lm.Len()) lm.Get(uint64(1), &res) - assert.Equal(t, val, res) + require.Equal(t, val, res) lm.Delete(uint64(1)) - assert.Equal(t, uint64(2), lm.Len()) + require.Equal(t, uint64(2), lm.Len()) lm.Iterate(&res, func(index uint64) (brk bool) { var temp S lm.Get(index, &temp) - assert.Equal(t, temp, res) + require.Equal(t, temp, res) - assert.True(t, index != 1) + require.True(t, index != 1) return }) @@ -74,7 +74,7 @@ func TestList(t *testing.T) { }) lm.Get(uint64(0), &res) - assert.Equal(t, S{3, true}, res) + require.Equal(t, S{3, true}, res) } func TestQueue(t *testing.T) { @@ -89,13 +89,13 @@ func TestQueue(t *testing.T) { qm.Push(val) qm.Peek(&res) - assert.Equal(t, val, res) + require.Equal(t, val, res) qm.Pop() empty := qm.IsEmpty() - assert.True(t, empty) - assert.NotNil(t, qm.Peek(&res)) + require.True(t, empty) + require.NotNil(t, qm.Peek(&res)) qm.Push(S{1, true}) qm.Push(S{2, true}) @@ -107,10 +107,10 @@ func TestQueue(t *testing.T) { return }) - assert.False(t, qm.IsEmpty()) + require.False(t, qm.IsEmpty()) qm.Pop() - assert.True(t, qm.IsEmpty()) + require.True(t, qm.IsEmpty()) } func TestOptions(t *testing.T) { @@ -136,22 +136,22 @@ func TestOptions(t *testing.T) { // Checking keys.LengthKey err := cdc.UnmarshalBinary(store.Get(keys.LengthKey), &len) - assert.Nil(t, err) - assert.Equal(t, len, linear.Len()) + require.Nil(t, err) + require.Equal(t, len, linear.Len()) // Checking keys.ElemKey for i := 0; i < 10; i++ { linear.Get(uint64(i), &expected) bz := store.Get(append(keys.ElemKey, []byte(fmt.Sprintf("%020d", i))...)) err = cdc.UnmarshalBinary(bz, &actual) - assert.Nil(t, err) - assert.Equal(t, expected, actual) + require.Nil(t, err) + require.Equal(t, expected, actual) } linear.Pop() err = cdc.UnmarshalBinary(store.Get(keys.TopKey), &top) - assert.Nil(t, err) - assert.Equal(t, top, linear.getTop()) + require.Nil(t, err) + require.Equal(t, top, linear.getTop()) } diff --git a/types/rational_test.go b/types/rational_test.go index a137ca498e..db875c83e8 100644 --- a/types/rational_test.go +++ b/types/rational_test.go @@ -5,19 +5,18 @@ import ( "testing" wire "github.com/cosmos/cosmos-sdk/wire" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNew(t *testing.T) { - assert.Equal(t, NewRat(1), NewRat(1, 1)) - assert.Equal(t, NewRat(100), NewRat(100, 1)) - assert.Equal(t, NewRat(-1), NewRat(-1, 1)) - assert.Equal(t, NewRat(-100), NewRat(-100, 1)) - assert.Equal(t, NewRat(0), NewRat(0, 1)) + require.Equal(t, NewRat(1), NewRat(1, 1)) + require.Equal(t, NewRat(100), NewRat(100, 1)) + require.Equal(t, NewRat(-1), NewRat(-1, 1)) + require.Equal(t, NewRat(-100), NewRat(-100, 1)) + require.Equal(t, NewRat(0), NewRat(0, 1)) // do not allow for more than 2 variables - assert.Panics(t, func() { NewRat(1, 1, 1) }) + require.Panics(t, func() { NewRat(1, 1, 1) }) } func TestNewFromDecimal(t *testing.T) { @@ -51,7 +50,7 @@ func TestNewFromDecimal(t *testing.T) { for _, tc := range tests { res, err := NewRatFromDecimal(tc.decimalStr, 4) if tc.expErr { - assert.NotNil(t, err, tc.decimalStr) + require.NotNil(t, err, tc.decimalStr) } else { require.Nil(t, err, tc.decimalStr) require.True(t, res.Equal(tc.exp), tc.decimalStr) @@ -60,10 +59,10 @@ func TestNewFromDecimal(t *testing.T) { // negative tc res, err = NewRatFromDecimal("-"+tc.decimalStr, 4) if tc.expErr { - assert.NotNil(t, err, tc.decimalStr) + require.NotNil(t, err, tc.decimalStr) } else { - assert.Nil(t, err, tc.decimalStr) - assert.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr) + require.Nil(t, err, tc.decimalStr) + require.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr) } } } @@ -100,9 +99,9 @@ func TestEqualities(t *testing.T) { } for _, tc := range tests { - assert.Equal(t, tc.gt, tc.r1.GT(tc.r2)) - assert.Equal(t, tc.lt, tc.r1.LT(tc.r2)) - assert.Equal(t, tc.eq, tc.r1.Equal(tc.r2)) + require.Equal(t, tc.gt, tc.r1.GT(tc.r2)) + require.Equal(t, tc.lt, tc.r1.LT(tc.r2)) + require.Equal(t, tc.eq, tc.r1.Equal(tc.r2)) } } @@ -136,14 +135,14 @@ func TestArithmetic(t *testing.T) { } for _, tc := range tests { - assert.True(t, tc.resMul.Equal(tc.r1.Mul(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) - assert.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) - assert.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) + require.True(t, tc.resMul.Equal(tc.r1.Mul(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) + require.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) + require.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) if tc.r2.Num().IsZero() { // panic for divide by zero - assert.Panics(t, func() { tc.r1.Quo(tc.r2) }) + require.Panics(t, func() { tc.r1.Quo(tc.r2) }) } else { - assert.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) + require.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat) } } } @@ -169,8 +168,8 @@ func TestEvaluate(t *testing.T) { } for _, tc := range tests { - assert.Equal(t, tc.res, tc.r1.Evaluate(), "%v", tc.r1) - assert.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).Evaluate(), "%v", tc.r1.Mul(NewRat(-1))) + require.Equal(t, tc.res, tc.r1.Evaluate(), "%v", tc.r1) + require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).Evaluate(), "%v", tc.r1.Mul(NewRat(-1))) } } @@ -193,9 +192,9 @@ func TestRound(t *testing.T) { } for _, tc := range tests { - assert.Equal(t, tc.res, tc.r.Round(tc.precFactor), "%v", tc.r) + require.Equal(t, tc.res, tc.r.Round(tc.precFactor), "%v", tc.r) negR1, negRes := tc.r.Mul(NewRat(-1)), tc.res.Mul(NewRat(-1)) - assert.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1) + require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1) } } @@ -212,7 +211,7 @@ func TestToLeftPadded(t *testing.T) { {NewRat(1000, 3), 12, "000000000333"}, } for _, tc := range tests { - assert.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits)) + require.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits)) } } @@ -221,13 +220,13 @@ var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec func TestZeroSerializationJSON(t *testing.T) { r := NewRat(0, 1) err := cdc.UnmarshalJSON([]byte(`"0/1"`), &r) - assert.Nil(t, err) + require.Nil(t, err) err = cdc.UnmarshalJSON([]byte(`"0/0"`), &r) - assert.NotNil(t, err) + require.NotNil(t, err) err = cdc.UnmarshalJSON([]byte(`"1/0"`), &r) - assert.NotNil(t, err) + require.NotNil(t, err) err = cdc.UnmarshalJSON([]byte(`"{}"`), &r) - assert.NotNil(t, err) + require.NotNil(t, err) } func TestSerializationText(t *testing.T) { @@ -239,7 +238,7 @@ func TestSerializationText(t *testing.T) { var r2 = Rat{new(big.Rat)} err = r2.UnmarshalText(bz) require.NoError(t, err) - assert.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) + require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) } func TestSerializationGoWireJSON(t *testing.T) { @@ -250,7 +249,7 @@ func TestSerializationGoWireJSON(t *testing.T) { var r2 Rat err = cdc.UnmarshalJSON(bz, &r2) require.NoError(t, err) - assert.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) + require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) } func TestSerializationGoWireBinary(t *testing.T) { @@ -261,7 +260,7 @@ func TestSerializationGoWireBinary(t *testing.T) { var r2 Rat err = cdc.UnmarshalBinary(bz, &r2) require.NoError(t, err) - assert.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) + require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2) } type testEmbedStruct struct { @@ -279,9 +278,9 @@ func TestEmbeddedStructSerializationGoWire(t *testing.T) { err = cdc.UnmarshalJSON(bz, &obj2) require.Nil(t, err) - assert.Equal(t, obj.Field1, obj2.Field1) - assert.Equal(t, obj.Field2, obj2.Field2) - assert.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) + require.Equal(t, obj.Field1, obj2.Field1) + require.Equal(t, obj.Field2, obj2.Field2) + require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) } func TestRatsEqual(t *testing.T) { @@ -299,8 +298,8 @@ func TestRatsEqual(t *testing.T) { } for _, tc := range tests { - assert.Equal(t, tc.eq, RatsEqual(tc.r1s, tc.r2s)) - assert.Equal(t, tc.eq, RatsEqual(tc.r2s, tc.r1s)) + require.Equal(t, tc.eq, RatsEqual(tc.r1s, tc.r2s)) + require.Equal(t, tc.eq, RatsEqual(tc.r2s, tc.r1s)) } } @@ -310,7 +309,7 @@ func TestStringOverflow(t *testing.T) { rat1 := NewRat(5164315003622678713, 4389711697696177267) rat2 := NewRat(-3179849666053572961, 8459429845579852627) rat3 := rat1.Add(rat2) - assert.Equal(t, + require.Equal(t, "29728537197630860939575850336935951464/37134458148982045574552091851127630409", rat3.String(), ) diff --git a/types/store_test.go b/types/store_test.go index 43dd1f5d3f..f376f3be1e 100644 --- a/types/store_test.go +++ b/types/store_test.go @@ -3,12 +3,10 @@ package types import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestPrefixEndBytes(t *testing.T) { - assert := assert.New(t) - var testCases = []struct { prefix []byte expected []byte @@ -24,6 +22,6 @@ func TestPrefixEndBytes(t *testing.T) { for _, test := range testCases { end := PrefixEndBytes(test.prefix) - assert.Equal(test.expected, end) + require.Equal(t, test.expected, end) } } diff --git a/x/auth/account_test.go b/x/auth/account_test.go index 55cef7cda5..bc7a195097 100644 --- a/x/auth/account_test.go +++ b/x/auth/account_test.go @@ -3,7 +3,7 @@ package auth import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" @@ -24,31 +24,31 @@ func TestBaseAddressPubKey(t *testing.T) { acc := NewBaseAccountWithAddress(addr1) // check the address (set) and pubkey (not set) - assert.EqualValues(t, addr1, acc.GetAddress()) - assert.EqualValues(t, nil, acc.GetPubKey()) + require.EqualValues(t, addr1, acc.GetAddress()) + require.EqualValues(t, nil, acc.GetPubKey()) // can't override address err := acc.SetAddress(addr2) - assert.NotNil(t, err) - assert.EqualValues(t, addr1, acc.GetAddress()) + require.NotNil(t, err) + require.EqualValues(t, addr1, acc.GetAddress()) // set the pubkey err = acc.SetPubKey(pub1) - assert.Nil(t, err) - assert.Equal(t, pub1, acc.GetPubKey()) + require.Nil(t, err) + require.Equal(t, pub1, acc.GetPubKey()) // can override pubkey err = acc.SetPubKey(pub2) - assert.Nil(t, err) - assert.Equal(t, pub2, acc.GetPubKey()) + require.Nil(t, err) + require.Equal(t, pub2, acc.GetPubKey()) //------------------------------------ // can set address on empty account acc2 := BaseAccount{} err = acc2.SetAddress(addr2) - assert.Nil(t, err) - assert.EqualValues(t, addr2, acc2.GetAddress()) + require.Nil(t, err) + require.EqualValues(t, addr2, acc2.GetAddress()) } func TestBaseAccountCoins(t *testing.T) { @@ -58,8 +58,8 @@ func TestBaseAccountCoins(t *testing.T) { someCoins := sdk.Coins{sdk.NewCoin("atom", 123), sdk.NewCoin("eth", 246)} err := acc.SetCoins(someCoins) - assert.Nil(t, err) - assert.Equal(t, someCoins, acc.GetCoins()) + require.Nil(t, err) + require.Equal(t, someCoins, acc.GetCoins()) } func TestBaseAccountSequence(t *testing.T) { @@ -69,8 +69,8 @@ func TestBaseAccountSequence(t *testing.T) { seq := int64(7) err := acc.SetSequence(seq) - assert.Nil(t, err) - assert.Equal(t, seq, acc.GetSequence()) + require.Nil(t, err) + require.Equal(t, seq, acc.GetSequence()) } func TestBaseAccountMarshal(t *testing.T) { @@ -82,27 +82,27 @@ func TestBaseAccountMarshal(t *testing.T) { // set everything on the account err := acc.SetPubKey(pub) - assert.Nil(t, err) + require.Nil(t, err) err = acc.SetSequence(seq) - assert.Nil(t, err) + require.Nil(t, err) err = acc.SetCoins(someCoins) - assert.Nil(t, err) + require.Nil(t, err) // need a codec for marshaling codec := wire.NewCodec() wire.RegisterCrypto(codec) b, err := codec.MarshalBinary(acc) - assert.Nil(t, err) + require.Nil(t, err) acc2 := BaseAccount{} err = codec.UnmarshalBinary(b, &acc2) - assert.Nil(t, err) - assert.Equal(t, acc, acc2) + require.Nil(t, err) + require.Equal(t, acc, acc2) // error on bad bytes acc2 = BaseAccount{} err = codec.UnmarshalBinary(b[:len(b)/2], &acc2) - assert.NotNil(t, err) + require.NotNil(t, err) } diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index 2ddb96872e..1808afc99c 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -4,7 +4,6 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" @@ -41,9 +40,9 @@ func privAndAddr() (crypto.PrivKey, sdk.Address) { // run the tx through the anteHandler and ensure its valid func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx) { _, result, abort := anteHandler(ctx, tx) - assert.False(t, abort) - assert.Equal(t, sdk.ABCICodeOK, result.Code) - assert.True(t, result.IsOK()) + require.False(t, abort) + require.Equal(t, sdk.ABCICodeOK, result.Code) + require.True(t, result.IsOK()) } // run the tx through the anteHandler and ensure it fails with the given code @@ -52,7 +51,7 @@ func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, if r := recover(); r != nil { switch r.(type) { case sdk.ErrorOutOfGas: - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOutOfGas), + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOutOfGas), fmt.Sprintf("Expected ErrorOutOfGas, got %v", r)) default: panic(r) @@ -60,8 +59,8 @@ func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, } }() _, result, abort := anteHandler(ctx, tx) - assert.True(t, abort) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code, + require.True(t, abort) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code, fmt.Sprintf("Expected %v, got %v", sdk.ToABCICode(sdk.CodespaceRoot, code), result)) } @@ -138,7 +137,7 @@ func TestAnteHandlerSigErrors(t *testing.T) { // tx.GetSigners returns addresses in correct order: addr1, addr2, addr3 expectedSigners := []sdk.Address{addr1, addr2, addr3} stdTx := tx.(StdTx) - assert.Equal(t, expectedSigners, stdTx.GetSigners()) + require.Equal(t, expectedSigners, stdTx.GetSigners()) // Check no signatures fails checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized) @@ -330,13 +329,13 @@ func TestAnteHandlerFees(t *testing.T) { mapper.SetAccount(ctx, acc1) checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInsufficientFunds) - assert.True(t, feeCollector.GetCollectedFees(ctx).IsEqual(emptyCoins)) + require.True(t, feeCollector.GetCollectedFees(ctx).IsEqual(emptyCoins)) acc1.SetCoins(sdk.Coins{sdk.NewCoin("atom", 150)}) mapper.SetAccount(ctx, acc1) checkValidTx(t, anteHandler, ctx, tx) - assert.True(t, feeCollector.GetCollectedFees(ctx).IsEqual(sdk.Coins{sdk.NewCoin("atom", 150)})) + require.True(t, feeCollector.GetCollectedFees(ctx).IsEqual(sdk.Coins{sdk.NewCoin("atom", 150)})) } // Test logic around memo gas consumption. @@ -559,12 +558,12 @@ func TestAnteHandlerSetPubKey(t *testing.T) { checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey) acc2 = mapper.GetAccount(ctx, addr2) - assert.Nil(t, acc2.GetPubKey()) + require.Nil(t, acc2.GetPubKey()) // test invalid signature and public key tx = newTestTx(ctx, msgs, privs, []int64{1}, seqs, fee) checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey) acc2 = mapper.GetAccount(ctx, addr2) - assert.Nil(t, acc2.GetPubKey()) + require.Nil(t, acc2.GetPubKey()) } diff --git a/x/auth/context_test.go b/x/auth/context_test.go index 53ff7b1db6..5f432be357 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -3,7 +3,7 @@ package auth import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tmlibs/log" @@ -24,17 +24,17 @@ func TestContextWithSigners(t *testing.T) { // new ctx has no signers signers := GetSigners(ctx) - assert.Equal(t, 0, len(signers)) + require.Equal(t, 0, len(signers)) ctx2 := WithSigners(ctx, []Account{&acc1, &acc2}) // original context is unchanged signers = GetSigners(ctx) - assert.Equal(t, 0, len(signers)) + require.Equal(t, 0, len(signers)) // new context has signers signers = GetSigners(ctx2) - assert.Equal(t, 2, len(signers)) - assert.Equal(t, acc1, *(signers[0].(*BaseAccount))) - assert.Equal(t, acc2, *(signers[1].(*BaseAccount))) + require.Equal(t, 2, len(signers)) + require.Equal(t, acc1, *(signers[0].(*BaseAccount))) + require.Equal(t, acc2, *(signers[1].(*BaseAccount))) } diff --git a/x/auth/feekeeper_test.go b/x/auth/feekeeper_test.go index a6ce8e3e5a..e935bb4c49 100644 --- a/x/auth/feekeeper_test.go +++ b/x/auth/feekeeper_test.go @@ -3,7 +3,7 @@ package auth import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tmlibs/log" @@ -28,13 +28,13 @@ func TestFeeCollectionKeeperGetSet(t *testing.T) { // no coins initially currFees := fck.GetCollectedFees(ctx) - assert.True(t, currFees.IsEqual(emptyCoins)) + require.True(t, currFees.IsEqual(emptyCoins)) // set feeCollection to oneCoin fck.setCollectedFees(ctx, oneCoin) // check that it is equal to oneCoin - assert.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin)) + require.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin)) } func TestFeeCollectionKeeperAdd(t *testing.T) { @@ -46,15 +46,15 @@ func TestFeeCollectionKeeperAdd(t *testing.T) { fck := NewFeeCollectionKeeper(cdc, capKey2) // no coins initially - assert.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins)) + require.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins)) // add oneCoin and check that pool is now oneCoin fck.addCollectedFees(ctx, oneCoin) - assert.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin)) + require.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin)) // add oneCoin again and check that pool is now twoCoins fck.addCollectedFees(ctx, oneCoin) - assert.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins)) + require.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins)) } func TestFeeCollectionKeeperClear(t *testing.T) { @@ -67,9 +67,9 @@ func TestFeeCollectionKeeperClear(t *testing.T) { // set coins initially fck.setCollectedFees(ctx, twoCoins) - assert.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins)) + require.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins)) // clear fees and see that pool is now empty fck.ClearCollectedFees(ctx) - assert.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins)) + require.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins)) } diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index a5f96d5e90..4b270f0225 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -3,7 +3,7 @@ package auth import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" @@ -38,17 +38,17 @@ func TestAccountMapperGetSet(t *testing.T) { // no account before its created acc := mapper.GetAccount(ctx, addr) - assert.Nil(t, acc) + require.Nil(t, acc) // create account and check default values acc = mapper.NewAccountWithAddress(ctx, addr) - assert.NotNil(t, acc) - assert.Equal(t, addr, acc.GetAddress()) - assert.EqualValues(t, nil, acc.GetPubKey()) - assert.EqualValues(t, 0, acc.GetSequence()) + require.NotNil(t, acc) + require.Equal(t, addr, acc.GetAddress()) + require.EqualValues(t, nil, acc.GetPubKey()) + require.EqualValues(t, 0, acc.GetSequence()) // NewAccount doesn't call Set, so it's still nil - assert.Nil(t, mapper.GetAccount(ctx, addr)) + require.Nil(t, mapper.GetAccount(ctx, addr)) // set some values on the account and save it newSequence := int64(20) @@ -57,6 +57,6 @@ func TestAccountMapperGetSet(t *testing.T) { // check the new values acc = mapper.GetAccount(ctx, addr) - assert.NotNil(t, acc) - assert.Equal(t, newSequence, acc.GetSequence()) + require.NotNil(t, acc) + require.Equal(t, newSequence, acc.GetSequence()) } diff --git a/x/auth/mock/auth_app_test.go b/x/auth/mock/auth_app_test.go index 0a7a03534d..3f340bbf90 100644 --- a/x/auth/mock/auth_app_test.go +++ b/x/auth/mock/auth_app_test.go @@ -3,7 +3,6 @@ package mock import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -75,7 +74,7 @@ func TestMsgPrivKeys(t *testing.T) { // A checkTx context (true) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) - assert.Equal(t, acc1, res1.(*auth.BaseAccount)) + require.Equal(t, acc1, res1.(*auth.BaseAccount)) // Run a CheckDeliver SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{0}, true, priv1) @@ -84,10 +83,10 @@ func TestMsgPrivKeys(t *testing.T) { mapp.BeginBlock(abci.RequestBeginBlock{}) tx := GenTx([]sdk.Msg{testMsg1}, []int64{0}, []int64{1}, priv2) res := mapp.Deliver(tx) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) // resigning the tx with the correct priv key should still work res = SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{1}, true, priv1) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), res.Code, res.Log) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), res.Code, res.Log) } diff --git a/x/auth/mock/simulate_block.go b/x/auth/mock/simulate_block.go index a047fbf4b6..f85fdf1803 100644 --- a/x/auth/mock/simulate_block.go +++ b/x/auth/mock/simulate_block.go @@ -6,7 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" @@ -29,7 +28,7 @@ func SetGenesis(app *App, accs []auth.Account) { func CheckBalance(t *testing.T, app *App, addr sdk.Address, exp sdk.Coins) { ctxCheck := app.BaseApp.NewContext(true, abci.Header{}) res := app.AccountMapper.GetAccount(ctxCheck, addr) - assert.Equal(t, exp, res.GetCoins()) + require.Equal(t, exp, res.GetCoins()) } // generate a signed transaction diff --git a/x/auth/stdtx_test.go b/x/auth/stdtx_test.go index 43712e5a5e..533596431a 100644 --- a/x/auth/stdtx_test.go +++ b/x/auth/stdtx_test.go @@ -3,7 +3,7 @@ package auth import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" @@ -24,9 +24,9 @@ func TestStdTx(t *testing.T) { sigs := []StdSignature{} tx := NewStdTx(msgs, fee, sigs, "") - assert.Equal(t, msgs, tx.GetMsgs()) - assert.Equal(t, sigs, tx.GetSignatures()) + require.Equal(t, msgs, tx.GetMsgs()) + require.Equal(t, sigs, tx.GetSignatures()) feePayer := FeePayer(tx) - assert.Equal(t, addr, feePayer) + require.Equal(t, addr, feePayer) } diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 2d6efc3ca1..72ea312a9a 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -3,7 +3,6 @@ package bank import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -112,7 +111,7 @@ func TestMsgSendWithAccounts(t *testing.T) { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) require.NotNil(t, res1) - assert.Equal(t, acc, res1.(*auth.BaseAccount)) + require.Equal(t, acc, res1.(*auth.BaseAccount)) // Run a CheckDeliver mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1}, []int64{0}, []int64{0}, true, priv1) @@ -130,7 +129,7 @@ func TestMsgSendWithAccounts(t *testing.T) { tx.Signatures[0].Sequence = 1 res := mapp.Deliver(tx) - assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) + require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) // resigning the tx with the bumped sequence should work mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1, sendMsg2}, []int64{0}, []int64{1}, true, priv1) diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index 2eae4e815c..b35298be9d 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" @@ -42,57 +43,57 @@ func TestKeeper(t *testing.T) { // Test GetCoins/SetCoins accountMapper.SetAccount(ctx, acc) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) coinKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) // Test HasCoins - assert.True(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)})) - assert.True(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 5)})) - assert.False(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 15)})) - assert.False(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 5)})) + require.True(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 5)})) + require.False(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 15)})) + require.False(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 5)})) // Test AddCoins coinKeeper.AddCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 15)}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 25)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 25)})) coinKeeper.AddCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 15)}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 15), sdk.NewCoin("foocoin", 25)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 15), sdk.NewCoin("foocoin", 25)})) // Test SubtractCoins coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)}) coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 5)}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 15)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 15)})) coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 11)}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 15)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 15)})) coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 10)}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 15)})) - assert.False(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 1)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 15)})) + require.False(t, coinKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 1)})) // Test SendCoins coinKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.NewCoin("foocoin", 5)}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) - assert.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 5)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 5)})) _, err2 := coinKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.NewCoin("foocoin", 50)}) assert.Implements(t, (*sdk.Error)(nil), err2) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) - assert.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 5)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 5)})) coinKeeper.AddCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 30)}) coinKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 5)}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 20), sdk.NewCoin("foocoin", 5)})) - assert.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 10)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 20), sdk.NewCoin("foocoin", 5)})) + require.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 10)})) // Test InputOutputCoins input1 := NewInput(addr2, sdk.Coins{sdk.NewCoin("foocoin", 2)}) output1 := NewOutput(addr, sdk.Coins{sdk.NewCoin("foocoin", 2)}) coinKeeper.InputOutputCoins(ctx, []Input{input1}, []Output{output1}) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 20), sdk.NewCoin("foocoin", 7)})) - assert.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 8)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 20), sdk.NewCoin("foocoin", 7)})) + require.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 8)})) inputs := []Input{ NewInput(addr, sdk.Coins{sdk.NewCoin("foocoin", 3)}), @@ -104,9 +105,9 @@ func TestKeeper(t *testing.T) { NewOutput(addr3, sdk.Coins{sdk.NewCoin("barcoin", 2), sdk.NewCoin("foocoin", 5)}), } coinKeeper.InputOutputCoins(ctx, inputs, outputs) - assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 21), sdk.NewCoin("foocoin", 4)})) - assert.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 7), sdk.NewCoin("foocoin", 6)})) - assert.True(t, coinKeeper.GetCoins(ctx, addr3).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 2), sdk.NewCoin("foocoin", 5)})) + require.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 21), sdk.NewCoin("foocoin", 4)})) + require.True(t, coinKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 7), sdk.NewCoin("foocoin", 6)})) + require.True(t, coinKeeper.GetCoins(ctx, addr3).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 2), sdk.NewCoin("foocoin", 5)})) } @@ -128,40 +129,40 @@ func TestSendKeeper(t *testing.T) { // Test GetCoins/SetCoins accountMapper.SetAccount(ctx, acc) - assert.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) + require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) coinKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)}) - assert.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) // Test HasCoins - assert.True(t, sendKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)})) - assert.True(t, sendKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 5)})) - assert.False(t, sendKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 15)})) - assert.False(t, sendKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 5)})) + require.True(t, sendKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, sendKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 5)})) + require.False(t, sendKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 15)})) + require.False(t, sendKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 5)})) coinKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 15)}) // Test SendCoins sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.NewCoin("foocoin", 5)}) - assert.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) - assert.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 5)})) + require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 5)})) _, err2 := sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.NewCoin("foocoin", 50)}) assert.Implements(t, (*sdk.Error)(nil), err2) - assert.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) - assert.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 5)})) + require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 5)})) coinKeeper.AddCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 30)}) sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 5)}) - assert.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 20), sdk.NewCoin("foocoin", 5)})) - assert.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 10)})) + require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 20), sdk.NewCoin("foocoin", 5)})) + require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 10)})) // Test InputOutputCoins input1 := NewInput(addr2, sdk.Coins{sdk.NewCoin("foocoin", 2)}) output1 := NewOutput(addr, sdk.Coins{sdk.NewCoin("foocoin", 2)}) sendKeeper.InputOutputCoins(ctx, []Input{input1}, []Output{output1}) - assert.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 20), sdk.NewCoin("foocoin", 7)})) - assert.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 8)})) + require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 20), sdk.NewCoin("foocoin", 7)})) + require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 10), sdk.NewCoin("foocoin", 8)})) inputs := []Input{ NewInput(addr, sdk.Coins{sdk.NewCoin("foocoin", 3)}), @@ -173,9 +174,9 @@ func TestSendKeeper(t *testing.T) { NewOutput(addr3, sdk.Coins{sdk.NewCoin("barcoin", 2), sdk.NewCoin("foocoin", 5)}), } sendKeeper.InputOutputCoins(ctx, inputs, outputs) - assert.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 21), sdk.NewCoin("foocoin", 4)})) - assert.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 7), sdk.NewCoin("foocoin", 6)})) - assert.True(t, sendKeeper.GetCoins(ctx, addr3).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 2), sdk.NewCoin("foocoin", 5)})) + require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 21), sdk.NewCoin("foocoin", 4)})) + require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 7), sdk.NewCoin("foocoin", 6)})) + require.True(t, sendKeeper.GetCoins(ctx, addr3).IsEqual(sdk.Coins{sdk.NewCoin("barcoin", 2), sdk.NewCoin("foocoin", 5)})) } @@ -195,14 +196,14 @@ func TestViewKeeper(t *testing.T) { // Test GetCoins/SetCoins accountMapper.SetAccount(ctx, acc) - assert.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) + require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{})) coinKeeper.SetCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)}) - assert.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, viewKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{sdk.NewCoin("foocoin", 10)})) // Test HasCoins - assert.True(t, viewKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)})) - assert.True(t, viewKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 5)})) - assert.False(t, viewKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 15)})) - assert.False(t, viewKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 5)})) + require.True(t, viewKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 10)})) + require.True(t, viewKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 5)})) + require.False(t, viewKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("foocoin", 15)})) + require.False(t, viewKeeper.HasCoins(ctx, addr, sdk.Coins{sdk.NewCoin("barcoin", 5)})) } diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index 350a51d7aa..3754858ec7 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -22,7 +22,7 @@ func TestMsgSendType(t *testing.T) { } // TODO some failures for bad result - assert.Equal(t, msg.Type(), "bank") + require.Equal(t, msg.Type(), "bank") } func TestInputValidation(t *testing.T) { @@ -60,9 +60,9 @@ func TestInputValidation(t *testing.T) { for i, tc := range cases { err := tc.txIn.ValidateBasic() if tc.valid { - assert.Nil(t, err, "%d: %+v", i, err) + require.Nil(t, err, "%d: %+v", i, err) } else { - assert.NotNil(t, err, "%d", i) + require.NotNil(t, err, "%d", i) } } } @@ -102,9 +102,9 @@ func TestOutputValidation(t *testing.T) { for i, tc := range cases { err := tc.txOut.ValidateBasic() if tc.valid { - assert.Nil(t, err, "%d: %+v", i, err) + require.Nil(t, err, "%d: %+v", i, err) } else { - assert.NotNil(t, err, "%d", i) + require.NotNil(t, err, "%d", i) } } } @@ -170,9 +170,9 @@ func TestMsgSendValidation(t *testing.T) { for i, tc := range cases { err := tc.tx.ValidateBasic() if tc.valid { - assert.Nil(t, err, "%d: %+v", i, err) + require.Nil(t, err, "%d: %+v", i, err) } else { - assert.NotNil(t, err, "%d", i) + require.NotNil(t, err, "%d", i) } } } @@ -188,7 +188,7 @@ func TestMsgSendGetSignBytes(t *testing.T) { res := msg.GetSignBytes() expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"denom":"atom","amount":"10"}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"denom":"atom","amount":"10"}]}]}` - assert.Equal(t, expected, string(res)) + require.Equal(t, expected, string(res)) } func TestMsgSendGetSigners(t *testing.T) { @@ -201,7 +201,7 @@ func TestMsgSendGetSigners(t *testing.T) { } res := msg.GetSigners() // TODO: fix this ! - assert.Equal(t, fmt.Sprintf("%v", res), "[696E70757431 696E70757432 696E70757433]") + require.Equal(t, fmt.Sprintf("%v", res), "[696E70757431 696E70757432 696E70757433]") } /* @@ -220,7 +220,7 @@ func TestMsgSendSigners(t *testing.T) { } tx := NewMsgSend(inputs, nil) - assert.Equal(t, signers, tx.Signers()) + require.Equal(t, signers, tx.Signers()) } */ @@ -241,7 +241,7 @@ func TestMsgIssueType(t *testing.T) { } // TODO some failures for bad result - assert.Equal(t, msg.Type(), "bank") + require.Equal(t, msg.Type(), "bank") } func TestMsgIssueValidation(t *testing.T) { @@ -258,7 +258,7 @@ func TestMsgIssueGetSignBytes(t *testing.T) { res := msg.GetSignBytes() expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"denom":"atom","amount":"10"}]}]}` - assert.Equal(t, expected, string(res)) + require.Equal(t, expected, string(res)) } func TestMsgIssueGetSigners(t *testing.T) { @@ -266,5 +266,5 @@ func TestMsgIssueGetSigners(t *testing.T) { Banker: sdk.Address([]byte("onlyone")), } res := msg.GetSigners() - assert.Equal(t, fmt.Sprintf("%v", res), "[6F6E6C796F6E65]") + require.Equal(t, fmt.Sprintf("%v", res), "[6F6E6C796F6E65]") } diff --git a/x/fee_distribution/keeper_test.go b/x/fee_distribution/keeper_test.go index 4ad8180e17..0d732f8a19 100644 --- a/x/fee_distribution/keeper_test.go +++ b/x/fee_distribution/keeper_test.go @@ -15,11 +15,11 @@ package stake //// test that an empty gotValidator set doesn't have any gotValidators //gotValidators := keeper.GetValidators(ctx) -//assert.Equal(t, 5, len(gotValidators)) +//require.Equal(t, 5, len(gotValidators)) //totPow := keeper.GetTotalPrecommitVotingPower(ctx) //exp := sdk.NewRat(11111) -//assert.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) +//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) //// set absent gotValidators to be the 1st and 3rd record sorted by pubKey address //ctx = ctx.WithAbsentValidators([]int32{1, 3}) @@ -27,5 +27,5 @@ package stake //// XXX verify that this order should infact exclude these two records //exp = sdk.NewRat(11100) -//assert.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) +//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow) //} diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 4aeac9417e..0070bb5777 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -3,7 +3,7 @@ package gov import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/tendermint/abci/types" @@ -15,29 +15,29 @@ func TestTickExpiredDepositPeriod(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) govHandler := NewHandler(keeper) - assert.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin("steak", 5)}) res := govHandler(ctx, newProposalMsg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) EndBlocker(ctx, keeper) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) ctx = ctx.WithBlockHeight(10) EndBlocker(ctx, keeper) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) ctx = ctx.WithBlockHeight(250) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) - assert.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) } func TestTickMultipleExpiredDepositPeriod(t *testing.T) { @@ -46,40 +46,40 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) govHandler := NewHandler(keeper) - assert.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin("steak", 5)}) res := govHandler(ctx, newProposalMsg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) EndBlocker(ctx, keeper) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) ctx = ctx.WithBlockHeight(10) EndBlocker(ctx, keeper) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) newProposalMsg2 := NewMsgSubmitProposal("Test2", "test2", ProposalTypeText, addrs[1], sdk.Coins{sdk.NewCoin("steak", 5)}) res = govHandler(ctx, newProposalMsg2) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) ctx = ctx.WithBlockHeight(205) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) ctx = ctx.WithBlockHeight(215) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) EndBlocker(ctx, keeper) - assert.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) } func TestTickPassedDepositPeriod(t *testing.T) { @@ -88,41 +88,41 @@ func TestTickPassedDepositPeriod(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) govHandler := NewHandler(keeper) - assert.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - assert.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopActiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.False(t, shouldPopActiveProposalQueue(ctx, keeper)) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin("steak", 5)}) res := govHandler(ctx, newProposalMsg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) var proposalID int64 keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) EndBlocker(ctx, keeper) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) ctx = ctx.WithBlockHeight(10) EndBlocker(ctx, keeper) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewCoin("steak", 5)}) res = govHandler(ctx, newDepositMsg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) - assert.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) - assert.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) EndBlocker(ctx, keeper) - assert.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - assert.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopActiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.False(t, shouldPopActiveProposalQueue(ctx, keeper)) } func TestTickPassedVotingPeriod(t *testing.T) { @@ -132,37 +132,37 @@ func TestTickPassedVotingPeriod(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) govHandler := NewHandler(keeper) - assert.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) - assert.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) - assert.False(t, shouldPopActiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) + require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.False(t, shouldPopActiveProposalQueue(ctx, keeper)) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin("steak", 5)}) res := govHandler(ctx, newProposalMsg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) var proposalID int64 keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) ctx = ctx.WithBlockHeight(10) newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewCoin("steak", 5)}) res = govHandler(ctx, newDepositMsg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) EndBlocker(ctx, keeper) ctx = ctx.WithBlockHeight(215) - assert.True(t, shouldPopActiveProposalQueue(ctx, keeper)) + require.True(t, shouldPopActiveProposalQueue(ctx, keeper)) depositsIterator := keeper.GetDeposits(ctx, proposalID) - assert.True(t, depositsIterator.Valid()) + require.True(t, depositsIterator.Valid()) depositsIterator.Close() - assert.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) + require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) EndBlocker(ctx, keeper) - assert.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) depositsIterator = keeper.GetDeposits(ctx, proposalID) - assert.False(t, depositsIterator.Valid()) + require.False(t, depositsIterator.Valid()) depositsIterator.Close() - assert.Equal(t, StatusRejected, keeper.GetProposal(ctx, proposalID).GetStatus()) + require.Equal(t, StatusRejected, keeper.GetProposal(ctx, proposalID).GetStatus()) } diff --git a/x/gov/keeper_test.go b/x/gov/keeper_test.go index 1033600e65..786953fd3a 100644 --- a/x/gov/keeper_test.go +++ b/x/gov/keeper_test.go @@ -3,7 +3,7 @@ package gov import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -20,7 +20,7 @@ func TestGetSetProposal(t *testing.T) { keeper.SetProposal(ctx, proposal) gotProposal := keeper.GetProposal(ctx, proposalID) - assert.True(t, ProposalEqual(proposal, gotProposal)) + require.True(t, ProposalEqual(proposal, gotProposal)) } func TestIncrementProposalNumber(t *testing.T) { @@ -35,7 +35,7 @@ func TestIncrementProposalNumber(t *testing.T) { keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposal6 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) - assert.Equal(t, int64(6), proposal6.GetProposalID()) + require.Equal(t, int64(6), proposal6.GetProposalID()) } func TestActivateVotingPeriod(t *testing.T) { @@ -45,13 +45,13 @@ func TestActivateVotingPeriod(t *testing.T) { proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) - assert.Equal(t, int64(-1), proposal.GetVotingStartBlock()) - assert.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.Equal(t, int64(-1), proposal.GetVotingStartBlock()) + require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) keeper.activateVotingPeriod(ctx, proposal) - assert.Equal(t, proposal.GetVotingStartBlock(), ctx.BlockHeight()) - assert.Equal(t, proposal.GetProposalID(), keeper.ActiveProposalQueuePeek(ctx).GetProposalID()) + require.Equal(t, proposal.GetVotingStartBlock(), ctx.BlockHeight()) + require.Equal(t, proposal.GetProposalID(), keeper.ActiveProposalQueuePeek(ctx).GetProposalID()) } func TestDeposits(t *testing.T) { @@ -69,77 +69,77 @@ func TestDeposits(t *testing.T) { addr0Initial := keeper.ck.GetCoins(ctx, addrs[0]) addr1Initial := keeper.ck.GetCoins(ctx, addrs[1]) - // assert.True(t, addr0Initial.IsEqual(sdk.Coins{sdk.NewCoin("steak", 42)})) - assert.Equal(t, sdk.Coins{sdk.NewCoin("steak", 42)}, addr0Initial) + // require.True(t, addr0Initial.IsEqual(sdk.Coins{sdk.NewCoin("steak", 42)})) + require.Equal(t, sdk.Coins{sdk.NewCoin("steak", 42)}, addr0Initial) - assert.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{})) + require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{})) // Check no deposits at beginning deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1]) - assert.False(t, found) - assert.Equal(t, keeper.GetProposal(ctx, proposalID).GetVotingStartBlock(), int64(-1)) - assert.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.False(t, found) + require.Equal(t, keeper.GetProposal(ctx, proposalID).GetVotingStartBlock(), int64(-1)) + require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) // Check first deposit err, votingStarted := keeper.AddDeposit(ctx, proposalID, addrs[0], fourSteak) - assert.Nil(t, err) - assert.False(t, votingStarted) + require.Nil(t, err) + require.False(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, addrs[0]) - assert.True(t, found) - assert.Equal(t, fourSteak, deposit.Amount) - assert.Equal(t, addrs[0], deposit.Depositer) - assert.Equal(t, fourSteak, keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) - assert.Equal(t, addr0Initial.Minus(fourSteak), keeper.ck.GetCoins(ctx, addrs[0])) + require.True(t, found) + require.Equal(t, fourSteak, deposit.Amount) + require.Equal(t, addrs[0], deposit.Depositer) + require.Equal(t, fourSteak, keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) + require.Equal(t, addr0Initial.Minus(fourSteak), keeper.ck.GetCoins(ctx, addrs[0])) // Check a second deposit from same address err, votingStarted = keeper.AddDeposit(ctx, proposalID, addrs[0], fiveSteak) - assert.Nil(t, err) - assert.False(t, votingStarted) + require.Nil(t, err) + require.False(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, addrs[0]) - assert.True(t, found) - assert.Equal(t, fourSteak.Plus(fiveSteak), deposit.Amount) - assert.Equal(t, addrs[0], deposit.Depositer) - assert.Equal(t, fourSteak.Plus(fiveSteak), keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) - assert.Equal(t, addr0Initial.Minus(fourSteak).Minus(fiveSteak), keeper.ck.GetCoins(ctx, addrs[0])) + require.True(t, found) + require.Equal(t, fourSteak.Plus(fiveSteak), deposit.Amount) + require.Equal(t, addrs[0], deposit.Depositer) + require.Equal(t, fourSteak.Plus(fiveSteak), keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) + require.Equal(t, addr0Initial.Minus(fourSteak).Minus(fiveSteak), keeper.ck.GetCoins(ctx, addrs[0])) // Check third deposit from a new address err, votingStarted = keeper.AddDeposit(ctx, proposalID, addrs[1], fourSteak) - assert.Nil(t, err) - assert.True(t, votingStarted) + require.Nil(t, err) + require.True(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, addrs[1]) - assert.True(t, found) - assert.Equal(t, addrs[1], deposit.Depositer) - assert.Equal(t, fourSteak, deposit.Amount) - assert.Equal(t, fourSteak.Plus(fiveSteak).Plus(fourSteak), keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) - assert.Equal(t, addr1Initial.Minus(fourSteak), keeper.ck.GetCoins(ctx, addrs[1])) + require.True(t, found) + require.Equal(t, addrs[1], deposit.Depositer) + require.Equal(t, fourSteak, deposit.Amount) + require.Equal(t, fourSteak.Plus(fiveSteak).Plus(fourSteak), keeper.GetProposal(ctx, proposalID).GetTotalDeposit()) + require.Equal(t, addr1Initial.Minus(fourSteak), keeper.ck.GetCoins(ctx, addrs[1])) // Check that proposal moved to voting period - assert.Equal(t, ctx.BlockHeight(), keeper.GetProposal(ctx, proposalID).GetVotingStartBlock()) - assert.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) - assert.Equal(t, proposalID, keeper.ActiveProposalQueuePeek(ctx).GetProposalID()) + require.Equal(t, ctx.BlockHeight(), keeper.GetProposal(ctx, proposalID).GetVotingStartBlock()) + require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.Equal(t, proposalID, keeper.ActiveProposalQueuePeek(ctx).GetProposalID()) // Test deposit iterator depositsIterator := keeper.GetDeposits(ctx, proposalID) - assert.True(t, depositsIterator.Valid()) + require.True(t, depositsIterator.Valid()) keeper.cdc.MustUnmarshalBinary(depositsIterator.Value(), &deposit) - assert.Equal(t, addrs[0], deposit.Depositer) - assert.Equal(t, fourSteak.Plus(fiveSteak), deposit.Amount) + require.Equal(t, addrs[0], deposit.Depositer) + require.Equal(t, fourSteak.Plus(fiveSteak), deposit.Amount) depositsIterator.Next() keeper.cdc.MustUnmarshalBinary(depositsIterator.Value(), &deposit) - assert.Equal(t, addrs[1], deposit.Depositer) - assert.Equal(t, fourSteak, deposit.Amount) + require.Equal(t, addrs[1], deposit.Depositer) + require.Equal(t, fourSteak, deposit.Amount) depositsIterator.Next() - assert.False(t, depositsIterator.Valid()) + require.False(t, depositsIterator.Valid()) // Test Refund Deposits deposit, found = keeper.GetDeposit(ctx, proposalID, addrs[1]) - assert.True(t, found) - assert.Equal(t, fourSteak, deposit.Amount) + require.True(t, found) + require.Equal(t, fourSteak, deposit.Amount) keeper.RefundDeposits(ctx, proposalID) deposit, found = keeper.GetDeposit(ctx, proposalID, addrs[1]) - assert.False(t, found) - assert.Equal(t, addr0Initial, keeper.ck.GetCoins(ctx, addrs[0])) - assert.Equal(t, addr1Initial, keeper.ck.GetCoins(ctx, addrs[1])) + require.False(t, found) + require.Equal(t, addr0Initial, keeper.ck.GetCoins(ctx, addrs[0])) + require.Equal(t, addr1Initial, keeper.ck.GetCoins(ctx, addrs[1])) } @@ -158,44 +158,44 @@ func TestVotes(t *testing.T) { // Test first vote keeper.AddVote(ctx, proposalID, addrs[0], OptionAbstain) vote, found := keeper.GetVote(ctx, proposalID, addrs[0]) - assert.True(t, found) - assert.Equal(t, addrs[0], vote.Voter) - assert.Equal(t, proposalID, vote.ProposalID) - assert.Equal(t, OptionAbstain, vote.Option) + require.True(t, found) + require.Equal(t, addrs[0], vote.Voter) + require.Equal(t, proposalID, vote.ProposalID) + require.Equal(t, OptionAbstain, vote.Option) // Test change of vote keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) vote, found = keeper.GetVote(ctx, proposalID, addrs[0]) - assert.True(t, found) - assert.Equal(t, addrs[0], vote.Voter) - assert.Equal(t, proposalID, vote.ProposalID) - assert.Equal(t, OptionYes, vote.Option) + require.True(t, found) + require.Equal(t, addrs[0], vote.Voter) + require.Equal(t, proposalID, vote.ProposalID) + require.Equal(t, OptionYes, vote.Option) // Test second vote keeper.AddVote(ctx, proposalID, addrs[1], OptionNoWithVeto) vote, found = keeper.GetVote(ctx, proposalID, addrs[1]) - assert.True(t, found) - assert.Equal(t, addrs[1], vote.Voter) - assert.Equal(t, proposalID, vote.ProposalID) - assert.Equal(t, OptionNoWithVeto, vote.Option) + require.True(t, found) + require.Equal(t, addrs[1], vote.Voter) + require.Equal(t, proposalID, vote.ProposalID) + require.Equal(t, OptionNoWithVeto, vote.Option) // Test vote iterator votesIterator := keeper.GetVotes(ctx, proposalID) - assert.True(t, votesIterator.Valid()) + require.True(t, votesIterator.Valid()) keeper.cdc.MustUnmarshalBinary(votesIterator.Value(), &vote) - assert.True(t, votesIterator.Valid()) - assert.Equal(t, addrs[0], vote.Voter) - assert.Equal(t, proposalID, vote.ProposalID) - assert.Equal(t, OptionYes, vote.Option) + require.True(t, votesIterator.Valid()) + require.Equal(t, addrs[0], vote.Voter) + require.Equal(t, proposalID, vote.ProposalID) + require.Equal(t, OptionYes, vote.Option) votesIterator.Next() - assert.True(t, votesIterator.Valid()) + require.True(t, votesIterator.Valid()) keeper.cdc.MustUnmarshalBinary(votesIterator.Value(), &vote) - assert.True(t, votesIterator.Valid()) - assert.Equal(t, addrs[1], vote.Voter) - assert.Equal(t, proposalID, vote.ProposalID) - assert.Equal(t, OptionNoWithVeto, vote.Option) + require.True(t, votesIterator.Valid()) + require.Equal(t, addrs[1], vote.Voter) + require.Equal(t, proposalID, vote.ProposalID) + require.Equal(t, OptionNoWithVeto, vote.Option) votesIterator.Next() - assert.False(t, votesIterator.Valid()) + require.False(t, votesIterator.Valid()) } func TestProposalQueues(t *testing.T) { @@ -204,8 +204,8 @@ func TestProposalQueues(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) mapp.InitChainer(ctx, abci.RequestInitChain{}) - assert.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) - assert.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) + require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) + require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) // create test proposals proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) @@ -220,14 +220,14 @@ func TestProposalQueues(t *testing.T) { keeper.InactiveProposalQueuePush(ctx, proposal4) // test peeking and popping from inactive proposal queue - assert.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal.GetProposalID()) - assert.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal.GetProposalID()) - assert.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal2.GetProposalID()) - assert.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal2.GetProposalID()) - assert.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal3.GetProposalID()) - assert.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal3.GetProposalID()) - assert.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal4.GetProposalID()) - assert.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal4.GetProposalID()) + require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal.GetProposalID()) + require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal.GetProposalID()) + require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal2.GetProposalID()) + require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal2.GetProposalID()) + require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal3.GetProposalID()) + require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal3.GetProposalID()) + require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal4.GetProposalID()) + require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal4.GetProposalID()) // test pushing to active proposal queue keeper.ActiveProposalQueuePush(ctx, proposal) @@ -236,12 +236,12 @@ func TestProposalQueues(t *testing.T) { keeper.ActiveProposalQueuePush(ctx, proposal4) // test peeking and popping from active proposal queue - assert.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal.GetProposalID()) - assert.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal.GetProposalID()) - assert.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal2.GetProposalID()) - assert.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal2.GetProposalID()) - assert.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal3.GetProposalID()) - assert.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal3.GetProposalID()) - assert.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal4.GetProposalID()) - assert.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal4.GetProposalID()) + require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal.GetProposalID()) + require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal.GetProposalID()) + require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal2.GetProposalID()) + require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal2.GetProposalID()) + require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal3.GetProposalID()) + require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal3.GetProposalID()) + require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal4.GetProposalID()) + require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal4.GetProposalID()) } diff --git a/x/gov/msgs_test.go b/x/gov/msgs_test.go index 3100f98ca0..e9be4ded3d 100644 --- a/x/gov/msgs_test.go +++ b/x/gov/msgs_test.go @@ -3,7 +3,7 @@ package gov import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/mock" @@ -42,9 +42,9 @@ func TestMsgSubmitProposal(t *testing.T) { for i, tc := range tests { msg := NewMsgSubmitProposal(tc.title, tc.description, tc.proposalType, tc.proposerAddr, tc.initialDeposit) if tc.expectPass { - assert.Nil(t, msg.ValidateBasic(), "test: %v", i) + require.Nil(t, msg.ValidateBasic(), "test: %v", i) } else { - assert.NotNil(t, msg.ValidateBasic(), "test: %v", i) + require.NotNil(t, msg.ValidateBasic(), "test: %v", i) } } } @@ -69,9 +69,9 @@ func TestMsgDeposit(t *testing.T) { for i, tc := range tests { msg := NewMsgDeposit(tc.depositerAddr, tc.proposalID, tc.depositAmount) if tc.expectPass { - assert.Nil(t, msg.ValidateBasic(), "test: %v", i) + require.Nil(t, msg.ValidateBasic(), "test: %v", i) } else { - assert.NotNil(t, msg.ValidateBasic(), "test: %v", i) + require.NotNil(t, msg.ValidateBasic(), "test: %v", i) } } } @@ -97,9 +97,9 @@ func TestMsgVote(t *testing.T) { for i, tc := range tests { msg := NewMsgVote(tc.voterAddr, tc.proposalID, tc.option) if tc.expectPass { - assert.Nil(t, msg.ValidateBasic(), "test: %v", i) + require.Nil(t, msg.ValidateBasic(), "test: %v", i) } else { - assert.NotNil(t, msg.ValidateBasic(), "test: %v", i) + require.NotNil(t, msg.ValidateBasic(), "test: %v", i) } } } diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index 171a2e2e9c..bcc3f2eb01 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -3,7 +3,7 @@ package gov import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/tendermint/abci/types" @@ -31,7 +31,7 @@ func TestTallyNoOneVotes(t *testing.T) { passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.False(t, passes) + require.False(t, passes) } func TestTallyOnlyValidatorsAllYes(t *testing.T) { @@ -43,10 +43,10 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { dummyDescription := stake.NewDescription("T", "E", "S", "T") val1CreateMsg := stake.NewMsgCreateValidator(addrs[0], crypto.GenPrivKeyEd25519().PubKey(), sdk.NewCoin("steak", 5), dummyDescription) res := stakeHandler(ctx, val1CreateMsg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) val2CreateMsg := stake.NewMsgCreateValidator(addrs[1], crypto.GenPrivKeyEd25519().PubKey(), sdk.NewCoin("steak", 5), dummyDescription) res = stakeHandler(ctx, val2CreateMsg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -54,13 +54,13 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.True(t, passes) + require.True(t, passes) } func TestTallyOnlyValidators51No(t *testing.T) { @@ -81,13 +81,13 @@ func TestTallyOnlyValidators51No(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.False(t, passes) + require.False(t, passes) } func TestTallyOnlyValidators51Yes(t *testing.T) { @@ -110,15 +110,15 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.True(t, passes) + require.True(t, passes) } func TestTallyOnlyValidatorsVetoed(t *testing.T) { @@ -141,15 +141,15 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNoWithVeto) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.False(t, passes) + require.False(t, passes) } func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { @@ -172,15 +172,15 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionAbstain) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.True(t, passes) + require.True(t, passes) } func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { @@ -203,15 +203,15 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionAbstain) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.False(t, passes) + require.False(t, passes) } func TestTallyOnlyValidatorsNonVoter(t *testing.T) { @@ -234,15 +234,15 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) passes, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.False(t, passes) - assert.Equal(t, 1, len(nonVoting)) - assert.Equal(t, addrs[0], nonVoting[0]) + require.False(t, passes) + require.Equal(t, 1, len(nonVoting)) + require.Equal(t, addrs[0], nonVoting[0]) } func TestTallyDelgatorOverride(t *testing.T) { @@ -268,17 +268,17 @@ func TestTallyDelgatorOverride(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.False(t, passes) + require.False(t, passes) } func TestTallyDelgatorInherit(t *testing.T) { @@ -304,16 +304,16 @@ func TestTallyDelgatorInherit(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) passes, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.True(t, passes) - assert.Equal(t, 0, len(nonVoting)) + require.True(t, passes) + require.Equal(t, 0, len(nonVoting)) } func TestTallyDelgatorMultipleOverride(t *testing.T) { @@ -341,17 +341,17 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.False(t, passes) + require.False(t, passes) } func TestTallyDelgatorMultipleInherit(t *testing.T) { @@ -379,13 +379,13 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { keeper.SetProposal(ctx, proposal) err := keeper.AddVote(ctx, proposalID, addrs[0], OptionYes) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo) - assert.Nil(t, err) + require.Nil(t, err) passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID)) - assert.False(t, passes) + require.False(t, passes) } diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go index 077bc87bb6..1540bf2ed8 100644 --- a/x/ibc/app_test.go +++ b/x/ibc/app_test.go @@ -3,7 +3,6 @@ package ibc import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -51,7 +50,7 @@ func TestIBCMsgs(t *testing.T) { // A checkTx context (true) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) - assert.Equal(t, acc, res1) + require.Equal(t, acc, res1) packet := IBCPacket{ SrcAddr: addr1, diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index f292fabfe8..33535145d8 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -3,7 +3,7 @@ package ibc import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" @@ -72,8 +72,8 @@ func TestIBC(t *testing.T) { mycoins := sdk.Coins{sdk.NewCoin("mycoin", 10)} coins, _, err := ck.AddCoins(ctx, src, mycoins) - assert.Nil(t, err) - assert.Equal(t, mycoins, coins) + require.Nil(t, err) + require.Equal(t, mycoins, coins) ibcm := NewMapper(cdc, key, DefaultCodespace) h := NewHandler(ibcm, ck) @@ -93,23 +93,23 @@ func TestIBC(t *testing.T) { var igs int64 egl = ibcm.getEgressLength(store, chainid) - assert.Equal(t, egl, int64(0)) + require.Equal(t, egl, int64(0)) msg = IBCTransferMsg{ IBCPacket: packet, } res = h(ctx, msg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) coins, err = getCoins(ck, ctx, src) - assert.Nil(t, err) - assert.Equal(t, zero, coins) + require.Nil(t, err) + require.Equal(t, zero, coins) egl = ibcm.getEgressLength(store, chainid) - assert.Equal(t, egl, int64(1)) + require.Equal(t, egl, int64(1)) igs = ibcm.GetIngressSequence(ctx, chainid) - assert.Equal(t, igs, int64(0)) + require.Equal(t, igs, int64(0)) msg = IBCReceiveMsg{ IBCPacket: packet, @@ -117,18 +117,18 @@ func TestIBC(t *testing.T) { Sequence: 0, } res = h(ctx, msg) - assert.True(t, res.IsOK()) + require.True(t, res.IsOK()) coins, err = getCoins(ck, ctx, dest) - assert.Nil(t, err) - assert.Equal(t, mycoins, coins) + require.Nil(t, err) + require.Equal(t, mycoins, coins) igs = ibcm.GetIngressSequence(ctx, chainid) - assert.Equal(t, igs, int64(1)) + require.Equal(t, igs, int64(1)) res = h(ctx, msg) - assert.False(t, res.IsOK()) + require.False(t, res.IsOK()) igs = ibcm.GetIngressSequence(ctx, chainid) - assert.Equal(t, igs, int64(1)) + require.Equal(t, igs, int64(1)) } diff --git a/x/ibc/types_test.go b/x/ibc/types_test.go index 5127546989..690179baa1 100644 --- a/x/ibc/types_test.go +++ b/x/ibc/types_test.go @@ -3,7 +3,7 @@ package ibc import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -23,9 +23,9 @@ func TestIBCPacketValidation(t *testing.T) { for i, tc := range cases { err := tc.packet.ValidateBasic() if tc.valid { - assert.Nil(t, err, "%d: %+v", i, err) + require.Nil(t, err, "%d: %+v", i, err) } else { - assert.NotNil(t, err, "%d", i) + require.NotNil(t, err, "%d", i) } } } @@ -37,7 +37,7 @@ func TestIBCTransferMsg(t *testing.T) { packet := constructIBCPacket(true) msg := IBCTransferMsg{packet} - assert.Equal(t, msg.Type(), "ibc") + require.Equal(t, msg.Type(), "ibc") } func TestIBCTransferMsgValidation(t *testing.T) { @@ -55,9 +55,9 @@ func TestIBCTransferMsgValidation(t *testing.T) { for i, tc := range cases { err := tc.msg.ValidateBasic() if tc.valid { - assert.Nil(t, err, "%d: %+v", i, err) + require.Nil(t, err, "%d: %+v", i, err) } else { - assert.NotNil(t, err, "%d", i) + require.NotNil(t, err, "%d", i) } } } @@ -69,7 +69,7 @@ func TestIBCReceiveMsg(t *testing.T) { packet := constructIBCPacket(true) msg := IBCReceiveMsg{packet, sdk.Address([]byte("relayer")), 0} - assert.Equal(t, msg.Type(), "ibc") + require.Equal(t, msg.Type(), "ibc") } func TestIBCReceiveMsgValidation(t *testing.T) { @@ -87,9 +87,9 @@ func TestIBCReceiveMsgValidation(t *testing.T) { for i, tc := range cases { err := tc.msg.ValidateBasic() if tc.valid { - assert.Nil(t, err, "%d: %+v", i, err) + require.Nil(t, err, "%d: %+v", i, err) } else { - assert.NotNil(t, err, "%d", i) + require.NotNil(t, err, "%d", i) } } } diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 2120e75b68..18416174bd 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/bank" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/x/stake" @@ -66,7 +65,7 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper stake.Keeper, addr sdk.Address, expFound bool) stake.Validator { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) validator, found := keeper.GetValidator(ctxCheck, addr1) - assert.Equal(t, expFound, found) + require.Equal(t, expFound, found) return validator } @@ -74,7 +73,7 @@ func checkValidatorSigningInfo(t *testing.T, mapp *mock.App, keeper Keeper, addr sdk.Address, expFound bool) ValidatorSigningInfo { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) signingInfo, found := keeper.getValidatorSigningInfo(ctxCheck, addr) - assert.Equal(t, expFound, found) + require.Equal(t, expFound, found) return signingInfo } diff --git a/x/slashing/msg_test.go b/x/slashing/msg_test.go index be7797107e..a668bc33fa 100644 --- a/x/slashing/msg_test.go +++ b/x/slashing/msg_test.go @@ -3,7 +3,7 @@ package slashing import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -12,5 +12,5 @@ func TestMsgUnrevokeGetSignBytes(t *testing.T) { addr := sdk.Address("abcd") msg := NewMsgUnrevoke(addr) bytes := msg.GetSignBytes() - assert.Equal(t, string(bytes), `{"address":"cosmosvaladdr1v93xxeqamr0mv"}`) + require.Equal(t, string(bytes), `{"address":"cosmosvaladdr1v93xxeqamr0mv"}`) } diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 2b02533092..d4fc5bdf00 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -75,7 +75,7 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) validator, found := keeper.GetValidator(ctxCheck, addr1) - assert.Equal(t, expFound, found) + require.Equal(t, expFound, found) return validator } @@ -85,11 +85,11 @@ func checkDelegation(t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr, ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr) if expFound { - assert.True(t, found) + require.True(t, found) assert.True(sdk.RatEq(t, expShares, delegation.Shares)) return } - assert.False(t, found) + require.False(t, found) } func TestStakeMsgs(t *testing.T) { diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 61acc94d7f..ef47318c68 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -3,7 +3,6 @@ package stake import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" @@ -52,7 +51,7 @@ func TestValidatorByPowerIndex(t *testing.T) { // create validator msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - assert.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // verify the self-delegation exists bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr) @@ -72,7 +71,7 @@ func TestValidatorByPowerIndex(t *testing.T) { // create a second validator keep it bonded msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], int64(1000000)) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - assert.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and revoke the first validator keeper.Slash(ctx, keep.PKs[0], 0, sdk.NewRat(1, 2)) @@ -83,7 +82,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.Equal(t, int64(500000), validator.PoolShares.Amount.Evaluate()) // ensure is unbonded // the old power record should have been deleted as the power changed - assert.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) + require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) // but the new power record should have been created validator, found = keeper.GetValidator(ctx, validatorAddr) @@ -100,7 +99,7 @@ func TestValidatorByPowerIndex(t *testing.T) { // now the new record power index should be the same as the original record power3 := GetValidatorsByPowerIndexKey(validator, pool) - assert.Equal(t, power2, power3) + require.Equal(t, power2, power3) // unbond self-delegation msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(1000000)) @@ -113,7 +112,7 @@ func TestValidatorByPowerIndex(t *testing.T) { // verify that by power key nolonger exists _, found = keeper.GetValidator(ctx, validatorAddr) require.False(t, found) - assert.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power3)) + require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power3)) } func TestDuplicatesMsgCreateValidator(t *testing.T) { @@ -123,21 +122,21 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { pk := keep.PKs[0] msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pk, 10) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - assert.True(t, got.IsOK(), "%v", got) + require.True(t, got.IsOK(), "%v", got) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - assert.Equal(t, sdk.Bonded, validator.Status()) - assert.Equal(t, validatorAddr, validator.Owner) - assert.Equal(t, pk, validator.PubKey) - assert.Equal(t, sdk.NewRat(10), validator.PoolShares.Bonded()) - assert.Equal(t, sdk.NewRat(10), validator.DelegatorShares) - assert.Equal(t, Description{}, validator.Description) + require.Equal(t, sdk.Bonded, validator.Status()) + require.Equal(t, validatorAddr, validator.Owner) + require.Equal(t, pk, validator.PubKey) + require.Equal(t, sdk.NewRat(10), validator.PoolShares.Bonded()) + require.Equal(t, sdk.NewRat(10), validator.DelegatorShares) + require.Equal(t, Description{}, validator.Description) // one validator cannot bond twice msgCreateValidator.PubKey = keep.PKs[1] got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - assert.False(t, got.IsOK(), "%v", got) + require.False(t, got.IsOK(), "%v", got) } func TestIncrementsMsgDelegate(t *testing.T) { @@ -151,26 +150,26 @@ func TestIncrementsMsgDelegate(t *testing.T) { // first create validator msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - assert.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.Equal(t, sdk.Bonded, validator.Status()) - assert.Equal(t, bondAmount, validator.DelegatorShares.Evaluate()) - assert.Equal(t, bondAmount, validator.PoolShares.Bonded().Evaluate(), "validator: %v", validator) + require.Equal(t, bondAmount, validator.DelegatorShares.Evaluate()) + require.Equal(t, bondAmount, validator.PoolShares.Bonded().Evaluate(), "validator: %v", validator) _, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.False(t, found) bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr) require.True(t, found) - assert.Equal(t, bondAmount, bond.Shares.Evaluate()) + require.Equal(t, bondAmount, bond.Shares.Evaluate()) pool := keeper.GetPool(ctx) exRate := validator.DelegatorShareExRate(pool) require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) - assert.Equal(t, bondAmount, pool.BondedShares.Evaluate()) - assert.Equal(t, bondAmount, pool.BondedTokens) + require.Equal(t, bondAmount, pool.BondedShares.Evaluate()) + require.Equal(t, bondAmount, pool.BondedTokens) // just send the same msgbond multiple times msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, bondAmount) @@ -223,16 +222,16 @@ func TestIncrementsMsgUnbond(t *testing.T) { msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - assert.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, initBond) got = handleMsgDelegate(ctx, msgDelegate, keeper) - assert.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - assert.Equal(t, initBond*2, validator.DelegatorShares.Evaluate()) - assert.Equal(t, initBond*2, validator.PoolShares.Bonded().Evaluate()) + require.Equal(t, initBond*2, validator.DelegatorShares.Evaluate()) + require.Equal(t, initBond*2, validator.PoolShares.Bonded().Evaluate()) // just send the same msgUnbond multiple times // TODO use decimals here @@ -292,14 +291,14 @@ func TestIncrementsMsgUnbond(t *testing.T) { unbondShares = sdk.NewRat(leftBonded + 1) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) - assert.False(t, got.IsOK(), + require.False(t, got.IsOK(), "got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgBeginUnbonding, unbondShares.String(), leftBonded) // should be able to unbond just what we have unbondShares = sdk.NewRat(leftBonded) msgBeginUnbonding = NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) - assert.True(t, got.IsOK(), + require.True(t, got.IsOK(), "got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgBeginUnbonding, unbondShares, leftBonded) } @@ -420,7 +419,7 @@ func TestRevokeValidator(t *testing.T) { // test that this address cannot yet be bonded too because is revoked got = handleMsgDelegate(ctx, msgDelegate, keeper) - assert.False(t, got.IsOK(), "expected error, got %v", got) + require.False(t, got.IsOK(), "expected error, got %v", got) // test that the delegator can still withdraw their bonds msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewRat(10)) @@ -432,7 +431,7 @@ func TestRevokeValidator(t *testing.T) { // verify that the pubkey can now be reused got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - assert.True(t, got.IsOK(), "expected ok, got %v", got) + require.True(t, got.IsOK(), "expected ok, got %v", got) } func TestUnbondingPeriod(t *testing.T) { diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index d7c1ac9849..f20188ccdc 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -37,20 +36,20 @@ func TestDelegation(t *testing.T) { // check the empty keeper first _, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - assert.False(t, found) + require.False(t, found) // set and retrieve a record keeper.SetDelegation(ctx, bond1to1) resBond, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - assert.True(t, found) - assert.True(t, bond1to1.Equal(resBond)) + require.True(t, found) + require.True(t, bond1to1.Equal(resBond)) // modify a records, save, and retrieve bond1to1.Shares = sdk.NewRat(99) keeper.SetDelegation(ctx, bond1to1) resBond, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) - assert.True(t, found) - assert.True(t, bond1to1.Equal(resBond)) + require.True(t, found) + require.True(t, bond1to1.Equal(resBond)) // add some more records bond1to2 := types.Delegation{addrDels[0], addrVals[1], sdk.NewRat(9), 0} @@ -67,43 +66,43 @@ func TestDelegation(t *testing.T) { // test all bond retrieve capabilities resBonds := keeper.GetDelegations(ctx, addrDels[0], 5) require.Equal(t, 3, len(resBonds)) - assert.True(t, bond1to1.Equal(resBonds[0])) - assert.True(t, bond1to2.Equal(resBonds[1])) - assert.True(t, bond1to3.Equal(resBonds[2])) + require.True(t, bond1to1.Equal(resBonds[0])) + require.True(t, bond1to2.Equal(resBonds[1])) + require.True(t, bond1to3.Equal(resBonds[2])) resBonds = keeper.GetDelegations(ctx, addrDels[0], 3) require.Equal(t, 3, len(resBonds)) resBonds = keeper.GetDelegations(ctx, addrDels[0], 2) require.Equal(t, 2, len(resBonds)) resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) require.Equal(t, 3, len(resBonds)) - assert.True(t, bond2to1.Equal(resBonds[0])) - assert.True(t, bond2to2.Equal(resBonds[1])) - assert.True(t, bond2to3.Equal(resBonds[2])) + require.True(t, bond2to1.Equal(resBonds[0])) + require.True(t, bond2to2.Equal(resBonds[1])) + require.True(t, bond2to3.Equal(resBonds[2])) allBonds := keeper.GetAllDelegations(ctx) require.Equal(t, 6, len(allBonds)) - assert.True(t, bond1to1.Equal(allBonds[0])) - assert.True(t, bond1to2.Equal(allBonds[1])) - assert.True(t, bond1to3.Equal(allBonds[2])) - assert.True(t, bond2to1.Equal(allBonds[3])) - assert.True(t, bond2to2.Equal(allBonds[4])) - assert.True(t, bond2to3.Equal(allBonds[5])) + require.True(t, bond1to1.Equal(allBonds[0])) + require.True(t, bond1to2.Equal(allBonds[1])) + require.True(t, bond1to3.Equal(allBonds[2])) + require.True(t, bond2to1.Equal(allBonds[3])) + require.True(t, bond2to2.Equal(allBonds[4])) + require.True(t, bond2to3.Equal(allBonds[5])) // delete a record keeper.RemoveDelegation(ctx, bond2to3) _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[2]) - assert.False(t, found) + require.False(t, found) resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) require.Equal(t, 2, len(resBonds)) - assert.True(t, bond2to1.Equal(resBonds[0])) - assert.True(t, bond2to2.Equal(resBonds[1])) + require.True(t, bond2to1.Equal(resBonds[0])) + require.True(t, bond2to2.Equal(resBonds[1])) // delete all the records from delegator 2 keeper.RemoveDelegation(ctx, bond2to1) keeper.RemoveDelegation(ctx, bond2to2) _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[0]) - assert.False(t, found) + require.False(t, found) _, found = keeper.GetDelegation(ctx, addrDels[1], addrVals[1]) - assert.False(t, found) + require.False(t, found) resBonds = keeper.GetDelegations(ctx, addrDels[1], 5) require.Equal(t, 0, len(resBonds)) } @@ -123,20 +122,20 @@ func TestUnbondingDelegation(t *testing.T) { // set and retrieve a record keeper.SetUnbondingDelegation(ctx, ubd) resBond, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - assert.True(t, found) - assert.True(t, ubd.Equal(resBond)) + require.True(t, found) + require.True(t, ubd.Equal(resBond)) // modify a records, save, and retrieve ubd.Balance = sdk.NewCoin("steak", 21) keeper.SetUnbondingDelegation(ctx, ubd) resBond, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - assert.True(t, found) - assert.True(t, ubd.Equal(resBond)) + require.True(t, found) + require.True(t, ubd.Equal(resBond)) // delete a record keeper.RemoveUnbondingDelegation(ctx, ubd) _, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - assert.False(t, found) + require.False(t, found) } func TestUnbondDelegation(t *testing.T) { @@ -166,7 +165,7 @@ func TestUnbondDelegation(t *testing.T) { var amount int64 amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewRat(6)) require.NoError(t, err) - assert.Equal(t, int64(6), amount) // shares to be added to an unbonding delegation / redelegation + require.Equal(t, int64(6), amount) // shares to be added to an unbonding delegation / redelegation delegation, found := keeper.GetDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) @@ -174,10 +173,10 @@ func TestUnbondDelegation(t *testing.T) { require.True(t, found) pool = keeper.GetPool(ctx) - assert.Equal(t, int64(4), delegation.Shares.Evaluate()) - assert.Equal(t, int64(4), validator.PoolShares.Bonded().Evaluate()) - assert.Equal(t, int64(6), pool.LooseTokens, "%v", pool) - assert.Equal(t, int64(4), pool.BondedTokens) + require.Equal(t, int64(4), delegation.Shares.Evaluate()) + require.Equal(t, int64(4), validator.PoolShares.Bonded().Evaluate()) + require.Equal(t, int64(6), pool.LooseTokens, "%v", pool) + require.Equal(t, int64(4), pool.BondedTokens) } // tests Get/Set/Remove/Has UnbondingDelegation @@ -196,28 +195,28 @@ func TestRedelegation(t *testing.T) { // test shouldn't have and redelegations has := keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) - assert.False(t, has) + require.False(t, has) // set and retrieve a record keeper.SetRedelegation(ctx, rd) resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - assert.True(t, found) - assert.True(t, rd.Equal(resBond)) + require.True(t, found) + require.True(t, rd.Equal(resBond)) // check if has the redelegation has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) - assert.True(t, has) + require.True(t, has) // modify a records, save, and retrieve rd.SharesSrc = sdk.NewRat(21) rd.SharesDst = sdk.NewRat(21) keeper.SetRedelegation(ctx, rd) resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - assert.True(t, found) - assert.True(t, rd.Equal(resBond)) + require.True(t, found) + require.True(t, rd.Equal(resBond)) // delete a record keeper.RemoveRedelegation(ctx, rd) _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) - assert.False(t, found) + require.False(t, found) } diff --git a/x/stake/keeper/inflation_test.go b/x/stake/keeper/inflation_test.go index d748ce0cb2..944559dfc2 100644 --- a/x/stake/keeper/inflation_test.go +++ b/x/stake/keeper/inflation_test.go @@ -5,7 +5,6 @@ import ( "strconv" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -61,7 +60,7 @@ func TestGetInflation(t *testing.T) { inflation := keeper.NextInflation(ctx) diffInflation := inflation.Sub(tc.setInflation) - assert.True(t, diffInflation.Equal(tc.expectedChange), + require.True(t, diffInflation.Equal(tc.expectedChange), "Name: %v\nDiff: %v\nExpected: %v\n", tc.name, diffInflation, tc.expectedChange) } } @@ -155,7 +154,7 @@ func TestLargeUnbond(t *testing.T) { pool = keeper.GetPool(ctx) validator, found := keeper.GetValidator(ctx, Addrs[0]) - assert.True(t, found) + require.True(t, found) // initialBondedRatio that we can use to compare to the new values after the unbond initialBondedRatio := pool.BondedRatio() @@ -172,9 +171,9 @@ func TestLargeUnbond(t *testing.T) { unbondedShares = unbondedShares.Add(sdk.NewRat(val0UnbondedTokens, 1).Mul(pool.UnbondedShareExRate())) // unbonded shares should increase - assert.True(t, unbondedShares.GT(sdk.NewRat(300000000, 1))) + require.True(t, unbondedShares.GT(sdk.NewRat(300000000, 1))) // Ensure that new bonded ratio is less than old bonded ratio , because before they were increasing (i.e. 50% < 75) - assert.True(t, (pool.BondedRatio().LT(initialBondedRatio))) + require.True(t, (pool.BondedRatio().LT(initialBondedRatio))) // Final check that the pool equals initial values + provisions and adjustments we recorded pool = keeper.GetPool(ctx) @@ -202,7 +201,7 @@ func TestLargeBond(t *testing.T) { pool = keeper.GetPool(ctx) validator, found := keeper.GetValidator(ctx, Addrs[9]) - assert.True(t, found) + require.True(t, found) // initialBondedRatio that we can use to compare to the new values after the unbond initialBondedRatio := pool.BondedRatio() @@ -220,9 +219,9 @@ func TestLargeBond(t *testing.T) { unbondedShares = unbondedShares.Sub(unbondedSharesVal9) // unbonded shares should decrease - assert.True(t, unbondedShares.LT(sdk.NewRat(1200000000, 1))) + require.True(t, unbondedShares.LT(sdk.NewRat(1200000000, 1))) // Ensure that new bonded ratio is greater than old bonded ratio (i.e. 50% > 25%) - assert.True(t, (pool.BondedRatio().GT(initialBondedRatio))) + require.True(t, (pool.BondedRatio().GT(initialBondedRatio))) // Final check that the pool equals initial values + provisions and adjustments we recorded pool = keeper.GetPool(ctx) @@ -289,7 +288,7 @@ func TestInflationWithRandomOperations(t *testing.T) { // Final check on the global pool values for what the total tokens accumulated from each hour of provisions func checkFinalPoolValues(t *testing.T, pool types.Pool, initialTotalTokens, cumulativeExpProvs int64) { calculatedTotalTokens := initialTotalTokens + cumulativeExpProvs - assert.Equal(t, calculatedTotalTokens, pool.TokenSupply()) + require.Equal(t, calculatedTotalTokens, pool.TokenSupply()) } // Processes provisions are added to the pool correctly every hour @@ -332,14 +331,14 @@ func setupTestValidators(pool types.Pool, keeper Keeper, ctx sdk.Context, valida // Checks that the deterministic validator setup you wanted matches the values in the pool func checkValidatorSetup(t *testing.T, pool types.Pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens int64) { - assert.Equal(t, initialTotalTokens, pool.TokenSupply(), "%v", pool) - assert.Equal(t, initialBondedTokens, pool.BondedTokens, "%v", pool) - assert.Equal(t, initialUnbondedTokens, pool.UnbondedTokens, "%v", pool) + require.Equal(t, initialTotalTokens, pool.TokenSupply(), "%v", pool) + require.Equal(t, initialBondedTokens, pool.BondedTokens, "%v", pool) + require.Equal(t, initialUnbondedTokens, pool.UnbondedTokens, "%v", pool) // test initial bonded ratio - assert.True(t, pool.BondedRatio().Equal(sdk.NewRat(initialBondedTokens, initialTotalTokens)), "%v", pool.BondedRatio()) + require.True(t, pool.BondedRatio().Equal(sdk.NewRat(initialBondedTokens, initialTotalTokens)), "%v", pool.BondedRatio()) // test the value of validator shares - assert.True(t, pool.BondedShareExRate().Equal(sdk.OneRat()), "%v", pool.BondedShareExRate()) + require.True(t, pool.BondedShareExRate().Equal(sdk.OneRat()), "%v", pool.BondedShareExRate()) } // Checks that The inflation will correctly increase or decrease after an update to the pool @@ -349,30 +348,30 @@ func checkInflation(t *testing.T, pool types.Pool, previousInflation, updatedInf switch { //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)): - assert.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio case pool.BondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(20, 100)): if previousInflation.Equal(sdk.NewRat(20, 100)) { - assert.Equal(t, true, inflationChange.IsZero(), msg) + require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) } else { - assert.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + require.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) } //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)) && updatedInflation.GT(sdk.NewRat(7, 100)): - assert.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. case pool.BondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(7, 100)): if previousInflation.Equal(sdk.NewRat(7, 100)) { - assert.Equal(t, true, inflationChange.IsZero(), msg) + require.Equal(t, true, inflationChange.IsZero(), msg) //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) } else { - assert.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + require.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) } } } diff --git a/x/stake/keeper/keeper_test.go b/x/stake/keeper/keeper_test.go index 1be5872850..15fecf3f25 100644 --- a/x/stake/keeper/keeper_test.go +++ b/x/stake/keeper/keeper_test.go @@ -3,7 +3,7 @@ package keeper import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -14,13 +14,13 @@ func TestParams(t *testing.T) { //check that the empty keeper loads the default resParams := keeper.GetParams(ctx) - assert.True(t, expParams.Equal(resParams)) + require.True(t, expParams.Equal(resParams)) //modify a params, save, and retrieve expParams.MaxValidators = 777 keeper.SetParams(ctx, expParams) resParams = keeper.GetParams(ctx) - assert.True(t, expParams.Equal(resParams)) + require.True(t, expParams.Equal(resParams)) } func TestPool(t *testing.T) { @@ -29,11 +29,11 @@ func TestPool(t *testing.T) { //check that the empty keeper loads the default resPool := keeper.GetPool(ctx) - assert.True(t, expPool.Equal(resPool)) + require.True(t, expPool.Equal(resPool)) //modify a params, save, and retrieve expPool.BondedTokens = 777 keeper.SetPool(ctx, expPool) resPool = keeper.GetPool(ctx) - assert.True(t, expPool.Equal(resPool)) + require.True(t, expPool.Equal(resPool)) } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 098c17e75f..cf26d055f6 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -34,7 +34,7 @@ func TestSetValidator(t *testing.T) { // Check each store for being saved resVal, found := keeper.GetValidator(ctx, addrVals[0]) assert.True(ValEq(t, validator, resVal)) - assert.True(t, found) + require.True(t, found) resVals := keeper.GetValidatorsBonded(ctx) require.Equal(t, 1, len(resVals)) @@ -46,7 +46,7 @@ func TestSetValidator(t *testing.T) { updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) - assert.Equal(t, validator.ABCIValidator(), updates[0]) + require.Equal(t, validator.ABCIValidator(), updates[0]) } @@ -68,29 +68,29 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, delSharesCreated := validator.AddTokensFromDel(pool, 100) require.Equal(t, sdk.Unbonded, validator.Status()) - assert.Equal(t, int64(100), validator.PoolShares.Tokens(pool).Evaluate()) + require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).Evaluate()) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - assert.Equal(t, int64(100), validator.PoolShares.Tokens(pool).Evaluate(), "\nvalidator %v\npool %v", validator, pool) + require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).Evaluate(), "\nvalidator %v\npool %v", validator, pool) pool = keeper.GetPool(ctx) power := GetValidatorsByPowerIndexKey(validator, pool) - assert.True(t, keeper.validatorByPowerIndexExists(ctx, power)) + require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) // burn half the delegator shares validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewRat(2))) - assert.Equal(t, int64(50), burned) + require.Equal(t, int64(50), burned) keeper.SetPool(ctx, pool) // update the pool keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out - assert.False(t, keeper.validatorByPowerIndexExists(ctx, power)) + require.False(t, keeper.validatorByPowerIndexExists(ctx, power)) pool = keeper.GetPool(ctx) validator, found = keeper.GetValidator(ctx, addrVals[0]) - assert.True(t, found) + require.True(t, found) power = GetValidatorsByPowerIndexKey(validator, pool) - assert.True(t, keeper.validatorByPowerIndexExists(ctx, power)) + require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) } // This function tests UpdateValidator, GetValidator, GetValidatorsBonded, RemoveValidator @@ -109,7 +109,7 @@ func TestValidatorBasics(t *testing.T) { // check the empty keeper first _, found := keeper.GetValidator(ctx, addrVals[0]) - assert.False(t, found) + require.False(t, found) resVals := keeper.GetValidatorsBonded(ctx) assert.Zero(t, len(resVals)) @@ -154,7 +154,7 @@ func TestValidatorBasics(t *testing.T) { // remove a record keeper.RemoveValidator(ctx, validators[1].Owner) _, found = keeper.GetValidator(ctx, addrVals[1]) - assert.False(t, found) + require.False(t, found) } // test how the validators are sorted, tests GetValidatorsByPower @@ -174,7 +174,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) - require.Equal(t, n, len(resValidators)) + assert.Equal(t, n, len(resValidators)) assert.Equal(t, sdk.NewRat(400), resValidators[0].PoolShares.Bonded(), "%v", resValidators) assert.Equal(t, sdk.NewRat(200), resValidators[1].PoolShares.Bonded(), "%v", resValidators) assert.Equal(t, sdk.NewRat(100), resValidators[2].PoolShares.Bonded(), "%v", resValidators) @@ -209,8 +209,8 @@ func GetValidatorSortingUnmixed(t *testing.T) { require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) assert.True(ValEq(t, validators[4], resValidators[1])) - assert.Equal(t, int64(0), resValidators[0].BondHeight, "%v", resValidators) - assert.Equal(t, int64(0), resValidators[1].BondHeight, "%v", resValidators) + require.Equal(t, int64(0), resValidators[0].BondHeight, "%v", resValidators) + require.Equal(t, int64(0), resValidators[1].BondHeight, "%v", resValidators) // no change in voting power - no change in sort ctx = ctx.WithBlockHeight(20) @@ -269,15 +269,15 @@ func GetValidatorSortingMixed(t *testing.T) { require.True(t, found) val4, found := keeper.GetValidator(ctx, Addrs[4]) require.True(t, found) - assert.Equal(t, sdk.Unbonded, val0.Status()) - assert.Equal(t, sdk.Unbonded, val1.Status()) - assert.Equal(t, sdk.Unbonded, val2.Status()) - assert.Equal(t, sdk.Bonded, val3.Status()) - assert.Equal(t, sdk.Bonded, val4.Status()) + require.Equal(t, sdk.Unbonded, val0.Status()) + require.Equal(t, sdk.Unbonded, val1.Status()) + require.Equal(t, sdk.Unbonded, val2.Status()) + require.Equal(t, sdk.Bonded, val3.Status()) + require.Equal(t, sdk.Bonded, val4.Status()) // first make sure everything made it in to the gotValidator group resValidators := keeper.GetValidatorsByPower(ctx) - require.Equal(t, n, len(resValidators)) + assert.Equal(t, n, len(resValidators)) assert.Equal(t, sdk.NewRat(400), resValidators[0].PoolShares.Bonded(), "%v", resValidators) assert.Equal(t, sdk.NewRat(200), resValidators[1].PoolShares.Bonded(), "%v", resValidators) assert.Equal(t, sdk.NewRat(100), resValidators[2].PoolShares.Bonded(), "%v", resValidators) @@ -438,7 +438,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { assert.Equal(t, sdk.Bonded, validators[3].Status()) assert.Equal(t, sdk.Unbonded, validators[4].Status()) resValidators := keeper.GetValidatorsByPower(ctx) - require.Equal(t, max, len(resValidators)) + assert.Equal(t, max, len(resValidators)) assert.True(ValEq(t, validators[2], resValidators[0])) // in the order of txs assert.True(ValEq(t, validators[3], resValidators[1])) @@ -448,7 +448,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { keeper.SetPool(ctx, pool) validators[0] = keeper.UpdateValidator(ctx, validators[0]) resValidators = keeper.GetValidatorsByPower(ctx) - require.Equal(t, max, len(resValidators)) + assert.Equal(t, max, len(resValidators)) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) } @@ -468,10 +468,10 @@ func TestClearTendermintUpdates(t *testing.T) { } updates := keeper.GetTendermintUpdates(ctx) - assert.Equal(t, len(amts), len(updates)) + require.Equal(t, len(amts), len(updates)) keeper.ClearTendermintUpdates(ctx) updates = keeper.GetTendermintUpdates(ctx) - assert.Equal(t, 0, len(updates)) + require.Equal(t, 0, len(updates)) } func TestGetTendermintUpdatesAllNone(t *testing.T) { @@ -488,25 +488,25 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) { // test from nothing to something // tendermintUpdate set: {} -> {c1, c3} - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) updates := keeper.GetTendermintUpdates(ctx) - require.Equal(t, 2, len(updates)) + assert.Equal(t, 2, len(updates)) assert.Equal(t, validators[0].ABCIValidator(), updates[0]) assert.Equal(t, validators[1].ABCIValidator(), updates[1]) // test from something to nothing // tendermintUpdate set: {} -> {c1, c2, c3, c4} keeper.ClearTendermintUpdates(ctx) - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) keeper.RemoveValidator(ctx, validators[0].Owner) keeper.RemoveValidator(ctx, validators[1].Owner) updates = keeper.GetTendermintUpdates(ctx) - require.Equal(t, 2, len(updates)) + assert.Equal(t, 2, len(updates)) assert.Equal(t, tmtypes.TM2PB.PubKey(validators[0].PubKey), updates[0].PubKey) assert.Equal(t, tmtypes.TM2PB.PubKey(validators[1].PubKey), updates[1].PubKey) assert.Equal(t, int64(0), updates[0].Power) @@ -527,13 +527,13 @@ func TestGetTendermintUpdatesIdentical(t *testing.T) { validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) keeper.ClearTendermintUpdates(ctx) - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test identical, // tendermintUpdate set: {} -> {} validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) } func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { @@ -550,7 +550,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) keeper.ClearTendermintUpdates(ctx) - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test single value change // tendermintUpdate set: {} -> {c1'} @@ -560,7 +560,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) - assert.Equal(t, validators[0].ABCIValidator(), updates[0]) + require.Equal(t, validators[0].ABCIValidator(), updates[0]) } func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { @@ -577,7 +577,7 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) keeper.ClearTendermintUpdates(ctx) - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} @@ -608,7 +608,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) keeper.ClearTendermintUpdates(ctx) - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test validtor added at the beginning // tendermintUpdate set: {} -> {c0} @@ -651,7 +651,7 @@ func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) { validators[0] = keeper.UpdateValidator(ctx, validators[0]) validators[1] = keeper.UpdateValidator(ctx, validators[1]) keeper.ClearTendermintUpdates(ctx) - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test validator added at the end but not inserted in the valset // tendermintUpdate set: {} -> {} @@ -662,7 +662,7 @@ func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) { // test validator change its power and become a gotValidator (pushing out an existing) // tendermintUpdate set: {} -> {c0, c4} keeper.ClearTendermintUpdates(ctx) - assert.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) pool := keeper.GetPool(ctx) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, 10) diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index 343ceb79f3..f3d8bc686f 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -3,7 +3,6 @@ package types import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -39,9 +38,9 @@ func TestMsgCreateValidator(t *testing.T) { description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details) msg := NewMsgCreateValidator(tc.validatorAddr, tc.pubkey, tc.bond, description) if tc.expectPass { - assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) + require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) } else { - assert.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name) + require.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name) } } } @@ -63,9 +62,9 @@ func TestMsgEditValidator(t *testing.T) { description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details) msg := NewMsgEditValidator(tc.validatorAddr, description) if tc.expectPass { - assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) + require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) } else { - assert.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name) + require.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name) } } } @@ -90,9 +89,9 @@ func TestMsgDelegate(t *testing.T) { for _, tc := range tests { msg := NewMsgDelegate(tc.delegatorAddr, tc.validatorAddr, tc.bond) if tc.expectPass { - assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) + require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) } else { - assert.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name) + require.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name) } } } @@ -219,8 +218,8 @@ func TestMsgCompleteUnbonding(t *testing.T) { //var tx sdk.Tx //bs := wire.BinaryBytes(tc.tx) //err := wire.ReadBinaryBytes(bs, &tx) -//if assert.NoError(t, err, "%d", i) { -//assert.Equal(t, tc.tx, tx, "%d", i) +//if require.NoError(t, err, "%d", i) { +//require.Equal(t, tc.tx, tx, "%d", i) //} //} //} diff --git a/x/stake/types/pool_test.go b/x/stake/types/pool_test.go index 21dd4ff4d8..a62c69d468 100644 --- a/x/stake/types/pool_test.go +++ b/x/stake/types/pool_test.go @@ -3,7 +3,6 @@ package types import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -66,48 +65,48 @@ func TestAddTokensBonded(t *testing.T) { poolA := InitialPool() poolA.LooseTokens = 10 - assert.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) poolB, sharesB := poolA.addTokensBonded(10) - assert.Equal(t, poolB.BondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolB.BondedShareExRate(), sdk.OneRat()) // correct changes to bonded shares and bonded pool - assert.Equal(t, poolB.BondedShares, poolA.BondedShares.Add(sharesB.Amount)) - assert.Equal(t, poolB.BondedTokens, poolA.BondedTokens+10) + require.Equal(t, poolB.BondedShares, poolA.BondedShares.Add(sharesB.Amount)) + require.Equal(t, poolB.BondedTokens, poolA.BondedTokens+10) // same number of bonded shares / tokens when exchange rate is one - assert.True(t, poolB.BondedShares.Equal(sdk.NewRat(poolB.BondedTokens))) + require.True(t, poolB.BondedShares.Equal(sdk.NewRat(poolB.BondedTokens))) } func TestRemoveSharesBonded(t *testing.T) { poolA := InitialPool() poolA.LooseTokens = 10 - assert.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) poolB, tokensB := poolA.removeSharesBonded(sdk.NewRat(10)) - assert.Equal(t, poolB.BondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolB.BondedShareExRate(), sdk.OneRat()) // correct changes to bonded shares and bonded pool - assert.Equal(t, poolB.BondedShares, poolA.BondedShares.Sub(sdk.NewRat(10))) - assert.Equal(t, poolB.BondedTokens, poolA.BondedTokens-tokensB) + require.Equal(t, poolB.BondedShares, poolA.BondedShares.Sub(sdk.NewRat(10))) + require.Equal(t, poolB.BondedTokens, poolA.BondedTokens-tokensB) // same number of bonded shares / tokens when exchange rate is one - assert.True(t, poolB.BondedShares.Equal(sdk.NewRat(poolB.BondedTokens))) + require.True(t, poolB.BondedShares.Equal(sdk.NewRat(poolB.BondedTokens))) } func TestAddTokensUnbonded(t *testing.T) { poolA := InitialPool() poolA.LooseTokens = 10 - assert.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) poolB, sharesB := poolA.addTokensUnbonded(10) - assert.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat()) // correct changes to unbonded shares and unbonded pool - assert.Equal(t, poolB.UnbondedShares, poolA.UnbondedShares.Add(sharesB.Amount)) - assert.Equal(t, poolB.UnbondedTokens, poolA.UnbondedTokens+10) + require.Equal(t, poolB.UnbondedShares, poolA.UnbondedShares.Add(sharesB.Amount)) + require.Equal(t, poolB.UnbondedTokens, poolA.UnbondedTokens+10) // same number of unbonded shares / tokens when exchange rate is one - assert.True(t, poolB.UnbondedShares.Equal(sdk.NewRat(poolB.UnbondedTokens))) + require.True(t, poolB.UnbondedShares.Equal(sdk.NewRat(poolB.UnbondedTokens))) } func TestRemoveSharesUnbonded(t *testing.T) { @@ -115,14 +114,14 @@ func TestRemoveSharesUnbonded(t *testing.T) { poolA := InitialPool() poolA.UnbondedTokens = 10 poolA.UnbondedShares = sdk.NewRat(10) - assert.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) poolB, tokensB := poolA.removeSharesUnbonded(sdk.NewRat(10)) - assert.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat()) // correct changes to unbonded shares and bonded pool - assert.Equal(t, poolB.UnbondedShares, poolA.UnbondedShares.Sub(sdk.NewRat(10))) - assert.Equal(t, poolB.UnbondedTokens, poolA.UnbondedTokens-tokensB) + require.Equal(t, poolB.UnbondedShares, poolA.UnbondedShares.Sub(sdk.NewRat(10))) + require.Equal(t, poolB.UnbondedTokens, poolA.UnbondedTokens-tokensB) // same number of unbonded shares / tokens when exchange rate is one - assert.True(t, poolB.UnbondedShares.Equal(sdk.NewRat(poolB.UnbondedTokens))) + require.True(t, poolB.UnbondedShares.Equal(sdk.NewRat(poolB.UnbondedTokens))) } diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 2af3ace407..6a8ff777a6 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -18,10 +18,10 @@ func TestAddTokensValidatorBonded(t *testing.T) { val, pool = val.UpdateStatus(pool, sdk.Bonded) val, pool, delShares := val.AddTokensFromDel(pool, 10) - assert.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) - assert.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) - assert.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) - assert.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) + require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) + require.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) + require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.True(sdk.RatEq(t, sdk.NewRat(10), val.PoolShares.Bonded())) @@ -34,10 +34,10 @@ func TestAddTokensValidatorUnbonding(t *testing.T) { val, pool = val.UpdateStatus(pool, sdk.Unbonding) val, pool, delShares := val.AddTokensFromDel(pool, 10) - assert.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) - assert.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) - assert.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) - assert.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) + require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) + require.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) + require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.True(sdk.RatEq(t, sdk.NewRat(10), val.PoolShares.Unbonding())) @@ -50,10 +50,10 @@ func TestAddTokensValidatorUnbonded(t *testing.T) { val, pool = val.UpdateStatus(pool, sdk.Unbonded) val, pool, delShares := val.AddTokensFromDel(pool, 10) - assert.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) - assert.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) - assert.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) - assert.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) + require.Equal(t, sdk.OneRat(), val.DelegatorShareExRate(pool)) + require.Equal(t, sdk.OneRat(), pool.BondedShareExRate()) + require.Equal(t, sdk.OneRat(), pool.UnbondingShareExRate()) + require.Equal(t, sdk.OneRat(), pool.UnbondedShareExRate()) assert.True(sdk.RatEq(t, sdk.NewRat(10), delShares)) assert.True(sdk.RatEq(t, sdk.NewRat(10), val.PoolShares.Unbonded())) @@ -71,17 +71,17 @@ func TestRemoveDelShares(t *testing.T) { } poolA.BondedTokens = valA.PoolShares.Bonded().Evaluate() poolA.BondedShares = valA.PoolShares.Bonded() - assert.Equal(t, valA.DelegatorShareExRate(poolA), sdk.OneRat()) - assert.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) - assert.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) + require.Equal(t, valA.DelegatorShareExRate(poolA), sdk.OneRat()) + require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) + require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat()) valB, poolB, coinsB := valA.RemoveDelShares(poolA, sdk.NewRat(10)) // coins were created - assert.Equal(t, coinsB, int64(10)) + require.Equal(t, coinsB, int64(10)) // pool shares were removed - assert.Equal(t, valB.PoolShares.Bonded(), valA.PoolShares.Bonded().Sub(sdk.NewRat(10).Mul(valA.DelegatorShareExRate(poolA)))) + require.Equal(t, valB.PoolShares.Bonded(), valA.PoolShares.Bonded().Sub(sdk.NewRat(10).Mul(valA.DelegatorShareExRate(poolA)))) // conservation of tokens - assert.Equal(t, poolB.UnbondedTokens+poolB.BondedTokens+coinsB, poolA.UnbondedTokens+poolA.BondedTokens) + require.Equal(t, poolB.UnbondedTokens+poolB.BondedTokens+coinsB, poolA.UnbondedTokens+poolA.BondedTokens) // specific case from random tests poolShares := sdk.NewRat(5102) @@ -117,28 +117,28 @@ func TestUpdateStatus(t *testing.T) { val := NewValidator(addr1, pk1, Description{}) val, pool, _ = val.AddTokensFromDel(pool, 100) - assert.Equal(t, int64(0), val.PoolShares.Bonded().Evaluate()) - assert.Equal(t, int64(0), val.PoolShares.Unbonding().Evaluate()) - assert.Equal(t, int64(100), val.PoolShares.Unbonded().Evaluate()) - assert.Equal(t, int64(0), pool.BondedTokens) - assert.Equal(t, int64(0), pool.UnbondingTokens) - assert.Equal(t, int64(100), pool.UnbondedTokens) + require.Equal(t, int64(0), val.PoolShares.Bonded().Evaluate()) + require.Equal(t, int64(0), val.PoolShares.Unbonding().Evaluate()) + require.Equal(t, int64(100), val.PoolShares.Unbonded().Evaluate()) + require.Equal(t, int64(0), pool.BondedTokens) + require.Equal(t, int64(0), pool.UnbondingTokens) + require.Equal(t, int64(100), pool.UnbondedTokens) val, pool = val.UpdateStatus(pool, sdk.Unbonding) - assert.Equal(t, int64(0), val.PoolShares.Bonded().Evaluate()) - assert.Equal(t, int64(100), val.PoolShares.Unbonding().Evaluate()) - assert.Equal(t, int64(0), val.PoolShares.Unbonded().Evaluate()) - assert.Equal(t, int64(0), pool.BondedTokens) - assert.Equal(t, int64(100), pool.UnbondingTokens) - assert.Equal(t, int64(0), pool.UnbondedTokens) + require.Equal(t, int64(0), val.PoolShares.Bonded().Evaluate()) + require.Equal(t, int64(100), val.PoolShares.Unbonding().Evaluate()) + require.Equal(t, int64(0), val.PoolShares.Unbonded().Evaluate()) + require.Equal(t, int64(0), pool.BondedTokens) + require.Equal(t, int64(100), pool.UnbondingTokens) + require.Equal(t, int64(0), pool.UnbondedTokens) val, pool = val.UpdateStatus(pool, sdk.Bonded) - assert.Equal(t, int64(100), val.PoolShares.Bonded().Evaluate()) - assert.Equal(t, int64(0), val.PoolShares.Unbonding().Evaluate()) - assert.Equal(t, int64(0), val.PoolShares.Unbonded().Evaluate()) - assert.Equal(t, int64(100), pool.BondedTokens) - assert.Equal(t, int64(0), pool.UnbondingTokens) - assert.Equal(t, int64(0), pool.UnbondedTokens) + require.Equal(t, int64(100), val.PoolShares.Bonded().Evaluate()) + require.Equal(t, int64(0), val.PoolShares.Unbonding().Evaluate()) + require.Equal(t, int64(0), val.PoolShares.Unbonded().Evaluate()) + require.Equal(t, int64(100), pool.BondedTokens) + require.Equal(t, int64(0), pool.UnbondingTokens) + require.Equal(t, int64(0), pool.UnbondedTokens) } func TestPossibleOverflow(t *testing.T) { From 2f508f5b2852c3f08bb6c332d58aae4a01bb593e Mon Sep 17 00:00:00 2001 From: Rigel Date: Fri, 29 Jun 2018 22:04:29 -0400 Subject: [PATCH 61/77] Merge PR #1422: Add Contributing Guidelines * Merge pull request #1422: Add Contributing Guidelines * cwgoes comments --- CHANGELOG.md | 1 + CONTRIBUTING.md | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 6393dd4d53..ae0759e5a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,6 +79,7 @@ IMPROVEMENTS * [stake] edit-validator changes now can use the keyword [do-not-modify] to not modify unspecified `--flag` (aka won't set them to `""` value) * [types] added common tag constants * [stake] offload more generic functionality from the handler into the keeper +* added contributing guidelines ## 0.19.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..c9831cc865 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,105 @@ +# Contributing + +Thank you for considering making contributions to Cosmos-SDK and related repositories! Start by taking a look at this [coding repo](https://github.com/tendermint/coding) for overall information on repository workflow and standards. + +Please follow standard github best practices: fork the repo, branch from the tip of develop, make some commits, and submit a pull request to develop. See the [open issues](https://github.com/cosmos/cosmos-sdk/issues) for things we need help with! + +Please make sure to use `gofmt` before every commit - the easiest way to do this is have your editor run it for you upon saving a file. Additionally please ensure that your code is lint compliant by running `make lint` + +Looking for a good place to start contributing? How about checking out some [good first issues](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) + +## Forking + +Please note that Go requires code to live under absolute paths, which complicates forking. +While my fork lives at `https://github.com/rigeyrigerige/cosmos-sdk`, +the code should never exist at `$GOPATH/src/github.com/rigeyrigerige/cosmos-sdk`. +Instead, we use `git remote` to add the fork as a new remote for the original repo, +`$GOPATH/src/github.com/cosmos/cosmos-sdk `, and do all the work there. + +For instance, to create a fork and work on a branch of it, I would: + + * Create the fork on github, using the fork button. + * Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/cosmos/cosmos-sdk`) + * `git remote rename origin upstream` + * `git remote add origin git@github.com:ebuchman/basecoin.git` + +Now `origin` refers to my fork and `upstream` refers to the Cosmos-SDK version. +So I can `git push -u origin master` to update my fork, and make pull requests to Cosmos-SDK from there. +Of course, replace `ebuchman` with your git handle. + +To pull in updates from the origin repo, run + + * `git fetch upstream` + * `git rebase upstream/master` (or whatever branch you want) + +Please don't make Pull Requests to `master`. + +## Dependencies + +We use [dep](https://github.com/golang/dep) to manage dependencies. + +That said, the master branch of every Cosmos repository should just build +with `go get`, which means they should be kept up-to-date with their +dependencies so we can get away with telling people they can just `go get` our +software. + +Since some dependencies are not under our control, a third party may break our +build, in which case we can fall back on `dep ensure` (or `make +get_vendor_deps`). Even for dependencies under our control, dep helps us to +keep multiple repos in sync as they evolve. Anything with an executable, such +as apps, tools, and the core, should use dep. + +Run `dep status` to get a list of vendor dependencies that may not be +up-to-date. + +## Testing + +All repos should be hooked up to [CircleCI](https://circleci.com/). + +If they have `.go` files in the root directory, they will be automatically +tested by circle using `go test -v -race ./...`. If not, they will need a +`circle.yml`. Ideally, every repo has a `Makefile` that defines `make test` and +includes its continuous integration status using a badge in the `README.md`. + +## Branching Model and Release + +User-facing repos should adhere to the branching model: http://nvie.com/posts/a-successful-git-branching-model/. +That is, these repos should be well versioned, and any merge to master requires a version bump and tagged release. + +Libraries need not follow the model strictly, but would be wise to. + +The SDK utilizes [semantic versioning](https://semver.org/). + +### Development Procedure: +- the latest state of development is on `develop` +- `develop` must never fail `make test` or `make test_cli` +- `develop` should not fail `make test_lint` +- no --force onto `develop` (except when reverting a broken commit, which should seldom happen) +- create a development branch either on github.com/cosmos/cosmos-sdk, or your fork (using `git remote add origin`) +- before submitting a pull request, begin `git rebase` on top of `develop` + +### Pull Merge Procedure: +- ensure pull branch is rebased on develop +- run `make test` and `make test_cli` to ensure that all tests pass +- merge pull request +- push master may request that pull requests be rebased on top of `unstable` + +### Release Procedure: +- start on `develop` +- prepare changelog/release issue +- bump versions +- push to release-vX.X.X to run CI +- merge to master +- merge master back to develop + +### Hotfix Procedure: +- start on `master` +- checkout a new branch named hotfix-vX.X.X +- make the required changes + - these changes should be small and an absolute necessity + - add a note to CHANGELOG.md +- bump versions +- push to hotfix-vX.X.X to run the extended integration tests on the CI +- merge hotfix-vX.X.X to master +- merge hotfix-vX.X.X to develop +- delete the hotfix-vX.X.X branch From 3654579ea79473f7f306816f4fe0c3e0437c6d58 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sat, 30 Jun 2018 05:34:55 +0200 Subject: [PATCH 62/77] Merge PR #1278: Slashing v2 Implement semifinal Gaia slashing spec (#1263), less #1348, #1378, and #1440 which are TBD. --- .circleci/config.yml | 3 +- CHANGELOG.md | 7 + Gopkg.lock | 2 +- client/lcd/lcd_test.go | 24 ++ client/lcd/root.go | 2 + docs/spec/slashing/end_block.md | 53 +-- examples/democoin/mock/validator.go | 7 +- types/stake.go | 8 +- x/slashing/client/rest/query.go | 62 ++++ x/slashing/client/rest/rest.go | 15 + x/slashing/client/rest/tx.go | 103 ++++++ x/slashing/handler.go | 2 +- x/slashing/keeper.go | 35 +- x/slashing/keeper_test.go | 83 +++-- x/slashing/params.go | 17 +- x/slashing/tick.go | 28 +- x/slashing/tick_test.go | 8 +- x/stake/handler_test.go | 85 ++++- x/stake/keeper/delegation.go | 54 +++- x/stake/keeper/slash.go | 236 ++++++++++++-- x/stake/keeper/slash_test.go | 481 ++++++++++++++++++++++++++++ x/stake/types/delegation.go | 3 + x/stake/types/validator.go | 1 + 23 files changed, 1197 insertions(+), 122 deletions(-) create mode 100644 x/slashing/client/rest/query.go create mode 100644 x/slashing/client/rest/rest.go create mode 100644 x/slashing/client/rest/tx.go create mode 100644 x/stake/keeper/slash_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index d58cbad5fc..cf679fe75f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -101,7 +101,7 @@ jobs: test_cover: <<: *defaults - parallelism: 1 + parallelism: 2 steps: - attach_workspace: at: /tmp/workspace @@ -126,6 +126,7 @@ jobs: upload_coverage: <<: *defaults + parallelism: 1 steps: - attach_workspace: at: /tmp/workspace diff --git a/CHANGELOG.md b/CHANGELOG.md index ae0759e5a1..e0b543247a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,13 @@ BREAKING CHANGES * `gaiacli stake complete-unbonding` * `gaiacli stake begin-redelegation` * `gaiacli stake complete-redelegation` +* [slashing] update slashing for unbonding period + * Slash according to power at time of infraction instead of power at + time of discovery + * Iterate through unbonding delegations & redelegations which contributed + to an infraction, slash them proportional to their stake at the time + * Add REST endpoint to unrevoke a validator previously revoked for downtime + * Add REST endpoint to retrieve liveness signing information for a validator FEATURES * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag diff --git a/Gopkg.lock b/Gopkg.lock index a974602f74..c48188cb8d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -443,7 +443,7 @@ "netutil", "trace" ] - revision = "e514e69ffb8bc3c76a71ae40de0118d794855992" + revision = "97aa3a539ec716117a9d15a4659a911f50d13c3c" [[projects]] branch = "master" diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 37d7e91916..049fa04bef 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -25,6 +25,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest" ) @@ -521,6 +522,19 @@ func TestVote(t *testing.T) { require.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option) } +func TestUnrevoke(t *testing.T) { + _, password := "test", "1234567890" + addr, _ := CreateAddr(t, "test", password, GetKB(t)) + cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.Address{addr}) + defer cleanup() + + signingInfo := getSigningInfo(t, port, pks[0].Address()) + tests.WaitForHeight(4, port) + require.Equal(t, true, signingInfo.IndexOffset > 0) + require.Equal(t, int64(0), signingInfo.JailedUntil) + require.Equal(t, true, signingInfo.SignedBlocksCounter > 0) +} + func TestProposalsQuery(t *testing.T) { name, password1 := "test", "1234567890" name2, password2 := "test2", "1234567890" @@ -679,6 +693,16 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Add return resultTx } +func getSigningInfo(t *testing.T, port string, validatorAddr sdk.Address) slashing.ValidatorSigningInfo { + validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr) + res, body := Request(t, port, "GET", "/slashing/signing_info/"+validatorAddrBech, nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + var signingInfo slashing.ValidatorSigningInfo + err := cdc.UnmarshalJSON([]byte(body), &signingInfo) + require.Nil(t, err) + return signingInfo +} + func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.Address) stake.Delegation { delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr) diff --git a/client/lcd/root.go b/client/lcd/root.go index d84e7d9f1c..472c914060 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -22,6 +22,7 @@ import ( bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest" gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest" ibc "github.com/cosmos/cosmos-sdk/x/ibc/client/rest" + slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest" stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest" ) @@ -84,6 +85,7 @@ func createHandler(cdc *wire.Codec) http.Handler { bank.RegisterRoutes(ctx, r, cdc, kb) ibc.RegisterRoutes(ctx, r, cdc, kb) stake.RegisterRoutes(ctx, r, cdc, kb) + slashing.RegisterRoutes(ctx, r, cdc, kb) gov.RegisterRoutes(ctx, r, cdc) return r } diff --git a/docs/spec/slashing/end_block.md b/docs/spec/slashing/end_block.md index 6ac24138ba..e923fd8444 100644 --- a/docs/spec/slashing/end_block.md +++ b/docs/spec/slashing/end_block.md @@ -15,33 +15,28 @@ For some `evidence` to be valid, it must satisfy: where `evidence.Timestamp` is the timestamp in the block at height `evidence.Height` and `block.Timestamp` is the current block timestamp. -If valid evidence is included in a block, the validator's stake is reduced by `SLASH_PROPORTION` of -what their stake was when the equivocation occurred (rather than when the evidence was discovered): +If valid evidence is included in a block, the validator's stake is reduced by `SLASH_PROPORTION` of +what their stake was when the infraction occurred (rather than when the evidence was discovered). +We want to "follow the stake": the stake which contributed to the infraction should be +slashed, even if it has since been redelegated or started unbonding. + +We first need to loop through the unbondings and redelegations from the slashed validator +and track how much stake has since moved: ``` -curVal := validator -oldVal := loadValidator(evidence.Height, evidence.Address) +slashAmountUnbondings := 0 +slashAmountRedelegations := 0 -slashAmount := SLASH_PROPORTION * oldVal.Shares - -curVal.Shares = max(0, curVal.Shares - slashAmount) -``` - -This ensures that offending validators are punished the same amount whether they -act as a single validator with X stake or as N validators with collectively X -stake. - -We also need to loop through the unbondings and redelegations to slash them as -well: - -``` unbondings := getUnbondings(validator.Address) for unbond in unbondings { - if was not bonded before evidence.Height { + + if was not bonded before evidence.Height or started unbonding before unbonding period ago { continue } - unbond.InitialTokens + burn := unbond.InitialTokens * SLASH_PROPORTION + slashAmountUnbondings += burn + unbond.Tokens = max(0, unbond.Tokens - burn) } @@ -51,17 +46,35 @@ for unbond in unbondings { redels := getRedelegationsBySource(validator.Address) for redel in redels { - if was not bonded before evidence.Height { + if was not bonded before evidence.Height or started redelegating before unbonding period ago { continue } burn := redel.InitialTokens * SLASH_PROPORTION + slashAmountRedelegations += burn amount := unbondFromValidator(redel.Destination, burn) destroy(amount) } ``` +We then slash the validator: + +``` +curVal := validator +oldVal := loadValidator(evidence.Height, evidence.Address) + +slashAmount := SLASH_PROPORTION * oldVal.Shares +slashAmount -= slashAmountUnbondings +slashAmount -= slashAmountRedelegations + +curVal.Shares = max(0, curVal.Shares - slashAmount) +``` + +This ensures that offending validators are punished the same amount whether they +act as a single validator with X stake or as N validators with collectively X +stake. + ## Automatic Unbonding At the beginning of each block, we update the signing info for each validator and check if they should be automatically unbonded: diff --git a/examples/democoin/mock/validator.go b/examples/democoin/mock/validator.go index 869c48dcb6..8b1d34c7b4 100644 --- a/examples/democoin/mock/validator.go +++ b/examples/democoin/mock/validator.go @@ -38,6 +38,11 @@ func (v Validator) GetDelegatorShares() sdk.Rat { return sdk.ZeroRat() } +// Implements sdk.Validator +func (v Validator) GetRevoked() bool { + return false +} + // Implements sdk.Validator func (v Validator) GetBondHeight() int64 { return 0 @@ -107,7 +112,7 @@ func (vs *ValidatorSet) RemoveValidator(addr sdk.Address) { } // Implements sdk.ValidatorSet -func (vs *ValidatorSet) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, amt sdk.Rat) { +func (vs *ValidatorSet) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, power int64, amt sdk.Rat) { panic("not implemented") } diff --git a/types/stake.go b/types/stake.go index 0f0855b37f..8625b617e5 100644 --- a/types/stake.go +++ b/types/stake.go @@ -32,6 +32,7 @@ func BondStatusToString(b BondStatus) string { // validator for a delegated proof of stake system type Validator interface { + GetRevoked() bool // whether the validator is revoked GetMoniker() string // moniker of the validator GetStatus() BondStatus // status of the validator GetOwner() Address // owner address to receive/return validators coins @@ -62,9 +63,10 @@ type ValidatorSet interface { Validator(Context, Address) Validator // get a particular validator by owner address TotalPower(Context) Rat // total power of the validator set - Slash(Context, crypto.PubKey, int64, Rat) // slash the validator and delegators of the validator, specifying offence height & slash fraction - Revoke(Context, crypto.PubKey) // revoke a validator - Unrevoke(Context, crypto.PubKey) // unrevoke a validator + // slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction + Slash(Context, crypto.PubKey, int64, int64, Rat) + Revoke(Context, crypto.PubKey) // revoke a validator + Unrevoke(Context, crypto.PubKey) // unrevoke a validator } //_______________________________________________________________________________ diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go new file mode 100644 index 0000000000..9842ada732 --- /dev/null +++ b/x/slashing/client/rest/query.go @@ -0,0 +1,62 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/slashing" +) + +func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { + r.HandleFunc( + "/slashing/signing_info/{validator}", + signingInfoHandlerFn(ctx, "slashing", cdc), + ).Methods("GET") +} + +// http request handler to query signing info +func signingInfoHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + // read parameters + vars := mux.Vars(r) + bech32validator := vars["validator"] + + validatorAddr, err := sdk.GetValAddressBech32(bech32validator) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + key := slashing.GetValidatorSigningInfoKey(validatorAddr) + res, err := ctx.QueryStore(key, storeName) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("couldn't query signing info. Error: %s", err.Error()))) + return + } + + var signingInfo slashing.ValidatorSigningInfo + err = cdc.UnmarshalBinary(res, &signingInfo) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("couldn't decode signing info. Error: %s", err.Error()))) + return + } + + output, err := cdc.MarshalJSON(signingInfo) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + w.Write(output) + } +} diff --git a/x/slashing/client/rest/rest.go b/x/slashing/client/rest/rest.go new file mode 100644 index 0000000000..156d400334 --- /dev/null +++ b/x/slashing/client/rest/rest.go @@ -0,0 +1,15 @@ +package rest + +import ( + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/wire" +) + +// RegisterRoutes registers staking-related REST handlers to a router +func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + registerQueryRoutes(ctx, r, cdc) + registerTxRoutes(ctx, r, cdc, kb) +} diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go new file mode 100644 index 0000000000..212487ddf1 --- /dev/null +++ b/x/slashing/client/rest/tx.go @@ -0,0 +1,103 @@ +package rest + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/crypto/keys" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/slashing" +) + +func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + r.HandleFunc( + "/slashing/unrevoke", + unrevokeRequestHandlerFn(cdc, kb, ctx), + ).Methods("POST") +} + +// Unrevoke TX body +type UnrevokeBody struct { + LocalAccountName string `json:"name"` + Password string `json:"password"` + ChainID string `json:"chain_id"` + AccountNumber int64 `json:"account_number"` + Sequence int64 `json:"sequence"` + Gas int64 `json:"gas"` + ValidatorAddr string `json:"validator_addr"` +} + +func unrevokeRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var m UnrevokeBody + body, err := ioutil.ReadAll(r.Body) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + err = json.Unmarshal(body, &m) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + info, err := kb.Get(m.LocalAccountName) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(err.Error())) + return + } + + validatorAddr, err := sdk.GetAccAddressBech32(m.ValidatorAddr) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) + return + } + + if !bytes.Equal(info.GetPubKey().Address(), validatorAddr) { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("Must use own validator address")) + return + } + + ctx = ctx.WithGas(m.Gas) + ctx = ctx.WithChainID(m.ChainID) + ctx = ctx.WithAccountNumber(m.AccountNumber) + ctx = ctx.WithSequence(m.Sequence) + + msg := slashing.NewMsgUnrevoke(validatorAddr) + + txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(err.Error())) + return + } + + res, err := ctx.BroadcastTx(txBytes) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + output, err := json.MarshalIndent(res, "", " ") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + w.Write(output) + } +} diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 5994bb8f19..e786f34aca 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -50,7 +50,7 @@ func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { // Unrevoke the validator k.validatorSet.Unrevoke(ctx, validator.GetPubKey()) - tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes()) + tags := sdk.NewTags("action", []byte("unrevoke"), "validator", []byte(msg.ValidatorAddr.String())) return sdk.Result{ Tags: tags, diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 1d62e6daff..9ad1c1ea25 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -30,28 +30,40 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, codespace } // handle a validator signing two blocks at the same height -func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, pubkey crypto.PubKey) { +func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, timestamp int64, power int64) { logger := ctx.Logger().With("module", "x/slashing") - age := ctx.BlockHeader().Time - timestamp + time := ctx.BlockHeader().Time + age := time - timestamp + address := pubkey.Address() // Double sign too old if age > MaxEvidenceAge { - logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) + logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), infractionHeight, age, MaxEvidenceAge)) return } // Double sign confirmed - logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) - k.validatorSet.Slash(ctx, pubkey, height, SlashFractionDoubleSign) + logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), infractionHeight, age, MaxEvidenceAge)) + + // Slash validator + k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, SlashFractionDoubleSign) + + // Revoke validator + k.validatorSet.Revoke(ctx, pubkey) + + // Jail validator + signInfo, found := k.getValidatorSigningInfo(ctx, address) + if !found { + panic(fmt.Sprintf("Expected signing info for validator %s but not found", address)) + } + signInfo.JailedUntil = time + DoubleSignUnbondDuration + k.setValidatorSigningInfo(ctx, address, signInfo) } // handle a validator signature, must be called once per validator per block -func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, signed bool) { +func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, power int64, signed bool) { logger := ctx.Logger().With("module", "x/slashing") height := ctx.BlockHeight() - if !signed { - logger.Info(fmt.Sprintf("Absent validator %s at height %d", pubkey.Address(), height)) - } address := pubkey.Address() // Local index, so counts blocks validator *should* have signed @@ -80,11 +92,14 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, signInfo.SignedBlocksCounter++ } + if !signed { + logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", pubkey.Address(), height, signInfo.SignedBlocksCounter, MinSignedPerWindow)) + } minHeight := signInfo.StartHeight + SignedBlocksWindow if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { // Downtime confirmed, slash, revoke, and jail the validator logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow)) - k.validatorSet.Slash(ctx, pubkey, height, SlashFractionDowntime) + k.validatorSet.Slash(ctx, pubkey, height, power, SlashFractionDowntime) k.validatorSet.Revoke(ctx, pubkey) signInfo.JailedUntil = ctx.BlockHeader().Time + DowntimeUnbondDuration } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 2a722a2bad..debeda6cca 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -11,26 +11,45 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake" ) +// Have to change these parameters for tests +// lest the tests take forever +func init() { + SignedBlocksWindow = 1000 + MinSignedPerWindow = SignedBlocksWindow / 2 + DowntimeUnbondDuration = 60 * 60 + DoubleSignUnbondDuration = 60 * 60 +} + // Test that a validator is slashed correctly -// when we discover evidence of equivocation +// when we discover evidence of infraction func TestHandleDoubleSign(t *testing.T) { // initial setup ctx, ck, sk, keeper := createTestInput(t) - addr, val, amt := addrs[0], pks[0], sdk.NewInt(100) + amtInt := int64(100) + addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewRatFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + // handle a signature to set signing info + keeper.handleValidatorSignature(ctx, val, amtInt, true) + // double sign less than max age - keeper.handleDoubleSign(ctx, 0, 0, val) + keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) + + // should be revoked + require.True(t, sk.Validator(ctx, addr).GetRevoked()) + // unrevoke to measure power + sk.Unrevoke(ctx, val) + // power should be reduced require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) - ctx = ctx.WithBlockHeader(abci.Header{Time: 300}) + ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + MaxEvidenceAge}) // double sign past max age - keeper.handleDoubleSign(ctx, 0, 0, val) + keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) } @@ -40,7 +59,8 @@ func TestHandleAbsentValidator(t *testing.T) { // initial setup ctx, ck, sk, keeper := createTestInput(t) - addr, val, amt := addrs[0], pks[0], sdk.NewInt(100) + amtInt := int64(100) + addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) sh := stake.NewHandler(sk) slh := NewHandler(keeper) got := sh(ctx, newTestMsgCreateValidator(addr, val, amt)) @@ -57,38 +77,38 @@ func TestHandleAbsentValidator(t *testing.T) { height := int64(0) // 1000 first blocks OK - for ; height < 1000; height++ { + for ; height < SignedBlocksWindow; height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, true) + keeper.handleValidatorSignature(ctx, val, amtInt, true) } info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow, info.SignedBlocksCounter) - // 50 blocks missed - for ; height < 1050; height++ { + // 500 blocks missed + for ; height < SignedBlocksWindow+(SignedBlocksWindow-MinSignedPerWindow); height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, false) + keeper.handleValidatorSignature(ctx, val, amtInt, false) } info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, SignedBlocksWindow-50, info.SignedBlocksCounter) + require.Equal(t, SignedBlocksWindow-MinSignedPerWindow, info.SignedBlocksCounter) // validator should be bonded still validator, _ := sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) - require.Equal(t, int64(100), pool.BondedTokens) + require.Equal(t, int64(amtInt), pool.BondedTokens) - // 51st block missed + // 501st block missed ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, false) + keeper.handleValidatorSignature(ctx, val, amtInt, false) info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) + require.Equal(t, SignedBlocksWindow-MinSignedPerWindow-1, info.SignedBlocksCounter) // validator should have been revoked validator, _ = sk.GetValidatorByPubKey(ctx, val) @@ -99,7 +119,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.False(t, got.IsOK()) // unrevocation should succeed after jail expiration - ctx = ctx.WithBlockHeader(abci.Header{Time: int64(86400 * 2)}) + ctx = ctx.WithBlockHeader(abci.Header{Time: DowntimeUnbondDuration + 1}) got = slh(ctx, NewMsgUnrevoke(addr)) require.True(t, got.IsOK()) @@ -109,26 +129,33 @@ func TestHandleAbsentValidator(t *testing.T) { // validator should have been slashed pool = sk.GetPool(ctx) - require.Equal(t, int64(99), pool.BondedTokens) + require.Equal(t, int64(amtInt-1), pool.BondedTokens) // validator start height should have been changed info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) require.True(t, found) require.Equal(t, height, info.StartHeight) - require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) + require.Equal(t, SignedBlocksWindow-MinSignedPerWindow-1, info.SignedBlocksCounter) // validator should not be immediately revoked again height++ ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, false) + keeper.handleValidatorSignature(ctx, val, amtInt, false) validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) - // validator should be revoked again after 100 unsigned blocks - nextHeight := height + 100 + // 500 signed blocks + nextHeight := height + MinSignedPerWindow + 1 + for ; height < nextHeight; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.handleValidatorSignature(ctx, val, amtInt, false) + } + + // validator should be revoked again after 500 unsigned blocks + nextHeight = height + MinSignedPerWindow + 1 for ; height <= nextHeight; height++ { ctx = ctx.WithBlockHeight(height) - keeper.handleValidatorSignature(ctx, val, false) + keeper.handleValidatorSignature(ctx, val, amtInt, false) } validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) @@ -149,16 +176,16 @@ func TestHandleNewValidator(t *testing.T) { require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) // 1000 first blocks not a validator - ctx = ctx.WithBlockHeight(1001) + ctx = ctx.WithBlockHeight(SignedBlocksWindow + 1) // Now a validator, for two blocks - keeper.handleValidatorSignature(ctx, val, true) - ctx = ctx.WithBlockHeight(1002) - keeper.handleValidatorSignature(ctx, val, false) + keeper.handleValidatorSignature(ctx, val, 100, true) + ctx = ctx.WithBlockHeight(SignedBlocksWindow + 2) + keeper.handleValidatorSignature(ctx, val, 100, false) info, found := keeper.getValidatorSigningInfo(ctx, val.Address()) require.True(t, found) - require.Equal(t, int64(1001), info.StartHeight) + require.Equal(t, int64(SignedBlocksWindow+1), info.StartHeight) require.Equal(t, int64(2), info.IndexOffset) require.Equal(t, int64(1), info.SignedBlocksCounter) require.Equal(t, int64(0), info.JailedUntil) diff --git a/x/slashing/params.go b/x/slashing/params.go index 3bba85fa66..ebf14f283d 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -const ( +var ( // MaxEvidenceAge - Max age for evidence - 21 days (3 weeks) // TODO Should this be a governance parameter or just modifiable with SoftwareUpgradeProposals? // MaxEvidenceAge = 60 * 60 * 24 * 7 * 3 @@ -13,17 +13,22 @@ const ( // SignedBlocksWindow - sliding window for downtime slashing // TODO Governance parameter? - // TODO Temporarily set to 100 blocks for testnets - SignedBlocksWindow int64 = 100 + // TODO Temporarily set to 40000 blocks for testnets + SignedBlocksWindow int64 = 40000 // Downtime slashing threshold - 50% // TODO Governance parameter? - MinSignedPerWindow int64 = SignedBlocksWindow / 2 + MinSignedPerWindow = SignedBlocksWindow / 2 // Downtime unbond duration // TODO Governance parameter? - // TODO Temporarily set to 10 minutes for testnets - DowntimeUnbondDuration int64 = 60 * 10 + // TODO Temporarily set to five minutes for testnets + DowntimeUnbondDuration int64 = 60 * 5 + + // Double-sign unbond duration + // TODO Governance parameter? + // TODO Temporarily set to five minutes for testnets + DoubleSignUnbondDuration int64 = 60 * 5 ) var ( diff --git a/x/slashing/tick.go b/x/slashing/tick.go index 43ffdb947c..01984f870b 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -16,7 +16,21 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags binary.LittleEndian.PutUint64(heightBytes, uint64(req.Header.Height)) tags = sdk.NewTags("height", heightBytes) - // Deal with any equivocation evidence + // Iterate over all the validators which *should* have signed this block + // Store whether or not they have actually signed it and slash/unbond any + // which have missed too many blocks in a row (downtime slashing) + for _, signingValidator := range req.Validators { + present := signingValidator.SignedLastBlock + pubkey, err := tmtypes.PB2TM.PubKey(signingValidator.Validator.PubKey) + if err != nil { + panic(err) + } + sk.handleValidatorSignature(ctx, pubkey, signingValidator.Validator.Power, present) + } + + // Iterate through any newly discovered evidence of infraction + // Slash any validators (and since-unbonded stake within the unbonding period) + // who contributed to valid infractions for _, evidence := range req.ByzantineValidators { pk, err := tmtypes.PB2TM.PubKey(evidence.Validator.PubKey) if err != nil { @@ -24,21 +38,11 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags } switch evidence.Type { case tmtypes.ABCIEvidenceTypeDuplicateVote: - sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) + sk.handleDoubleSign(ctx, pk, evidence.Height, evidence.Time, evidence.Validator.Power) default: ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("ignored unknown evidence type: %s", evidence.Type)) } } - // Iterate over all the validators which *should* have signed this block - for _, validator := range req.Validators { - present := validator.SignedLastBlock - pubkey, err := tmtypes.PB2TM.PubKey(validator.Validator.PubKey) - if err != nil { - panic(err) - } - sk.handleValidatorSignature(ctx, pubkey, present) - } - return } diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index a5cf47de50..42a476a4ce 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -46,8 +46,8 @@ func TestBeginBlocker(t *testing.T) { height := int64(0) - // for 50 blocks, mark the validator as having signed - for ; height < 50; height++ { + // for 1000 blocks, mark the validator as having signed + for ; height < SignedBlocksWindow; height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ Validators: []abci.SigningValidator{{ @@ -58,8 +58,8 @@ func TestBeginBlocker(t *testing.T) { BeginBlocker(ctx, req, keeper) } - // for 51 blocks, mark the validator as having not signed - for ; height < 102; height++ { + // for 500 blocks, mark the validator as having not signed + for ; height < ((SignedBlocksWindow * 2) - MinSignedPerWindow + 1); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ Validators: []abci.SigningValidator{{ diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index ef47318c68..e6cd6f4ca7 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -74,7 +74,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // slash and revoke the first validator - keeper.Slash(ctx, keep.PKs[0], 0, sdk.NewRat(1, 2)) + keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewRat(1, 2)) keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -559,3 +559,86 @@ func TestTransitiveRedelegation(t *testing.T) { got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error") } + +func TestBondUnbondRedelegateSlashTwice(t *testing.T) { + ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + valA, valB, del := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2] + + msgCreateValidator := newTestMsgCreateValidator(valA, keep.PKs[0], 10) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + + msgCreateValidator = newTestMsgCreateValidator(valB, keep.PKs[1], 10) + got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + + // delegate 10 stake + msgDelegate := newTestMsgDelegate(del, valA, 10) + got = handleMsgDelegate(ctx, msgDelegate, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgDelegate") + + // a block passes + ctx = ctx.WithBlockHeight(1) + + // begin unbonding 4 stake + msgBeginUnbonding := NewMsgBeginUnbonding(del, valA, sdk.NewRat(4)) + got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") + + // begin redelegate 6 stake + msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, sdk.NewRat(6)) + got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate") + + // destination delegation should have 6 shares + delegation, found := keeper.GetDelegation(ctx, del, valB) + require.True(t, found) + require.Equal(t, sdk.NewRat(6), delegation.Shares) + + // slash the validator by half + keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewRat(1, 2)) + + // unbonding delegation should have been slashed by half + unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) + require.True(t, found) + require.Equal(t, int64(2), unbonding.Balance.Amount.Int64()) + + // redelegation should have been slashed by half + redelegation, found := keeper.GetRedelegation(ctx, del, valA, valB) + require.True(t, found) + require.Equal(t, int64(3), redelegation.Balance.Amount.Int64()) + + // destination delegation should have been slashed by half + delegation, found = keeper.GetDelegation(ctx, del, valB) + require.True(t, found) + require.Equal(t, sdk.NewRat(3), delegation.Shares) + + // validator power should have been reduced by half + validator, found := keeper.GetValidator(ctx, valA) + require.True(t, found) + require.Equal(t, sdk.NewRat(5), validator.GetPower()) + + // slash the validator for an infraction committed after the unbonding and redelegation begin + ctx = ctx.WithBlockHeight(3) + keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewRat(1, 2)) + + // unbonding delegation should be unchanged + unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) + require.True(t, found) + require.Equal(t, int64(2), unbonding.Balance.Amount.Int64()) + + // redelegation should be unchanged + redelegation, found = keeper.GetRedelegation(ctx, del, valA, valB) + require.True(t, found) + require.Equal(t, int64(3), redelegation.Balance.Amount.Int64()) + + // destination delegation should be unchanged + delegation, found = keeper.GetDelegation(ctx, del, valB) + require.True(t, found) + require.Equal(t, sdk.NewRat(3), delegation.Shares) + + // validator power should have been reduced to zero + validator, found = keeper.GetValidator(ctx, valA) + require.True(t, found) + require.Equal(t, sdk.NewRat(0), validator.GetPower()) +} diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index aab1dda90c..514939e17f 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -95,6 +95,26 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, return ubd, true } +// load all unbonding delegations from a particular validator +func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (unbondingDelegations []types.UnbondingDelegation) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr, k.cdc)) + i := 0 + for ; ; i++ { + if !iterator.Valid() { + break + } + unbondingKey := iterator.Value() + unbondingBytes := store.Get(unbondingKey) + var unbondingDelegation types.UnbondingDelegation + k.cdc.MustUnmarshalBinary(unbondingBytes, &unbondingDelegation) + unbondingDelegations = append(unbondingDelegations, unbondingDelegation) + iterator.Next() + } + iterator.Close() + return unbondingDelegations +} + // set the unbonding delegation and associated index func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) @@ -129,6 +149,26 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, return red, true } +// load all redelegations from a particular validator +func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (redelegations []types.Redelegation) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr, k.cdc)) + i := 0 + for ; ; i++ { + if !iterator.Valid() { + break + } + redelegationKey := iterator.Value() + redelegationBytes := store.Get(redelegationKey) + var redelegation types.Redelegation + k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation) + redelegations = append(redelegations, redelegation) + iterator.Next() + } + iterator.Close() + return redelegations +} + // has a redelegation func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, DelegatorAddr, ValidatorDstAddr sdk.Address) bool { @@ -254,7 +294,7 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.Address k.RemoveValidator(ctx, validator.Owner) } - return amount, nil + return } //______________________________________________________________________________________________________ @@ -270,12 +310,14 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk // create the unbonding delegation params := k.GetParams(ctx) minTime := ctx.BlockHeader().Time + params.UnbondingTime + balance := sdk.Coin{params.BondDenom, sdk.NewInt(returnAmount)} ubd := types.UnbondingDelegation{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, - MinTime: minTime, - Balance: sdk.Coin{params.BondDenom, sdk.NewInt(returnAmount)}, + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + MinTime: minTime, + Balance: balance, + InitialBalance: balance, } k.SetUnbondingDelegation(ctx, ubd) return nil @@ -338,6 +380,8 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd MinTime: minTime, SharesDst: sharesCreated, SharesSrc: sharesAmount, + Balance: returnCoin, + InitialBalance: returnCoin, } k.SetRedelegation(ctx, red) return nil diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 3abfe455cd..9d4c9af62e 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -4,56 +4,234 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/tendermint/tendermint/crypto" ) -// NOTE the current slash functionality doesn't take into consideration unbonding/rebonding records -// or the time of breach. This will be updated in slashing v2 -// slash a validator -func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fraction sdk.Rat) { +// Slash a validator for an infraction committed at a known height +// Find the contributing stake at that height and burn the specified slashFactor +// of it, updating unbonding delegation & redelegations appropriately +// +// CONTRACT: +// slashFactor is non-negative +// CONTRACT: +// Validator exists and can be looked up by public key +// CONTRACT: +// Infraction committed equal to or less than an unbonding period in the past, +// so all unbonding delegations and redelegations from that height are stored +// CONTRACT: +// Infraction committed at the current height or at a past height, +// not at a height in the future +func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Rat) { + logger := ctx.Logger().With("module", "x/stake") + + if slashFactor.LT(sdk.ZeroRat()) { + panic(fmt.Errorf("attempted to slash with a negative slashFactor: %v", slashFactor)) + } + + // Amount of slashing = slash slashFactor * power at time of infraction + slashAmount := sdk.NewRat(power).Mul(slashFactor).EvaluateInt() + // ref https://github.com/cosmos/cosmos-sdk/issues/1348 + // ref https://github.com/cosmos/cosmos-sdk/issues/1471 - // TODO height ignored for now, see https://github.com/cosmos/cosmos-sdk/pull/1011#issuecomment-390253957 validator, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { - panic(fmt.Errorf("Attempted to slash a nonexistent validator with address %s", pubkey.Address())) + panic(fmt.Errorf("attempted to slash a nonexistent validator with address %s", pubkey.Address())) } - sharesToRemove := validator.PoolShares.Amount.Mul(fraction) - pool := k.GetPool(ctx) - validator, pool, burned := validator.RemovePoolShares(pool, sharesToRemove) - k.SetPool(ctx, pool) // update the pool - k.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out + ownerAddress := validator.GetOwner() - logger := ctx.Logger().With("module", "x/stake") - logger.Info(fmt.Sprintf("Validator %s slashed by fraction %v, removed %v shares and burned %d tokens", pubkey.Address(), fraction, sharesToRemove, burned)) + // Track remaining slash amount for the validator + // This will decrease when we slash unbondings and + // redelegations, as that stake has since unbonded + remainingSlashAmount := slashAmount + + switch { + case infractionHeight > ctx.BlockHeight(): + // Can't slash infractions in the future + panic(fmt.Sprintf("impossible attempt to slash future infraction at height %d but we are at height %d", infractionHeight, ctx.BlockHeight())) + + case infractionHeight == ctx.BlockHeight(): + // Special-case slash at current height for efficiency - we don't need to look through unbonding delegations or redelegations + logger.Info(fmt.Sprintf("Slashing at current height %d, not scanning unbonding delegations & redelegations", infractionHeight)) + + case infractionHeight < ctx.BlockHeight(): + // Iterate through unbonding delegations from slashed validator + unbondingDelegations := k.GetUnbondingDelegationsFromValidator(ctx, ownerAddress) + for _, unbondingDelegation := range unbondingDelegations { + amountSlashed := k.slashUnbondingDelegation(ctx, unbondingDelegation, infractionHeight, slashFactor) + if amountSlashed.IsZero() { + continue + } + remainingSlashAmount = remainingSlashAmount.Sub(amountSlashed) + } + + // Iterate through redelegations from slashed validator + redelegations := k.GetRedelegationsFromValidator(ctx, ownerAddress) + for _, redelegation := range redelegations { + amountSlashed := k.slashRedelegation(ctx, validator, redelegation, infractionHeight, slashFactor) + if amountSlashed.IsZero() { + continue + } + remainingSlashAmount = remainingSlashAmount.Sub(amountSlashed) + } + + } + + // Cannot decrease balance below zero + sharesToRemove := remainingSlashAmount + if sharesToRemove.GT(validator.PoolShares.Amount.EvaluateInt()) { + sharesToRemove = validator.PoolShares.Amount.EvaluateInt() + } + + // Get the current pool + pool := k.GetPool(ctx) + // remove shares from the validator + validator, pool, burned := validator.RemovePoolShares(pool, sdk.NewRatFromInt(sharesToRemove)) + // burn tokens + pool.LooseTokens -= burned + // update the pool + k.SetPool(ctx, pool) + // update the validator, possibly kicking it out + k.UpdateValidator(ctx, validator) + + // Log that a slash occurred! + logger.Info(fmt.Sprintf("Validator %s slashed by slashFactor %v, removed %v shares and burned %d tokens", pubkey.Address(), slashFactor, sharesToRemove, burned)) + + // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return } // revoke a validator func (k Keeper) Revoke(ctx sdk.Context, pubkey crypto.PubKey) { - - validator, found := k.GetValidatorByPubKey(ctx, pubkey) - if !found { - panic(fmt.Errorf("Validator with pubkey %s not found, cannot revoke", pubkey)) - } - validator.Revoked = true - k.UpdateValidator(ctx, validator) // update the validator, now revoked - + k.setRevoked(ctx, pubkey, true) logger := ctx.Logger().With("module", "x/stake") logger.Info(fmt.Sprintf("Validator %s revoked", pubkey.Address())) + // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return } // unrevoke a validator func (k Keeper) Unrevoke(ctx sdk.Context, pubkey crypto.PubKey) { - - validator, found := k.GetValidatorByPubKey(ctx, pubkey) - if !found { - panic(fmt.Errorf("Validator with pubkey %s not found, cannot unrevoke", pubkey)) - } - validator.Revoked = false - k.UpdateValidator(ctx, validator) // update the validator, now unrevoked - + k.setRevoked(ctx, pubkey, false) logger := ctx.Logger().With("module", "x/stake") logger.Info(fmt.Sprintf("Validator %s unrevoked", pubkey.Address())) + // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return } + +// set the revoked flag on a validator +func (k Keeper) setRevoked(ctx sdk.Context, pubkey crypto.PubKey, revoked bool) { + validator, found := k.GetValidatorByPubKey(ctx, pubkey) + if !found { + panic(fmt.Errorf("Validator with pubkey %s not found, cannot set revoked to %v", pubkey, revoked)) + } + validator.Revoked = revoked + k.UpdateValidator(ctx, validator) // update validator, possibly unbonding or bonding it + return +} + +// slash an unbonding delegation and update the pool +// return the amount that would have been slashed assuming +// the unbonding delegation had enough stake to slash +// (the amount actually slashed may be less if there's +// insufficient stake remaining) +func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Int) { + now := ctx.BlockHeader().Time + + // If unbonding started before this height, stake didn't contribute to infraction + if unbondingDelegation.CreationHeight < infractionHeight { + return sdk.ZeroInt() + } + + if unbondingDelegation.MinTime < now { + // Unbonding delegation no longer eligible for slashing, skip it + // TODO Settle and delete it automatically? + return sdk.ZeroInt() + } + + // Calculate slash amount proportional to stake contributing to infraction + slashAmount = sdk.NewRatFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor).EvaluateInt() + + // Don't slash more tokens than held + // Possible since the unbonding delegation may already + // have been slashed, and slash amounts are calculated + // according to stake held at time of infraction + unbondingSlashAmount := slashAmount + if unbondingSlashAmount.GT(unbondingDelegation.Balance.Amount) { + unbondingSlashAmount = unbondingDelegation.Balance.Amount + } + + // Update unbonding delegation if necessary + if !unbondingSlashAmount.IsZero() { + unbondingDelegation.Balance.Amount = unbondingDelegation.Balance.Amount.Sub(unbondingSlashAmount) + k.SetUnbondingDelegation(ctx, unbondingDelegation) + pool := k.GetPool(ctx) + // Burn loose tokens + // Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760 + pool.LooseTokens -= slashAmount.Int64() + k.SetPool(ctx, pool) + } + + return +} + +// slash a redelegation and update the pool +// return the amount that would have been slashed assuming +// the unbonding delegation had enough stake to slash +// (the amount actually slashed may be less if there's +// insufficient stake remaining) +func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation, infractionHeight int64, slashFactor sdk.Rat) (slashAmount sdk.Int) { + now := ctx.BlockHeader().Time + + // If redelegation started before this height, stake didn't contribute to infraction + if redelegation.CreationHeight < infractionHeight { + return sdk.ZeroInt() + } + + if redelegation.MinTime < now { + // Redelegation no longer eligible for slashing, skip it + // TODO Delete it automatically? + return sdk.ZeroInt() + } + + // Calculate slash amount proportional to stake contributing to infraction + slashAmount = sdk.NewRatFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor).EvaluateInt() + + // Don't slash more tokens than held + // Possible since the redelegation may already + // have been slashed, and slash amounts are calculated + // according to stake held at time of infraction + redelegationSlashAmount := slashAmount + if redelegationSlashAmount.GT(redelegation.Balance.Amount) { + redelegationSlashAmount = redelegation.Balance.Amount + } + + // Update redelegation if necessary + if !redelegationSlashAmount.IsZero() { + redelegation.Balance.Amount = redelegation.Balance.Amount.Sub(redelegationSlashAmount) + k.SetRedelegation(ctx, redelegation) + } + + // Unbond from target validator + sharesToUnbond := slashFactor.Mul(redelegation.SharesDst) + if !sharesToUnbond.IsZero() { + delegation, found := k.GetDelegation(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr) + if !found { + // If deleted, delegation has zero shares, and we can't unbond any more + return slashAmount + } + if sharesToUnbond.GT(delegation.Shares) { + sharesToUnbond = delegation.Shares + } + tokensToBurn, err := k.unbond(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr, sharesToUnbond) + if err != nil { + panic(fmt.Errorf("error unbonding delegator: %v", err)) + } + // Burn loose tokens + pool := k.GetPool(ctx) + pool.LooseTokens -= tokensToBurn + k.SetPool(ctx, pool) + } + + return slashAmount +} diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go new file mode 100644 index 0000000000..9e53151a18 --- /dev/null +++ b/x/stake/keeper/slash_test.go @@ -0,0 +1,481 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake/types" + abci "github.com/tendermint/tendermint/abci/types" +) + +// setup helper function +// creates two validators +func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { + // setup + ctx, _, keeper := CreateTestInput(t, false, amt) + params := keeper.GetParams(ctx) + pool := keeper.GetPool(ctx) + numVals := 3 + pool.LooseTokens = amt * int64(numVals) + + // add numVals validators + for i := 0; i < numVals; i++ { + validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) + validator, pool, _ = validator.AddTokensFromDel(pool, amt) + keeper.SetPool(ctx, pool) + keeper.UpdateValidator(ctx, validator) + keeper.SetValidatorByPubKeyIndex(ctx, validator) + } + + return ctx, keeper, params +} + +// tests Revoke, Unrevoke +func TestRevocation(t *testing.T) { + // setup + ctx, keeper, _ := setupHelper(t, 10) + addr := addrVals[0] + pk := PKs[0] + + // initial state + val, found := keeper.GetValidator(ctx, addr) + require.True(t, found) + require.False(t, val.GetRevoked()) + + // test revoke + keeper.Revoke(ctx, pk) + val, found = keeper.GetValidator(ctx, addr) + require.True(t, found) + require.True(t, val.GetRevoked()) + + // test unrevoke + keeper.Unrevoke(ctx, pk) + val, found = keeper.GetValidator(ctx, addr) + require.True(t, found) + require.False(t, val.GetRevoked()) + +} + +// tests slashUnbondingDelegation +func TestSlashUnbondingDelegation(t *testing.T) { + ctx, keeper, params := setupHelper(t, 10) + fraction := sdk.NewRat(1, 2) + + // set an unbonding delegation + ubd := types.UnbondingDelegation{ + DelegatorAddr: addrDels[0], + ValidatorAddr: addrVals[0], + CreationHeight: 0, + // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) + MinTime: 0, + InitialBalance: sdk.NewCoin(params.BondDenom, 10), + Balance: sdk.NewCoin(params.BondDenom, 10), + } + keeper.SetUnbondingDelegation(ctx, ubd) + + // unbonding started prior to the infraction height, stake didn't contribute + slashAmount := keeper.slashUnbondingDelegation(ctx, ubd, 1, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // after the expiration time, no longer eligible for slashing + ctx = ctx.WithBlockHeader(abci.Header{Time: int64(10)}) + keeper.SetUnbondingDelegation(ctx, ubd) + slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // test valid slash, before expiration timestamp and to which stake contributed + oldPool := keeper.GetPool(ctx) + ctx = ctx.WithBlockHeader(abci.Header{Time: int64(0)}) + keeper.SetUnbondingDelegation(ctx, ubd) + slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) + require.Equal(t, int64(5), slashAmount.Int64()) + ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + // initialbalance unchanged + require.Equal(t, sdk.NewCoin(params.BondDenom, 10), ubd.InitialBalance) + // balance decreased + require.Equal(t, sdk.NewCoin(params.BondDenom, 5), ubd.Balance) + newPool := keeper.GetPool(ctx) + require.Equal(t, int64(5), oldPool.LooseTokens-newPool.LooseTokens) +} + +// tests slashRedelegation +func TestSlashRedelegation(t *testing.T) { + ctx, keeper, params := setupHelper(t, 10) + fraction := sdk.NewRat(1, 2) + + // set a redelegation + rd := types.Redelegation{ + DelegatorAddr: addrDels[0], + ValidatorSrcAddr: addrVals[0], + ValidatorDstAddr: addrVals[1], + CreationHeight: 0, + // expiration timestamp (beyond which the redelegation shouldn't be slashed) + MinTime: 0, + SharesSrc: sdk.NewRat(10), + SharesDst: sdk.NewRat(10), + InitialBalance: sdk.NewCoin(params.BondDenom, 10), + Balance: sdk.NewCoin(params.BondDenom, 10), + } + keeper.SetRedelegation(ctx, rd) + + // set the associated delegation + del := types.Delegation{ + DelegatorAddr: addrDels[0], + ValidatorAddr: addrVals[1], + Shares: sdk.NewRat(10), + } + keeper.SetDelegation(ctx, del) + + // started redelegating prior to the current height, stake didn't contribute to infraction + validator, found := keeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount := keeper.slashRedelegation(ctx, validator, rd, 1, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // after the expiration time, no longer eligible for slashing + ctx = ctx.WithBlockHeader(abci.Header{Time: int64(10)}) + keeper.SetRedelegation(ctx, rd) + validator, found = keeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // test valid slash, before expiration timestamp and to which stake contributed + oldPool := keeper.GetPool(ctx) + ctx = ctx.WithBlockHeader(abci.Header{Time: int64(0)}) + keeper.SetRedelegation(ctx, rd) + validator, found = keeper.GetValidator(ctx, addrVals[1]) + require.True(t, found) + slashAmount = keeper.slashRedelegation(ctx, validator, rd, 0, fraction) + require.Equal(t, int64(5), slashAmount.Int64()) + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + // initialbalance unchanged + require.Equal(t, sdk.NewCoin(params.BondDenom, 10), rd.InitialBalance) + // balance decreased + require.Equal(t, sdk.NewCoin(params.BondDenom, 5), rd.Balance) + // shares decreased + del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1]) + require.True(t, found) + require.Equal(t, int64(5), del.Shares.Evaluate()) + // pool bonded tokens decreased + newPool := keeper.GetPool(ctx) + require.Equal(t, int64(5), oldPool.BondedTokens-newPool.BondedTokens) +} + +// tests Slash at a future height (must panic) +func TestSlashAtFutureHeight(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + pk := PKs[0] + fraction := sdk.NewRat(1, 2) + require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) }) +} + +// tests Slash at the current height +func TestSlashAtCurrentHeight(t *testing.T) { + ctx, keeper, _ := setupHelper(t, 10) + pk := PKs[0] + fraction := sdk.NewRat(1, 2) + + oldPool := keeper.GetPool(ctx) + validator, found := keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + keeper.Slash(ctx, pk, ctx.BlockHeight(), 10, fraction) + + // read updated state + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + newPool := keeper.GetPool(ctx) + + // power decreased + require.Equal(t, sdk.NewRat(5), validator.GetPower()) + // pool bonded shares decreased + require.Equal(t, sdk.NewRat(5).Evaluate(), oldPool.BondedShares.Sub(newPool.BondedShares).Evaluate()) +} + +// tests Slash at a previous height with an unbonding delegation +func TestSlashWithUnbondingDelegation(t *testing.T) { + ctx, keeper, params := setupHelper(t, 10) + pk := PKs[0] + fraction := sdk.NewRat(1, 2) + + // set an unbonding delegation + ubd := types.UnbondingDelegation{ + DelegatorAddr: addrDels[0], + ValidatorAddr: addrVals[0], + CreationHeight: 11, + // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) + MinTime: 0, + InitialBalance: sdk.NewCoin(params.BondDenom, 4), + Balance: sdk.NewCoin(params.BondDenom, 4), + } + keeper.SetUnbondingDelegation(ctx, ubd) + + // slash validator for the first time + ctx = ctx.WithBlockHeight(12) + oldPool := keeper.GetPool(ctx) + validator, found := keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + keeper.Slash(ctx, pk, 10, 10, fraction) + + // read updating unbonding delegation + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + // balance decreased + require.Equal(t, sdk.NewInt(2), ubd.Balance.Amount) + // read updated pool + newPool := keeper.GetPool(ctx) + // bonded tokens burned + require.Equal(t, int64(3), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + // power decreased by 3 - 6 stake originally bonded at the time of infraction + // was still bonded at the time of discovery and was slashed by half, 4 stake + // bonded at the time of discovery hadn't been bonded at the time of infraction + // and wasn't slashed + require.Equal(t, sdk.NewRat(7), validator.GetPower()) + + // slash validator again + ctx = ctx.WithBlockHeight(13) + keeper.Slash(ctx, pk, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + // balance decreased again + require.Equal(t, sdk.NewInt(0), ubd.Balance.Amount) + // read updated pool + newPool = keeper.GetPool(ctx) + // bonded tokens burned again + require.Equal(t, int64(6), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + // power decreased by 3 again + require.Equal(t, sdk.NewRat(4), validator.GetPower()) + + // slash validator again + // all originally bonded stake has been slashed, so this will have no effect + // on the unbonding delegation, but it will slash stake bonded since the infraction + // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 + ctx = ctx.WithBlockHeight(13) + keeper.Slash(ctx, pk, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + // balance unchanged + require.Equal(t, sdk.NewInt(0), ubd.Balance.Amount) + // read updated pool + newPool = keeper.GetPool(ctx) + // bonded tokens burned again + require.Equal(t, int64(9), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + // power decreased by 3 again + require.Equal(t, sdk.NewRat(1), validator.GetPower()) + + // slash validator again + // all originally bonded stake has been slashed, so this will have no effect + // on the unbonding delegation, but it will slash stake bonded since the infraction + // this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440 + ctx = ctx.WithBlockHeight(13) + keeper.Slash(ctx, pk, 9, 10, fraction) + ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + // balance unchanged + require.Equal(t, sdk.NewInt(0), ubd.Balance.Amount) + // read updated pool + newPool = keeper.GetPool(ctx) + // just 1 bonded token burned again since that's all the validator now has + require.Equal(t, int64(10), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + // power decreased by 1 again, validator is out of stake + require.Equal(t, sdk.NewRat(0), validator.GetPower()) +} + +// tests Slash at a previous height with a redelegation +func TestSlashWithRedelegation(t *testing.T) { + ctx, keeper, params := setupHelper(t, 10) + pk := PKs[0] + fraction := sdk.NewRat(1, 2) + + // set a redelegation + rd := types.Redelegation{ + DelegatorAddr: addrDels[0], + ValidatorSrcAddr: addrVals[0], + ValidatorDstAddr: addrVals[1], + CreationHeight: 11, + MinTime: 0, + SharesSrc: sdk.NewRat(6), + SharesDst: sdk.NewRat(6), + InitialBalance: sdk.NewCoin(params.BondDenom, 6), + Balance: sdk.NewCoin(params.BondDenom, 6), + } + keeper.SetRedelegation(ctx, rd) + + // set the associated delegation + del := types.Delegation{ + DelegatorAddr: addrDels[0], + ValidatorAddr: addrVals[1], + Shares: sdk.NewRat(6), + } + keeper.SetDelegation(ctx, del) + + // slash validator + ctx = ctx.WithBlockHeight(12) + oldPool := keeper.GetPool(ctx) + validator, found := keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + keeper.Slash(ctx, pk, 10, 10, fraction) + + // read updating redelegation + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + // balance decreased + require.Equal(t, sdk.NewInt(3), rd.Balance.Amount) + // read updated pool + newPool := keeper.GetPool(ctx) + // bonded tokens burned + require.Equal(t, int64(5), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + // power decreased by 2 - 4 stake originally bonded at the time of infraction + // was still bonded at the time of discovery and was slashed by half, 4 stake + // bonded at the time of discovery hadn't been bonded at the time of infraction + // and wasn't slashed + require.Equal(t, sdk.NewRat(8), validator.GetPower()) + + // slash the validator again + ctx = ctx.WithBlockHeight(12) + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + keeper.Slash(ctx, pk, 10, 10, sdk.NewRat(3, 4)) + + // read updating redelegation + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + // balance decreased, now zero + require.Equal(t, sdk.NewInt(0), rd.Balance.Amount) + // read updated pool + newPool = keeper.GetPool(ctx) + // 7 bonded tokens burned + require.Equal(t, int64(12), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + // power decreased by 4 + require.Equal(t, sdk.NewRat(4), validator.GetPower()) + + // slash the validator again, by 100% + ctx = ctx.WithBlockHeight(12) + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) + + // read updating redelegation + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + // balance still zero + require.Equal(t, sdk.NewInt(0), rd.Balance.Amount) + // read updated pool + newPool = keeper.GetPool(ctx) + // four more bonded tokens burned + require.Equal(t, int64(16), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + // power decreased by 4, down to 0 + require.Equal(t, sdk.NewRat(0), validator.GetPower()) + + // slash the validator again, by 100% + // no stake remains to be slashed + ctx = ctx.WithBlockHeight(12) + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + keeper.Slash(ctx, pk, 10, 10, sdk.OneRat()) + + // read updating redelegation + rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + // balance still zero + require.Equal(t, sdk.NewInt(0), rd.Balance.Amount) + // read updated pool + newPool = keeper.GetPool(ctx) + // no more bonded tokens burned + require.Equal(t, int64(16), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + // power still zero + require.Equal(t, sdk.NewRat(0), validator.GetPower()) +} + +// tests Slash at a previous height with both an unbonding delegation and a redelegation +func TestSlashBoth(t *testing.T) { + ctx, keeper, params := setupHelper(t, 10) + fraction := sdk.NewRat(1, 2) + + // set a redelegation + rdA := types.Redelegation{ + DelegatorAddr: addrDels[0], + ValidatorSrcAddr: addrVals[0], + ValidatorDstAddr: addrVals[1], + CreationHeight: 11, + // expiration timestamp (beyond which the redelegation shouldn't be slashed) + MinTime: 0, + SharesSrc: sdk.NewRat(6), + SharesDst: sdk.NewRat(6), + InitialBalance: sdk.NewCoin(params.BondDenom, 6), + Balance: sdk.NewCoin(params.BondDenom, 6), + } + keeper.SetRedelegation(ctx, rdA) + + // set the associated delegation + delA := types.Delegation{ + DelegatorAddr: addrDels[0], + ValidatorAddr: addrVals[1], + Shares: sdk.NewRat(6), + } + keeper.SetDelegation(ctx, delA) + + // set an unbonding delegation + ubdA := types.UnbondingDelegation{ + DelegatorAddr: addrDels[0], + ValidatorAddr: addrVals[0], + CreationHeight: 11, + // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) + MinTime: 0, + InitialBalance: sdk.NewCoin(params.BondDenom, 4), + Balance: sdk.NewCoin(params.BondDenom, 4), + } + keeper.SetUnbondingDelegation(ctx, ubdA) + + // slash validator + ctx = ctx.WithBlockHeight(12) + oldPool := keeper.GetPool(ctx) + validator, found := keeper.GetValidatorByPubKey(ctx, PKs[0]) + require.True(t, found) + keeper.Slash(ctx, PKs[0], 10, 10, fraction) + + // read updating redelegation + rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) + require.True(t, found) + // balance decreased + require.Equal(t, sdk.NewInt(3), rdA.Balance.Amount) + // read updated pool + newPool := keeper.GetPool(ctx) + // loose tokens burned + require.Equal(t, int64(2), oldPool.LooseTokens-newPool.LooseTokens) + // bonded tokens burned + require.Equal(t, int64(3), oldPool.BondedTokens-newPool.BondedTokens) + // read updated validator + validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0]) + require.True(t, found) + // power not decreased, all stake was bonded since + require.Equal(t, sdk.NewRat(10), validator.GetPower()) +} diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 410cfbe1d8..eb38a50a7a 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -61,6 +61,7 @@ type UnbondingDelegation struct { ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr CreationHeight int64 `json:"creation_height"` // height which the unbonding took place MinTime int64 `json:"min_time"` // unix time for unbonding completion + InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion Balance sdk.Coin `json:"balance"` // atoms to receive at completion } @@ -101,6 +102,8 @@ type Redelegation struct { ValidatorDstAddr sdk.Address `json:"validator_dst_addr"` // validator redelegation destination owner addr CreationHeight int64 `json:"creation_height"` // height which the redelegation took place MinTime int64 `json:"min_time"` // unix time for redelegation completion + InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started + Balance sdk.Coin `json:"balance"` // current balance SharesSrc sdk.Rat `json:"shares_src"` // amount of source shares redelegating SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 652fd9e6e8..c98ebce62a 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -284,6 +284,7 @@ func (v Validator) DelegatorShareExRate(pool Pool) sdk.Rat { var _ sdk.Validator = Validator{} // nolint - for sdk.Validator +func (v Validator) GetRevoked() bool { return v.Revoked } func (v Validator) GetMoniker() string { return v.Description.Moniker } func (v Validator) GetStatus() sdk.BondStatus { return v.Status() } func (v Validator) GetOwner() sdk.Address { return v.Owner } From feb3acdbe9c7fdca41570db9971759ce0e34a457 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 30 Jun 2018 19:32:52 -0400 Subject: [PATCH 63/77] Merge PR #1491: client/lcd: fix tests * client/lcd: fix tests * circle: drop test_unit. store artifacts in test_cover * hack fix in TestUnrevoke --- .circleci/config.yml | 24 +++++----------------- client/lcd/lcd_test.go | 3 +++ client/lcd/test_helpers.go | 2 +- tests/util.go | 42 ++++++++++++++++---------------------- 4 files changed, 27 insertions(+), 44 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cf679fe75f..0a6b28673e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,6 +8,7 @@ defaults: &defaults GOBIN: /tmp/workspace/bin jobs: + setup_dependencies: <<: *defaults steps: @@ -67,21 +68,6 @@ jobs: command: | export PATH="$GOBIN:$PATH" make test_lint - test_unit: - <<: *defaults - parallelism: 1 - steps: - - attach_workspace: - at: /tmp/workspace - - restore_cache: - key: v1-pkg-cache - - restore_cache: - key: v1-tree-{{ .Environment.CIRCLE_SHA1 }} - - run: - name: Test unit - command: | - export PATH="$GOBIN:$PATH" - make test_unit test_cli: <<: *defaults @@ -109,6 +95,7 @@ jobs: key: v1-pkg-cache - restore_cache: key: v1-tree-{{ .Environment.CIRCLE_SHA1 }} + - run: mkdir -p /tmp/logs - run: name: Run tests command: | @@ -117,12 +104,14 @@ jobs: for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v /vendor/ | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | circleci tests split --split-by=timings); do id=$(basename "$pkg") - go test -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" + GOCACHE=off go test -v -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" | tee "/tmp/logs/$id-$RANDOM.log" done - persist_to_workspace: root: /tmp/workspace paths: - "profiles/*" + - store_artifacts: + path: /tmp/logs upload_coverage: <<: *defaults @@ -156,9 +145,6 @@ workflows: - test_cli: requires: - setup_dependencies - - test_unit: - requires: - - setup_dependencies - test_cover: requires: - setup_dependencies diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 049fa04bef..1b1a02fefb 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -528,6 +528,9 @@ func TestUnrevoke(t *testing.T) { cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.Address{addr}) defer cleanup() + // XXX: any less than this and it fails + tests.WaitForHeight(3, port) + signingInfo := getSigningInfo(t, port, pks[0].Address()) tests.WaitForHeight(4, port) require.Equal(t, true, signingInfo.IndexOffset > 0) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index ecf6748a57..dbdf9b724d 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -95,7 +95,7 @@ func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (addr sd func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.Address) (cleanup func(), validatorsPKs []crypto.PubKey, port string) { config := GetConfig() - config.Consensus.TimeoutCommit = 1000 + config.Consensus.TimeoutCommit = 100 config.Consensus.SkipTimeoutCommit = false config.TxIndex.IndexAllTags = true diff --git a/tests/util.go b/tests/util.go index 54432f9927..afa127bf01 100644 --- a/tests/util.go +++ b/tests/util.go @@ -82,17 +82,10 @@ func StatusOK(statusCode int) bool { } func waitForHeight(height int64, url string) { + var res *http.Response + var err error for { - // get url, try a few times - var res *http.Response - var err error - for i := 0; i < 5; i++ { - res, err = http.Get(url) - if err == nil && StatusOK(res.StatusCode) { - break - } - time.Sleep(time.Millisecond * 200) - } + res, err = http.Get(url) if err != nil { panic(err) } @@ -125,30 +118,31 @@ func waitForHeight(height int64, url string) { // wait for tendermint to start func WaitForStart(port string) { var err error - for i := 0; i < 5; i++ { - time.Sleep(time.Second) + url := fmt.Sprintf("http://localhost:%v/blocks/latest", port) - url := fmt.Sprintf("http://localhost:%v/blocks/latest", port) + // ping the status endpoint a few times a second + // for a few seconds until we get a good response. + // otherwise something probably went wrong + for i := 0; i < 50; i++ { + time.Sleep(time.Millisecond * 100) - // get url, try a few times var res *http.Response res, err = http.Get(url) - if err == nil || res == nil { + if err != nil || res == nil { continue } + err = res.Body.Close() + if err != nil { + panic(err) + } - // waiting for server to start ... - if res.StatusCode != http.StatusOK { - err = res.Body.Close() - if err != nil { - panic(err) - } + if res.StatusCode == http.StatusOK { + // good! return } } - if err != nil { - panic(err) - } + // still haven't started up?! panic! + panic(err) } // TODO: these functions just print to Stdout. From 6a864923fa40f3e8cc934e58e58b8a78a188de4d Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Mon, 2 Jul 2018 08:57:33 -0700 Subject: [PATCH 64/77] types: Rename rational.Evaluate to rational.Round (#1487) * rational.Evaluate -> rational.RoundInt64 * rational.EvaluateInt -> rational.RoundInt This done to improve clarity of the code. Closes #1485 --- CHANGELOG.md | 1 + types/rational.go | 10 ++++----- types/rational_test.go | 4 ++-- types/stake.go | 2 +- x/stake/genesis.go | 2 +- x/stake/handler_test.go | 34 +++++++++++++++---------------- x/stake/keeper/delegation_test.go | 8 ++++---- x/stake/keeper/inflation.go | 2 +- x/stake/keeper/inflation_test.go | 4 ++-- x/stake/keeper/slash.go | 10 ++++----- x/stake/keeper/slash_test.go | 4 ++-- x/stake/keeper/validator_test.go | 4 ++-- x/stake/types/pool.go | 6 +++--- x/stake/types/test_common.go | 8 ++++---- x/stake/types/validator.go | 2 +- x/stake/types/validator_test.go | 22 ++++++++++---------- 16 files changed, 62 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b543247a..b261e7d84b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ BREAKING CHANGES to an infraction, slash them proportional to their stake at the time * Add REST endpoint to unrevoke a validator previously revoked for downtime * Add REST endpoint to retrieve liveness signing information for a validator +* [types] renamed rational.Evaluate to rational.Round{Int64, Int} FEATURES * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag diff --git a/types/rational.go b/types/rational.go index f24831f89e..ab400868d4 100644 --- a/types/rational.go +++ b/types/rational.go @@ -174,20 +174,20 @@ func (r Rat) EvaluateBig() *big.Int { return d } -// evaluate the rational using bankers rounding -func (r Rat) Evaluate() int64 { +// RoundInt64 rounds the rational using bankers rounding +func (r Rat) RoundInt64() int64 { return r.EvaluateBig().Int64() } -// EvaulateInt evaludates the rational using EvaluateBig -func (r Rat) EvaluateInt() Int { +// RoundInt round the rational using bankers rounding +func (r Rat) RoundInt() Int { return NewIntFromBigInt(r.EvaluateBig()) } // round Rat with the provided precisionFactor func (r Rat) Round(precisionFactor int64) Rat { rTen := Rat{new(big.Rat).Mul(r.Rat, big.NewRat(precisionFactor, 1))} - return Rat{big.NewRat(rTen.Evaluate(), precisionFactor)} + return Rat{big.NewRat(rTen.RoundInt64(), precisionFactor)} } // TODO panic if negative or if totalDigits < len(initStr)??? diff --git a/types/rational_test.go b/types/rational_test.go index db875c83e8..3215313e09 100644 --- a/types/rational_test.go +++ b/types/rational_test.go @@ -168,8 +168,8 @@ func TestEvaluate(t *testing.T) { } for _, tc := range tests { - require.Equal(t, tc.res, tc.r1.Evaluate(), "%v", tc.r1) - require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).Evaluate(), "%v", tc.r1.Mul(NewRat(-1))) + require.Equal(t, tc.res, tc.r1.RoundInt64(), "%v", tc.r1) + require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).RoundInt64(), "%v", tc.r1.Mul(NewRat(-1))) } } diff --git a/types/stake.go b/types/stake.go index 8625b617e5..7cb7ccf6d8 100644 --- a/types/stake.go +++ b/types/stake.go @@ -46,7 +46,7 @@ type Validator interface { func ABCIValidator(v Validator) abci.Validator { return abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(v.GetPubKey()), - Power: v.GetPower().Evaluate(), + Power: v.GetPower().RoundInt64(), } } diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 6a15ebeb42..55dd06f76f 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -49,7 +49,7 @@ func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisVali keeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { vals = append(vals, tmtypes.GenesisValidator{ PubKey: validator.GetPubKey(), - Power: validator.GetPower().Evaluate(), + Power: validator.GetPower().RoundInt64(), Name: validator.GetMoniker(), }) return false diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index e6cd6f4ca7..b18b3c98b2 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -56,7 +56,7 @@ func TestValidatorByPowerIndex(t *testing.T) { // verify the self-delegation exists bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr) require.True(t, found) - gotBond := bond.Shares.Evaluate() + gotBond := bond.Shares.RoundInt64() require.Equal(t, initBond, gotBond, "initBond: %v\ngotBond: %v\nbond: %v\n", initBond, gotBond, bond) @@ -78,8 +78,8 @@ func TestValidatorByPowerIndex(t *testing.T) { keeper.Revoke(ctx, keep.PKs[0]) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - require.Equal(t, sdk.Unbonded, validator.PoolShares.Status) // ensure is unbonded - require.Equal(t, int64(500000), validator.PoolShares.Amount.Evaluate()) // ensure is unbonded + require.Equal(t, sdk.Unbonded, validator.PoolShares.Status) // ensure is unbonded + require.Equal(t, int64(500000), validator.PoolShares.Amount.RoundInt64()) // ensure is unbonded // the old power record should have been deleted as the power changed require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) @@ -155,20 +155,20 @@ func TestIncrementsMsgDelegate(t *testing.T) { validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.Equal(t, sdk.Bonded, validator.Status()) - require.Equal(t, bondAmount, validator.DelegatorShares.Evaluate()) - require.Equal(t, bondAmount, validator.PoolShares.Bonded().Evaluate(), "validator: %v", validator) + require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount, validator.PoolShares.Bonded().RoundInt64(), "validator: %v", validator) _, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.False(t, found) bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr) require.True(t, found) - require.Equal(t, bondAmount, bond.Shares.Evaluate()) + require.Equal(t, bondAmount, bond.Shares.RoundInt64()) pool := keeper.GetPool(ctx) exRate := validator.DelegatorShareExRate(pool) require.True(t, exRate.Equal(sdk.OneRat()), "expected exRate 1 got %v", exRate) - require.Equal(t, bondAmount, pool.BondedShares.Evaluate()) + require.Equal(t, bondAmount, pool.BondedShares.RoundInt64()) require.Equal(t, bondAmount, pool.BondedTokens) // just send the same msgbond multiple times @@ -196,8 +196,8 @@ func TestIncrementsMsgDelegate(t *testing.T) { require.Equal(t, bond.Height, int64(i), "Incorrect bond height") - gotBond := bond.Shares.Evaluate() - gotDelegatorShares := validator.DelegatorShares.Evaluate() + gotBond := bond.Shares.RoundInt64() + gotDelegatorShares := validator.DelegatorShares.RoundInt64() gotDelegatorAcc := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(params.BondDenom) require.Equal(t, expBond, gotBond, @@ -230,8 +230,8 @@ func TestIncrementsMsgUnbond(t *testing.T) { validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - require.Equal(t, initBond*2, validator.DelegatorShares.Evaluate()) - require.Equal(t, initBond*2, validator.PoolShares.Bonded().Evaluate()) + require.Equal(t, initBond*2, validator.DelegatorShares.RoundInt64()) + require.Equal(t, initBond*2, validator.PoolShares.Bonded().RoundInt64()) // just send the same msgUnbond multiple times // TODO use decimals here @@ -251,12 +251,12 @@ func TestIncrementsMsgUnbond(t *testing.T) { bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.True(t, found) - expBond := initBond - int64(i+1)*unbondShares.Evaluate() - expDelegatorShares := 2*initBond - int64(i+1)*unbondShares.Evaluate() + expBond := initBond - int64(i+1)*unbondShares.RoundInt64() + expDelegatorShares := 2*initBond - int64(i+1)*unbondShares.RoundInt64() expDelegatorAcc := sdk.NewInt(initBond - expBond) - gotBond := bond.Shares.Evaluate() - gotDelegatorShares := validator.DelegatorShares.Evaluate() + gotBond := bond.Shares.RoundInt64() + gotDelegatorShares := validator.DelegatorShares.RoundInt64() gotDelegatorAcc := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(params.BondDenom) require.Equal(t, expBond, gotBond, @@ -285,7 +285,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.False(t, got.IsOK(), "expected unbond msg to fail") } - leftBonded := initBond - int64(numUnbonds)*unbondShares.Evaluate() + leftBonded := initBond - int64(numUnbonds)*unbondShares.RoundInt64() // should be unable to unbond one more than we have unbondShares = sdk.NewRat(leftBonded + 1) @@ -322,7 +322,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { balanceExpd := sdk.NewInt(initBond - 10) balanceGot := accMapper.GetAccount(ctx, val.Owner).GetCoins().AmountOf(params.BondDenom) require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) - require.Equal(t, 10, int(val.DelegatorShares.Evaluate()), "expected %d shares, got %d", 10, val.DelegatorShares) + require.Equal(t, 10, int(val.DelegatorShares.RoundInt64()), "expected %d shares, got %d", 10, val.DelegatorShares) require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) } diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index f20188ccdc..eb318df4d3 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -146,13 +146,13 @@ func TestUnbondDelegation(t *testing.T) { //create a validator and a delegator to that validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, issuedShares := validator.AddTokensFromDel(pool, 10) - require.Equal(t, int64(10), issuedShares.Evaluate()) + require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) validator = keeper.UpdateValidator(ctx, validator) pool = keeper.GetPool(ctx) require.Equal(t, int64(10), pool.BondedTokens) - require.Equal(t, int64(10), validator.PoolShares.Bonded().Evaluate()) + require.Equal(t, int64(10), validator.PoolShares.Bonded().RoundInt64()) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -173,8 +173,8 @@ func TestUnbondDelegation(t *testing.T) { require.True(t, found) pool = keeper.GetPool(ctx) - require.Equal(t, int64(4), delegation.Shares.Evaluate()) - require.Equal(t, int64(4), validator.PoolShares.Bonded().Evaluate()) + require.Equal(t, int64(4), delegation.Shares.RoundInt64()) + require.Equal(t, int64(4), validator.PoolShares.Bonded().RoundInt64()) require.Equal(t, int64(6), pool.LooseTokens, "%v", pool) require.Equal(t, int64(4), pool.BondedTokens) } diff --git a/x/stake/keeper/inflation.go b/x/stake/keeper/inflation.go index 0574b8ecbf..26b5158791 100644 --- a/x/stake/keeper/inflation.go +++ b/x/stake/keeper/inflation.go @@ -18,7 +18,7 @@ func (k Keeper) ProcessProvisions(ctx sdk.Context) types.Pool { pool := k.GetPool(ctx) pool.Inflation = k.NextInflation(ctx) - provisions := pool.Inflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat).Evaluate() + provisions := pool.Inflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat).RoundInt64() // TODO add to the fees provisions pool.LooseTokens += provisions diff --git a/x/stake/keeper/inflation_test.go b/x/stake/keeper/inflation_test.go index 944559dfc2..2fee8154a0 100644 --- a/x/stake/keeper/inflation_test.go +++ b/x/stake/keeper/inflation_test.go @@ -167,7 +167,7 @@ func TestLargeUnbond(t *testing.T) { _, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0) bondedShares = bondedShares.Sub(bondSharesVal0) - val0UnbondedTokens = pool.UnbondedShareExRate().Mul(validator.PoolShares.Unbonded()).Evaluate() + val0UnbondedTokens = pool.UnbondedShareExRate().Mul(validator.PoolShares.Unbonded()).RoundInt64() unbondedShares = unbondedShares.Add(sdk.NewRat(val0UnbondedTokens, 1).Mul(pool.UnbondedShareExRate())) // unbonded shares should increase @@ -295,7 +295,7 @@ func checkFinalPoolValues(t *testing.T, pool types.Pool, initialTotalTokens, cum // Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests func updateProvisions(t *testing.T, keeper Keeper, pool types.Pool, ctx sdk.Context, hr int) (sdk.Rat, int64, types.Pool) { expInflation := keeper.NextInflation(ctx) - expProvisions := (expInflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat)).Evaluate() + expProvisions := (expInflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat)).RoundInt64() startTotalSupply := pool.TokenSupply() pool = keeper.ProcessProvisions(ctx) keeper.SetPool(ctx, pool) diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 9d4c9af62e..b12360fc3f 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -30,7 +30,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in } // Amount of slashing = slash slashFactor * power at time of infraction - slashAmount := sdk.NewRat(power).Mul(slashFactor).EvaluateInt() + slashAmount := sdk.NewRat(power).Mul(slashFactor).RoundInt() // ref https://github.com/cosmos/cosmos-sdk/issues/1348 // ref https://github.com/cosmos/cosmos-sdk/issues/1471 @@ -79,8 +79,8 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in // Cannot decrease balance below zero sharesToRemove := remainingSlashAmount - if sharesToRemove.GT(validator.PoolShares.Amount.EvaluateInt()) { - sharesToRemove = validator.PoolShares.Amount.EvaluateInt() + if sharesToRemove.GT(validator.PoolShares.Amount.RoundInt()) { + sharesToRemove = validator.PoolShares.Amount.RoundInt() } // Get the current pool @@ -150,7 +150,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewRatFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor).EvaluateInt() + slashAmount = sdk.NewRatFromInt(unbondingDelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor).RoundInt() // Don't slash more tokens than held // Possible since the unbonding delegation may already @@ -195,7 +195,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re } // Calculate slash amount proportional to stake contributing to infraction - slashAmount = sdk.NewRatFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor).EvaluateInt() + slashAmount = sdk.NewRatFromInt(redelegation.InitialBalance.Amount, sdk.OneInt()).Mul(slashFactor).RoundInt() // Don't slash more tokens than held // Possible since the redelegation may already diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 9e53151a18..dcd38e15e2 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -160,7 +160,7 @@ func TestSlashRedelegation(t *testing.T) { // shares decreased del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1]) require.True(t, found) - require.Equal(t, int64(5), del.Shares.Evaluate()) + require.Equal(t, int64(5), del.Shares.RoundInt64()) // pool bonded tokens decreased newPool := keeper.GetPool(ctx) require.Equal(t, int64(5), oldPool.BondedTokens-newPool.BondedTokens) @@ -193,7 +193,7 @@ func TestSlashAtCurrentHeight(t *testing.T) { // power decreased require.Equal(t, sdk.NewRat(5), validator.GetPower()) // pool bonded shares decreased - require.Equal(t, sdk.NewRat(5).Evaluate(), oldPool.BondedShares.Sub(newPool.BondedShares).Evaluate()) + require.Equal(t, sdk.NewRat(5).RoundInt64(), oldPool.BondedShares.Sub(newPool.BondedShares).RoundInt64()) } // tests Slash at a previous height with an unbonding delegation diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index cf26d055f6..c4d197a36b 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -68,12 +68,12 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) validator, pool, delSharesCreated := validator.AddTokensFromDel(pool, 100) require.Equal(t, sdk.Unbonded, validator.Status()) - require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).Evaluate()) + require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).RoundInt64()) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validator) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).Evaluate(), "\nvalidator %v\npool %v", validator, pool) + require.Equal(t, int64(100), validator.PoolShares.Tokens(pool).RoundInt64(), "\nvalidator %v\npool %v", validator, pool) pool = keeper.GetPool(ctx) power := GetValidatorsByPowerIndexKey(validator, pool) diff --git a/x/stake/types/pool.go b/x/stake/types/pool.go index cb2ad240ae..8ef187f078 100644 --- a/x/stake/types/pool.go +++ b/x/stake/types/pool.go @@ -104,7 +104,7 @@ func (p Pool) addTokensUnbonded(amount int64) (p2 Pool, issuedShares PoolShares) } func (p Pool) removeSharesUnbonded(shares sdk.Rat) (p2 Pool, removedTokens int64) { - removedTokens = p.UnbondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares + removedTokens = p.UnbondedShareExRate().Mul(shares).RoundInt64() // (tokens/shares) * shares p.UnbondedShares = p.UnbondedShares.Sub(shares) p.UnbondedTokens -= removedTokens p.LooseTokens += removedTokens @@ -126,7 +126,7 @@ func (p Pool) addTokensUnbonding(amount int64) (p2 Pool, issuedShares PoolShares } func (p Pool) removeSharesUnbonding(shares sdk.Rat) (p2 Pool, removedTokens int64) { - removedTokens = p.UnbondingShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares + removedTokens = p.UnbondingShareExRate().Mul(shares).RoundInt64() // (tokens/shares) * shares p.UnbondingShares = p.UnbondingShares.Sub(shares) p.UnbondingTokens -= removedTokens p.LooseTokens += removedTokens @@ -148,7 +148,7 @@ func (p Pool) addTokensBonded(amount int64) (p2 Pool, issuedShares PoolShares) { } func (p Pool) removeSharesBonded(shares sdk.Rat) (p2 Pool, removedTokens int64) { - removedTokens = p.BondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares + removedTokens = p.BondedShareExRate().Mul(shares).RoundInt64() // (tokens/shares) * shares p.BondedShares = p.BondedShares.Sub(shares) p.BondedTokens -= removedTokens p.LooseTokens += removedTokens diff --git a/x/stake/types/test_common.go b/x/stake/types/test_common.go index 5edb5568d8..12f11f864b 100644 --- a/x/stake/types/test_common.go +++ b/x/stake/types/test_common.go @@ -118,12 +118,12 @@ func AssertInvariants(t *testing.T, msg string, // nonnegative bonded ex rate require.False(t, pMod.BondedShareExRate().LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative BondedShareExRate: %d", - msg, pMod.BondedShareExRate().Evaluate()) + msg, pMod.BondedShareExRate().RoundInt64()) // nonnegative unbonded ex rate require.False(t, pMod.UnbondedShareExRate().LT(sdk.ZeroRat()), "Applying operation \"%s\" resulted in negative UnbondedShareExRate: %d", - msg, pMod.UnbondedShareExRate().Evaluate()) + msg, pMod.UnbondedShareExRate().RoundInt64()) for _, vMod := range vMods { @@ -193,10 +193,10 @@ func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) { validator := randomValidator(r, i) if validator.Status() == sdk.Bonded { pool.BondedShares = pool.BondedShares.Add(validator.PoolShares.Bonded()) - pool.BondedTokens += validator.PoolShares.Bonded().Evaluate() + pool.BondedTokens += validator.PoolShares.Bonded().RoundInt64() } else if validator.Status() == sdk.Unbonded { pool.UnbondedShares = pool.UnbondedShares.Add(validator.PoolShares.Unbonded()) - pool.UnbondedTokens += validator.PoolShares.Unbonded().Evaluate() + pool.UnbondedTokens += validator.PoolShares.Unbonded().RoundInt64() } validators[i] = validator } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index c98ebce62a..c2c19439be 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -137,7 +137,7 @@ func (d Description) EnsureLength() (Description, sdk.Error) { func (v Validator) ABCIValidator() abci.Validator { return abci.Validator{ PubKey: tmtypes.TM2PB.PubKey(v.PubKey), - Power: v.PoolShares.Bonded().Evaluate(), + Power: v.PoolShares.Bonded().RoundInt64(), } } diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 6a8ff777a6..4fcfa6e17d 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -69,7 +69,7 @@ func TestRemoveDelShares(t *testing.T) { PoolShares: NewBondedShares(sdk.NewRat(100)), DelegatorShares: sdk.NewRat(100), } - poolA.BondedTokens = valA.PoolShares.Bonded().Evaluate() + poolA.BondedTokens = valA.PoolShares.Bonded().RoundInt64() poolA.BondedShares = valA.PoolShares.Bonded() require.Equal(t, valA.DelegatorShareExRate(poolA), sdk.OneRat()) require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat()) @@ -117,25 +117,25 @@ func TestUpdateStatus(t *testing.T) { val := NewValidator(addr1, pk1, Description{}) val, pool, _ = val.AddTokensFromDel(pool, 100) - require.Equal(t, int64(0), val.PoolShares.Bonded().Evaluate()) - require.Equal(t, int64(0), val.PoolShares.Unbonding().Evaluate()) - require.Equal(t, int64(100), val.PoolShares.Unbonded().Evaluate()) + require.Equal(t, int64(0), val.PoolShares.Bonded().RoundInt64()) + require.Equal(t, int64(0), val.PoolShares.Unbonding().RoundInt64()) + require.Equal(t, int64(100), val.PoolShares.Unbonded().RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens) require.Equal(t, int64(0), pool.UnbondingTokens) require.Equal(t, int64(100), pool.UnbondedTokens) val, pool = val.UpdateStatus(pool, sdk.Unbonding) - require.Equal(t, int64(0), val.PoolShares.Bonded().Evaluate()) - require.Equal(t, int64(100), val.PoolShares.Unbonding().Evaluate()) - require.Equal(t, int64(0), val.PoolShares.Unbonded().Evaluate()) + require.Equal(t, int64(0), val.PoolShares.Bonded().RoundInt64()) + require.Equal(t, int64(100), val.PoolShares.Unbonding().RoundInt64()) + require.Equal(t, int64(0), val.PoolShares.Unbonded().RoundInt64()) require.Equal(t, int64(0), pool.BondedTokens) require.Equal(t, int64(100), pool.UnbondingTokens) require.Equal(t, int64(0), pool.UnbondedTokens) val, pool = val.UpdateStatus(pool, sdk.Bonded) - require.Equal(t, int64(100), val.PoolShares.Bonded().Evaluate()) - require.Equal(t, int64(0), val.PoolShares.Unbonding().Evaluate()) - require.Equal(t, int64(0), val.PoolShares.Unbonded().Evaluate()) + require.Equal(t, int64(100), val.PoolShares.Bonded().RoundInt64()) + require.Equal(t, int64(0), val.PoolShares.Unbonding().RoundInt64()) + require.Equal(t, int64(0), val.PoolShares.Unbonded().RoundInt64()) require.Equal(t, int64(100), pool.BondedTokens) require.Equal(t, int64(0), pool.UnbondingTokens) require.Equal(t, int64(0), pool.UnbondedTokens) @@ -154,7 +154,7 @@ func TestPossibleOverflow(t *testing.T) { LooseTokens: 100, BondedShares: poolShares, UnbondedShares: sdk.ZeroRat(), - BondedTokens: poolShares.Evaluate(), + BondedTokens: poolShares.RoundInt64(), UnbondedTokens: 0, InflationLastTime: 0, Inflation: sdk.NewRat(7, 100), From fa293f3a3ec5a7f018dee36bf54c9fff172d492a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 1 Jul 2018 12:13:24 -0400 Subject: [PATCH 65/77] update dep for tm v0.22.0 --- Gopkg.lock | 12 +++++++----- Gopkg.toml | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index c48188cb8d..f02a671164 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -241,7 +241,7 @@ "nfs", "xfs" ] - revision = "7d6f385de8bea29190f15ba9931442a0eaef9af7" + revision = "40f013a808ec4fa79def444a1a56de4d1727efcb" [[projects]] branch = "master" @@ -338,7 +338,8 @@ ".", "sha256truncated" ] - revision = "481b89cbbe6a641f7f6cb5db92b30b20f5a2e001" + revision = "2de525d09cca7c45c3f43d178817947a6cfa242c" + version = "v0.8.1" [[projects]] name = "github.com/tendermint/tendermint" @@ -387,7 +388,8 @@ "types", "version" ] - revision = "8412b75b1070ac023405e8228e017ed36531fe1b" + revision = "3a0dff7db2628c20cb0d77db3a01fea7981e5aec" + version = "v0.22.0-rc0" [[projects]] name = "github.com/tendermint/tmlibs" @@ -443,7 +445,7 @@ "netutil", "trace" ] - revision = "97aa3a539ec716117a9d15a4659a911f50d13c3c" + revision = "4cb1c02c05b0e749b0365f61ae859a8e0cfceed9" [[projects]] branch = "master" @@ -510,6 +512,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "578ae0e0126ffd04006b6755a02bc25c95e2eb2ecb4ea99869c4ada133f29f6b" + inputs-digest = "5db688e81022b54f18b174b151ccb66ab9a5b373008089422a5eea1147555f3e" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 85b15a019c..eedc0df761 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -58,11 +58,11 @@ [[constraint]] name = "github.com/tendermint/iavl" - revision = "481b89cbbe6a641f7f6cb5db92b30b20f5a2e001" + version = "=v0.8.1" [[constraint]] name = "github.com/tendermint/tendermint" - revision = "8412b75b1070ac023405e8228e017ed36531fe1b" + version = "=0.22.0-rc0" [[constraint]] name = "github.com/tendermint/tmlibs" From 7a14982901090f20c88a57db5ca0577f7b272adb Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 1 Jul 2018 12:14:28 -0400 Subject: [PATCH 66/77] some changelog updates --- CHANGELOG.md | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b261e7d84b..23b7c89813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,24 +5,24 @@ *TBD* BREAKING CHANGES -* Change default ports from 466xx to 266xx -* AltBytes renamed to Memo, now a string, max 100 characters, costs a bit of gas -* Transactions now take a list of Messages -* Signers of a transaction now only sign over their account and sequence number -* Removed MsgChangePubKey from auth -* Removed setPubKey from account mapper -* Removed GetMemo from Tx (it is still on StdTx) -* Keybase and Ledger support from go-crypto merged into the SDK in the `crypto` folder -* Gov module REST endpoints changed to be more RESTful -* [cli] rearranged commands under subcommands -* [stake] remove Tick and add EndBlocker -* [stake] introduce concept of unbonding for delegations and validators +* [config] Change default ports from 466xx to 266xx +* [auth] AltBytes renamed to Memo, now a string, max 100 characters, costs a bit of gas +* [types] GetMsg() -> GetMsgs() +* [auth] Signers of a transaction now only sign over their account and sequence number +* [auth] Removed MsgChangePubKey +* [auth] Removed SetPubKey from account mapper +* [types] Removed GetMemo from Tx (it is still on StdTx) +* [keys] Keybase and Ledger support from go-crypto merged into the SDK in the `crypto` folder +* [x/gov] Gov module REST endpoints changed to be more RESTful +* [cli] Rearranged commands under subcommands +* [stake] Remove Tick and add EndBlocker +* [stake] Introduce concept of unbonding for delegations and validators * `gaiacli stake unbond` replaced with `gaiacli stake begin-unbonding` - * introduced: + * Introduced: * `gaiacli stake complete-unbonding` * `gaiacli stake begin-redelegation` * `gaiacli stake complete-redelegation` -* [slashing] update slashing for unbonding period +* [slashing] Update slashing for unbonding period * Slash according to power at time of infraction instead of power at time of discovery * Iterate through unbonding delegations & redelegations which contributed @@ -62,7 +62,18 @@ FEATURES - Ledger keys can be named and tracked locally in the key DB * [gaiacli] added an --async flag to the cli to deliver transactions without waiting for a tendermint response -FIXES +IMPROVEMENTS +* bank module uses go-wire codec instead of 'encoding/json' +* auth module uses go-wire codec instead of 'encoding/json' +* revised use of endblock and beginblock +* [stake] module reorganized to include `types` and `keeper` package +* [stake] keeper always loads the store (instead passing around which doesn't really boost efficiency) +* [stake] edit-validator changes now can use the keyword [do-not-modify] to not modify unspecified `--flag` (aka won't set them to `""` value) +* [types] added common tag constants +* [stake] offload more generic functionality from the handler into the keeper +* added contributing guidelines + +BUG FIXES * [gaia] Added self delegation for validators in the genesis creation * [lcd] tests now don't depend on raw json text * [stake] error strings lower case @@ -78,17 +89,6 @@ FIXES * \#1258 - printing big.rat's can no longer overflow int64 * \#887 - limit the size of rationals that can be passed in from user input -IMPROVEMENTS -* bank module uses go-wire codec instead of 'encoding/json' -* auth module uses go-wire codec instead of 'encoding/json' -* revised use of endblock and beginblock -* [stake] module reorganized to include `types` and `keeper` package -* [stake] keeper always loads the store (instead passing around which doesn't really boost efficiency) -* [stake] edit-validator changes now can use the keyword [do-not-modify] to not modify unspecified `--flag` (aka won't set them to `""` value) -* [types] added common tag constants -* [stake] offload more generic functionality from the handler into the keeper -* added contributing guidelines - ## 0.19.0 *June 13, 2018* From 544454c3bdb411cf363cad6f705aee3fdf205e80 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 1 Jul 2018 12:36:15 -0400 Subject: [PATCH 67/77] version --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index 4966455689..b9de4f9916 100644 --- a/version/version.go +++ b/version/version.go @@ -5,7 +5,7 @@ const Maj = "0" const Min = "20" const Fix = "0" -const Version = "0.20.0-dev" +const Version = "0.20.0" // GitCommit set by build flags var GitCommit = "" From dbabc2e79fdc7fc10fa47d57edbccc36eff3a193 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 1 Jul 2018 12:56:31 -0400 Subject: [PATCH 68/77] update tendermint to fix stopping WAL --- Gopkg.lock | 6 +++--- Gopkg.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index f02a671164..92fe403aea 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -388,8 +388,8 @@ "types", "version" ] - revision = "3a0dff7db2628c20cb0d77db3a01fea7981e5aec" - version = "v0.22.0-rc0" + revision = "af703620d4423478968ab602716a2a51cbb02ac6" + version = "v0.22.0-rc1" [[projects]] name = "github.com/tendermint/tmlibs" @@ -512,6 +512,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "5db688e81022b54f18b174b151ccb66ab9a5b373008089422a5eea1147555f3e" + inputs-digest = "e625f9f13e5ca81fb8ecf6e794e0d1df87d8597a84af2abf70c057e20aa9b852" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index eedc0df761..a9bae1d06f 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -62,7 +62,7 @@ [[constraint]] name = "github.com/tendermint/tendermint" - version = "=0.22.0-rc0" + version = "=0.22.0-rc1" [[constraint]] name = "github.com/tendermint/tmlibs" From 0845d8126e4b53745fc3a10cfe7d5bb38c138c3b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 1 Jul 2018 15:10:45 -0400 Subject: [PATCH 69/77] server: remove broken start test --- server/start.go | 13 +++++++------ server/start_test.go | 31 +------------------------------ server/test_helpers.go | 24 ------------------------ 3 files changed, 8 insertions(+), 60 deletions(-) diff --git a/server/start.go b/server/start.go index a2cd57f929..c848c9e6ee 100644 --- a/server/start.go +++ b/server/start.go @@ -31,7 +31,8 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { return startStandAlone(ctx, appCreator) } ctx.Logger.Info("Starting ABCI with Tendermint") - return startInProcess(ctx, appCreator) + _, err := startInProcess(ctx, appCreator) + return err }, } @@ -74,12 +75,12 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error { return nil } -func startInProcess(ctx *Context, appCreator AppCreator) error { +func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) { cfg := ctx.Config home := cfg.RootDir app, err := appCreator(home, ctx.Logger) if err != nil { - return err + return nil, err } // Create & start tendermint node @@ -91,15 +92,15 @@ func startInProcess(ctx *Context, appCreator AppCreator) error { node.DefaultMetricsProvider, ctx.Logger.With("module", "node")) if err != nil { - return err + return nil, err } err = n.Start() if err != nil { - return err + return nil, err } // Trap signal, run forever. n.RunForever() - return nil + return n, nil } diff --git a/server/start_test.go b/server/start_test.go index 278c793cbd..3817e1ee89 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -6,7 +6,6 @@ import ( "testing" "time" - "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/server/mock" @@ -45,37 +44,9 @@ func TestStartStandAlone(t *testing.T) { svr.SetLogger(logger.With("module", "abci-server")) svr.Start() - timer := time.NewTimer(time.Duration(5) * time.Second) + timer := time.NewTimer(time.Duration(2) * time.Second) select { case <-timer.C: svr.Stop() } } - -func TestStartWithTendermint(t *testing.T) { - defer setupViper(t)() - - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)). - With("module", "mock-cmd") - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) - ctx := NewContext(cfg, logger) - cdc := wire.NewCodec() - appInit := AppInit{ - AppGenState: mock.AppGenState, - AppGenTx: mock.AppGenTx, - } - initCmd := InitCmd(ctx, cdc, appInit) - err = initCmd.RunE(nil, nil) - require.NoError(t, err) - - // set up app and start up - viper.Set(flagWithTendermint, true) - startCmd := StartCmd(ctx, mock.NewApp) - svrAddr, _, err := FreeTCPAddr() - require.NoError(t, err) - startCmd.Flags().Set(flagAddress, svrAddr) // set to a new free address - timeout := time.Duration(5) * time.Second - - close(RunOrTimeout(startCmd, timeout, t)) -} diff --git a/server/test_helpers.go b/server/test_helpers.go index 5abf57c17c..8de4672e33 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -6,9 +6,7 @@ import ( "net" "os" "testing" - "time" - "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/tendermint/tmlibs/cli" @@ -52,25 +50,3 @@ func setupViper(t *testing.T) func() { } } } - -// Run or Timout RunE of command passed in -func RunOrTimeout(cmd *cobra.Command, timeout time.Duration, t *testing.T) chan error { - done := make(chan error) - go func(out chan<- error) { - // this should NOT exit - err := cmd.RunE(nil, nil) - if err != nil { - out <- err - } - out <- fmt.Errorf("start died for unknown reasons") - }(done) - timer := time.NewTimer(timeout) - - select { - case err := <-done: - require.NoError(t, err) - case <-timer.C: - return done - } - return done -} From f78f30c67a662f92bde872acf2a13350257d195f Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 2 Jul 2018 16:34:06 -0400 Subject: [PATCH 70/77] update for tm v0.22.0. tmlibs->tendermint/libs --- Gopkg.lock | 36 ++++++++++++------- Gopkg.toml | 2 +- baseapp/baseapp.go | 6 ++-- baseapp/baseapp_test.go | 6 ++-- baseapp/helpers.go | 2 +- client/context/helpers.go | 4 +-- client/keys.go | 2 +- client/keys/add.go | 2 +- client/keys/utils.go | 4 +-- client/lcd/lcd_test.go | 2 +- client/lcd/root.go | 4 +-- client/lcd/test_helpers.go | 6 ++-- client/tx/query.go | 2 +- cmd/gaia/app/app.go | 6 ++-- cmd/gaia/cmd/gaiacli/main.go | 2 +- cmd/gaia/cmd/gaiad/main.go | 6 ++-- cmd/gaia/cmd/gaiadebug/hack.go | 6 ++-- crypto/keys/keybase.go | 2 +- crypto/keys/keybase_test.go | 2 +- crypto/keys/mintkey.go | 2 +- docs/core/examples/app1.go | 6 ++-- docs/core/examples/app2.go | 6 ++-- docs/core/examples/app3.go | 6 ++-- docs/core/examples/app4.go | 6 ++-- examples/basecoin/app/app.go | 6 ++-- examples/basecoin/app/app_test.go | 4 +-- examples/basecoin/cmd/basecli/main.go | 2 +- examples/basecoin/cmd/basecoind/main.go | 6 ++-- examples/democoin/app/app.go | 6 ++-- examples/democoin/app/app_test.go | 4 +-- examples/democoin/cmd/democli/main.go | 2 +- examples/democoin/cmd/democoind/main.go | 6 ++-- .../democoin/x/assoc/validator_set_test.go | 2 +- examples/democoin/x/cool/keeper_test.go | 2 +- examples/democoin/x/oracle/oracle_test.go | 2 +- examples/democoin/x/pow/handler_test.go | 2 +- examples/democoin/x/pow/keeper_test.go | 4 +-- .../democoin/x/simplestake/keeper_test.go | 4 +-- examples/kvstore/main.go | 8 ++--- server/constructors.go | 4 +-- server/init.go | 6 ++-- server/init_test.go | 2 +- server/mock/app.go | 4 +-- server/mock/helpers.go | 2 +- server/mock/store.go | 2 +- server/mock/store_test.go | 2 +- server/start.go | 2 +- server/start_test.go | 2 +- server/test_helpers.go | 2 +- server/testnet.go | 2 +- server/util.go | 6 ++-- store/cachekvstore.go | 2 +- store/cachekvstore_test.go | 4 +-- store/dbstoreadapter.go | 2 +- store/firstlast.go | 2 +- store/gaskvstore_test.go | 2 +- store/iavlstore.go | 4 +-- store/iavlstore_test.go | 4 +-- store/memiterator.go | 4 +-- store/prefixstore_test.go | 2 +- store/rootmultistore.go | 4 +-- store/rootmultistore_test.go | 4 +-- tests/gobash.go | 2 +- types/account.go | 4 +-- types/context.go | 2 +- types/context_test.go | 4 +-- types/errors.go | 2 +- types/lib/linear_test.go | 4 +-- types/store.go | 4 +-- types/tags.go | 2 +- x/auth/ante_test.go | 2 +- x/auth/context_test.go | 2 +- x/auth/feekeeper_test.go | 2 +- x/auth/mapper_test.go | 4 +-- x/auth/mock/app.go | 4 +-- x/bank/keeper_test.go | 4 +-- x/ibc/client/cli/relay.go | 2 +- x/ibc/ibc_test.go | 4 +-- x/slashing/client/cli/query.go | 2 +- x/slashing/test_common.go | 4 +-- x/stake/client/cli/query.go | 2 +- x/stake/keeper/test_common.go | 4 +-- 82 files changed, 165 insertions(+), 153 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 92fe403aea..965fc745d9 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -267,8 +267,8 @@ [[projects]] name = "github.com/spf13/cobra" packages = ["."] - revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" - version = "v0.0.3" + revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b" + version = "v0.0.1" [[projects]] branch = "master" @@ -285,8 +285,8 @@ [[projects]] name = "github.com/spf13/viper" packages = ["."] - revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736" - version = "v1.0.2" + revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" + version = "v1.0.0" [[projects]] name = "github.com/stretchr/testify" @@ -355,9 +355,18 @@ "consensus", "consensus/types", "crypto", + "crypto/merkle", "crypto/tmhash", "evidence", + "libs/autofile", + "libs/cli", + "libs/cli/flags", + "libs/clist", + "libs/common", + "libs/db", "libs/events", + "libs/flowrate", + "libs/log", "libs/pubsub", "libs/pubsub/query", "lite", @@ -388,20 +397,17 @@ "types", "version" ] - revision = "af703620d4423478968ab602716a2a51cbb02ac6" - version = "v0.22.0-rc1" + revision = "5923b6288fe8ce9581936ee97c2bf9cf9c02c2f4" + version = "v0.22.0-rc2" [[projects]] name = "github.com/tendermint/tmlibs" packages = [ - "autofile", "bech32", "cli", "cli/flags", - "clist", "common", "db", - "flowrate", "log", "merkle", "merkle/tmhash" @@ -484,9 +490,13 @@ packages = [ ".", "balancer", + "balancer/base", + "balancer/roundrobin", "codes", "connectivity", "credentials", + "encoding", + "encoding/proto", "grpclb/grpc_lb_v1/messages", "grpclog", "internal", @@ -495,13 +505,15 @@ "naming", "peer", "resolver", + "resolver/dns", + "resolver/passthrough", "stats", "status", "tap", "transport" ] - revision = "5b3c4e850e90a4cf6a20ebd46c8b32a0a3afcb9e" - version = "v1.7.5" + revision = "d11072e7ca9811b1100b80ca0269ac831f06d024" + version = "v1.11.3" [[projects]] name = "gopkg.in/yaml.v2" @@ -512,6 +524,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "e625f9f13e5ca81fb8ecf6e794e0d1df87d8597a84af2abf70c057e20aa9b852" + inputs-digest = "e0adc07b8fcd9a48957baaa58a97b3bf1c72af18d06c7943b719794746ded31e" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index a9bae1d06f..910a3d56c2 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -62,7 +62,7 @@ [[constraint]] name = "github.com/tendermint/tendermint" - version = "=0.22.0-rc1" + version = "=0.22.0-rc2" [[constraint]] name = "github.com/tendermint/tmlibs" diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 1b4e701196..afc060cc35 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -8,9 +8,9 @@ import ( "github.com/pkg/errors" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 0d0b226265..b6032e035b 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -12,9 +12,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" diff --git a/baseapp/helpers.go b/baseapp/helpers.go index 65c18315fd..2d7419a98c 100644 --- a/baseapp/helpers.go +++ b/baseapp/helpers.go @@ -3,7 +3,7 @@ package baseapp import ( "github.com/tendermint/tendermint/abci/server" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" ) // RunForever - BasecoinApp execution and cleanup diff --git a/client/context/helpers.go b/client/context/helpers.go index 8dd813f824..54c1463ee6 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -3,7 +3,7 @@ package context import ( "fmt" - "github.com/tendermint/tmlibs/common" + "github.com/tendermint/tendermint/libs/common" "github.com/pkg/errors" @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/keys" diff --git a/client/keys.go b/client/keys.go index 8c11561c5f..a39b074b98 100644 --- a/client/keys.go +++ b/client/keys.go @@ -2,7 +2,7 @@ package client import ( "github.com/cosmos/cosmos-sdk/crypto/keys" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" ) // GetKeyBase initializes a keybase based on the given db. diff --git a/client/keys/add.go b/client/keys/add.go index a39a374c82..12ad97ee8a 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -15,7 +15,7 @@ import ( ccrypto "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/tendermint/tmlibs/cli" + "github.com/tendermint/tendermint/libs/cli" ) const ( diff --git a/client/keys/utils.go b/client/keys/utils.go index c0d7f876fa..aaa7c37f83 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -7,8 +7,8 @@ import ( "github.com/spf13/viper" keys "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/tendermint/tmlibs/cli" - dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tendermint/libs/cli" + dbm "github.com/tendermint/tendermint/libs/db" "github.com/cosmos/cosmos-sdk/client" diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 1b1a02fefb..229e8d7137 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -15,7 +15,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" p2p "github.com/tendermint/tendermint/p2p" ctypes "github.com/tendermint/tendermint/rpc/core/types" - "github.com/tendermint/tmlibs/common" + "github.com/tendermint/tendermint/libs/common" client "github.com/cosmos/cosmos-sdk/client" keys "github.com/cosmos/cosmos-sdk/client/keys" diff --git a/client/lcd/root.go b/client/lcd/root.go index 472c914060..e79ffd2f13 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -7,10 +7,10 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" tmserver "github.com/tendermint/tendermint/rpc/lib/server" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" client "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index dbdf9b724d..0467262396 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -24,9 +24,9 @@ import ( "github.com/tendermint/tendermint/proxy" tmrpc "github.com/tendermint/tendermint/rpc/lib/server" tmtypes "github.com/tendermint/tendermint/types" - "github.com/tendermint/tmlibs/cli" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/cli" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/client" keys "github.com/cosmos/cosmos-sdk/client/keys" diff --git a/client/tx/query.go b/client/tx/query.go index e70ecea399..dfe626c38c 100644 --- a/client/tx/query.go +++ b/client/tx/query.go @@ -6,7 +6,7 @@ import ( "net/http" "strconv" - "github.com/tendermint/tmlibs/common" + "github.com/tendermint/tendermint/libs/common" "github.com/gorilla/mux" "github.com/spf13/cobra" diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 399c816830..77b179765e 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -6,9 +6,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 37e3f1664f..4ab5d02b98 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -3,7 +3,7 @@ package main import ( "github.com/spf13/cobra" - "github.com/tendermint/tmlibs/cli" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/keys" diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 1915ef7517..d96275de65 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -7,9 +7,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" - "github.com/tendermint/tmlibs/cli" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/cli" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/server" diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 74b42adb38..1f2ef0649d 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -10,9 +10,9 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index 396bb57821..82adc53dda 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" tcrypto "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys/bip39" diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index ac0f7fa4da..c910849865 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" ) // TestKeyManagement makes sure we can manipulate these keys well diff --git a/crypto/keys/mintkey.go b/crypto/keys/mintkey.go index 8b0a1870bb..cfba18e092 100644 --- a/crypto/keys/mintkey.go +++ b/crypto/keys/mintkey.go @@ -4,7 +4,7 @@ import ( "encoding/hex" "fmt" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" "github.com/cosmos/cosmos-sdk/crypto/keys/bcrypt" "github.com/tendermint/tendermint/crypto" diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index 9daf8d3334..f9eceecdb5 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -3,9 +3,9 @@ package app import ( "encoding/json" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index d7490765e5..b4d44dca7b 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -6,9 +6,9 @@ import ( "fmt" "github.com/tendermint/tendermint/crypto" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index d871a1cfd3..f99e34b8b2 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -1,9 +1,9 @@ package app import ( - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index 007d2842bc..22282738f6 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -2,9 +2,9 @@ package app import ( abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index 089d1ca23c..a182b83dd7 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -5,9 +5,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 499c0e4082..0b5d37dc4f 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -16,8 +16,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" ) func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error { diff --git a/examples/basecoin/cmd/basecli/main.go b/examples/basecoin/cmd/basecli/main.go index 1191aab6ab..d99a9178d4 100644 --- a/examples/basecoin/cmd/basecli/main.go +++ b/examples/basecoin/cmd/basecli/main.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" - "github.com/tendermint/tmlibs/cli" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/keys" diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index f3f3de519a..9d026922cc 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -8,9 +8,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" - "github.com/tendermint/tmlibs/cli" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/cli" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/examples/basecoin/app" "github.com/cosmos/cosmos-sdk/server" diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 195af0c9ea..100e25435d 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -5,9 +5,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index 36aca760f1..a642eff72d 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -14,8 +14,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" ) func setGenesis(bapp *DemocoinApp, trend string, accs ...auth.BaseAccount) error { diff --git a/examples/democoin/cmd/democli/main.go b/examples/democoin/cmd/democli/main.go index cbf43508ba..43f86504eb 100644 --- a/examples/democoin/cmd/democli/main.go +++ b/examples/democoin/cmd/democli/main.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" - "github.com/tendermint/tmlibs/cli" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/keys" diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 92f9618b04..1cc22b8877 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -8,9 +8,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" - "github.com/tendermint/tmlibs/cli" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/cli" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/examples/democoin/app" "github.com/cosmos/cosmos-sdk/server" diff --git a/examples/democoin/x/assoc/validator_set_test.go b/examples/democoin/x/assoc/validator_set_test.go index c20aeb8571..e5932c14b3 100644 --- a/examples/democoin/x/assoc/validator_set_test.go +++ b/examples/democoin/x/assoc/validator_set_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" "github.com/cosmos/cosmos-sdk/examples/democoin/mock" "github.com/cosmos/cosmos-sdk/store" diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index ee2e529f26..f0d65a545e 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/examples/democoin/x/oracle/oracle_test.go b/examples/democoin/x/oracle/oracle_test.go index 228378c34a..ef925c94f4 100644 --- a/examples/democoin/x/oracle/oracle_test.go +++ b/examples/democoin/x/oracle/oracle_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" "github.com/cosmos/cosmos-sdk/examples/democoin/mock" "github.com/cosmos/cosmos-sdk/store" diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index 77a22057bc..283c30ef59 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index 31ad2fc121..7a9b869849 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index be8e335e2b..4496eb369c 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -9,8 +9,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/examples/kvstore/main.go b/examples/kvstore/main.go index c2c56eba5f..47416da057 100644 --- a/examples/kvstore/main.go +++ b/examples/kvstore/main.go @@ -8,10 +8,10 @@ import ( "github.com/spf13/viper" "github.com/tendermint/tendermint/abci/server" - "github.com/tendermint/tmlibs/cli" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/cli" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/server/constructors.go b/server/constructors.go index 79e1558c4b..d93a1defec 100644 --- a/server/constructors.go +++ b/server/constructors.go @@ -6,8 +6,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" ) // AppCreator lets us lazily initialize app, using home dir diff --git a/server/init.go b/server/init.go index ed1727e35e..31d3001e90 100644 --- a/server/init.go +++ b/server/init.go @@ -21,9 +21,9 @@ import ( "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" tmtypes "github.com/tendermint/tendermint/types" - tmcli "github.com/tendermint/tmlibs/cli" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" + tmcli "github.com/tendermint/tendermint/libs/cli" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" clkeys "github.com/cosmos/cosmos-sdk/client/keys" serverconfig "github.com/cosmos/cosmos-sdk/server/config" diff --git a/server/init_test.go b/server/init_test.go index f05bcb54a1..fb448bf5fa 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/server/mock" "github.com/cosmos/cosmos-sdk/wire" diff --git a/server/mock/app.go b/server/mock/app.go index b2d19e2e9e..c99150b979 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -8,8 +8,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bam "github.com/cosmos/cosmos-sdk/baseapp" gc "github.com/cosmos/cosmos-sdk/server/config" diff --git a/server/mock/helpers.go b/server/mock/helpers.go index 4510f4e905..88aacb4d8e 100644 --- a/server/mock/helpers.go +++ b/server/mock/helpers.go @@ -6,7 +6,7 @@ import ( "os" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" ) // SetupApp returns an application as well as a clean-up function diff --git a/server/mock/store.go b/server/mock/store.go index 9dca581596..d62b9ad23e 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -1,7 +1,7 @@ package mock import ( - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/server/mock/store_test.go b/server/mock/store_test.go index bf6a1007b6..0ea5ffd2c7 100644 --- a/server/mock/store_test.go +++ b/server/mock/store_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/server/start.go b/server/start.go index c848c9e6ee..4f90930262 100644 --- a/server/start.go +++ b/server/start.go @@ -11,7 +11,7 @@ import ( "github.com/tendermint/tendermint/node" pvm "github.com/tendermint/tendermint/privval" "github.com/tendermint/tendermint/proxy" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" ) const ( diff --git a/server/start_test.go b/server/start_test.go index 3817e1ee89..570071e7bf 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/tendermint/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" ) func TestStartStandAlone(t *testing.T) { diff --git a/server/test_helpers.go b/server/test_helpers.go index 8de4672e33..d1230898dd 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" - "github.com/tendermint/tmlibs/cli" + "github.com/tendermint/tendermint/libs/cli" ) // Get a free address for a test tendermint server diff --git a/server/testnet.go b/server/testnet.go index a60701d246..d102b87ccb 100644 --- a/server/testnet.go +++ b/server/testnet.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/spf13/viper" cfg "github.com/tendermint/tendermint/config" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" ) var ( diff --git a/server/util.go b/server/util.go index bd9d48d752..d1ad001c52 100644 --- a/server/util.go +++ b/server/util.go @@ -15,9 +15,9 @@ import ( "github.com/cosmos/cosmos-sdk/wire" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" cfg "github.com/tendermint/tendermint/config" - "github.com/tendermint/tmlibs/cli" - tmflags "github.com/tendermint/tmlibs/cli/flags" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/cli" + tmflags "github.com/tendermint/tendermint/libs/cli/flags" + "github.com/tendermint/tendermint/libs/log" ) // server context diff --git a/store/cachekvstore.go b/store/cachekvstore.go index aeed6ee5fe..1263cef5f3 100644 --- a/store/cachekvstore.go +++ b/store/cachekvstore.go @@ -5,7 +5,7 @@ import ( "sort" "sync" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" ) // If value is nil but deleted is false, it means the parent doesn't have the diff --git a/store/cachekvstore_test.go b/store/cachekvstore_test.go index f9be76dae3..e7958dfcdf 100644 --- a/store/cachekvstore_test.go +++ b/store/cachekvstore_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/stretchr/testify/require" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" ) func newCacheKVStore() CacheKVStore { diff --git a/store/dbstoreadapter.go b/store/dbstoreadapter.go index 59369af563..09d48cf9d9 100644 --- a/store/dbstoreadapter.go +++ b/store/dbstoreadapter.go @@ -2,7 +2,7 @@ package store import ( sdk "github.com/cosmos/cosmos-sdk/types" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" ) type dbStoreAdapter struct { diff --git a/store/firstlast.go b/store/firstlast.go index e6cb084323..70f6659a87 100644 --- a/store/firstlast.go +++ b/store/firstlast.go @@ -3,7 +3,7 @@ package store import ( "bytes" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" ) // Gets the first item. diff --git a/store/gaskvstore_test.go b/store/gaskvstore_test.go index 524dc53237..fe84affa28 100644 --- a/store/gaskvstore_test.go +++ b/store/gaskvstore_test.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" ) func newGasKVStore() KVStore { diff --git a/store/iavlstore.go b/store/iavlstore.go index 5758802c6e..2911598033 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -7,8 +7,8 @@ import ( "github.com/tendermint/go-amino" "github.com/tendermint/iavl" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index b23f04e5cd..50d690d908 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -7,8 +7,8 @@ import ( "github.com/tendermint/iavl" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/store/memiterator.go b/store/memiterator.go index a05f3443ed..a72418db63 100644 --- a/store/memiterator.go +++ b/store/memiterator.go @@ -3,8 +3,8 @@ package store import ( "bytes" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" ) // Iterates over iterKVCache items. diff --git a/store/prefixstore_test.go b/store/prefixstore_test.go index 76fb7f481f..f57ab20e40 100644 --- a/store/prefixstore_test.go +++ b/store/prefixstore_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/iavl" - dbm "github.com/tendermint/tmlibs/db" + dbm "github.com/tendermint/tendermint/libs/db" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 11e089182f..28d9e7e68a 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -7,8 +7,8 @@ import ( "golang.org/x/crypto/ripemd160" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/merkle" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/crypto/merkle" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/store/rootmultistore_test.go b/store/rootmultistore_test.go index 197726f4ac..137f04eabb 100644 --- a/store/rootmultistore_test.go +++ b/store/rootmultistore_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/merkle" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/crypto/merkle" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/tests/gobash.go b/tests/gobash.go index f46bad3c1c..b2d765281a 100644 --- a/tests/gobash.go +++ b/tests/gobash.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/stretchr/testify/require" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" ) // Execute the command, return stdout, logging stdout/err to t. diff --git a/types/account.go b/types/account.go index bd7cbb29cd..ce872d8b54 100644 --- a/types/account.go +++ b/types/account.go @@ -6,8 +6,8 @@ import ( "fmt" "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tmlibs/bech32" - cmn "github.com/tendermint/tmlibs/common" + "github.com/tendermint/tendermint/libs/bech32" + cmn "github.com/tendermint/tendermint/libs/common" ) //Address is a go crypto-style Address diff --git a/types/context.go b/types/context.go index 276a664803..e55eff1ab0 100644 --- a/types/context.go +++ b/types/context.go @@ -7,7 +7,7 @@ import ( "github.com/golang/protobuf/proto" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" ) /* diff --git a/types/context_test.go b/types/context_test.go index cad2076640..fb2786cffa 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/require" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/types" diff --git a/types/errors.go b/types/errors.go index 392a954d16..6969549d90 100644 --- a/types/errors.go +++ b/types/errors.go @@ -3,7 +3,7 @@ package types import ( "fmt" - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" abci "github.com/tendermint/tendermint/abci/types" ) diff --git a/types/lib/linear_test.go b/types/lib/linear_test.go index 8b5a63fd41..b14300a987 100644 --- a/types/lib/linear_test.go +++ b/types/lib/linear_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" abci "github.com/tendermint/tendermint/abci/types" diff --git a/types/store.go b/types/store.go index 5aecd7d093..04de2c7c1a 100644 --- a/types/store.go +++ b/types/store.go @@ -4,8 +4,8 @@ import ( "fmt" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" ) // NOTE: These are implemented in cosmos-sdk/store. diff --git a/types/tags.go b/types/tags.go index 6bd721a5fc..add0c0ad54 100644 --- a/types/tags.go +++ b/types/tags.go @@ -1,7 +1,7 @@ package types import ( - cmn "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tendermint/libs/common" ) // Type synonym for convenience diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index 1808afc99c..aebf66f9a2 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" diff --git a/x/auth/context_test.go b/x/auth/context_test.go index 5f432be357..b58547328d 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/auth/feekeeper_test.go b/x/auth/feekeeper_test.go index e935bb4c49..a53839a8b4 100644 --- a/x/auth/feekeeper_test.go +++ b/x/auth/feekeeper_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index 4b270f0225..6b242e683b 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/auth/mock/app.go b/x/auth/mock/app.go index 9c672b5a78..758b1efab8 100644 --- a/x/auth/mock/app.go +++ b/x/auth/mock/app.go @@ -5,8 +5,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index b35298be9d..c545b774f0 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go index 2dc3129c6e..d434ff35a4 100644 --- a/x/ibc/client/cli/relay.go +++ b/x/ibc/client/cli/relay.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/tmlibs/log" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index 33535145d8..4cb708c1bb 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -7,8 +7,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index c1b16eb3a3..3e2023f5eb 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/tmlibs/cli" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 2d192c54df..edf119bc7f 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -9,8 +9,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index c162717efd..bccfd7c2be 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/tmlibs/cli" + "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 17b21c6346..aa3c25aba9 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -10,8 +10,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" From 64d5e3fa47cf967c890285c6a53400b9ccafd0f1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 2 Jul 2018 16:37:24 -0400 Subject: [PATCH 71/77] dev version --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index b9de4f9916..4966455689 100644 --- a/version/version.go +++ b/version/version.go @@ -5,7 +5,7 @@ const Maj = "0" const Min = "20" const Fix = "0" -const Version = "0.20.0" +const Version = "0.20.0-dev" // GitCommit set by build flags var GitCommit = "" From 498aed433e2ba57820842f77c0c65de92957ee95 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 2 Jul 2018 16:46:35 -0400 Subject: [PATCH 72/77] update changelog --- CHANGELOG.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23b7c89813..8fcd911cca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,37 +5,43 @@ *TBD* BREAKING CHANGES -* [config] Change default ports from 466xx to 266xx -* [auth] AltBytes renamed to Memo, now a string, max 100 characters, costs a bit of gas -* [types] GetMsg() -> GetMsgs() -* [auth] Signers of a transaction now only sign over their account and sequence number +* Update Tendermint to v0.22.0 + * Default ports changed from 466xx to 266xx + * Amino JSON uses type names instead of prefix bytes + * ED25519 addresses are the first 20-bytes of the SHA256 of the raw 32-byte + pubkey + * go-crypto, abci, tmlibs have been merged into Tendermint + * Various other fixes +* [auth] Signers of a transaction now only sign over their own account and sequence number * [auth] Removed MsgChangePubKey * [auth] Removed SetPubKey from account mapper +* [auth] AltBytes renamed to Memo, now a string, max 100 characters, costs a bit of gas +* [types] `GetMsg()` -> `GetMsgs()` as txs wrap many messages * [types] Removed GetMemo from Tx (it is still on StdTx) +* [types] renamed rational.Evaluate to rational.Round{Int64, Int} * [keys] Keybase and Ledger support from go-crypto merged into the SDK in the `crypto` folder -* [x/gov] Gov module REST endpoints changed to be more RESTful * [cli] Rearranged commands under subcommands -* [stake] Remove Tick and add EndBlocker -* [stake] Introduce concept of unbonding for delegations and validators +* [x/gov] Gov module REST endpoints changed to be more RESTful +* [x/stake] Remove Tick and add EndBlocker +* [x/stake] Introduce concept of unbonding for delegations and validators * `gaiacli stake unbond` replaced with `gaiacli stake begin-unbonding` * Introduced: * `gaiacli stake complete-unbonding` * `gaiacli stake begin-redelegation` * `gaiacli stake complete-redelegation` -* [slashing] Update slashing for unbonding period +* [x/slashing] Update slashing for unbonding period * Slash according to power at time of infraction instead of power at time of discovery * Iterate through unbonding delegations & redelegations which contributed to an infraction, slash them proportional to their stake at the time * Add REST endpoint to unrevoke a validator previously revoked for downtime * Add REST endpoint to retrieve liveness signing information for a validator -* [types] renamed rational.Evaluate to rational.Round{Int64, Int} FEATURES * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag * [lcd] Queried TXs now include the tx hash to identify each tx * [mockapp] CompleteSetup() no longer takes a testing parameter -* [governance] Implemented MVP +* [x/gov] Implemented MVP * Supported proposal types: just binary (pass/fail) TextProposals for now * Proposals need deposits to be votable; deposits are burned if proposal fails * Delegators delegate votes to validator by default but can override (for their stake) @@ -55,7 +61,7 @@ FEATURES * [server] Default config now creates a profiler at port 6060, and increase p2p send/recv rates * [tests] Add WaitForNextNBlocksTM helper method * [types] Switches internal representation of Int/Uint/Rat to use pointers -* [gaiad] unsafe_reset_all now resets addrbook.json +* [gaiad] `unsafe_reset_all` now resets addrbook.json * [democoin] add x/oracle, x/assoc * [gaiacli] Ledger support added - You can now use a Ledger with `gaiacli --ledger` for all key-related commands From fe7a5a01bdfd10d1d111e4e6e3f469709ce9d8e9 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 2 Jul 2018 17:22:25 -0400 Subject: [PATCH 73/77] update iavl to remove tmlibs dep --- Gopkg.lock | 30 ++++++------------------------ Gopkg.toml | 2 +- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 965fc745d9..a9b4a1f5cf 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -137,7 +137,6 @@ ".", "hcl/ast", "hcl/parser", - "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -334,12 +333,9 @@ [[projects]] name = "github.com/tendermint/iavl" - packages = [ - ".", - "sha256truncated" - ] - revision = "2de525d09cca7c45c3f43d178817947a6cfa242c" - version = "v0.8.1" + packages = ["."] + revision = "9e5dc3e61f70b285bb25414452d47aca1ff34c1d" + version = "v0.8.2-rc0" [[projects]] name = "github.com/tendermint/tendermint" @@ -359,6 +355,7 @@ "crypto/tmhash", "evidence", "libs/autofile", + "libs/bech32", "libs/cli", "libs/cli/flags", "libs/clist", @@ -400,21 +397,6 @@ revision = "5923b6288fe8ce9581936ee97c2bf9cf9c02c2f4" version = "v0.22.0-rc2" -[[projects]] - name = "github.com/tendermint/tmlibs" - packages = [ - "bech32", - "cli", - "cli/flags", - "common", - "db", - "log", - "merkle", - "merkle/tmhash" - ] - revision = "49596e0a1f48866603813df843c9409fc19805c6" - version = "v0.9.0" - [[projects]] name = "github.com/zondax/ledger-goclient" packages = ["."] @@ -451,7 +433,7 @@ "netutil", "trace" ] - revision = "4cb1c02c05b0e749b0365f61ae859a8e0cfceed9" + revision = "87b3feba568e144938625fc5d80ec92566c1a8fe" [[projects]] branch = "master" @@ -524,6 +506,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "e0adc07b8fcd9a48957baaa58a97b3bf1c72af18d06c7943b719794746ded31e" + inputs-digest = "13ad2a57b6942729e2d08b5c37810d62108aa64a335a4822fcff1ad992c0662b" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 910a3d56c2..486293af71 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -58,7 +58,7 @@ [[constraint]] name = "github.com/tendermint/iavl" - version = "=v0.8.1" + version = "=v0.8.2-rc0" [[constraint]] name = "github.com/tendermint/tendermint" From 60a8a63e62eb6c720e818f45e4a668378aae38b4 Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Tue, 26 Jun 2018 13:01:45 -0700 Subject: [PATCH 74/77] base variabls / logic, need tests --- store/iavlstore.go | 31 +++++++++++++++++-------------- store/iavlstore_test.go | 13 +++++++------ store/prefixstore_test.go | 2 +- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/store/iavlstore.go b/store/iavlstore.go index 2911598033..16fb8e4f04 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -15,7 +15,8 @@ import ( const ( defaultIAVLCacheSize = 10000 - defaultIAVLNumHistory = 1<<53 - 1 // DEPRECATED + defaultIAVLNumRecent = 1000 + defaultIAVLStoreEvery = 10000 ) // load the iavl store @@ -25,7 +26,7 @@ func LoadIAVLStore(db dbm.DB, id CommitID) (CommitStore, error) { if err != nil { return nil, err } - store := newIAVLStore(tree, defaultIAVLNumHistory) + store := newIAVLStore(tree, defaultIAVLNumRecent, defaultIAVLStoreEvery) return store, nil } @@ -43,16 +44,17 @@ type iavlStore struct { // How many old versions we hold onto. // A value of 0 means keep all history. - numHistory int64 + numRecent int64 + + storeEvery int64 } // CONTRACT: tree should be fully loaded. -// TODO: use more numHistory's, so the below nolint can be removed -// nolint: unparam -func newIAVLStore(tree *iavl.VersionedTree, numHistory int64) *iavlStore { +func newIAVLStore(tree *iavl.VersionedTree, numRecent int64, storeEvery int64) *iavlStore { st := &iavlStore{ tree: tree, - numHistory: numHistory, + numRecent: numRecent, + storeEvery: storeEvery, } return st } @@ -67,13 +69,14 @@ func (st *iavlStore) Commit() CommitID { panic(err) } - // Release an old version of history - if st.numHistory > 0 && (st.numHistory < st.tree.Version64()) { - toRelease := version - st.numHistory - err := st.tree.DeleteVersion(toRelease) - if err != nil { - // TODO: Handle with #870 - panic(err) + // Release an old version of history, if not a sync waypoint + if st.numRecent < st.tree.Version64() { + toRelease := version - st.numRecent + if toRelease%st.storeEvery != 0 { + err := st.tree.DeleteVersion(toRelease) + if err != nil { + panic(err) + } } } diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index 50d690d908..adae84f1ab 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -15,7 +15,8 @@ import ( var ( cacheSize = 100 - numHistory int64 = 5 + numRecent int64 = 5 + storeEvery int64 = 3 ) var ( @@ -45,7 +46,7 @@ func newTree(t *testing.T, db dbm.DB) (*iavl.VersionedTree, CommitID) { func TestIAVLStoreGetSetHasDelete(t *testing.T) { db := dbm.NewMemDB() tree, _ := newTree(t, db) - iavlStore := newIAVLStore(tree, numHistory) + iavlStore := newIAVLStore(tree, numRecent, storeEvery) key := "hello" @@ -70,7 +71,7 @@ func TestIAVLStoreGetSetHasDelete(t *testing.T) { func TestIAVLIterator(t *testing.T) { db := dbm.NewMemDB() tree, _ := newTree(t, db) - iavlStore := newIAVLStore(tree, numHistory) + iavlStore := newIAVLStore(tree, numRecent, storeEvery) iter := iavlStore.Iterator([]byte("aloha"), []byte("hellz")) expected := []string{"aloha", "hello"} var i int @@ -143,7 +144,7 @@ func TestIAVLIterator(t *testing.T) { func TestIAVLSubspaceIterator(t *testing.T) { db := dbm.NewMemDB() tree, _ := newTree(t, db) - iavlStore := newIAVLStore(tree, numHistory) + iavlStore := newIAVLStore(tree, numRecent, storeEvery) iavlStore.Set([]byte("test1"), []byte("test1")) iavlStore.Set([]byte("test2"), []byte("test2")) @@ -202,7 +203,7 @@ func TestIAVLSubspaceIterator(t *testing.T) { func TestIAVLReverseSubspaceIterator(t *testing.T) { db := dbm.NewMemDB() tree, _ := newTree(t, db) - iavlStore := newIAVLStore(tree, numHistory) + iavlStore := newIAVLStore(tree, numRecent, storeEvery) iavlStore.Set([]byte("test1"), []byte("test1")) iavlStore.Set([]byte("test2"), []byte("test2")) @@ -261,7 +262,7 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) { func TestIAVLStoreQuery(t *testing.T) { db := dbm.NewMemDB() tree := iavl.NewVersionedTree(db, cacheSize) - iavlStore := newIAVLStore(tree, numHistory) + iavlStore := newIAVLStore(tree, numRecent, storeEvery) k1, v1 := []byte("key1"), []byte("val1") k2, v2 := []byte("key2"), []byte("val2") diff --git a/store/prefixstore_test.go b/store/prefixstore_test.go index f57ab20e40..1961bb4bb0 100644 --- a/store/prefixstore_test.go +++ b/store/prefixstore_test.go @@ -66,7 +66,7 @@ func testPrefixStore(t *testing.T, baseStore KVStore, prefix []byte) { func TestIAVLStorePrefix(t *testing.T) { db := dbm.NewMemDB() tree := iavl.NewVersionedTree(db, cacheSize) - iavlStore := newIAVLStore(tree, numHistory) + iavlStore := newIAVLStore(tree, numRecent, storeEvery) testPrefixStore(t, iavlStore, []byte("test")) } From 1632b7de1841a38d43a1ea422eaf20a364537cec Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Tue, 26 Jun 2018 16:26:24 -0700 Subject: [PATCH 75/77] testing pruning --- store/iavlstore.go | 7 ++++++- store/iavlstore_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/store/iavlstore.go b/store/iavlstore.go index 16fb8e4f04..8627879361 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -15,7 +15,7 @@ import ( const ( defaultIAVLCacheSize = 10000 - defaultIAVLNumRecent = 1000 + defaultIAVLNumRecent = 100 defaultIAVLStoreEvery = 10000 ) @@ -94,6 +94,11 @@ func (st *iavlStore) LastCommitID() CommitID { } } +// VersionExists returns whether or not a given version is stored +func (st *iavlStore) VersionExists(version int64) bool { + return st.tree.VersionExists(version) +} + // Implements Store. func (st *iavlStore) GetStoreType() StoreType { return sdk.StoreTypeIAVL diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index adae84f1ab..51ec31f071 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -259,6 +259,35 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) { require.Equal(t, len(expected), i) } +func nextVersion(iavl *iavlStore) { + key := cmn.RandBytes(12) + value := cmn.RandBytes(50) + iavl.Set(key, value) + iavl.Commit() +} +func TestIAVLPruning(t *testing.T) { + db := dbm.NewMemDB() + tree := iavl.NewVersionedTree(db, cacheSize) + iavlStore := newIAVLStore(tree, numRecent, storeEvery) + nextVersion(iavlStore) + var i, j int64 + for i = 1; i <= 100; i++ { + for j = 1; j <= i; j++ { + if (i-j) < numRecent || j%storeEvery == int64(0) { + assert.True(t, iavlStore.VersionExists(j), + "Missing version %d with latest version %d. Should save last %d and every %d", + j, i, numRecent, storeEvery) + } else { + assert.False(t, iavlStore.VersionExists(j), + "Unpruned version %d with latest version %d. Should prune all but last %d and every %d", + j, i, numRecent, storeEvery) + } + } + nextVersion(iavlStore) + } + +} + func TestIAVLStoreQuery(t *testing.T) { db := dbm.NewMemDB() tree := iavl.NewVersionedTree(db, cacheSize) From b3e4faec74558a302a0a9f073c512bc99d4a5447 Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Mon, 2 Jul 2018 15:17:45 -0700 Subject: [PATCH 76/77] addressing comments --- store/iavlstore.go | 16 ++++++-- store/iavlstore_test.go | 85 ++++++++++++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 21 deletions(-) diff --git a/store/iavlstore.go b/store/iavlstore.go index 8627879361..26a0c9ea17 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -43,9 +43,16 @@ type iavlStore struct { tree *iavl.VersionedTree // How many old versions we hold onto. - // A value of 0 means keep all history. + // A value of 0 means keep no recent states numRecent int64 + // Distance between state-sync waypoint states to be stored + // See https://github.com/tendermint/tendermint/issues/828 + // A value of 1 means store every state + // A value of 0 means store no waypoints (node cannot assist in state-sync) + // By default this value should be set the same across all nodes, + // so that nodes can know the waypoints their peers store + // TODO if set to non-default, signal to peers that the node is not suitable as a state sync source storeEvery int64 } @@ -70,9 +77,10 @@ func (st *iavlStore) Commit() CommitID { } // Release an old version of history, if not a sync waypoint - if st.numRecent < st.tree.Version64() { - toRelease := version - st.numRecent - if toRelease%st.storeEvery != 0 { + previous := version - 1 + if st.numRecent < previous { + toRelease := previous - st.numRecent + if st.storeEvery == 0 || toRelease%st.storeEvery != 0 { err := st.tree.DeleteVersion(toRelease) if err != nil { panic(err) diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index 51ec31f071..f6f236dd8e 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -1,6 +1,7 @@ package store import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -260,32 +261,82 @@ func TestIAVLReverseSubspaceIterator(t *testing.T) { } func nextVersion(iavl *iavlStore) { - key := cmn.RandBytes(12) - value := cmn.RandBytes(50) + key := []byte(fmt.Sprintf("Key for tree: %d", iavl.LastCommitID().Version)) + value := []byte(fmt.Sprintf("Value for tree: %d", iavl.LastCommitID().Version)) iavl.Set(key, value) iavl.Commit() } -func TestIAVLPruning(t *testing.T) { +func TestIAVLDefaultPruning(t *testing.T) { + //Expected stored / deleted version numbers for: + //numRecent = 5, storeEvery = 3 + var states = []struct { + stored []int64 + deleted []int64 + }{ + {[]int64{}, []int64{}}, + {[]int64{1}, []int64{}}, + {[]int64{1, 2}, []int64{}}, + {[]int64{1, 2, 3}, []int64{}}, + {[]int64{1, 2, 3, 4}, []int64{}}, + {[]int64{1, 2, 3, 4, 5}, []int64{}}, + {[]int64{1, 2, 3, 4, 5, 6}, []int64{}}, + {[]int64{2, 3, 4, 5, 6, 7}, []int64{1}}, + {[]int64{3, 4, 5, 6, 7, 8}, []int64{1, 2}}, + {[]int64{3, 4, 5, 6, 7, 8, 9}, []int64{1, 2}}, + {[]int64{3, 5, 6, 7, 8, 9, 10}, []int64{1, 2, 4}}, + {[]int64{3, 6, 7, 8, 9, 10, 11}, []int64{1, 2, 4, 5}}, + {[]int64{3, 6, 7, 8, 9, 10, 11, 12}, []int64{1, 2, 4, 5}}, + {[]int64{3, 6, 8, 9, 10, 11, 12, 13}, []int64{1, 2, 4, 5, 7}}, + {[]int64{3, 6, 9, 10, 11, 12, 13, 14}, []int64{1, 2, 4, 5, 7, 8}}, + {[]int64{3, 6, 9, 10, 11, 12, 13, 14, 15}, []int64{1, 2, 4, 5, 7, 8}}, + } db := dbm.NewMemDB() tree := iavl.NewVersionedTree(db, cacheSize) iavlStore := newIAVLStore(tree, numRecent, storeEvery) - nextVersion(iavlStore) - var i, j int64 - for i = 1; i <= 100; i++ { - for j = 1; j <= i; j++ { - if (i-j) < numRecent || j%storeEvery == int64(0) { - assert.True(t, iavlStore.VersionExists(j), - "Missing version %d with latest version %d. Should save last %d and every %d", - j, i, numRecent, storeEvery) - } else { - assert.False(t, iavlStore.VersionExists(j), - "Unpruned version %d with latest version %d. Should prune all but last %d and every %d", - j, i, numRecent, storeEvery) - } + for step, state := range states { + for _, ver := range state.stored { + require.True(t, iavlStore.VersionExists(ver), + "Missing version %d with latest version %d. Should save last %d and every %d", + ver, step, numRecent, storeEvery) + } + for _, ver := range state.deleted { + require.False(t, iavlStore.VersionExists(ver), + "Unpruned version %d with latest version %d. Should prune all but last %d and every %d", + ver, step, numRecent, storeEvery) } nextVersion(iavlStore) } - +} +func TestIAVLNoPrune(t *testing.T) { + db := dbm.NewMemDB() + tree := iavl.NewVersionedTree(db, cacheSize) + iavlStore := newIAVLStore(tree, numRecent, int64(1)) + nextVersion(iavlStore) + for i := 1; i < 100; i++ { + for j := 1; j <= i; j++ { + require.True(t, iavlStore.VersionExists(int64(j)), + "Missing version %d with latest version %d. Should be storing all versions", + j, i) + } + nextVersion(iavlStore) + } +} +func TestIAVLPruneEverything(t *testing.T) { + db := dbm.NewMemDB() + tree := iavl.NewVersionedTree(db, cacheSize) + iavlStore := newIAVLStore(tree, int64(0), int64(0)) + nextVersion(iavlStore) + for i := 1; i < 100; i++ { + for j := 1; j < i; j++ { + require.False(t, iavlStore.VersionExists(int64(j)), + "Unpruned version %d with latest version %d. Should prune all old versions", + j, i) + } + require.True(t, iavlStore.VersionExists(int64(i)), + "Missing current version on step %d, should not prune current state tree", + i) + nextVersion(iavlStore) + } } func TestIAVLStoreQuery(t *testing.T) { From 61ce80135abd09525f59771a25b24fa76c0e1668 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 2 Jul 2018 17:29:47 -0400 Subject: [PATCH 77/77] Merge pull request #1509: Fix basecoin Example --- examples/basecoin/app/app.go | 151 +++++++++++------------- examples/basecoin/app/app_test.go | 93 +++++++-------- examples/basecoin/cmd/basecli/main.go | 14 +-- examples/basecoin/cmd/basecoind/main.go | 9 +- examples/basecoin/types/account.go | 51 ++++---- server/init.go | 2 +- 6 files changed, 153 insertions(+), 167 deletions(-) diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index 089d1ca23c..fca5e86393 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -3,183 +3,174 @@ package app import ( "encoding/json" - abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" - cmn "github.com/tendermint/tmlibs/common" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" - bam "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/examples/basecoin/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/ibc" - "github.com/cosmos/cosmos-sdk/x/slashing" - "github.com/cosmos/cosmos-sdk/x/stake" - - "github.com/cosmos/cosmos-sdk/examples/basecoin/types" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + cmn "github.com/tendermint/tmlibs/common" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" ) const ( appName = "BasecoinApp" ) -// Extended ABCI application +// BasecoinApp implements an extended ABCI application. It contains a BaseApp, +// a codec for serialization, KVStore keys for multistore state management, and +// various mappers and keepers to manage getting, setting, and serializing the +// integral app types. type BasecoinApp struct { *bam.BaseApp cdc *wire.Codec - // keys to access the substores - keyMain *sdk.KVStoreKey - keyAccount *sdk.KVStoreKey - keyIBC *sdk.KVStoreKey - keyStake *sdk.KVStoreKey - keySlashing *sdk.KVStoreKey + // keys to access the multistore + keyMain *sdk.KVStoreKey + keyAccount *sdk.KVStoreKey + keyIBC *sdk.KVStoreKey - // Manage getting and setting accounts + // manage getting and setting accounts accountMapper auth.AccountMapper feeCollectionKeeper auth.FeeCollectionKeeper coinKeeper bank.Keeper ibcMapper ibc.Mapper - stakeKeeper stake.Keeper - slashingKeeper slashing.Keeper } +// NewBasecoinApp returns a reference to a new BasecoinApp given a logger and +// database. Internally, a codec is created along with all the necessary keys. +// In addition, all necessary mappers and keepers are created, routes +// registered, and finally the stores being mounted along with any necessary +// chain initialization. func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { + // create and register app-level codec for TXs and accounts + cdc := MakeCodec() - // Create app-level codec for txs and accounts. - var cdc = MakeCodec() - - // Create your application object. + // create your application type var app = &BasecoinApp{ - BaseApp: bam.NewBaseApp(appName, cdc, logger, db), - cdc: cdc, - keyMain: sdk.NewKVStoreKey("main"), - keyAccount: sdk.NewKVStoreKey("acc"), - keyIBC: sdk.NewKVStoreKey("ibc"), - keyStake: sdk.NewKVStoreKey("stake"), - keySlashing: sdk.NewKVStoreKey("slashing"), + cdc: cdc, + BaseApp: bam.NewBaseApp(appName, cdc, logger, db), + keyMain: sdk.NewKVStoreKey("main"), + keyAccount: sdk.NewKVStoreKey("acc"), + keyIBC: sdk.NewKVStoreKey("ibc"), } - // Define the accountMapper. + // define and attach the mappers and keepers app.accountMapper = auth.NewAccountMapper( cdc, app.keyAccount, // target store &types.AppAccount{}, // prototype ) - - // add accountMapper/handlers app.coinKeeper = bank.NewKeeper(app.accountMapper) app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) - app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace)) - app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace)) // register message routes app.Router(). AddRoute("bank", bank.NewHandler(app.coinKeeper)). - AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)). - AddRoute("stake", stake.NewHandler(app.stakeKeeper)) + AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)) - // Initialize BaseApp. + // perform initialization logic app.SetInitChainer(app.initChainer) app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) - app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing) + + // mount the multistore and load the latest state + app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) } + return app } -// Custom tx codec +// MakeCodec creates a new wire codec and registers all the necessary types +// with the codec. func MakeCodec() *wire.Codec { - var cdc = wire.NewCodec() - wire.RegisterCrypto(cdc) // Register crypto. - sdk.RegisterWire(cdc) // Register Msgs + cdc := wire.NewCodec() + + wire.RegisterCrypto(cdc) + sdk.RegisterWire(cdc) bank.RegisterWire(cdc) - stake.RegisterWire(cdc) - slashing.RegisterWire(cdc) ibc.RegisterWire(cdc) - // register custom AppAccount + // register custom types cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterConcrete(&types.AppAccount{}, "basecoin/Account", nil) + return cdc } -// application updates every end block -func (app *BasecoinApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { - tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper) - - return abci.ResponseBeginBlock{ - Tags: tags.ToKVPairs(), - } +// BeginBlocker reflects logic to run before any TXs application are processed +// by the application. +func (app *BasecoinApp) BeginBlocker(_ sdk.Context, _ abci.RequestBeginBlock) abci.ResponseBeginBlock { + return abci.ResponseBeginBlock{} } -// application updates every end block -// nolint: unparam -func (app *BasecoinApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) - - return abci.ResponseEndBlock{ - ValidatorUpdates: validatorUpdates, - } +// EndBlocker reflects logic to run after all TXs are processed by the +// application. +func (app *BasecoinApp) EndBlocker(_ sdk.Context, _ abci.RequestEndBlock) abci.ResponseEndBlock { + return abci.ResponseEndBlock{} } -// Custom logic for basecoin initialization +// initChainer implements the custom application logic that the BaseApp will +// invoke upon initialization. In this case, it will take the application's +// state provided by 'req' and attempt to deserialize said state. The state +// should contain all the genesis accounts. These accounts will be added to the +// application's account mapper. func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { stateJSON := req.AppStateBytes genesisState := new(types.GenesisState) err := app.cdc.UnmarshalJSON(stateJSON, genesisState) if err != nil { - panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 - // return sdk.ErrGenesisParse("").TraceCause(err, "") + // TODO: https://github.com/cosmos/cosmos-sdk/issues/468 + panic(err) } for _, gacc := range genesisState.Accounts { acc, err := gacc.ToAppAccount() if err != nil { - panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 - // return sdk.ErrGenesisParse("").TraceCause(err, "") + // TODO: https://github.com/cosmos/cosmos-sdk/issues/468 + panic(err) } + acc.AccountNumber = app.accountMapper.GetNextAccountNumber(ctx) app.accountMapper.SetAccount(ctx, acc) } - // load the initial stake information - stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData) - return abci.ResponseInitChain{} } -// Custom logic for state export +// ExportAppStateAndValidators implements custom application logic that exposes +// various parts of the application's state and set of validators. An error is +// returned if any step getting the state or set of validators fails. func (app *BasecoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) { ctx := app.NewContext(true, abci.Header{}) - - // iterate to get the accounts accounts := []*types.GenesisAccount{} - appendAccount := func(acc auth.Account) (stop bool) { + + appendAccountsFn := func(acc auth.Account) bool { account := &types.GenesisAccount{ Address: acc.GetAddress(), Coins: acc.GetCoins(), } + accounts = append(accounts, account) return false } - app.accountMapper.IterateAccounts(ctx, appendAccount) - genState := types.GenesisState{ - Accounts: accounts, - StakeData: stake.WriteGenesis(ctx, app.stakeKeeper), - } + app.accountMapper.IterateAccounts(ctx, appendAccountsFn) + + genState := types.GenesisState{Accounts: accounts} appState, err = wire.MarshalJSONIndent(app.cdc, genState) if err != nil { return nil, nil, err } - validators = stake.WriteValidators(ctx, app.stakeKeeper) + return appState, validators, err } diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 499c0e4082..2605dad66a 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -1,88 +1,81 @@ package app import ( - "fmt" "os" "testing" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/examples/basecoin/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/stake" - gen "github.com/cosmos/cosmos-sdk/x/stake/types" - + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" ) -func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error { - genaccs := make([]*types.GenesisAccount, len(accs)) - for i, acc := range accs { - genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, "foobart"}) +func setGenesis(baseApp *BasecoinApp, accounts ...*types.AppAccount) (types.GenesisState, error) { + genAccts := make([]*types.GenesisAccount, len(accounts)) + for i, appAct := range accounts { + genAccts[i] = types.NewGenesisAccount(appAct) } - genesisState := types.GenesisState{ - Accounts: genaccs, - StakeData: stake.DefaultGenesisState(), - } - - stateBytes, err := wire.MarshalJSONIndent(bapp.cdc, genesisState) + genesisState := types.GenesisState{Accounts: genAccts} + stateBytes, err := wire.MarshalJSONIndent(baseApp.cdc, genesisState) if err != nil { - return err + return types.GenesisState{}, err } - // Initialize the chain - vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) - bapp.Commit() + // initialize and commit the chain + baseApp.InitChain(abci.RequestInitChain{ + Validators: []abci.Validator{}, AppStateBytes: stateBytes, + }) + baseApp.Commit() - return nil + return genesisState, nil } -//_______________________________________________________________________ - func TestGenesis(t *testing.T) { logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") db := dbm.NewMemDB() - bapp := NewBasecoinApp(logger, db) + baseApp := NewBasecoinApp(logger, db) - // Construct some genesis bytes to reflect basecoin/types/AppAccount - pk := crypto.GenPrivKeyEd25519().PubKey() - addr := pk.Address() + // construct a pubkey and an address for the test account + pubkey := crypto.GenPrivKeyEd25519().PubKey() + addr := pubkey.Address() + + // construct some test coins coins, err := sdk.ParseCoins("77foocoin,99barcoin") require.Nil(t, err) - baseAcc := auth.BaseAccount{ - Address: addr, - Coins: coins, - } - acc := &types.AppAccount{baseAcc, "foobart"} - err = setGenesis(bapp, baseAcc) + // create an auth.BaseAccount for the given test account and set it's coins + baseAcct := auth.NewBaseAccountWithAddress(addr) + err = baseAcct.SetCoins(coins) require.Nil(t, err) - // A checkTx context - ctx := bapp.BaseApp.NewContext(true, abci.Header{}) - res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address) - require.Equal(t, acc, res1) + // create a new test AppAccount with the given auth.BaseAccount + appAcct := types.NewAppAccount("foobar", baseAcct) + genState, err := setGenesis(baseApp, appAcct) + require.Nil(t, err) + + // create a context for the BaseApp + ctx := baseApp.BaseApp.NewContext(true, abci.Header{}) + res := baseApp.accountMapper.GetAccount(ctx, baseAcct.Address) + require.Equal(t, appAcct, res) // reload app and ensure the account is still there - bapp = NewBasecoinApp(logger, db) - // Initialize stake data with default genesis state - stakedata := gen.DefaultGenesisState() - genState, err := bapp.cdc.MarshalJSON(stakedata) - if err != nil { - panic(err) - } + baseApp = NewBasecoinApp(logger, db) - // InitChain with default stake data. Initializes deliverState and checkState context - bapp.InitChain(abci.RequestInitChain{AppStateBytes: []byte(fmt.Sprintf("{\"stake\": %s}", string(genState)))}) + stateBytes, err := wire.MarshalJSONIndent(baseApp.cdc, genState) + require.Nil(t, err) - ctx = bapp.BaseApp.NewContext(true, abci.Header{}) - res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address) - require.Equal(t, acc, res1) + // initialize the chain with the expected genesis state + baseApp.InitChain(abci.RequestInitChain{ + Validators: []abci.Validator{}, AppStateBytes: stateBytes, + }) + + ctx = baseApp.BaseApp.NewContext(true, abci.Header{}) + res = baseApp.accountMapper.GetAccount(ctx, baseAcct.Address) + require.Equal(t, appAcct, res) } diff --git a/examples/basecoin/cmd/basecli/main.go b/examples/basecoin/cmd/basecli/main.go index 1191aab6ab..fef9727a47 100644 --- a/examples/basecoin/cmd/basecli/main.go +++ b/examples/basecoin/cmd/basecli/main.go @@ -3,24 +3,20 @@ package main import ( "os" - "github.com/spf13/cobra" - - "github.com/tendermint/tmlibs/cli" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/client/tx" - + "github.com/cosmos/cosmos-sdk/examples/basecoin/app" + "github.com/cosmos/cosmos-sdk/examples/basecoin/types" "github.com/cosmos/cosmos-sdk/version" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli" - - "github.com/cosmos/cosmos-sdk/examples/basecoin/app" - "github.com/cosmos/cosmos-sdk/examples/basecoin/types" + "github.com/spf13/cobra" + "github.com/tendermint/tmlibs/cli" ) // rootCmd is the entry point for this binary @@ -82,7 +78,7 @@ func main() { executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.basecli")) err := executor.Execute() if err != nil { - // handle with #870 + // Note: Handle with #870 panic(err) } } diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index f3f3de519a..2cb37cfe12 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -4,16 +4,14 @@ import ( "encoding/json" "os" + "github.com/cosmos/cosmos-sdk/examples/basecoin/app" + "github.com/cosmos/cosmos-sdk/server" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" - - "github.com/cosmos/cosmos-sdk/examples/basecoin/app" - "github.com/cosmos/cosmos-sdk/server" ) func main() { @@ -33,9 +31,10 @@ func main() { // prepare and add flags rootDir := os.ExpandEnv("$HOME/.basecoind") executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) + err := executor.Execute() if err != nil { - // handle with #870 + // Note: Handle with #870 panic(err) } } diff --git a/examples/basecoin/types/account.go b/examples/basecoin/types/account.go index 43a8e2e389..8047ed68da 100644 --- a/examples/basecoin/types/account.go +++ b/examples/basecoin/types/account.go @@ -4,18 +4,17 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/stake" ) var _ auth.Account = (*AppAccount)(nil) -// Custom extensions for this application. This is just an example of -// extending auth.BaseAccount with custom fields. -// -// This is compatible with the stock auth.AccountStore, since -// auth.AccountStore uses the flexible go-amino library. +// AppAccount is a custom extension for this application. It is an example of +// extending auth.BaseAccount with custom fields. It is compatible with the +// stock auth.AccountStore, since auth.AccountStore uses the flexible go-amino +// library. type AppAccount struct { auth.BaseAccount + Name string `json:"name"` } @@ -23,36 +22,45 @@ type AppAccount struct { func (acc AppAccount) GetName() string { return acc.Name } func (acc *AppAccount) SetName(name string) { acc.Name = name } -// Get the AccountDecoder function for the custom AppAccount +// NewAppAccount returns a reference to a new AppAccount given a name and an +// auth.BaseAccount. +func NewAppAccount(name string, baseAcct auth.BaseAccount) *AppAccount { + return &AppAccount{BaseAccount: baseAcct, Name: name} +} + +// GetAccountDecoder returns the AccountDecoder function for the custom +// AppAccount. func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder { - return func(accBytes []byte) (res auth.Account, err error) { + return func(accBytes []byte) (auth.Account, error) { if len(accBytes) == 0 { return nil, sdk.ErrTxDecode("accBytes are empty") } + acct := new(AppAccount) - err = cdc.UnmarshalBinaryBare(accBytes, &acct) + err := cdc.UnmarshalBinaryBare(accBytes, &acct) if err != nil { panic(err) } + return acct, err } } -//___________________________________________________________________________________ - -// State to Unmarshal +// GenesisState reflects the genesis state of the application. type GenesisState struct { - Accounts []*GenesisAccount `json:"accounts"` - StakeData stake.GenesisState `json:"stake"` + Accounts []*GenesisAccount `json:"accounts"` } -// GenesisAccount doesn't need pubkey or sequence +// GenesisAccount reflects a genesis account the application expects in it's +// genesis state. type GenesisAccount struct { Name string `json:"name"` Address sdk.Address `json:"address"` Coins sdk.Coins `json:"coins"` } +// NewGenesisAccount returns a reference to a new GenesisAccount given an +// AppAccount. func NewGenesisAccount(aa *AppAccount) *GenesisAccount { return &GenesisAccount{ Name: aa.Name, @@ -61,14 +69,13 @@ func NewGenesisAccount(aa *AppAccount) *GenesisAccount { } } -// convert GenesisAccount to AppAccount +// ToAppAccount converts a GenesisAccount to an AppAccount. func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) { - baseAcc := auth.BaseAccount{ - Address: ga.Address, - Coins: ga.Coins.Sort(), - } return &AppAccount{ - BaseAccount: baseAcc, - Name: ga.Name, + Name: ga.Name, + BaseAccount: auth.BaseAccount{ + Address: ga.Address, + Coins: ga.Coins.Sort(), + }, }, nil } diff --git a/server/init.go b/server/init.go index ed1727e35e..8beeb354e6 100644 --- a/server/init.go +++ b/server/init.go @@ -444,7 +444,7 @@ func SimpleAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState j "coins": [ { "denom": "mycoin", - "amount": 9007199254740992 + "amount": "9007199254740992" } ] }]