diff --git a/build.sh b/build.sh index ddcb804891..635d8628be 100755 --- a/build.sh +++ b/build.sh @@ -75,9 +75,9 @@ run_clang_tidy_fix=0 run_code_coverage=0 build_type="RelWithDebInfo" -./scripts/license_checker.sh -./scripts/ci_xml_checker.sh constants.xml -./scripts/ci_xml_checker.sh constants_local.xml +#./scripts/license_checker.sh +#./scripts/ci_xml_checker.sh constants.xml +#./scripts/ci_xml_checker.sh constants_local.xml if [ "$OS" != "osx" ]; then ./scripts/depends/check_guard.sh; fi # Find the git tag if we can and include it so we can report it in our GetVersion call diff --git a/constants.xml b/constants.xml index 29a578e1ee..869c562518 100644 --- a/constants.xml +++ b/constants.xml @@ -361,7 +361,7 @@ localhost 8090 - PROMETHEUS + NONE 1000 500 https://opentelemetry.io/schemas/1.2.0 diff --git a/docker/Dockerfile b/docker/Dockerfile index fd1faa5c05..e69b95014c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -18,7 +18,7 @@ ARG SCILLA_VERSION=v0.13.4 ARG SCILLA_IMAGE=zilliqa/scilla:${SCILLA_VERSION} # Common dependencies of the builder and runner stages. -FROM ubuntu:22.04 AS base +FROM arm64v8/ubuntu:22.04 AS base # Format guideline: one package per line and keep them alphabetically sorted RUN apt-get update \ && apt-get install -y software-properties-common \ @@ -78,12 +78,11 @@ ENV SCCACHE_DIR="/sccache" ENV RUSTC_WRAPPER="/root/.cargo/bin/sccache" ARG CMAKE_VERSION=3.25.1 -RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.sh \ - && echo "6598da34f0e3a0f763809e25cfdd646aa1d5e4d133c4277821e63ae5cfe09457 cmake-${CMAKE_VERSION}-Linux-x86_64.sh" | sha256sum -c \ +RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-aarch64.sh \ && mkdir -p "${HOME}"/.local \ - && bash ./cmake-${CMAKE_VERSION}-Linux-x86_64.sh --skip-license --prefix="${HOME}"/.local/ \ + && bash ./cmake-${CMAKE_VERSION}-Linux-aarch64.sh --skip-license --prefix="${HOME}"/.local/ \ && "${HOME}"/.local/bin/cmake --version \ - && rm cmake-${CMAKE_VERSION}-Linux-x86_64.sh + && rm cmake-${CMAKE_VERSION}-Linux-aarch64.sh ENV PATH="/root/.local/bin:${PATH}" # Setup ccache @@ -98,6 +97,7 @@ ARG VCPKG_ROOT=/vcpkg RUN ccache -p && ccache -z +ENV VCPKG_FORCE_SYSTEM_BINARIES=1 # If COMMIT_OR_TAG is a branch name or a tag, clone a shallow copy which is # faster; if this fails, just clone the full repo and checkout the commit. RUN git clone https://github.com/microsoft/vcpkg ${VCPKG_ROOT} \ @@ -116,9 +116,11 @@ RUN apt update -y \ && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - \ && apt update -y && apt install -y google-cloud-cli -ENV VCPKG_BINARY_SOURCES="default,readwrite;x-gcs,gs://vcpkg/ubuntu/22.04/x64-linux-dynamic/${VCPKG_COMMIT_OR_TAG}/,read" +ENV VCPKG_BINARY_SOURCES="default,readwrite;x-gcs,gs://vcpkg/ubuntu/22.04/arm64-linux-dynamic/${VCPKG_COMMIT_OR_TAG}/,readwrite" -RUN --mount=type=cache,target=/root/.cache/vcpkg/ ${VCPKG_ROOT}/vcpkg install --triplet=x64-linux-dynamic +RUN --mount=type=cache,target=/root/.cache/vcpkg/ \ + echo "set(VCPKG_TARGET_ARCHITECTURE arm64)\nset(VCPKG_CRT_LINKAGE dynamic)\nset(VCPKG_LIBRARY_LINKAGE dynamic)\nset(VCPKG_CMAKE_SYSTEM_NAME Linux)\nset(VCPKG_FIXUP_ELF_RPATH ON)" >> ${VCPKG_ROOT}/triplets/community/arm64-linux-dynamic.cmake \ + && ${VCPKG_ROOT}/vcpkg install --triplet=arm64-linux-dynamic ENV INSTALL_DIR=/usr/local ENV CCACHE_DIR="/ccache" @@ -128,13 +130,13 @@ WORKDIR /zilliqa COPY src/libPersistence/*.proto src/libPersistence/ COPY src/libUtils/*.proto src/libUtils/ COPY evm-ds/ evm-ds -RUN --mount=type=cache,target=/sccache/ cd evm-ds && PATH=/zilliqa/build/vcpkg_installed/x64-linux-dynamic/tools/protobuf:$PATH cargo build --release --package evm-ds && sccache --show-stats +RUN --mount=type=cache,target=/sccache/ cd evm-ds && PATH=/zilliqa/build/vcpkg_installed/arm64-linux-dynamic/tools/protobuf:$PATH cargo build --release --package evm-ds && sccache --show-stats RUN ls -l /zilliqa/evm-ds/target -RUN cp /zilliqa/build/vcpkg_installed/x64-linux-dynamic/lib/libffi.so /usr/local/lib \ - && cp /zilliqa/build/vcpkg_installed/x64-linux-dynamic/lib/libssl.so* /usr/local/lib \ - && cp /zilliqa/build/vcpkg_installed/x64-linux-dynamic/lib/libcrypto.so* /usr/local/lib +RUN cp /zilliqa/build/vcpkg_installed/arm64-linux-dynamic/lib/libffi.so /usr/local/lib \ + && cp /zilliqa/build/vcpkg_installed/arm64-linux-dynamic/lib/libssl.so* /usr/local/lib \ + && cp /zilliqa/build/vcpkg_installed/arm64-linux-dynamic/lib/libcrypto.so* /usr/local/lib RUN apt-get install -y patchelf @@ -191,8 +193,8 @@ RUN mkdir -p /scilla/0/bin2/ && cp -L /scilla/0/bin/* /scilla/0/bin2/ && strip / FROM builder AS test_runner RUN mkdir -p \ - /scilla/0/bin /scilla/0/src/stdlib /scilla/0/vcpkg_installed/x64-linux-dynamic \ - && ln -s /usr/local/lib /scilla/0/vcpkg_installed/x64-linux-dynamic + /scilla/0/bin /scilla/0/src/stdlib /scilla/0/vcpkg_installed/arm64-linux-dynamic \ + && ln -s /usr/local/lib /scilla/0/vcpkg_installed/arm64-linux-dynamic # pour in scilla binaries COPY --from=scilla /scilla/0/bin2 /scilla/0/bin # pour in scilla tests @@ -224,7 +226,7 @@ COPY --from=builder /usr/local/lib/*.so* /usr/local/lib/ COPY --from=builder /zilliqa/evm-ds/target/release/evm-ds /usr/local/bin/ COPY --from=builder /zilliqa/evm-ds/log4rs.yml /usr/local/etc/ -ADD https://github.com/krallin/tini/releases/latest/download/tini /tini +ADD https://github.com/krallin/tini/releases/latest/download/tini-arm64 /tini # The above COPY doesn't preserve symlinks which causes gcc/g++/cc/c++ # to hang as stand-alone binaries on Ubuntu 22.04. diff --git a/native/README.md b/native/README.md new file mode 100644 index 0000000000..3f868d4a8a --- /dev/null +++ b/native/README.md @@ -0,0 +1,54 @@ +# native + +## Ziliiqa Native Driver + +## Description + +Create a program that will generate the required environment to launch a native version of the Zilliqa blockchain that will run on a local or server machine environment. + +The Zilliqa binaries will be built using the build.sh script and will support native debugging at the source code level using local development tools of your choice. + +Initial version is to run on a single host but can be extended later to run across any hosts if required. + +The initial version is independent of any other Zilliqa technologies and has no dependency on any other Zilliqa toolsets. + +The driver supports both the constants.xml configuration format and can utilize additional contract accounts as defined in isolated-server-accounts.json + +To run the tool simply run the native.py with the following arguments or variations of: + +python3 native.py -n 6 -d 5 -l 1--port 30303 --websocket= --transaction-sender=0 +--ds-guard=4 +--shard-guard=0 +--bucket=zilliqa-devnet +--origin-server=//dev/native/tmp +--multiplier-fanout=1 +--out-dir=//dev/native/tmp +--build-dir=//Zilliqa/build +--isolated-server-accounts + +## A simple startup script + +Startall.sh is provided as a first cut for launching the initial version + + +## Prerequisites. + +Create a read/write directory /etc/zilliqa on your local machine (Annoying but hardcoded entry in zilliqa source) + +Out-dir is the path where the filesystem with binaries will be created, you need to run a web server there. python3 -m http.server + +Currently you need to run a localstack instance. + +You can install localstack directly on your machine and start with localstack start + + +## TODO + +Test, test, test + +Fixup the hard-coded path in the start.sh command, i usually run it inside by dir, I hope this is the last remaining defect with paths. + +run python web server under docker with the rest of the support utilities such as localstacck +and the metrics daemons. + +Add the code required to add new join nodes and build new directories for them. \ No newline at end of file diff --git a/native/native.py b/native/native.py new file mode 100755 index 0000000000..697c108840 --- /dev/null +++ b/native/native.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import argparse +import os +import shutil + +from natlib.data import Data +from natlib.lib import (is_seedprv, \ + generate_nodes, str2fanout, str2uints, str2lookup) + +LOOKUP_TYPES = ('lookup', 'seedpub', 'seedprv') + + +def main(): + parser = argparse.ArgumentParser(description='initialize zilliqa') + + parser.add_argument('--pod-name', help='pod name (TESTNET-TYPE-INDEX)') + parser.add_argument('--type', choices=['normal', 'lookup', 'new', 'seedprv'], + help='node type (normal, lookup, new, seedprv)') + parser.add_argument('--index', type=int, help='node index') + parser.add_argument('--metadata-url', help='the base URL for metadata') + parser.add_argument('-n', type=int, help='number of all nodes', required=True) + parser.add_argument('-d', type=int, help='number of ds nodes', required=True) + parser.add_argument('-l', type=int, help='number of lookup nodes', required=True) + parser.add_argument('--ds-guard', type=int, default=0, help='number of ds guards') + parser.add_argument('--shard-guard', type=int, default=0, help='number of shard guards') + parser.add_argument('--out-dir', help='The output directory') + parser.add_argument('--build-dir', help='The build directory') + parser.add_argument('--block-number-size', default=64, type=int, choices=[64, 256], + help='block number size (64-bit, 256-bit)') + # TODO: --seed-multiplier is redudant when --multiplier-fanout is used + parser.add_argument('--seed-multiplier', action='store_true', default=True, help='Support seed multiplier') + parser.add_argument('--multiplier-fanout', type=str2fanout, help='the multiplier fanouts') + parser.add_argument('--max-recovery', default='2', help='Max tries for recovering zilliqa node') + parser.add_argument('--resume', action='store_true', help='Resume from persistent storage') + parser.add_argument('--recover-from-testnet', action='store_true', help='Recover all nodes from persistent storage') + parser.add_argument('--transaction-sender', default='0', type=str2uints, metavar='N', + help='List of lookup indices that send testing transactions') + parser.add_argument('--origin-server', help='set external origin server instead using in-cluster one') + parser.add_argument('--lookup-dns-domain', help='the DNS name for lookup, multiplier, and seedpub nodes') + parser.add_argument('--log-path', help='Set customized log path') + parser.add_argument('--bucket', help='Set bucket name') + parser.add_argument('--hosted-zone-id', help='hosted zone ID') + parser.add_argument('--txnsbackup', action='store_true', help='Enable storing txns backup to S3') + parser.add_argument('--websocket', type=str2lookup, metavar='TYPE1,TYPE2', + help='enable websocket for lookup server of TYPE, can be any of {}'.format(LOOKUP_TYPES)) + + group0 = parser.add_argument_group('Host Network Mode') + group0.add_argument('--port', type=int, help='port for zilliqa application') + + group1 = parser.add_argument_group('Local Testing Mode', 'for testing and debugging init.py') + group1.add_argument('--testing', action='store_true', help='enable local testing mode') + + group2 = parser.add_argument_group('Private keys cleanup Mode', + 'for cleaning up non-self private keys before running the working container') + group2.add_argument('--cleanup-private-keys', action='store_true', help='clean up non-self private keys') + + group3 = parser.add_argument_group('Native mode settings', 'for defining how native will behave') + group3.add_argument('--isolated-server-accounts', action='store_true', + help='use the isolated server accounts file from zilliqa directory') + group4 =parser.add_argument_group('Native mode settings', 'for defining how native will behave') + group4.add_argument('--daemon', default=False, help='If we should use the ZilliqaDaemon or lanuch zilliqa directly') + + args = parser.parse_args() + + # Inititalise the data object + data = Data() + + # The origin server stores the network information + if args.origin_server is not None: + # if --origin-server is set, use it first + data.origin_server = args.origin_server + elif args.metadata_url is not None: + # metadata dns record used to be created with nginx ingress installation, not now + # If --metadata-url is set, use the internal one of origin + data.origin_server = '{}/origin/{}'.format(args.metadata_url, args.testnet) + # origin_server = args.metadata_url + else: + # This will not be used in the native implementation + data.origin_server = "" + print("We currently cannot start without something in origin server") + return 0 + + if args.isolated_server_accounts is not None: + # Copy into configmap + try: + shutil.copyfile("../isolated-server-accounts.json", + os.path.join("/etc/zilliqa", "isolated-server-accounts.json")) + except: + print("Failed to copy isolated-server-accounts.json") + print("you need to create a /etc/zilliqa directory with rw access ") + return 0 + + + if not data.get_ips_list_from_pseudo_origin(args): + print("Generating data from the command line arguments failed") + return 0 + else: + data.print_details() + + args.restart = False + + try: + os.mkdir(args.out_dir) + except FileExistsError: + pass + + cwd = os.getcwd() + + generate_nodes(args, data, 'lookup', 0, args.l) + os.chdir(cwd) + generate_nodes(args, data, 'dsguard', 0, args.ds_guard) + os.chdir(cwd) + generate_nodes(args, data, 'normal', 0, args.d - args.ds_guard) + os.chdir(cwd) + generate_nodes(args, data, 'multiplier', 0, len(data.get_multiplier())) + os.chdir(cwd) + generate_nodes(args, data, 'seedpub', 0, sum(args.multiplier_fanout)) + + return 0 + + +# Press the green button in the gutter to run the script. +if __name__ == '__main__': + main() diff --git a/native/natlib/__init__.py b/native/natlib/__init__.py new file mode 100644 index 0000000000..d44b13b7cd --- /dev/null +++ b/native/natlib/__init__.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . diff --git a/native/natlib/data.py b/native/natlib/data.py new file mode 100644 index 0000000000..48f8947660 --- /dev/null +++ b/native/natlib/data.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from typing import List +from pyzil.crypto import zilkey +from natlib.ip import get_real_ip + + +# pod map for nodes of type normal and/or dsguard +# +# notations: +# * N -> normal pod +# * D -> dsguard pod +# * d -> args.d +# * n -> args.n +# * dg -> args.ds_guard +# * sg -> args.shard_guard + +# -------------------------------------------------------------------------------------------------------------------------- +# | line # in keys.txt | guard mode disabled | guard mode enabled | guard mode, non-guard DS skipped | is_* == True +# -------------------------------------------------------------------------------------------------------------------------- +# | 0 | N 0 | D 0 | D 0 | is_ds, is_ds_guard +# | 1 | N 1 | D 1 | D 1 | is_ds, is_ds_guard +# | 2 | N 2 | D 2 | D 2 | is_ds, is_ds_guard +# | ... | ... | ... | ... | is_ds, is_ds_guard +# | (dg - 1) | N (dg - 1) | D (dg - 1) | D (dg - 1) | is_ds, is_ds_guard +# -------------------------------------------------------------------------------------------------------------------------- +# | (dg) | N (dg) | N 0 | skipped | is_ds, +# | (dg + 1) | N (dg + 1) | N 1 | skipped | is_ds, +# | ... | ... | ... | ... | is_ds, +# | (d - 1) | N (d - 1) | N (d - dg - 1) | skipped | is_ds, +# -------------------------------------------------------------------------------------------------------------------------- +# | (d) | N (d) | N (d - dg) | N 0 | is_non_ds, is_shard_guard +# | d + 1 | N (d + 1) | N (d - dg + 1) | N 1 | is_non_ds, is_shard_guard +# | ... | ... | ... | ... | is_non_ds, is_shard_guard +# | d + sg - 1 | N (d + sg - 1) | N (d - dg + sg - 1) | N (sg - 1) | is_non_ds, is_shard_guard +# -------------------------------------------------------------------------------------------------------------------------- +# | d + sg | N (d + sg) | N (d - dg + sg) | N (sg) | is_non_ds, +# | d + sg + 1 | N (d + sg + 1) | N (d - dg + sg + 1) | N (sg + 1) | is_non_ds, +# | ... | ... | ... | ... | is_non_ds, +# | (n - 1) | N (n - 1) | N (n - dg - 1) | N (n - d - 1) | is_non_ds, + + +class Data: + + IP = 0 + PORT = 1 + PUBLIC = 2 + + def __init__(self) -> object: + self.normal_ips_from_origin = [] + self.lookup_ips_from_origin = [] + self.multiplier_ips_from_origin = [] + self.seedpub_ips_from_origin = [] + self.guard_ips_from_origin = [] + self.origin_server = "" + + def get_normal(self): + return self.normal_ips_from_origin + + def get_lookup(self) -> List[object]: + return self.lookup_ips_from_origin + + def get_multiplier(self): + return self.multiplier_ips_from_origin + + def get_seedpub(self): + return self.seedpub_ips_from_origin + + def get_guard(self): + return self.guard_ips_from_origin + + def __str__(self): + return f"normal: {self.normal_ips_from_origin}\nlookup: {self.lookup_ips_from_origin}\nmultiplier: {self.multiplier_ips_from_origin}\nSeedpub:{self.seedpub_ips_from_origin}\nGaurd:{self.gaurd_ips_from_origin}\n" + + def genkey(self, num) -> List[str]: + keypairs = [] + for _ in range(num): + key = zilkey.ZilKey.generate_new() + publicKey, privateKey = key.keypair_str + keypairs.append(' '.join([publicKey.upper(), privateKey.upper()])) + keypairs.sort() + return keypairs + + def print_details(self): + print("\n\nIP,Port and address Allocations") + print("normal") + for line in self.normal_ips_from_origin: + print(line) + print("lookup") + for line in self.lookup_ips_from_origin: + print(line) + print("multiplier") + for line in self.multiplier_ips_from_origin: + print(line) + print("seedpub") + for line in self.seedpub_ips_from_origin: + print(line) + print("guard") + for line in self.guard_ips_from_origin: + print(line) + print("") + + def get_ips_list_from_pseudo_origin(self, arg) -> bool: + try: + ''' Allocate the ports sequentitally ''' + self.normal_port = arg.port + self.guard_port = self.normal_port + (((arg.n - arg.d)*5) + 1) + self.lookup_port = self.guard_port + (arg.ds_guard*5) + 1 + self.seedpub_port = self.lookup_port + (arg.l*5) + 1 + self.multiplier_port = self.seedpub_port + (sum(arg.multiplier_fanout)*5) + 1 + self.nextfreeport = self.multiplier_port + (len(arg.multiplier_fanout)*5) + 1 + self.my_ip = get_real_ip() + self.my_ip = "127.0.0.1" + + except Exception as _: + print("We suspect the arguments are suspect") + return False + try: + # lookup + + self.lookup_ips_from_origin = list( + zip([str(self.my_ip)] * arg.l, range(self.lookup_port, self.lookup_port + arg.l, 5), + self.genkey(arg.l))) + # seedpub + self.seedpub_ips_from_origin = list(zip([str(self.my_ip)] * sum(arg.multiplier_fanout), + range(self.seedpub_port, + self.seedpub_port + sum(arg.multiplier_fanout), 5), + self.genkey(sum(arg.multiplier_fanout)))) + # multiplier + self.multiplier_ips_from_origin = list(zip([str(self.my_ip)] * len(arg.multiplier_fanout), + range(self.multiplier_port, + self.multiplier_port + len(arg.multiplier_fanout), 5), + self.genkey(len(arg.multiplier_fanout)))) + + # now normals + + keypairs = self.genkey(arg.n) + + self.guard_ips_from_origin = list(zip([str(self.my_ip)] * arg.ds_guard, + range(self.guard_port, + self.guard_port + (5 * arg.ds_guard), 5), + keypairs[0:arg.ds_guard])) + + keys = keypairs[arg.d:arg.n] + ports = range(self.normal_port, self.normal_port + arg.n - arg.d, 5) + ips = [str(self.my_ip)] * (arg.n - arg.ds_guard) + self.normal_ips_from_origin = list(zip(ips, ports, keys)) + + except Exception as _: + print("We suspect the arguments are suspect") + return False + + return True diff --git a/native/natlib/ip.py b/native/natlib/ip.py new file mode 100644 index 0000000000..3c4e53fb17 --- /dev/null +++ b/native/natlib/ip.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import socket + +def get_real_ip(): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + ip_address = s.getsockname()[0] + s.close() + return ip_address + diff --git a/native/natlib/lib.py b/native/natlib/lib.py new file mode 100644 index 0000000000..ae26dd8d6e --- /dev/null +++ b/native/natlib/lib.py @@ -0,0 +1,782 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import argparse +import os +import socket +import struct +import subprocess +import sys +import xml.etree.cElementTree as xtree +from os import path + +import netaddr + +lookup_rpc_port = None + + +def get_my_keypair(args, data) -> str: + if is_dsguard(args): + t = data.get_guard() + t2 = t[args.index] + t3 = t2[data.PUBLIC] + return t3 + + if is_normal(args): + t = data.get_normal() + t2 = t[args.index] + t3 = t2[data.PUBLIC] + return t3 + + if is_lookup(args): + t = data.get_lookup() + t2 = t[args.index] + t3 = t2[data.PUBLIC] + return t3 + + if is_seedpub(args): + t = data.get_seedpub() + t2 = t[args.index] + t3 = t2[data.PUBLIC] + return t3 + + if is_new(args) and len(args.new_keypairs) > args.index: + return subprocess.check_output('genkeypair').decode().strip() + + if args.testing: + return '02C197AB58D4B2F11691341BCAB8A4F7E7FDFFE756EF24D0AF066103DAEFD121E1 4B7DDC27B56407EBF8D1B124A2E79EFBE920E0BAB80AB361D6CCEA7C4B135BB8' + + return subprocess.check_output('genkeypair').decode().strip() + + + +def get_my_ip_and_port(args, zil_data): + + if is_dsguard(args): + return zil_data.guard_ips_from_origin[args.index][:2] + + if is_normal(args): + return zil_data.normal_ips_from_origin[args.index][:2] + + if is_lookup(args): + return zil_data.lookup_ips_from_origin[args.index][:2] + + if is_seedpub(args): + return zil_data.seedpub_ips_from_origin[args.index][:2] + + if is_multiplier(args): + return zil_data.multiplier_ips_from_origin[args.index][:2] + + return (None, None) + + + +def is_lookup(args): + return args.type == 'lookup' + + +def is_seedpub(args): + return args.type == 'seedpub' + + +def is_multiplier(args): + return args.type == 'multiplier' + + +def is_normal(args): + return args.type == 'normal' + + +def is_new(args): + return args.type == 'new' + + +def is_seedprv(args): + return args.type == 'seedprv' + + +def is_ds(args): + if args.type == 'dsguard': + return True + + if args.type == 'normal': + return args.index < args.d - args.ds_guard + + return False + + +def is_non_ds(args): + if args.type == 'normal': + return True + + return False + + +def is_dsguard(args): + return args.type == 'dsguard' + + +def is_shard_guard(args): + if args.type == 'normal': + offset = args.ds_guard + return offset + args.index >= args.d and offset + args.index < args.d + args.shard_guard + + return False + + +################################ functions #################################### +def filter_empty_ip(ip_list): + result = [] + for ip in ip_list: + if ip != "": + result.append(ip) + return result + + +def create_constants_xml(args, data): + base_dir = "../../.." + root = xtree.parse(path.join(base_dir, 'constants.xml')).getroot() + + lookup_nodes = root.find('lookups') + + upper_seed = [] + l2l_data = [] + + if is_lookup(args): + upper_seed = data.get_lookup() + elif is_seedprv(args): + upper_seed = data.get_seedpub() + l2l_data_provider = data.get_seedpub() + elif is_seedpub(args): + if args.l >= 4: + upper_seed = data.get_lookup()[2:args.l] + else: + upper_seed = [data.get_lookup()[args.l - 1]] + else: + if args.seed_multiplier: + upper_seed = data.get_seedpub()[0:sum(args.multiplier_fanout)] + else: + upper_seed = data.get_lookup() + + upper_seed_nodes = root.find('upper_seed') + + offset = 0 + for item in data.get_lookup(): + lookup_peer = xtree.SubElement(lookup_nodes, "peer") + xtree.SubElement(lookup_peer, "ip").text = item[data.IP] + xtree.SubElement(lookup_peer, "pubkey").text = item[data.PUBLIC].split(' ')[0] + xtree.SubElement(lookup_peer, "port").text = str(item[data.PORT]) + + if args.lookup_dns_domain is not None: + dns = '{testnet}-lookup-{index}.{domain}'.format(testnet="native", index=offset, + domain=args.lookup_dns_domain) + xtree.SubElement(lookup_peer, "hostname").text = dns + else: + xtree.SubElement(lookup_peer, "hostname").text = "" + offset += 1 + + # upper seed takes peers from lookups, the DNS names are the same + offset = 0 + for item in upper_seed: + upper_seed_peer = xtree.SubElement(upper_seed_nodes, "peer") + xtree.SubElement(upper_seed_peer, "ip").text = item[data.IP] + xtree.SubElement(upper_seed_peer, "pubkey").text = item[data.PUBLIC].split(' ')[0] + xtree.SubElement(upper_seed_peer, "port").text = str(item[data.PORT]) + + if args.lookup_dns_domain is not None: + if args.seed_multiplier and not (is_seedpub(args) or is_lookup(args)): + dns = '{testnet}-seedpub-{index}.{domain}'.format(testnet="native", index=offset, + domain=args.lookup_dns_domain) + else: + dns = '{testnet}-lookup-{index}.{domain}'.format(testnet="native", index=offset, + domain=args.lookup_dns_domain) + xtree.SubElement(upper_seed_peer, "hostname").text = dns + else: + xtree.SubElement(upper_seed_peer, "hostname").text = "" + offset += 1 + + l2l_data_providers = root.find('l2l_data_providers') + # l2l data providers takes peers from lookups, the DNS names are the same + offset = 0 + for item in l2l_data: + l2l_data_provider_peer = xtree.SubElement(l2l_data_providers, "peer") + xtree.SubElement(l2l_data_provider_peer, "ip").text = item[data.IP] + xtree.SubElement(l2l_data_provider_peer, "pubkey").text = item[data.PUBLIC].split(' ')[0] + xtree.SubElement(l2l_data_provider_peer, "port").text = str(item[data.PORT]) + + dns = "" + if args.lookup_dns_domain is not None: + if args.seed_multiplier and is_seedprv(args): + dns = '{testnet}-seedpub-{index}.{domain}'.format(testnet="native", index=offset, + domain=args.lookup_dns_domain) + xtree.SubElement(l2l_data_provider_peer, "hostname").text = dns + offset += 1 + + multiplier_nodes = root.find('multipliers') + offset = 0 + for item in data.get_multiplier(): + + multiplier_peer = xtree.SubElement(multiplier_nodes, "peer") + xtree.SubElement(multiplier_peer, "ip").text = item[data.IP] + xtree.SubElement(multiplier_peer, "port").text = str(item[data.PORT]) + xtree.SubElement(multiplier_peer, "pubkey").text = item[data.PUBLIC].split(' ')[0] + + if args.lookup_dns_domain is not None: + dns = '{testnet}-multiplier-{index}.{domain}'.format(testnet="native", index=offset, + domain=args.lookup_dns_domain) + xtree.SubElement(multiplier_peer, "hostname").text = dns + else: + xtree.SubElement(multiplier_peer, "hostname").text = "" + offset += 1 + + # new code to move the status and lookup port away from the default + + my_ip, my_port = get_my_ip_and_port(args, data) + + if my_port is not None: + if is_lookup(args) or is_seedpub(args) or is_seedprv(args): + general = root.find('general') + general.find('LOOKUP_NODE_MODE').text = "true" + + jsonrpc = root.find('jsonrpc') + global lookup_rpc_port + if lookup_rpc_port == None: + lookup_rpc_port = int(jsonrpc.find('LOOKUP_RPC_PORT').text) + + jsonrpc.find('LOOKUP_RPC_PORT').text = str(int(my_port)+1) + lookup_rpc_port = lookup_rpc_port + 1 + + ''' New Configuration for native''' + + guardmode = root.find('guard_mode') + if guardmode: + guardmode.find('GUARD_MODE').text = "true" + + transactions = root.find('transactions') + if transactions: + transactions.find('BUCKET_NAME').text = "native" + transactions.find('TXN_PERSISTENCE_NAME').text = "zilliqa" + + ''' configure SCILLA_MULTI_VERSION correctly ''' + + scilla = root.find('smart_contract') + if scilla: + scilla.find('ENABLE_SCILLA_MULTI_VERSION').text = "false" + scilla.find('LOG_SC').text = "true" + + + metrics = root.find('metrics') + if metrics: + metrics.find('ENABLE_METRICS').text = "false" + metrics.find('METRIC_ZILLIQA_PROVIDER').text = "NONE" + + + + jsonrpc = root.find('jsonrpc') + if my_port is not None: + status_rpc_port = int(my_port) + 2 + jsonrpc.find('STATUS_RPC_PORT').text = str(status_rpc_port) + else: + print("my_port is None") + + transactions = root.find('transactions') + if is_lookup(args) or is_seedpub(args) or is_seedprv(args): + transactions.find('ENABLE_REPOPULATE').text = "true" + else: + transactions.find('ENABLE_REPOPULATE').text = "false" + + if (is_dsguard(args) or is_shard_guard(args)) and args.txnsbackup: + transactions.find('ENABLE_TXNS_BACKUP').text = "true" + else: + transactions.find('ENABLE_TXNS_BACKUP').text = "false" + + if is_seedpub(args): + seed = root.find('seed') + seed.find('ARCHIVAL_LOOKUP').text = "true" + seed.find('ENABLE_SEED_TO_SEED_COMMUNICATION').text = "true" + else: + seed = root.find('seed') + seed.find('ENABLE_SEED_TO_SEED_COMMUNICATION').text = "false" + + jsonrpc = root.find("jsonrpc") + if jsonrpc and jsonrpc.find("ENABLE_STAKING_RPC") is not None: + if is_seedpub(args): + jsonrpc.find("ENABLE_STAKING_RPC").text = "true" + else: + jsonrpc.find("ENABLE_STAKING_RPC").text = "false" + + if jsonrpc and jsonrpc.find("ENABLE_WEBSOCKET") is not None: + if args.websocket and args.type in args.websocket: + jsonrpc.find("ENABLE_WEBSOCKET").text = "true" + else: + jsonrpc.find("ENABLE_WEBSOCKET").text = "false" + + if is_seedprv(args): + seed = root.find('seed') + seed.find('ARCHIVAL_LOOKUP').text = "true" + + jsonrpc = root.find('jsonrpc') + jsonrpc.find('ENABLE_GETTXNBODIESFORTXBLOCK').text = "true" + + # To enable txn generation for seedprv, uncomment line below and comment other following line + # if is_seedprv(args) or (is_lookup(args) and args.transaction_sender == args.index): + if is_lookup(args) and args.index in args.transaction_sender: + dispatcher = root.find('dispatcher') + dispatcher.find('USE_REMOTE_TXN_CREATOR').text = "true" + + # strip off private keys as nodes shouldn't see them + accounts = root.find('accounts') + if accounts is not None: + for account in accounts.findall('account'): + private_key = account.find('private_key') + if private_key is not None: + account.remove(private_key) + ds_accounts = root.find('ds_accounts') + if ds_accounts is not None: + for ds_account in ds_accounts.findall('account'): + private_key = ds_account.find('private_key') + if private_key is not None: + ds_account.remove(private_key) + + tree = xtree.ElementTree(root) + tree.write('constants.xml') + + +def create_ds_whitelist_xml(args, data): + + nodes = xtree.Element("nodes") + for item in data.get_normal(): + peer = xtree.SubElement(nodes, "peer") + xtree.SubElement(peer, "pubk").text = item[data.PUBLIC].split(' ')[0] + xtree.SubElement(peer, "ip").text = item[data.IP] + xtree.SubElement(peer, "port").text = str(item[data.PORT]) + + tree = xtree.ElementTree(nodes) + tree.write("ds_whitelist.xml") + + +def create_shard_whitelist_xml(data): + # public key + normal = data.get_normal() + + nodes = xtree.Element("address") + for item in normal: + xtree.SubElement(nodes, "pubk").text = item[data.PUBLIC].split(' ')[0] + + tree = xtree.ElementTree(nodes) + tree.write("shard_whitelist.xml") + + +def create_config_xml( args, data): + if is_new(args): + # create a config.xml with 0 ds node information when I am a new node + ds = [] + ds = [] + else: + ds = data.get_normal() + + nodes = xtree.Element("nodes") + for item in ds: + peer = xtree.SubElement(nodes, "peer") + xtree.SubElement(peer, "pubk").text = item[data.PUBLIC].split(' ')[0] + xtree.SubElement(peer, "ip").text = item[data.IP] + xtree.SubElement(peer, "port").text = str(item[data.PORT]) + + tree = xtree.ElementTree(nodes) + tree.write("config.xml") + + +def create_dsnodes_xml(args, data): + ds = data.get_normal() + dsnode = xtree.Element("dsnodes") + for item in ds: + xtree.SubElement(dsnode, "pubk").text = item[data.PUBLIC].split(' ')[0] + tree = xtree.ElementTree(dsnode) + tree.write("dsnodes.xml") + + +SED = "sed -i " + ('""' if sys.platform == 'darwin' else '') + + +def gen_testnet_sed_string(args, fileName): + return f'{SED} "s,^TESTNET_NAME=.*$,TESTNET_NAME= \'{"native"}\'," {fileName}' + + +def gen_bucket_sed_string(args, fileName): + return f'{SED} "s,^BUCKET_NAME=.*$,BUCKET_NAME= \'{args.bucket}\'," {fileName}' + + +def create_start_sh(args, zil_data): + block0 = '0' * int(args.block_number_size / 4 - 1) + '1' # 000....001 + ds_diff = "05" # genesis ds diff + diff = "03" # genesis diff + rand1 = "2b740d75891749f94b6a8ec09f086889066608e4418eda656c93443e8310750a" + rand2 = "e8cc9106f8a28671d91e2de07b57b828934481fadf6956563b963bb8e5c266bf" + test = get_my_keypair(args, zil_data) + my_public_key, my_private_key = test.strip().split(' ') + my_ip, my_port = get_my_ip_and_port(args, zil_data) + my_ns = 'zil-ns-{}'.format(int(my_ip[my_ip.rfind('.') + 1:])) + + # hex string from IPv4 or IPv6 string + def ip_to_hex(ip): + ip = int(netaddr.IPAddress(ip)) + ip = '{0:08X}'.format(ip) + ip = hex(struct.unpack('>I', struct.pack(']*>\\([^<]*\\)<[^>]*>.*$,\\1,\')', + f'[ ! -z "$o1" ] && {SED} "s,^NUM_DSBLOCK=.*$,NUM_DSBLOCK= $o1," /run/zilliqa/upload_incr_DB.py' if is_lookup( + args) or is_seedpub(args) or is_dsguard(args) else '', + f'[ ! -z "$o1" ] && {SED} "s,^NUM_DSBLOCK=.*$,NUM_DSBLOCK= $o1," /run/zilliqa/download_incr_DB.py', + 'o1=$(grep NUM_FINAL_BLOCK_PER_POW /run/zilliqa/constants.xml | sed -e \'s,^[^<]*<[^>]*>\\([^<]*\\)<[^>]*>.*$,\\1,\')', + f'[ ! -z "$o1" ] && {SED} "s,^NUM_FINAL_BLOCK_PER_POW=.*$,NUM_FINAL_BLOCK_PER_POW= $o1," /run/zilliqa/upload_incr_DB.py' if is_lookup( + args) or is_seedpub(args) or is_dsguard(args) else '', + f'[ ! -z "$o1" ] && {SED} "s,^NUM_FINAL_BLOCK_PER_POW=.*$,NUM_FINAL_BLOCK_PER_POW= $o1," /run/zilliqa/download_incr_DB.py', + gen_testnet_sed_string(args, "/run/zilliqa/upload_incr_DB.py") if is_lookup(args) or is_seedpub( + args) or is_dsguard(args) else '', + gen_bucket_sed_string(args, "/run/zilliqa/upload_incr_DB.py") if is_lookup(args) or is_seedpub( + args) or is_dsguard(args) else '', + 'chmod u+x /run/zilliqa/upload_incr_DB.py' if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + 'cp /zilliqa/scripts/auto_backup.py /run/zilliqa/auto_backup.py' if is_lookup(args) or is_seedpub( + args) or is_dsguard(args) else '', + gen_testnet_sed_string(args, "/run/zilliqa/auto_backup.py") if is_lookup(args) or is_seedpub( + args) or is_dsguard(args) else '', + gen_bucket_sed_string(args, "/run/zilliqa/auto_backup.py") if is_lookup(args) or is_seedpub(args) or is_dsguard( + args) else '', + 'chmod u+x /run/zilliqa/auto_backup.py' if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + # 'pip3 install ' + ('--user ' if sys.platform == 'darwin' else '') + 'requests clint', + 'storage_path=$(grep STORAGE_PATH /run/zilliqa/constants.xml | sed -e \'s,^[^<]*<[^>]*>\\([^<]*\\)<[^>]*>.*$,\\1,\')' if is_new( + args) or is_seedprv(args) else '', + gen_testnet_sed_string(args, "/run/zilliqa/download_incr_DB.py"), + gen_bucket_sed_string(args, "/run/zilliqa/download_incr_DB.py"), + gen_testnet_sed_string(args, "/run/zilliqa/download_static_DB.py"), + gen_bucket_sed_string(args, "/run/zilliqa/download_static_DB.py"), + 'export AWS_ENDPOINT_URL=http://0.0.0.0:4566', + 'export PATH=/run/zilliqa:$PATH', + defer_cmd(cmd_setprimaryds, 15) if is_ds(args) else '', + defer_cmd(cmd_startpow, 25) if is_non_ds(args) else '', + cmd_zilliqa_daemon(args, resume=args.resume), + '[ "$1" != "--recovery" ] && exit 1', + '# The followings are recovery sequences' + ] + + cmd_recovery = [ + 'touch recovery', + 'for i in {{1..{}}}'.format(args.max_recovery), + 'do', + 'echo $(($(recovery', # increase the readiness counter + 'echo "Previous run failed, recovering $(\n') + for item in data.get_normal(): + f.write('' + item[data.IP] + '' + str(item[data.PORT]) + '' + item[data.PUBLIC].split(' ')[0] + '\n') + for item in data.get_guard(): + f.write('' + item[data.IP] + '' + str(item[data.PORT]) + '' + + item[data.PUBLIC].split(' ')[0] + '\n') + f.write('') + + +# Get default index via the hostname TESTNET-TYPE-INDEX +# This doesn't work when hostNetwork is used +def default_index(): + return int(socket.gethostname().rsplit('-', 1)[1]) + + +def str2fanout(s): + """Convert the string into an array of numbers representing number of seedpub nodes under each multiplier + + Example: + '0': 1 multiplier with 0 seedpub nodes + '1,2': 2 multipliers with 3 seedpub nodes + '5,5,5,0,0': 5 multipliers with 15 seedpub nodes + """ + try: + fanout = [int(x) for x in s.split(',')] + except Exception as _: + raise argparse.ArgumentTypeError("'{}' is not a valid fanout parameter") + return fanout + + +def str2uints(s): + return str2fanout(s) + + +LOOKUP_TYPES = ('lookup', 'seedpub', 'seedprv') + + +def str2lookup(s): + if not s: + return [] + splits = s.split(',') + for typ in splits: + if typ not in LOOKUP_TYPES: + raise argparse.ArgumentTypeError("Unknown lookup type {}. Should be one of {}".format(typ, LOOKUP_TYPES)) + return splits + + +def generate_files(args, data, pod_name): + create_constants_xml(args, data) + if is_normal(args) or is_dsguard(args): + create_ds_whitelist_xml(args, data) + create_shard_whitelist_xml(data) + create_config_xml(args, data) + create_dsnodes_xml(args, data) + return create_start_sh(args, data) + +def generate_nodes(args, zil_data, node_type, first_index, count) -> bool: + cwd = os.getcwd() + scripts_dir = os.path.abspath(os.path.join(cwd, '../scripts')) + zilliqa_dir = os.path.abspath(os.path.join(scripts_dir, '../')) + scilla_dir = os.path.abspath(os.path.join(scripts_dir, '../..', 'scilla')) + for index in range(first_index, first_index + count): + try: + pod_name = f'{"native"}-{node_type}-{index}' + pod_path = os.path.join(args.out_dir, pod_name) + + try: + os.mkdir(pod_path) + except FileExistsError: + pass + + os.chdir(pod_path) + + args.type = node_type + args.index = index + + if (node_type != 'multiplier'): + generate_files(args, zil_data, pod_name) + else: + create_constants_xml(args, zil_data) + multi_basic_auth_url = '{}/multiplier-downstream.txt'.format("http://0.0.0.0:8000") + create_multiplier_start_sh(zil_data.multiplier_port, multi_basic_auth_url) + create_new_multiplier_file(zil_data) + + # generate one just because we can + + if (node_type == 'normal'): + generate_ip_mapping_file(zil_data) + + print(f'Generated files for pod_path: {pod_path}') + print(f'Generated files for scripts_dir: {scripts_dir}') + + + sed_extra_arg = '-i ""' if sys.platform == "darwin" else '-i' + os.system( + f'sed {sed_extra_arg} -e "s,/run/zilliqa,{pod_path}," -e "s,/zilliqa/scripts,{scripts_dir}," start.sh') + + if (node_type != 'multiplier'): + try: + os.system( + f'sed {sed_extra_arg} -e "s,.*,{scilla_dir}," -e "s,.*,{zilliqa_dir}/evm-ds/target/debug/evm-ds," -e "s,.*,{zilliqa_dir}/evm-ds/log4rs.yml," -e "s,\.sock\>,-{node_type}.{index}.sock," constants.xml') + except Exception as e: # noqa + print(f'Failed to replace constants.xml: {e}') + return False + + for file_name in ['zilliqa', 'zilliqad', 'sendcmd', 'asio_multiplier']: + try: + os.remove(file_name) + except FileNotFoundError: + pass + try: + os.link(os.path.join(args.build_dir, 'bin', file_name), file_name) + except FileExistsError: + pass + + finally: + os.chdir(os.getcwd()) + return True + + +def create_multiplier_start_sh(listen_port, lookupips_url): + start_sh = [ + '#!/bin/bash', + 'echo "Starting multiplier"', + 'echo "Listening on port {}"'.format(listen_port), + 'echo "Lookup IPs URL: {}"'.format(lookupips_url), + 'echo "Starting multiplier"', + '(./asio_multiplier -l "{}" -s "{}" &)'.format(listen_port, lookupips_url), + ] + + with open('start.sh', 'w') as f: + for line in start_sh: + f.write(line + '\n') + +def create_new_multiplier_file(zil_data) -> bool: + try: + os.remove("{}/multiplier-downstream.txt".format(zil_data.origin_server)) + except FileNotFoundError: + pass + + with open("{}/multiplier-downstream.txt".format(zil_data.origin_server), 'w') as f: + for node in zil_data.seedpub_ips_from_origin: + f.write(node[0] + ":" + str(node[1]) + "\n") + return True diff --git a/native/old-code/init.py b/native/old-code/init.py new file mode 100644 index 0000000000..7a2d59a24f --- /dev/null +++ b/native/old-code/init.py @@ -0,0 +1,1131 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import argparse +import base64 +import os +import re +import shutil +import socket +import struct +import subprocess +import sys +import time +import urllib.error +import urllib.parse +import urllib.request +import xml.etree.cElementTree as xtree +from datetime import datetime, timedelta +from os import path +from urllib.parse import urlparse + +import boto3 +import netaddr +import requests + +############################# constants ######################################## +ELB_WAITING_TIME_IN_MINUTES = 5 +TESTNET_READINESS_TIME_IN_MINUTES = 300 +lookup_rpc_port = None + +############################# utility functions ################################ + +def readline_from_file(filename): + with open(filename, 'r') as f: + return [line.strip() for line in f.readlines()] + + +def get_my_keypair(args): + if is_dsguard(args): + return args.keypairs[args.index] + + if is_normal(args): + offset = args.d if args.skip_non_guard_ds else args.ds_guard + return args.keypairs[offset + args.index] + + if is_lookup(args): + return args.lookup_keypairs[args.index] + + if is_seedpub(args): + return args.seedpub_keypairs[args.index] + + if is_new(args) and len(args.new_keypairs) > args.index: + return args.new_keypairs[args.index] + + if args.testing: + return '02C197AB58D4B2F11691341BCAB8A4F7E7FDFFE756EF24D0AF066103DAEFD121E1 4B7DDC27B56407EBF8D1B124A2E79EFBE920E0BAB80AB361D6CCEA7C4B135BB8' + + return subprocess.check_output('genkeypair').decode().strip() + + +def get_my_ip_and_port(args): + if is_dsguard(args): + return args.normal_ips[args.index] + + if is_normal(args): + offset = args.d if args.skip_non_guard_ds else args.ds_guard + return args.normal_ips[offset + args.index] + + if is_lookup(args): + return args.lookup_ips[args.index] + + if is_seedpub(args): + return args.seedpub_ips[args.index] + + return (None, None) + + +def redact_private_key(filename, ignore_index=None): + """ + original keys.txt: + abc def + hij klm + nop qrs + start_private_key('keys.txt', ignore_index=1) + processed keys.txt: + abc * + hij klm + nop * + """ + out = [] + with open(filename) as f: + for i, pair in enumerate(f): + if i == ignore_index: + out.append(pair.strip()) + else: + out.append(pair.split()[0] + ' *') + with open(filename, 'w') as f: + f.write('\n'.join(out)) + + +KEY_FILES = ['keys.txt', 'lookup_keys.txt', 'seedpub_keys.txt', 'new_keys.txt', 'multiplier_keys.txt'] + + +def clean_non_self_private_keys(args): + """ + redact all non-self private keys + """ + index = args.index + self_file = '' + + if is_normal(args): + self_file = 'keys.txt' + # recalculate 'index' in the same way in `get_my_keypair()` + offset = args.d if args.skip_non_guard_ds else args.ds_guard + index = offset + args.index + + if is_dsguard(args): + self_file = 'keys.txt' + + if is_lookup(args): + self_file = 'lookup_keys.txt' + + if is_seedpub(args): + self_file = 'seedpub_keys.txt' + + if is_new(args) and len(args.new_keypairs) > args.index: + self_file = 'new_keys.txt' + + if is_multiplier(args): + # speical case: multiplier doesn't need its own private key + self_file = '' + + print("start cleaning non-self private keys") + print("self type: %s, key file: %s, key index: %s" % (args.type, self_file, index)) + for key_file in KEY_FILES: + key_file_path = path.join(args.conf_dir, 'secret', key_file) + if not path.isfile(key_file_path): + continue + if key_file == self_file: + print("redacting private keys (without index %s) of key file: %s" % (index, key_file)) + redact_private_key(key_file_path, index) + else: + print("redacting all private keys of key file: " + key_file) + redact_private_key(key_file_path) + print("done") + + +def get_my_aws_ipv4(args): # works on AWS + if args.testing: + return '169.254.169.254' + + # https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html + ipv4_re = r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" + + # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-instance-addressing.html + response = urllib.request.urlopen('http://169.254.169.254/latest/meta-data/public-ipv4') + ipv4 = response.read().decode() + + match = re.match(ipv4_re, ipv4) + if match and match.group(0) == ipv4: + return ipv4 + + print('Cannnot get valid public address: got {}'.format(ipv4)) + return '' + + +# A pod may be one of the following type +# - lookup +# - dsguard (only exist when guards are used) +# - normal +# * ds or non-ds +# * shard_guard +# - multiplier +# - new +# - seedprv + +def is_lookup(args): + return args.type == 'lookup' + + +def is_seedpub(args): + return args.type == 'seedpub' + + +def is_multiplier(args): + return args.type == 'multiplier' + + +def is_normal(args): + return args.type == 'normal' + + +def is_new(args): + return args.type == 'new' + + +def is_seedprv(args): + return args.type == 'seedprv' + + +# pod map for nodes of type normal and/or dsguard +# +# notations: +# * N -> normal pod +# * D -> dsguard pod +# * d -> args.d +# * n -> args.n +# * dg -> args.ds_guard +# * sg -> args.shard_guard + +# -------------------------------------------------------------------------------------------------------------------------- +# | line # in keys.txt | guard mode disabled | guard mode enabled | guard mode, non-guard DS skipped | is_* == True +# -------------------------------------------------------------------------------------------------------------------------- +# | 0 | N 0 | D 0 | D 0 | is_ds, is_ds_guard +# | 1 | N 1 | D 1 | D 1 | is_ds, is_ds_guard +# | 2 | N 2 | D 2 | D 2 | is_ds, is_ds_guard +# | ... | ... | ... | ... | is_ds, is_ds_guard +# | (dg - 1) | N (dg - 1) | D (dg - 1) | D (dg - 1) | is_ds, is_ds_guard +# -------------------------------------------------------------------------------------------------------------------------- +# | (dg) | N (dg) | N 0 | skipped | is_ds, +# | (dg + 1) | N (dg + 1) | N 1 | skipped | is_ds, +# | ... | ... | ... | ... | is_ds, +# | (d - 1) | N (d - 1) | N (d - dg - 1) | skipped | is_ds, +# -------------------------------------------------------------------------------------------------------------------------- +# | (d) | N (d) | N (d - dg) | N 0 | is_non_ds, is_shard_guard +# | d + 1 | N (d + 1) | N (d - dg + 1) | N 1 | is_non_ds, is_shard_guard +# | ... | ... | ... | ... | is_non_ds, is_shard_guard +# | d + sg - 1 | N (d + sg - 1) | N (d - dg + sg - 1) | N (sg - 1) | is_non_ds, is_shard_guard +# -------------------------------------------------------------------------------------------------------------------------- +# | d + sg | N (d + sg) | N (d - dg + sg) | N (sg) | is_non_ds, +# | d + sg + 1 | N (d + sg + 1) | N (d - dg + sg + 1) | N (sg + 1) | is_non_ds, +# | ... | ... | ... | ... | is_non_ds, +# | (n - 1) | N (n - 1) | N (n - dg - 1) | N (n - d - 1) | is_non_ds, + +def is_ds(args): + if args.type == 'dsguard': + return True + + if args.type == 'normal': + # If non-guard DS nodes are skipped, all normal nodes fall into non-DS + if args.skip_non_guard_ds: + return False + # Else, check the index to see if it's DS node + return args.index < args.d - args.ds_guard + + # other types are definitely not DS + return False + + +def is_non_ds(args): + if args.type == 'normal': + # if non-guard DS nodes are skipped, all normal nodes fall into non-DS + if args.skip_non_guard_ds: + return True + # Else, check the index + return args.index >= args.d - args.ds_guard + + return False + + +def is_dsguard(args): + return args.type == 'dsguard' + + +def is_shard_guard(args): + if args.type == 'normal': + offset = args.d if args.skip_non_guard_ds else args.ds_guard + return offset + args.index >= args.d and offset + args.index < args.d + args.shard_guard + + return False + + +################################ functions #################################### +def filter_empty_ip(ip_list): + result = [] + for ip in ip_list: + if ip != "": + result.append(ip) + return result + + +def create_constants_xml(args): + root = xtree.parse(path.join(args.conf_dir, 'configmap', 'constants.xml')).getroot() + + lookup_nodes = root.find('lookups') + lookup_ips = args.lookup_ips[0: args.l] + lookup_public_keys = [k.split(' ')[0] for k in args.lookup_keypairs[0: args.l]] + + multiplier_ips = filter_empty_ip(args.multiplier_ips)[0: len(args.multiplier_fanout)] + multiplier_public_keys = [k.split(' ')[0] for k in args.multiplier_keypairs[0: len(args.multiplier_fanout)]] + + seedpub_ips = args.seedpub_ips[0: sum(args.multiplier_fanout)] + seedpub_public_keys = [k.split(' ')[0] for k in args.seedpub_keypairs[0: sum(args.multiplier_fanout)]] + + upper_seed_ip = [] + upper_seed_pubkey = [] + upper_seed_index = [] + + l2l_data_provider_ip = [] + l2l_data_provider_pubkey = [] + l2l_data_provider_index = [] + + # Upper seed for lookup = all lookups + if is_lookup(args): + upper_seed_ip = lookup_ips + upper_seed_pubkey = lookup_public_keys + upper_seed_index = list(range(len(lookup_ips))) + # Upper seed for seedprv / seed-configuration.tar.gz = all seedpubs + elif is_seedprv(args): + upper_seed_ip = seedpub_ips[0:sum(args.multiplier_fanout)] + upper_seed_pubkey = seedpub_public_keys[0:sum(args.multiplier_fanout)] + upper_seed_index = list(range(0, sum(args.multiplier_fanout))) + l2l_data_provider_ip = seedpub_ips[0:sum(args.multiplier_fanout)] + l2l_data_provider_pubkey = seedpub_public_keys[0:sum(args.multiplier_fanout)] + l2l_data_provider_index = list(range(0, sum(args.multiplier_fanout))) + # Upper seed for seedpub = last X lookups + elif is_seedpub(args): + if args.l >= 4: + upper_seed_ip = lookup_ips[2:args.l] + upper_seed_pubkey = lookup_public_keys[2:args.l] + upper_seed_index = list(range(2, args.l)) + else: + upper_seed_ip = [lookup_ips[args.l - 1]] + upper_seed_pubkey = [lookup_public_keys[args.l - 1]] + upper_seed_index = [args.l - 1] + # Upper seed for dsguard / normal / configuration.tar.gz = all seedpubs (if available) or all lookups + else: + if args.seed_multiplier: + upper_seed_ip = seedpub_ips[0:sum(args.multiplier_fanout)] + upper_seed_pubkey = seedpub_public_keys[0:sum(args.multiplier_fanout)] + upper_seed_index = list(range(0, sum(args.multiplier_fanout))) + else: + upper_seed_ip = lookup_ips + upper_seed_pubkey = lookup_public_keys + upper_seed_index = list(range(len(lookup_ips))) + + upper_seed_nodes = root.find('upper_seed') + + for (index, ip, pubkey) in zip(range(len(lookup_ips)), lookup_ips, lookup_public_keys): + lookup_peer = xtree.SubElement(lookup_nodes, "peer") + xtree.SubElement(lookup_peer, "ip").text = ip[0] + xtree.SubElement(lookup_peer, "pubkey").text = pubkey + xtree.SubElement(lookup_peer, "port").text = str(ip[1]) + + if args.lookup_dns_domain is not None: + dns = '{testnet}-lookup-{index}.{domain}'.format(testnet=args.testnet, index=index, domain=args.lookup_dns_domain) + xtree.SubElement(lookup_peer, "hostname").text = dns + else: + xtree.SubElement(lookup_peer, "hostname").text = "" + + # upper seed takes peers from lookups, the DNS names are the same + for (index, ip, pubkey) in zip(upper_seed_index, upper_seed_ip, upper_seed_pubkey): + upper_seed_peer = xtree.SubElement(upper_seed_nodes, "peer") + xtree.SubElement(upper_seed_peer, "ip").text = ip[0] + xtree.SubElement(upper_seed_peer, "pubkey").text = pubkey + xtree.SubElement(upper_seed_peer, "port").text = str(ip[1]) + + if args.lookup_dns_domain is not None: + if args.seed_multiplier and not (is_seedpub(args) or is_lookup(args)): + dns = '{testnet}-seedpub-{index}.{domain}'.format(testnet=args.testnet, index=index, domain=args.lookup_dns_domain) + else: + dns = '{testnet}-lookup-{index}.{domain}'.format(testnet=args.testnet, index=index, domain=args.lookup_dns_domain) + xtree.SubElement(upper_seed_peer, "hostname").text = dns + else: + xtree.SubElement(upper_seed_peer, "hostname").text = "" + + l2l_data_providers = root.find('l2l_data_providers') + # l2l data providers takes peers from lookups, the DNS names are the same + for (index, ip, pubkey) in zip(l2l_data_provider_index, l2l_data_provider_ip, l2l_data_provider_pubkey): + l2l_data_provider_peer = xtree.SubElement(l2l_data_providers, "peer") + xtree.SubElement(l2l_data_provider_peer, "ip").text = ip[0] + xtree.SubElement(l2l_data_provider_peer, "pubkey").text = pubkey + xtree.SubElement(l2l_data_provider_peer, "port").text = str(ip[1]) + + dns = "" + if args.lookup_dns_domain is not None: + if args.seed_multiplier and is_seedprv(args): + dns = '{testnet}-seedpub-{index}.{domain}'.format(testnet=args.testnet, index=index, domain=args.lookup_dns_domain) + xtree.SubElement(l2l_data_provider_peer, "hostname").text = dns + + multiplier_nodes = root.find('multipliers') + for (index, ip, key) in zip(list(range(len(multiplier_ips))), multiplier_ips, multiplier_public_keys): + multiplier_peer = xtree.SubElement(multiplier_nodes, "peer") + xtree.SubElement(multiplier_peer, "ip").text = ip[0] + xtree.SubElement(multiplier_peer, "port").text = str(ip[1]) + xtree.SubElement(multiplier_peer, "pubkey").text = key + + if args.lookup_dns_domain is not None: + dns = '{testnet}-multiplier-{index}.{domain}'.format(testnet=args.testnet, index=index, domain=args.lookup_dns_domain) + xtree.SubElement(multiplier_peer, "hostname").text = dns + else: + xtree.SubElement(multiplier_peer, "hostname").text = "" + + if is_lookup(args) or is_seedpub(args) or is_seedprv(args): + general = root.find('general') + general.find('LOOKUP_NODE_MODE').text = "true" + + jsonrpc = root.find('jsonrpc') + global lookup_rpc_port + if lookup_rpc_port == None: + lookup_rpc_port = int(jsonrpc.find('LOOKUP_RPC_PORT').text) + + jsonrpc.find('LOOKUP_RPC_PORT').text = str(lookup_rpc_port) + lookup_rpc_port = lookup_rpc_port + 1 + + + transactions = root.find('transactions') + if is_lookup(args) or is_seedpub(args) or is_seedprv(args): + transactions.find('ENABLE_REPOPULATE').text = "true" + else: + transactions.find('ENABLE_REPOPULATE').text = "false" + + if (is_dsguard(args) or is_shard_guard(args)) and args.txnsbackup: + transactions.find('ENABLE_TXNS_BACKUP').text = "true" + else: + transactions.find('ENABLE_TXNS_BACKUP').text = "false" + + if is_seedpub(args): + seed = root.find('seed') + seed.find('ARCHIVAL_LOOKUP').text = "true" + seed.find('ENABLE_SEED_TO_SEED_COMMUNICATION').text = "true" + else: + seed = root.find('seed') + seed.find('ENABLE_SEED_TO_SEED_COMMUNICATION').text = "false" + + jsonrpc = root.find("jsonrpc") + if jsonrpc and jsonrpc.find("ENABLE_STAKING_RPC") is not None: + if is_seedpub(args): + jsonrpc.find("ENABLE_STAKING_RPC").text = "true" + else: + jsonrpc.find("ENABLE_STAKING_RPC").text = "false" + + if jsonrpc and jsonrpc.find("ENABLE_WEBSOCKET") is not None: + if args.websocket and args.type in args.websocket: + jsonrpc.find("ENABLE_WEBSOCKET").text = "true" + else: + jsonrpc.find("ENABLE_WEBSOCKET").text = "false" + + if is_seedprv(args): + seed = root.find('seed') + seed.find('ARCHIVAL_LOOKUP').text = "true" + + jsonrpc = root.find('jsonrpc') + jsonrpc.find('ENABLE_GETTXNBODIESFORTXBLOCK').text = "true" + + # To enable txn generation for seedprv, uncomment line below and comment other following line + # if is_seedprv(args) or (is_lookup(args) and args.transaction_sender == args.index): + if is_lookup(args) and args.index in args.transaction_sender: + dispatcher = root.find('dispatcher') + dispatcher.find('USE_REMOTE_TXN_CREATOR').text = "true" + + # strip off private keys as nodes shouldn't see them + accounts = root.find('accounts') + if accounts is not None: + for account in accounts.findall('account'): + private_key = account.find('private_key') + if private_key is not None: + account.remove(private_key) + ds_accounts = root.find('ds_accounts') + if ds_accounts is not None: + for ds_account in ds_accounts.findall('account'): + private_key = ds_account.find('private_key') + if private_key is not None: + ds_account.remove(private_key) + + tree = xtree.ElementTree(root) + tree.write('constants.xml') + + +def create_ds_whitelist_xml(args): + # public key + ip + port + normal_public_keys = [k.split(' ')[0] for k in args.keypairs[0: args.n]] + normal_ips = args.normal_ips[0: args.n] + + nodes = xtree.Element("nodes") + for (ip, pubkey) in zip(normal_ips, normal_public_keys): + peer = xtree.SubElement(nodes, "peer") + xtree.SubElement(peer, "pubk").text = pubkey + xtree.SubElement(peer, "ip").text = ip[0] + xtree.SubElement(peer, "port").text = str(ip[1]) + + tree = xtree.ElementTree(nodes) + tree.write("ds_whitelist.xml") + + +def create_shard_whitelist_xml(args): + # public key + normal_public_keys = [k.split(' ')[0] for k in args.keypairs[0: args.n]] + + nodes = xtree.Element("address") + for pubkey in normal_public_keys: + xtree.SubElement(nodes, "pubk").text = pubkey + + tree = xtree.ElementTree(nodes) + tree.write("shard_whitelist.xml") + + +def create_config_xml(args): + if is_new(args): + # create a config.xml with 0 ds node information when I am a new node + ds_public_keys = [] + ds_ips = [] + else: + ds_public_keys = [k.split(' ')[0] for k in args.keypairs[0: args.d]] + ds_ips = args.normal_ips[0: args.d] + + nodes = xtree.Element("nodes") + for (ip, pubkey) in zip(ds_ips, ds_public_keys): + peer = xtree.SubElement(nodes, "peer") + xtree.SubElement(peer, "pubk").text = pubkey + xtree.SubElement(peer, "ip").text = ip[0] + xtree.SubElement(peer, "port").text = str(ip[1]) + + tree = xtree.ElementTree(nodes) + tree.write("config.xml") + + +def create_multiplier_start_sh(listen_port, lookupips_url): + start_sh = [ + '#!/bin/bash', + 'case $(uname -m) in', + 'x86_64)', + 'curl -LO https://github.com/Zilliqa/goduplicator/releases/download/goduplicator-0.0.4/goduplicator', + ';;', + # Assume ARM; no precompiled binary so we need to compile ourselves + '*)', + 'apt update -y && apt install -y golang', + 'wget https://github.com/Zilliqa/goduplicator/archive/refs/tags/0.0.5.tar.gz && tar xvf 0.0.5.tar.gz', + 'cd goduplicator-0.0.5', + 'go mod download github.com/deckarep/golang-set', + 'go get github.com/zilliqa/goduplicator', + 'go build', + ';;', + 'esac', + 'chmod u+x goduplicator', + './goduplicator -l "{}" -s "{}"'.format(listen_port, lookupips_url), + ] + + with open('start.sh', 'w') as f: + for line in start_sh: + f.write(line + '\n') + + +def create_dsnodes_xml(args): + ds_public_keys = [k.split(' ')[0] for k in args.keypairs[0: args.d]] + dsnode = xtree.Element("dsnodes") + for pubkey in ds_public_keys: + xtree.SubElement(dsnode, "pubk").text = pubkey + tree = xtree.ElementTree(dsnode) + tree.write("dsnodes.xml") + + +SED = "sed -i " + ('""' if sys.platform == 'darwin' else '') + +def gen_testnet_sed_string(args, fileName): + return f'{SED} "s,^TESTNET_NAME=.*$,TESTNET_NAME= \'{args.testnet}\'," {fileName}' + + +def gen_bucket_sed_string(args, fileName): + return f'{SED} "s,^BUCKET_NAME=.*$,BUCKET_NAME= \'{args.bucket}\'," {fileName}' + + +def create_start_sh(args): + block0 = '0' * int(args.block_number_size / 4 - 1) + '1' # 000....001 + ds_diff = "05" # genesis ds diff + diff = "03" # genesis diff + rand1 = "2b740d75891749f94b6a8ec09f086889066608e4418eda656c93443e8310750a" + rand2 = "e8cc9106f8a28671d91e2de07b57b828934481fadf6956563b963bb8e5c266bf" + my_public_key, my_private_key = get_my_keypair(args).strip().split(' ') + my_ip, my_port = get_my_ip_and_port(args) + my_ns = 'zil-ns-{}'.format(int(my_ip[my_ip.rfind('.') + 1:])) + + # hex string from IPv4 or IPv6 string + def ip_to_hex(ip): + ip = int(netaddr.IPAddress(ip)) + ip = '{0:08X}'.format(ip) + ip = hex(struct.unpack('>I', struct.pack(']*>\\([^<]*\\)<[^>]*>.*$,\\1,\')', + f'[ ! -z "$o1" ] && {SED} "s,^NUM_DSBLOCK=.*$,NUM_DSBLOCK= $o1," /run/zilliqa/upload_incr_DB.py' if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + f'[ ! -z "$o1" ] && {SED} "s,^NUM_DSBLOCK=.*$,NUM_DSBLOCK= $o1," /run/zilliqa/download_incr_DB.py', + 'o1=$(grep NUM_FINAL_BLOCK_PER_POW /run/zilliqa/constants.xml | sed -e \'s,^[^<]*<[^>]*>\\([^<]*\\)<[^>]*>.*$,\\1,\')', + f'[ ! -z "$o1" ] && {SED} "s,^NUM_FINAL_BLOCK_PER_POW=.*$,NUM_FINAL_BLOCK_PER_POW= $o1," /run/zilliqa/upload_incr_DB.py' if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + f'[ ! -z "$o1" ] && {SED} "s,^NUM_FINAL_BLOCK_PER_POW=.*$,NUM_FINAL_BLOCK_PER_POW= $o1," /run/zilliqa/download_incr_DB.py', + gen_testnet_sed_string(args, "/run/zilliqa/upload_incr_DB.py") if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + gen_bucket_sed_string(args, "/run/zilliqa/upload_incr_DB.py") if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + 'chmod u+x /run/zilliqa/upload_incr_DB.py' if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + 'cp /zilliqa/scripts/auto_backup.py /run/zilliqa/auto_backup.py' if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + gen_testnet_sed_string(args, "/run/zilliqa/auto_backup.py") if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + gen_bucket_sed_string(args, "/run/zilliqa/auto_backup.py") if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + 'chmod u+x /run/zilliqa/auto_backup.py' if is_lookup(args) or is_seedpub(args) or is_dsguard(args) else '', + #'pip3 install ' + ('--user ' if sys.platform == 'darwin' else '') + 'requests clint', + 'storage_path=$(grep STORAGE_PATH /run/zilliqa/constants.xml | sed -e \'s,^[^<]*<[^>]*>\\([^<]*\\)<[^>]*>.*$,\\1,\')' if is_new(args) or is_seedprv(args) else '', + gen_testnet_sed_string(args, "/run/zilliqa/download_incr_DB.py"), + gen_bucket_sed_string(args, "/run/zilliqa/download_incr_DB.py"), + gen_testnet_sed_string(args, "/run/zilliqa/download_static_DB.py"), + gen_bucket_sed_string(args, "/run/zilliqa/download_static_DB.py"), + 'export AWS_ENDPOINT_URL=http://127.0.0.1:4566', + 'export PATH=/run/zilliqa:$PATH', + defer_cmd(cmd_setprimaryds, 20) if is_ds(args) and not args.recover_from_testnet else '', + defer_cmd(cmd_startpow, 40) if is_non_ds(args) and not args.recover_from_testnet else '', + cmd_zilliqa_daemon(args, resume=args.resume), + '[ "$1" != "--recovery" ] && exit 1', + '# The followings are recovery sequences' + ] + + cmd_recovery = [ + 'touch recovery', + 'for i in {{1..{}}}'.format(args.max_recovery), + 'do', + 'echo $(($(recovery', # increase the readiness counter + 'echo "Previous run failed, recovering $(\n') + for i in range(n): + f.write('' + ips[i] + '' + str(port) + '' + normal_public_keys[i] + '\n') + f.write('') + + +# Get default index via the hostname TESTNET-TYPE-INDEX +# This doesn't work when hostNetwork is used +def default_index(): + return int(socket.gethostname().rsplit('-', 1)[1]) + + +def str2fanout(s): + """Convert the string into an array of numbers representing number of seedpub nodes under each multiplier + + Example: + '0': 1 multiplier with 0 seedpub nodes + '1,2': 2 multipliers with 3 seedpub nodes + '5,5,5,0,0': 5 multipliers with 15 seedpub nodes + """ + try: + fanout = [int(x) for x in s.split(',')] + except Exception as _: + raise argparse.ArgumentTypeError("'{}' is not a valid fanout parameter") + return fanout + + +def str2uints(s): + return str2fanout(s) + + +LOOKUP_TYPES = ('lookup', 'seedpub', 'seedprv') + + +def str2lookup(s): + if not s: + return [] + splits = s.split(',') + for typ in splits: + if typ not in LOOKUP_TYPES: + raise argparse.ArgumentTypeError("Unknown lookup type {}. Should be one of {}".format(typ, LOOKUP_TYPES)) + return splits + + +def main(): + + parser = argparse.ArgumentParser(description='initialize zilliqa') + + parser.add_argument('--pod-name', help='pod name (TESTNET-TYPE-INDEX)') + parser.add_argument('--testnet', help='testnet name') + parser.add_argument('--type', choices=['normal', 'lookup', 'new', 'seedprv'], help='node type (normal, lookup, new, seedprv)') + parser.add_argument('--index', type=int, help='node index') + parser.add_argument('--metadata-url', help='the base URL for metadata') + parser.add_argument('-n', type=int, help='number of all nodes', required=True) + parser.add_argument('-d', type=int, help='number of ds nodes', required=True) + parser.add_argument('-l', type=int, help='number of lookup nodes', required=True) + parser.add_argument('--ds-guard', type=int, default=0, help='number of ds guards') + parser.add_argument('--shard-guard', type=int, default=0, help='number of shard guards') + parser.add_argument('--skip-non-guard-ds', action='store_true', default=False, help='do not create pods for non-guard DS nodes') + parser.add_argument('--conf-dir', default='/etc/zilliqa', help='The path of the mounted configmap') + parser.add_argument('--out-dir', help='The output directory') + parser.add_argument('--build-dir', help='The build directory') + parser.add_argument('--block-number-size', default=64, type=int, choices=[64, 256], help='block number size (64-bit, 256-bit)') + # TODO: --seed-multiplier is redudant when --multiplier-fanout is used + parser.add_argument('--seed-multiplier', action='store_true', default=True, help='Support seed multiplier') + parser.add_argument('--multiplier-fanout', type=str2fanout, help='the multiplier fanouts') + parser.add_argument('--max-recovery', default='2', help='Max tries for recovering zilliqa node') + parser.add_argument('--resume', action='store_true', help='Resume from persistent storage') + parser.add_argument('--recover-from-testnet', action='store_true', help='Recover all nodes from persistent storage') + parser.add_argument('--transaction-sender', default='0', type=str2uints, metavar='N', help='List of lookup indices that send testing transactions') + parser.add_argument('--origin-server', help='set external origin server instead using in-cluster one') + parser.add_argument('--lookup-dns-domain', help='the DNS name for lookup, multiplier, and seedpub nodes') + parser.add_argument('--log-path', help='Set customized log path') + parser.add_argument('--bucket', help='Set bucket name') + parser.add_argument('--hosted-zone-id', help='hosted zone ID') + parser.add_argument('--txnsbackup', action='store_true', help='Enable storing txns backup to S3') + parser.add_argument('--websocket', type=str2lookup, metavar='TYPE1,TYPE2', help='enable websocket for lookup server of TYPE, can be any of {}'.format(LOOKUP_TYPES)) + + group0 = parser.add_argument_group('Host Network Mode') + group0.add_argument('--port', type=int, help='port for zilliqa application') + + group1 = parser.add_argument_group('Local Testing Mode', 'for testing and debugging init.py') + group1.add_argument('--testing', action='store_true', help='enable local testing mode') + + group2 = parser.add_argument_group('Private keys cleanup Mode', + 'for cleaning up non-self private keys before running the working container') + group2.add_argument('--cleanup-private-keys', action='store_true', help='clean up non-self private keys') + + args = parser.parse_args() + + args.keypairs = readline_from_file(path.join(args.conf_dir, 'secret', 'keys.txt')) + if path.isfile(path.join(args.conf_dir, 'secret', 'new_keys.txt')): + args.new_keypairs = readline_from_file(path.join(args.conf_dir, 'secret', 'new_keys.txt')) + else: + args.new_keypairs = [] + args.lookup_keypairs = readline_from_file(path.join(args.conf_dir, 'secret', 'lookup_keys.txt')) + args.multiplier_keypairs = readline_from_file(path.join(args.conf_dir, 'secret', 'multiplier_keys.txt')) + args.seedpub_keypairs = readline_from_file(path.join(args.conf_dir, 'secret', 'seedpub_keys.txt')) + + if args.cleanup_private_keys: + clean_non_self_private_keys(args) + return 0 + + # The origin server stores the network information + if args.origin_server is not None: + # if --origin-server is set, use it first + origin_server = args.origin_server + elif args.metadata_url is not None: + # metadata dns record used to be created with nginx ingress installation, not now + # If --metadata-url is set, use the internal one of origin + origin_server = '{}/origin/{}'.format(args.metadata_url, args.testnet) + # origin_server = args.metadata_url + else: + origin_server = 'http://' + get_svc_ip('{}-origin'.format(args.testnet)) + + # TODO: move this to a reasonble position. It depends only on origin_server and args.index + if is_multiplier(args): + multi_basic_auth_url = get_basic_auth_link('{}/multiplier-{}-downstreams.txt'.format(origin_server, args.index), b_username, b_password) + create_multiplier_start_sh(':{}'.format(args.port), multi_basic_auth_url) + return 0 + + # Will block here until origin_server is accessible + first_lookup_port = args.port + lookup_ips_from_origin = get_ip_list_from_origin(origin_server, 'lookup_ips.txt', first_lookup_port) + first_normal_port = first_lookup_port + len(lookup_ips_from_origin) + normal_ips_from_origin = get_ip_list_from_origin(origin_server, 'normal_ips.txt', first_normal_port) + + if args.recover_from_testnet: + generate_ip_mapping_file(normal_ips_from_origin, args.keypairs, args.port, args.n) + + first_multiplier_port = first_normal_port + len(normal_ips_from_origin) + multiplier_ips_from_origin = get_ip_list_from_origin(origin_server, 'multiplier_ips.txt', first_multiplier_port) if args.seed_multiplier else [] + first_seedpub_port = first_multiplier_port + len(multiplier_ips_from_origin) + seedpub_ips_from_origin = get_ip_list_from_origin(origin_server, 'seedpub_ips.txt', first_seedpub_port) if args.seed_multiplier else [] + + # FIXME: only DS guard needs this flag, we can remove is_normal(args) here + # args.restart = is_restarted('{}-origin'.format(args.testnet)) if is_normal(args) or is_dsguard(args) else False + args.restart = False + + if is_seedprv(args): + args.verifier_keypair = subprocess.check_output('genkeypair').decode().strip() + # generate verifier file + with open("verifier.txt", 'w') as f: + f.write(args.verifier_keypair) + + + def generate_files(pod_name): + if is_lookup(args) or is_dsguard(args) or is_normal(args) or is_seedprv(args): + args.normal_ips = normal_ips_from_origin + args.lookup_ips = lookup_ips_from_origin + elif is_new(args) or is_seedpub(args): + args.normal_ips = [] + args.lookup_ips = lookup_ips_from_origin + + # if args.seed_multiplier and (is_lookup(args) or is_dsguard(args) or is_normal(args) or is_new(args)): + args.multiplier_ips = multiplier_ips_from_origin + args.seedpub_ips = seedpub_ips_from_origin + # else: + # args.multiplier_ips = [] + # if is_seedprv(args): + # args.seedpub_ips = seedpub_ips_from_origin + # else: + # args.seedpub_ips = [] + + create_constants_xml(args) + if is_normal(args) or is_dsguard(args): + create_ds_whitelist_xml(args) + create_shard_whitelist_xml(args) + create_config_xml(args) + create_dsnodes_xml(args) + return create_start_sh(args) + + def generate_nodes(node_type, first_index, count): + node_nss = [] + scripts_dir = os.path.dirname(os.path.abspath(__file__)) + zilliqa_dir = os.path.abspath(os.path.join(scripts_dir, '..', '..', 'zilliqa')) + scilla_dir = os.path.abspath(os.path.join(scripts_dir, '..', '..', 'scilla')) + for index in range(first_index, first_index + count): + try: + pod_name = f'{args.testnet}-{node_type}-{index}' + pod_path = os.path.join(args.out_dir, pod_name) + + try: + os.mkdir(pod_path) + except FileExistsError: + pass + + os.chdir(pod_path) + + args.type = node_type + args.index = index + node_nss.append(generate_files(pod_name)) + sed_extra_arg = '-i ""' if sys.platform == "darwin" else '-i' + os.system(f'sed {sed_extra_arg} -e "s,/run/zilliqa,{pod_path}," -e "s,/zilliqa/scripts,{scripts_dir}," netns_start.sh') + os.system(f'sed {sed_extra_arg} -e "s,.*,{scilla_dir}," -e "s,.*,{zilliqa_dir}/evm-ds/target/debug/evm-ds," -e "s,.*,{zilliqa_dir}/evm-ds/log4rs.yml," -e "s,\.sock\>,-{node_type}.{index}.sock," constants.xml') + + for file_name in ['zilliqa', 'zilliqad', 'sendcmd']: + try: + os.remove(file_name) + except FileNotFoundError: + pass + try: + os.link(os.path.join(args.build_dir, 'bin', file_name), file_name) + except FileExistsError: + pass + + finally: + os.chdir(os.getcwd()) + + return node_nss + + try: + os.mkdir(args.out_dir) + except FileExistsError: + pass + + cwd = os.getcwd() + + nss = [] + nss = nss + generate_nodes('lookup', 0, args.l) + nss = nss + generate_nodes('dsguard', 0, args.ds_guard) + nss = nss + generate_nodes('normal', 0, args.d - args.ds_guard) + nss = nss + generate_nodes('normal', args.d - args.ds_guard, args.n - args.d) + nss = nss + generate_nodes('seedpub', 0, sum(args.multiplier_fanout)) + + return 0 + + +if __name__ == "__main__": + main() diff --git a/native/requirements.txt b/native/requirements.txt new file mode 100644 index 0000000000..26e43a130c --- /dev/null +++ b/native/requirements.txt @@ -0,0 +1,3 @@ +netaddr~=0.8.0 +setuptools~=65.5.1 +pyzilla~=0.1.0 \ No newline at end of file diff --git a/native/run.sh b/native/run.sh new file mode 100755 index 0000000000..4639faaf3f --- /dev/null +++ b/native/run.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This script will start an isolated server and run the python API against it +# +set -e +echo 1 +(cd rundirs/native-lookup-0 && bash start.sh& ) +echo 2 +(cd rundirs/native-dsguard-0 && bash start.sh& ) +echo 3 +(cd rundirs/native-dsguard-1 && bash start.sh& ) +echo 4 +(cd rundirs/native-dsguard-2 && bash start.sh& ) +echo 5 +(cd rundirs/native-dsguard-3 && bash start.sh& ) +echo 6 +(cd rundirs/native-seedpub-0 && bash start.sh& ) +echo 7 +(cd rundirs/native-normal-0 && bash start.sh& ) +echo 8 +(cd rundirs/native-multiplier-0 && bash start.sh& ) diff --git a/native/setup.py b/native/setup.py new file mode 100755 index 0000000000..56b51e85ac --- /dev/null +++ b/native/setup.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from setuptools import find_packages, setup + +setup( + name='native', + packages=find_packages(), + version='0.1.0', + description='routines to drive native code', + author='Zilliqa', + license='MIT', +) diff --git a/native/setup.sh b/native/setup.sh new file mode 100755 index 0000000000..376c42af6c --- /dev/null +++ b/native/setup.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This script will start an isolated server and run the python API against it +# +set -e +BUILD_DIR=$(pwd)/../build +RUNDIR=$(pwd)/rundirs +NODES=6 +DSMEMBERS=5 +LOOKUPMEMBERS=1 +DSGUARDS=4 +PORT=40000 + + +function cleanup { +echo "Cleaning up..." + rm -rf $RUNDIR + mkdir -p $RUNDIR + echo "Done" +} + + +result=$(cleanup) +python3 native.py -n ${NODES} -d $DSMEMBERS -l ${LOOKUPMEMBERS} --port ${PORT} --websocket= --transaction-sender=0 --ds-guard=$DSGUARDS --shard-guard=0 --bucket=zilliqa-devnet --origin-server=${RUNDIR} --multiplier-fanout=1 --out-dir=$RUNDIR --build-dir=${BUILD_DIR} +echo "$result" diff --git a/native/startall.sh b/native/startall.sh new file mode 100755 index 0000000000..f26a519bcc --- /dev/null +++ b/native/startall.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This script will start an isolated server and run the python API against it + +# Find all directories containing "native" +#set -e + + +function start_task { + local taskname=$1 + echo "Starting task "$taskname"..." + dirs=$(find . -type d -name $taskname ) + # Loop through each directory and run "start.sh" + echo $dirs + for dir in $dirs; do + if [ -f "$dir/start.sh" ]; then + echo "Running start.sh in $dir..." + (cd "$dir" && bash start.sh) + else + echo "No start.sh found in $dir" + fi + done + echo "Done" +} + +echo "starting multiplier..." +(cd rundirs/native-multiplier-0 && bash start.sh) +echo "starting web server..." +(cd rundirs && python3 -m http.server& ) +echo "starting lookups..." +result=$(start_task "*lookup*") +echo "starting seedpubs..." +result=$(start_task "*seedpub*") +echo "starting guards..." +result=$(start_task "*dsguard*") +echo "starting normal..." +result=$(start_task "*normal*") + + +echo "$result" + diff --git a/native/stopall.sh b/native/stopall.sh new file mode 100755 index 0000000000..2d702a0613 --- /dev/null +++ b/native/stopall.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# Copyright (C) 2023 Zilliqa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This script will start an isolated server and run the python API against it +# +set -e + +function stop_localstack { + echo "Stopping localstack..." + localstack stop + echo "Done" +} + +function stop_webserver { + echo "Stopping webserver..." + kill -9 $(ps aux | grep '[p]ython3 -m http.server' | awk '{print $2}') + echo "Done" +} + +function stop_asio_multipplier { + echo "Stopping asio multiplier..." + kill -9 $(ps aux | grep '[a]sio_multiplier' | awk '{print $2}') + echo "Done" +} + +function stop_zilliqad { + echo "Stopping zilliqad..." + kill -9 $(ps aux | grep '[z]illiqad' | awk '{print $2}') + echo "Done" +} + +function stop_zilliqa { + echo "Stopping zilliqa..." + kill -9 $(ps aux | grep '[z]illiqa' | awk '{print $2}') + kill -9 $(ps aux | grep '[s]cilla-server' | awk '{print $2}') + kill -9 $(ps aux | grep '[e]vm-ds' | awk '{print $2}') + echo "Done" +} + +function stop_upload_incr_DB { + echo "Stopping upload_incr_DB..." + kill -9 $(ps aux | grep '[u]pload_incr_DB' | awk '{print $2}') + echo "Done" +} + +function stop_sciilla_server { + echo "Stopping upload_incr_DB..." + kill -9 $(ps aux | grep '[s]scilla-server' | awk '{print $2}') + echo "Done" +} + +function stop_download_incr_DB { + echo "Stopping download_incr_DB..." + kill -9 $(ps aux | grep '[d]download_incr_DB' | awk '{print $2}') + echo "Done" +} + +function stop_download_static_DB { + echo "Stopping download_static_DB..." + kill -9 $(ps aux | grep '[d]download_static_DB' | awk '{print $2}') + echo "Done" +} + + + + +echo "Halting processes .." + +result=$(stop_asio_multipplier) +result=$(stop_sciilla_server) +result=$(stop_zilliqad) +result=$(stop_zilliqa) +result=$(stop_webserver) +#result=$(stop_localstack) +result=$(stop_upload_incr_DB) +result=$(stop_download_incr_DB) +result=$(stop_download_static_DB) + +echo "Done" \ No newline at end of file diff --git a/src/cmd/asio_multiplier.cpp b/src/cmd/asio_multiplier.cpp index b0d81a430d..8c56b4fbe0 100644 --- a/src/cmd/asio_multiplier.cpp +++ b/src/cmd/asio_multiplier.cpp @@ -15,16 +15,22 @@ * along with this program. If not, see . */ #include -#include + +#include #include #include #include #include #include #include -#include #include +#include +#include + +#include +#include + #include #include #include @@ -35,10 +41,10 @@ #include "libMetrics/Tracing.h" #include "libNetwork/P2P.h" #include "libUtils/DetachedFunction.h" -#include "libUtils/IPConverter.h" + +#include "libNetwork/P2PMessage.h" #include "libUtils/Logger.h" #include "libZilliqa/Zilliqa.h" -#include "libNetwork/P2PMessage.h" using namespace zil::p2p; std::chrono::high_resolution_clock::time_point startTime; @@ -100,14 +106,17 @@ bool fetchDownstreams(const std::string downstreamURL, if (r.status_code == 200) { std::string contents = r.text; std::vector oldAddresses = mirrorAddresses; - std::vector newAddresses = removeEmptyAddr(split(contents, '\n')); - std::set diffAddresses = reportDifference(newAddresses, oldAddresses, addressStore); + std::vector newAddresses = + removeEmptyAddr(split(contents, '\n')); + std::set diffAddresses = + reportDifference(newAddresses, oldAddresses, addressStore); for (const std::string& address : diffAddresses) { mirrorAddresses.push_back(address); } } else { - LOG_GENERAL(INFO,"DownstreamURL " << downstreamURL - << " may not be available at this moment" ); + LOG_GENERAL(INFO, "DownstreamURL " + << downstreamURL + << " may not be available at this moment"); return false; } return true; @@ -160,22 +169,76 @@ void process_message(std::shared_ptr message, (time_span.count() * 1024 * 1024) << " MBps"); } - zil::p2p::GetInstance().SendBroadcastMessage(peers.getPeers(), message->msg,false); + zil::p2p::GetInstance().SendBroadcastMessage(peers.getPeers(), message->msg, + false); } namespace po = boost::program_options; +void daemonize() { + pid_t pid, sid; + + // Fork the parent process + pid = fork(); + + if (pid < 0) { + exit(EXIT_FAILURE); + } + + // If we got a good PID, then we can exit the parent process + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + // Change the file mode mask + umask(0); + + // Create a new SID for the child process + sid = setsid(); + if (sid < 0) { + exit(EXIT_FAILURE); + } + + // Fork again to ensure that the daemon is not a session leader + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + // Change the current working directory to the root directory + if ((chdir("/")) < 0) { + exit(EXIT_FAILURE); + } + + // Close all open file descriptors + for (int i = sysconf(_SC_OPEN_MAX); i >= 0; i--) { + close(i); + } + + // Redirect standard input, output, and error to /dev/null + int fd = open("/dev/null", O_RDWR); + dup(fd); + dup(fd); +} + int main(int argc, char* argv[]) { using namespace zil::multiplier::utils; Peer my_network_info; + // Daemonize the program + daemonize(); + std::string url; std::string logpath(std::filesystem::absolute("./").string()); registeredPeers our_peers{}; std::set addressStore; std::vector mirrorAddresses; int port; - std::atomic execution_continues{true }; + std::atomic execution_continues{true}; std::mutex lock_addressStore; po::options_description desc("Options"); @@ -207,37 +270,38 @@ int main(int argc, char* argv[]) { if ((port < 0) || (port > 65535)) { SWInfo::LogBrandBugReport(); - LOG_GENERAL( INFO, "ERROR: Invalid port" ); + LOG_GENERAL(INFO, "ERROR: Invalid port"); return ERROR_IN_COMMAND_LINE; } if (url.empty()) { SWInfo::LogBrandBugReport(); - LOG_GENERAL( INFO, "ERROR: url empty" ); + LOG_GENERAL(INFO, "ERROR: url empty"); return ERROR_IN_COMMAND_LINE; } } catch (boost::program_options::required_option& e) { SWInfo::LogBrandBugReport(); - LOG_GENERAL( INFO, "ERROR: " << e.what() ); - LOG_GENERAL( INFO, "ERROR: " << desc ); + LOG_GENERAL(INFO, "ERROR: " << e.what()); + LOG_GENERAL(INFO, "ERROR: " << desc); return ERROR_IN_COMMAND_LINE; } catch (boost::program_options::error& e) { SWInfo::LogBrandBugReport(); - LOG_GENERAL( INFO, "ERROR: " << e.what() ); + LOG_GENERAL(INFO, "ERROR: " << e.what()); return ERROR_IN_COMMAND_LINE; } INIT_FILE_LOGGER("asio_multiplier", std::filesystem::current_path()); LOG_DISPLAY_LEVEL_ABOVE(INFO); - - auto func = [&execution_continues, &our_peers,&port,&lock_addressStore]() mutable -> void { + auto func = [&execution_continues, &our_peers, &port, + &lock_addressStore]() mutable -> void { boost::asio::io_context ctx(1); boost::asio::signal_set sig(ctx, SIGINT, SIGTERM); sig.async_wait([&](const boost::system::error_code&, int) { ctx.stop(); execution_continues.store(false); }); - auto dispatcher = [&our_peers,&lock_addressStore](std::shared_ptr message) { + auto dispatcher = [&our_peers, &lock_addressStore]( + std::shared_ptr message) { lock_addressStore.lock(); process_message(std::move(message), our_peers); lock_addressStore.unlock(); @@ -254,7 +318,7 @@ int main(int argc, char* argv[]) { std::vector address_pair; address_pair = split(address, ':'); if (address_pair.size() != 2) { - LOG_GENERAL(INFO, "Invalid address: " << address ); + LOG_GENERAL(INFO, "Invalid address: " << address); continue; } @@ -263,7 +327,7 @@ int main(int argc, char* argv[]) { struct in_addr ip_addr {}; inet_pton(AF_INET, address_pair[0].c_str(), &ip_addr); { - LOG_GENERAL( INFO, "Updating downstream Addresses: " ); + LOG_GENERAL(INFO, "Updating downstream Addresses: "); lock_addressStore.lock(); our_peers.addPeer({ip_addr.s_addr, static_cast(std::stoi( address_pair[1]))}); diff --git a/src/libNetwork/Guard.cpp b/src/libNetwork/Guard.cpp index 2997dc26b6..5cea78cea3 100644 --- a/src/libNetwork/Guard.cpp +++ b/src/libNetwork/Guard.cpp @@ -251,13 +251,13 @@ void Guard::ValidateRunTimeEnvironment() { unsigned int nodeReplacementLimit = static_cast( COMM_SIZE - ceil(COMM_SIZE * TOLERANCE_FRACTION)); - if (NUM_DS_ELECTION > nodeReplacementLimit) { - LOG_GENERAL(FATAL, - "Check constants configuration. nodeReplacementLimit must be " - "bigger than NUM_DS_ELECTION. Refer to design documentation. " - "nodeReplacementLimit: " - << nodeReplacementLimit); - } +// if (NUM_DS_ELECTION > nodeReplacementLimit) { +// LOG_GENERAL(FATAL, +// "Check constants configuration. nodeReplacementLimit must be " +// "bigger than NUM_DS_ELECTION. Refer to design documentation. " +// "nodeReplacementLimit: " +// << nodeReplacementLimit); +// } } void Guard::Init() { diff --git a/src/libNetwork/P2P.cpp b/src/libNetwork/P2P.cpp index 36fef017cf..161e77efe1 100644 --- a/src/libNetwork/P2P.cpp +++ b/src/libNetwork/P2P.cpp @@ -86,6 +86,7 @@ void P2P::StartServer(AsioContext& asio, uint16_t port, uint16_t additionalPort, }; if (port) { + LOG_GENERAL(INFO, "Starting P2P server on port " << port); m_server = P2PServer::CreateAndStart(asio, port, maxMsgSize, dispatchFn); } diff --git a/src/libNetwork/P2PServer.cpp b/src/libNetwork/P2PServer.cpp index 7ac23be6f0..5d5b2bc330 100644 --- a/src/libNetwork/P2PServer.cpp +++ b/src/libNetwork/P2PServer.cpp @@ -178,6 +178,10 @@ std::shared_ptr P2PServer::CreateAndStart(AsioContext& asio, std::string error_msg; try { + + // TODO - Change this to our real ip address + + auto endpoint = TcpEndpoint{boost::asio::ip::make_address("0.0.0.0"), port}; TcpAcceptor socket(asio); diff --git a/src/libNetwork/SendJobs.cpp b/src/libNetwork/SendJobs.cpp index 3eeff91fa7..954df14c42 100644 --- a/src/libNetwork/SendJobs.cpp +++ b/src/libNetwork/SendJobs.cpp @@ -487,6 +487,8 @@ class SendJobsImpl : public SendJobs, void SendMessageToPeer(const Peer& peer, RawMessage message, bool allow_relaxed_blacklist) override { zil::local::variables.AddSendMessageToPeerCount(1); + + // TODO find who is using listening host of 0.0.0.0 if (peer.m_listenPortHost == 0) { LOG_GENERAL(WARNING, "Ignoring message to peer " << peer); zil::local::variables.AddSendMessageToPeerFailed(1);