From 837a91304f38f6170e904b6eeb804f7e7ed08063 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 18 Nov 2019 08:33:15 +0100 Subject: [PATCH 1/3] Testnet Docker implementation Signed-off-by: Riccardo Montagnin --- Dockerfile | 33 +++++++++++++ docker-compose.yml | 67 +++++++++++++++++++++++++++ networks/local/Makefile | 6 +++ networks/local/desmosdnode/Dockerfile | 23 +++++++++ networks/local/desmosdnode/wrapper.sh | 32 +++++++++++++ 5 files changed, 161 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 networks/local/Makefile create mode 100644 networks/local/desmosdnode/Dockerfile create mode 100644 networks/local/desmosdnode/wrapper.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..74a1c47bad --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# Simple usage with a mounted data directory: +# > docker build -t desmos . +# > docker run -it -p 46657:46657 -p 46656:46656 -v ~/.desmosd:/root/.desmosd -v ~/.desmoscli:/root/.desmoscli desmos desmosd init +# > docker run -it -p 46657:46657 -p 46656:46656 -v ~/.desmosd:/root/.desmosd -v ~/.desmoscli:/root/.desmoscli desmos desmosd start +FROM golang:alpine AS build-env + +# Set up dependencies +ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python + +# Set working directory for the build +WORKDIR /go/src/github.com/cosmos/desmos + +# Add source files +COPY . . + +# Install minimum necessary dependencies, build Cosmos SDK, remove packages +RUN apk add --no-cache $PACKAGES && \ + make tools && \ + make install + +# Final image +FROM alpine:edge + +# Install ca-certificates +RUN apk add --update ca-certificates +WORKDIR /root + +# Copy over binaries from the build-env +COPY --from=build-env /go/bin/desmosd /usr/bin/desmosd +COPY --from=build-env /go/bin/desmoscli /usr/bin/desmoscli + +# Run desmosd by default, omit entrypoint to ease using container with desmoscli +CMD ["desmosd"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..9c32a5c69a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,67 @@ +version: '3' + +services: + desmosdnode0: + container_name: desmosdnode0 + image: "desmos-labs/desmosdnode" + ports: + - "26656-26657:26656-26657" + environment: + - ID=0 + - LOG=${LOG:-desmosd.log} + volumes: + - ./build:/desmosd:Z + networks: + localnet: + ipv4_address: 192.168.10.2 + + desmosdnode1: + container_name: desmosdnode1 + image: "desmos-labs/desmosdnode" + ports: + - "26659-26660:26656-26657" + environment: + - ID=1 + - LOG=${LOG:-desmosd.log} + volumes: + - ./build:/desmosd:Z + networks: + localnet: + ipv4_address: 192.168.10.3 + + desmosdnode2: + container_name: desmosdnode2 + image: "desmos-labs/desmosdnode" + environment: + - ID=2 + - LOG=${LOG:-desmosd.log} + ports: + - "26661-26662:26656-26657" + volumes: + - ./build:/desmosd:Z + networks: + localnet: + ipv4_address: 192.168.10.4 + + desmosdnode3: + container_name: desmosdnode3 + image: "desmos-labs/desmosdnode" + environment: + - ID=3 + - LOG=${LOG:-desmosd.log} + ports: + - "26663-26664:26656-26657" + volumes: + - ./build:/desmosd:Z + networks: + localnet: + ipv4_address: 192.168.10.5 + +networks: + localnet: + driver: bridge + ipam: + driver: default + config: + - + subnet: 192.168.10.0/16 diff --git a/networks/local/Makefile b/networks/local/Makefile new file mode 100644 index 0000000000..45ad6cd916 --- /dev/null +++ b/networks/local/Makefile @@ -0,0 +1,6 @@ +# Makefile for the "desmosd" docker image. + +all: + docker build --tag desmos-labs/desmosdnode desmosdnode + +.PHONY: all \ No newline at end of file diff --git a/networks/local/desmosdnode/Dockerfile b/networks/local/desmosdnode/Dockerfile new file mode 100644 index 0000000000..0afe80ffd2 --- /dev/null +++ b/networks/local/desmosdnode/Dockerfile @@ -0,0 +1,23 @@ +#FROM alpine:3.10.2 +# +#RUN apk update && \ +# apk upgrade && \ +# apk --no-cache add curl jq file + +# Changed from Alpine to Ubuntu because the keyring PR is linking to libc +# Alpine uses muslc instead of libc + +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get -y upgrade && \ + apt-get -y install curl jq file + +VOLUME [ /desmosd ] +WORKDIR /desmosd +EXPOSE 26656 26657 +ENTRYPOINT ["/usr/bin/wrapper.sh"] +CMD ["start"] +STOPSIGNAL SIGTERM + +COPY wrapper.sh /usr/bin/wrapper.sh \ No newline at end of file diff --git a/networks/local/desmosdnode/wrapper.sh b/networks/local/desmosdnode/wrapper.sh new file mode 100644 index 0000000000..bc13f0ce96 --- /dev/null +++ b/networks/local/desmosdnode/wrapper.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env sh + +## +## Input parameters +## +BINARY=/desmosd/${BINARY:-desmosd} +ID=${ID:-0} +LOG=${LOG:-desmosd.log} + +## +## Assert linux binary +## +if ! [ -f "${BINARY}" ]; then + echo "The binary $(basename "${BINARY}") cannot be found. Please add the binary to the shared folder. Please use the BINARY environment variable if the name of the binary is not 'desmosd' E.g.: -e BINARY=desmosd_my_test_version" + exit 1 +fi +BINARY_CHECK="$(file "$BINARY" | grep 'ELF 64-bit LSB executable, x86-64')" +if [ -z "${BINARY_CHECK}" ]; then + echo "Binary needs to be OS linux, ARCH amd64" + exit 1 +fi + +## +## Run binary with all parameters +## +export DESMOSDHOME="/desmosd/node${ID}/desmosd" + +if [ -d "$(dirname "${DESMOSDHOME}"/"${LOG}")" ]; then + "${BINARY}" --home "${DESMOSDHOME}" "$@" | tee "${DESMOSDHOME}/${LOG}" +else + "${BINARY}" --home "${DESMOSDHOME}" "$@" +fi \ No newline at end of file From 3fab69132a60baac03d153b585826ffeaed40553 Mon Sep 17 00:00:00 2001 From: RiccardoM Date: Tue, 19 Nov 2019 09:31:27 +0100 Subject: [PATCH 2/3] Completed the localnet-start command fixing all the errors Signed-off-by: RiccardoM --- Makefile | 44 +++-- README.md | 95 ++++++++++- cmd/desmosd/main.go | 18 +- cmd/desmosd/testnet.go | 374 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 513 insertions(+), 18 deletions(-) create mode 100644 cmd/desmosd/testnet.go diff --git a/Makefile b/Makefile index 5ac3fb93a9..14e1be56a2 100644 --- a/Makefile +++ b/Makefile @@ -39,29 +39,31 @@ all: lint install ### Install install: go.sum - go install -mod=readonly $(BUILD_FLAGS) ./cmd/desmosd/main.go - go install -mod=readonly $(BUILD_FLAGS) ./cmd/desmoscli/main.go - go install -mod=readonly $(BUILD_FLAGS) ./cmd/desmoskeyutil/main.go + go install -mod=readonly $(BUILD_FLAGS) ./cmd/desmosd + go install -mod=readonly $(BUILD_FLAGS) ./cmd/desmoscli + go install -mod=readonly $(BUILD_FLAGS) ./cmd/desmoskeyutil ######################################## ### Build build: go.sum ifeq ($(OS),Windows_NT) - go build -mod=readonly $(BUILD_FLAGS) -o ./build/desmod.exe ./cmd/desmosd/main.go - go build -mod=readonly $(BUILD_FLAGS) -o ./build/desmoscli.exe ./cmd/desmoscli/main.go + go build -mod=readonly $(BUILD_FLAGS) -o ./build/desmod.exe ./cmd/desmosd + go build -mod=readonly $(BUILD_FLAGS) -o ./build/desmoscli.exe ./cmd/desmoscli else - go build -mod=readonly $(BUILD_FLAGS) -o ./build/desmosd ./cmd/desmosd/main.go - go build -mod=readonly $(BUILD_FLAGS) -o ./build/desmoscli ./cmd/desmoscli/main.go + go build -mod=readonly $(BUILD_FLAGS) -o ./build/desmosd ./cmd/desmosd + go build -mod=readonly $(BUILD_FLAGS) -o ./build/desmoscli ./cmd/desmoscli endif +build-linux: go.sum + LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build + ######################################## ### Tools & dependencies go-mod-cache: go.sum @echo "--> Download go modules to local cache" @go mod download -.PHONY: go-mod-cache go.sum: go.mod @echo "--> Ensure dependencies have not been modified" @@ -76,7 +78,27 @@ lint: ######################################## ### Testing -test: test_unit +test: test-unit + +test-unit: + @VERSION=$(VERSION) go test -mod=readonly $(PACKAGES_NOSIMULATION) -tags='ledger test_ledger_mock' + + +######################################## +### Local validator nodes using docker and docker-compose + +build-docker-desmosdnode: + $(MAKE) -C networks/local + +# Run a 4-node testnet locally +localnet-start: build-docker-desmosdnode build-linux localnet-stop + @if ! [ -f build/node0/desmosd/config/genesis.json ]; then docker run -e COSMOS_SDK_TEST_KEYRING=y --rm -v $(CURDIR)/build:/desmosd:Z desmos-labs/desmosdnode testnet --v 4 -o . --starting-ip-address 192.168.10.2 ; fi + docker-compose up -d + +# Stop testnet +localnet-stop: + docker-compose down -test_unit: - @VERSION=$(VERSION) go test -mod=readonly $(PACKAGES_NOSIMULATION) -tags='ledger test_ledger_mock' \ No newline at end of file +.PHONY: all build-linux install \ + go-mod-cache build \ + test test-unit \ No newline at end of file diff --git a/README.md b/README.md index 1f5b5a599c..efc4476e6e 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,13 @@ Desmos social chain ## Installation - ``` sh make install ``` ## Start a testnet +### Single node, manual Run the [desmos-faucet](https://github.com/desmos-labs/desmos-faucet). ``` sh @@ -33,3 +33,96 @@ Edit `$HOME/.desmosd/config/genesis.json` and update the `bond_denom` from `stak ``` sh desmosd start ``` + +### Multi node, automatic +To start a 4 node testnet run: + +``` +make localnet-start +``` + +This command creates a 4-node network using the demsosdnode image. +The ports for each node are found in this table: + +| Node ID | P2P Port | RPC Port | +| --------|-------|------| +| `desmosdnode0` | `26656` | `26657` | +| `desmosdnode1` | `26659` | `26660` | +| `desmosdnode2` | `26661` | `26662` | +| `desmosdnode3` | `26663` | `26664` | + +To update the binary, just rebuild it and restart the nodes: + +``` +make build-linux localnet-start +``` + +#### Configuration + +The `make localnet-start` creates files for a 4-node testnet in `./build` by +calling the `demosd testnet` command. This outputs a handful of files in the +`./build` directory: + +```bash +$ tree -L 2 build/ +build/ +├── desmoscli +├── desmosd +├── gentxs +│ ├── node0.json +│ ├── node1.json +│ ├── node2.json +│ └── node3.json +├── node0 +│ ├── desmoscli +│ │ ├── key_seed.json +│ │ └── keys +│ └── desmosd +│ ├── ${LOG:-desmosd.log} +│ ├── config +│ └── data +├── node1 +│ ├── desmoscli +│ │ └── key_seed.json +│ └── desmosd +│ ├── ${LOG:-desmosd.log} +│ ├── config +│ └── data +├── node2 +│ ├── desmoscli +│ │ └── key_seed.json +│ └── desmosd +│ ├── ${LOG:-desmosd.log} +│ ├── config +│ └── data +└── node3 + ├── desmoscli + │ └── key_seed.json + └── desmosd + ├── ${LOG:-desmosd.log} + ├── config + └── data +``` + +Each `./build/nodeN` directory is mounted to the `/desmosd` directory in each container. + +#### Logging +Logs are saved under each `./build/nodeN/desmosd/desmos.log`. You can also watch logs +directly via Docker, for example: + +``` +docker logs -f desmosdnode0 +``` + +#### Keys & Accounts +To interact with `desmoscli` and start querying state or creating txs, you use the +`desmoscli` directory of any given node as your `home`, for example: + +```shell +desmoscli keys list --home ./build/node0/desmoscli +``` + +Now that accounts exists, you may create new accounts and send those accounts +funds! + +**Note**: Each node's seed is located at `./build/nodeN/desmoscli/key_seed.json` and can be restored to the CLI using the `desmoscli keys add --restore` command \ No newline at end of file diff --git a/cmd/desmosd/main.go b/cmd/desmosd/main.go index 850931cf67..86c2f32c57 100644 --- a/cmd/desmosd/main.go +++ b/cmd/desmosd/main.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "github.com/cosmos/cosmos-sdk/client" "io" "github.com/cosmos/cosmos-sdk/server" @@ -42,14 +43,19 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } // CLI commands to initialize the chain + rootCmd.AddCommand(genutilcli.InitCmd(ctx, cdc, app.ModuleBasics, app.DefaultNodeHome)) + rootCmd.AddCommand(genutilcli.CollectGenTxsCmd(ctx, cdc, genaccounts.AppModuleBasic{}, app.DefaultNodeHome)) + rootCmd.AddCommand(genutilcli.MigrateGenesisCmd(ctx, cdc)) rootCmd.AddCommand( - genutilcli.InitCmd(ctx, cdc, app.ModuleBasics, app.DefaultNodeHome), - genutilcli.CollectGenTxsCmd(ctx, cdc, genaccounts.AppModuleBasic{}, app.DefaultNodeHome), - genutilcli.GenTxCmd(ctx, cdc, app.ModuleBasics, staking.AppModuleBasic{}, genaccounts.AppModuleBasic{}, app.DefaultNodeHome, app.DefaultCLIHome), - genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics), - // AddGenesisAccountCmd allows users to add accounts to the genesis file - genaccscli.AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome), + genutilcli.GenTxCmd( + ctx, cdc, app.ModuleBasics, staking.AppModuleBasic{}, + genaccounts.AppModuleBasic{}, app.DefaultNodeHome, app.DefaultCLIHome, + ), ) + rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics)) + rootCmd.AddCommand(genaccscli.AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome)) + rootCmd.AddCommand(client.NewCompletionCmd(rootCmd, true)) + rootCmd.AddCommand(testnetCmd(ctx, cdc, app.ModuleBasics, genaccounts.AppModuleBasic{})) server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators) diff --git a/cmd/desmosd/testnet.go b/cmd/desmosd/testnet.go new file mode 100644 index 0000000000..6f338e4b78 --- /dev/null +++ b/cmd/desmosd/testnet.go @@ -0,0 +1,374 @@ +package main + +// DONTCOVER + +import ( + "bufio" + "encoding/json" + "fmt" + "github.com/cosmos/cosmos-sdk/x/genaccounts" + "net" + "os" + "path/filepath" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + tmconfig "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/crypto" + cmn "github.com/tendermint/tendermint/libs/common" + "github.com/tendermint/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + srvconfig "github.com/cosmos/cosmos-sdk/server/config" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +var ( + flagNodeDirPrefix = "node-dir-prefix" + flagNumValidators = "v" + flagOutputDir = "output-dir" + flagNodeDaemonHome = "node-daemon-home" + flagNodeCLIHome = "node-cli-home" + flagStartingIPAddress = "starting-ip-address" +) + +// get cmd to initialize all files for tendermint testnet and application +func testnetCmd(ctx *server.Context, cdc *codec.Codec, + mbm module.BasicManager, genAccIterator genutiltypes.GenesisAccountsIterator, +) *cobra.Command { + + cmd := &cobra.Command{ + Use: "testnet", + Short: "Initialize files for a Desmosd testnet", + Long: `testnet will create "v" number of directories and populate each with +necessary files (private validator, genesis, config, etc.). + +Note, strict routability for addresses is turned off in the config file. + +Example: + gaiad testnet --v 4 --output-dir ./output --starting-ip-address 192.168.10.2 + `, + RunE: func(cmd *cobra.Command, _ []string) error { + config := ctx.Config + + outputDir := viper.GetString(flagOutputDir) + chainID := viper.GetString(client.FlagChainID) + minGasPrices := viper.GetString(server.FlagMinGasPrices) + nodeDirPrefix := viper.GetString(flagNodeDirPrefix) + nodeDaemonHome := viper.GetString(flagNodeDaemonHome) + nodeCLIHome := viper.GetString(flagNodeCLIHome) + startingIPAddress := viper.GetString(flagStartingIPAddress) + numValidators := viper.GetInt(flagNumValidators) + + return InitTestnet(cmd, config, cdc, mbm, genAccIterator, outputDir, chainID, + minGasPrices, nodeDirPrefix, nodeDaemonHome, nodeCLIHome, startingIPAddress, numValidators) + }, + } + + cmd.Flags().Int(flagNumValidators, 4, + "Number of validators to initialize the testnet with") + cmd.Flags().StringP(flagOutputDir, "o", "./mytestnet", + "Directory to store initialization data for the testnet") + cmd.Flags().String(flagNodeDirPrefix, "node", + "Prefix the directory name for each node with (node results in node0, node1, ...)") + cmd.Flags().String(flagNodeDaemonHome, "desmosd", + "Home directory of the node's daemon configuration") + cmd.Flags().String(flagNodeCLIHome, "desmoscli", + "Home directory of the node's cli configuration") + cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", + "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)") + cmd.Flags().String( + client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") + cmd.Flags().String( + server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), + "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)") + return cmd +} + +const nodeDirPerm = 0755 + +// Initialize the testnet +func InitTestnet(cmd *cobra.Command, config *tmconfig.Config, cdc *codec.Codec, + mbm module.BasicManager, genAccIterator genutiltypes.GenesisAccountsIterator, + outputDir, chainID, minGasPrices, nodeDirPrefix, nodeDaemonHome, + nodeCLIHome, startingIPAddress string, numValidators int) error { + + if chainID == "" { + chainID = "chain-" + cmn.RandStr(6) + } + + monikers := make([]string, numValidators) + nodeIDs := make([]string, numValidators) + valPubKeys := make([]crypto.PubKey, numValidators) + + gaiaConfig := srvconfig.DefaultConfig() + gaiaConfig.MinGasPrices = minGasPrices + + var ( + genAccounts []genaccounts.GenesisAccount + genFiles []string + ) + + // generate private keys, node IDs, and initial transactions + for i := 0; i < numValidators; i++ { + nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i) + nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome) + clientDir := filepath.Join(outputDir, nodeDirName, nodeCLIHome) + gentxsDir := filepath.Join(outputDir, "gentxs") + + config.SetRoot(nodeDir) + config.RPC.ListenAddress = "tcp://0.0.0.0:26657" + + if err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm); err != nil { + _ = os.RemoveAll(outputDir) + return err + } + + if err := os.MkdirAll(clientDir, nodeDirPerm); err != nil { + _ = os.RemoveAll(outputDir) + return err + } + + monikers = append(monikers, nodeDirName) + config.Moniker = nodeDirName + + ip, err := getIP(i, startingIPAddress) + if err != nil { + _ = os.RemoveAll(outputDir) + return err + } + + nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(config) + if err != nil { + _ = os.RemoveAll(outputDir) + return err + } + + memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip) + genFiles = append(genFiles, config.GenesisFile()) + + buf := bufio.NewReader(cmd.InOrStdin()) + prompt := fmt.Sprintf( + "Password for account '%s' (default %s):", nodeDirName, client.DefaultKeyPass, + ) + + keyPass, err := client.GetPassword(prompt, buf) + if err != nil && keyPass != "" { + // An error was returned that either failed to read the password from + // STDIN or the given password is not empty but failed to meet minimum + // length requirements. + return err + } + + if keyPass == "" { + keyPass = client.DefaultKeyPass + } + + addr, secret, err := server.GenerateSaveCoinKey(clientDir, nodeDirName, keyPass, true) + if err != nil { + _ = os.RemoveAll(outputDir) + return err + } + + info := map[string]string{"secret": secret} + + cliPrint, err := json.Marshal(info) + if err != nil { + return err + } + + // save private key seed words + if err := writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, cliPrint); err != nil { + return err + } + + accTokens := sdk.TokensFromConsensusPower(1000) + accStakingTokens := sdk.TokensFromConsensusPower(500) + coins := sdk.Coins{ + sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), accTokens), + sdk.NewCoin(sdk.DefaultBondDenom, accStakingTokens), + } + genAccounts = append(genAccounts, genaccounts.NewGenesisAccount(auth.NewBaseAccount(addr, coins.Sort(), nil, 0, 0))) + + valTokens := sdk.TokensFromConsensusPower(100) + msg := staking.NewMsgCreateValidator( + sdk.ValAddress(addr), + valPubKeys[i], + sdk.NewCoin(sdk.DefaultBondDenom, valTokens), + staking.NewDescription(nodeDirName, "", "", ""), + staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), + sdk.OneInt(), + ) + + kb, err := keys.NewKeyBaseFromDir(clientDir) + if err != nil { + return err + } + + tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo) + txBldr := auth.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo).WithKeybase(kb) + + signedTx, err := txBldr.SignStdTx(nodeDirName, client.DefaultKeyPass, tx, false) + if err != nil { + _ = os.RemoveAll(outputDir) + return err + } + + txBytes, err := cdc.MarshalJSON(signedTx) + if err != nil { + _ = os.RemoveAll(outputDir) + return err + } + + // gather gentxs folder + if err := writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes); err != nil { + _ = os.RemoveAll(outputDir) + return err + } + + gaiaConfigFilePath := filepath.Join(nodeDir, "config/gaiad.toml") + srvconfig.WriteConfigFile(gaiaConfigFilePath, gaiaConfig) + } + + if err := initGenFiles(cdc, mbm, chainID, genAccounts, genFiles, numValidators); err != nil { + return err + } + + err := collectGenFiles( + cdc, config, chainID, monikers, nodeIDs, valPubKeys, numValidators, + outputDir, nodeDirPrefix, nodeDaemonHome, genAccIterator, + ) + if err != nil { + return err + } + + cmd.PrintErrf("Successfully initialized %d node directories\n", numValidators) + return nil +} + +func initGenFiles( + cdc *codec.Codec, mbm module.BasicManager, chainID string, + genAccounts []genaccounts.GenesisAccount, genFiles []string, numValidators int, +) error { + + appGenState := mbm.DefaultGenesis() + + // set the genesisAccounts in the genesis state + appGenState[genaccounts.ModuleName] = cdc.MustMarshalJSON(genaccounts.GenesisState(genAccounts)) + + appGenStateJSON, err := codec.MarshalJSONIndent(cdc, appGenState) + if err != nil { + return err + } + + genDoc := types.GenesisDoc{ + ChainID: chainID, + AppState: appGenStateJSON, + Validators: nil, + } + + // generate empty genesis files for each validator and save + for i := 0; i < numValidators; i++ { + if err := genDoc.SaveAs(genFiles[i]); err != nil { + return err + } + } + return nil +} + +func collectGenFiles( + cdc *codec.Codec, config *tmconfig.Config, chainID string, + monikers, nodeIDs []string, valPubKeys []crypto.PubKey, + numValidators int, outputDir, nodeDirPrefix, nodeDaemonHome string, + genAccIterator genutiltypes.GenesisAccountsIterator) error { + + var appState json.RawMessage + genTime := tmtime.Now() + + for i := 0; i < numValidators; i++ { + nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i) + nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome) + gentxsDir := filepath.Join(outputDir, "gentxs") + moniker := monikers[i] + config.Moniker = nodeDirName + + config.SetRoot(nodeDir) + + nodeID, valPubKey := nodeIDs[i], valPubKeys[i] + initCfg := genutil.NewInitConfig(chainID, gentxsDir, moniker, nodeID, valPubKey) + + genDoc, err := types.GenesisDocFromFile(config.GenesisFile()) + if err != nil { + return err + } + + nodeAppState, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genAccIterator) + if err != nil { + return err + } + + if appState == nil { + // set the canonical application state (they should not differ) + appState = nodeAppState + } + + genFile := config.GenesisFile() + + // overwrite each validator's genesis file to have a canonical genesis time + if err := genutil.ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime); err != nil { + return err + } + } + + return nil +} + +func getIP(i int, startingIPAddr string) (ip string, err error) { + if len(startingIPAddr) == 0 { + ip, err = server.ExternalIP() + if err != nil { + return "", err + } + return ip, nil + } + return calculateIP(startingIPAddr, i) +} + +func calculateIP(ip string, i int) (string, error) { + ipv4 := net.ParseIP(ip).To4() + if ipv4 == nil { + return "", fmt.Errorf("%v: non ipv4 address", ip) + } + + for j := 0; j < i; j++ { + ipv4[3]++ + } + + return ipv4.String(), nil +} + +func writeFile(name string, dir string, contents []byte) error { + writePath := filepath.Join(dir) + file := filepath.Join(writePath, name) + + err := cmn.EnsureDir(writePath, 0700) + if err != nil { + return err + } + + err = cmn.WriteFile(file, contents, 0600) + if err != nil { + return err + } + + return nil +} From 1f59cc3fc3d0bb5ba8d6ac9455c83954d3d47c31 Mon Sep 17 00:00:00 2001 From: RiccardoM Date: Wed, 20 Nov 2019 07:33:30 +0100 Subject: [PATCH 3/3] Fixes - Fixed some typo into the README - Updated the chmod index of wrapper.sh - Updated the Docker image organization name Signed-off-by: RiccardoM --- README.md | 4 ++-- docker-compose.yml | 8 ++++---- networks/local/Makefile | 2 +- networks/local/desmosdnode/wrapper.sh | 0 4 files changed, 7 insertions(+), 7 deletions(-) mode change 100644 => 100755 networks/local/desmosdnode/wrapper.sh diff --git a/README.md b/README.md index efc4476e6e..cc65a8a01c 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ To start a 4 node testnet run: make localnet-start ``` -This command creates a 4-node network using the demsosdnode image. +This command creates a 4-node network using the `desmoslabs/desmosdnode` image. The ports for each node are found in this table: | Node ID | P2P Port | RPC Port | @@ -60,7 +60,7 @@ make build-linux localnet-start #### Configuration The `make localnet-start` creates files for a 4-node testnet in `./build` by -calling the `demosd testnet` command. This outputs a handful of files in the +calling the `desmosd testnet` command. This outputs a handful of files in the `./build` directory: ```bash diff --git a/docker-compose.yml b/docker-compose.yml index 9c32a5c69a..f934a35660 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ version: '3' services: desmosdnode0: container_name: desmosdnode0 - image: "desmos-labs/desmosdnode" + image: "desmoslabs/desmosdnode" ports: - "26656-26657:26656-26657" environment: @@ -17,7 +17,7 @@ services: desmosdnode1: container_name: desmosdnode1 - image: "desmos-labs/desmosdnode" + image: "desmoslabs/desmosdnode" ports: - "26659-26660:26656-26657" environment: @@ -31,7 +31,7 @@ services: desmosdnode2: container_name: desmosdnode2 - image: "desmos-labs/desmosdnode" + image: "desmoslabs/desmosdnode" environment: - ID=2 - LOG=${LOG:-desmosd.log} @@ -45,7 +45,7 @@ services: desmosdnode3: container_name: desmosdnode3 - image: "desmos-labs/desmosdnode" + image: "desmoslabs/desmosdnode" environment: - ID=3 - LOG=${LOG:-desmosd.log} diff --git a/networks/local/Makefile b/networks/local/Makefile index 45ad6cd916..6b184c9a91 100644 --- a/networks/local/Makefile +++ b/networks/local/Makefile @@ -1,6 +1,6 @@ # Makefile for the "desmosd" docker image. all: - docker build --tag desmos-labs/desmosdnode desmosdnode + docker build --tag desmoslabs/desmosdnode desmosdnode .PHONY: all \ No newline at end of file diff --git a/networks/local/desmosdnode/wrapper.sh b/networks/local/desmosdnode/wrapper.sh old mode 100644 new mode 100755