Merge remote-tracking branch 'origin/develop' into rigel/stake-cons-addr
This commit is contained in:
commit
a2b2ef92f2
|
@ -4,6 +4,7 @@ BREAKING CHANGES
|
|||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
* [x/stake] Validator.Owner renamed to Validator.Operator
|
||||
* [\#595](https://github.com/cosmos/cosmos-sdk/issues/595) Connections to the REST server are now secured using Transport Layer Security by default. The --insecure flag is provided to switch back to insecure HTTP.
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [x/stake] Validator.Owner renamed to Validator.Operator
|
||||
|
@ -49,6 +50,7 @@ BREAKING CHANGES
|
|||
* [store] Change storeInfo within the root multistore to use tmhash instead of ripemd160 \#2308
|
||||
* [codec] \#2324 All referrences to wire have been renamed to codec. Additionally, wire.NewCodec is now codec.New().
|
||||
* [types] \#2343 Make sdk.Msg have a names field, to facilitate automatic tagging.
|
||||
* [baseapp] \#2366 Automatically add action tags to all messages
|
||||
* [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index
|
||||
|
||||
* Tendermint
|
||||
|
|
|
@ -539,6 +539,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
|||
if mode != runTxModeCheck {
|
||||
msgResult = handler(ctx, msg)
|
||||
}
|
||||
msgResult.Tags = append(msgResult.Tags, sdk.MakeTag("action", []byte(msg.Name())))
|
||||
|
||||
// NOTE: GasWanted is determined by ante handler and
|
||||
// GasUsed by the GasMeter
|
||||
|
|
|
@ -94,13 +94,15 @@ func createCertifier() tmlite.Certifier {
|
|||
errMsg.WriteString("--node ")
|
||||
}
|
||||
if errMsg.Len() != 0 {
|
||||
fmt.Printf("must specify these options: %s when --trust-node is false\n", 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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package lcd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
|
@ -23,35 +25,84 @@ import (
|
|||
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
)
|
||||
|
||||
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 *codec.Codec) *cobra.Command {
|
||||
flagListenAddr := "laddr"
|
||||
flagCORS := "cors"
|
||||
flagMaxOpenConnections := "max-open"
|
||||
|
||||
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(
|
||||
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)
|
||||
})
|
||||
|
@ -61,6 +112,10 @@ func ServeCommand(cdc *codec.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, "", "Chain ID of Tendermint node")
|
||||
cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
|
||||
|
@ -95,3 +150,16 @@ func createHandler(cdc *codec.Codec) http.Handler {
|
|||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
tmTypes "github.com/tendermint/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
|
@ -78,7 +77,7 @@ func getValidators(cliCtx context.CLIContext, height *int64) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if !bytes.Equal(check.ValidatorsHash(), tmTypes.NewValidatorSet(validatorsRes.Validators).Hash()) {
|
||||
if !bytes.Equal(check.ValidatorsHash(), tmtypes.NewValidatorSet(validatorsRes.Validators).Hash()) {
|
||||
return nil, fmt.Errorf("got invalid validatorset")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export default ({ router }) => {
|
||||
router.addRoutes([{ path: "/testnet/", redirect: "/" }])
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
$accentColor = #304DE9
|
||||
$textColor = #15192C
|
||||
$borderColor = #eaecef
|
||||
$codeBgColor = #282c34
|
|
@ -24,7 +24,7 @@ on the website.
|
|||
|
||||
## Config.js
|
||||
|
||||
The [config.js](./config.js) generates the sidebar and Table of Contents
|
||||
The [config.js](./.vuepress/config.js) generates the sidebar and Table of Contents
|
||||
on the website docs. Note the use of relative links and the omission of
|
||||
file extensions. Additional features are available to improve the look
|
||||
of the sidebar.
|
||||
|
@ -59,9 +59,34 @@ to send users to the GitHub.
|
|||
|
||||
## Building Locally
|
||||
|
||||
Not currently possible but coming soon! Doing so requires
|
||||
assets held in the (private) website repo, installing
|
||||
[VuePress](https://vuepress.vuejs.org/), and modifying the `config.js`.
|
||||
To build and serve the documentation locally, run:
|
||||
|
||||
```
|
||||
npm install -g vuepress
|
||||
```
|
||||
|
||||
then change the following line in the `config.js`:
|
||||
|
||||
```
|
||||
base: "/docs/",
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```
|
||||
base: "/",
|
||||
```
|
||||
|
||||
Finally, go up one directory to the root of the repo and run:
|
||||
|
||||
```
|
||||
# from root of repo
|
||||
vuepress build docs
|
||||
cd dist/docs
|
||||
python -m SimpleHTTPServer 8080
|
||||
```
|
||||
|
||||
then navigate to localhost:8080 in your browser.
|
||||
|
||||
## Consistency
|
||||
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
# Integrate a Cosmos-SDK based blockchain as a Service Provider
|
||||
|
||||
We define 'service providers' as entities providing services for end-users that involve some form of interaction with a Cosmos-SDK based blockchain (this includes the Cosmos Hub). More specifically, this document will be focused around interactions with tokens.
|
||||
|
||||
This section does not concern wallet builders that want to provide [Light-Client](https://github.com/cosmos/cosmos-sdk/tree/develop/docs/light) functionalities. Service providers are expected to act as trusted point of contact to the blockchain for their end-users.
|
||||
|
||||
## High-level description of the architecture
|
||||
|
||||
There are three main pieces to consider:
|
||||
|
||||
- Full-nodes: To interact with the blockchain.
|
||||
- Rest Server: This acts as a relayer for HTTP calls.
|
||||
- Rest API: Define available endpoints for the Rest Server.
|
||||
|
||||
## Running a Full-Node
|
||||
|
||||
### Installation and configuration
|
||||
|
||||
We will describe the steps to run and interract with a full-node for the Cosmos Hub. For other SDK-based blockchain, the process should be similar.
|
||||
|
||||
First, you need to [install the software](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/getting-started/installation.md).
|
||||
|
||||
Then, you can start [running a full-node](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/getting-started/full-node.md).
|
||||
|
||||
### Command-Line interface
|
||||
|
||||
Next you will find a few useful CLI commands to interact with the Full-Node.
|
||||
|
||||
#### Creating a key-pair
|
||||
|
||||
To generate a new key (default ed25519 elliptic curve):
|
||||
|
||||
```bash
|
||||
gaiacli keys add <your_key_name>
|
||||
```
|
||||
|
||||
You will be asked to create a passwords (at least 8 characters) for this key-pair. The command returns 4 informations:
|
||||
|
||||
- `NAME`: Name of your key
|
||||
- `ADDRESS`: Your address. Used to receive funds.
|
||||
- `PUBKEY`: Your public key. Useful for validators.
|
||||
- `Seed phrase`: 12-words phrase. **Save this seed phrase somewhere safe**. It is used to recover your private key in case you forget the password.
|
||||
|
||||
You can see all your available keys by typing:
|
||||
|
||||
```bash
|
||||
gaiacli keys list
|
||||
```
|
||||
|
||||
#### Checking your balance
|
||||
|
||||
After receiving tokens to your address, you can view your account's balance by typing:
|
||||
|
||||
```bash
|
||||
gaiacli account <YOUR_ADDRESS>
|
||||
```
|
||||
|
||||
*Note: When you query an account balance with zero tokens, you will get this error: No account with address <YOUR_ADDRESS> was found in the state. This is expected! We're working on improving our error messages.*
|
||||
|
||||
#### Sending coins via the CLI
|
||||
|
||||
Here is the command to send coins via the CLI:
|
||||
|
||||
```bash
|
||||
gaiacli send --amount=10faucetToken --chain-id=<name_of_testnet_chain> --name=<key_name> --to=<destination_address>
|
||||
```
|
||||
|
||||
Flags:
|
||||
- `--amount`: This flag accepts the format `<value|coinName>`.
|
||||
- `--chain-id`: This flag allows you to specify the id of the chain. There will be different ids for different testnet chains and main chain.
|
||||
- `--name`: Name of the key of the sending account.
|
||||
- `--to`: Address of the recipient.
|
||||
|
||||
#### Help
|
||||
|
||||
If you need to do something else, the best command you can run is:
|
||||
|
||||
```bash
|
||||
gaiacli
|
||||
```
|
||||
|
||||
It will display all the available commands. For each command, you can use the `--help` flag to get further information.
|
||||
|
||||
## Setting up the Rest Server
|
||||
|
||||
The Rest Server acts as an intermediary between the front-end and the full-node. You don't need to run the Rest Server on the same machine as the full-node. If you intend to run the Rest Server on another machine, you need to go through the [Installation and configuration](#installation-and-configuration) again on this machine.
|
||||
|
||||
To start the Rest server:
|
||||
|
||||
```bash
|
||||
gaiacli advanced rest-server --trust-node=false --node=<full_node_address:full_node_port>
|
||||
```
|
||||
|
||||
Flags:
|
||||
- `--trust-node`: A boolean. If `true`, light-client verification is enabled. If `false`, it is disabled. For service providers, this should be set to `false`.
|
||||
- `--node`: This is where you indicate the address and the port of your full-node. The format is <full_node_address:full_node_port>. If the full-node is on the same machine, the address should be "tcp://localhost".
|
||||
- `--laddr`: This flag allows you to specify the address and port for the Rest Server. You will mostly use this flag only to specify the port, in which case just input "localhost" for the address. The format is <rest_server_address:port>.
|
||||
|
||||
### Listening for incoming transaction
|
||||
|
||||
The recommended way to listen for incoming transaction is to periodically query the blockchain through the following endpoint of the LCD:
|
||||
|
||||
[`/bank/balance/{account}`](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#bankbalanceaccount---get)
|
||||
|
||||
## Rest API
|
||||
|
||||
The Rest API documents all the available endpoints that you can use to interract with your full node. It can be found [here](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md).
|
||||
|
||||
The API is divided into ICS standards for each category of endpoints. For example, the [ICS20](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#ics20---tokenapi) describes the API to interact with tokens.
|
||||
|
||||
To give more flexibility to implementers, we have separated the different steps that are involved in the process of sending transactions. You will be able to generate unsigned transactions (example with [coin transfer](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-banktransfers)), [sign](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-authtxsign) and [broadcast](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-authtxbroadcast) them with different API endpoints. This allows service providers to use their own signing mechanism for instance.
|
|
@ -1,6 +1,6 @@
|
|||
# Getting Started
|
||||
|
||||
To start a rest server, we need to specify the following parameters:
|
||||
To start a REST server, we need to specify the following parameters:
|
||||
| Parameter | Type | Default | Required | Description |
|
||||
| ----------- | --------- | ----------------------- | -------- | ---------------------------------------------------- |
|
||||
| chain-id | string | null | true | chain id of the full node to connect |
|
||||
|
@ -12,9 +12,25 @@ To start a rest server, we need to specify the following parameters:
|
|||
Sample command:
|
||||
|
||||
```bash
|
||||
gaiacli light-client --chain-id=test --laddr=tcp://localhost:1317 --node tcp://localhost:46657 --trust-node=false
|
||||
gaiacli rest-server --chain-id=test \
|
||||
--laddr=tcp://localhost:1317 \
|
||||
--node tcp://localhost:46657 \
|
||||
--trust-node=false
|
||||
```
|
||||
|
||||
The server listens on HTTPS by default. You can set the SSL certificate to be used by the server with these additional flags:
|
||||
|
||||
```bash
|
||||
gaiacli rest-server --chain-id=test \
|
||||
--laddr=tcp://localhost:1317 \
|
||||
--node tcp://localhost:46657 \
|
||||
--trust-node=false \
|
||||
--certfile=mycert.pem --keyfile=mykey.key
|
||||
```
|
||||
|
||||
If no certificate/keyfile pair is supplied, a self-signed certificate will be generated and its fingerprint printed out.
|
||||
Append `--insecure` to the command line if you want to disable the secure layer and listen on an insecure HTTP port.
|
||||
|
||||
## Gaia Light Use Cases
|
||||
|
||||
LCD could be very helpful for related service providers. For a wallet service provider, LCD could
|
||||
|
|
Loading…
Reference in New Issue