Merge PR #3674: Remove password/keybase from REST Client
This commit is contained in:
parent
6967de1073
commit
e39debd359
@ -6,6 +6,11 @@
|
||||
|
||||
### Gaia REST API
|
||||
|
||||
* [\#3641] Remove the ability to use a Keybase from the REST API client:
|
||||
* `password` and `generate_only` have been removed from the `base_req` object
|
||||
* All txs that used to sign or use the Keybase now only generate the tx
|
||||
* `keys` routes completely removed
|
||||
|
||||
### Gaia CLI
|
||||
|
||||
### Gaia
|
||||
|
||||
@ -2,10 +2,7 @@ package keys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
@ -13,15 +10,13 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/go-bip39"
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/multisig"
|
||||
@ -304,191 +299,3 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// REST
|
||||
|
||||
// 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 := keys.NewInMemory()
|
||||
pass := app.DefaultKeyPass
|
||||
name := "inmemorykey"
|
||||
_, seed, _ := kb.CreateMnemonic(name, keys.English, pass, algo)
|
||||
return seed
|
||||
}
|
||||
|
||||
// CheckAndWriteErrorResponse will check for errors and return
|
||||
// a given error message when corresponding
|
||||
//TODO: Move to utils/rest or similar
|
||||
func CheckAndWriteErrorResponse(w http.ResponseWriter, httpErr int, err error) bool {
|
||||
if err != nil {
|
||||
w.WriteHeader(httpErr)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// add new key REST handler
|
||||
func AddNewKeyRequestHandler(indent bool) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var kb keys.Keybase
|
||||
var m AddNewKey
|
||||
|
||||
kb, err := NewKeyBaseFromHomeFlag()
|
||||
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) {
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &m)
|
||||
if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check parameters
|
||||
if m.Name == "" {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName())
|
||||
return
|
||||
}
|
||||
if m.Password == "" {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword())
|
||||
return
|
||||
}
|
||||
|
||||
mnemonic := m.Mnemonic
|
||||
// if mnemonic is empty, generate one
|
||||
if mnemonic == "" {
|
||||
mnemonic = generateMnemonic(keys.Secp256k1)
|
||||
}
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic())
|
||||
}
|
||||
|
||||
if m.Account < 0 || m.Account > maxValidAccountValue {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber())
|
||||
return
|
||||
}
|
||||
|
||||
if m.Index < 0 || m.Index > maxValidIndexalue {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = kb.Get(m.Name)
|
||||
if err == nil {
|
||||
CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(m.Name))
|
||||
return
|
||||
}
|
||||
|
||||
// create account
|
||||
account := uint32(m.Account)
|
||||
index := uint32(m.Index)
|
||||
info, err := kb.CreateAccount(m.Name, mnemonic, keys.DefaultBIP39Passphrase, m.Password, account, index)
|
||||
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
|
||||
return
|
||||
}
|
||||
|
||||
keyOutput, err := Bech32KeyOutput(info)
|
||||
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
|
||||
return
|
||||
}
|
||||
|
||||
keyOutput.Mnemonic = mnemonic
|
||||
|
||||
rest.PostProcessResponse(w, cdc, keyOutput, indent)
|
||||
}
|
||||
}
|
||||
|
||||
// Seed REST request handler
|
||||
func SeedRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
algoType := vars["type"]
|
||||
|
||||
// algo type defaults to secp256k1
|
||||
if algoType == "" {
|
||||
algoType = "secp256k1"
|
||||
}
|
||||
|
||||
algo := keys.SigningAlgo(algoType)
|
||||
seed := generateMnemonic(algo)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(seed))
|
||||
}
|
||||
|
||||
// RecoverRequestHandler performs key recover request
|
||||
func RecoverRequestHandler(indent bool) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
var m RecoverKey
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) {
|
||||
return
|
||||
}
|
||||
|
||||
err = cdc.UnmarshalJSON(body, &m)
|
||||
if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) {
|
||||
return
|
||||
}
|
||||
|
||||
kb, err := NewKeyBaseFromHomeFlag()
|
||||
CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err)
|
||||
|
||||
if name == "" {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName())
|
||||
return
|
||||
}
|
||||
if m.Password == "" {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword())
|
||||
return
|
||||
}
|
||||
|
||||
mnemonic := m.Mnemonic
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic())
|
||||
}
|
||||
|
||||
if m.Mnemonic == "" {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingMnemonic())
|
||||
return
|
||||
}
|
||||
|
||||
if m.Account < 0 || m.Account > maxValidAccountValue {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber())
|
||||
return
|
||||
}
|
||||
|
||||
if m.Index < 0 || m.Index > maxValidIndexalue {
|
||||
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = kb.Get(name)
|
||||
if err == nil {
|
||||
CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(name))
|
||||
return
|
||||
}
|
||||
|
||||
account := uint32(m.Account)
|
||||
index := uint32(m.Index)
|
||||
|
||||
info, err := kb.CreateAccount(name, mnemonic, keys.DefaultBIP39Passphrase, m.Password, account, index)
|
||||
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
|
||||
return
|
||||
}
|
||||
|
||||
keyOutput, err := Bech32KeyOutput(info)
|
||||
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
|
||||
return
|
||||
}
|
||||
|
||||
rest.PostProcessResponse(w, cdc, keyOutput, indent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,13 +2,9 @@ package keys
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
@ -61,39 +57,3 @@ func Test_runAddCmdBasic(t *testing.T) {
|
||||
err = runAddCmd(cmd, []string{"keyname2"})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
type MockResponseWriter struct {
|
||||
dataHeaderStatus int
|
||||
dataBody []byte
|
||||
}
|
||||
|
||||
func (MockResponseWriter) Header() http.Header {
|
||||
panic("Unexpected call!")
|
||||
}
|
||||
|
||||
func (w *MockResponseWriter) Write(data []byte) (int, error) {
|
||||
w.dataBody = append(w.dataBody, data...)
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func (w *MockResponseWriter) WriteHeader(statusCode int) {
|
||||
w.dataHeaderStatus = statusCode
|
||||
}
|
||||
|
||||
func TestCheckAndWriteErrorResponse(t *testing.T) {
|
||||
mockRW := MockResponseWriter{}
|
||||
|
||||
mockRW.WriteHeader(100)
|
||||
assert.Equal(t, 100, mockRW.dataHeaderStatus)
|
||||
|
||||
detected := CheckAndWriteErrorResponse(&mockRW, http.StatusBadRequest, errors.New("some ERROR"))
|
||||
require.True(t, detected)
|
||||
require.Equal(t, http.StatusBadRequest, mockRW.dataHeaderStatus)
|
||||
require.Equal(t, "some ERROR", string(mockRW.dataBody[:]))
|
||||
|
||||
mockRW = MockResponseWriter{}
|
||||
detected = CheckAndWriteErrorResponse(&mockRW, http.StatusBadRequest, nil)
|
||||
require.False(t, detected)
|
||||
require.Equal(t, 0, mockRW.dataHeaderStatus)
|
||||
require.Equal(t, "", string(mockRW.dataBody[:]))
|
||||
}
|
||||
|
||||
@ -2,19 +2,14 @@ package keys
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -101,51 +96,3 @@ func confirmDeletion(buf *bufio.Reader) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// REST
|
||||
|
||||
// delete key request REST body
|
||||
type DeleteKeyBody struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// delete key REST handler
|
||||
func DeleteKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
var kb keys.Keybase
|
||||
var m DeleteKeyBody
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&m)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
kb, err = NewKeyBaseFromHomeFlag()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
err = kb.Delete(name, m.Password, false)
|
||||
if keyerror.IsErrKeyNotFound(err) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
} else if keyerror.IsErrWrongPassword(err) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
} else if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -29,36 +26,3 @@ func runListCmd(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// REST
|
||||
|
||||
// query key list REST handler
|
||||
func QueryKeysRequestHandler(indent bool) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
kb, err := NewKeyBaseFromHomeFlag()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
infos, err := kb.List()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
// an empty list will be JSONized as null, but we want to keep the empty list
|
||||
if len(infos) == 0 {
|
||||
rest.PostProcessResponse(w, cdc, []string{}, indent)
|
||||
return
|
||||
}
|
||||
keysOutput, err := Bech32KeysOutput(infos)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
rest.PostProcessResponse(w, cdc, keysOutput, indent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
@ -30,14 +29,3 @@ func Commands() *cobra.Command {
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// resgister REST routes
|
||||
func RegisterRoutes(r *mux.Router, indent bool) {
|
||||
r.HandleFunc("/keys", QueryKeysRequestHandler(indent)).Methods("GET")
|
||||
r.HandleFunc("/keys", AddNewKeyRequestHandler(indent)).Methods("POST")
|
||||
r.HandleFunc("/keys/seed", SeedRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/keys/{name}/recover", RecoverRequestHandler(indent)).Methods("POST")
|
||||
r.HandleFunc("/keys/{name}", GetKeyRequestHandler(indent)).Methods("GET")
|
||||
r.HandleFunc("/keys/{name}", UpdateKeyRequestHandler).Methods("PUT")
|
||||
r.HandleFunc("/keys/{name}", DeleteKeyRequestHandler).Methods("DELETE")
|
||||
}
|
||||
|
||||
@ -4,8 +4,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func TestCommands(t *testing.T) {
|
||||
@ -15,8 +13,3 @@ func TestCommands(t *testing.T) {
|
||||
// Commands are registered
|
||||
assert.Equal(t, 7, len(rootCommands.Commands()))
|
||||
}
|
||||
|
||||
func TestRegisterRoutes(t *testing.T) {
|
||||
fakeRouter := mux.Router{}
|
||||
RegisterRoutes(&fakeRouter, false)
|
||||
}
|
||||
|
||||
@ -2,22 +2,18 @@ package keys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/crypto/multisig"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@ -149,46 +145,3 @@ func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
|
||||
|
||||
return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix)
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// REST
|
||||
|
||||
// get key REST handler
|
||||
func GetKeyRequestHandler(indent bool) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
bechPrefix := r.URL.Query().Get(FlagBechPrefix)
|
||||
|
||||
if bechPrefix == "" {
|
||||
bechPrefix = sdk.PrefixAccount
|
||||
}
|
||||
|
||||
bechKeyOut, err := getBechKeyOut(bechPrefix)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
info, err := GetKeyInfo(name)
|
||||
if keyerror.IsErrKeyNotFound(err) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
} else if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
keyOutput, err := bechKeyOut(info)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
rest.PostProcessResponse(w, cdc, keyOutput, indent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,11 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||
)
|
||||
|
||||
func updateKeyCommand() *cobra.Command {
|
||||
@ -52,55 +45,3 @@ func runUpdateCmd(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println("Password successfully updated!")
|
||||
return nil
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// REST
|
||||
|
||||
// update key request REST body
|
||||
type UpdateKeyBody struct {
|
||||
NewPassword string `json:"new_password"`
|
||||
OldPassword string `json:"old_password"`
|
||||
}
|
||||
|
||||
// update key REST handler
|
||||
func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
var kb keys.Keybase
|
||||
var m UpdateKeyBody
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&m)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
kb, err = NewKeyBaseFromHomeFlag()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
getNewpass := func() (string, error) { return m.NewPassword, nil }
|
||||
|
||||
err = kb.Update(name, m.OldPassword, getNewpass)
|
||||
if keyerror.IsErrKeyNotFound(err) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
} else if keyerror.IsErrWrongPassword(err) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
} else if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
@ -23,7 +22,6 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
dclcommon "github.com/cosmos/cosmos-sdk/x/distribution/client/common"
|
||||
distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
|
||||
@ -48,119 +46,6 @@ func init() {
|
||||
version.Version = os.Getenv("VERSION")
|
||||
}
|
||||
|
||||
func TestSeedsAreDifferent(t *testing.T) {
|
||||
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
|
||||
require.NoError(t, err)
|
||||
addr, _ := CreateAddr(t, name1, pw, kb)
|
||||
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true)
|
||||
defer cleanup()
|
||||
|
||||
mnemonic1 := getKeysSeed(t, port)
|
||||
mnemonic2 := getKeysSeed(t, port)
|
||||
|
||||
require.NotEqual(t, mnemonic1, mnemonic2)
|
||||
}
|
||||
|
||||
func TestKeyRecover(t *testing.T) {
|
||||
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
|
||||
require.NoError(t, err)
|
||||
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true)
|
||||
defer cleanup()
|
||||
|
||||
myName1 := "TestKeyRecover_1"
|
||||
myName2 := "TestKeyRecover_2"
|
||||
|
||||
mnemonic := getKeysSeed(t, port)
|
||||
expectedInfo, _ := kb.CreateAccount(myName1, mnemonic, "", pw, 0, 0)
|
||||
expectedAddress := expectedInfo.GetAddress().String()
|
||||
expectedPubKey := sdk.MustBech32ifyAccPub(expectedInfo.GetPubKey())
|
||||
|
||||
// recover key
|
||||
doRecoverKey(t, port, myName2, pw, mnemonic, 0, 0)
|
||||
|
||||
keys := getKeys(t, port)
|
||||
|
||||
require.Equal(t, expectedAddress, keys[0].Address)
|
||||
require.Equal(t, expectedPubKey, keys[0].PubKey)
|
||||
}
|
||||
|
||||
func TestKeyRecoverHDPath(t *testing.T) {
|
||||
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
|
||||
require.NoError(t, err)
|
||||
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true)
|
||||
defer cleanup()
|
||||
|
||||
mnemonic := getKeysSeed(t, port)
|
||||
|
||||
for account := uint32(0); account < 50; account += 13 {
|
||||
for index := uint32(0); index < 50; index += 15 {
|
||||
name1Idx := fmt.Sprintf("name1_%d_%d", account, index)
|
||||
name2Idx := fmt.Sprintf("name2_%d_%d", account, index)
|
||||
|
||||
expectedInfo, _ := kb.CreateAccount(name1Idx, mnemonic, "", pw, account, index)
|
||||
expectedAddress := expectedInfo.GetAddress().String()
|
||||
expectedPubKey := sdk.MustBech32ifyAccPub(expectedInfo.GetPubKey())
|
||||
|
||||
// recover key
|
||||
doRecoverKey(t, port, name2Idx, pw, mnemonic, account, index)
|
||||
|
||||
keysName2Idx := getKey(t, port, name2Idx)
|
||||
|
||||
require.Equal(t, expectedAddress, keysName2Idx.Address)
|
||||
require.Equal(t, expectedPubKey, keysName2Idx.PubKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeys(t *testing.T) {
|
||||
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
|
||||
require.NoError(t, err)
|
||||
addr1, _ := CreateAddr(t, name1, pw, kb)
|
||||
addr1Bech32 := addr1.String()
|
||||
|
||||
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr1}, true)
|
||||
defer cleanup()
|
||||
|
||||
// get new seed & recover key
|
||||
mnemonic2 := getKeysSeed(t, port)
|
||||
doRecoverKey(t, port, name2, pw, mnemonic2, 0, 0)
|
||||
|
||||
// add key
|
||||
mnemonic3 := mnemonic2
|
||||
resp := doKeysPost(t, port, name3, pw, mnemonic3, 0, 0)
|
||||
|
||||
addr3Bech32 := resp.Address
|
||||
_, err = sdk.AccAddressFromBech32(addr3Bech32)
|
||||
require.NoError(t, err, "Failed to return a correct bech32 address")
|
||||
|
||||
// test if created account is the correct account
|
||||
expectedInfo3, _ := kb.CreateAccount(name3, mnemonic3, "", pw, 0, 0)
|
||||
expectedAddress3 := sdk.AccAddress(expectedInfo3.GetPubKey().Address()).String()
|
||||
require.Equal(t, expectedAddress3, addr3Bech32)
|
||||
|
||||
// existing keys
|
||||
require.Equal(t, name1, getKey(t, port, name1).Name, "Did not serve keys name correctly")
|
||||
require.Equal(t, addr1Bech32, getKey(t, port, name1).Address, "Did not serve keys Address correctly")
|
||||
require.Equal(t, name2, getKey(t, port, name2).Name, "Did not serve keys name correctly")
|
||||
require.Equal(t, addr3Bech32, getKey(t, port, name2).Address, "Did not serve keys Address correctly")
|
||||
require.Equal(t, name3, getKey(t, port, name3).Name, "Did not serve keys name correctly")
|
||||
require.Equal(t, addr3Bech32, getKey(t, port, name3).Address, "Did not serve keys Address correctly")
|
||||
|
||||
// select key
|
||||
key := getKey(t, port, name3)
|
||||
require.Equal(t, name3, key.Name, "Did not serve keys name correctly")
|
||||
require.Equal(t, addr3Bech32, key.Address, "Did not serve keys Address correctly")
|
||||
|
||||
// update key
|
||||
updateKey(t, port, name3, pw, altPw, false)
|
||||
|
||||
// here it should say unauthorized as we changed the password before
|
||||
updateKey(t, port, name3, pw, altPw, true)
|
||||
|
||||
// delete key
|
||||
deleteKey(t, port, name3, altPw)
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
// skip the test if the VERSION environment variable has not been set
|
||||
if version.Version == "" {
|
||||
@ -255,7 +140,7 @@ func TestCoinSend(t *testing.T) {
|
||||
require.Equal(t, int64(1), coins2[0].Amount.Int64())
|
||||
|
||||
// test failure with too little gas
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "100", 0, false, false, fees)
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "100", 0, false, true, fees)
|
||||
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
|
||||
require.Nil(t, err)
|
||||
|
||||
@ -268,11 +153,11 @@ func TestCoinSend(t *testing.T) {
|
||||
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
|
||||
|
||||
// test failure with 0 gas
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "0", 0, false, false, fees)
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "0", 0, false, true, fees)
|
||||
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
|
||||
|
||||
// test failure with wrong adjustment
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, client.GasFlagAuto, 0.1, false, false, fees)
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, client.GasFlagAuto, 0.1, false, true, fees)
|
||||
|
||||
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
|
||||
|
||||
@ -291,7 +176,7 @@ func TestCoinSend(t *testing.T) {
|
||||
|
||||
// run successful tx
|
||||
gas := fmt.Sprintf("%d", gasEstResp.GasEstimate)
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, gas, 1.0, false, false, fees)
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, gas, 1.0, false, true, fees)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
|
||||
@ -316,7 +201,9 @@ func TestCoinSendAccAuto(t *testing.T) {
|
||||
initialBalance := acc.GetCoins()
|
||||
|
||||
// send a transfer tx without specifying account number and sequence
|
||||
res, body, _ := doTransferWithGasAccAuto(t, port, seed, name1, memo, pw, "200000", 1.0, false, false, fees)
|
||||
res, body, _ := doTransferWithGasAccAuto(
|
||||
t, port, seed, name1, memo, pw, addr, "200000", 1.0, false, true, fees,
|
||||
)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
// query sender
|
||||
@ -336,7 +223,7 @@ func TestCoinMultiSendGenerateOnly(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
// generate only
|
||||
res, body, _ := doTransferWithGas(t, port, seed, "", memo, "", addr, "200000", 1, false, true, fees)
|
||||
res, body, _ := doTransferWithGas(t, port, seed, "", memo, "", addr, "200000", 1, false, false, fees)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var stdTx auth.StdTx
|
||||
@ -356,6 +243,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
addr, seed := CreateAddr(t, name1, pw, kb)
|
||||
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true)
|
||||
|
||||
defer cleanup()
|
||||
acc := getAccount(t, port, addr)
|
||||
|
||||
@ -371,74 +259,40 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
|
||||
|
||||
// generate tx
|
||||
gas := fmt.Sprintf("%d", gasEstResp.GasEstimate)
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, "", addr, gas, 1, false, true, fees)
|
||||
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, "", addr, gas, 1, false, false, fees)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var msg auth.StdTx
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &msg))
|
||||
require.Equal(t, len(msg.Msgs), 1)
|
||||
require.Equal(t, msg.Msgs[0].Route(), "bank")
|
||||
require.Equal(t, msg.Msgs[0].GetSigners(), []sdk.AccAddress{addr})
|
||||
require.Equal(t, 0, len(msg.Signatures))
|
||||
require.Equal(t, memo, msg.Memo)
|
||||
require.NotZero(t, msg.Fee.Gas)
|
||||
var tx auth.StdTx
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &tx))
|
||||
require.Equal(t, len(tx.Msgs), 1)
|
||||
require.Equal(t, tx.Msgs[0].Route(), "bank")
|
||||
require.Equal(t, tx.Msgs[0].GetSigners(), []sdk.AccAddress{addr})
|
||||
require.Equal(t, 0, len(tx.Signatures))
|
||||
require.Equal(t, memo, tx.Memo)
|
||||
require.NotZero(t, tx.Fee.Gas)
|
||||
|
||||
gasEstimate := int64(msg.Fee.Gas)
|
||||
accnum := acc.GetAccountNumber()
|
||||
sequence := acc.GetSequence()
|
||||
|
||||
// sign tx
|
||||
var signedMsg auth.StdTx
|
||||
|
||||
payload := authrest.SignBody{
|
||||
Tx: msg,
|
||||
BaseReq: rest.NewBaseReq(
|
||||
name1, pw, "", viper.GetString(client.FlagChainID), "", "",
|
||||
accnum, sequence, nil, nil, false, false,
|
||||
),
|
||||
}
|
||||
json, err := cdc.MarshalJSON(payload)
|
||||
require.Nil(t, err)
|
||||
|
||||
res, body = Request(t, port, "POST", "/tx/sign", json)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &signedMsg))
|
||||
require.Equal(t, len(msg.Msgs), len(signedMsg.Msgs))
|
||||
require.Equal(t, msg.Msgs[0].Type(), signedMsg.Msgs[0].Type())
|
||||
require.Equal(t, msg.Msgs[0].GetSigners(), signedMsg.Msgs[0].GetSigners())
|
||||
require.Equal(t, 1, len(signedMsg.Signatures))
|
||||
|
||||
// broadcast tx
|
||||
broadcastPayload := struct {
|
||||
Tx auth.StdTx `json:"tx"`
|
||||
Return string `json:"return"`
|
||||
}{Tx: signedMsg, Return: "block"}
|
||||
json, err = cdc.MarshalJSON(broadcastPayload)
|
||||
require.Nil(t, err)
|
||||
res, body = Request(t, port, "POST", "/tx/broadcast", json)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
gasEstimate := int64(tx.Fee.Gas)
|
||||
_, body = signAndBroadcastGenTx(t, port, name1, pw, body, acc, 1.0, false)
|
||||
|
||||
// check if tx was committed
|
||||
var resultTx sdk.TxResponse
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &resultTx))
|
||||
require.Equal(t, uint32(0), resultTx.Code)
|
||||
require.Equal(t, gasEstimate, resultTx.GasWanted)
|
||||
var txResp sdk.TxResponse
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &txResp))
|
||||
require.Equal(t, uint32(0), txResp.Code)
|
||||
require.Equal(t, gasEstimate, txResp.GasWanted)
|
||||
}
|
||||
|
||||
func TestEncodeTx(t *testing.T) {
|
||||
// Setup
|
||||
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
|
||||
require.NoError(t, err)
|
||||
addr, seed := CreateAddr(t, name1, pw, kb)
|
||||
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true)
|
||||
defer cleanup()
|
||||
|
||||
// Make a transaction to test with
|
||||
res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, "2", 1, false, true, fees)
|
||||
res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, "2", 1, false, false, fees)
|
||||
var tx auth.StdTx
|
||||
cdc.UnmarshalJSON([]byte(body), &tx)
|
||||
|
||||
// Build the request
|
||||
// build the request
|
||||
encodeReq := struct {
|
||||
Tx auth.StdTx `json:"tx"`
|
||||
}{Tx: tx}
|
||||
@ -446,20 +300,19 @@ func TestEncodeTx(t *testing.T) {
|
||||
res, body = Request(t, port, "POST", "/tx/encode", encodedJSON)
|
||||
|
||||
// Make sure it came back ok, and that we can decode it back to the transaction
|
||||
// 200 response
|
||||
// 200 response.
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
encodeResp := struct {
|
||||
Tx string `json:"tx"`
|
||||
}{}
|
||||
|
||||
// No error decoding the JSON
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &encodeResp))
|
||||
|
||||
// Check that the base64 decodes
|
||||
// verify that the base64 decodes
|
||||
decodedBytes, err := base64.StdEncoding.DecodeString(encodeResp.Tx)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Check that the transaction decodes as expected
|
||||
// check that the transaction decodes as expected
|
||||
var decodedTx auth.StdTx
|
||||
require.Nil(t, cdc.UnmarshalBinaryLengthPrefixed(decodedBytes, &decodedTx))
|
||||
require.Equal(t, memo, decodedTx.Memo)
|
||||
|
||||
253
client/lcd/swagger-ui/swagger.yaml
vendored
253
client/lcd/swagger-ui/swagger.yaml
vendored
@ -3,14 +3,12 @@ swagger: "2.0"
|
||||
info:
|
||||
version: "3.0"
|
||||
title: Gaia-Lite for Cosmos
|
||||
description: A REST interface for state queries, transaction generation, signing, and broadcast.
|
||||
description: A REST interface for state queries, transaction generation and broadcasting.
|
||||
tags:
|
||||
- name: ICS0
|
||||
description: Tendermint APIs, such as query blocks, transactions and validatorset
|
||||
- name: ICS1
|
||||
description: Key management APIs
|
||||
- name: ICS20
|
||||
description: Create, sign and broadcast transactions
|
||||
description: Create and broadcast transactions
|
||||
- name: ICS21
|
||||
description: Stake module APIs
|
||||
- name: ICS22
|
||||
@ -269,42 +267,6 @@ paths:
|
||||
$ref: "#/definitions/BroadcastTxCommitResult"
|
||||
500:
|
||||
description: Internal Server Error
|
||||
/tx/sign:
|
||||
post:
|
||||
tags:
|
||||
- ICS20
|
||||
summary: Sign a Tx
|
||||
description: Sign a Tx providing locally stored account and according password
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: body
|
||||
name: sendToken
|
||||
description: sign tx
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
base_req:
|
||||
$ref: "#/definitions/BaseReq"
|
||||
tx:
|
||||
$ref: "#/definitions/StdTx"
|
||||
append_sig:
|
||||
type: boolean
|
||||
example: true
|
||||
responses:
|
||||
200:
|
||||
description: The signed Tx
|
||||
schema:
|
||||
$ref: "#/definitions/StdTx"
|
||||
400:
|
||||
description: The Tx was malformated or key doesn't exist
|
||||
401:
|
||||
description: Key password is wrong
|
||||
500:
|
||||
description: Server internal error
|
||||
/tx/broadcast:
|
||||
post:
|
||||
tags:
|
||||
@ -393,8 +355,7 @@ paths:
|
||||
description: Server internal error
|
||||
/bank/accounts/{address}/transfers:
|
||||
post:
|
||||
summary: Send coins (build -> sign -> send)
|
||||
description: Send coins (build -> sign -> send)
|
||||
summary: Send coins from one account to another
|
||||
tags:
|
||||
- ICS20
|
||||
consumes:
|
||||
@ -409,7 +370,7 @@ paths:
|
||||
type: string
|
||||
- in: body
|
||||
name: account
|
||||
description: The password of the account to remove from the KMS
|
||||
description: The sender and tx information
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
@ -422,188 +383,13 @@ paths:
|
||||
$ref: "#/definitions/Coin"
|
||||
responses:
|
||||
202:
|
||||
description: Tx was send and will probably be added to the next block
|
||||
description: Tx was succesfully generated
|
||||
schema:
|
||||
$ref: "#/definitions/BroadcastTxCommitResult"
|
||||
$ref: "#/definitions/StdTx"
|
||||
400:
|
||||
description: Invalid request
|
||||
401:
|
||||
description: Key password is wrong
|
||||
500:
|
||||
description: Server internal error
|
||||
/keys:
|
||||
get:
|
||||
summary: List of accounts stored locally
|
||||
tags:
|
||||
- ICS1
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
200:
|
||||
description: Array of accounts
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/KeyOutput"
|
||||
500:
|
||||
description: Server internal error
|
||||
post:
|
||||
summary: Create a new account locally
|
||||
tags:
|
||||
- ICS1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: body
|
||||
name: account
|
||||
description: The account to create
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- password
|
||||
- seed
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
seed:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Returns account information of the created key
|
||||
schema:
|
||||
$ref: "#/definitions/KeyOutput"
|
||||
400:
|
||||
description: Invalid request
|
||||
409:
|
||||
description: Key name confliction
|
||||
500:
|
||||
description: Server internal error
|
||||
/keys/seed:
|
||||
get:
|
||||
summary: Create a new seed to create a new account with
|
||||
tags:
|
||||
- ICS1
|
||||
responses:
|
||||
200:
|
||||
description: 24 word Seed
|
||||
schema:
|
||||
type: string
|
||||
example: blossom pool issue kidney elevator blame furnace winter account merry vessel security depend exact travel bargain problem jelly rural net again mask roast chest
|
||||
/keys/{name}/recover:
|
||||
post:
|
||||
summary: Recover a account from a seed
|
||||
tags:
|
||||
- ICS1
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: path
|
||||
name: name
|
||||
description: Account name
|
||||
required: true
|
||||
type: string
|
||||
- in: body
|
||||
name: pwdAndSeed
|
||||
description: Provide password and seed to recover a key
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- password
|
||||
- seed
|
||||
properties:
|
||||
password:
|
||||
type: string
|
||||
seed:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Returns account information of the recovered key
|
||||
schema:
|
||||
$ref: "#/definitions/KeyOutput"
|
||||
400:
|
||||
description: Invalid request
|
||||
409:
|
||||
description: Key name confliction
|
||||
500:
|
||||
description: Server internal error
|
||||
/keys/{name}:
|
||||
parameters:
|
||||
- in: path
|
||||
name: name
|
||||
description: Account name
|
||||
required: true
|
||||
type: string
|
||||
get:
|
||||
summary: Get a certain locally stored account
|
||||
tags:
|
||||
- ICS1
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
200:
|
||||
description: Locally stored account
|
||||
schema:
|
||||
$ref: "#/definitions/KeyOutput"
|
||||
404:
|
||||
description: Key doesn't exist
|
||||
put:
|
||||
summary: Update the password for this account in the KMS
|
||||
tags:
|
||||
- ICS1
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: body
|
||||
name: account
|
||||
description: The new and old password
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- new_password
|
||||
- old_password
|
||||
properties:
|
||||
new_password:
|
||||
type: string
|
||||
old_password:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Updated password
|
||||
401:
|
||||
description: Key password is wrong
|
||||
404:
|
||||
description: Key doesn't exist
|
||||
delete:
|
||||
summary: Remove an account
|
||||
tags:
|
||||
- ICS1
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: body
|
||||
name: account
|
||||
description: The password of the account to remove from the KMS
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- password
|
||||
properties:
|
||||
password:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Removed account
|
||||
401:
|
||||
description: Key password is wrong
|
||||
404:
|
||||
description: Key doesn't exist
|
||||
/auth/accounts/{address}:
|
||||
get:
|
||||
summary: Get the account information on blockchain
|
||||
@ -861,7 +647,7 @@ paths:
|
||||
parameters:
|
||||
- in: body
|
||||
name: delegation
|
||||
description: The password of the account to remove from the KMS
|
||||
description: The sender and tx information
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
@ -884,13 +670,11 @@ paths:
|
||||
- application/json
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
description: Tx was succesfully generated
|
||||
schema:
|
||||
$ref: "#/definitions/BroadcastTxCommitResult"
|
||||
$ref: "#/definitions/StdTx"
|
||||
400:
|
||||
description: Invalid delegator address or redelegation request body
|
||||
401:
|
||||
description: Key password is wrong
|
||||
500:
|
||||
description: Internal Server Error
|
||||
/staking/delegators/{delegatorAddr}/validators:
|
||||
@ -1170,16 +954,14 @@ paths:
|
||||
type: object
|
||||
properties:
|
||||
base_req:
|
||||
$ref: "#/definitions/BaseReq"
|
||||
$ref: "#/definitions/StdTx"
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
description: Tx was succesfully generated
|
||||
schema:
|
||||
$ref: "#/definitions/BroadcastTxCommitResult"
|
||||
400:
|
||||
description: Invalid validator address or base_req
|
||||
401:
|
||||
description: Key password is wrong
|
||||
500:
|
||||
description: Internal Server Error
|
||||
/slashing/parameters:
|
||||
@ -1246,13 +1028,11 @@ paths:
|
||||
$ref: "#/definitions/Coin"
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
description: Tx was succesfully generated
|
||||
schema:
|
||||
$ref: "#/definitions/BroadcastTxCommitResult"
|
||||
$ref: "#/definitions/StdTx"
|
||||
400:
|
||||
description: Invalid proposal body
|
||||
401:
|
||||
description: Key password is wrong
|
||||
500:
|
||||
description: Internal Server Error
|
||||
get:
|
||||
@ -2189,9 +1969,6 @@ definitions:
|
||||
type: string
|
||||
example: "cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc"
|
||||
description: Sender address or Keybase name to generate a transaction
|
||||
password:
|
||||
type: string
|
||||
example: "12345678"
|
||||
memo:
|
||||
type: string
|
||||
example: "Sent via Cosmos Voyager 🚀"
|
||||
@ -2214,10 +1991,6 @@ definitions:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Coin"
|
||||
generate_only:
|
||||
type: boolean
|
||||
example: false
|
||||
description: Create a JSON transaction that can be signed client side instead of actually signing and broadcasting
|
||||
simulate:
|
||||
type: boolean
|
||||
example: false
|
||||
|
||||
@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
@ -397,7 +398,6 @@ func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing
|
||||
|
||||
// NOTE: If making updates here also update cmd/gaia/cmd/gaiacli/main.go
|
||||
func registerRoutes(rs *RestServer) {
|
||||
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
|
||||
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
|
||||
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||
authrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, auth.StoreKey)
|
||||
@ -647,52 +647,42 @@ func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account {
|
||||
// ICS 20 - Tokens
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// POST /tx/sign Sign a Tx
|
||||
func doSign(t *testing.T, port, name, password, chainID string, accnum, sequence uint64, msg auth.StdTx) auth.StdTx {
|
||||
var signedMsg auth.StdTx
|
||||
payload := authrest.SignBody{
|
||||
Tx: msg,
|
||||
BaseReq: rest.NewBaseReq(
|
||||
name, password, "", chainID, "", "", accnum, sequence, nil, nil, false, false,
|
||||
),
|
||||
}
|
||||
json, err := cdc.MarshalJSON(payload)
|
||||
require.Nil(t, err)
|
||||
res, body := Request(t, port, "POST", "/tx/sign", json)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &signedMsg))
|
||||
return signedMsg
|
||||
}
|
||||
|
||||
// POST /tx/broadcast Send a signed Tx
|
||||
func doBroadcast(t *testing.T, port string, msg auth.StdTx) sdk.TxResponse {
|
||||
tx := authrest.BroadcastReq{Tx: msg, Return: "block"}
|
||||
req, err := cdc.MarshalJSON(tx)
|
||||
require.Nil(t, err)
|
||||
res, body := Request(t, port, "POST", "/tx/broadcast", req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var resultTx sdk.TxResponse
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &resultTx))
|
||||
return resultTx
|
||||
}
|
||||
func doBroadcast(t *testing.T, port string, tx auth.StdTx) (*http.Response, string) {
|
||||
txReq := authrest.BroadcastReq{Tx: tx, Return: "block"}
|
||||
|
||||
// GET /bank/balances/{address} Get the account balances
|
||||
|
||||
// POST /bank/accounts/{address}/transfers Send coins (build -> sign -> send)
|
||||
func doTransfer(t *testing.T, port, seed, name, memo, password string, addr sdk.AccAddress, fees sdk.Coins) (receiveAddr sdk.AccAddress, resultTx sdk.TxResponse) {
|
||||
res, body, receiveAddr := doTransferWithGas(t, port, seed, name, memo, password, addr, "", 1.0, false, false, fees)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
err := cdc.UnmarshalJSON([]byte(body), &resultTx)
|
||||
req, err := cdc.MarshalJSON(txReq)
|
||||
require.Nil(t, err)
|
||||
|
||||
return receiveAddr, resultTx
|
||||
return Request(t, port, "POST", "/tx/broadcast", req)
|
||||
}
|
||||
|
||||
// doTransfer performs a balance transfer with auto gas calculation. It also signs
|
||||
// the tx and broadcasts it.
|
||||
func doTransfer(
|
||||
t *testing.T, port, seed, name, memo, pwd string, addr sdk.AccAddress, fees sdk.Coins,
|
||||
) (sdk.AccAddress, sdk.TxResponse) {
|
||||
|
||||
resp, body, recvAddr := doTransferWithGas(
|
||||
t, port, seed, name, memo, pwd, addr, "", 1.0, false, true, fees,
|
||||
)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, resp)
|
||||
|
||||
var txResp sdk.TxResponse
|
||||
err := cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return recvAddr, txResp
|
||||
}
|
||||
|
||||
// doTransferWithGas performs a balance transfer with a specified gas value. The
|
||||
// broadcast parameter determines if the tx should only be generated or also
|
||||
// signed and broadcasted. The sending account's number and sequence are
|
||||
// determined prior to generating the tx.
|
||||
func doTransferWithGas(
|
||||
t *testing.T, port, seed, from, memo, password string, addr sdk.AccAddress,
|
||||
gas string, gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins,
|
||||
) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
|
||||
t *testing.T, port, seed, name, memo, pwd string, addr sdk.AccAddress,
|
||||
gas string, gasAdjustment float64, simulate, broadcast bool, fees sdk.Coins,
|
||||
) (resp *http.Response, body string, receiveAddr sdk.AccAddress) {
|
||||
|
||||
// create receive address
|
||||
kb := crkeys.NewInMemory()
|
||||
@ -708,15 +698,9 @@ func doTransferWithGas(
|
||||
sequence := acc.GetSequence()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
|
||||
if generateOnly {
|
||||
// generate only txs do not use a Keybase so the address must be used
|
||||
from = addr.String()
|
||||
}
|
||||
|
||||
from := addr.String()
|
||||
baseReq := rest.NewBaseReq(
|
||||
from, password, memo, chainID, gas,
|
||||
fmt.Sprintf("%f", gasAdjustment), accnum, sequence, fees, nil,
|
||||
generateOnly, simulate,
|
||||
from, memo, chainID, gas, fmt.Sprintf("%f", gasAdjustment), accnum, sequence, fees, nil, simulate,
|
||||
)
|
||||
|
||||
sr := bankrest.SendReq{
|
||||
@ -727,17 +711,28 @@ func doTransferWithGas(
|
||||
req, err := cdc.MarshalJSON(sr)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, body = Request(t, port, "POST", fmt.Sprintf("/bank/accounts/%s/transfers", receiveAddr), req)
|
||||
return
|
||||
// generate tx
|
||||
resp, body = Request(t, port, "POST", fmt.Sprintf("/bank/accounts/%s/transfers", receiveAddr), req)
|
||||
if !broadcast {
|
||||
return resp, body, receiveAddr
|
||||
}
|
||||
|
||||
// sign and broadcast
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, gasAdjustment, simulate)
|
||||
return resp, body, receiveAddr
|
||||
}
|
||||
|
||||
// doTransferWithGasAccAuto is similar to doTransferWithGas except that it
|
||||
// automatically determines the account's number and sequence when generating the
|
||||
// tx.
|
||||
func doTransferWithGasAccAuto(
|
||||
t *testing.T, port, seed, from, memo, password string, gas string,
|
||||
gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins,
|
||||
) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
|
||||
t *testing.T, port, seed, name, memo, pwd string, addr sdk.AccAddress,
|
||||
gas string, gasAdjustment float64, simulate, broadcast bool, fees sdk.Coins,
|
||||
) (resp *http.Response, body string, receiveAddr sdk.AccAddress) {
|
||||
|
||||
// create receive address
|
||||
kb := crkeys.NewInMemory()
|
||||
acc := getAccount(t, port, addr)
|
||||
|
||||
receiveInfo, _, err := kb.CreateMnemonic(
|
||||
"receive_address", crkeys.English, gapp.DefaultKeyPass, crkeys.SigningAlgo("secp256k1"),
|
||||
@ -747,9 +742,9 @@ func doTransferWithGasAccAuto(
|
||||
receiveAddr = sdk.AccAddress(receiveInfo.GetPubKey().Address())
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
|
||||
from := addr.String()
|
||||
baseReq := rest.NewBaseReq(
|
||||
from, password, memo, chainID, gas,
|
||||
fmt.Sprintf("%f", gasAdjustment), 0, 0, fees, nil, generateOnly, simulate,
|
||||
from, memo, chainID, gas, fmt.Sprintf("%f", gasAdjustment), 0, 0, fees, nil, simulate,
|
||||
)
|
||||
|
||||
sr := bankrest.SendReq{
|
||||
@ -760,8 +755,45 @@ func doTransferWithGasAccAuto(
|
||||
req, err := cdc.MarshalJSON(sr)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, body = Request(t, port, "POST", fmt.Sprintf("/bank/accounts/%s/transfers", receiveAddr), req)
|
||||
return
|
||||
resp, body = Request(t, port, "POST", fmt.Sprintf("/bank/accounts/%s/transfers", receiveAddr), req)
|
||||
if !broadcast {
|
||||
return resp, body, receiveAddr
|
||||
}
|
||||
|
||||
// sign and broadcast
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, gasAdjustment, simulate)
|
||||
return resp, body, receiveAddr
|
||||
}
|
||||
|
||||
// signAndBroadcastGenTx accepts a successfully generated unsigned tx, signs it,
|
||||
// and broadcasts it.
|
||||
func signAndBroadcastGenTx(
|
||||
t *testing.T, port, name, pwd, genTx string, acc auth.Account, gasAdjustment float64, simulate bool,
|
||||
) (resp *http.Response, body string) {
|
||||
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
|
||||
var tx auth.StdTx
|
||||
err := cdc.UnmarshalJSON([]byte(genTx), &tx)
|
||||
require.Nil(t, err)
|
||||
|
||||
txbldr := txbuilder.NewTxBuilder(
|
||||
utils.GetTxEncoder(cdc),
|
||||
acc.GetAccountNumber(),
|
||||
acc.GetSequence(),
|
||||
tx.Fee.Gas,
|
||||
gasAdjustment,
|
||||
simulate,
|
||||
chainID,
|
||||
tx.Memo,
|
||||
tx.Fee.Amount,
|
||||
nil,
|
||||
)
|
||||
|
||||
signedTx, err := txbldr.SignStdTx(name, pwd, tx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
return doBroadcast(t, port, signedTx)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@ -769,30 +801,40 @@ func doTransferWithGasAccAuto(
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
||||
func doDelegate(t *testing.T, port, name, password string,
|
||||
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Int, fees sdk.Coins) (resultTx sdk.TxResponse) {
|
||||
func doDelegate(
|
||||
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress,
|
||||
valAddr sdk.ValAddress, amount sdk.Int, fees sdk.Coins,
|
||||
) sdk.TxResponse {
|
||||
|
||||
acc := getAccount(t, port, delAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
sequence := acc.GetSequence()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
|
||||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
msg := msgDelegationsInput{
|
||||
BaseReq: baseReq,
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
Delegation: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
||||
}
|
||||
|
||||
req, err := cdc.MarshalJSON(msg)
|
||||
require.NoError(t, err)
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/delegations", delAddr.String()), req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var result sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &result)
|
||||
require.Nil(t, err)
|
||||
resp, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/delegations", delAddr.String()), req)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
return result
|
||||
// sign and broadcast
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, client.DefaultGasAdjustment, false)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
var txResp sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return txResp
|
||||
}
|
||||
|
||||
type msgDelegationsInput struct {
|
||||
@ -803,31 +845,39 @@ type msgDelegationsInput struct {
|
||||
}
|
||||
|
||||
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
||||
func doUndelegate(t *testing.T, port, name, password string,
|
||||
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Int, fees sdk.Coins) (resultTx sdk.TxResponse) {
|
||||
func doUndelegate(
|
||||
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress,
|
||||
valAddr sdk.ValAddress, amount sdk.Int, fees sdk.Coins,
|
||||
) sdk.TxResponse {
|
||||
|
||||
acc := getAccount(t, port, delAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
sequence := acc.GetSequence()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
|
||||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
msg := msgUndelegateInput{
|
||||
BaseReq: baseReq,
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
SharesAmount: sdk.NewDecFromInt(amount),
|
||||
}
|
||||
|
||||
req, err := cdc.MarshalJSON(msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/unbonding_delegations", delAddr), req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
resp, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/unbonding_delegations", delAddr), req)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
var result sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &result)
|
||||
require.Nil(t, err)
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, client.DefaultGasAdjustment, false)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
return result
|
||||
var txResp sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return txResp
|
||||
}
|
||||
|
||||
type msgUndelegateInput struct {
|
||||
@ -838,17 +888,18 @@ type msgUndelegateInput struct {
|
||||
}
|
||||
|
||||
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
||||
func doBeginRedelegation(t *testing.T, port, name, password string,
|
||||
delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, amount sdk.Int,
|
||||
fees sdk.Coins) (resultTx sdk.TxResponse) {
|
||||
func doBeginRedelegation(
|
||||
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress, valSrcAddr,
|
||||
valDstAddr sdk.ValAddress, amount sdk.Int, fees sdk.Coins,
|
||||
) sdk.TxResponse {
|
||||
|
||||
acc := getAccount(t, port, delAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
sequence := acc.GetSequence()
|
||||
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
|
||||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
msg := stakingrest.MsgBeginRedelegateInput{
|
||||
BaseReq: baseReq,
|
||||
DelegatorAddr: delAddr,
|
||||
@ -856,17 +907,21 @@ func doBeginRedelegation(t *testing.T, port, name, password string,
|
||||
ValidatorDstAddr: valDstAddr,
|
||||
SharesAmount: sdk.NewDecFromInt(amount),
|
||||
}
|
||||
|
||||
req, err := cdc.MarshalJSON(msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/redelegations", delAddr), req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
resp, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/redelegations", delAddr), req)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
var result sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &result)
|
||||
require.Nil(t, err)
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, client.DefaultGasAdjustment, false)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
return result
|
||||
var txResp sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return txResp
|
||||
}
|
||||
|
||||
type msgBeginRedelegateInput struct {
|
||||
@ -1073,15 +1128,18 @@ func getStakingParams(t *testing.T, port string) staking.Params {
|
||||
// ICS 22 - Gov
|
||||
// ----------------------------------------------------------------------
|
||||
// POST /gov/proposals Submit a proposal
|
||||
func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress,
|
||||
amount sdk.Int, fees sdk.Coins) (resultTx sdk.TxResponse) {
|
||||
func doSubmitProposal(
|
||||
t *testing.T, port, seed, name, pwd string, proposerAddr sdk.AccAddress,
|
||||
amount sdk.Int, fees sdk.Coins,
|
||||
) sdk.TxResponse {
|
||||
|
||||
acc := getAccount(t, port, proposerAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
sequence := acc.GetSequence()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
|
||||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
pr := govrest.PostProposalReq{
|
||||
Title: "Test",
|
||||
Description: "test",
|
||||
@ -1095,14 +1153,17 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
|
||||
require.NoError(t, err)
|
||||
|
||||
// submitproposal
|
||||
res, body := Request(t, port, "POST", "/gov/proposals", req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
resp, body := Request(t, port, "POST", "/gov/proposals", req)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
var results sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &results)
|
||||
require.Nil(t, err)
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, client.DefaultGasAdjustment, false)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
return results
|
||||
var txResp sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return txResp
|
||||
}
|
||||
|
||||
// GET /gov/proposals Query proposals
|
||||
@ -1161,15 +1222,18 @@ func getProposalsFilterStatus(t *testing.T, port string, status gov.ProposalStat
|
||||
}
|
||||
|
||||
// POST /gov/proposals/{proposalId}/deposits Deposit tokens to a proposal
|
||||
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64,
|
||||
amount sdk.Int, fees sdk.Coins) (resultTx sdk.TxResponse) {
|
||||
func doDeposit(
|
||||
t *testing.T, port, seed, name, pwd string, proposerAddr sdk.AccAddress,
|
||||
proposalID uint64, amount sdk.Int, fees sdk.Coins,
|
||||
) sdk.TxResponse {
|
||||
|
||||
acc := getAccount(t, port, proposerAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
sequence := acc.GetSequence()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
|
||||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
dr := govrest.DepositReq{
|
||||
Depositor: proposerAddr,
|
||||
Amount: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, amount)},
|
||||
@ -1179,14 +1243,17 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
|
||||
req, err := cdc.MarshalJSON(dr)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
resp, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), req)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
var results sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &results)
|
||||
require.Nil(t, err)
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, client.DefaultGasAdjustment, false)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
return results
|
||||
var txResp sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return txResp
|
||||
}
|
||||
|
||||
// GET /gov/proposals/{proposalId}/deposits Query deposits
|
||||
@ -1210,14 +1277,19 @@ func getTally(t *testing.T, port string, proposalID uint64) gov.TallyResult {
|
||||
}
|
||||
|
||||
// POST /gov/proposals/{proposalId}/votes Vote a proposal
|
||||
func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64, option string, fees sdk.Coins) (resultTx sdk.TxResponse) {
|
||||
func doVote(
|
||||
t *testing.T, port, seed, name, pwd string, proposerAddr sdk.AccAddress,
|
||||
proposalID uint64, option string, fees sdk.Coins,
|
||||
) sdk.TxResponse {
|
||||
|
||||
// get the account to get the sequence
|
||||
acc := getAccount(t, port, proposerAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
sequence := acc.GetSequence()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
|
||||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
vr := govrest.VoteReq{
|
||||
Voter: proposerAddr,
|
||||
Option: option,
|
||||
@ -1227,14 +1299,17 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ac
|
||||
req, err := cdc.MarshalJSON(vr)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
resp, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), req)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
var results sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &results)
|
||||
require.Nil(t, err)
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, client.DefaultGasAdjustment, false)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
return results
|
||||
var txResp sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return txResp
|
||||
}
|
||||
|
||||
// GET /gov/proposals/{proposalId}/votes Query voters
|
||||
@ -1339,24 +1414,32 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.
|
||||
|
||||
// TODO: Test this functionality, it is not currently in any of the tests
|
||||
// POST /slashing/validators/{validatorAddr}/unjail Unjail a jailed validator
|
||||
func doUnjail(t *testing.T, port, seed, name, password string,
|
||||
valAddr sdk.ValAddress, fees sdk.Coins) (resultTx sdk.TxResponse) {
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", 1, 1, fees, nil, false, false)
|
||||
func doUnjail(
|
||||
t *testing.T, port, seed, name, pwd string, valAddr sdk.ValAddress, fees sdk.Coins,
|
||||
) sdk.TxResponse {
|
||||
|
||||
acc := getAccount(t, port, sdk.AccAddress(valAddr.Bytes()))
|
||||
from := acc.GetAddress().String()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", 1, 1, fees, nil, false)
|
||||
ur := slashingrest.UnjailReq{
|
||||
BaseReq: baseReq,
|
||||
}
|
||||
req, err := cdc.MarshalJSON(ur)
|
||||
require.NoError(t, err)
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/slashing/validators/%s/unjail", valAddr.String()), req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var results sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &results)
|
||||
require.Nil(t, err)
|
||||
resp, body := Request(t, port, "POST", fmt.Sprintf("/slashing/validators/%s/unjail", valAddr.String()), req)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
return results
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, client.DefaultGasAdjustment, false)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
var txResp sdk.TxResponse
|
||||
err = cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return txResp
|
||||
}
|
||||
|
||||
type unjailReq struct {
|
||||
@ -1366,27 +1449,34 @@ type unjailReq struct {
|
||||
// ICS24 - fee distribution
|
||||
|
||||
// POST /distribution/delegators/{delgatorAddr}/rewards Withdraw delegator rewards
|
||||
func doWithdrawDelegatorAllRewards(t *testing.T, port, seed, name, password string,
|
||||
delegatorAddr sdk.AccAddress, fees sdk.Coins) (resultTx sdk.TxResponse) {
|
||||
func doWithdrawDelegatorAllRewards(
|
||||
t *testing.T, port, seed, name, pwd string, delegatorAddr sdk.AccAddress, fees sdk.Coins,
|
||||
) sdk.TxResponse {
|
||||
// get the account to get the sequence
|
||||
acc := getAccount(t, port, delegatorAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
sequence := acc.GetSequence()
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
|
||||
from := acc.GetAddress().String()
|
||||
|
||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||
wr := struct {
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
}{BaseReq: baseReq}
|
||||
|
||||
req := cdc.MustMarshalJSON(wr)
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/distribution/delegators/%s/rewards", delegatorAddr), req)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var results sdk.TxResponse
|
||||
cdc.MustUnmarshalJSON([]byte(body), &results)
|
||||
resp, body := Request(t, port, "POST", fmt.Sprintf("/distribution/delegators/%s/rewards", delegatorAddr), req)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
return results
|
||||
resp, body = signAndBroadcastGenTx(t, port, name, pwd, body, acc, client.DefaultGasAdjustment, false)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||
|
||||
var txResp sdk.TxResponse
|
||||
err := cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
return txResp
|
||||
}
|
||||
|
||||
func mustParseDecCoins(dcstring string) sdk.DecCoins {
|
||||
|
||||
@ -7,7 +7,6 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
@ -17,84 +16,6 @@ import (
|
||||
//-----------------------------------------------------------------------------
|
||||
// Building / Sending utilities
|
||||
|
||||
// CompleteAndBroadcastTxREST implements a utility function that facilitates
|
||||
// sending a series of messages in a signed tx. In addition, it will handle
|
||||
// tx gas simulation and estimation.
|
||||
//
|
||||
// NOTE: Also see CompleteAndBroadcastTxCLI.
|
||||
func CompleteAndBroadcastTxREST(w http.ResponseWriter, cliCtx context.CLIContext,
|
||||
baseReq rest.BaseReq, msgs []sdk.Msg, cdc *codec.Codec) {
|
||||
|
||||
gasAdj, ok := rest.ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
simAndExec, gas, err := client.ParseGas(baseReq.Gas)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// derive the from account address and name from the Keybase
|
||||
fromAddress, fromName, err := context.GetFromFields(baseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress)
|
||||
txBldr := authtxb.NewTxBuilder(
|
||||
utils.GetTxEncoder(cdc), baseReq.AccountNumber,
|
||||
baseReq.Sequence, gas, gasAdj, baseReq.Simulate,
|
||||
baseReq.ChainID, baseReq.Memo, baseReq.Fees, baseReq.GasPrices,
|
||||
)
|
||||
|
||||
txBldr, err = utils.PrepareTxBuilder(txBldr, cliCtx)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if baseReq.Simulate || simAndExec {
|
||||
if gasAdj < 0 {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, client.ErrInvalidGasAdjustment.Error())
|
||||
return
|
||||
}
|
||||
|
||||
txBldr, err = utils.EnrichWithGas(txBldr, cliCtx, msgs)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if baseReq.Simulate {
|
||||
rest.WriteSimulationResponse(w, cdc, txBldr.Gas())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
txBytes, err := txBldr.BuildAndSign(cliCtx.GetFromName(), baseReq.Password, msgs)
|
||||
if keyerror.IsErrKeyNotFound(err) {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
} else if keyerror.IsErrWrongPassword(err) {
|
||||
rest.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
} else if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
|
||||
}
|
||||
|
||||
// WriteGenerateStdTxResponse writes response for the generate only mode.
|
||||
func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec,
|
||||
cliCtx context.CLIContext, br rest.BaseReq, msgs []sdk.Msg) {
|
||||
@ -115,7 +36,7 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec,
|
||||
br.Simulate, br.ChainID, br.Memo, br.Fees, br.GasPrices,
|
||||
)
|
||||
|
||||
if simAndExec {
|
||||
if br.Simulate || simAndExec {
|
||||
if gasAdj < 0 {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, client.ErrInvalidGasAdjustment.Error())
|
||||
return
|
||||
@ -126,6 +47,11 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec,
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if br.Simulate {
|
||||
rest.WriteSimulationResponse(w, cdc, txBldr.Gas())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
stdMsg, err := txBldr.BuildSignMsg(msgs)
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
@ -40,8 +40,6 @@ func GenerateOrBroadcastMsgs(cliCtx context.CLIContext, txBldr authtxb.TxBuilder
|
||||
// QueryContext. It ensures that the account exists, has a proper number and
|
||||
// sequence set. In addition, it builds and signs a transaction with the
|
||||
// supplied messages. Finally, it broadcasts the signed transaction to a node.
|
||||
//
|
||||
// NOTE: Also see CompleteAndBroadcastTxREST.
|
||||
func CompleteAndBroadcastTxCLI(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) error {
|
||||
txBldr, err := PrepareTxBuilder(txBldr, cliCtx)
|
||||
if err != nil {
|
||||
|
||||
@ -158,7 +158,6 @@ func txCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
|
||||
// NOTE: If making updates here you also need to update the test helper in client/lcd/test_helper.go
|
||||
func registerRoutes(rs *lcd.RestServer) {
|
||||
registerSwaggerUI(rs)
|
||||
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
|
||||
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
|
||||
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, at.StoreKey)
|
||||
|
||||
@ -22,7 +22,6 @@ type GasEstimateResponse struct {
|
||||
// that all share common "base" fields.
|
||||
type BaseReq struct {
|
||||
From string `json:"from"`
|
||||
Password string `json:"password"`
|
||||
Memo string `json:"memo"`
|
||||
ChainID string `json:"chain_id"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
@ -31,19 +30,17 @@ type BaseReq struct {
|
||||
GasPrices sdk.DecCoins `json:"gas_prices"`
|
||||
Gas string `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
GenerateOnly bool `json:"generate_only"`
|
||||
Simulate bool `json:"simulate"`
|
||||
}
|
||||
|
||||
// NewBaseReq creates a new basic request instance and sanitizes its values
|
||||
func NewBaseReq(
|
||||
from, password, memo, chainID string, gas, gasAdjustment string,
|
||||
accNumber, seq uint64, fees sdk.Coins, gasPrices sdk.DecCoins, genOnly, simulate bool,
|
||||
from, memo, chainID string, gas, gasAdjustment string, accNumber, seq uint64,
|
||||
fees sdk.Coins, gasPrices sdk.DecCoins, simulate bool,
|
||||
) BaseReq {
|
||||
|
||||
return BaseReq{
|
||||
From: strings.TrimSpace(from),
|
||||
Password: password,
|
||||
Memo: strings.TrimSpace(memo),
|
||||
ChainID: strings.TrimSpace(chainID),
|
||||
Fees: fees,
|
||||
@ -52,7 +49,6 @@ func NewBaseReq(
|
||||
GasAdjustment: strings.TrimSpace(gasAdjustment),
|
||||
AccountNumber: accNumber,
|
||||
Sequence: seq,
|
||||
GenerateOnly: genOnly,
|
||||
Simulate: simulate,
|
||||
}
|
||||
}
|
||||
@ -60,8 +56,8 @@ func NewBaseReq(
|
||||
// Sanitize performs basic sanitization on a BaseReq object.
|
||||
func (br BaseReq) Sanitize() BaseReq {
|
||||
return NewBaseReq(
|
||||
br.From, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment,
|
||||
br.AccountNumber, br.Sequence, br.Fees, br.GasPrices, br.GenerateOnly, br.Simulate,
|
||||
br.From, br.Memo, br.ChainID, br.Gas, br.GasAdjustment,
|
||||
br.AccountNumber, br.Sequence, br.Fees, br.GasPrices, br.Simulate,
|
||||
)
|
||||
}
|
||||
|
||||
@ -69,12 +65,8 @@ func (br BaseReq) Sanitize() BaseReq {
|
||||
// logic is needed, the implementing request handler should perform those
|
||||
// checks manually.
|
||||
func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool {
|
||||
if !br.GenerateOnly && !br.Simulate {
|
||||
if !br.Simulate {
|
||||
switch {
|
||||
case len(br.Password) == 0:
|
||||
WriteErrorResponse(w, http.StatusUnauthorized, "password required but not specified")
|
||||
return false
|
||||
|
||||
case len(br.ChainID) == 0:
|
||||
WriteErrorResponse(w, http.StatusUnauthorized, "chain-id required but not specified")
|
||||
return false
|
||||
@ -91,8 +83,8 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if len(br.From) == 0 {
|
||||
WriteErrorResponse(w, http.StatusUnauthorized, "name or address required but not specified")
|
||||
if _, err := sdk.AccAddressFromBech32(br.From); err != nil || len(br.From) == 0 {
|
||||
WriteErrorResponse(w, http.StatusUnauthorized, fmt.Sprintf("invalid from address: %s", br.From))
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@ -14,35 +14,27 @@ import (
|
||||
|
||||
type mockResponseWriter struct{}
|
||||
|
||||
func TestBaseReq_ValidateBasic(t *testing.T) {
|
||||
func TestBaseReqValidateBasic(t *testing.T) {
|
||||
fromAddr := "cosmos1cq0sxam6x4l0sv9yz3a2vlqhdhvt2k6jtgcse0"
|
||||
tenstakes, err := types.ParseCoins("10stake")
|
||||
require.NoError(t, err)
|
||||
onestake, err := types.ParseDecCoins("1.0stake")
|
||||
require.NoError(t, err)
|
||||
|
||||
req1 := NewBaseReq(
|
||||
"nonempty", "nonempty", "", "nonempty", "", "",
|
||||
0, 0, tenstakes, nil, false, false,
|
||||
fromAddr, "", "nonempty", "", "", 0, 0, tenstakes, nil, false,
|
||||
)
|
||||
req2 := NewBaseReq(
|
||||
"", "nonempty", "", "nonempty", "", "",
|
||||
0, 0, tenstakes, nil, false, false,
|
||||
"", "", "nonempty", "", "", 0, 0, tenstakes, nil, false,
|
||||
)
|
||||
req3 := NewBaseReq(
|
||||
"nonempty", "", "", "nonempty", "", "",
|
||||
0, 0, tenstakes, nil, false, false,
|
||||
fromAddr, "", "", "", "", 0, 0, tenstakes, nil, false,
|
||||
)
|
||||
req4 := NewBaseReq(
|
||||
"nonempty", "nonempty", "", "", "", "",
|
||||
0, 0, tenstakes, nil, false, false,
|
||||
fromAddr, "", "nonempty", "", "", 0, 0, tenstakes, onestake, false,
|
||||
)
|
||||
req5 := NewBaseReq(
|
||||
"nonempty", "nonempty", "", "nonempty", "", "",
|
||||
0, 0, tenstakes, onestake, false, false,
|
||||
)
|
||||
req6 := NewBaseReq(
|
||||
"nonempty", "nonempty", "", "nonempty", "", "",
|
||||
0, 0, types.Coins{}, types.DecCoins{}, false, false,
|
||||
fromAddr, "", "nonempty", "", "", 0, 0, types.Coins{}, types.DecCoins{}, false,
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
@ -52,11 +44,10 @@ func TestBaseReq_ValidateBasic(t *testing.T) {
|
||||
want bool
|
||||
}{
|
||||
{"ok", req1, httptest.NewRecorder(), true},
|
||||
{"neither fees nor gasprices provided", req6, httptest.NewRecorder(), true},
|
||||
{"neither fees nor gasprices provided", req5, httptest.NewRecorder(), true},
|
||||
{"empty from", req2, httptest.NewRecorder(), false},
|
||||
{"empty password", req3, httptest.NewRecorder(), false},
|
||||
{"empty chain-id", req4, httptest.NewRecorder(), false},
|
||||
{"fees and gasprices provided", req5, httptest.NewRecorder(), false},
|
||||
{"empty chain-id", req3, httptest.NewRecorder(), false},
|
||||
{"fees and gasprices provided", req4, httptest.NewRecorder(), false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@ -31,10 +31,6 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec,
|
||||
"/tx/encode",
|
||||
EncodeTxRequestHandlerFn(cdc, cliCtx),
|
||||
).Methods("POST")
|
||||
r.HandleFunc(
|
||||
"/tx/sign",
|
||||
SignTxRequestHandlerFn(cdc, cliCtx),
|
||||
).Methods("POST")
|
||||
}
|
||||
|
||||
// query accountREST Handler
|
||||
|
||||
@ -5,5 +5,5 @@ import "github.com/cosmos/cosmos-sdk/x/auth"
|
||||
// BroadcastReq requests broadcasting a transaction
|
||||
type BroadcastReq struct {
|
||||
Tx auth.StdTx `json:"tx"`
|
||||
Return string `json:"return"`
|
||||
Return string `json:"return"` // TODO: Do we need this?
|
||||
}
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
)
|
||||
|
||||
// SignBody defines the properties of a sign request's body.
|
||||
type SignBody struct {
|
||||
Tx auth.StdTx `json:"tx"`
|
||||
AppendSig bool `json:"append_sig"`
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
// sign tx REST handler
|
||||
func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var m SignBody
|
||||
|
||||
if !rest.ReadRESTReq(w, r, cdc, &m) {
|
||||
return
|
||||
}
|
||||
|
||||
if !m.BaseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
|
||||
// validate tx
|
||||
// discard error if it's CodeNoSignatures as the tx comes with no signatures
|
||||
if err := m.Tx.ValidateBasic(); err != nil && err.Code() != sdk.CodeNoSignatures {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// derive the from account address and name from the Keybase
|
||||
fromAddress, fromName, err := context.GetFromFields(m.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress)
|
||||
|
||||
txBldr := authtxb.NewTxBuilder(
|
||||
utils.GetTxEncoder(cdc),
|
||||
m.BaseReq.AccountNumber,
|
||||
m.BaseReq.Sequence,
|
||||
m.Tx.Fee.Gas,
|
||||
1.0,
|
||||
false,
|
||||
m.BaseReq.ChainID,
|
||||
m.Tx.GetMemo(),
|
||||
m.Tx.Fee.Amount,
|
||||
nil,
|
||||
)
|
||||
|
||||
signedTx, err := txBldr.SignStdTx(cliCtx.GetFromName(), m.BaseReq.Password, m.Tx, m.AppendSig)
|
||||
if keyerror.IsErrKeyNotFound(err) {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
} else if keyerror.IsErrWrongPassword(err) {
|
||||
rest.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
} else if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
rest.PostProcessResponse(w, cdc, signedTx, cliCtx.Indent)
|
||||
}
|
||||
}
|
||||
@ -54,30 +54,13 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
// When generate only is supplied, the from field must be a valid Bech32
|
||||
// address.
|
||||
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
msg := bank.NewMsgSend(fromAddr, toAddr, req.Amount)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
// derive the from account address and name from the Keybase
|
||||
fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From)
|
||||
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress)
|
||||
msg := bank.NewMsgSend(cliCtx.GetFromAddress(), toAddr, req.Amount)
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
msg := bank.NewMsgSend(fromAddr, toAddr, req.Amount)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,8 +56,10 @@ type (
|
||||
)
|
||||
|
||||
// Withdraw delegator rewards
|
||||
func withdrawDelegatorRewardsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext,
|
||||
queryRoute string) http.HandlerFunc {
|
||||
func withdrawDelegatorRewardsHandlerFn(
|
||||
cdc *codec.Codec, cliCtx context.CLIContext, queryRoute string,
|
||||
) http.HandlerFunc {
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req withdrawRewardsReq
|
||||
if !rest.ReadRESTReq(w, r, cdc, &req) {
|
||||
@ -81,12 +83,7 @@ func withdrawDelegatorRewardsHandlerFn(cdc *codec.Codec, cliCtx context.CLIConte
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, msgs)
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, msgs, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, msgs)
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,12 +118,7 @@ func withdrawDelegationRewardsHandlerFn(cdc *codec.Codec, cliCtx context.CLICont
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,12 +148,7 @@ func setDelegatorWithdrawalAddrHandlerFn(cdc *codec.Codec, cliCtx context.CLICon
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,12 +179,7 @@ func withdrawValidatorRewardsHandlerFn(cdc *codec.Codec, cliCtx context.CLIConte
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, msgs)
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, msgs, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, msgs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -101,12 +101,7 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,12 +138,7 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,12 +181,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -48,28 +48,15 @@ func TransferRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.
|
||||
return
|
||||
}
|
||||
|
||||
var fromAddr sdk.AccAddress
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
// When generate only is supplied, the from field must be a valid Bech32
|
||||
// address.
|
||||
addr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fromAddr = addr
|
||||
}
|
||||
|
||||
packet := ibc.NewIBCPacket(fromAddr, to, req.Amount, req.BaseReq.ChainID, destChainID)
|
||||
msg := ibc.IBCTransferMsg{IBCPacket: packet}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
from, err := sdk.AccAddressFromBech32(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
packet := ibc.NewIBCPacket(from, to, req.Amount, req.BaseReq.ChainID, destChainID)
|
||||
msg := ibc.IBCTransferMsg{IBCPacket: packet}
|
||||
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,17 @@ func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CL
|
||||
return
|
||||
}
|
||||
|
||||
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(fromAddr, valAddr) {
|
||||
rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own validator address")
|
||||
return
|
||||
}
|
||||
|
||||
msg := slashing.NewMsgUnjail(valAddr)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
@ -56,25 +67,6 @@ func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CL
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
// derive the from account address and name from the Keybase
|
||||
fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress)
|
||||
|
||||
if !bytes.Equal(cliCtx.GetFromAddress(), valAddr) {
|
||||
rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own validator address")
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,26 +76,18 @@ func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
// derive the from account address and name from the Keybase
|
||||
fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From)
|
||||
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress)
|
||||
|
||||
if !bytes.Equal(cliCtx.GetFromAddress(), req.DelegatorAddr) {
|
||||
if !bytes.Equal(fromAddr, req.DelegatorAddr) {
|
||||
rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,26 +110,18 @@ func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx contex
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
// derive the from account address and name from the Keybase
|
||||
fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From)
|
||||
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress)
|
||||
|
||||
if !bytes.Equal(cliCtx.GetFromAddress(), req.DelegatorAddr) {
|
||||
if !bytes.Equal(fromAddr, req.DelegatorAddr) {
|
||||
rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,25 +144,17 @@ func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx
|
||||
return
|
||||
}
|
||||
|
||||
if req.BaseReq.GenerateOnly {
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
return
|
||||
}
|
||||
|
||||
// derive the from account address and name from the Keybase
|
||||
fromAddress, fromName, err := context.GetFromFields(req.BaseReq.From)
|
||||
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress)
|
||||
|
||||
if !bytes.Equal(cliCtx.GetFromAddress(), req.DelegatorAddr) {
|
||||
if !bytes.Equal(fromAddr, req.DelegatorAddr) {
|
||||
rest.WriteErrorResponse(w, http.StatusUnauthorized, "must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
clientrest.CompleteAndBroadcastTxREST(w, cliCtx, req.BaseReq, []sdk.Msg{msg}, cdc)
|
||||
clientrest.WriteGenerateStdTxResponse(w, cdc, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user