Merge PR #1086: Bech32Cosmos output/input for the LCD

* refactored bech32ization
* updated keys endpoints for bech32
* bech32 for sending and querying
* trying to change output of validator addresses
* fixed validator output
* linted
* fixed merge conflict
* added bech32 to staking endpoints
* removed some logging statements
* added GetAccPubKeyBech32Cosmos
* fixed cli tests
* updated swagger
* merged standard bech32 change
* renamed bech32cosmos to bech32
* bech32ify json output for key add
* readded changelog
* fixed changelog merge issue
* Update CHANGELOG.md
This commit is contained in:
Fabian 2018-06-06 06:53:04 +02:00 committed by Christopher Goes
parent af15f89531
commit 5f409ce832
15 changed files with 348 additions and 138 deletions

View File

@ -1,5 +1,9 @@
# Changelog # Changelog
BREAKING CHANGES
* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs
## 0.18.0 ## 0.18.0
_2018-06-05_ _2018-06-05_

View File

@ -102,12 +102,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
return nil return nil
} }
// addOutput lets us json format the data
type addOutput struct {
Key keys.Info `json:"key"`
Seed string `json:"seed"`
}
func printCreate(info keys.Info, seed string) { func printCreate(info keys.Info, seed string) {
output := viper.Get(cli.OutputFlag) output := viper.Get(cli.OutputFlag)
switch output { switch output {
@ -121,7 +115,10 @@ func printCreate(info keys.Info, seed string) {
fmt.Println(seed) fmt.Println(seed)
} }
case "json": case "json":
out := addOutput{Key: info} out, err := Bech32KeyOutput(info)
if err != nil {
panic(err)
}
if !viper.GetBool(flagNoBackup) { if !viper.GetBool(flagNoBackup) {
out.Seed = seed out.Seed = seed
} }

View File

@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -54,9 +53,11 @@ func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("[]")) w.Write([]byte("[]"))
return return
} }
keysOutput := make([]KeyOutput, len(infos)) keysOutput, err := Bech32KeysOutput(infos)
for i, info := range infos { if err != nil {
keysOutput[i] = KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address().Bytes())} w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
} }
output, err := json.MarshalIndent(keysOutput, "", " ") output, err := json.MarshalIndent(keysOutput, "", " ")
if err != nil { if err != nil {

View File

@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/gorilla/mux" "github.com/gorilla/mux"
keys "github.com/tendermint/go-crypto/keys" keys "github.com/tendermint/go-crypto/keys"
@ -51,7 +50,12 @@ func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
keyOutput := KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address())} keyOutput, err := Bech32KeyOutput(info)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := json.MarshalIndent(keyOutput, "", " ") output, err := json.MarshalIndent(keyOutput, "", " ")
if err != nil { if err != nil {
w.WriteHeader(500) w.WriteHeader(500)

View File

@ -6,7 +6,6 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
crypto "github.com/tendermint/go-crypto"
keys "github.com/tendermint/go-crypto/keys" keys "github.com/tendermint/go-crypto/keys"
"github.com/tendermint/tmlibs/cli" "github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
@ -47,29 +46,47 @@ func SetKeyBase(kb keys.Keybase) {
// used for outputting keys.Info over REST // used for outputting keys.Info over REST
type KeyOutput struct { type KeyOutput struct {
Name string `json:"name"` Name string `json:"name"`
Address sdk.Address `json:"address"` Address string `json:"address"`
PubKey crypto.PubKey `json:"pub_key"` PubKey string `json:"pub_key"`
Seed string `json:"seed,omitempty"`
} }
func NewKeyOutput(info keys.Info) KeyOutput { // create a list of KeyOutput in bech32 format
return KeyOutput{ func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) {
Name: info.Name,
Address: sdk.Address(info.PubKey.Address().Bytes()),
PubKey: info.PubKey,
}
}
func NewKeyOutputs(infos []keys.Info) []KeyOutput {
kos := make([]KeyOutput, len(infos)) kos := make([]KeyOutput, len(infos))
for i, info := range infos { for i, info := range infos {
kos[i] = NewKeyOutput(info) ko, err := Bech32KeyOutput(info)
if err != nil {
return nil, err
}
kos[i] = ko
} }
return kos return kos, nil
}
// create a KeyOutput in bech32 format
func Bech32KeyOutput(info keys.Info) (KeyOutput, error) {
bechAccount, err := sdk.Bech32ifyAcc(sdk.Address(info.PubKey.Address().Bytes()))
if err != nil {
return KeyOutput{}, err
}
bechPubKey, err := sdk.Bech32ifyAccPub(info.PubKey)
if err != nil {
return KeyOutput{}, err
}
return KeyOutput{
Name: info.Name,
Address: bechAccount,
PubKey: bechPubKey,
}, nil
} }
func printInfo(info keys.Info) { func printInfo(info keys.Info) {
ko := NewKeyOutput(info) ko, err := Bech32KeyOutput(info)
if err != nil {
panic(err)
}
switch viper.Get(cli.OutputFlag) { switch viper.Get(cli.OutputFlag) {
case "text": case "text":
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
@ -84,7 +101,10 @@ func printInfo(info keys.Info) {
} }
func printInfos(infos []keys.Info) { func printInfos(infos []keys.Info) {
kos := NewKeyOutputs(infos) kos, err := Bech32KeysOutput(infos)
if err != nil {
panic(err)
}
switch viper.Get(cli.OutputFlag) { switch viper.Get(cli.OutputFlag) {
case "text": case "text":
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
@ -101,13 +121,5 @@ func printInfos(infos []keys.Info) {
} }
func printKeyOutput(ko KeyOutput) { func printKeyOutput(ko KeyOutput) {
bechAccount, err := sdk.Bech32ifyAcc(ko.Address) fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey)
if err != nil {
panic(err)
}
bechPubKey, err := sdk.Bech32ifyAccPub(ko.PubKey)
if err != nil {
panic(err)
}
fmt.Printf("%s\t%s\t%s\n", ko.Name, bechAccount, bechPubKey)
} }

View File

@ -33,6 +33,7 @@ import (
client "github.com/cosmos/cosmos-sdk/client" client "github.com/cosmos/cosmos-sdk/client"
keys "github.com/cosmos/cosmos-sdk/client/keys" keys "github.com/cosmos/cosmos-sdk/client/keys"
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app" gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server"
tests "github.com/cosmos/cosmos-sdk/tests" tests "github.com/cosmos/cosmos-sdk/tests"
@ -40,14 +41,17 @@ import (
"github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake"
stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
) )
var ( var (
coinDenom = "steak" coinDenom = "steak"
coinAmount = int64(10000000) coinAmount = int64(10000000)
validatorAddr1 = "" validatorAddr1Hx = ""
validatorAddr2 = "" validatorAddr2Hx = ""
validatorAddr1 = ""
validatorAddr2 = ""
// XXX bad globals // XXX bad globals
name = "test" name = "test"
@ -99,13 +103,13 @@ func TestKeys(t *testing.T) {
err = cdc.UnmarshalJSON([]byte(body), &m) err = cdc.UnmarshalJSON([]byte(body), &m)
require.Nil(t, err) require.Nil(t, err)
sendAddrAcc, _ := sdk.GetAccAddressHex(sendAddr)
addrAcc, _ := sdk.GetAccAddressHex(addr) addrAcc, _ := sdk.GetAccAddressHex(addr)
addrBech32, _ := sdk.Bech32ifyAcc(addrAcc)
assert.Equal(t, m[0].Name, name, "Did not serve keys name correctly") assert.Equal(t, name, m[0].Name, "Did not serve keys name correctly")
assert.Equal(t, m[0].Address, sendAddrAcc, "Did not serve keys Address correctly") assert.Equal(t, sendAddr, m[0].Address, "Did not serve keys Address correctly")
assert.Equal(t, m[1].Name, newName, "Did not serve keys name correctly") assert.Equal(t, newName, m[1].Name, "Did not serve keys name correctly")
assert.Equal(t, m[1].Address, addrAcc, "Did not serve keys Address correctly") assert.Equal(t, addrBech32, m[1].Address, "Did not serve keys Address correctly")
// select key // select key
keyEndpoint := fmt.Sprintf("/keys/%s", newName) keyEndpoint := fmt.Sprintf("/keys/%s", newName)
@ -116,7 +120,7 @@ func TestKeys(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly") assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
assert.Equal(t, addrAcc, m2.Address, "Did not serve keys Address correctly") assert.Equal(t, addrBech32, m2.Address, "Did not serve keys Address correctly")
// update key // update key
jsonStr = []byte(fmt.Sprintf(`{"old_password":"%s", "new_password":"12345678901"}`, newPassword)) jsonStr = []byte(fmt.Sprintf(`{"old_password":"%s", "new_password":"12345678901"}`, newPassword))
@ -198,7 +202,7 @@ func TestBlock(t *testing.T) {
func TestValidators(t *testing.T) { func TestValidators(t *testing.T) {
var resultVals ctypes.ResultValidators var resultVals rpc.ResultValidatorsOutput
res, body := request(t, port, "GET", "/validatorsets/latest", nil) res, body := request(t, port, "GET", "/validatorsets/latest", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -206,7 +210,10 @@ func TestValidators(t *testing.T) {
err := cdc.UnmarshalJSON([]byte(body), &resultVals) err := cdc.UnmarshalJSON([]byte(body), &resultVals)
require.Nil(t, err, "Couldn't parse validatorset") require.Nil(t, err, "Couldn't parse validatorset")
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals) assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
assert.Contains(t, resultVals.Validators[0].Address, "cosmosvaladdr")
assert.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub")
// -- // --
@ -216,7 +223,7 @@ func TestValidators(t *testing.T) {
err = cdc.UnmarshalJSON([]byte(body), &resultVals) err = cdc.UnmarshalJSON([]byte(body), &resultVals)
require.Nil(t, err, "Couldn't parse validatorset") require.Nil(t, err, "Couldn't parse validatorset")
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals) assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
// -- // --
@ -225,10 +232,11 @@ func TestValidators(t *testing.T) {
} }
func TestCoinSend(t *testing.T) { func TestCoinSend(t *testing.T) {
bz, _ := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6")
someFakeAddr, _ := sdk.Bech32ifyAcc(bz)
// query empty // query empty
//res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil) res, body := request(t, port, "GET", "/accounts/"+someFakeAddr, nil)
res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil)
require.Equal(t, http.StatusNoContent, res.StatusCode, body) require.Equal(t, http.StatusNoContent, res.StatusCode, body)
acc := getAccount(t, sendAddr) acc := getAccount(t, sendAddr)
@ -323,15 +331,14 @@ func TestValidatorsQuery(t *testing.T) {
// make sure all the validators were found (order unknown because sorted by owner addr) // make sure all the validators were found (order unknown because sorted by owner addr)
foundVal1, foundVal2 := false, false foundVal1, foundVal2 := false, false
res1, res2 := hex.EncodeToString(validators[0].Owner), hex.EncodeToString(validators[1].Owner) if validators[0].Owner == validatorAddr1 || validators[1].Owner == validatorAddr1 {
if res1 == validatorAddr1 || res2 == validatorAddr1 {
foundVal1 = true foundVal1 = true
} }
if res1 == validatorAddr2 || res2 == validatorAddr2 { if validators[0].Owner == validatorAddr2 || validators[1].Owner == validatorAddr2 {
foundVal2 = true foundVal2 = true
} }
assert.True(t, foundVal1, "validatorAddr1 %v, res1 %v, res2 %v", validatorAddr1, res1, res2) assert.True(t, foundVal1, "validatorAddr1 %v, owner1 %v, owner2 %v", validatorAddr1, validators[0].Owner, validators[1].Owner)
assert.True(t, foundVal2, "validatorAddr2 %v, res1 %v, res2 %v", validatorAddr2, res1, res2) assert.True(t, foundVal2, "validatorAddr2 %v, owner1 %v, owner2 %v", validatorAddr2, validators[0].Owner, validators[1].Owner)
} }
func TestBond(t *testing.T) { func TestBond(t *testing.T) {
@ -418,8 +425,10 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
pk1 := genDoc.Validators[0].PubKey pk1 := genDoc.Validators[0].PubKey
pk2 := genDoc.Validators[1].PubKey pk2 := genDoc.Validators[1].PubKey
validatorAddr1 = hex.EncodeToString(pk1.Address()) validatorAddr1Hx = hex.EncodeToString(pk1.Address())
validatorAddr2 = hex.EncodeToString(pk2.Address()) validatorAddr2Hx = hex.EncodeToString(pk2.Address())
validatorAddr1, _ = sdk.Bech32ifyVal(pk1.Address())
validatorAddr2, _ = sdk.Bech32ifyVal(pk2.Address())
// NOTE it's bad practice to reuse pk address for the owner address but doing in the // NOTE it's bad practice to reuse pk address for the owner address but doing in the
// test for simplicity // test for simplicity
@ -444,7 +453,8 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
sendAddr = info.PubKey.Address().String() // XXX global sendAddrHex, _ := sdk.GetAccAddressHex(info.PubKey.Address().String())
sendAddr, _ = sdk.Bech32ifyAcc(sendAddrHex) // XXX global
accAuth := auth.NewBaseAccountWithAddress(info.PubKey.Address()) accAuth := auth.NewBaseAccountWithAddress(info.PubKey.Address())
accAuth.Coins = sdk.Coins{{"steak", 100}} accAuth.Coins = sdk.Coins{{"steak", 100}}
acc := gapp.NewGenesisAccount(&accAuth) acc := gapp.NewGenesisAccount(&accAuth)
@ -548,7 +558,7 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
kb := client.MockKeyBase() kb := client.MockKeyBase()
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519")) receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
require.Nil(t, err) require.Nil(t, err)
receiveAddr = receiveInfo.PubKey.Address().String() receiveAddr, _ = sdk.Bech32ifyAcc(receiveInfo.PubKey.Address())
acc := getAccount(t, sendAddr) acc := getAccount(t, sendAddr)
sequence := acc.GetSequence() sequence := acc.GetSequence()
@ -565,12 +575,11 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
} }
func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
// create receive address // create receive address
kb := client.MockKeyBase() kb := client.MockKeyBase()
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519")) receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
require.Nil(t, err) require.Nil(t, err)
receiveAddr := receiveInfo.PubKey.Address().String() receiveAddr, _ := sdk.Bech32ifyAcc(receiveInfo.PubKey.Address())
// get the account to get the sequence // get the account to get the sequence
acc := getAccount(t, sendAddr) acc := getAccount(t, sendAddr)
@ -609,13 +618,13 @@ func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxC
"sequence": %d, "sequence": %d,
"delegate": [ "delegate": [
{ {
"delegator_addr": "%x", "delegator_addr": "%s",
"validator_addr": "%s", "validator_addr": "%s",
"bond": { "denom": "%s", "amount": 10 } "bond": { "denom": "%s", "amount": 10 }
} }
], ],
"unbond": [] "unbond": []
}`, name, password, sequence, acc.GetAddress(), validatorAddr1, coinDenom)) }`, name, password, sequence, sendAddr, validatorAddr1, coinDenom))
res, body := request(t, port, "POST", "/stake/delegations", jsonStr) res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -639,12 +648,12 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT
"bond": [], "bond": [],
"unbond": [ "unbond": [
{ {
"delegator_addr": "%x", "delegator_addr": "%s",
"validator_addr": "%s", "validator_addr": "%s",
"shares": "1" "shares": "1"
} }
] ]
}`, name, password, sequence, acc.GetAddress(), validatorAddr1)) }`, name, password, sequence, sendAddr, validatorAddr1))
res, body := request(t, port, "POST", "/stake/delegations", jsonStr) res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -655,11 +664,11 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT
return results[0] return results[0]
} }
func getValidators(t *testing.T) []stake.Validator { func getValidators(t *testing.T) []stakerest.StakeValidatorOutput {
// get the account to get the sequence // get the account to get the sequence
res, body := request(t, port, "GET", "/stake/validators", nil) res, body := request(t, port, "GET", "/stake/validators", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
var validators stake.Validators var validators []stakerest.StakeValidatorOutput
err := cdc.UnmarshalJSON([]byte(body), &validators) err := cdc.UnmarshalJSON([]byte(body), &validators)
require.Nil(t, err) require.Nil(t, err)
return validators return validators

View File

@ -10,6 +10,8 @@ import (
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
tmtypes "github.com/tendermint/tendermint/types"
) )
// TODO these next two functions feel kinda hacky based on their placement // TODO these next two functions feel kinda hacky based on their placement
@ -28,6 +30,38 @@ func ValidatorCommand() *cobra.Command {
return cmd return cmd
} }
// Validator output in bech32 format
type ValidatorOutput struct {
Address string `json:"address"` // in bech32
PubKey string `json:"pub_key"` // in bech32
Accum int64 `json:"accum"`
VotingPower int64 `json:"voting_power"`
}
// Validators at a certain height output in bech32 format
type ResultValidatorsOutput struct {
BlockHeight int64 `json:"block_height"`
Validators []ValidatorOutput `json:"validators"`
}
func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) {
bechAddress, err := sdk.Bech32ifyVal(validator.Address)
if err != nil {
return ValidatorOutput{}, err
}
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
if err != nil {
return ValidatorOutput{}, err
}
return ValidatorOutput{
Address: bechAddress,
PubKey: bechValPubkey,
Accum: validator.Accum,
VotingPower: validator.VotingPower,
}, nil
}
func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) { func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
// get the node // get the node
node, err := ctx.GetNode() node, err := ctx.GetNode()
@ -35,12 +69,23 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
return nil, err return nil, err
} }
res, err := node.Validators(height) validatorsRes, err := node.Validators(height)
if err != nil { if err != nil {
return nil, err return nil, err
} }
output, err := cdc.MarshalJSON(res) outputValidatorsRes := ResultValidatorsOutput{
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
}
for i := 0; i < len(validatorsRes.Validators); i++ {
outputValidatorsRes.Validators[i], err = bech32ValidatorOutput(validatorsRes.Validators[i])
if err != nil {
return nil, err
}
}
output, err := cdc.MarshalJSON(outputValidatorsRes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -96,6 +141,7 @@ func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
return return
} }
w.Write(output) w.Write(output)
} }
} }

View File

@ -170,7 +170,13 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.Address, crypto.PubKey)
var ko keys.KeyOutput var ko keys.KeyOutput
keys.UnmarshalJSON([]byte(out), &ko) keys.UnmarshalJSON([]byte(out), &ko)
return ko.Address, ko.PubKey address, err := sdk.GetAccAddressBech32(ko.Address)
require.NoError(t, err)
pk, err := sdk.GetAccPubKeyBech32(ko.PubKey)
require.NoError(t, err)
return address, pk
} }
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {

View File

@ -102,7 +102,7 @@ paths:
- application/json - application/json
responses: responses:
200: 200:
description: 12 word Seed description: 16 word Seed
schema: schema:
type: string type: string
/keys/{name}: /keys/{name}:
@ -204,7 +204,7 @@ paths:
parameters: parameters:
- in: path - in: path
name: address name: address
description: Account address description: Account address in bech32 format
required: true required: true
type: string type: string
get: get:
@ -222,7 +222,7 @@ paths:
parameters: parameters:
- in: path - in: path
name: address name: address
description: Account address description: Account address in bech32 format
required: true required: true
type: string type: string
post: post:
@ -255,18 +255,6 @@ paths:
description: Tx was send and will probably be added to the next block description: Tx was send and will probably be added to the next block
400: 400:
description: The Tx was malformated description: The Tx was malformated
/accounts/{address}/nonce:
parameters:
- in: path
name: address
description: Account address
required: true
type: string
get:
summary: Get the nonce for a certain account
responses:
200:
description: Plaintext nonce i.e. "4" defaults to "0"
/blocks/latest: /blocks/latest:
get: get:
summary: Get the latest block summary: Get the latest block
@ -304,9 +292,14 @@ paths:
200: 200:
description: The validator set at the latest block height description: The validator set at the latest block height
schema: schema:
type: array type: object
items: properties:
$ref: "#/definitions/Delegate" block_height:
type: number
validators:
type: array
items:
$ref: "#/definitions/Validator"
/validatorsets/{height}: /validatorsets/{height}:
parameters: parameters:
- in: path - in: path
@ -322,9 +315,14 @@ paths:
200: 200:
description: The validator set at a specific block height description: The validator set at a specific block height
schema: schema:
type: array type: object
items: properties:
$ref: "#/definitions/Delegate" block_height:
type: number
validators:
type: array
items:
$ref: "#/definitions/Validator"
404: 404:
description: Block at height not available description: Block at height not available
# /txs: # /txs:
@ -549,7 +547,20 @@ paths:
definitions: definitions:
Address: Address:
type: string type: string
example: DF096FDE8D380FA5B2AD20DB2962C82DDEA1ED9B description: bech32 encoded addres
example: cosmosaccaddr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
ValidatorAddress:
type: string
description: bech32 encoded addres
example: cosmosvaladdr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
PubKey:
type: string
description: bech32 encoded public key
example: cosmosaccpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
ValidatorPubKey:
type: string
description: bech32 encoded public key
example: cosmosvalpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
Coins: Coins:
type: object type: object
properties: properties:
@ -652,16 +663,6 @@ definitions:
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958 example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
Pubkey: Pubkey:
$ref: "#/definitions/PubKey" $ref: "#/definitions/PubKey"
PubKey:
type: object
properties:
type:
type: string
enum:
- ed25519
data:
type: string
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
Account: Account:
type: object type: object
properties: properties:
@ -753,17 +754,19 @@ definitions:
type: array type: array
items: items:
type: object type: object
Delegate: Validator:
type: object type: object
properties: properties:
address:
$ref: '#/definitions/ValidatorAddress'
pub_key: pub_key:
$ref: "#/definitions/PubKey" $ref: "#/definitions/ValidatorPubKey"
power: power:
type: number type: number
example: 1000 example: 1000
name: accum:
type: string type: number
example: "159.89.3.34" example: 1000
# Added by API Auto Mocking Plugin # Added by API Auto Mocking Plugin
host: virtserver.swaggerhub.com host: virtserver.swaggerhub.com
basePath: /faboweb1/Cosmos-LCD-2/1.0.0 basePath: /faboweb1/Cosmos-LCD-2/1.0.0

View File

@ -32,7 +32,7 @@ func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
} }
// Bech32ifyVal returns the bech32 encoded string for a validator address // Bech32ifyVal returns the bech32 encoded string for a validator address
func bech32ifyVal(addr Address) (string, error) { func Bech32ifyVal(addr Address) (string, error) {
return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes()) return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes())
} }
@ -62,6 +62,21 @@ func GetAccAddressBech32(address string) (addr Address, err error) {
return Address(bz), nil return Address(bz), nil
} }
// create a Pubkey from a string
func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) {
bz, err := getFromBech32(address, Bech32PrefixAccPub)
if err != nil {
return nil, err
}
pk, err = crypto.PubKeyFromBytes(bz)
if err != nil {
return nil, err
}
return pk, nil
}
// create an Address from a hex string // create an Address from a hex string
func GetValAddressHex(address string) (addr Address, err error) { func GetValAddressHex(address string) (addr Address, err error) {
if len(address) == 0 { if len(address) == 0 {

View File

@ -1,7 +1,6 @@
package rest package rest
import ( import (
"encoding/hex"
"fmt" "fmt"
"net/http" "net/http"
@ -26,17 +25,16 @@ func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, sto
func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc { func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
addr := vars["address"] bech32addr := vars["address"]
bz, err := hex.DecodeString(addr) addr, err := sdk.GetAccAddressBech32(bech32addr)
if err != nil { if err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
return return
} }
key := sdk.Address(bz)
res, err := ctx.Query(key, storeName) res, err := ctx.Query(addr, storeName)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error()))) w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error())))

View File

@ -41,7 +41,14 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// collect data // collect data
vars := mux.Vars(r) vars := mux.Vars(r)
address := vars["address"] bech32addr := vars["address"]
address, err := sdk.GetAccAddressBech32(bech32addr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
var m sendBody var m sendBody
body, err := ioutil.ReadAll(r.Body) body, err := ioutil.ReadAll(r.Body)
@ -64,7 +71,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont
return return
} }
to, err := sdk.GetAccAddressHex(address) to, err := sdk.GetAccAddressHex(address.String())
if err != nil { if err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))

View File

@ -35,7 +35,14 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
// collect data // collect data
vars := mux.Vars(r) vars := mux.Vars(r)
destChainID := vars["destchain"] destChainID := vars["destchain"]
address := vars["address"] bech32addr := vars["address"]
address, err := sdk.GetAccAddressBech32(bech32addr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
var m transferBody var m transferBody
body, err := ioutil.ReadAll(r.Body) body, err := ioutil.ReadAll(r.Body)
@ -58,7 +65,7 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
return return
} }
bz, err := hex.DecodeString(address) bz, err := hex.DecodeString(address.String())
if err != nil { if err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))

View File

@ -1,7 +1,6 @@
package rest package rest
import ( import (
"encoding/hex"
"fmt" "fmt"
"net/http" "net/http"
@ -30,24 +29,22 @@ func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire
// read parameters // read parameters
vars := mux.Vars(r) vars := mux.Vars(r)
delegator := vars["delegator"] bech32delegator := vars["delegator"]
validator := vars["validator"] bech32validator := vars["validator"]
bz, err := hex.DecodeString(delegator) delegatorAddr, err := sdk.GetAccAddressBech32(bech32delegator)
if err != nil { if err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
return return
} }
delegatorAddr := sdk.Address(bz)
bz, err = hex.DecodeString(validator) validatorAddr, err := sdk.GetValAddressBech32(bech32validator)
if err != nil { if err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
return return
} }
validatorAddr := sdk.Address(bz)
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
@ -83,6 +80,62 @@ func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire
} }
} }
// TODO inherit from Validator
type StakeValidatorOutput struct {
Owner string `json:"owner"` // in bech32
PubKey string `json:"pub_key"` // in bech32
Revoked bool `json:"revoked"` // has the validator been revoked from bonded status?
PoolShares stake.PoolShares `json:"pool_shares"` // total shares for tokens held in the pool
DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators
Description stake.Description `json:"description"` // description terms for the validator
BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator
BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change
ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer
Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators
CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge
CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission
CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time)
// fee related
PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools
}
func bech32StakeValidatorOutput(validator stake.Validator) (StakeValidatorOutput, error) {
bechOwner, err := sdk.Bech32ifyVal(validator.Owner)
if err != nil {
return StakeValidatorOutput{}, err
}
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
if err != nil {
return StakeValidatorOutput{}, err
}
return StakeValidatorOutput{
Owner: bechOwner,
PubKey: bechValPubkey,
Revoked: validator.Revoked,
PoolShares: validator.PoolShares,
DelegatorShares: validator.DelegatorShares,
Description: validator.Description,
BondHeight: validator.BondHeight,
BondIntraTxCounter: validator.BondIntraTxCounter,
ProposerRewardPool: validator.ProposerRewardPool,
Commission: validator.Commission,
CommissionMax: validator.CommissionMax,
CommissionChangeRate: validator.CommissionChangeRate,
CommissionChangeToday: validator.CommissionChangeToday,
PrevBondedShares: validator.PrevBondedShares,
}, nil
}
// TODO bech32
// http request handler to query list of validators // http request handler to query list of validators
func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
@ -100,16 +153,20 @@ func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Co
} }
// parse out the validators // parse out the validators
validators := make([]stake.Validator, len(kvs)) validators := make([]StakeValidatorOutput, len(kvs))
for i, kv := range kvs { for i, kv := range kvs {
var validator stake.Validator var validator stake.Validator
var bech32Validator StakeValidatorOutput
err = cdc.UnmarshalBinary(kv.Value, &validator) err = cdc.UnmarshalBinary(kv.Value, &validator)
if err == nil {
bech32Validator, err = bech32StakeValidatorOutput(validator)
}
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return return
} }
validators[i] = validator validators[i] = bech32Validator
} }
output, err := cdc.MarshalJSON(validators) output, err := cdc.MarshalJSON(validators)

View File

@ -3,6 +3,7 @@ package rest
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -23,13 +24,24 @@ func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, k
).Methods("POST") ).Methods("POST")
} }
type msgDelegateInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
Bond sdk.Coin `json:"bond"`
}
type msgUnbondInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
Shares string `json:"shares"`
}
type editDelegationsBody struct { type editDelegationsBody struct {
LocalAccountName string `json:"name"` LocalAccountName string `json:"name"`
Password string `json:"password"` Password string `json:"password"`
ChainID string `json:"chain_id"` ChainID string `json:"chain_id"`
Sequence int64 `json:"sequence"` Sequence int64 `json:"sequence"`
Delegate []stake.MsgDelegate `json:"delegate"` Delegate []msgDelegateInput `json:"delegate"`
Unbond []stake.MsgUnbond `json:"unbond"` Unbond []msgUnbondInput `json:"unbond"`
} }
func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
@ -59,21 +71,53 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
messages := make([]sdk.Msg, len(m.Delegate)+len(m.Unbond)) messages := make([]sdk.Msg, len(m.Delegate)+len(m.Unbond))
i := 0 i := 0
for _, msg := range m.Delegate { for _, msg := range m.Delegate {
if !bytes.Equal(info.Address(), msg.DelegatorAddr) { delegatorAddr, err := sdk.GetAccAddressBech32(msg.DelegatorAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
return
}
validatorAddr, err := sdk.GetValAddressBech32(msg.ValidatorAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
if !bytes.Equal(info.Address(), delegatorAddr) {
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Must use own delegator address")) w.Write([]byte("Must use own delegator address"))
return return
} }
messages[i] = msg messages[i] = stake.MsgDelegate{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
Bond: msg.Bond,
}
i++ i++
} }
for _, msg := range m.Unbond { for _, msg := range m.Unbond {
if !bytes.Equal(info.Address(), msg.DelegatorAddr) { delegatorAddr, err := sdk.GetAccAddressBech32(msg.DelegatorAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
return
}
validatorAddr, err := sdk.GetValAddressBech32(msg.ValidatorAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
if !bytes.Equal(info.Address(), delegatorAddr) {
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Must use own delegator address")) w.Write([]byte("Must use own delegator address"))
return return
} }
messages[i] = msg messages[i] = stake.MsgUnbond{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
Shares: msg.Shares,
}
i++ i++
} }