Merge with develop
This commit is contained in:
@@ -6,7 +6,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
tmlite "github.com/tendermint/tendermint/lite"
|
||||
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
"os"
|
||||
)
|
||||
|
||||
const ctxAccStoreName = "acc"
|
||||
@@ -22,7 +23,7 @@ const ctxAccStoreName = "acc"
|
||||
// CLIContext implements a typical CLI context created in SDK modules for
|
||||
// transaction handling and queries.
|
||||
type CLIContext struct {
|
||||
Codec *wire.Codec
|
||||
Codec *codec.Codec
|
||||
AccDecoder auth.AccountDecoder
|
||||
Client rpcclient.Client
|
||||
Logger io.Writer
|
||||
@@ -68,37 +69,47 @@ func NewCLIContext() CLIContext {
|
||||
}
|
||||
|
||||
func createCertifier() tmlite.Certifier {
|
||||
trustNodeDefined := viper.IsSet(client.FlagTrustNode)
|
||||
if !trustNodeDefined {
|
||||
return nil
|
||||
}
|
||||
|
||||
trustNode := viper.GetBool(client.FlagTrustNode)
|
||||
if trustNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
home := viper.GetString(cli.HomeFlag)
|
||||
nodeURI := viper.GetString(client.FlagNode)
|
||||
|
||||
var errMsg bytes.Buffer
|
||||
if chainID == "" {
|
||||
errMsg.WriteString("chain-id ")
|
||||
errMsg.WriteString("--chain-id ")
|
||||
}
|
||||
if home == "" {
|
||||
errMsg.WriteString("home ")
|
||||
errMsg.WriteString("--home ")
|
||||
}
|
||||
if nodeURI == "" {
|
||||
errMsg.WriteString("node ")
|
||||
errMsg.WriteString("--node ")
|
||||
}
|
||||
// errMsg is not empty
|
||||
if errMsg.Len() != 0 {
|
||||
panic(fmt.Errorf("can't create certifier for distrust mode, empty values from these options: %s", errMsg.String()))
|
||||
fmt.Printf("Must specify these options: %s when --trust-node is false\n", errMsg.String())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
certifier, err := tmliteProxy.GetCertifier(chainID, home, nodeURI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
fmt.Printf("Create certifier failed: %s\n", err.Error())
|
||||
fmt.Printf("Please check network connection and verify the address of the node to connect to\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return certifier
|
||||
}
|
||||
|
||||
// WithCodec returns a copy of the context with an updated codec.
|
||||
func (ctx CLIContext) WithCodec(cdc *wire.Codec) CLIContext {
|
||||
func (ctx CLIContext) WithCodec(cdc *codec.Codec) CLIContext {
|
||||
ctx.Codec = cdc
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -11,3 +11,11 @@ func ErrInvalidAccount(addr sdk.AccAddress) error {
|
||||
return errors.Errorf(`No account with address %s was found in the state.
|
||||
Are you sure there has been a transaction involving it?`, addr)
|
||||
}
|
||||
|
||||
// ErrVerifyCommit returns a common error reflecting that the blockchain commit at a given
|
||||
// height can't be verified. The reason is that the base checkpoint of the certifier is
|
||||
// newer than the given height
|
||||
func ErrVerifyCommit(height int64) error {
|
||||
return errors.Errorf(`The height of base truststore in gaia-lite is higher than height %d.
|
||||
Can't verify blockchain proof at this height. Please set --trust-node to true and try again`, height)
|
||||
}
|
||||
|
||||
+21
-11
@@ -12,10 +12,12 @@ import (
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/lite"
|
||||
tmliteErr "github.com/tendermint/tendermint/lite/errors"
|
||||
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
@@ -326,7 +328,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
|
||||
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
|
||||
}
|
||||
|
||||
// Data from trusted node or subspace query doesn't need verification
|
||||
// Data from trusted node or subspace query doesn't need verification.
|
||||
if ctx.TrustNode || !isQueryStoreWithProof(path) {
|
||||
return resp.Value, nil
|
||||
}
|
||||
@@ -339,6 +341,17 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
|
||||
return resp.Value, nil
|
||||
}
|
||||
|
||||
// Certify verifies the consensus proof at given height
|
||||
func (ctx CLIContext) Certify(height int64) (lite.Commit, error) {
|
||||
check, err := tmliteProxy.GetCertifiedCommit(height, ctx.Client, ctx.Certifier)
|
||||
if tmliteErr.IsCommitNotFoundErr(err) {
|
||||
return lite.Commit{}, ErrVerifyCommit(height)
|
||||
} else if err != nil {
|
||||
return lite.Commit{}, err
|
||||
}
|
||||
return check, nil
|
||||
}
|
||||
|
||||
// verifyProof perform response proof verification
|
||||
// nolint: unparam
|
||||
func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
|
||||
@@ -347,34 +360,31 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
|
||||
return fmt.Errorf("missing valid certifier to verify data from untrusted node")
|
||||
}
|
||||
|
||||
node, err := ctx.GetNode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// AppHash for height H is in header H+1
|
||||
commit, err := tmliteProxy.GetCertifiedCommit(resp.Height+1, node, ctx.Certifier)
|
||||
commit, err := ctx.Certify(resp.Height + 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var multiStoreProof store.MultiStoreProof
|
||||
cdc := wire.NewCodec()
|
||||
cdc := codec.New()
|
||||
err = cdc.UnmarshalBinary(resp.Proof, &multiStoreProof)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to unmarshalBinary rangeProof")
|
||||
}
|
||||
|
||||
// Verify the substore commit hash against trusted appHash
|
||||
substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName,
|
||||
multiStoreProof.StoreInfos, commit.Header.AppHash)
|
||||
substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(
|
||||
multiStoreProof.StoreName, multiStoreProof.StoreInfos, commit.Header.AppHash)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed in verifying the proof against appHash")
|
||||
}
|
||||
|
||||
err = store.VerifyRangeProof(resp.Key, resp.Value, substoreCommitHash, &multiStoreProof.RangeProof)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed in the range proof verification")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -46,8 +46,7 @@ var (
|
||||
// GetCommands adds common flags to query commands
|
||||
func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||
for _, c := range cmds {
|
||||
// TODO: make this default false when we support proofs
|
||||
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for responses")
|
||||
c.Flags().Bool(FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||
c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
|
||||
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
|
||||
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
|
||||
@@ -71,7 +70,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
|
||||
c.Flags().Bool(FlagJson, false, "return output in json format")
|
||||
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
|
||||
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses")
|
||||
c.Flags().Bool(FlagTrustNode, true, "Trust connected full node (don't verify proofs for responses)")
|
||||
c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
|
||||
c.Flags().Bool(FlagGenerateOnly, false, "build an unsigned transaction and write it to STDOUT")
|
||||
// --gas can accept integers and "simulate"
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
var cdc *wire.Codec
|
||||
var cdc *codec.Codec
|
||||
|
||||
func init() {
|
||||
cdc = wire.NewCodec()
|
||||
wire.RegisterCrypto(cdc)
|
||||
cdc = codec.New()
|
||||
codec.RegisterCrypto(cdc)
|
||||
}
|
||||
|
||||
// marshal keys
|
||||
@@ -0,0 +1,174 @@
|
||||
package lcd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// default: 30 days
|
||||
const defaultValidFor = 30 * 24 * time.Hour
|
||||
|
||||
func generateSelfSignedCert(host string) (certBytes []byte, priv *ecdsa.PrivateKey, err error) {
|
||||
priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(defaultValidFor)
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to generate serial number: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Gaia Lite"},
|
||||
},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
hosts := strings.Split(host, ",")
|
||||
for _, h := range hosts {
|
||||
if ip := net.ParseIP(h); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, h)
|
||||
}
|
||||
}
|
||||
|
||||
certBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("couldn't create certificate: %s", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeCertAndPrivKey(certBytes []byte, priv *ecdsa.PrivateKey) (certFile string, keyFile string, err error) {
|
||||
if priv == nil {
|
||||
err = errors.New("private key is nil")
|
||||
return
|
||||
}
|
||||
certFile, err = writeCertificateFile(certBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
keyFile, err = writeKeyFile(priv)
|
||||
return
|
||||
}
|
||||
|
||||
func writeCertificateFile(certBytes []byte) (filename string, err error) {
|
||||
f, err := ioutil.TempFile("", "cert_")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
filename = f.Name()
|
||||
if err := pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}); err != nil {
|
||||
return filename, fmt.Errorf("failed to write data to %s: %s", filename, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeKeyFile(priv *ecdsa.PrivateKey) (filename string, err error) {
|
||||
f, err := ioutil.TempFile("", "key_")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
filename = f.Name()
|
||||
block, err := pemBlockForKey(priv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err := pem.Encode(f, block); err != nil {
|
||||
return filename, fmt.Errorf("failed to write data to %s: %s", filename, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func pemBlockForKey(priv *ecdsa.PrivateKey) (*pem.Block, error) {
|
||||
b, err := x509.MarshalECPrivateKey(priv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to marshal ECDSA private key: %v", err)
|
||||
}
|
||||
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, nil
|
||||
|
||||
}
|
||||
|
||||
func genCertKeyFilesAndReturnFingerprint(sslHosts string) (certFile, keyFile string, fingerprint string, err error) {
|
||||
certBytes, priv, err := generateSelfSignedCert(sslHosts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
certFile, keyFile, err = writeCertAndPrivKey(certBytes, priv)
|
||||
cleanupFunc := func() {
|
||||
os.Remove(certFile)
|
||||
os.Remove(keyFile)
|
||||
}
|
||||
// Either of the files could have been written already,
|
||||
// thus clean up regardless of the error.
|
||||
if err != nil {
|
||||
defer cleanupFunc()
|
||||
return
|
||||
}
|
||||
fingerprint, err = fingerprintForCertificate(certBytes)
|
||||
if err != nil {
|
||||
defer cleanupFunc()
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fingerprintForCertificate(certBytes []byte) (string, error) {
|
||||
cert, err := x509.ParseCertificate(certBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
h := sha256.New()
|
||||
h.Write(cert.Raw)
|
||||
fingerprintBytes := h.Sum(nil)
|
||||
var buf bytes.Buffer
|
||||
for i, b := range fingerprintBytes {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(&buf, ":")
|
||||
}
|
||||
fmt.Fprintf(&buf, "%02X", b)
|
||||
}
|
||||
return fmt.Sprintf("SHA256 Fingerprint=%s", buf.String()), nil
|
||||
}
|
||||
|
||||
func fingerprintFromFile(certFile string) (string, error) {
|
||||
f, err := os.Open(certFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
block, _ := pem.Decode(data)
|
||||
if block == nil {
|
||||
return "", fmt.Errorf("couldn't find PEM data in %s", certFile)
|
||||
}
|
||||
return fingerprintForCertificate(block.Bytes)
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package lcd
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGenerateSelfSignedCert(t *testing.T) {
|
||||
host := "127.0.0.1,localhost,::1"
|
||||
certBytes, _, err := generateSelfSignedCert(host)
|
||||
require.Nil(t, err)
|
||||
cert, err := x509.ParseCertificate(certBytes)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 2, len(cert.IPAddresses))
|
||||
require.Equal(t, 1, len(cert.DNSNames))
|
||||
require.True(t, cert.IsCA)
|
||||
}
|
||||
|
||||
func TestWriteCertAndPrivKey(t *testing.T) {
|
||||
expectedPerm := "-rw-------"
|
||||
derBytes, priv, err := generateSelfSignedCert("localhost")
|
||||
require.Nil(t, err)
|
||||
type args struct {
|
||||
certBytes []byte
|
||||
priv *ecdsa.PrivateKey
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid certificate", args{derBytes, priv}, false},
|
||||
{"garbage", args{[]byte("some garbage"), nil}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotCertFile, gotKeyFile, err := writeCertAndPrivKey(tt.args.certBytes, tt.args.priv)
|
||||
defer os.Remove(gotCertFile)
|
||||
defer os.Remove(gotKeyFile)
|
||||
if tt.wantErr {
|
||||
require.NotNil(t, err)
|
||||
return
|
||||
}
|
||||
require.Nil(t, err)
|
||||
info, err := os.Stat(gotCertFile)
|
||||
require.Nil(t, err)
|
||||
require.True(t, info.Mode().IsRegular())
|
||||
require.Equal(t, expectedPerm, info.Mode().String())
|
||||
info, err = os.Stat(gotKeyFile)
|
||||
require.Nil(t, err)
|
||||
require.True(t, info.Mode().IsRegular())
|
||||
require.Equal(t, expectedPerm, info.Mode().String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFingerprintFromFile(t *testing.T) {
|
||||
cert := `-----BEGIN CERTIFICATE-----
|
||||
MIIBbDCCARGgAwIBAgIQSuFKYv/22v+cxtVgMUrQADAKBggqhkjOPQQDAjASMRAw
|
||||
DgYDVQQKEwdBY21lIENvMB4XDTE4MDkyMDIzNDQyNloXDTE5MDkyMDIzNDQyNlow
|
||||
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDIo
|
||||
ujAesRczcPVAWiLhpeV1B7hS/RI2LJaGj3QjyJ8hiUthJTPIamr8m7LuS/U5fS0o
|
||||
hY297YeTIGo9YkxClICjSTBHMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
|
||||
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MA8GA1UdEQQIMAaHBH8AAAEwCgYIKoZI
|
||||
zj0EAwIDSQAwRgIhAKnwbhX9FrGG1otCVLwhClQ3RaLxnNpCgIGTqSimb34cAiEA
|
||||
stMN+IqMCKWlZyGqxGIiyksMLMEU3lRqKNQn2EoAZJY=
|
||||
-----END CERTIFICATE-----`
|
||||
wantFingerprint := `SHA256 Fingerprint=0B:ED:9A:AA:A2:D1:7E:B2:53:56:F6:FC:C0:E6:1A:69:70:21:A2:B0:90:FC:AF:BB:EF:AE:2C:78:52:AB:68:40`
|
||||
certFile, err := ioutil.TempFile("", "test_cert_")
|
||||
require.Nil(t, err)
|
||||
_, err = certFile.Write([]byte(cert))
|
||||
require.Nil(t, err)
|
||||
err = certFile.Close()
|
||||
require.Nil(t, err)
|
||||
defer os.Remove(certFile.Name())
|
||||
fingerprint, err := fingerprintFromFile(certFile.Name())
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, wantFingerprint, fingerprint)
|
||||
|
||||
// test failure
|
||||
emptyFile, err := ioutil.TempFile("", "test_cert_")
|
||||
require.Nil(t, err)
|
||||
err = emptyFile.Close()
|
||||
require.Nil(t, err)
|
||||
defer os.Remove(emptyFile.Name())
|
||||
_, err = fingerprintFromFile(emptyFile.Name())
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
+36
-31
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -22,19 +23,20 @@ import (
|
||||
client "github.com/cosmos/cosmos-sdk/client"
|
||||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
tests "github.com/cosmos/cosmos-sdk/tests"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
version "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/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cryptoKeys.BcryptSecurityParameter = 1
|
||||
version.Version = os.Getenv("VERSION")
|
||||
}
|
||||
|
||||
func TestKeys(t *testing.T) {
|
||||
@@ -63,7 +65,7 @@ func TestKeys(t *testing.T) {
|
||||
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var resp keys.KeyOutput
|
||||
err = wire.Cdc.UnmarshalJSON([]byte(body), &resp)
|
||||
err = codec.Cdc.UnmarshalJSON([]byte(body), &resp)
|
||||
require.Nil(t, err, body)
|
||||
|
||||
addr2Bech32 := resp.Address
|
||||
@@ -127,16 +129,16 @@ func TestVersion(t *testing.T) {
|
||||
res, body := Request(t, port, "GET", "/version", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
reg, err := regexp.Compile(`\d+\.\d+\.\d+(-dev)?`)
|
||||
reg, err := regexp.Compile(`\d+\.\d+\.\d+.*`)
|
||||
require.Nil(t, err)
|
||||
match := reg.MatchString(body)
|
||||
require.True(t, match, body)
|
||||
require.True(t, match, body, fmt.Sprintf("%s", body))
|
||||
|
||||
// node info
|
||||
res, body = Request(t, port, "GET", "/node_version", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
reg, err = regexp.Compile(`\d+\.\d+\.\d+(-dev)?`)
|
||||
reg, err = regexp.Compile(`\d+\.\d+\.\d+.*`)
|
||||
require.Nil(t, err)
|
||||
match = reg.MatchString(body)
|
||||
require.True(t, match, body)
|
||||
@@ -180,10 +182,10 @@ func TestBlock(t *testing.T) {
|
||||
|
||||
// --
|
||||
|
||||
res, body = Request(t, port, "GET", "/blocks/1", nil)
|
||||
res, body = Request(t, port, "GET", "/blocks/2", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
err = wire.Cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||
err = codec.Cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||
require.Nil(t, err, "Couldn't parse block")
|
||||
|
||||
require.NotEqual(t, ctypes.ResultBlock{}, resultBlock)
|
||||
@@ -213,7 +215,7 @@ func TestValidators(t *testing.T) {
|
||||
|
||||
// --
|
||||
|
||||
res, body = Request(t, port, "GET", "/validatorsets/1", nil)
|
||||
res, body = Request(t, port, "GET", "/validatorsets/2", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
err = cdc.UnmarshalJSON([]byte(body), &resultVals)
|
||||
@@ -295,7 +297,7 @@ func TestCoinSend(t *testing.T) {
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
}
|
||||
|
||||
func TestIBCTransfer(t *testing.T) {
|
||||
func DisabledTestIBCTransfer(t *testing.T) {
|
||||
name, password := "test", "1234567890"
|
||||
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
|
||||
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
|
||||
@@ -513,6 +515,7 @@ func TestBonding(t *testing.T) {
|
||||
cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
|
||||
defer cleanup()
|
||||
|
||||
amt := sdk.NewDec(60)
|
||||
validator1Operator := sdk.ValAddress(pks[0].Address())
|
||||
validator := getValidator(t, port, validator1Operator)
|
||||
|
||||
@@ -530,18 +533,18 @@ func TestBonding(t *testing.T) {
|
||||
|
||||
// query validator
|
||||
bond := getDelegation(t, port, addr, validator1Operator)
|
||||
require.Equal(t, "60.0000000000", bond.Shares)
|
||||
require.Equal(t, amt, bond.Shares)
|
||||
|
||||
summary := getDelegationSummary(t, port, addr)
|
||||
|
||||
require.Len(t, summary.Delegations, 1, "Delegation summary holds all delegations")
|
||||
require.Equal(t, "60.0000000000", summary.Delegations[0].Shares)
|
||||
require.Equal(t, amt, summary.Delegations[0].Shares)
|
||||
require.Len(t, summary.UnbondingDelegations, 0, "Delegation summary holds all unbonding-delegations")
|
||||
|
||||
bondedValidators := getDelegatorValidators(t, port, addr)
|
||||
require.Len(t, bondedValidators, 1)
|
||||
require.Equal(t, validator1Operator, bondedValidators[0].OperatorAddr)
|
||||
require.Equal(t, validator.DelegatorShares.Add(sdk.NewDec(60)).String(), bondedValidators[0].DelegatorShares.String())
|
||||
require.Equal(t, validator.DelegatorShares.Add(amt).String(), bondedValidators[0].DelegatorShares.String())
|
||||
|
||||
bondedValidator := getDelegatorValidator(t, port, addr, validator1Operator)
|
||||
require.Equal(t, validator1Operator, bondedValidator.OperatorAddr)
|
||||
@@ -561,9 +564,8 @@ func TestBonding(t *testing.T) {
|
||||
coins = acc.GetCoins()
|
||||
require.Equal(t, int64(40), coins.AmountOf("steak").Int64())
|
||||
|
||||
unbondings := getUndelegations(t, port, addr, validator1Operator)
|
||||
require.Len(t, unbondings, 1, "Unbondings holds all unbonding-delegations")
|
||||
require.Equal(t, "60", unbondings[0].Balance.Amount.String())
|
||||
unbonding := getUndelegation(t, port, addr, validator1Operator)
|
||||
require.Equal(t, "60", unbonding.Balance.Amount.String())
|
||||
|
||||
summary = getDelegationSummary(t, port, addr)
|
||||
|
||||
@@ -907,43 +909,43 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc
|
||||
func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.ValidatorSigningInfo {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/slashing/signing_info/%s", validatorPubKey), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var signingInfo slashing.ValidatorSigningInfo
|
||||
err := cdc.UnmarshalJSON([]byte(body), &signingInfo)
|
||||
require.Nil(t, err)
|
||||
|
||||
return signingInfo
|
||||
}
|
||||
|
||||
// ============= Stake Module ================
|
||||
|
||||
func getDelegation(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) rest.DelegationWithoutRat {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delAddr, valAddr), nil)
|
||||
func getDelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.Delegation {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var bond rest.DelegationWithoutRat
|
||||
|
||||
var bond stake.Delegation
|
||||
err := cdc.UnmarshalJSON([]byte(body), &bond)
|
||||
require.Nil(t, err)
|
||||
|
||||
return bond
|
||||
}
|
||||
|
||||
func getUndelegations(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) []stake.UnbondingDelegation {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delAddr, valAddr), nil)
|
||||
func getUndelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.UnbondingDelegation {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var unbondings []stake.UnbondingDelegation
|
||||
|
||||
var unbondings stake.UnbondingDelegation
|
||||
err := cdc.UnmarshalJSON([]byte(body), &unbondings)
|
||||
require.Nil(t, err)
|
||||
|
||||
return unbondings
|
||||
}
|
||||
|
||||
func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) rest.DelegationSummary {
|
||||
func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) stake.DelegationSummary {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s", delegatorAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var summary rest.DelegationSummary
|
||||
var summary stake.DelegationSummary
|
||||
|
||||
err := cdc.UnmarshalJSON([]byte(body), &summary)
|
||||
require.Nil(t, err)
|
||||
@@ -982,8 +984,8 @@ func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddr
|
||||
return bondedValidators
|
||||
}
|
||||
|
||||
func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.Validator {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delAddr, valAddr), nil)
|
||||
func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.Validator {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delegatorAddr, validatorAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var bondedValidator stake.Validator
|
||||
@@ -1109,18 +1111,22 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
|
||||
func getValidators(t *testing.T, port string) []stake.Validator {
|
||||
res, body := Request(t, port, "GET", "/stake/validators", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var validators []stake.Validator
|
||||
err := cdc.UnmarshalJSON([]byte(body), &validators)
|
||||
require.Nil(t, err)
|
||||
|
||||
return validators
|
||||
}
|
||||
|
||||
func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.Validator {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", valAddr.String()), nil)
|
||||
func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake.Validator {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", validatorAddr.String()), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var validator stake.Validator
|
||||
err := cdc.UnmarshalJSON([]byte(body), &validator)
|
||||
require.Nil(t, err)
|
||||
|
||||
return validator
|
||||
}
|
||||
|
||||
@@ -1296,7 +1302,6 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ac
|
||||
}
|
||||
}`, proposerAddr, name, password, chainID, accnum, sequence))
|
||||
res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), jsonStr)
|
||||
fmt.Println(res)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var results ctypes.ResultBroadcastTxCommit
|
||||
|
||||
+163
-48
@@ -1,6 +1,8 @@
|
||||
package lcd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
@@ -9,51 +11,99 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||
ibc "github.com/cosmos/cosmos-sdk/x/ibc/client/rest"
|
||||
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
||||
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rakyll/statik/fs"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
"github.com/rakyll/statik/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
flagListenAddr = "laddr"
|
||||
flagCORS = "cors"
|
||||
flagMaxOpenConnections = "max-open"
|
||||
flagInsecure = "insecure"
|
||||
flagSSLHosts = "ssl-hosts"
|
||||
flagSSLCertFile = "ssl-certfile"
|
||||
flagSSLKeyFile = "ssl-keyfile"
|
||||
)
|
||||
|
||||
// ServeCommand will generate a long-running rest server
|
||||
// (aka Light Client Daemon) that exposes functionality similar
|
||||
// to the cli, but over rest
|
||||
func ServeCommand(cdc *wire.Codec) *cobra.Command {
|
||||
flagListenAddr := "laddr"
|
||||
flagCORS := "cors"
|
||||
flagMaxOpenConnections := "max-open"
|
||||
func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "rest-server",
|
||||
Short: "Start LCD (light-client daemon), a local REST server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
listenAddr := viper.GetString(flagListenAddr)
|
||||
handler := createHandler(cdc)
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
|
||||
maxOpen := viper.GetInt(flagMaxOpenConnections)
|
||||
sslHosts := viper.GetString(flagSSLHosts)
|
||||
certFile := viper.GetString(flagSSLCertFile)
|
||||
keyFile := viper.GetString(flagSSLKeyFile)
|
||||
cleanupFunc := func() {}
|
||||
|
||||
listener, err := tmserver.StartHTTPServer(
|
||||
listenAddr, handler, logger,
|
||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
var listener net.Listener
|
||||
var fingerprint string
|
||||
if viper.GetBool(flagInsecure) {
|
||||
listener, err = tmserver.StartHTTPServer(
|
||||
listenAddr, handler, logger,
|
||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if certFile != "" {
|
||||
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
|
||||
err = validateCertKeyFiles(certFile, keyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// cert/key pair is provided, read the fingerprint
|
||||
fingerprint, err = fingerprintFromFile(certFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// if certificate is not supplied, generate a self-signed one
|
||||
certFile, keyFile, fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cleanupFunc = func() {
|
||||
os.Remove(certFile)
|
||||
os.Remove(keyFile)
|
||||
}
|
||||
defer cleanupFunc()
|
||||
}
|
||||
listener, err = tmserver.StartHTTPAndTLSServer(
|
||||
listenAddr, handler,
|
||||
certFile, keyFile,
|
||||
logger,
|
||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
logger.Info(fingerprint)
|
||||
}
|
||||
|
||||
logger.Info("REST server started")
|
||||
|
||||
// wait forever and cleanup
|
||||
cmn.TrapSignal(func() {
|
||||
defer cleanupFunc()
|
||||
err := listener.Close()
|
||||
logger.Error("error closing listener", "err", err)
|
||||
})
|
||||
@@ -63,16 +113,20 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command {
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagListenAddr, "tcp://localhost:1317", "The address for the server to listen on")
|
||||
cmd.Flags().Bool(flagInsecure, false, "Do not set up SSL/TLS layer")
|
||||
cmd.Flags().String(flagSSLHosts, "", "Comma-separated hostnames and IPs to generate a certificate for")
|
||||
cmd.Flags().String(flagSSLCertFile, "", "Path to a SSL certificate file. If not supplied, a self-signed certificate will be generated.")
|
||||
cmd.Flags().String(flagSSLKeyFile, "", "Path to a key file; ignored if a certificate file is not supplied.")
|
||||
cmd.Flags().String(flagCORS, "", "Set the domains that can make CORS requests (* for all)")
|
||||
cmd.Flags().String(client.FlagChainID, "", "The chain ID to connect to")
|
||||
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
|
||||
cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
|
||||
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Whether trust connected full node")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func createHandler(cdc *wire.Codec) http.Handler {
|
||||
func createHandler(cdc *codec.Codec) http.Handler {
|
||||
r := mux.NewRouter()
|
||||
|
||||
kb, err := keys.GetKeyBase() //XXX
|
||||
@@ -91,7 +145,6 @@ func createHandler(cdc *wire.Codec) http.Handler {
|
||||
tx.RegisterRoutes(cliCtx, r, cdc)
|
||||
auth.RegisterRoutes(cliCtx, r, cdc, "acc")
|
||||
bank.RegisterRoutes(cliCtx, r, cdc, kb)
|
||||
ibc.RegisterRoutes(cliCtx, r, cdc, kb)
|
||||
stake.RegisterRoutes(cliCtx, r, cdc, kb)
|
||||
slashing.RegisterRoutes(cliCtx, r, cdc, kb)
|
||||
gov.RegisterRoutes(cliCtx, r, cdc)
|
||||
@@ -100,40 +153,70 @@ func createHandler(cdc *wire.Codec) http.Handler {
|
||||
}
|
||||
|
||||
// ServeLiteCommand will generate a long-running rest server for gaia-lite
|
||||
func ServeLiteCommand(cdc *wire.Codec) *cobra.Command {
|
||||
flagListenAddr := "laddr"
|
||||
flagCORS := "cors"
|
||||
flagMaxOpenConnections := "max-open"
|
||||
|
||||
func ServeLiteCommand(cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "lite-server",
|
||||
Short: "Start Gaia-lite server daemon, a local REST server with swagger-ui, default url: http://localhost:1317/swagger-ui/",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Short: "Start Gaia-lite (light-client daemon), a local REST server with swagger-ui, default url: http://localhost:1317/swagger-ui/",
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
listenAddr := viper.GetString(flagListenAddr)
|
||||
router := createLiteHandler(cdc)
|
||||
|
||||
statikFS, err := fs.New()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
staticServer := http.FileServer(statikFS)
|
||||
router.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer))
|
||||
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "lite-server")
|
||||
handler := createLiteHandler(cdc)
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "gaia-lite")
|
||||
maxOpen := viper.GetInt(flagMaxOpenConnections)
|
||||
sslHosts := viper.GetString(flagSSLHosts)
|
||||
certFile := viper.GetString(flagSSLCertFile)
|
||||
keyFile := viper.GetString(flagSSLKeyFile)
|
||||
cleanupFunc := func() {}
|
||||
|
||||
listener, err := tmserver.StartHTTPServer(
|
||||
listenAddr, router, logger,
|
||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
var listener net.Listener
|
||||
var fingerprint string
|
||||
if viper.GetBool(flagInsecure) {
|
||||
listener, err = tmserver.StartHTTPServer(
|
||||
listenAddr, handler, logger,
|
||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if certFile != "" {
|
||||
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
|
||||
err = validateCertKeyFiles(certFile, keyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// cert/key pair is provided, read the fingerprint
|
||||
fingerprint, err = fingerprintFromFile(certFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// if certificate is not supplied, generate a self-signed one
|
||||
certFile, keyFile, fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cleanupFunc = func() {
|
||||
os.Remove(certFile)
|
||||
os.Remove(keyFile)
|
||||
}
|
||||
defer cleanupFunc()
|
||||
}
|
||||
listener, err = tmserver.StartHTTPAndTLSServer(
|
||||
listenAddr, handler,
|
||||
certFile, keyFile,
|
||||
logger,
|
||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
logger.Info(fingerprint)
|
||||
}
|
||||
|
||||
logger.Info("Gaia-lite server started")
|
||||
logger.Info("Gaia-lite REST server started")
|
||||
|
||||
// wait forever and cleanup
|
||||
cmn.TrapSignal(func() {
|
||||
defer cleanupFunc()
|
||||
err := listener.Close()
|
||||
logger.Error("error closing listener", "err", err)
|
||||
})
|
||||
@@ -143,16 +226,20 @@ func ServeLiteCommand(cdc *wire.Codec) *cobra.Command {
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagListenAddr, "tcp://localhost:1317", "The address for the server to listen on")
|
||||
cmd.Flags().Bool(flagInsecure, false, "Do not set up SSL/TLS layer")
|
||||
cmd.Flags().String(flagSSLHosts, "", "Comma-separated hostnames and IPs to generate a certificate for")
|
||||
cmd.Flags().String(flagSSLCertFile, "", "Path to a SSL certificate file. If not supplied, a self-signed certificate will be generated.")
|
||||
cmd.Flags().String(flagSSLKeyFile, "", "Path to a key file; ignored if a certificate file is not supplied.")
|
||||
cmd.Flags().String(flagCORS, "", "Set the domains that can make CORS requests (* for all)")
|
||||
cmd.Flags().String(client.FlagChainID, "", "The chain ID to connect to")
|
||||
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
|
||||
cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
|
||||
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Whether trust connected full node")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func createLiteHandler(cdc *wire.Codec) *mux.Router {
|
||||
func createLiteHandler(cdc *codec.Codec) *mux.Router {
|
||||
r := mux.NewRouter()
|
||||
|
||||
kb, err := keys.GetKeyBase() //XXX
|
||||
@@ -160,12 +247,40 @@ func createLiteHandler(cdc *wire.Codec) *mux.Router {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
statikFS, err := fs.New()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
staticServer := http.FileServer(statikFS)
|
||||
r.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer))
|
||||
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc).WithLogger(os.Stdout)
|
||||
|
||||
// TODO: make more functional? aka r = keys.RegisterRoutes(r)
|
||||
r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET")
|
||||
|
||||
bank.RegisterLiteRoutes(cliCtx, r, cdc, kb)
|
||||
keys.RegisterRoutes(r)
|
||||
rpc.RegisterRoutes(cliCtx, r)
|
||||
tx.RegisterRoutes(cliCtx, r, cdc)
|
||||
auth.RegisterRoutes(cliCtx, r, cdc, "acc")
|
||||
bank.RegisterRoutes(cliCtx, r, cdc, kb)
|
||||
stake.RegisterRoutes(cliCtx, r, cdc, kb)
|
||||
slashing.RegisterRoutes(cliCtx, r, cdc, kb)
|
||||
gov.RegisterRoutes(cliCtx, r, cdc)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func validateCertKeyFiles(certFile, keyFile string) error {
|
||||
if keyFile == "" {
|
||||
return errors.New("a key file is required")
|
||||
}
|
||||
if _, err := os.Stat(certFile); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := os.Stat(keyFile); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "All Gaia-lite supported APIs will be shown by this swagger-ui page. You can access these APIs through this page.",
|
||||
"description": "All Gaia-lite supported APIs will be shown by this swagger-ui page. You can access these APIs on this page.",
|
||||
"version": "1.0",
|
||||
"title": "Gaia-lite Swagger-UI",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"termsOfService": "https://explorecosmos.network/",
|
||||
"contact": {
|
||||
"name": "API Support",
|
||||
"url": "http://www.swagger.io/support",
|
||||
"email": "support@swagger.io"
|
||||
"name": "Cosmos",
|
||||
"url": "https://cosmos.network/"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
|
||||
@@ -15,11 +15,11 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
@@ -176,7 +176,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
||||
genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100))
|
||||
}
|
||||
|
||||
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
|
||||
appState, err := codec.MarshalJSONIndent(cdc, genesisState)
|
||||
require.NoError(t, err)
|
||||
genDoc.AppState = appState
|
||||
|
||||
@@ -186,6 +186,10 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
||||
// XXX: Need to set this so LCD knows the tendermint node address!
|
||||
viper.Set(client.FlagNode, config.RPC.ListenAddress)
|
||||
viper.Set(client.FlagChainID, genDoc.ChainID)
|
||||
viper.Set(client.FlagTrustNode, false)
|
||||
dir, err := ioutil.TempDir("", "lcd_test")
|
||||
require.NoError(t, err)
|
||||
viper.Set(cli.HomeFlag, dir)
|
||||
|
||||
node, err := startTM(config, logger, genDoc, privVal, app)
|
||||
require.NoError(t, err)
|
||||
@@ -245,7 +249,7 @@ func startTM(
|
||||
// startLCD starts the LCD.
|
||||
//
|
||||
// NOTE: This causes the thread to block.
|
||||
func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) {
|
||||
func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec) (net.Listener, error) {
|
||||
return tmrpc.StartHTTPServer(listenAddr, createHandler(cdc), logger, tmrpc.Config{})
|
||||
}
|
||||
|
||||
|
||||
+21
-3
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
||||
)
|
||||
|
||||
//BlockCommand returns the verified block data for a given heights
|
||||
@@ -21,8 +22,8 @@ func BlockCommand() *cobra.Command {
|
||||
RunE: printBlock,
|
||||
}
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||
// TODO: change this to false when we can
|
||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -41,8 +42,25 @@ func getBlock(cliCtx context.CLIContext, height *int64) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cliCtx.TrustNode {
|
||||
check, err := cliCtx.Certify(res.Block.Height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = tmliteProxy.ValidateBlockMeta(res.BlockMeta, check)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = tmliteProxy.ValidateBlock(res.Block, check)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move maarshalling into cmd/rest functions
|
||||
// output, err := tmwire.MarshalJSON(res)
|
||||
// output, err := tmcodec.MarshalJSON(res)
|
||||
output, err := cdc.MarshalJSON(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"bytes"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@@ -25,8 +26,8 @@ func ValidatorCommand() *cobra.Command {
|
||||
RunE: printValidators,
|
||||
}
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||
// TODO: change this to false when we can
|
||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -70,6 +71,17 @@ func getValidators(cliCtx context.CLIContext, height *int64) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cliCtx.TrustNode {
|
||||
check, err := cliCtx.Certify(validatorsRes.BlockHeight)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !bytes.Equal(check.ValidatorsHash(), tmtypes.NewValidatorSet(validatorsRes.Validators).Hash()) {
|
||||
return nil, fmt.Errorf("got invalid validatorset")
|
||||
}
|
||||
}
|
||||
|
||||
outputValidatorsRes := ResultValidatorsOutput{
|
||||
BlockHeight: validatorsRes.BlockHeight,
|
||||
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
|
||||
|
||||
+34
-24
@@ -3,26 +3,23 @@ package tx
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
)
|
||||
|
||||
// QueryTxCmd implements the default command for a tx query.
|
||||
func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||
func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "tx [hash]",
|
||||
Short: "Matches this txhash over all committed blocks",
|
||||
@@ -30,11 +27,10 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// find the key to look up the account
|
||||
hashHexStr := args[0]
|
||||
trustNode := viper.GetBool(client.FlagTrustNode)
|
||||
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
output, err := queryTx(cdc, cliCtx, hashHexStr, trustNode)
|
||||
output, err := queryTx(cdc, cliCtx, hashHexStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -45,13 +41,12 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||
}
|
||||
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||
|
||||
// TODO: change this to false when we can
|
||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func queryTx(cdc *wire.Codec, cliCtx context.CLIContext, hashHexStr string, trustNode bool) ([]byte, error) {
|
||||
func queryTx(cdc *codec.Codec, cliCtx context.CLIContext, hashHexStr string) ([]byte, error) {
|
||||
hash, err := hex.DecodeString(hashHexStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -62,21 +57,41 @@ func queryTx(cdc *wire.Codec, cliCtx context.CLIContext, hashHexStr string, trus
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := node.Tx(hash, !trustNode)
|
||||
res, err := node.Tx(hash, !cliCtx.TrustNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cliCtx.TrustNode {
|
||||
err := ValidateTxResult(cliCtx, res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
info, err := formatTxResult(cdc, res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return wire.MarshalJSONIndent(cdc, info)
|
||||
return codec.MarshalJSONIndent(cdc, info)
|
||||
}
|
||||
|
||||
func formatTxResult(cdc *wire.Codec, res *ctypes.ResultTx) (Info, error) {
|
||||
// TODO: verify the proof if requested
|
||||
// ValidateTxResult performs transaction verification
|
||||
func ValidateTxResult(cliCtx context.CLIContext, res *ctypes.ResultTx) error {
|
||||
check, err := cliCtx.Certify(res.Height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = res.Proof.Validate(check.Header.DataHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatTxResult(cdc *codec.Codec, res *ctypes.ResultTx) (Info, error) {
|
||||
tx, err := parseTx(cdc, res.Tx)
|
||||
if err != nil {
|
||||
return Info{}, err
|
||||
@@ -98,7 +113,7 @@ type Info struct {
|
||||
Result abci.ResponseDeliverTx `json:"result"`
|
||||
}
|
||||
|
||||
func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) {
|
||||
func parseTx(cdc *codec.Codec, txBytes []byte) (sdk.Tx, error) {
|
||||
var tx auth.StdTx
|
||||
|
||||
err := cdc.UnmarshalBinary(txBytes, &tx)
|
||||
@@ -112,17 +127,12 @@ func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) {
|
||||
// REST
|
||||
|
||||
// transaction query REST handler
|
||||
func QueryTxRequestHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
func QueryTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
hashHexStr := vars["hash"]
|
||||
trustNode, err := strconv.ParseBool(r.FormValue("trust_node"))
|
||||
// trustNode defaults to true
|
||||
if err != nil {
|
||||
trustNode = true
|
||||
}
|
||||
|
||||
output, err := queryTx(cdc, cliCtx, hashHexStr, trustNode)
|
||||
output, err := queryTx(cdc, cliCtx, hashHexStr)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
+3
-3
@@ -5,11 +5,11 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
// AddCommands adds a number of tx-query related subcommands
|
||||
func AddCommands(cmd *cobra.Command, cdc *wire.Codec) {
|
||||
func AddCommands(cmd *cobra.Command, cdc *codec.Codec) {
|
||||
cmd.AddCommand(
|
||||
SearchTxCmd(cdc),
|
||||
QueryTxCmd(cdc),
|
||||
@@ -17,7 +17,7 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) {
|
||||
}
|
||||
|
||||
// register REST routes
|
||||
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) {
|
||||
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) {
|
||||
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, cliCtx)).Methods("GET")
|
||||
r.HandleFunc("/txs", SearchTxRequestHandlerFn(cliCtx, cdc)).Methods("GET")
|
||||
// r.HandleFunc("/txs/sign", SignTxRequstHandler).Methods("POST")
|
||||
|
||||
+17
-9
@@ -9,8 +9,8 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -24,7 +24,7 @@ const (
|
||||
)
|
||||
|
||||
// default client command to search through tagged transactions
|
||||
func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||
func SearchTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "txs",
|
||||
Short: "Search for all transactions that match the given tags.",
|
||||
@@ -62,15 +62,14 @@ $ gaiacli tendermint txs --tag test1,test2 --any
|
||||
}
|
||||
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||
|
||||
// TODO: change this to false once proofs built in
|
||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
|
||||
cmd.Flags().StringSlice(flagTags, nil, "Comma-separated list of tags that must match")
|
||||
cmd.Flags().Bool(flagAny, false, "Return transactions that match ANY tag, rather than ALL")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func searchTxs(cliCtx context.CLIContext, cdc *wire.Codec, tags []string) ([]Info, error) {
|
||||
func searchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string) ([]Info, error) {
|
||||
if len(tags) == 0 {
|
||||
return nil, errors.New("must declare at least one tag to search")
|
||||
}
|
||||
@@ -84,7 +83,7 @@ func searchTxs(cliCtx context.CLIContext, cdc *wire.Codec, tags []string) ([]Inf
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prove := !viper.GetBool(client.FlagTrustNode)
|
||||
prove := !cliCtx.TrustNode
|
||||
|
||||
// TODO: take these as args
|
||||
page := 0
|
||||
@@ -94,6 +93,15 @@ func searchTxs(cliCtx context.CLIContext, cdc *wire.Codec, tags []string) ([]Inf
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if prove {
|
||||
for _, tx := range res.Txs {
|
||||
err := ValidateTxResult(cliCtx, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info, err := FormatTxResults(cdc, res.Txs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -103,7 +111,7 @@ func searchTxs(cliCtx context.CLIContext, cdc *wire.Codec, tags []string) ([]Inf
|
||||
}
|
||||
|
||||
// parse the indexed txs into an array of Info
|
||||
func FormatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]Info, error) {
|
||||
func FormatTxResults(cdc *codec.Codec, res []*ctypes.ResultTx) ([]Info, error) {
|
||||
var err error
|
||||
out := make([]Info, len(res))
|
||||
for i := range res {
|
||||
@@ -119,7 +127,7 @@ func FormatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]Info, error) {
|
||||
// REST
|
||||
|
||||
// Search Tx REST Handler
|
||||
func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
|
||||
func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
tag := r.FormValue("tag")
|
||||
if tag == "" {
|
||||
|
||||
@@ -133,6 +133,7 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
||||
return txBldr.SignStdTx(name, passphrase, stdTx, appendSig)
|
||||
}
|
||||
|
||||
// nolint
|
||||
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
|
||||
func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (estimated, adjusted int64, err error) {
|
||||
txBytes, err := txBldr.BuildWithPubKey(name, msgs)
|
||||
|
||||
Reference in New Issue
Block a user