Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Desktop App #1262

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 264 additions & 0 deletions mainnet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
# Quicksilver-2 chain restart instructions

Chain restart is due at 1700 UTC on Tuesday 3rd January 2023. We will use `quicksilverd v1.2.0` to export and restart the chain. You must upgrade before the export, else the export will fail. For build instructions, see below.

1. `git fetch && git checkout v1.2.0`
2. `make install`
3. `quicksilverd export --for-zero-height --height 115000 > export-quicksilver-1-115000.json`
4. `jq . export-quicksilver-1-115000.json -S -c | shasum -a256`
5. Check output matches `7df73ba5fdbaf6f4b5cced3f16b8f44047ad8f42a7a6f87f764413b474e81c54`
6. Run `python3 migrate-genesis.py`
7. `jq . genesis.json -S -c | shasum -a256`
8. Check output matches `cab2352d12f9e388bc633d909a26eaea8fc52904990405cd20d72077415a51d2`
9. `cp genesis.json ~/.quicksilverd/config/genesis.json` (be sure to replace `~/.quicksilverd` with your node's `HOME`).
10. `quicksilverd tendermint unsafe-reset-all`
11. If you use an external signer, update the chain_id and reset state.
12. `quicksilverd start` or, if using systemd, `systemctl start quicksilver`

# Quicksilver Mainnet joining instructions

## Minimum hardware requirements

- 4 cores (max. clock speed possible)
- 16GB RAM
- 500GB+ of NVMe or SSD disk

## Software requirements

Current version: v1.2.0

### Install Quicksilver

Requires [Go version v1.19+](https://golang.org/doc/install).

```sh
> git clone https://github.com/ingenuity-build/quicksilver && cd quicksilver
> git fetch origin --tags
> git checkout v1.2.0
> make install
or
> make build
```

`make build` will output the binary in the `build` directory.

Alternatively, to build a docker container, use `make build-docker`.

#### Verify installation

To verify if the installation was successful, execute the following command:

```sh
> quicksilverd version --long
```

It will display the version of quicksilverd currently installed:

```sh
name: quicksilverd
server_name: quicksilverd
version: 1.2.0
commit: 0ce6daf33aaeb93e1cb306a1fc8672c0123cffd1
build_tags: netgo,ledger
go: go version go1.19.2 linux/amd64
```

**Ensure go version is 1.19+; using 1.18 will cause non-deterministic behaviour.**

## Create a validator

1. Init Chain and start your node

```sh
> quicksilverd init <moniker-name> --chain-id=quicksilver-2
```

2. Create a local key pair
**Note: we recommend _only_ using Ledger for mainnet! Key security is important!**

```sh
> ## create a new key:
> quicksilverd keys add <key-name>
> ## or use a ledger:
> quicksilverd key add <key-name> --ledger
> ## or import an old key:
> quicksilverd keys show <key-name> -a
```

3. Download genesis
Fetch `genesis.json` into `quicksilverd`'s `config` directory (default: ~/.quicksilverd)

```sh
> curl -s https://raw.githubusercontent.com/ingenuity-build/mainnet/main/genesis.json > genesis.json
```

**Genesis sha256**

```sh
jq . ~/.quicksilverd/config/genesis.json -S -c | shasum -a256
cab2352d12f9e388bc633d909a26eaea8fc52904990405cd20d72077415a51d2 -
```

4. Define minimum gas prices

```sh
sed -i.bak -e "s/^minimum-gas-prices *=.*/minimum-gas-prices = \"0.0001uqck\"/;" ~/.quicksilverd/config/app.toml
```

5. Define seed nodes

```sh
export SEEDS="[email protected]:11156,[email protected]:11156,00f51227c4d5d977ad7174f1c0cea89082016ba2@seed-quick-mainnet.moonshot.army:26650"
sed -i.bak -e "s/^seeds *=.*/seeds = \"$SEEDS\"/" ~/.quicksilverd/config/config.toml
```

6. Start your node and sync to the latest block

7. Create validator

```sh
$ quicksilverd tx staking create-validator \
--amount 50000000uqck \
--commission-max-change-rate "0.1" \
--commission-max-rate "0.20" \
--commission-rate "0.1" \
--min-self-delegation "1" \
--details "a short description lives here" \
--pubkey=$(quicksilverd tendermint show-validator) \
--security-contact "[email protected]" \
--moniker <your_moniker> \
--chain-id quicksilver-2 \
--from <key-name>
```

## Cosmovisor

Optional, but highly recommended for upgrade automation.

Cosmovisor is process manager for Cosmos-SDK application binaries that enables node automation. It monitors the application's governance module for upgrade proposals and allows for automation of application binary downloads and replacement, resulting in near zero-downtime chain upgrades.

### Installation

#### 1. Install cosmovisor

Using go version 1.15 or later:

```sh
go install github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor@latest
```

or, specify the target version, for example:

```sh
go install github.com/cosmos/cosmos-sdk/cosmovisor/cmd/[email protected]
```

Confirm installation with:

```sh
which cosmovisor
```

The output should be a path to the cosmovisor binary:

```sh
/home/<user>/go/bin/cosmovisor
```

#### 2. Add environment variables to shell

The following environment variables must be set:

1. `export DAEMON_NAME=quicksilverd`
2. `export DAEMON_HOME=$HOME/.quicksilverd`
3. `export DAEMON_DATA_BACKUP_DIR=$HOME/.quicksilverd/data_backup`

Ensure your environment setup is correctly configured to persist across sessions. Make use of the appropriate system environment configuration files, such as `.profile` to accomplish this.

#### 3. Directory structure

Cosmovisor expects the following directory structure in `$DAEMON_HOME/cosmovisor`:

```sh
.
├── current -> genesis or upgrades/<name>
├── genesis
│ └── bin
│ └── $DAEMON_NAME
└── upgrades
└── <name>
└── bin
└── $DAEMON_NAME
```

Create the target directory structure with the following:

```sh
mkdir -p $DAEMON_HOME/cosmovisor/genesis/bin
mkdir -p $DAEMON_HOME/cosmovisor/upgrades
```

`current` is a symlink that will be created by `cosmovisor`.

### Set the genesis binary

Cosmovisor requires the genesis binary to be set. Do this by copying the quicksilverd binary to `$DAEMON_HOME/cosmovisor/genesis/bin/$DAEMON_NAME`.

```sh
# find quicksilverd binary
which quicksilverd
# copy binary to cosmovisor genesis using output from above command, e.g.
cp build/quicksilverd $DAEMON_HOME/cosmovisor/genesis/bin/$DAEMON_NAME
```

### Configure cosmovisor as a system service

Create the system service file:

```sh
sudo touch /etc/systemd/system/cosmovisor.service
```

Use an editor like `vim`, `micro` or `nano` and set the contents of the file according to your system configuration, for example:

```sh
[Unit]
Description=cosmovisor
After=network-online.target
[Service]
User=<your-user>
ExecStart=/home/<your-user>/go/bin/cosmovisor start
Restart=always
RestartSec=3
LimitNOFILE=4096
Environment="DAEMON_NAME=quicksilverd"
Environment="DAEMON_HOME=/home/<your-user>/.quicksilverd"
Environment="DAEMON_ALLOW_DOWNLOAD_BINARIES=false"
# Set buffer size to handle:
# https://github.com/cosmos/cosmos-sdk/pull/8590
Environment="DAEMON_LOG_BUFFER_SIZE=512"
Environment="DAEMON_RESTART_AFTER_UPGRADE=true"
Environment="DAEMON_POLL_INTERVAL=300ms"
Environment="DAEMON_DATA_BACKUP_DIR=${HOME}/.quicksilverd"
# Set to true if disk space is limited:
Environment="UNSAFE_SKIP_BACKUP=false"
Environment="DAEMON_PREUPGRADE_MAX_RETRIES=0"
[Install]
WantedBy=multi-user.target
```

**IMPORTANT**: If you have limited disk space please set `UNSAFE_SKIP_BACKUP=true`. This will avoid an upgrade failure due to insufficient disk space when the backup is created.

Enable and start the cosmovisor service:

```sh
sudo systemctl daemon-reload
sudo systemctl enable cosmovisor
sudo systemctl restart cosmovisor
```

Check that the service is running:

```sh
sudo systemctl status cosmovisor
```
1 change: 1 addition & 0 deletions mainnet/export-quicksilver-1-115000.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions mainnet/export-quicksilver-1-115000.json.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7df73ba5fdbaf6f4b5cced3f16b8f44047ad8f42a7a6f87f764413b474e81c54 export-quicksilver-1-115000.json
1 change: 1 addition & 0 deletions mainnet/genesis.json

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions mainnet/migrate-genesis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/python3
import json

'''
This script exists to take raw exported state from quicksilver-1 chain, zero the interchainstaking and interchainquery state, and ibc connections/channels/clients.
It also burns the uqatom balance (users have already been reimbursed the underlying atoms) and ibc/ denoms (1.12 osmo, and 0.888 swth), which will be reimbursed.
This is cheaper, quicker and easier than spending 100s of osmo and going through governance to recover a channel with $1.20 locked in it.

Min commission rates are adjusted up to 5%, and the global min commission rate param is set to 5%.

Chain ID is set to quicksilver-2 and the genesis time is set to 1700 UTC on 03/01/2023.
'''

with open('export-quicksilver-1-115000.json') as file:
input = json.load(file)
file.close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using file.close() is unnecessary when using the with statement for file operations in Python.

Remove the explicit file.close() call, as the with statement automatically handles file closure.

with open('export-quicksilver-1-115000.json') as file:
  input = json.load(file)
-  file.close()

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
with open('export-quicksilver-1-115000.json') as file:
input = json.load(file)
file.close()
with open('export-quicksilver-1-115000.json') as file:
input = json.load(file)


coins_to_burn = {}
## remove qatoms and ibc denoms
print("⚛️ Removing uqatom and ibc denoms from account balances")
balances = input.get('app_state').get('bank').get('balances')
for account_index, account in enumerate(balances):
balance = account.get('coins', [])
for coin_index, coin in enumerate(account.get('coins', [])):
if coin.get('denom') != "uqck":
coins_to_burn.update({coin.get('denom'): coins_to_burn.get(coin.get('denom'), 0)+int(coin.get('amount'))})
print(" ⚛ Removing {} from {}".format(coin, account.get('address')))
balance.remove(coin)
account.update({'coins': balance})

print("⚛️ Coins to remove from supply")
print(coins_to_burn)

supply = input.get('app_state').get('bank').get('supply')
print("⚛️ Supply before migration")
print(supply)
for denom, amount in coins_to_burn.items():
print(" ⚛ Removing {} from supply".format({"amount": str(amount), "denom": denom}))
supply.remove({"amount": str(amount), "denom": denom})

print("⚛️ Supply post migration")
print(input.get('app_state').get('bank').get('supply'))

print("⚛️ Removing ibc channels, clients, connections and capabilities")
## remove ibc capabilities, clients, connections, channels
input.get('app_state').update({'capability': {"index": "1"}})
input.get('app_state').get('ibc').update({"channel_genesis": {"channels": [],"acknowledgements": [],"commitments": [],"receipts": [],"send_sequences": [],"recv_sequences": [],"ack_sequences": [],"next_channel_sequence": "0"}, "client_genesis": {"clients": [], "clients_consensus": [], "clients_metadata": [], "params": {"allowed_clients": ["06-solomachine","07-tendermint"]}, "create_localhost": False, "next_client_sequence": "0"}, "connection_genesis": {"connections": [],"client_connection_paths": [],"next_connection_sequence": "0","params": {"max_expected_time_per_block": "30000000000"}}})

Check notice

Code scanning / devskim

Accessing localhost could indicate debug code, or could hinder scaling. Note

Do not leave debug code in production
input.get('app_state').get('transfer').update({'denom_traces': []})
input.get('app_state').get('interchainaccounts').update({"controller_genesis_state": {"active_channels": [],"interchain_accounts": [],"ports": [],"params": {"controller_enabled": True}},"host_genesis_state": {"active_channels": [],"interchain_accounts": [],"port": "icahost","params": {"host_enabled": False,"allow_messages": []}}})

## remove interchainstaking / interchain query entries
print("⚛️ Zeroing interchainstaking and interchainquery state")
input.get('app_state').get('interchainquery').update({'queries': []})
input.get('app_state').update({'interchainstaking': {'params': input.get('app_state').get('interchainstaking').get('params')}})

## reset epochs
print("⚛️ Zeroing epoch state")
input.get('app_state').get('epochs').get('epochs')[0].update({"start_time": "0001-01-01T00:00:00Z", "current_epoch": "0", "current_epoch_start_time": "0001-01-01T00:00:00Z", "epoch_counting_started": False, "current_epoch_start_height": "0"})
input.get('app_state').get('epochs').get('epochs')[1].update({"start_time": "0001-01-01T00:00:00Z", "current_epoch": "0", "current_epoch_start_time": "0001-01-01T00:00:00Z", "epoch_counting_started": False, "current_epoch_start_height": "0"})

## update min commission to 5%
print("⚛️ Updating validator min commission rate to 5%")
for validator in input.get('app_state').get('staking').get('validators'):
if float(validator.get('commission').get('commission_rates').get('rate')) < 0.05:
print(" ⚛ Found {} with commission rate < 0.05; updating".format(validator.get('description').get('moniker')))
validator.get('commission').get('commission_rates').update({'rate': "0.050000000000000000"})
if float(validator.get('commission').get('commission_rates').get('max_rate')) < 0.05:
validator.get('commission').get('commission_rates').update({'max_rate': "0.050000000000000000"})

## update param
print("⚛️ Updating min_commission_rate param to 5%")
input.get('app_state').get('staking').get('params').update({'min_commission_rate': "0.050000000000000000"})

## chain id and genesis time
print("⚛️ Setting chain id and genesis time")
input.update({'chain_id': 'quicksilver-2', 'genesis_time': '2023-01-03T17:00:00Z'})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script lacks error handling for file operations and JSON parsing.

Add try-except blocks around file reading and JSON parsing to gracefully handle errors such as file not found or invalid JSON format.

try:
    with open('export-quicksilver-1-115000.json') as file:
        input = json.load(file)
except FileNotFoundError:
    print("File not found. Please ensure the file path is correct.")
    exit(1)
except json.JSONDecodeError:
    print("Failed to parse JSON. Please ensure the file is a valid JSON format.")
    exit(1)


with open("genesis.json", "w+") as file:
json.dump(input, file)
file.close()
Empty file added mainnet/quicksilver-1/PEERS
Empty file.
Loading
Loading