Merge PR #3626: Release v0.31.2

This commit is contained in:
Jack Zampolin 2019-02-12 09:40:30 -08:00 committed by GitHub
commit 05de8135ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 626 additions and 233 deletions

View File

@ -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

View File

@ -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)

View File

@ -48,4 +48,4 @@ BUG FIXES
* SDK
* Tendermint
* Tendermint

View File

@ -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())
}

View File

@ -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)

View File

@ -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()))
}

View File

@ -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

View File

@ -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

View File

@ -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"),

View File

@ -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)

View File

@ -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.

View File

@ -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)
}

View File

@ -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 {
// The mock is available, check that the address is correct
pubKey := ledger.GetPubKey()
addr, err := sdk.Bech32ifyAccPub(pubKey)
assert.NoError(t, err)
assert.Equal(t, "cosmospub1addwnpepqfsdqjr68h7wjg5wacksmqaypasnra232fkgu5sxdlnlu8j22ztxvlqvd65", addr)
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()
pk, err := sdk.Bech32ifyAccPub(pubKey)
assert.NoError(t, err)
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())
}

View File

@ -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() {}

View File

@ -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"`

40
crypto/keys/types_test.go Normal file
View File

@ -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())
}

View File

@ -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
}

View File

@ -4,10 +4,11 @@ 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.
entirety prior to proceeding and reach out to us in case you need support.
Please also note that you are about to interact with the Cosmos Hub, a
blockchain technology containing highly experimental software. While the
@ -21,7 +22,8 @@ associated with cryptographic software (see also risk section of the
the Tendermint Team may not be held liable for potential damages arising out of the use of the
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.
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:

View File

@ -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 its
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 dont just happen via email: these days,
opportunistic and targeted phishing attempts take place [anywhere that you have
an inbox][inbox]. It doesnt matter if youre 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 dont 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 youre preparing for
Cosmos mainnet launch:**
- Download software directly from official sources, and make sure that youre
always using the latest, most secure version of gaiacli when youre 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 youre 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 youre 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 youve 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, theyre 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 havent
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
youre 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/

View File

@ -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
}
}

View File

@ -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}}))

View File

@ -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 {

View File

@ -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}",
abciLog[:msgIdx],
"something unexpected happened",
abciLog[msgIdx:len(abciLog)-1]),
require.Equal(
t,
fmt.Sprintf("%s%s; %s}",
abciLog[:msgIdx],
"something unexpected happened",
abciLog[msgIdx:len(abciLog)-1],
),
msg,
fmt.Sprintf("Should have formatted the error message of ABCI Log. tc #%d", i))
}

View File

@ -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(),

View File

@ -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{}

View File

@ -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 {