diff --git a/.github/scripts/check_finalization.sh b/.github/scripts/check_finalization.sh new file mode 100755 index 0000000000..36d21ad191 --- /dev/null +++ b/.github/scripts/check_finalization.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +RPC_HOST=127.0.0.1 +RPC_PORT=9933 +LAST_FINALIZED="" +VALIDATOR=damian + +while [[ "$LAST_FINALIZED" =~ "0x0" ]] || [[ -z "$LAST_FINALIZED" ]]; do + block_hash=$(docker run --network container:$VALIDATOR appropriate/curl:latest \ + -H "Content-Type: application/json" \ + -d '{"id":1, "jsonrpc":"2.0", "method": "chain_getFinalizedHead"}' http://$RPC_HOST:$RPC_PORT | jq '.result') + ret_val=$? + if [ $ret_val -ne 0 ]; then + echo "failed calling the `chain_getFinalizedHead` method" >&2 + continue + fi + + finalized_block=$(docker run --network container:$VALIDATOR appropriate/curl:latest \ + -H "Content-Type: application/json" \ + -d '{"id":1, "jsonrpc":"2.0", "method": "chain_getBlock", "params": ['$block_hash']}' http://$RPC_HOST:$RPC_PORT | jq '.result.block.header.number') + + ret_val=$? + if [ $ret_val -ne 0 ]; then + echo "failed calling the `chain_getBlock` method" >&2 + continue + else + LAST_FINALIZED=$finalized_block + echo "Last finalized block number: $LAST_FINALIZED" + fi + +done + +exit $? diff --git a/.github/scripts/generate_chainspec.sh b/.github/scripts/generate_chainspec.sh new file mode 100755 index 0000000000..ce0c3fd498 --- /dev/null +++ b/.github/scripts/generate_chainspec.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e + +# populate validators keystore and generate chainspec +chmod +x target/release/aleph-node +./target/release/aleph-node bootstrap-chain --base-path docker/data --chain-id a0dnet1 --n-members 4 --session-period 5 --millisecs-per-block 1000 > docker/data/chainspec.json + +echo "Done" +exit $? diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index 1906eb6263..1698196427 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -110,48 +110,34 @@ jobs: - name: Build docker image id: build-image run: | + # copy downloaded artifact to the path that the scripts expect mkdir -p target/release/ - # copy artifact cp aleph-node target/release/aleph-node - # Build and tag a docker container docker build --tag aleph-node:latest -f ./docker/Dockerfile . - - name: Generate chainspec - run: | - # populate validators keystore and generate chainspec - chmod +x target/release/aleph-node - ./target/release/aleph-node bootstrap-chain --base-path docker/data --chain-id a0tnet1 > docker/data/chainspec.json + - name: Generate chainspec and populate comittee keystores + shell: bash + run: ./.github/scripts/generate_chainspec.sh - name: Run consensus party - run: | - docker-compose --env-file docker/.env -f docker/docker-compose.yml up -d + run: docker-compose -f docker/docker-compose.yml up -d - - name: Consensus party logs - run: | - docker logs damian --follow & + - name: Display bootnode logs + run: docker logs damian --follow & - # NOTE: this step contacts every node in the comittee by their container id and sends a simple RPC request - # that lists all the RPC methods that they expose. - # Once they respond we know all nodes are online - - name: Verify nodes respond - run: | - validators=( damian tomasz zbyszko hansu ) - rpc_port=9933 - - for validator in "${validators[@]}"; do - docker run --network container:$validator appropriate/curl:latest \ - --retry 3 \ - --retry-delay 10 \ - -H "Content-Type: application/json" \ - -d '{"id":1, "jsonrpc":"2.0", "method": "rpc_methods"}' http://127.0.0.1:$rpc_port - let rpc_port=$rpc_port+1 - done + - name: Setup upterm session + uses: lhotari/action-upterm@v1 + + # NOTE: this step waits until chain starts finalizing blocks + - name: Wait for consensus + shell: bash + timeout-minutes: 5 + run: ./.github/scripts/check_finalization.sh # note: more complex test scenarios can be run from here on out - name: Save docker image - run: | - docker save -o aleph-node.tar aleph-node:latest + run: docker save -o aleph-node.tar aleph-node:latest # NOTE: stores the final artifacts if tests completed successfully - name: Upload docker image diff --git a/bin/node/src/chain_spec.rs b/bin/node/src/chain_spec.rs index ec76c282d7..1974d206d0 100644 --- a/bin/node/src/chain_spec.rs +++ b/bin/node/src/chain_spec.rs @@ -8,6 +8,7 @@ use aleph_runtime::{ use hex_literal::hex; use sc_service::config::BasePath; use sc_service::ChainType; +use sp_application_crypto::Ss58Codec; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::{IdentifyAccount, Verify}; @@ -17,10 +18,6 @@ use structopt::StructOpt; const FAUCET_HASH: [u8; 32] = hex!("eaefd9d9b42915bda608154f17bb03e407cbf244318a0499912c2fb1cd879b74"); -pub const LOCAL_AUTHORITIES: [&str; 8] = [ - "Damian", "Tomasz", "Zbyszko", "Hansu", "Adam", "Matt", "Antoni", "Michal", -]; - pub const DEVNET_ID: &str = "dev"; /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. @@ -55,8 +52,8 @@ pub struct ChainParams { /// Pass the chain id. /// /// It can be a predefined one (dev) or an arbitrary chain id passed to the genesis block - #[structopt(long, value_name = "CHAIN_SPEC")] - pub chain_id: Option, + #[structopt(long, value_name = "CHAIN_SPEC", default_value = "a0dnet1")] + pub chain_id: String, /// Specify custom base path. #[structopt(long, short = "d", value_name = "PATH", parse(from_os_str))] @@ -73,14 +70,20 @@ pub struct ChainParams { #[structopt(long)] pub token_symbol: Option, + + /// Pass the AccountIds of authorities forming the committe at the genesis + /// + /// Expects a delimited collection of accountIds + #[structopt(long, require_delimiter = true)] + account_ids: Option>, + + #[structopt(long)] + n_members: Option, } impl ChainParams { pub fn chain_id(&self) -> &str { - match &self.chain_name { - Some(id) => id, - None => "a0dnet1", - } + &self.chain_id } pub fn base_path(&self) -> BasePath { @@ -109,6 +112,31 @@ impl ChainParams { None => "Aleph Zero Development", } } + + pub fn account_ids(&self) -> Vec { + match &self.account_ids { + Some(ids) => ids + .iter() + .map(|id| { + AccountId::from_string(id.as_str()) + .expect("Passed string is not a hex encoding of a public key") + }) + .collect(), + None => { + let n_members = self + .n_members + .expect("Pass account-ids or n-members argument"); + + (0..n_members) + .into_iter() + .map(|id| { + let seed = id.to_string(); + get_account_id_from_seed::(&seed.as_str()) + }) + .collect() + } + } + } } pub fn development_config( diff --git a/bin/node/src/commands.rs b/bin/node/src/commands.rs index ceec73a5de..37d633d897 100644 --- a/bin/node/src/commands.rs +++ b/bin/node/src/commands.rs @@ -1,6 +1,4 @@ -use crate::chain_spec::{ - self, get_account_id_from_seed, AuthorityKeys, ChainParams, LOCAL_AUTHORITIES, -}; +use crate::chain_spec::{self, AuthorityKeys, ChainParams}; use aleph_primitives::AuthorityId as AlephId; use log::info; use sc_cli::{Error, KeystoreParams}; @@ -8,7 +6,6 @@ use sc_keystore::LocalKeystore; use sc_service::config::{BasePath, KeystoreConfig}; use sp_application_crypto::key_types; use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_core::sr25519; use sp_keystore::SyncCryptoStore; use std::io::Write; use std::ops::Deref; @@ -57,17 +54,20 @@ impl BootstrapChainCmd { pub fn run(&self) -> Result<(), Error> { let chain_id = self.chain_params.chain_id(); - let genesis_authorities = LOCAL_AUTHORITIES + let genesis_authorities = self + .chain_params + .account_ids() .iter() - .map(|authority| { + .map(|account_id| { + let authority = account_id.to_string(); + let authority_keystore = self - .open_keystore(authority, chain_id) + .open_keystore(&authority, chain_id) .unwrap_or_else(|_| panic!("Cannot open keystore for {}", authority)); let aura_key = aura_key(Deref::deref(&authority_keystore)); let aleph_key = aleph_key(Deref::deref(&authority_keystore)); - // NOTE : the account_id's should definitely not be generated from seed in case of testnet and mainnet - let account_id = get_account_id_from_seed::(authority); + let account_id = account_id.to_owned(); AuthorityKeys { account_id, diff --git a/docker/.env b/docker/.env deleted file mode 100644 index 20b560cb5a..0000000000 --- a/docker/.env +++ /dev/null @@ -1 +0,0 @@ -VERSION=latest \ No newline at end of file diff --git a/docker/data/Damian/libp2p_secret b/docker/data/5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH/libp2p_secret similarity index 100% rename from docker/data/Damian/libp2p_secret rename to docker/data/5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH/libp2p_secret diff --git a/docker/data/Hansu/libp2p_secret b/docker/data/5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9/libp2p_secret similarity index 100% rename from docker/data/Hansu/libp2p_secret rename to docker/data/5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9/libp2p_secret diff --git a/docker/data/Tomasz/libp2p_secret b/docker/data/5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK/libp2p_secret similarity index 100% rename from docker/data/Tomasz/libp2p_secret rename to docker/data/5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK/libp2p_secret diff --git a/docker/data/Zbyszko/libp2p_secret b/docker/data/5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o/libp2p_secret similarity index 100% rename from docker/data/Zbyszko/libp2p_secret rename to docker/data/5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o/libp2p_secret diff --git a/docker/data/n_members b/docker/data/n_members deleted file mode 100644 index bf0d87ab1b..0000000000 --- a/docker/data/n_members +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 4379b4d5ce..57dc56959d 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -3,10 +3,8 @@ services: # bootnode damian: - image: aleph-node:${VERSION} + image: aleph-node:latest container_name: damian - privileged: true - network_mode: host environment: - RUST_LOG=info - RPC_PORT=9933 @@ -14,66 +12,95 @@ services: - PORT=30333 - PURGE_BEFORE_START=true - NAME=Damian - - BASE_PATH=/tmp/Damian - - NODE_KEY_PATH=/tmp/Damian/libp2p_secret + - BASE_PATH=/tmp/5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH + - NODE_KEY_PATH=/tmp/5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH/libp2p_secret - CHAIN=/tmp/chainspec.json - - BOOT_NODES=/ip4/127.0.0.1/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm + - PUBLIC_ADDR=/ip4/172.28.1.1/tcp/30333 + # - PUBLIC_ADDR=/dns4/damian/tcp/30333 volumes: - ./data/:/tmp/ + networks: + dev_net: + ipv4_address: 172.28.1.1 tomasz: - image: aleph-node:${VERSION} + image: aleph-node:latest container_name: tomasz - privileged: true - network_mode: host environment: - RUST_LOG=info - - RPC_PORT=9934 - - WS_PORT=9944 - - PORT=30334 + - RPC_PORT=9933 + - WS_PORT=9943 + - PORT=30333 - PURGE_BEFORE_START=true - NAME=Tomasz - - BASE_PATH=/tmp/Tomasz - - NODE_KEY_PATH=/tmp/Tomasz/libp2p_secret + - BASE_PATH=/tmp/5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK + - NODE_KEY_PATH=/tmp/5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK/libp2p_secret - CHAIN=/tmp/chainspec.json - - BOOT_NODES=/ip4/127.0.0.1/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm + - PUBLIC_ADDR=/ip4/172.28.1.2/tcp/30333 + # - BOOT_NODES=/ip4/172.28.1.1/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm + # - PUBLIC_ADDR=/dns4/tomasz/tcp/30333 + - BOOT_NODES=/dns4/damian/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm volumes: - ./data/:/tmp/ + links: + - "damian:damian" # service damian is reachable as hostname damian + networks: + dev_net: + ipv4_address: 172.28.1.2 zbyszko: - image: aleph-node:${VERSION} + image: aleph-node:latest container_name: zbyszko - privileged: true - network_mode: host environment: - RUST_LOG=info - - RPC_PORT=9935 - - WS_PORT=9945 - - PORT=30335 + - RPC_PORT=9933 + - WS_PORT=9943 + - PORT=30333 - PURGE_BEFORE_START=true - NAME=Zbyszko - - BASE_PATH=/tmp/Zbyszko - - NODE_KEY_PATH=/tmp/Zbyszko/libp2p_secret + - BASE_PATH=/tmp/5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9 + - NODE_KEY_PATH=/tmp/5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9/libp2p_secret - CHAIN=/tmp/chainspec.json - - BOOT_NODES=/ip4/127.0.0.1/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm + - PUBLIC_ADDR=/ip4/172.28.1.3/tcp/30333 + # - BOOT_NODES=/ip4/172.28.1.1/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm + # - PUBLIC_ADDR=/dns4/zbyszko/tcp/30333 + - BOOT_NODES=/dns4/damian/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm volumes: - ./data/:/tmp/ + links: + - "damian:damian" + networks: + dev_net: + ipv4_address: 172.28.1.3 hansu: - image: aleph-node:${VERSION} + image: aleph-node:latest container_name: hansu - privileged: true - network_mode: host environment: - RUST_LOG=info - - RPC_PORT=9936 - - WS_PORT=9946 - - PORT=30336 + - RPC_PORT=9933 + - WS_PORT=9943 + - PORT=30333 - PURGE_BEFORE_START=true - NAME=Hansu - - BASE_PATH=/tmp/Hansu - - NODE_KEY_PATH=/tmp/Hansu/libp2p_secret + - BASE_PATH=/tmp/5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o + - NODE_KEY_PATH=/tmp/5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o/libp2p_secret - CHAIN=/tmp/chainspec.json - - BOOT_NODES=/ip4/127.0.0.1/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm + - PUBLIC_ADDR=/ip4/172.28.1.4/tcp/30333 + # - BOOT_NODES=/ip4/172.28.1.1/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm + # - PUBLIC_ADDR=/dns4/hansu/tcp/30333 + - BOOT_NODES=/dns4/damian/tcp/30333/p2p/12D3KooWAbWDCsZiA6EXrXh33E7hBYUFK53b5CSajoPsYL5n2Zdm volumes: - - ./data/:/tmp/ \ No newline at end of file + - ./data/:/tmp/ + links: + - "damian:damian" + networks: + dev_net: + ipv4_address: 172.28.1.4 + +networks: + dev_net: + ipam: + driver: default + config: + - subnet: 172.28.0.0/16 diff --git a/docker/docker_entrypoint.sh b/docker/docker_entrypoint.sh index 5b9817cb13..88918499f3 100644 --- a/docker/docker_entrypoint.sh +++ b/docker/docker_entrypoint.sh @@ -11,6 +11,7 @@ BASE_PATH=${BASE_PATH:?'Base path should be specified'} RPC_PORT=${RPC_PORT:-9933} WS_PORT=${WS_PORT:-9943} PORT=${PORT:-30333} +PUBLIC_ADDR=${PUBLIC_ADDR:-/ip4/127.0.0.1/tcp/$PORT} if [[ "true" == "$PURGE_BEFORE_START" ]]; then echo "Purging chain (${CHAIN}) at path ${BASE_PATH}" @@ -28,6 +29,7 @@ ARGS=( --rpc-cors all --rpc-methods Safe # TODO: should we allow to specify them? --no-prometheus --no-telemetry # Currently not using. plan to start as soon as capacity is available --no-mdns + --public-addr "${PUBLIC_ADDR}" ) if [[ -n "${BOOT_NODES:-}" ]]; then @@ -50,4 +52,6 @@ if [[ -n "${FLAG_L_ALEPH_BFT:-}" ]]; then ARGS+=(-lAlephBFT=debug) fi +echo "My public address to advertize is: $PUBLIC_ADDR" + aleph-node "${ARGS[@]}"