Merge PR #3626: Release v0.31.2
This commit is contained in:
commit
05de8135ac
33
CHANGELOG.md
33
CHANGELOG.md
|
@ -1,5 +1,38 @@
|
|||
# Changelog
|
||||
|
||||
## 0.31.2
|
||||
|
||||
BREAKING CHANGES
|
||||
|
||||
* SDK
|
||||
* [\#3592](https://github.com/cosmos/cosmos-sdk/issues/3592) Drop deprecated keybase implementation's
|
||||
New constructor in favor of a new
|
||||
crypto/keys.New(string, string) implementation that
|
||||
returns a lazy keybase instance. Remove client.MockKeyBase,
|
||||
superseded by crypto/keys.NewInMemory()
|
||||
|
||||
IMPROVEMENTS
|
||||
|
||||
* SDK
|
||||
* [\#3604](https://github.com/cosmos/cosmos-sdk/pulls/3604) Improve SDK funds related error messages and allow for unicode in
|
||||
JSON ABCI log.
|
||||
|
||||
* Tendermint
|
||||
* [\#3563](https://github.com/cosmos/cosmos-sdk/3563) Update to Tendermint version `0.30.0-rc0`
|
||||
|
||||
|
||||
BUG FIXES
|
||||
|
||||
* Gaia
|
||||
* [\#3585] Fix setting the tx hash in `NewResponseFormatBroadcastTxCommit`.
|
||||
* [\#3585] Return an empty `TxResponse` when Tendermint returns an empty
|
||||
`ResultBroadcastTx`.
|
||||
|
||||
* SDK
|
||||
* [\#3582](https://github.com/cosmos/cosmos-sdk/pull/3582) Running `make test_unit` was failing due to a missing tag
|
||||
* [\#3617](https://github.com/cosmos/cosmos-sdk/pull/3582) Fix fee comparison when the required fees does not contain any denom
|
||||
present in the tx fees.
|
||||
|
||||
## 0.31.0
|
||||
|
||||
BREAKING CHANGES
|
||||
|
|
2
Makefile
2
Makefile
|
@ -151,7 +151,7 @@ test_ledger:
|
|||
@go test -v `go list github.com/cosmos/cosmos-sdk/crypto` -tags='cgo ledger'
|
||||
|
||||
test_unit:
|
||||
@VERSION=$(VERSION) go test $(PACKAGES_NOSIMULATION) -tags='test_ledger_mock'
|
||||
@VERSION=$(VERSION) go test $(PACKAGES_NOSIMULATION) -tags='ledger test_ledger_mock'
|
||||
|
||||
test_race:
|
||||
@VERSION=$(VERSION) go test -race $(PACKAGES_NOSIMULATION)
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
)
|
||||
|
||||
// MockKeyBase generates an in-memory keybase that will be discarded
|
||||
// useful for --dry-run to generate a seed phrase without
|
||||
// storing the key
|
||||
func MockKeyBase() keys.Keybase {
|
||||
return keys.New(dbm.NewMemDB())
|
||||
}
|
|
@ -77,7 +77,7 @@ the flag --nosort is set.
|
|||
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")
|
||||
cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ func runAddCmd(_ *cobra.Command, args []string) error {
|
|||
if viper.GetBool(flagDryRun) {
|
||||
// we throw this away, so don't enforce args,
|
||||
// we want to get a new random seed phrase quickly
|
||||
kb = client.MockKeyBase()
|
||||
kb = keys.NewInMemory()
|
||||
encryptPassword = app.DefaultKeyPass
|
||||
} else {
|
||||
kb, err = NewKeyBaseFromHomeFlag()
|
||||
|
@ -309,7 +309,7 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error {
|
|||
|
||||
// function to just create a new seed to display in the UI before actually persisting it in the keybase
|
||||
func generateMnemonic(algo keys.SigningAlgo) string {
|
||||
kb := client.MockKeyBase()
|
||||
kb := keys.NewInMemory()
|
||||
pass := app.DefaultKeyPass
|
||||
name := "inmemorykey"
|
||||
_, seed, _ := kb.CreateMnemonic(name, keys.English, pass, algo)
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
//+build ledger,test_ledger_mock
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_runAddCmdLedger(t *testing.T) {
|
||||
cmd := addKeyCommand()
|
||||
assert.NotNil(t, cmd)
|
||||
|
||||
// Prepare a keybase
|
||||
kbHome, kbCleanUp := tests.NewTestCaseDir(t)
|
||||
assert.NotNil(t, kbHome)
|
||||
defer kbCleanUp()
|
||||
viper.Set(cli.HomeFlag, kbHome)
|
||||
viper.Set(client.FlagUseLedger, true)
|
||||
|
||||
/// Test Text
|
||||
viper.Set(cli.OutputFlag, OutputFormatText)
|
||||
// Now enter password
|
||||
cleanUp1 := client.OverrideStdin(bufio.NewReader(strings.NewReader("test1234\ntest1234\n")))
|
||||
defer cleanUp1()
|
||||
err := runAddCmd(cmd, []string{"keyname1"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Now check that it has been stored properly
|
||||
kb, err := NewKeyBaseFromHomeFlag()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, kb)
|
||||
key1, err := kb.Get("keyname1")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, key1)
|
||||
|
||||
assert.Equal(t, "keyname1", key1.GetName())
|
||||
assert.Equal(t, keys.TypeLedger, key1.GetType())
|
||||
assert.Equal(t,
|
||||
"cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0",
|
||||
sdk.MustBech32ifyAccPub(key1.GetPubKey()))
|
||||
}
|
|
@ -23,10 +23,6 @@ func Test_runAddCmdBasic(t *testing.T) {
|
|||
cmd := addKeyCommand()
|
||||
assert.NotNil(t, cmd)
|
||||
|
||||
// Missing input (enter password)
|
||||
err := runAddCmd(cmd, []string{"keyname"})
|
||||
assert.EqualError(t, err, "EOF")
|
||||
|
||||
// Prepare a keybase
|
||||
kbHome, kbCleanUp := tests.NewTestCaseDir(t)
|
||||
assert.NotNil(t, kbHome)
|
||||
|
@ -38,7 +34,7 @@ func Test_runAddCmdBasic(t *testing.T) {
|
|||
// Now enter password
|
||||
cleanUp1 := client.OverrideStdin(bufio.NewReader(strings.NewReader("test1234\ntest1234\n")))
|
||||
defer cleanUp1()
|
||||
err = runAddCmd(cmd, []string{"keyname1"})
|
||||
err := runAddCmd(cmd, []string{"keyname1"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
/// Test Text - Replace? >> FAIL
|
||||
|
|
|
@ -14,11 +14,13 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// KeyDBName is the directory under root where we store the keys
|
||||
// available output formats.
|
||||
const (
|
||||
KeyDBName = "keys"
|
||||
OutputFormatText = "text"
|
||||
OutputFormatJSON = "json"
|
||||
|
||||
// defaultKeyDBName is the client's subdirectory where keys are stored.
|
||||
defaultKeyDBName = "keys"
|
||||
)
|
||||
|
||||
type bechKeyOutFn func(keyInfo keys.Info) (KeyOutput, error)
|
||||
|
@ -87,7 +89,7 @@ func NewKeyBaseFromDir(rootDir string) (keys.Keybase, error) {
|
|||
func NewInMemoryKeyBase() keys.Keybase { return keys.NewInMemory() }
|
||||
|
||||
func getLazyKeyBaseFromDir(rootDir string) (keys.Keybase, error) {
|
||||
return keys.NewLazyKeybase(KeyDBName, filepath.Join(rootDir, "keys")), nil
|
||||
return keys.New(defaultKeyDBName, filepath.Join(rootDir, "keys")), nil
|
||||
}
|
||||
|
||||
// create a list of KeyOutput in bech32 format
|
||||
|
|
|
@ -682,7 +682,7 @@ func doTransferWithGas(
|
|||
) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
|
||||
|
||||
// create receive address
|
||||
kb := client.MockKeyBase()
|
||||
kb := crkeys.NewInMemory()
|
||||
|
||||
receiveInfo, _, err := kb.CreateMnemonic(
|
||||
"receive_address", crkeys.English, gapp.DefaultKeyPass, crkeys.SigningAlgo("secp256k1"),
|
||||
|
@ -724,7 +724,7 @@ func doTransferWithGasAccAuto(
|
|||
) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
|
||||
|
||||
// create receive address
|
||||
kb := client.MockKeyBase()
|
||||
kb := crkeys.NewInMemory()
|
||||
|
||||
receiveInfo, _, err := kb.CreateMnemonic(
|
||||
"receive_address", crkeys.English, gapp.DefaultKeyPass, crkeys.SigningAlgo("secp256k1"),
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package keys
|
||||
|
||||
import (
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||
|
||||
ccrypto "github.com/cosmos/cosmos-sdk/crypto"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
@ -12,8 +11,7 @@ var cdc = amino.NewCodec()
|
|||
func init() {
|
||||
cryptoAmino.RegisterAmino(cdc)
|
||||
cdc.RegisterInterface((*Info)(nil), nil)
|
||||
cdc.RegisterConcrete(ccrypto.PrivKeyLedgerSecp256k1{},
|
||||
"tendermint/PrivKeyLedgerSecp256k1", nil)
|
||||
cdc.RegisterConcrete(hd.BIP44Params{}, "crypto/keys/hd/BIP44Params", nil)
|
||||
cdc.RegisterConcrete(localInfo{}, "crypto/keys/localInfo", nil)
|
||||
cdc.RegisterConcrete(ledgerInfo{}, "crypto/keys/ledgerInfo", nil)
|
||||
cdc.RegisterConcrete(offlineInfo{}, "crypto/keys/offlineInfo", nil)
|
||||
|
|
|
@ -33,25 +33,25 @@ const (
|
|||
|
||||
// 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
|
||||
// m / purpose' / coinType' / account' / change / addressIndex
|
||||
// call String() on a BIP44Params instance.
|
||||
type BIP44Params struct {
|
||||
purpose uint32
|
||||
coinType uint32
|
||||
account uint32
|
||||
change bool
|
||||
addressIdx uint32
|
||||
Purpose uint32 `json:"purpose"`
|
||||
CoinType uint32 `json:"coinType"`
|
||||
Account uint32 `json:"account"`
|
||||
Change bool `json:"change"`
|
||||
AddressIndex uint32 `json:"addressIndex"`
|
||||
}
|
||||
|
||||
// NewParams creates a BIP 44 parameter object from the params:
|
||||
// m / purpose' / coin_type' / account' / change / address_index
|
||||
// m / purpose' / coinType' / account' / change / addressIndex
|
||||
func NewParams(purpose, coinType, account uint32, change bool, addressIdx uint32) *BIP44Params {
|
||||
return &BIP44Params{
|
||||
purpose: purpose,
|
||||
coinType: coinType,
|
||||
account: account,
|
||||
change: change,
|
||||
addressIdx: addressIdx,
|
||||
Purpose: purpose,
|
||||
CoinType: coinType,
|
||||
Account: account,
|
||||
Change: change,
|
||||
AddressIndex: addressIdx,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,11 +105,11 @@ func NewParamsFromPath(path string) (*BIP44Params, error) {
|
|||
}
|
||||
|
||||
return &BIP44Params{
|
||||
purpose: purpose,
|
||||
coinType: coinType,
|
||||
account: account,
|
||||
change: change > 0,
|
||||
addressIdx: addressIdx,
|
||||
Purpose: purpose,
|
||||
CoinType: coinType,
|
||||
Account: account,
|
||||
Change: change > 0,
|
||||
AddressIndex: addressIdx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -139,32 +139,32 @@ func NewFundraiserParams(account uint32, addressIdx uint32) *BIP44Params {
|
|||
// DerivationPath returns the BIP44 fields as an array.
|
||||
func (p BIP44Params) DerivationPath() []uint32 {
|
||||
change := uint32(0)
|
||||
if p.change {
|
||||
if p.Change {
|
||||
change = 1
|
||||
}
|
||||
return []uint32{
|
||||
p.purpose,
|
||||
p.coinType,
|
||||
p.account,
|
||||
p.Purpose,
|
||||
p.CoinType,
|
||||
p.Account,
|
||||
change,
|
||||
p.addressIdx,
|
||||
p.AddressIndex,
|
||||
}
|
||||
}
|
||||
|
||||
func (p BIP44Params) String() string {
|
||||
var changeStr string
|
||||
if p.change {
|
||||
if p.Change {
|
||||
changeStr = "1"
|
||||
} else {
|
||||
changeStr = "0"
|
||||
}
|
||||
// m / purpose' / coin_type' / account' / change / address_index
|
||||
// m / Purpose' / coin_type' / Account' / Change / address_index
|
||||
return fmt.Sprintf("%d'/%d'/%d'/%s/%d",
|
||||
p.purpose,
|
||||
p.coinType,
|
||||
p.account,
|
||||
p.Purpose,
|
||||
p.CoinType,
|
||||
p.Account,
|
||||
changeStr,
|
||||
p.addressIdx)
|
||||
p.AddressIndex)
|
||||
}
|
||||
|
||||
// ComputeMastersFromSeed returns the master public key, master secret, and chain code in hex.
|
||||
|
|
|
@ -77,14 +77,15 @@ 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 {
|
||||
// newDbKeybase creates a new keybase instance using the passed DB for reading and writing keys.
|
||||
func newDbKeybase(db dbm.DB) Keybase {
|
||||
return dbKeybase{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInMemory creates a new keybase on top of in-memory storage instance.
|
||||
// NewInMemory creates a transient keybase on top of in-memory storage
|
||||
// instance useful for testing purposes and on-the-fly key generation.
|
||||
func NewInMemory() Keybase { return dbKeybase{dbm.NewMemDB()} }
|
||||
|
||||
// CreateMnemonic generates a new key and persists it to storage, encrypted
|
||||
|
@ -284,9 +285,9 @@ func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcr
|
|||
return nil, err
|
||||
}
|
||||
case ledgerInfo:
|
||||
return nil, errors.New("Only works on local private keys")
|
||||
return nil, errors.New("only works on local private keys")
|
||||
case offlineInfo:
|
||||
return nil, errors.New("Only works on local private keys")
|
||||
return nil, errors.New("only works on local private keys")
|
||||
}
|
||||
return priv, nil
|
||||
}
|
||||
|
@ -428,7 +429,8 @@ func (kb dbKeybase) writeOfflineKey(name string, pub tmcrypto.PubKey) Info {
|
|||
func (kb dbKeybase) writeInfo(name string, info Info) {
|
||||
// write the info by key
|
||||
key := infoKey(name)
|
||||
kb.db.SetSync(key, writeInfo(info))
|
||||
serializedInfo := writeInfo(info)
|
||||
kb.db.SetSync(key, serializedInfo)
|
||||
// store a pointer to the infokey by address for fast lookup
|
||||
kb.db.SetSync(addrKey(info.GetAddress()), key)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package keys
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -10,42 +9,24 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
)
|
||||
|
||||
func init() {
|
||||
mintkey.BcryptSecurityParameter = 1
|
||||
}
|
||||
|
||||
func TestKeybaseOpenClose(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "TestKeybaseOpenClose")
|
||||
assert.Nil(t, err)
|
||||
|
||||
kb := New(dbm.NewDB("TestKeybaseOpenClose", dbm.LevelDBBackend, dir))
|
||||
kb.CloseDB()
|
||||
|
||||
// The DB has been closed. At the moment, the expected behaviour is to panic
|
||||
assert.Panics(t, func() {
|
||||
_, _ = kb.CreateAccount(
|
||||
"some_account",
|
||||
"key pair crucial catch public canyon evil outer stage ten gym tornado",
|
||||
"", "", 0, 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLanguage(t *testing.T) {
|
||||
kb := New(dbm.NewMemDB())
|
||||
kb := NewInMemory()
|
||||
_, _, err := kb.CreateMnemonic("something", Japanese, "no_pass", Secp256k1)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "unsupported language: only english is supported", err.Error())
|
||||
}
|
||||
|
||||
func TestCreateAccountInvalidMnemonic(t *testing.T) {
|
||||
kb := New(dbm.NewMemDB())
|
||||
kb := NewInMemory()
|
||||
_, err := kb.CreateAccount(
|
||||
"some_account",
|
||||
"malarkey pair crucial catch public canyon evil outer stage ten gym tornado",
|
||||
|
@ -55,39 +36,53 @@ func TestCreateAccountInvalidMnemonic(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCreateLedgerUnsupportedAlgo(t *testing.T) {
|
||||
kb := New(dbm.NewMemDB())
|
||||
kb := NewInMemory()
|
||||
_, err := kb.CreateLedger("some_account", Ed25519, 0, 1)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "unsupported signing algo: only secp256k1 is supported", err.Error())
|
||||
}
|
||||
|
||||
func TestCreateLedger(t *testing.T) {
|
||||
kb := New(dbm.NewMemDB())
|
||||
kb := NewInMemory()
|
||||
|
||||
// test_cover and test_unit will result in different answers
|
||||
// test_cover does not compile some dependencies so ledger is disabled
|
||||
// test_unit may add a ledger mock
|
||||
// both cases are acceptable
|
||||
ledger, err := kb.CreateLedger("some_account", Secp256k1, 0, 1)
|
||||
ledger, err := kb.CreateLedger("some_account", Secp256k1, 3, 1)
|
||||
|
||||
if err != nil {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error())
|
||||
assert.Nil(t, ledger)
|
||||
} else {
|
||||
t.Skip("ledger nano S: support for ledger devices is not available in this executable")
|
||||
return
|
||||
}
|
||||
|
||||
// The mock is available, check that the address is correct
|
||||
pubKey := ledger.GetPubKey()
|
||||
addr, err := sdk.Bech32ifyAccPub(pubKey)
|
||||
pk, err := sdk.Bech32ifyAccPub(pubKey)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "cosmospub1addwnpepqfsdqjr68h7wjg5wacksmqaypasnra232fkgu5sxdlnlu8j22ztxvlqvd65", addr)
|
||||
}
|
||||
assert.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk)
|
||||
|
||||
// Check that restoring the key gets the same results
|
||||
restoredKey, err := kb.Get("some_account")
|
||||
assert.NotNil(t, restoredKey)
|
||||
assert.Equal(t, "some_account", restoredKey.GetName())
|
||||
assert.Equal(t, TypeLedger, restoredKey.GetType())
|
||||
pubKey = restoredKey.GetPubKey()
|
||||
pk, err = sdk.Bech32ifyAccPub(pubKey)
|
||||
assert.Equal(t, "cosmospub1addwnpepqdszcr95mrqqs8lw099aa9h8h906zmet22pmwe9vquzcgvnm93eqygufdlv", pk)
|
||||
|
||||
linfo := restoredKey.(ledgerInfo)
|
||||
assert.Equal(t, "44'/118'/3'/0/1", linfo.GetPath().String())
|
||||
|
||||
}
|
||||
|
||||
// TestKeyManagement makes sure we can manipulate these keys well
|
||||
func TestKeyManagement(t *testing.T) {
|
||||
// make the storage with reasonable defaults
|
||||
db := dbm.NewMemDB()
|
||||
cstore := New(db)
|
||||
cstore := NewInMemory()
|
||||
|
||||
algo := Secp256k1
|
||||
n1, n2, n3 := "personal", "business", "other"
|
||||
|
@ -118,7 +113,7 @@ func TestKeyManagement(t *testing.T) {
|
|||
require.NotNil(t, err)
|
||||
_, err = cstore.GetByAddress(accAddr(i2))
|
||||
require.NoError(t, err)
|
||||
addr, err := types.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t")
|
||||
addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t")
|
||||
require.NoError(t, err)
|
||||
_, err = cstore.GetByAddress(addr)
|
||||
require.NotNil(t, err)
|
||||
|
@ -165,13 +160,12 @@ func TestKeyManagement(t *testing.T) {
|
|||
// addr cache gets nuked - and test skip flag
|
||||
err = cstore.Delete(n2, "", true)
|
||||
require.NoError(t, err)
|
||||
require.False(t, db.Has(addrKey(i2.GetAddress())))
|
||||
}
|
||||
|
||||
// TestSignVerify does some detailed checks on how we sign and validate
|
||||
// signatures
|
||||
func TestSignVerify(t *testing.T) {
|
||||
cstore := New(dbm.NewMemDB())
|
||||
cstore := NewInMemory()
|
||||
algo := Secp256k1
|
||||
|
||||
n1, n2, n3 := "some dude", "a dudette", "dude-ish"
|
||||
|
@ -253,12 +247,8 @@ func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) {
|
|||
|
||||
// TestExportImport tests exporting and importing
|
||||
func TestExportImport(t *testing.T) {
|
||||
|
||||
// make the storage with reasonable defaults
|
||||
db := dbm.NewMemDB()
|
||||
cstore := New(
|
||||
db,
|
||||
)
|
||||
cstore := NewInMemory()
|
||||
|
||||
info, _, err := cstore.CreateMnemonic("john", English, "secretcpw", Secp256k1)
|
||||
require.NoError(t, err)
|
||||
|
@ -286,10 +276,7 @@ func TestExportImport(t *testing.T) {
|
|||
//
|
||||
func TestExportImportPubKey(t *testing.T) {
|
||||
// make the storage with reasonable defaults
|
||||
db := dbm.NewMemDB()
|
||||
cstore := New(
|
||||
db,
|
||||
)
|
||||
cstore := NewInMemory()
|
||||
|
||||
// CreateMnemonic a private-public key pair and ensure consistency
|
||||
notPasswd := "n9y25ah7"
|
||||
|
@ -327,11 +314,8 @@ func TestExportImportPubKey(t *testing.T) {
|
|||
|
||||
// TestAdvancedKeyManagement verifies update, import, export functionality
|
||||
func TestAdvancedKeyManagement(t *testing.T) {
|
||||
|
||||
// make the storage with reasonable defaults
|
||||
cstore := New(
|
||||
dbm.NewMemDB(),
|
||||
)
|
||||
cstore := NewInMemory()
|
||||
|
||||
algo := Secp256k1
|
||||
n1, n2 := "old-name", "new name"
|
||||
|
@ -379,9 +363,7 @@ func TestAdvancedKeyManagement(t *testing.T) {
|
|||
func TestSeedPhrase(t *testing.T) {
|
||||
|
||||
// make the storage with reasonable defaults
|
||||
cstore := New(
|
||||
dbm.NewMemDB(),
|
||||
)
|
||||
cstore := NewInMemory()
|
||||
|
||||
algo := Secp256k1
|
||||
n1, n2 := "lost-key", "found-again"
|
||||
|
@ -410,9 +392,7 @@ func TestSeedPhrase(t *testing.T) {
|
|||
|
||||
func ExampleNew() {
|
||||
// Select the encryption and storage for your cryptostore
|
||||
cstore := New(
|
||||
dbm.NewMemDB(),
|
||||
)
|
||||
cstore := NewInMemory()
|
||||
|
||||
sec := Secp256k1
|
||||
|
||||
|
@ -460,6 +440,6 @@ func ExampleNew() {
|
|||
// signed by Bob
|
||||
}
|
||||
|
||||
func accAddr(info Info) types.AccAddress {
|
||||
return (types.AccAddress)(info.GetPubKey().Address())
|
||||
func accAddr(info Info) sdk.AccAddress {
|
||||
return (sdk.AccAddress)(info.GetPubKey().Address())
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ type lazyKeybase struct {
|
|||
dir string
|
||||
}
|
||||
|
||||
func NewLazyKeybase(name, dir string) Keybase {
|
||||
// New creates a new instance of a lazy keybase.
|
||||
func New(name, dir string) Keybase {
|
||||
return lazyKeybase{name: name, dir: dir}
|
||||
}
|
||||
|
||||
|
@ -25,7 +26,7 @@ func (lkb lazyKeybase) List() ([]Info, error) {
|
|||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).List()
|
||||
return newDbKeybase(db).List()
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Get(name string) (Info, error) {
|
||||
|
@ -34,7 +35,7 @@ func (lkb lazyKeybase) Get(name string) (Info, error) {
|
|||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).Get(name)
|
||||
return newDbKeybase(db).Get(name)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) GetByAddress(address types.AccAddress) (Info, error) {
|
||||
|
@ -43,7 +44,7 @@ func (lkb lazyKeybase) GetByAddress(address types.AccAddress) (Info, error) {
|
|||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).GetByAddress(address)
|
||||
return newDbKeybase(db).GetByAddress(address)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Delete(name, passphrase string, skipPass bool) error {
|
||||
|
@ -52,7 +53,7 @@ func (lkb lazyKeybase) Delete(name, passphrase string, skipPass bool) error {
|
|||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).Delete(name, passphrase, skipPass)
|
||||
return newDbKeybase(db).Delete(name, passphrase, skipPass)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) {
|
||||
|
@ -61,7 +62,7 @@ func (lkb lazyKeybase) Sign(name, passphrase string, msg []byte) ([]byte, crypto
|
|||
return nil, nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).Sign(name, passphrase, msg)
|
||||
return newDbKeybase(db).Sign(name, passphrase, msg)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) {
|
||||
|
@ -70,7 +71,7 @@ func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd str
|
|||
return nil, "", err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).CreateMnemonic(name, language, passwd, algo)
|
||||
return newDbKeybase(db).CreateMnemonic(name, language, passwd, algo)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) {
|
||||
|
@ -79,7 +80,7 @@ func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd
|
|||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
||||
return newDbKeybase(db).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) {
|
||||
|
@ -88,7 +89,7 @@ func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string,
|
|||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params)
|
||||
return newDbKeybase(db).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, account uint32, index uint32) (info Info, err error) {
|
||||
|
@ -97,7 +98,7 @@ func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, account uint3
|
|||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).CreateLedger(name, algo, account, index)
|
||||
return newDbKeybase(db).CreateLedger(name, algo, account, index)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) {
|
||||
|
@ -106,7 +107,7 @@ func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info In
|
|||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).CreateOffline(name, pubkey)
|
||||
return newDbKeybase(db).CreateOffline(name, pubkey)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
||||
|
@ -115,7 +116,7 @@ func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, e
|
|||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).Update(name, oldpass, getNewpass)
|
||||
return newDbKeybase(db).Update(name, oldpass, getNewpass)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Import(name string, armor string) (err error) {
|
||||
|
@ -124,7 +125,7 @@ func (lkb lazyKeybase) Import(name string, armor string) (err error) {
|
|||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).Import(name, armor)
|
||||
return newDbKeybase(db).Import(name, armor)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) ImportPubKey(name string, armor string) (err error) {
|
||||
|
@ -133,7 +134,7 @@ func (lkb lazyKeybase) ImportPubKey(name string, armor string) (err error) {
|
|||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).ImportPubKey(name, armor)
|
||||
return newDbKeybase(db).ImportPubKey(name, armor)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) Export(name string) (armor string, err error) {
|
||||
|
@ -142,7 +143,7 @@ func (lkb lazyKeybase) Export(name string) (armor string, err error) {
|
|||
return "", err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).Export(name)
|
||||
return newDbKeybase(db).Export(name)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) ExportPubKey(name string) (armor string, err error) {
|
||||
|
@ -151,7 +152,7 @@ func (lkb lazyKeybase) ExportPubKey(name string) (armor string, err error) {
|
|||
return "", err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).ExportPubKey(name)
|
||||
return newDbKeybase(db).ExportPubKey(name)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) {
|
||||
|
@ -160,7 +161,7 @@ func (lkb lazyKeybase) ExportPrivateKeyObject(name string, passphrase string) (c
|
|||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
return New(db).ExportPrivateKeyObject(name, passphrase)
|
||||
return newDbKeybase(db).ExportPrivateKeyObject(name, passphrase)
|
||||
}
|
||||
|
||||
func (lkb lazyKeybase) CloseDB() {}
|
||||
|
|
|
@ -150,6 +150,10 @@ func (i ledgerInfo) GetAddress() types.AccAddress {
|
|||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
func (i ledgerInfo) GetPath() hd.BIP44Params {
|
||||
return i.Path
|
||||
}
|
||||
|
||||
// offlineInfo is the public information about an offline key
|
||||
type offlineInfo struct {
|
||||
Name string `json:"name"`
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package keys
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
)
|
||||
|
||||
func Test_writeReadLedgerInfo(t *testing.T) {
|
||||
var tmpKey secp256k1.PubKeySecp256k1
|
||||
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
|
||||
copy(tmpKey[:], bz)
|
||||
|
||||
lInfo := ledgerInfo{
|
||||
"some_name",
|
||||
tmpKey,
|
||||
*hd.NewFundraiserParams(5, 1)}
|
||||
assert.Equal(t, TypeLedger, lInfo.GetType())
|
||||
assert.Equal(t, "44'/118'/5'/0/1", lInfo.GetPath().String())
|
||||
assert.Equal(t,
|
||||
"cosmospub1addwnpepqddddqg2glc8x4fl7vxjlnr7p5a3czm5kcdp4239sg6yqdc4rc2r5wmxv8p",
|
||||
types.MustBech32ifyAccPub(lInfo.GetPubKey()))
|
||||
|
||||
// Serialize and restore
|
||||
serialized := writeInfo(lInfo)
|
||||
restoredInfo, err := readInfo(serialized)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, restoredInfo)
|
||||
|
||||
// Check both keys match
|
||||
assert.Equal(t, lInfo.GetName(), restoredInfo.GetName())
|
||||
assert.Equal(t, lInfo.GetType(), restoredInfo.GetType())
|
||||
assert.Equal(t, lInfo.GetPubKey(), restoredInfo.GetPubKey())
|
||||
|
||||
assert.Equal(t, lInfo.GetPath(), restoredInfo.(ledgerInfo).GetPath())
|
||||
}
|
|
@ -79,7 +79,7 @@ func TestPublicKeyHDPath(t *testing.T) {
|
|||
// Store and restore
|
||||
serializedPk := priv.Bytes()
|
||||
require.NotNil(t, serializedPk)
|
||||
require.Equal(t, 44, len(serializedPk))
|
||||
require.True(t, len(serializedPk) >= 50)
|
||||
|
||||
privKeys[i] = priv
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ This document contains all the necessary information for delegators to interact
|
|||
|
||||
It also contains instructions on how to manage accounts, restore accounts from the fundraiser and use a ledger nano device.
|
||||
|
||||
__Very Important__: Please assure that you follow the steps described hereinafter
|
||||
::: danger
|
||||
**Very Important**: Please assure that you follow the steps described hereinafter
|
||||
carefully, as negligence in this significant process could lead to an indefinite
|
||||
loss of your Atoms. Therefore, read through the following instructions in their
|
||||
entirety prior to proceeding and reach out to us in case you need support.
|
||||
|
@ -22,6 +23,7 @@ the Tendermint Team may not be held liable for potential damages arising out of
|
|||
software. Any use of this open source software released under the Apache 2.0 license is
|
||||
done at your own risk and on a "AS IS" basis, without warranties or conditions
|
||||
of any kind.
|
||||
:::
|
||||
|
||||
Please exercise extreme caution!
|
||||
|
||||
|
@ -36,9 +38,11 @@ Please exercise extreme caution!
|
|||
+ [Connecting to a remote full-node](#connecting-to-a-remote-full-node)
|
||||
- [Setting up `gaiacli`](#setting-up-gaiacli)
|
||||
- [Querying the state](#querying-the-state)
|
||||
- [Bonding Atoms and Withdrawing rewards](#bonding-atoms-and-withdrawing-rewards)
|
||||
- [Participating in Governance](#participating-in-governance)
|
||||
- [Signing transactions from an offline computer](#signing-transactions-from-an-offline-computer)
|
||||
- [Sending Transactions](#sending-transactions)
|
||||
+ [A note on gas and fees](#a-note-on-gas-and-fees)
|
||||
+ [Bonding Atoms and Withdrawing rewards](#bonding-atoms-and-withdrawing-rewards)
|
||||
+ [Participating in Governance](#participating-in-governance)
|
||||
+ [Signing transactions from an offline computer](#signing-transactions-from-an-offline-computer)
|
||||
|
||||
## Installing `gaiacli`
|
||||
|
||||
|
@ -49,9 +53,17 @@ Please exercise extreme caution!
|
|||
:::
|
||||
|
||||
[**Download the binaries**]
|
||||
Not available yet.
|
||||
|
||||
[**Install from source**](https://cosmos.network/docs/gaia/installation.html)
|
||||
|
||||
::: tip
|
||||
`gaiacli` is used from a terminal. To open the terminal, follow these steps:
|
||||
- **Windows**: `Start` > `All Programs` > `Accessories` > `Command Prompt`
|
||||
- **MacOS**: `Finder` > `Applications` > `Utilities` > `Terminal`
|
||||
- **Linux**: `Ctrl` + `Alt` + `T`
|
||||
:::
|
||||
|
||||
## Cosmos Accounts
|
||||
|
||||
At the core of every Cosmos account, there is a seed, which takes the form of a 12 or 24-words mnemonic. From this mnemonic, it is possible to create any number of Cosmos accounts, i.e. pairs of private key/public key. This is called an HD wallet (see [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) for more information on the HD wallet specification).
|
||||
|
@ -155,9 +167,9 @@ To create an account, you just need to have `gaiacli` installed. Before creating
|
|||
|
||||
When you initialize your ledger, a 24-word mnemonic is generated and stored in the device. This mnemonic is compatible with Cosmos and Cosmos accounts can be derived from it. Therefore, all you have to do is make your ledger compatible with `gaiacli`. To do so, you need to go through the following steps:
|
||||
|
||||
1. Download the Ledger Live app [here](https://www.ledger.com/pages/ledger-live)
|
||||
1. Download the Ledger Live app [here](https://www.ledger.com/pages/ledger-live).
|
||||
2. Connect your ledger via USB and update to the latest firmware
|
||||
3. Go to the ledger live app store, and download the "Cosmos" application (this can take a while)
|
||||
3. Go to the ledger live app store, and download the "Cosmos" application (this can take a while). **Note: You may have to enable `Dev Mode` in the `Settings` of Ledger Live to be able to download the "Cosmos" application**.
|
||||
4. Navigate to the Cosmos app on your ledger device
|
||||
|
||||
Then, to create an account, use the following command:
|
||||
|
@ -231,11 +243,15 @@ In order to connect to the full-node, you will need an address of the following
|
|||
|
||||
## Setting up `gaiacli`
|
||||
|
||||
::: tip
|
||||
**Before setting up `gaiacli`, make sure you have set up a way to [access the Cosmos Hub network](#accessing-the-cosmos-hub-network)**
|
||||
:::
|
||||
|
||||
::: warning
|
||||
**Please check that you are always using the latest stable release of `gaiacli`**
|
||||
:::
|
||||
|
||||
`gaiacli` is the tool that enables you to interact with the node that runs on the Cosmos Hub network, whether you run it yourself or not (see [accessing the cosmos hub network](#accession-the-cosmos-hub-network)). Let us set it up properly.
|
||||
`gaiacli` is the tool that enables you to interact with the node that runs on the Cosmos Hub network, whether you run it yourself or not. Let us set it up properly.
|
||||
|
||||
In order to set up `gaiacli`, use the following command:
|
||||
|
||||
|
@ -266,40 +282,44 @@ gaiacli config trust-node false
|
|||
Finally, let us set the `chain-id` of the blockchain we want to interact with:
|
||||
|
||||
```bash
|
||||
gaiacli config chain-id gos-3
|
||||
gaiacli config chain-id gos-6
|
||||
```
|
||||
|
||||
## Querying the state
|
||||
|
||||
[`gaiacli`](https://cosmos.network/docs/gaia/gaiacli.html) lets you query all relevant information from the blockchain, like account balances, amount of bonded tokens, outstanding rewards, governance proposals and more. Next is a list of the most useful commands for delegator. Please make sure you [set up gaiacli](#setting-up-gaiacli) before trying them.
|
||||
::: tip
|
||||
**Before you can bond atoms and withdraw rewards, you need to [set up `gaiacli`](#setting-up-gaiacli)**
|
||||
:::
|
||||
|
||||
`gaiacli` lets you query all relevant information from the blockchain, like account balances, amount of bonded tokens, outstanding rewards, governance proposals and more. Next is a list of the most useful commands for delegator.
|
||||
|
||||
```bash
|
||||
// query account balances and other account-related information
|
||||
gaiacli query account
|
||||
|
||||
// query the list of validators
|
||||
gaiacli query validators
|
||||
gaiacli query staking validators
|
||||
|
||||
// query the information of a validator given their address (e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg)
|
||||
gaiacli query validator <validatorAddress>
|
||||
// query the information of a validator given their address (e.g. cosmosvaloper1n5pepvmgsfd3p2tqqgvt505jvymmstf6s9gw27)
|
||||
gaiacli query staking validator <validatorAddress>
|
||||
|
||||
// query all delegations made from a delegator given their address (e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg)
|
||||
gaiacli query delegations <delegatorAddress>
|
||||
gaiacli query staking delegations <delegatorAddress>
|
||||
|
||||
// query a specific delegation made from a delegator to a validator given their addresses
|
||||
gaiacli query delegations <delegatorAddress> <validatorAddress>
|
||||
// query a specific delegation made from a delegator (e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg) to a validator (e.g. cosmosvaloper1n5pepvmgsfd3p2tqqgvt505jvymmstf6s9gw27) given their addresses
|
||||
gaiacli query staking delegation <delegatorAddress> <validatorAddress>
|
||||
|
||||
// query the rewards of a delegator given a delegator address (e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg)
|
||||
gaiacli query distr rewards <delegatorAddress>
|
||||
|
||||
// query all proposals currently open for depositing
|
||||
gaiacli query proposals --status deposit_period
|
||||
gaiacli query gov proposals --status deposit_period
|
||||
|
||||
// query all proposals currently open for voting
|
||||
gaiacli query proposals --status voting_period
|
||||
gaiacli query gov proposals --status voting_period
|
||||
|
||||
// query a proposal given its proposalID
|
||||
gaiacli query proposal <proposalID>
|
||||
gaiacli query gov proposal <proposalID>
|
||||
```
|
||||
|
||||
For more commands, just type:
|
||||
|
@ -310,47 +330,7 @@ gaiacli query
|
|||
|
||||
For each command, you can use the `-h` or `--help` flag to get more information.
|
||||
|
||||
## Bonding Atoms and Withdrawing rewards
|
||||
|
||||
::: warning
|
||||
**Before bonding Atoms, please read the [delegator faq](https://cosmos.network/resources/delegators) to understand the risk and responsabilities involved with delegating**
|
||||
:::
|
||||
|
||||
::: warning
|
||||
**Note: These commands need to be run on an online computer. It is more secure to perform them commands using a ledger device. For the offline procedure, click [here](#signing-transactions-from-an-offline-computer).**
|
||||
:::
|
||||
|
||||
```bash
|
||||
// Bond Atoms
|
||||
// ex value for flags: <amountToBound>=10000stake, <bech32AddressOfValidator>=cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx staking --amount <amountToBond> --validator <bech32AddressOfValidator> --from <delegatorKeyName> --gas auto --gas-prices <gasPrice>
|
||||
|
||||
// Withdraw rewards
|
||||
|
||||
gaiacli tx distr withdraw-rewards --from <delegatorKeyName>
|
||||
```
|
||||
|
||||
::: tip
|
||||
If you use a connected Ledger, you will be asked to confirm the transaction on the device before it is signed and broadcast to the network
|
||||
:::
|
||||
|
||||
To confirm that your transaction went through, you can use the following queries:
|
||||
|
||||
```bash
|
||||
// your balance should change after you bond Atoms or withdraw rewards
|
||||
gaiacli query account
|
||||
|
||||
// you should have delegations after you bond Atom
|
||||
gaiacli query delegations <delegatorAddress>
|
||||
|
||||
// this returns your tx if it has been included
|
||||
// use the tx hash that was displayed when you created the tx
|
||||
gaiacli query tx <txHash>
|
||||
|
||||
```
|
||||
|
||||
Double check with a block explorer if you interact with the network through a trusted full-node.
|
||||
## Sending Transactions
|
||||
|
||||
### A note on gas and fees
|
||||
|
||||
|
@ -364,11 +344,66 @@ The `gas` is dependent on the transaction. Different transaction require differe
|
|||
|
||||
The `gasPrice` is the price of each unit of `gas`. Each validator sets a `min-gas-price` value, and will only include transactions that have a `gasPrice` greater than their `min-gas-price`.
|
||||
|
||||
The transaction `fees` are the product of `gas` and `gasPrice`. As a user, you have to input 2 out of 3. The higher the `gasPrice`, the higher the chance that your transaction will get included in a block.
|
||||
The transaction `fees` are the product of `gas` and `gasPrice`. As a user, you have to input 2 out of 3. The higher the `gasPrice`/`fees`, the higher the chance that your transaction will get included in a block.
|
||||
|
||||
### Bonding Atoms and Withdrawing rewards
|
||||
|
||||
::: tip
|
||||
**Before you can bond atoms and withdraw rewards, you need to [set up `gaiacli`](#setting-up-gaiacli) and [create an account](#creating-an-account)**
|
||||
:::
|
||||
|
||||
::: warning
|
||||
**Before bonding Atoms, please read the [delegator faq](https://cosmos.network/resources/delegators) to understand the risk and responsabilities involved with delegating**
|
||||
:::
|
||||
|
||||
::: warning
|
||||
**Note: These commands need to be run on an online computer. It is more secure to perform them commands using a ledger device. For the offline procedure, click [here](#signing-transactions-from-an-offline-computer).**
|
||||
:::
|
||||
|
||||
```bash
|
||||
// Bond a certain amount of Atoms to a given validator
|
||||
// ex value for flags: <validatorAddress>=cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, <amountToBound>=10000stake, <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx staking delegate <validatorAddress> <amountToBond> --from <delegatorKeyName> --gas auto --gas-prices <gasPrice>
|
||||
|
||||
|
||||
// Withdraw all rewards
|
||||
// ex value for flag: <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx distr withdraw-all-rewards --from <delegatorKeyName> --gas auto --gas-prices <gasPrice>
|
||||
|
||||
|
||||
// Unbond a certain amount of Atoms from a given validator
|
||||
// You will have to wait 3 weeks before your Atoms are fully unbonded and transferrable
|
||||
// ex value for flags: <validatorAddress>=cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, <amountToUnbound>=10000stake, <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx staking unbond <validatorAddress> <amountToUnbond> --from <delegatorKeyName> --gas auto --gas-prices <gasPrice>
|
||||
```
|
||||
|
||||
::: tip
|
||||
If you use a connected Ledger, you will be asked to confirm the transaction on the device before it is signed and broadcast to the network
|
||||
:::
|
||||
|
||||
To confirm that your transaction went through, you can use the following queries:
|
||||
|
||||
```bash
|
||||
// your balance should change after you bond Atoms or withdraw rewards
|
||||
gaiacli query account
|
||||
|
||||
// you should have delegations after you bond Atom
|
||||
gaiacli query staking delegations <delegatorAddress>
|
||||
|
||||
// this returns your tx if it has been included
|
||||
// use the tx hash that was displayed when you created the tx
|
||||
gaiacli query tx <txHash>
|
||||
|
||||
```
|
||||
|
||||
Double check with a block explorer if you interact with the network through a trusted full-node.
|
||||
|
||||
## Participating in governance
|
||||
|
||||
### Primer on governance
|
||||
#### Primer on governance
|
||||
|
||||
The Cosmos Hub has a built-in governance system that lets bonded Atom holders vote on proposals. There are three types of proposal:
|
||||
|
||||
|
@ -382,7 +417,11 @@ Once the `deposit` reaches `minDeposit`, the proposal enters the `voting_period`
|
|||
|
||||
At the end of the voting period, the proposal is accepted if there are more than 50% `Yes` votes (excluding `Abstain ` votes) and less than 33.33% of `NoWithVeto` votes (excluding `Abstain` votes).
|
||||
|
||||
### In practice
|
||||
#### In practice
|
||||
|
||||
::: tip
|
||||
**Before you can bond atoms and withdraw rewards, you need to [bond Atoms](#bonding-atoms-and-withdrawing-rewards)**
|
||||
:::
|
||||
|
||||
::: warning
|
||||
**Note: These commands need to be run on an online computer. It is more secure to perform them commands using a ledger device. For the offline procedure, click [here](#signing-transactions-from-an-offline-computer).**
|
||||
|
@ -408,7 +447,7 @@ gaiacli tx gov deposit <proposalID> <deposit> --gas auto --gas-prices <gasPrice>
|
|||
gaiacli tx gov vote <proposalID> <option> --gas auto --gas-prices <gasPrice> --from <delegatorKeyName>
|
||||
```
|
||||
|
||||
## Signing transactions from an offline computer
|
||||
### Signing transactions from an offline computer
|
||||
|
||||
If you do not have a ledger device and want to interact with your private key on an offline computer, you can use the following procedure. First, generate an unsigned transaction on an **online computer** with the following command (example with a bonding transaction):
|
||||
|
||||
|
@ -416,7 +455,7 @@ If you do not have a ledger device and want to interact with your private key on
|
|||
// Bond Atoms
|
||||
// ex value for flags: <amountToBound>=10000stake, <bech32AddressOfValidator>=cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx staking --amount <amountToBond> --validator <bech32AddressOfValidator> --gas auto --gas-prices <gasPrice> --generate-only > unsignedTX.json
|
||||
gaiacli tx staking delegate <validatorAddress> <amountToBond> --from <delegatorKeyName> --gas auto --gas-prices <gasPrice> --generate-only > unsignedTX.json
|
||||
```
|
||||
|
||||
Then, copy `unsignedTx.json` and transfer it (e.g. via USB) to the offline computer. If it is not done already, [create an account on the offline computer](#using-a-computer). For additional security, you can double check the parameters of your transaction before signing it using the following command:
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
# Cosmos Hub to Launch Mainnet
|
||||
|
||||
## Pre-launch Dependencies & How to Safely Claim Your Atoms
|
||||
|
||||
In the summer of 2016, the [Cosmos whitepaper][whitepaper] was released. In the
|
||||
spring of 2017, the [Cosmos fundraiser][fundraiser] was completed. In the first
|
||||
months of 2019, the software is [feature complete][releases]. The launch of the
|
||||
Cosmos Hub draws near. What does this mean for Atom holders?
|
||||
|
||||
If you are an Atom holder, you will be able to delegate Atoms to validators on
|
||||
the main network and vote on governance proposals. In fact, the future success
|
||||
of the network depends on you responsibly doing so! However, you will not be
|
||||
able to transfer Atoms yet. Transfers will be disabled at the protocol level
|
||||
until a hard-fork is executed to enable them.
|
||||
|
||||
Atom holders should carefully follow the guidelines in order to safely delegate
|
||||
Atoms. Please read through the entire guide first to familiarize yourself
|
||||
before you actually do anything: [CLI guide][cli]
|
||||
|
||||
The process outlined in the guide is currently the only verified and secure way
|
||||
to delegate Atoms at launch. This is because the gaiacli tool used in the guide
|
||||
is the only wallet software undergoing third-party security audits right now.
|
||||
No other wallet providers have begun security audits yet.
|
||||
|
||||
Remember that delegating Atoms involves significant risk. Once delegated to a
|
||||
validator, Atoms are bonded for a period of time during which they cannot be
|
||||
recovered. If the validator misbehaves during this time, some or all of the
|
||||
delegated Atoms may be burned. It is your responsibility to perform due
|
||||
diligence on validators before delegating!
|
||||
|
||||
The Cosmos Hub is highly experimental software. In these early days, we can
|
||||
expect to have issues, updates, and bugs. The existing tools require advanced
|
||||
technical skills and involve risks which are outside of the control of the
|
||||
Interchain Foundation and/or the Tendermint team (see also the risk section in
|
||||
the [Interchain Cosmos Contribution Terms][terms]). Any use of this open source
|
||||
[Apache 2.0 licensed][apache] software is done at your own risk and on a “AS
|
||||
IS” basis without warranties or conditions of any kind, and any and all
|
||||
liability of the Interchain Foundation and/or the Tendermint team for damages
|
||||
arising in connection to the software is excluded. Please exercise extreme
|
||||
caution!
|
||||
|
||||
If you are looking for more information about delegation and want to talk to
|
||||
the folks developing Cosmos, join the virtual meetup on February 14 where you
|
||||
will be walked through the step-by-step instructions for delegating Atoms at
|
||||
launch.
|
||||
|
||||
Register here: [gotowebinar.com/register/][webinar]
|
||||
|
||||
## Remaining Milestones for Launch
|
||||
|
||||
To follow mainnet launch progress, please bookmark:
|
||||
[cosmos.network/launch][cosmos].
|
||||
|
||||
### 5 Cosmos-SDK Security Audits ✔
|
||||
|
||||
In early January, the Cosmos-SDK underwent the first in a series of third-party
|
||||
security assessments scheduled for Q1 2019. This audit took place over a two
|
||||
and a half week period. To date, two different security auditing firms have
|
||||
assessed various parts of the Cosmos-SDK and a third audit is under way.
|
||||
|
||||
### 4 Cosmos SDK Feature Freeze
|
||||
|
||||
The final breaking changes to the Cosmos-SDK are included in the [v0.31.0
|
||||
launch RC][rc]. Once this RC is completed, the Cosmos-SDK team will engage in a
|
||||
round of internal bug hunting to further ensure sufficient pre-launch security
|
||||
due diligence.
|
||||
|
||||
Right after Cosmos-SDK v0.31.0 is released, a Gaia testnet will be released in
|
||||
an effort to flush out any hard to find bugs.
|
||||
|
||||
### 3 Game of Stakes Completed
|
||||
|
||||
Game of Stakes (GoS), [the first adversarial testnet competition of its
|
||||
kind][gos], was launched in December 2018 to stress test the economic incentive
|
||||
and social layers of a blockchain network secured purely by Proof-of-Stake. The
|
||||
GoS blockchain was successfully hard-forked three times to date. As soon as the
|
||||
GoS concludes, the [scoring criteria][scoring] will be used to determine
|
||||
winners. Those will be announced following the completion of the game.
|
||||
|
||||
### 2 Genesis Transactions Collected
|
||||
|
||||
The Interchain Foundation will publish a recommendation for the allocation of
|
||||
Atoms at genesis. This will include allocations for Cosmos fundraiser
|
||||
participants, early contributors, and Game of Stakes winners. Any one with a
|
||||
recommended allocation will have the opportunity to submit a gentx, which is
|
||||
required to become a validator at genesis. The ultimate result of the
|
||||
recommended allocation and the collection of gentxs is a final [genesis
|
||||
file][file].
|
||||
|
||||
### 1 Cosmos Hub Mainnet Launch
|
||||
|
||||
Once a genesis file is adopted by the community, and +⅔ of the voting power
|
||||
comes online, the Cosmos mainnet will be live.
|
||||
|
||||
## Official Cosmos Communication Channels
|
||||
|
||||
These are the official accounts that will communicate launch details:
|
||||
|
||||
- [Cosmos Network](https://twitter.com/cosmos)
|
||||
- [Cosmos GitHub](https://github.com/cosmos)
|
||||
- [Cosmos Blog](https://blog.cosmos.network)
|
||||
|
||||
Please be aware that the [Cosmos forum][forum], [Riot chat groups][riot], and
|
||||
[Telegram group][telegram] should not be treated as official news from Cosmos.
|
||||
|
||||
If you have doubt or confusion about what next steps to take and are unsure
|
||||
about trustworthy sources of information, do nothing for the initial period and
|
||||
wait for an update via the three communication channels listed above. Do not
|
||||
ever provide your 12 words to any admin, websites or unofficial software.
|
||||
|
||||
**We will never ask you for your private key or your seed phrase.**
|
||||
|
||||
## Staying Safe (and Secure!) for Mainnet Launch
|
||||
|
||||
The launch of any public blockchain is an incredibly exciting time, and it’s
|
||||
definitely one that malicious actors may try to take advantage of for their own
|
||||
personal gain. [Social engineering][social] has existed for about as long as
|
||||
human beings have been on the planet, and in the technical era, it usually
|
||||
takes in the form of [phishing] or [spearphishing]. Both of these attacks are
|
||||
wildly successful forms of trickery that are responsible for over 95% of
|
||||
account security breaches, and they don’t just happen via email: these days,
|
||||
opportunistic and targeted phishing attempts take place [anywhere that you have
|
||||
an inbox][inbox]. It doesn’t matter if you’re using Signal, Telegram, SMS,
|
||||
Twitter, or just checking your DMs on forums or social networks, attackers have
|
||||
a [plethora of opportunities][opportunities] to gain foothold in your digital
|
||||
life in effort to separate you from valuable information and assets that you
|
||||
most definitely don’t want to lose.
|
||||
|
||||
While the prospect of having to deal with a malicious actor plotting against
|
||||
you may seem daunting, there are many things that you can do to protect
|
||||
yourself from all kinds of social engineering schemes. In terms of preparing
|
||||
for mainnet launch, this should require training your instincts to successfully
|
||||
detect and avoid security risks, curating resources to serve as a source of
|
||||
truth for verifying information, and going through a few technical steps to
|
||||
reduce or eliminate the risk of key or credential theft.
|
||||
|
||||
**Here are few rules of engagement to keep in mind when you’re preparing for
|
||||
Cosmos mainnet launch:**
|
||||
|
||||
- Download software directly from official sources, and make sure that you’re
|
||||
always using the latest, most secure version of gaiacli when you’re doing
|
||||
anything that involves your 12 words. The latest versions of Tendermint, the
|
||||
Cosmos-SDK, and gaiacli will always be available from our official GitHub
|
||||
repositories, and downloading them from there ensures that you will not be
|
||||
tricked into using a maliciously modified version of software.
|
||||
|
||||
- Do not share your 12 words with anyone. The only person who should ever need
|
||||
to know them is you. This is especially important if you’re ever approached
|
||||
by someone attempting to offer custodial services for your Atom: to avoid
|
||||
losing control of your tokens, you should store them offline to minimize the
|
||||
risk of theft and have a strong backup strategy in place. And never, ever
|
||||
share them with anyone else.
|
||||
|
||||
- Be skeptical of unexpected attachments or emails that ask you to visit a
|
||||
suspicious or unfamiliar website in the context of blockchains or
|
||||
cryptocurrency. An attacker may attempt to lure you to a [compromised site]
|
||||
designed to steal sensitive information from your computer. If you’re a Gmail
|
||||
user, test your resilience against the latest email-based phishing tactics
|
||||
[here][quiz].
|
||||
|
||||
- Do your due diligence before purchasing Atoms. Atoms will not be transferable
|
||||
at launch, so they *cannot* be bought or sold until a hard fork enables them
|
||||
to be. If and when they become transferable, make sure that you’ve researched
|
||||
the seller or exchange to confirm that the Atoms are coming from a
|
||||
trustworthy source.
|
||||
|
||||
- Neither the Tendermint team nor the Interchain Foundation will be selling
|
||||
Atoms, so if you see social media posts or emails advertising a token sale
|
||||
from us, they’re not real and should be avoided. Enable 2-factor
|
||||
authentication, and be mindful of recovery methods used to regain access to
|
||||
your most important accounts. Unprotected accounts like email, social media,
|
||||
your GitHub account, the Cosmos Forum and anything in between could give an
|
||||
attacker opportunities to gain foothold in your online life. If you haven’t
|
||||
done so yet, start using an authenticator app or a hardware key immediately
|
||||
wherever you manage your tokens. This is a simple, effective, and proven way
|
||||
to reduce the risk of account theft.
|
||||
|
||||
- Be skeptical of technical advice, especially advice that comes from people
|
||||
you do not know in forums and on group chat channels. Familiarize yourself
|
||||
with important commands, especially those that will help you carry out
|
||||
high-risk actions, and consult our official documentation to make sure that
|
||||
you’re not being tricked into doing something that will harm you or your
|
||||
validator. And remember that the Cosmos forum, Riot channels, and Telegram
|
||||
are not sources of official information or news about Cosmos.
|
||||
|
||||
- Verify transactions before hitting send. Yes, those address strings are long,
|
||||
but visually comparing them in blocks of 4 characters at a time may be the
|
||||
difference between sending them to the right place or sending them into
|
||||
oblivion.
|
||||
|
||||
*If a deal pops up that [sounds too good to be true][good], or a message shows
|
||||
up asking for information that should never, ever be shared with someone else,
|
||||
you can always work to verify it before engaging with it by navigating to a
|
||||
website or official Cosmos communication channel on your own. No one from
|
||||
Cosmos, the Tendermint team or the Interchain Foundation will ever send an
|
||||
email that asks for you to share any kind of account credentials or your 12
|
||||
words with us, and we will always use our official blog, Twitter and GitHub
|
||||
accounts to communicate important news directly to the Cosmos community.*
|
||||
|
||||
[whitepaper]: https://cosmos.network/resources/whitepaper
|
||||
[fundraiser]: https://fundraiser.cosmos.network/
|
||||
[releases]: https://github.com/cosmos/cosmos-sdk/releases
|
||||
[cosmos]: https://cosmos.network/launch
|
||||
[social]: https://en.wikipedia.org/wiki/Social_engineering_%28security%29
|
||||
[phishing]: https://ssd.eff.org/en/module/how-avoid-phishing-attacks
|
||||
[spearphishing]: https://en.wikipedia.org/wiki/Phishing#Spear_phishing
|
||||
[inbox]: https://www.umass.edu/it/security/phishing-fraudulent-emails-text-messages-phone-calls
|
||||
[opportunities]: https://jia.sipa.columbia.edu/weaponization-social-media-spear-phishing-and-cyberattacks-democracy
|
||||
[cli]: https://github.com/cosmos/cosmos-sdk/blob/develop/docs/gaia/delegator-guide-cli.md
|
||||
[webinar]: https://register.gotowebinar.com/register/5028753165739687691
|
||||
[terms]: https://github.com/cosmos/cosmos/blob/master/fundraiser/Interchain%20Cosmos%20Contribution%20Terms%20-%20FINAL.pdf
|
||||
[apache]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
[gos]: https://blog.cosmos.network/announcing-incentivized-testnet-game-efe64e0956f6
|
||||
[scoring]: https://github.com/cosmos/game-of-stakes/blob/master/README.md#scoring
|
||||
[file]: https://forum.cosmos.network/t/genesis-files-network-starts-vs-upgrades/1464
|
||||
[forum]: https://forum.cosmos.network/
|
||||
[riot]: https://riot.im/app/#/group/+cosmos:matrix.org
|
||||
[telegram]: http://t.me/cosmosproject
|
||||
[good]: https://www.psychologytoday.com/us/blog/mind-in-the-machine/201712/how-fear-is-being-used-manipulate-cryptocurrency-markets
|
||||
[rc]: https://github.com/cosmos/cosmos-sdk/projects/27
|
||||
[compromised site]: https://blog.malwarebytes.com/cybercrime/2013/02/tools-of-the-trade-exploit-kits/
|
||||
[quiz]: https://phishingquiz.withgoogle.com/
|
|
@ -311,7 +311,7 @@ func (coins Coins) IsAnyGTE(coinsB Coins) bool {
|
|||
|
||||
for _, coin := range coins {
|
||||
amt := coinsB.AmountOf(coin.Denom)
|
||||
if coin.Amount.GTE(amt) {
|
||||
if coin.Amount.GTE(amt) && !amt.IsZero() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -517,6 +517,7 @@ func TestCoinsIsAnyGTE(t *testing.T) {
|
|||
assert.False(t, Coins{{"a", one}}.IsAnyGTE(Coins{}))
|
||||
assert.False(t, Coins{}.IsAnyGTE(Coins{{"a", one}}))
|
||||
assert.False(t, Coins{{"a", one}}.IsAnyGTE(Coins{{"a", two}}))
|
||||
assert.False(t, Coins{{"a", one}}.IsAnyGTE(Coins{{"b", one}}))
|
||||
assert.True(t, Coins{{"a", one}, {"b", two}}.IsAnyGTE(Coins{{"a", two}, {"b", one}}))
|
||||
assert.True(t, Coins{{"a", one}}.IsAnyGTE(Coins{{"a", one}}))
|
||||
assert.True(t, Coins{{"a", two}}.IsAnyGTE(Coins{{"a", one}}))
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
|
@ -246,19 +247,22 @@ func (err *sdkError) Code() CodeType {
|
|||
|
||||
// Implements ABCIError.
|
||||
func (err *sdkError) ABCILog() string {
|
||||
cdc := codec.New()
|
||||
errMsg := err.cmnError.Error()
|
||||
jsonErr := humanReadableError{
|
||||
Codespace: err.codespace,
|
||||
Code: err.code,
|
||||
Message: errMsg,
|
||||
}
|
||||
bz, er := cdc.MarshalJSON(jsonErr)
|
||||
if er != nil {
|
||||
panic(er)
|
||||
|
||||
var buff bytes.Buffer
|
||||
enc := json.NewEncoder(&buff)
|
||||
enc.SetEscapeHTML(false)
|
||||
|
||||
if err := enc.Encode(jsonErr); err != nil {
|
||||
panic(errors.Wrap(err, "failed to encode ABCI error log"))
|
||||
}
|
||||
stringifiedJSON := string(bz)
|
||||
return stringifiedJSON
|
||||
|
||||
return strings.TrimSpace(buff.String())
|
||||
}
|
||||
|
||||
func (err *sdkError) Result() Result {
|
||||
|
|
|
@ -72,18 +72,23 @@ func TestAppendMsgToErr(t *testing.T) {
|
|||
|
||||
// plain msg error
|
||||
msg := AppendMsgToErr("something unexpected happened", errMsg)
|
||||
require.Equal(t, fmt.Sprintf("something unexpected happened; %s",
|
||||
errMsg),
|
||||
require.Equal(
|
||||
t,
|
||||
fmt.Sprintf("something unexpected happened; %s", errMsg),
|
||||
msg,
|
||||
fmt.Sprintf("Should have formatted the error message of ABCI Log. tc #%d", i))
|
||||
fmt.Sprintf("Should have formatted the error message of ABCI Log. tc #%d", i),
|
||||
)
|
||||
|
||||
// ABCI Log msg error
|
||||
msg = AppendMsgToErr("something unexpected happened", abciLog)
|
||||
msgIdx := mustGetMsgIndex(abciLog)
|
||||
require.Equal(t, fmt.Sprintf("%s%s; %s}",
|
||||
require.Equal(
|
||||
t,
|
||||
fmt.Sprintf("%s%s; %s}",
|
||||
abciLog[:msgIdx],
|
||||
"something unexpected happened",
|
||||
abciLog[msgIdx:len(abciLog)-1]),
|
||||
abciLog[msgIdx:len(abciLog)-1],
|
||||
),
|
||||
msg,
|
||||
fmt.Sprintf("Should have formatted the error message of ABCI Log. tc #%d", i))
|
||||
}
|
||||
|
|
|
@ -55,6 +55,10 @@ type TxResponse struct {
|
|||
}
|
||||
|
||||
func NewResponseResultTx(res *ctypes.ResultTx, tx Tx) TxResponse {
|
||||
if res == nil {
|
||||
return TxResponse{}
|
||||
}
|
||||
|
||||
return TxResponse{
|
||||
TxHash: res.Hash.String(),
|
||||
Height: res.Height,
|
||||
|
@ -70,9 +74,18 @@ func NewResponseResultTx(res *ctypes.ResultTx, tx Tx) TxResponse {
|
|||
}
|
||||
|
||||
func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxResponse {
|
||||
if res == nil {
|
||||
return TxResponse{}
|
||||
}
|
||||
|
||||
var txHash string
|
||||
if res.Hash != nil {
|
||||
txHash = res.Hash.String()
|
||||
}
|
||||
|
||||
return TxResponse{
|
||||
Height: res.Height,
|
||||
TxHash: res.Hash.String(),
|
||||
TxHash: txHash,
|
||||
Code: res.DeliverTx.Code,
|
||||
Data: res.DeliverTx.Data,
|
||||
Log: res.DeliverTx.Log,
|
||||
|
@ -85,6 +98,10 @@ func NewResponseFormatBroadcastTxCommit(res *ctypes.ResultBroadcastTxCommit) TxR
|
|||
}
|
||||
|
||||
func NewResponseFormatBroadcastTx(res *ctypes.ResultBroadcastTx) TxResponse {
|
||||
if res == nil {
|
||||
return TxResponse{}
|
||||
}
|
||||
|
||||
return TxResponse{
|
||||
Code: res.Code,
|
||||
Data: res.Data.Bytes(),
|
||||
|
|
|
@ -306,20 +306,22 @@ func DeductFees(blockTime time.Time, acc Account, fee StdFee) (Account, sdk.Resu
|
|||
// get the resulting coins deducting the fees
|
||||
newCoins, ok := coins.SafeMinus(feeAmount)
|
||||
if ok {
|
||||
errMsg := fmt.Sprintf("%s < %s", coins, feeAmount)
|
||||
return nil, sdk.ErrInsufficientFunds(errMsg).Result()
|
||||
return nil, sdk.ErrInsufficientFunds(
|
||||
fmt.Sprintf("insufficient funds to pay for fees; %s < %s", coins, feeAmount),
|
||||
).Result()
|
||||
}
|
||||
|
||||
// Validate the account has enough "spendable" coins as this will cover cases
|
||||
// such as vesting accounts.
|
||||
spendableCoins := acc.SpendableCoins(blockTime)
|
||||
if _, hasNeg := spendableCoins.SafeMinus(feeAmount); hasNeg {
|
||||
return nil, sdk.ErrInsufficientFunds(fmt.Sprintf("%s < %s", spendableCoins, feeAmount)).Result()
|
||||
return nil, sdk.ErrInsufficientFunds(
|
||||
fmt.Sprintf("insufficient funds to pay for fees; %s < %s", spendableCoins, feeAmount),
|
||||
).Result()
|
||||
}
|
||||
|
||||
if err := acc.SetCoins(newCoins); err != nil {
|
||||
// Handle w/ #870
|
||||
panic(err)
|
||||
return nil, sdk.ErrInternal(err.Error()).Result()
|
||||
}
|
||||
|
||||
return acc, sdk.Result{}
|
||||
|
|
|
@ -230,7 +230,9 @@ func subtractCoins(ctx sdk.Context, ak auth.AccountKeeper, addr sdk.AccAddress,
|
|||
// So the check here is sufficient instead of subtracting from oldCoins.
|
||||
_, hasNeg := spendableCoins.SafeMinus(amt)
|
||||
if hasNeg {
|
||||
return amt, nil, sdk.ErrInsufficientCoins(fmt.Sprintf("%s < %s", spendableCoins, amt))
|
||||
return amt, nil, sdk.ErrInsufficientCoins(
|
||||
fmt.Sprintf("insufficient account funds; %s < %s", spendableCoins, amt),
|
||||
)
|
||||
}
|
||||
|
||||
newCoins := oldCoins.Minus(amt) // should not panic as spendable coins was already checked
|
||||
|
@ -246,7 +248,9 @@ func addCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt s
|
|||
newCoins := oldCoins.Plus(amt)
|
||||
|
||||
if newCoins.IsAnyNegative() {
|
||||
return amt, nil, sdk.ErrInsufficientCoins(fmt.Sprintf("%s < %s", oldCoins, amt))
|
||||
return amt, nil, sdk.ErrInsufficientCoins(
|
||||
fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt),
|
||||
)
|
||||
}
|
||||
|
||||
err := setCoins(ctx, am, addr, newCoins)
|
||||
|
@ -319,7 +323,9 @@ func delegateCoins(
|
|||
|
||||
_, hasNeg := oldCoins.SafeMinus(amt)
|
||||
if hasNeg {
|
||||
return nil, sdk.ErrInsufficientCoins(fmt.Sprintf("%s < %s", oldCoins, amt))
|
||||
return nil, sdk.ErrInsufficientCoins(
|
||||
fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt),
|
||||
)
|
||||
}
|
||||
|
||||
if err := trackDelegation(acc, ctx.BlockHeader().Time, amt); err != nil {
|
||||
|
|
Loading…
Reference in New Issue