diff --git a/README.md b/README.md index 6006fcce..3a9a5e21 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,7 @@ Set up the environment on Ubuntu 22.04 with the following steps: tar -xf cometbft_0.38.6_linux_amd64.tar.gz rm cometbft_0.38.6_linux_amd64.tar.gz ./cometbft init - cp src/xian/genesis/genesis.json /root/.cometbft/config/genesis.json - cp src/xian/config/config.toml /root/.cometbft/config/config.toml - rm /root/.cometbft/config/node_key.json - rm /root/.cometbft/config/priv_validator_key.json - echo '{"address": "ee06a34cf08bf72ce592d26d36b90c79daba2829ba9634992d034318160d49f9", "pub_key": {"type": "tendermint/PubKeyEd25519", "value": "7gajTPCL9yzlktJtNrkMedq6KCm6ljSZLQNDGBYNSfk="}, "priv_key": {"type": "tendermint/PrivKeyEd25519", "value": "zWzEX/586/CcbGAlV11Qu0LGxwwH4dvFFQqq3JhwXCvuBqNM8Iv3LOWS0m02uQx52rooKbqWNJktA0MYFg1J+Q=="}}' > /root/.cometbft/config/priv_validator_key.json + python src/xian/tools/configure.py --moniker "Node" --copy-genesis True --genesis-file-name genesis.json --validator_privkey "cd6cc45ffe7cebf09c6c6025575d50bb42c6c70c07e1dbc5150aaadc98705c2b" ./cometbft node --rpc.laddr tcp://0.0.0.0:26657 ``` diff --git a/src/xian/tools/configure.py b/src/xian/tools/configure.py new file mode 100644 index 00000000..a3d0f056 --- /dev/null +++ b/src/xian/tools/configure.py @@ -0,0 +1,118 @@ +from argparse import ArgumentParser +import toml +import os +import requests +import tarfile + +""" +This is to configure the CometBFT node. +""" + +class Configure: + config_path = os.path.join(os.path.expanduser('~'), '.cometbft', 'config', 'config.toml') + + def __init__(self): + self.parser = ArgumentParser(description='Configure') + self.parser.add_argument('--seed-node', type=str, help='IP of the Seed Node e.g. 91.108.112.184 (without port, but 26657 and 26656 needs to be open)', required=False) + self.parser.add_argument('--moniker', type=str, help='Moniker/Name of your node', required=True) + self.parser.add_argument('--allow-cors', type=bool, help='Allow CORS', required=False, default=True) + self.parser.add_argument('--snapshot-url', type=str, help='URL of the snapshot e.g. https://github.com/xian-network/snapshots/raw/main/testnet-2024-04-02.tar (tar.gz file)', required=False, default="https://github.com/xian-network/snapshots/raw/main/testnet-2024-04-02.tar") + self.parser.add_argument('--copy-genesis', type=bool, help='Copy genesis file', required=True, default=True) + self.parser.add_argument('--genesis-file-name', type=str, help='Genesis file name if copy-genesis is True e.g. genesis-testnet.json', required=True, default="genesis-testnet.json") + self.parser.add_argument('--validator-privkey', type=str, help='Validator wallet private key 64 characters', required=True) + # Chain ID is not neeeded anymore, bcz in Genesis block, we have chain_id + # Snapshot should be a tar.gz file containing the data directory and xian directory + # the priv_validator_state.json file that is in the snapshot should have + # round and step set to 0 + # and signature, signbytes removed + self.args = self.parser.parse_args() + + + def download_and_extract(url, target_path): + # Download the file from the URL + response = requests.get(url) + filename = url.split('/')[-1] # Assumes the URL ends with the filename + tar_path = os.path.join(target_path, filename) + + # Ensure the target directory exists + os.makedirs(target_path, exist_ok=True) + + # Save the downloaded file to disk + with open(tar_path, 'wb') as file: + file.write(response.content) + + # Extract the tar.gz file + if tar_path.endswith(".tar.gz"): + with tarfile.open(tar_path, "r:gz") as tar: + tar.extractall(path=target_path) + elif tar_path.endswith(".tar"): + with tarfile.open(tar_path, "r:") as tar: + tar.extractall(path=target_path) + else: + print("File format not recognized. Please use a .tar.gz or .tar file.") + + os.remove(tar_path) + + def main(self): + # Make sure this is run in the tools directory + os.chdir(os.path.dirname(os.path.abspath(__file__))) + + if not os.path.exists(self.config_path): + print('Initialize cometbft first') + return + + with open(self.config_path, 'r') as f: + config = toml.load(f) + + if self.args.seed_node: + info = requests.get(f'http://{self.args.seed_node}:26657/status') + if info.status_code != 200: + print('Seed node is not accessible') + return + id = info.json()['result']['node_info']['id'] + config['p2p']['seeds'] = f'{id}@{self.args.seed_node}:26656' + + if self.args.moniker: + config['moniker'] = self.args.moniker + + if self.args.allow_cors: + config['rpc']['cors_allowed_origins'] = ['*'] + + if self.args.snapshot_url: + # If data directory exists, delete it + data_dir = os.path.join(os.path.expanduser('~'), '.cometbft', 'data') + if os.path.exists(data_dir): + os.system(f'rm -rf {data_dir}') + # If xian directory exists, delete it + xian_dir = os.path.join(os.path.expanduser('~'), '.cometbft', 'xian') + if os.path.exists(xian_dir): + os.system(f'rm -rf {xian_dir}') + # Download the snapshot + self.download_and_extract(self.args.snapshot_url, os.path.join(os.path.expanduser('~'), '.cometbft')) + + if self.args.copy_genesis: + if not self.args.genesis_file_name: + print('Genesis file name is required') + return + # Copy the genesis file + genesis_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'genesis', self.args.genesis_file_name) + target_path = os.path.join(os.path.expanduser('~'), '.cometbft', 'config', 'genesis.json') + os.system(f'cp {genesis_path} {target_path}') + + if self.args.validator_privkey: + os.system(f'python3 validator_file_gen.py --validator_privkey {self.args.validator_privkey}') + # Copy the priv_validator_key.json file + file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'priv_validator_key.json') + target_path = os.path.join(os.path.expanduser('~'), '.cometbft', 'config', 'priv_validator_key.json') + os.system(f'cp {file_path} {target_path}') + # Remove node_key.json file + path = os.path.join(os.path.expanduser('~'), '.cometbft', 'config', 'node_key.json') + if os.path.exists(path): + os.system(f'rm {path}') + + with open(self.config_path, 'w') as f: + f.write(toml.dumps(config)) + +if __name__ == '__main__': + configure = Configure() + configure.main() \ No newline at end of file