diff --git a/app/data/compose/docker-compose-mainnet-laconicd.yml b/app/data/compose/docker-compose-mainnet-laconicd.yml index 78d2cd2f..d42c6a7c 100644 --- a/app/data/compose/docker-compose-mainnet-laconicd.yml +++ b/app/data/compose/docker-compose-mainnet-laconicd.yml @@ -2,14 +2,16 @@ services: laconicd: restart: no image: cerc/laconicd:local - command: ["/bin/sh", "-c", "while :; do sleep 600; done"] + command: ["/bin/sh", "-c", "/opt/run-laconicd.sh"] volumes: # The cosmos-sdk node's database directory: - laconicd-data:/root/.laconicd/data + - laconicd-config:/root/.laconicd/config + - laconicd-keyring:/root/.laconicd/keyring-test # TODO: look at folding these scripts into the container - - ../config/mainnet-laconicd/create-fixturenet.sh:/docker-entrypoint-scripts.d/create-fixturenet.sh - - ../config/mainnet-laconicd/export-mykey.sh:/docker-entrypoint-scripts.d/export-mykey.sh - - ../config/mainnet-laconicd/export-myaddress.sh:/docker-entrypoint-scripts.d/export-myaddress.sh + - ../config/mainnet-laconicd/scripts/run-laconicd.sh:/opt/run-laconicd.sh + - ../config/mainnet-laconicd/scripts/export-mykey.sh:/docker-entrypoint-scripts.d/export-mykey.sh + - ../config/mainnet-laconicd/scripts/export-myaddress.sh:/docker-entrypoint-scripts.d/export-myaddress.sh # TODO: determine which of the ports below is really needed ports: - "6060" @@ -28,3 +30,5 @@ services: volumes: laconicd-data: + laconicd-config: + laconicd-keyring: diff --git a/app/data/config/mainnet-laconicd/create-fixturenet.sh b/app/data/config/mainnet-laconicd/create-fixturenet.sh deleted file mode 100644 index 9c30bff8..00000000 --- a/app/data/config/mainnet-laconicd/create-fixturenet.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash - -# TODO: this file is now an unmodified copy of cerc-io/laconicd/init.sh -# so we should have a mechanism to bundle it inside the container rather than link from here -# at deploy time. - -KEY="mykey" -CHAINID="laconic_9000-1" -MONIKER="localtestnet" -KEYRING="test" -KEYALGO="eth_secp256k1" -LOGLEVEL="info" -# trace evm -TRACE="--trace" -# TRACE="" - -# validate dependencies are installed -command -v jq > /dev/null 2>&1 || { echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"; exit 1; } - -# remove existing daemon and client -rm -rf ~/.laconic* - -make install - -laconicd config keyring-backend $KEYRING -laconicd config chain-id $CHAINID - -# if $KEY exists it should be deleted -laconicd keys add $KEY --keyring-backend $KEYRING --algo $KEYALGO - -# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer) -laconicd init $MONIKER --chain-id $CHAINID - -# Change parameter token denominations to aphoton -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["staking"]["params"]["bond_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["crisis"]["constant_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -# Custom modules -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - -if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then - echo "Setting timers for expiry tests." - - cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -fi - -if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then - echo "Enabling auction and setting timers." - - cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_enabled"]=true' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="300s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commits_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveals_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json -fi - -# increase block time (?) -cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["time_iota_ms"]="1000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - -# Set gas limit in genesis -cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="10000000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json - -# disable produce empty block -if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml - else - sed -i 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml -fi - -if [[ $1 == "pending" ]]; then - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml - sed -i '' 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml - sed -i '' 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml - sed -i '' 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml - sed -i '' 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml - sed -i '' 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml - sed -i '' 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml - sed -i '' 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml - sed -i '' 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml - else - sed -i 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml - sed -i 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml - sed -i 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml - sed -i 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml - sed -i 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml - sed -i 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml - sed -i 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml - sed -i 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml - sed -i 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml - fi -fi - -# Allocate genesis accounts (cosmos formatted addresses) -laconicd add-genesis-account $KEY 100000000000000000000000000aphoton --keyring-backend $KEYRING - -# Sign genesis transaction -laconicd gentx $KEY 1000000000000000000000aphoton --keyring-backend $KEYRING --chain-id $CHAINID - -# Collect genesis tx -laconicd collect-gentxs - -# Run this to ensure everything worked and that the genesis file is setup correctly -laconicd validate-genesis - -if [[ $1 == "pending" ]]; then - echo "pending mode is on, please wait for the first block committed." -fi - -# Start the node (remove the --pruning=nothing flag if historical queries are not needed) -laconicd start --pruning=nothing --evm.tracer=json $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton --json-rpc.api eth,txpool,personal,net,debug,web3,miner --api.enable --gql-server --gql-playground diff --git a/app/data/config/mainnet-laconicd/export-myaddress.sh b/app/data/config/mainnet-laconicd/scripts/export-myaddress.sh similarity index 100% rename from app/data/config/mainnet-laconicd/export-myaddress.sh rename to app/data/config/mainnet-laconicd/scripts/export-myaddress.sh diff --git a/app/data/config/mainnet-laconicd/export-mykey.sh b/app/data/config/mainnet-laconicd/scripts/export-mykey.sh similarity index 100% rename from app/data/config/mainnet-laconicd/export-mykey.sh rename to app/data/config/mainnet-laconicd/scripts/export-mykey.sh diff --git a/app/data/config/mainnet-laconicd/scripts/run-laconicd.sh b/app/data/config/mainnet-laconicd/scripts/run-laconicd.sh new file mode 100755 index 00000000..50a82c69 --- /dev/null +++ b/app/data/config/mainnet-laconicd/scripts/run-laconicd.sh @@ -0,0 +1,18 @@ +#!/bin/sh +if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then + set -x +fi + +#TODO: pass these in from the caller +TRACE="--trace" +LOGLEVEL="info" + +laconicd start \ + --pruning=nothing \ + --evm.tracer=json $TRACE \ + --log_level $LOGLEVEL \ + --minimum-gas-prices=0.0001aphoton \ + --json-rpc.api eth,txpool,personal,net,debug,web3,miner \ + --api.enable \ + --gql-server \ + --gql-playground diff --git a/app/data/stacks/mainnet-laconic/deploy/commands.py b/app/data/stacks/mainnet-laconic/deploy/commands.py index 643b7d51..932dbc24 100644 --- a/app/data/stacks/mainnet-laconic/deploy/commands.py +++ b/app/data/stacks/mainnet-laconic/deploy/commands.py @@ -14,9 +14,13 @@ # along with this program. If not, see . from app.util import get_yaml -from app.deploy_types import DeployCommandContext +from app.deploy_types import DeployCommandContext, LaconicStackSetupCommand from app.stack_state import State from app.deploy_util import VolumeMapping, run_container_command +from enum import Enum +from pathlib import Path +import os +import sys default_spec_file_content = """config: node_moniker: my-node-name @@ -27,15 +31,99 @@ init_help_text = """Add helpful text here on setting config variables. """ -def setup(command_context: DeployCommandContext, extra_args): - node_moniker = "dbdb-node" - chain_id = "laconic_81337-1" - mounts = [ - VolumeMapping("./path", "/root/.laconicd") - ] - output, status = run_container_command( - command_context, "laconicd", f"laconicd init {node_moniker} --chain-id {chain_id}", mounts) - print(f"Command output: {output}") +class SetupPhase(Enum): + INITIALIZE = 1 + JOIN = 2 + CREATE = 3 + ILLEGAL = 3 + + +def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCommand, extra_args): + + print(f"parameters: {parameters}") + + phase = SetupPhase.ILLEGAL + + if parameters.initialize_network: + if parameters.join_network or parameters.create_network: + print("Can't supply --join-network or --create-network with --initialize-network") + sys.exit(1) + if not parameters.chain_id: + print("--chain-id is required") + sys.exit(1) + phase = SetupPhase.INITIALIZE + elif parameters.join_network: + if parameters.initialize_network or parameters.create_network: + print("Can't supply --initialize-network or --create-network with --join-network") + sys.exit(1) + phase = SetupPhase.JOIN + elif parameters.create_network: + if parameters.initialize_network or parameters.join_network: + print("Can't supply --initialize-network or --join-network with --create-network") + sys.exit(1) + phase = SetupPhase.CREATE + + if phase == SetupPhase.INITIALIZE: + network_dir = Path(parameters.network_dir).absolute() + # We want to create the directory so if it exists that's an error + if os.path.exists(network_dir): + print(f"Error: network directory {network_dir} already exists") + sys.exit(1) + os.mkdir(network_dir) + mounts = [ + VolumeMapping(network_dir, "/root/.laconicd") + ] + output, status = run_container_command( + command_context, "laconicd", f"laconicd init {parameters.node_moniker} --chain-id {parameters.chain_id}", mounts) + print(f"Command output: {output}") + + elif phase == SetupPhase.JOIN: + network_dir = Path(parameters.network_dir).absolute() + # We want to create the directory so if it exists that's an error + if not os.path.exists(network_dir): + print(f"Error: network directory {network_dir} doesn't exist") + sys.exit(1) + mounts = [ + VolumeMapping(network_dir, "/root/.laconicd") + ] + output1, status1 = run_container_command( + command_context, "laconicd", f"laconicd keys add {parameters.key_name} --keyring-backend test", mounts) + print(f"Command output: {output1}") + output2, status2 = run_container_command( + command_context, + "laconicd", + f"laconicd add-genesis-account {parameters.key_name} 12900000000000000000000achk --keyring-backend test", + mounts) + print(f"Command output: {output2}") + output3, status3 = run_container_command( + command_context, + "laconicd", + f"laconicd gentx {parameters.key_name} 90000000000achk --chain-id {parameters.chain_id} --keyring-backend test", + mounts) + print(f"Command output: {output3}") + + elif phase == SetupPhase.CREATE: + network_dir = Path(parameters.network_dir).absolute() + # We want to create the directory so if it exists that's an error + if not os.path.exists(network_dir): + print(f"Error: network directory {network_dir} doesn't exist") + sys.exit(1) + mounts = [ + VolumeMapping(network_dir, "/root/.laconicd") + ] + output1, status1 = run_container_command( + command_context, "laconicd", "laconicd collect-gentxs", mounts) + print(f"Command output: {output1}") + output2, status1 = run_container_command( + command_context, "laconicd", "laconicd validate-genesis", mounts) + print(f"Command output: {output2}") + else: + print("Illegal parameters supplied") + sys.exit(1) + + +def create(command_context: DeployCommandContext): + print("Copy the network files here") def init(command_context: DeployCommandContext): diff --git a/app/deploy_types.py b/app/deploy_types.py index c6df5784..b61a82d1 100644 --- a/app/deploy_types.py +++ b/app/deploy_types.py @@ -45,3 +45,14 @@ class DeploymentContext: class VolumeMapping: host_path: str container_path: str + + +@dataclass +class LaconicStackSetupCommand: + chain_id: str + node_moniker: str + key_name: str + initialize_network: bool + join_network: bool + create_network: bool + network_dir: str diff --git a/app/deployment_create.py b/app/deployment_create.py index af5eefb2..c183d898 100644 --- a/app/deployment_create.py +++ b/app/deployment_create.py @@ -20,8 +20,9 @@ import os from pathlib import Path from shutil import copyfile, copytree import sys -from app.util import get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, global_options, get_yaml, get_compose_file_dir -from app.deploy_types import DeploymentContext, DeployCommandContext +from app.util import get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, global_options, get_yaml +from app.util import get_compose_file_dir +from app.deploy_types import DeploymentContext, LaconicStackSetupCommand def _make_default_deployment_dir(): @@ -94,7 +95,7 @@ def call_stack_deploy_init(deploy_command_context): # TODO: fold this with function above -def call_stack_deploy_setup(deploy_command_context, extra_args): +def call_stack_deploy_setup(deploy_command_context, parameters: LaconicStackSetupCommand, extra_args): # Link with the python file in the stack # Call a function in it # If no function found, return None @@ -102,7 +103,7 @@ def call_stack_deploy_setup(deploy_command_context, extra_args): spec = util.spec_from_file_location("commands", python_file_path) imported_stack = util.module_from_spec(spec) spec.loader.exec_module(imported_stack) - return imported_stack.setup(deploy_command_context, extra_args) + return imported_stack.setup(deploy_command_context, parameters, extra_args) # TODO: fold this with function above @@ -213,13 +214,20 @@ def create(ctx, spec_file, deployment_dir): call_stack_deploy_create(deployment_context) +# TODO: this code should be in the stack .py files but +# we haven't yet figured out how to integrate click across +# the plugin boundary @click.command() -@click.option("--node-moniker", help="Help goes here") -@click.option("--key-name", help="Help goes here") -@click.option("--initialize-network", is_flag=True, default=False, help="Help goes here") -@click.option("--join-network", is_flag=True, default=False, help="Help goes here") -@click.option("--create-network", is_flag=True, default=False, help="Help goes here") +@click.option("--node-moniker", help="Moniker for this node") +@click.option("--chain-id", help="Supply the new chain id") +@click.option("--key-name", help="Name for new node key") +@click.option("--initialize-network", is_flag=True, default=False, help="Initialize phase") +@click.option("--join-network", is_flag=True, default=False, help="Join phase") +@click.option("--create-network", is_flag=True, default=False, help="Create phase") +@click.option("--network-dir", required=True, help="Directory for network files") @click.argument('extra_args', nargs=-1) @click.pass_context -def setup(ctx, node_moniker, key_name, initialize_network, join_network, create_network, extra_args): - call_stack_deploy_setup(ctx.obj, extra_args) +def setup(ctx, node_moniker, chain_id, key_name, initialize_network, join_network, create_network, network_dir, extra_args): + parmeters = LaconicStackSetupCommand(chain_id, node_moniker, key_name, initialize_network, join_network, create_network, + network_dir) + call_stack_deploy_setup(ctx.obj, parmeters, extra_args) diff --git a/app/stack_state.py b/app/stack_state.py index 830a47f7..d4e3e7af 100644 --- a/app/stack_state.py +++ b/app/stack_state.py @@ -15,6 +15,7 @@ from enum import Enum + class State(Enum): CREATED = 1 CONFIGURED = 2