Last active
October 5, 2023 15:33
-
-
Save sainoe/b9c4ad47d850cb9dd05bcd041581b743 to your computer and use it in GitHub Desktop.
consumer double signing and light client attacks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -eux | |
# User balance of stake tokens | |
USER_COINS="100000000000stake" | |
# Amount of stake tokens staked | |
STAKE="100000000stake" | |
# Node IP address | |
NODE_IP="127.0.0.1" | |
# Home directory | |
HOME_DIR=$HOME | |
# Validator moniker | |
MONIKERS=("coordinator" "alice" "bob") | |
LEAD_VALIDATOR_MONIKER="coordinator" | |
# Hermes will connect to this node on both provider and consumer | |
HERMES_VALIDATOR_MONIKER="bob" | |
PROV_NODES_ROOT_DIR=${HOME_DIR}/nodes/provider | |
CONS_NODES_ROOT_DIR=${HOME_DIR}/nodes/consumer | |
# Base port. Ports assigned after these ports sequentially by nodes. | |
RPC_LADDR_BASEPORT=29170 | |
P2P_LADDR_BASEPORT=29180 | |
GRPC_LADDR_BASEPORT=29190 | |
NODE_ADDRESS_BASEPORT=29200 | |
PPROF_LADDR_BASEPORT=29210 | |
CLIENT_BASEPORT=29220 | |
# Clean start | |
pkill -f interchain-security-pd &> /dev/null || true | |
sleep 1 | |
rm -rf ${PROV_NODES_ROOT_DIR} | |
# Let lead validator create genesis file | |
LEAD_VALIDATOR_PROV_DIR=${PROV_NODES_ROOT_DIR}/provider-${LEAD_VALIDATOR_MONIKER} | |
LEAD_VALIDATOR_CONS_DIR=${CONS_NODES_ROOT_DIR}/consumer-${LEAD_VALIDATOR_MONIKER} | |
LEAD_PROV_KEY=${LEAD_VALIDATOR_MONIKER}-key | |
LEAD_PROV_LISTEN_ADDR=tcp://${NODE_IP}:${RPC_LADDR_BASEPORT} | |
for index in "${!MONIKERS[@]}" | |
do | |
MONIKER=${MONIKERS[$index]} | |
# validator key | |
PROV_KEY=${MONIKER}-key | |
# home directory of this validator on provider | |
PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} | |
# home directory of this validator on consumer | |
CONS_NODE_DIR=${CONS_NODES_ROOT_DIR}/consumer-${MONIKER} | |
# Build genesis file and node directory structure | |
interchain-security-pd init $MONIKER --chain-id provider --home ${PROV_NODE_DIR} | |
jq ".app_state.gov.params.voting_period = \"10s\" | .app_state.staking.params.unbonding_time = \"86400s\"" \ | |
${PROV_NODE_DIR}/config/genesis.json > \ | |
${PROV_NODE_DIR}/edited_genesis.json && mv ${PROV_NODE_DIR}/edited_genesis.json ${PROV_NODE_DIR}/config/genesis.json | |
sleep 1 | |
# Create account keypair | |
interchain-security-pd keys add $PROV_KEY --home ${PROV_NODE_DIR} --keyring-backend test --output json > ${PROV_NODE_DIR}/${PROV_KEY}.json 2>&1 | |
sleep 1 | |
# copy genesis in, unless this validator is the lead validator | |
if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then | |
cp ${LEAD_VALIDATOR_PROV_DIR}/config/genesis.json ${PROV_NODE_DIR}/config/genesis.json | |
fi | |
# Add stake to user | |
PROV_ACCOUNT_ADDR=$(jq -r '.address' ${PROV_NODE_DIR}/${PROV_KEY}.json) | |
interchain-security-pd genesis add-genesis-account $PROV_ACCOUNT_ADDR $USER_COINS --home ${PROV_NODE_DIR} --keyring-backend test | |
sleep 1 | |
# copy genesis out, unless this validator is the lead validator | |
if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then | |
cp ${PROV_NODE_DIR}/config/genesis.json ${LEAD_VALIDATOR_PROV_DIR}/config/genesis.json | |
fi | |
PPROF_LADDR=${NODE_IP}:$(($PPROF_LADDR_BASEPORT + $index)) | |
P2P_LADDR_PORT=$(($P2P_LADDR_BASEPORT + $index)) | |
# adjust configs of this node | |
sed -i -r 's/timeout_commit = "5s"/timeout_commit = "3s"/g' ${PROV_NODE_DIR}/config/config.toml | |
sed -i -r 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ${PROV_NODE_DIR}/config/config.toml | |
# make address book non-strict. necessary for this setup | |
sed -i -r 's/addr_book_strict = true/addr_book_strict = false/g' ${PROV_NODE_DIR}/config/config.toml | |
# avoid port double binding | |
sed -i -r "s/pprof_laddr = \"localhost:6060\"/pprof_laddr = \"${PPROF_LADDR}\"/g" ${PROV_NODE_DIR}/config/config.toml | |
# allow duplicate IP addresses (all nodes are on the same machine) | |
sed -i -r 's/allow_duplicate_ip = false/allow_duplicate_ip = true/g' ${PROV_NODE_DIR}/config/config.toml | |
done | |
for MONIKER in "${MONIKERS[@]}" | |
do | |
# validator key | |
PROV_KEY=${MONIKER}-key | |
# home directory of this validator on provider | |
PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} | |
# copy genesis in, unless this validator is the lead validator | |
if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then | |
cp ${LEAD_VALIDATOR_PROV_DIR}/config/genesis.json* ${PROV_NODE_DIR}/config/genesis.json | |
fi | |
# Stake 1/1000 user's coins | |
interchain-security-pd genesis gentx $PROV_KEY $STAKE --chain-id provider --home ${PROV_NODE_DIR} --keyring-backend test --moniker $MONIKER | |
sleep 1 | |
# Copy gentxs to the lead validator for possible future collection. | |
# Obviously we don't need to copy the first validator's gentx to itself | |
if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then | |
cp ${PROV_NODE_DIR}/config/gentx/* ${LEAD_VALIDATOR_PROV_DIR}/config/gentx/ | |
fi | |
done | |
# Collect genesis transactions with lead validator | |
interchain-security-pd genesis collect-gentxs --home ${LEAD_VALIDATOR_PROV_DIR} --gentx-dir ${LEAD_VALIDATOR_PROV_DIR}/config/gentx/ | |
sleep 1 | |
for index in "${!MONIKERS[@]}" | |
do | |
MONIKER=${MONIKERS[$index]} | |
PERSISTENT_PEERS="" | |
for peer_index in "${!MONIKERS[@]}" | |
do | |
if [ $index == $peer_index ]; then | |
continue | |
fi | |
PEER_MONIKER=${MONIKERS[$peer_index]} | |
PEER_PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${PEER_MONIKER} | |
PEER_NODE_ID=$(interchain-security-pd tendermint show-node-id --home ${PEER_PROV_NODE_DIR}) | |
PEER_P2P_LADDR_PORT=$(($P2P_LADDR_BASEPORT + $peer_index)) | |
PERSISTENT_PEERS="$PERSISTENT_PEERS,$PEER_NODE_ID@${NODE_IP}:${PEER_P2P_LADDR_PORT}" | |
done | |
# remove trailing comma from persistent peers | |
PERSISTENT_PEERS=${PERSISTENT_PEERS:1} | |
# validator key | |
PROV_KEY=${MONIKER}-key | |
# home directory of this validator on provider | |
PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} | |
# home directory of this validator on consumer | |
CONS_NODE_DIR=${PROV_NODES_ROOT_DIR}/consumer-${MONIKER} | |
# copy genesis in, unless this validator is already the lead validator and thus it already has its genesis | |
if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then | |
cp ${LEAD_VALIDATOR_PROV_DIR}/config/genesis.json ${PROV_NODE_DIR}/config/genesis.json | |
fi | |
RPC_LADDR_PORT=$(($RPC_LADDR_BASEPORT + $index)) | |
P2P_LADDR_PORT=$(($P2P_LADDR_BASEPORT + $index)) | |
GRPC_LADDR_PORT=$(($GRPC_LADDR_BASEPORT + $index)) | |
NODE_ADDRESS_PORT=$(($NODE_ADDRESS_BASEPORT + $index)) | |
if [ $MONIKER == $HERMES_VALIDATOR_MONIKER ]; then | |
PRPC_LADDR_PORT=$RPC_LADDR_PORT | |
PGRPC_LADDR_PORT=$GRPC_LADDR_PORT | |
fi | |
# Start gaia | |
interchain-security-pd start \ | |
--home ${PROV_NODE_DIR} \ | |
--p2p.persistent_peers ${PERSISTENT_PEERS} \ | |
--rpc.laddr tcp://${NODE_IP}:${RPC_LADDR_PORT} \ | |
--grpc.address ${NODE_IP}:${GRPC_LADDR_PORT} \ | |
--address tcp://${NODE_IP}:${NODE_ADDRESS_PORT} \ | |
--p2p.laddr tcp://${NODE_IP}:${P2P_LADDR_PORT} \ | |
--grpc-web.enable=false &> ${PROV_NODE_DIR}/logs & | |
sleep 5 | |
done | |
# Build consumer chain proposal file | |
tee ${LEAD_VALIDATOR_PROV_DIR}/consumer-proposal.json<<EOF | |
{ | |
"title": "Create a chain", | |
"summary": "Gonna be a great chain", | |
"chain_id": "consumer", | |
"initial_height": { | |
"revision_height": 1 | |
}, | |
"genesis_hash": "Z2VuX2hhc2g=", | |
"binary_hash": "YmluX2hhc2g=", | |
"spawn_time": "2023-03-11T09:02:14.718477-08:00", | |
"deposit": "10000001stake", | |
"consumer_redistribution_fraction": "0.75", | |
"blocks_per_distribution_transmission": 1000, | |
"historical_entries": 10000, | |
"unbonding_period": 864000000000000, | |
"ccv_timeout_period": 259200000000000, | |
"transfer_timeout_period": 1800000000000 | |
} | |
EOF | |
sleep 5 | |
interchain-security-pd keys show $LEAD_PROV_KEY --keyring-backend test --home ${LEAD_VALIDATOR_PROV_DIR} | |
# Submit consumer chain proposal | |
interchain-security-pd tx gov submit-legacy-proposal consumer-addition ${LEAD_VALIDATOR_PROV_DIR}/consumer-proposal.json --chain-id provider --from $LEAD_PROV_KEY --home ${LEAD_VALIDATOR_PROV_DIR} --node $LEAD_PROV_LISTEN_ADDR --keyring-backend test -y --gas auto | |
sleep 1 | |
# Vote yes to proposal | |
for index in "${!MONIKERS[@]}" | |
do | |
MONIKER=${MONIKERS[$index]} | |
PROV_KEY=${MONIKER}-key | |
RPC_LADDR_PORT=$(($RPC_LADDR_BASEPORT + $index)) | |
RPC_LADDR=tcp://${NODE_IP}:${RPC_LADDR_PORT} | |
PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} | |
interchain-security-pd tx gov vote 1 yes --from $PROV_KEY --chain-id provider --home ${PROV_NODE_DIR} --node $RPC_LADDR -y --keyring-backend test | |
done | |
HERMES_PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${HERMES_VALIDATOR_MONIKER} | |
HERMES_KEY=${HERMES_VALIDATOR_MONIKER}-key | |
HERMES_CONS_NODE_DIR=${CONS_NODES_ROOT_DIR}/consumer-${HERMES_VALIDATOR_MONIKER} | |
sleep 15 | |
# # ## CONSUMER CHAIN ## | |
# # Clean start | |
pkill -f interchain-security-cd &> /dev/null || true | |
sleep 1 | |
rm -rf ${CONS_NODES_ROOT_DIR} | |
for index in "${!MONIKERS[@]}" | |
do | |
MONIKER=${MONIKERS[$index]} | |
# validator key | |
PROV_KEY=${MONIKER}-key | |
PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} | |
# home directory of this validator on consumer | |
CONS_NODE_DIR=${CONS_NODES_ROOT_DIR}/consumer-${MONIKER} | |
# Build genesis file and node directory structure | |
interchain-security-cd init $MONIKER --chain-id consumer --home ${CONS_NODE_DIR} | |
sleep 1 | |
# Create account keypair | |
interchain-security-cd keys add $PROV_KEY --home ${CONS_NODE_DIR} --keyring-backend test --output json > ${CONS_NODE_DIR}/${PROV_KEY}.json 2>&1 | |
sleep 1 | |
# copy genesis in, unless this validator is the lead validator | |
if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then | |
cp ${LEAD_VALIDATOR_CONS_DIR}/config/genesis.json ${CONS_NODE_DIR}/config/genesis.json | |
fi | |
# Add stake to user | |
CONS_ACCOUNT_ADDR=$(jq -r '.address' ${CONS_NODE_DIR}/${PROV_KEY}.json) | |
interchain-security-cd genesis add-genesis-account $CONS_ACCOUNT_ADDR $USER_COINS --home ${CONS_NODE_DIR} | |
### this probably doesnt have to be done for each node | |
# Add consumer genesis states to genesis file | |
RPC_LADDR_PORT=$(($RPC_LADDR_BASEPORT + $index)) | |
RPC_LADDR=tcp://${NODE_IP}:${RPC_LADDR_PORT} | |
interchain-security-pd query provider consumer-genesis consumer --home ${PROV_NODE_DIR} --node ${RPC_LADDR} -o json > consumer_gen.json | |
jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' ${CONS_NODE_DIR}/config/genesis.json consumer_gen.json > ${CONS_NODE_DIR}/edited_genesis.json \ | |
&& mv ${CONS_NODE_DIR}/edited_genesis.json ${CONS_NODE_DIR}/config/genesis.json | |
rm consumer_gen.json | |
### | |
# copy genesis out, unless this validator is the lead validator | |
if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then | |
cp ${CONS_NODE_DIR}/config/genesis.json ${LEAD_VALIDATOR_CONS_DIR}/config/genesis.json | |
fi | |
PPROF_LADDR=${NODE_IP}:$(($PPROF_LADDR_BASEPORT + ${#MONIKERS[@]} + $index)) | |
P2P_LADDR_PORT=$(($P2P_LADDR_BASEPORT + ${#MONIKERS[@]} + $index)) | |
# adjust configs of this node | |
sed -i -r 's/timeout_commit = "5s"/timeout_commit = "3s"/g' ${CONS_NODE_DIR}/config/config.toml | |
sed -i -r 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ${CONS_NODE_DIR}/config/config.toml | |
# make address book non-strict. necessary for this setup | |
sed -i -r 's/addr_book_strict = true/addr_book_strict = false/g' ${CONS_NODE_DIR}/config/config.toml | |
# avoid port double binding | |
sed -i -r "s/pprof_laddr = \"localhost:6060\"/pprof_laddr = \"${PPROF_LADDR}\"/g" ${CONS_NODE_DIR}/config/config.toml | |
# allow duplicate IP addresses (all nodes are on the same machine) | |
sed -i -r 's/allow_duplicate_ip = false/allow_duplicate_ip = true/g' ${CONS_NODE_DIR}/config/config.toml | |
# Create validator states | |
echo '{"height": "0","round": 0,"step": 0}' > ${CONS_NODE_DIR}/data/priv_validator_state.json | |
# Copy validator key files | |
cp ${PROV_NODE_DIR}/config/priv_validator_key.json ${CONS_NODE_DIR}/config/priv_validator_key.json | |
cp ${PROV_NODE_DIR}/config/node_key.json ${CONS_NODE_DIR}/config/node_key.json | |
# Set default client port | |
CLIENT_PORT=$(($CLIENT_BASEPORT + ${#MONIKERS[@]} + $index)) | |
sed -i -r "/node =/ s/= .*/= \"tcp:\/\/${NODE_IP}:${CLIENT_PORT}\"/" ${CONS_NODE_DIR}/config/client.toml | |
done | |
sleep 1 | |
for index in "${!MONIKERS[@]}" | |
do | |
MONIKER=${MONIKERS[$index]} | |
PERSISTENT_PEERS="" | |
for peer_index in "${!MONIKERS[@]}" | |
do | |
if [ $index == $peer_index ]; then | |
continue | |
fi | |
PEER_MONIKER=${MONIKERS[$peer_index]} | |
PEER_CONS_NODE_DIR=${CONS_NODES_ROOT_DIR}/consumer-${PEER_MONIKER} | |
PEER_NODE_ID=$(interchain-security-pd tendermint show-node-id --home ${PEER_CONS_NODE_DIR}) | |
PEER_P2P_LADDR_PORT=$(($P2P_LADDR_BASEPORT + ${#MONIKERS[@]} + $peer_index)) | |
PERSISTENT_PEERS="$PERSISTENT_PEERS,$PEER_NODE_ID@${NODE_IP}:${PEER_P2P_LADDR_PORT}" | |
done | |
# remove trailing comma from persistent peers | |
PERSISTENT_PEERS=${PERSISTENT_PEERS:1} | |
# validator key | |
PROV_KEY=${MONIKER}-key | |
# home directory of this validator on provider | |
PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} | |
# home directory of this validator on consumer | |
CONS_NODE_DIR=${CONS_NODES_ROOT_DIR}/consumer-${MONIKER} | |
# copy genesis in, unless this validator is already the lead validator and thus it already has its genesis | |
if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then | |
cp ${LEAD_VALIDATOR_CONS_DIR}/config/genesis.json ${CONS_NODE_DIR}/config/genesis.json | |
fi | |
RPC_LADDR_PORT=$(($RPC_LADDR_BASEPORT + ${#MONIKERS[@]} + $index)) | |
P2P_LADDR_PORT=$(($P2P_LADDR_BASEPORT + ${#MONIKERS[@]} + $index)) | |
GRPC_LADDR_PORT=$(($GRPC_LADDR_BASEPORT + ${#MONIKERS[@]} + $index)) | |
NODE_ADDRESS_PORT=$(($NODE_ADDRESS_BASEPORT + ${#MONIKERS[@]} + $index)) | |
if [ $MONIKER == $HERMES_VALIDATOR_MONIKER ]; then | |
CRPC_LADDR_PORT=$RPC_LADDR_PORT | |
CGRPC_LADDR_PORT=$GRPC_LADDR_PORT | |
fi | |
# Start gaia | |
interchain-security-cd start \ | |
--home ${CONS_NODE_DIR} \ | |
--p2p.persistent_peers ${PERSISTENT_PEERS} \ | |
--rpc.laddr tcp://${NODE_IP}:${RPC_LADDR_PORT} \ | |
--grpc.address ${NODE_IP}:${GRPC_LADDR_PORT} \ | |
--address tcp://${NODE_IP}:${NODE_ADDRESS_PORT} \ | |
--p2p.laddr tcp://${NODE_IP}:${P2P_LADDR_PORT} \ | |
--grpc-web.enable=false &> ${CONS_NODE_DIR}/logs & | |
sleep 6 | |
done | |
## Cause double signing | |
# create directory for double signing node | |
mkdir $HOME/nodes/consumer/consumer-bob-sybil/ | |
cp -r $HOME/nodes/consumer/consumer-bob/* $HOME/nodes/consumer/consumer-bob-sybil | |
# clear state in consumer-bob-sybil | |
echo '{"height": "0","round": 0,"step": 0,"signature":"","signbytes":""}' > $HOME/nodes/consumer/consumer-bob-sybil/data/priv_validator_state.json | |
# add new node key to sybil | |
# key was generated using gaiad init | |
# if the node key is not unique, double signing cannot be achieved | |
# and errors such as this can be seen in the terminal | |
# 5:54PM ERR found conflicting vote from ourselves; did you unsafe_reset a validator? height=1961 module=consensus round=0 type=2 | |
# 5:54PM ERR failed to process message err="conflicting votes from validator C888306A908A217B9A943D1DAD8790044D0947A4" | |
echo '{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"tj55by/yYwruSz4NxsOG9y9k2WrPvKLXKQdz/9jL9Uptmi647OYpcisjwf92TyA+wCUYVDOgW7D53Q+638l9/w=="}}' > $HOME/nodes/consumer/consumer-bob-sybil/config/node_key.json | |
# does not use persistent peers; will do a lookup in genesis.json to find peers | |
#ARGS="--address tcp://$CHAIN_PREFIX.252:26655 --rpc.laddr tcp://$CHAIN_PREFIX.252:26658 --grpc.address $CHAIN_PREFIX.252:9091 --log_level trace --p2p.laddr tcp://$CHAIN_PREFIX.252:26656 --grpc-web.enable=false" | |
# start double signing node - it should not talk to the node with the same key | |
#ip netns exec $HOME/nodes/consumer/consumer-bob-sybil $BIN $ARGS --home $HOME/nodes/consumer/consumer-bob-sybil start &> $HOME/nodes/consumer/consumer-bob-sybil/logs & | |
# Start gaia | |
interchain-security-cd start \ | |
--home $HOME/nodes/consumer/consumer-bob-sybil \ | |
--p2p.persistent_peers ${PERSISTENT_PEERS} \ | |
--rpc.laddr tcp://${NODE_IP}:29179 \ | |
--grpc.address ${NODE_IP}:29199 \ | |
--address tcp://${NODE_IP}:29209 \ | |
--p2p.laddr tcp://${NODE_IP}:29189 \ | |
--grpc-web.enable=false &> $HOME/nodes/consumer/consumer-bob-sybil/logs & | |
sleep 6 | |
# Setup Hermes in packet relayer mode | |
pkill -f hermes 2> /dev/null || true | |
tee ~/.hermes/config.toml<<EOF | |
[global] | |
log_level = "debug" | |
[mode] | |
[mode.clients] | |
enabled = true | |
refresh = true | |
misbehaviour = true | |
[mode.connections] | |
enabled = false | |
[mode.channels] | |
enabled = false | |
[mode.packets] | |
enabled = true | |
[[chains]] | |
id = "consumer" | |
rpc_addr = "http://${NODE_IP}:${CRPC_LADDR_PORT}" | |
event_source = { mode = 'push', url = 'ws://${NODE_IP}:${CRPC_LADDR_PORT}/websocket' , batch_delay = '50ms' } | |
grpc_addr = "tcp://${NODE_IP}:${CGRPC_LADDR_PORT}" | |
account_prefix = "cosmos" | |
clock_drift = "5s" | |
gas_multiplier = 1.1 | |
key_name = "relayer" | |
max_gas = 2000000 | |
rpc_timeout = "10s" | |
store_prefix = "ibc" | |
trusting_period = "1days" | |
ccv_consumer_chain = true | |
[chains.gas_price] | |
denom = "stake" | |
price = 0.00 | |
[chains.trust_threshold] | |
denominator = "3" | |
numerator = "1" | |
[[chains]] | |
id = "provider" | |
rpc_addr = "http://${NODE_IP}:${PRPC_LADDR_PORT}" | |
event_source = { mode = 'push', url = 'ws://${NODE_IP}:${PRPC_LADDR_PORT}/websocket' , batch_delay = '50ms' } | |
grpc_addr = "tcp://${NODE_IP}:${PGRPC_LADDR_PORT}" | |
account_prefix = "cosmos" | |
clock_drift = "5s" | |
gas_multiplier = 1.1 | |
key_name = "relayer" | |
max_gas = 2000000 | |
rpc_timeout = "10s" | |
store_prefix = "ibc" | |
trusting_period = "1days" | |
[chains.gas_price] | |
denom = "stake" | |
price = 0.00 | |
[chains.trust_threshold] | |
denominator = "3" | |
numerator = "1" | |
EOF | |
# Delete all previous keys in relayer | |
hermes keys delete --chain consumer --all | |
hermes keys delete --chain provider --all | |
# Restore keys to hermes relayer | |
hermes keys add --key-file ${HERMES_PROV_NODE_DIR}/${HERMES_KEY}.json --chain provider | |
hermes keys add --key-file ${HERMES_CONS_NODE_DIR}/${HERMES_KEY}.json --chain consumer | |
sleep 5 | |
hermes create connection \ | |
--a-chain consumer \ | |
--a-client 07-tendermint-0 \ | |
--b-client 07-tendermint-0 | |
hermes create channel \ | |
--a-chain consumer \ | |
--a-port consumer \ | |
--b-port provider \ | |
--order ordered \ | |
--channel-version 1 \ | |
--a-connection connection-0 | |
sleep 5 | |
hermes --json start &> ~/.hermes/logs & | |
sleep 3 | |
# Run hermes in evidence mode | |
hermes evidence --chain consumer &> ~/.hermes/evidence-logs & | |
sleep 1 | |
# check that misbehaving validator was jailed | |
interchain-security-pd q tendermint-validator-set --node tcp://0.0.0.0:26658 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -eux | |
diag() { | |
echo ">> | |
>> $@ | |
>>" 1>&2 | |
} | |
# Hermes binary | |
HERMES_BIN=hermes | |
# User balance of stake tokens | |
USER_COINS="100000000000stake" | |
# Amount of stake tokens staked | |
STAKE="100000000stake" | |
# Amount of stake tokens staked | |
STAKE2="4000000stake" | |
# Node IP address | |
NODE_IP="127.0.0.1" | |
# Home directory | |
HOME_DIR=$HOME | |
# Validator moniker | |
MONIKER="coordinator" | |
MONIKER_SUB="sub" | |
# Validator directory | |
PROV_NODE_DIR=${HOME_DIR}/provider-${MONIKER} | |
PROV_NODE_SUB_DIR=${HOME_DIR}/provider-${MONIKER_SUB} | |
CONS_NODE_DIR=${HOME_DIR}/consumer-${MONIKER} | |
CONS_NODE_SUB_DIR=${HOME_DIR}/consumer-${MONIKER_SUB} | |
CONS_FORK_NODE_DIR=${HOME_DIR}/consumer-fork-${MONIKER} | |
# Coordinator key | |
PROV_KEY=${MONIKER}-key | |
PROV_KEY_SUB=${MONIKER_SUB}-key | |
# Clean start | |
pkill -f interchain-security-pd &> /dev/null || true | |
rm -rf ${PROV_NODE_DIR} | |
# Build genesis file and node directory structure | |
interchain-security-pd init $MONIKER --chain-id provider --home ${PROV_NODE_DIR} | |
jq ".app_state.gov.params.voting_period = \"10s\" | .app_state.staking.params.unbonding_time = \"86400s\"" \ | |
${PROV_NODE_DIR}/config/genesis.json > \ | |
${PROV_NODE_DIR}/edited_genesis.json && mv ${PROV_NODE_DIR}/edited_genesis.json ${PROV_NODE_DIR}/config/genesis.json | |
sleep 1 | |
# Create account keypair | |
interchain-security-pd keys add $PROV_KEY --home ${PROV_NODE_DIR} --keyring-backend test --output json > ${PROV_NODE_DIR}/${PROV_KEY}.json 2>&1 | |
sleep 1 | |
# Add stake to user | |
PROV_ACCOUNT_ADDR=$(jq -r '.address' ${PROV_NODE_DIR}/${PROV_KEY}.json) | |
interchain-security-pd genesis add-genesis-account $PROV_ACCOUNT_ADDR $USER_COINS --home ${PROV_NODE_DIR} --keyring-backend test | |
sleep 1 | |
# Stake 1/1000 user's coins | |
interchain-security-pd genesis gentx $PROV_KEY $STAKE --chain-id provider --home ${PROV_NODE_DIR} --keyring-backend test --moniker $MONIKER | |
sleep 1 | |
## config second node | |
rm -rf ${PROV_NODE_SUB_DIR} | |
# Build genesis file and node directory structure | |
interchain-security-pd init $MONIKER_SUB --chain-id provider --home ${PROV_NODE_SUB_DIR} | |
sleep 1 | |
# Create account keypair | |
interchain-security-pd keys add $PROV_KEY_SUB --home ${PROV_NODE_SUB_DIR} --keyring-backend test --output json > ${PROV_NODE_SUB_DIR}/${PROV_KEY_SUB}.json 2>&1 | |
sleep 1 | |
cp ${PROV_NODE_DIR}/config/genesis.json ${PROV_NODE_SUB_DIR}/config/genesis.json | |
# Add stake to user | |
PROV_ACCOUNT_ADDR=$(jq -r '.address' ${PROV_NODE_SUB_DIR}/${PROV_KEY_SUB}.json) | |
interchain-security-pd genesis add-genesis-account $PROV_ACCOUNT_ADDR $USER_COINS --home ${PROV_NODE_SUB_DIR} --keyring-backend test | |
sleep 1 | |
cp -r ${PROV_NODE_DIR}/config/gentx/ ${PROV_NODE_SUB_DIR}/config/gentx/ | |
# # Stake 1/1000 user's coins | |
interchain-security-pd genesis gentx $PROV_KEY_SUB $STAKE2 --chain-id provider --home ${PROV_NODE_SUB_DIR} --keyring-backend test --moniker $MONIKER_SUB | |
sleep 1 | |
interchain-security-pd genesis collect-gentxs --home ${PROV_NODE_SUB_DIR} --gentx-dir ${PROV_NODE_SUB_DIR}/config/gentx/ | |
cp ${PROV_NODE_SUB_DIR}/config/genesis.json ${PROV_NODE_DIR}/config/genesis.json | |
# Start nodes | |
sed -i -r "/node =/ s/= .*/= \"tcp:\/\/${NODE_IP}:26658\"/" ${PROV_NODE_DIR}/config/client.toml | |
sed -i -r 's/timeout_commit = "5s"/timeout_commit = "3s"/g' ${PROV_NODE_DIR}/config/config.toml | |
sed -i -r 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ${PROV_NODE_DIR}/config/config.toml | |
sed -i -r 's/block_sync = true/block_sync = false/g' ${PROV_NODE_DIR}/config/config.toml | |
# Start gaia | |
interchain-security-pd start \ | |
--home ${PROV_NODE_DIR} \ | |
--rpc.laddr tcp://${NODE_IP}:26658 \ | |
--grpc.address ${NODE_IP}:9091 \ | |
--address tcp://${NODE_IP}:26655 \ | |
--p2p.laddr tcp://${NODE_IP}:26656 \ | |
--grpc-web.enable=false &> ${PROV_NODE_DIR}/logs & | |
sleep 5 | |
sed -i -r "/node =/ s/= .*/= \"tcp:\/\/${NODE_IP}:26628\"/" ${PROV_NODE_SUB_DIR}/config/client.toml | |
sed -i -r 's/timeout_commit = "5s"/timeout_commit = "3s"/g' ${PROV_NODE_SUB_DIR}/config/config.toml | |
sed -i -r 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ${PROV_NODE_SUB_DIR}/config/config.toml | |
sed -i -r 's/block_sync = true/block_sync = false/g' ${PROV_NODE_SUB_DIR}/config/config.toml | |
# # Start gaia | |
interchain-security-pd start \ | |
--home ${PROV_NODE_SUB_DIR} \ | |
--rpc.laddr tcp://${NODE_IP}:26628 \ | |
--grpc.address ${NODE_IP}:9021 \ | |
--address tcp://${NODE_IP}:26625 \ | |
--p2p.laddr tcp://${NODE_IP}:26626 \ | |
--grpc-web.enable=false &> ${PROV_NODE_SUB_DIR}/logs & | |
sleep 5 | |
# Build consumer chain proposal file | |
tee ${PROV_NODE_DIR}/consumer-proposal.json<<EOF | |
{ | |
"title": "Create a chain", | |
"summary": "Gonna be a great chain", | |
"chain_id": "consumer", | |
"initial_height": { | |
"revision_height": 1 | |
}, | |
"genesis_hash": "Z2VuX2hhc2g=", | |
"binary_hash": "YmluX2hhc2g=", | |
"spawn_time": "2023-03-11T09:02:14.718477-08:00", | |
"deposit": "10000001stake", | |
"consumer_redistribution_fraction": "0.75", | |
"blocks_per_distribution_transmission": 1000, | |
"historical_entries": 10000, | |
"unbonding_period": 864000000000000, | |
"ccv_timeout_period": 259200000000000, | |
"transfer_timeout_period": 1800000000000 | |
} | |
EOF | |
interchain-security-pd keys show $PROV_KEY --keyring-backend test --home ${PROV_NODE_DIR} | |
# Submit consumer chain proposal | |
interchain-security-pd tx gov submit-legacy-proposal consumer-addition ${PROV_NODE_DIR}/consumer-proposal.json --chain-id provider --from $PROV_KEY --home ${PROV_NODE_DIR} --node tcp://${NODE_IP}:26658 --keyring-backend test -y --gas auto | |
sleep 15 | |
# Vote yes to proposal | |
interchain-security-pd tx gov vote 1 yes --from $PROV_KEY --chain-id provider --home ${PROV_NODE_DIR} -y --keyring-backend test | |
sleep 5 | |
# CONSUMER CHAIN ## | |
# Clean start | |
pkill -f interchain-security-cd &> /dev/null || true | |
rm -rf ${CONS_NODE_DIR} | |
rm -rf ${CONS_NODE_SUB_DIR} | |
rm -rf ${CONS_FORK_NODE_DIR} | |
# Build genesis file and node directory structure | |
interchain-security-cd init $MONIKER --chain-id consumer --home ${CONS_NODE_DIR} | |
sleep 1 | |
# Create user account keypair | |
interchain-security-cd keys add $PROV_KEY --home ${CONS_NODE_DIR} --keyring-backend test --output json > ${CONS_NODE_DIR}/${PROV_KEY}.json 2>&1 | |
# Add stake to user account | |
CONS_ACCOUNT_ADDR=$(jq -r '.address' ${CONS_NODE_DIR}/${PROV_KEY}.json) | |
interchain-security-cd genesis add-genesis-account $CONS_ACCOUNT_ADDR 1000000000stake --home ${CONS_NODE_DIR} | |
sleep 5 | |
# Add consumer genesis states to genesis file | |
interchain-security-pd query provider consumer-genesis consumer --home ${PROV_NODE_DIR} -o json > consumer_gen.json | |
jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' ${CONS_NODE_DIR}/config/genesis.json consumer_gen.json > ${CONS_NODE_DIR}/edited_genesis.json \ | |
&& mv ${CONS_NODE_DIR}/edited_genesis.json ${CONS_NODE_DIR}/config/genesis.json | |
rm consumer_gen.json | |
# Create validator states | |
echo '{"height": "0","round": 0,"step": 0}' > ${CONS_NODE_DIR}/data/priv_validator_state.json | |
# Copy validator key files | |
cp ${PROV_NODE_DIR}/config/priv_validator_key.json ${CONS_NODE_DIR}/config/priv_validator_key.json | |
cp ${PROV_NODE_DIR}/config/node_key.json ${CONS_NODE_DIR}/config/node_key.json | |
# Set default client port | |
sed -i -r "/node =/ s/= .*/= \"tcp:\/\/${NODE_IP}:26648\"/" ${CONS_NODE_DIR}/config/client.toml | |
sed -i -r 's/block_sync = true/block_sync = false/g' ${CONS_NODE_DIR}/config/config.toml | |
# Start gaia | |
interchain-security-cd start --home ${CONS_NODE_DIR} \ | |
--rpc.laddr tcp://${NODE_IP}:26648 \ | |
--grpc.address ${NODE_IP}:9081 \ | |
--address tcp://${NODE_IP}:26645 \ | |
--p2p.laddr tcp://${NODE_IP}:26646 \ | |
--grpc-web.enable=false \ | |
&> ${CONS_NODE_DIR}/logs & | |
sleep 3 | |
# Setup Hermes in packet relayer mode | |
pkill -f hermes 2> /dev/null || true | |
tee ~/.hermes/config.toml<<EOF | |
[global] | |
log_level = "debug" | |
[mode] | |
[mode.clients] | |
enabled = true | |
refresh = true | |
misbehaviour = true | |
[mode.connections] | |
enabled = false | |
[mode.channels] | |
enabled = false | |
[mode.packets] | |
enabled = true | |
[[chains]] | |
id = "consumer" | |
ccv_consumer_chain = true | |
account_prefix = "cosmos" | |
clock_drift = "5s" | |
gas_multiplier = 1.1 | |
grpc_addr = "tcp://${NODE_IP}:9081" | |
key_name = "relayer" | |
max_gas = 2000000 | |
rpc_addr = "http://${NODE_IP}:26648" | |
rpc_timeout = "10s" | |
store_prefix = "ibc" | |
trusting_period = "2days" | |
event_source = { mode = 'push', url = 'ws://${NODE_IP}:26648/websocket' , batch_delay = '50ms' } | |
[chains.gas_price] | |
denom = "stake" | |
price = 0.00 | |
[chains.trust_threshold] | |
denominator = "3" | |
numerator = "1" | |
[[chains]] | |
id = "provider" | |
account_prefix = "cosmos" | |
clock_drift = "5s" | |
gas_multiplier = 1.1 | |
grpc_addr = "tcp://${NODE_IP}:9091" | |
key_name = "relayer" | |
max_gas = 2000000 | |
rpc_addr = "http://${NODE_IP}:26658" | |
rpc_timeout = "10s" | |
store_prefix = "ibc" | |
trusting_period = "2days" | |
event_source = { mode = 'push', url = 'ws://${NODE_IP}:26658/websocket' , batch_delay = '50ms' } | |
[chains.gas_price] | |
denom = "stake" | |
price = 0.00 | |
[chains.trust_threshold] | |
denominator = "3" | |
numerator = "1" | |
EOF | |
# Delet_e all previous keys in relayer | |
$HERMES_BIN keys delete --chain consumer --all | |
$HERMES_BIN keys delete --chain provider --all | |
# Restore keys to hermes relayer | |
$HERMES_BIN keys add --key-file ${CONS_NODE_DIR}/${PROV_KEY}.json --chain consumer | |
$HERMES_BIN keys add --key-file ${PROV_NODE_DIR}/${PROV_KEY}.json --chain provider | |
sleep 5 | |
$HERMES_BIN create connection \ | |
--a-chain consumer \ | |
--a-client 07-tendermint-0 \ | |
--b-client 07-tendermint-0 | |
$HERMES_BIN create channel \ | |
--a-chain consumer \ | |
--a-port consumer \ | |
--b-port provider \ | |
--order ordered \ | |
--channel-version 1 \ | |
--a-connection connection-0 | |
sleep 5 | |
# interchain-security-pd q tendermint-validator-set --home ${PROV_NODE_DIR} | |
# interchain-security-cd q tendermint-validator-set --home ${CONS_NODE_DIR} | |
# DELEGATIONS=$(interchain-security-pd q staking delegations $PROV_ACCOUNT_ADDR --home ${PROV_NODE_DIR} -o json) | |
# OPERATOR_ADDR=$(echo $DELEGATIONS | jq -r '.delegation_responses[0].delegation.validator_address') | |
# interchain-security-pd tx staking delegate $OPERATOR_ADDR 1000000stake \ | |
# --from $PROV_KEY \ | |
# --keyring-backend test \ | |
# --home ${PROV_NODE_DIR} \ | |
# --chain-id provider \ | |
# -y -b block | |
# sleep 5 | |
interchain-security-pd q tendermint-validator-set --home ${PROV_NODE_DIR} | |
interchain-security-cd q tendermint-validator-set --home ${CONS_NODE_DIR} | |
##### Fork consumer | |
tee ~/.hermes/config_fork.toml<<EOF | |
[global] | |
log_level = "debug" | |
[mode] | |
[mode.clients] | |
enabled = true | |
refresh = true | |
misbehaviour = true | |
[mode.connections] | |
enabled = false | |
[mode.channels] | |
enabled = false | |
[mode.packets] | |
enabled = true | |
[[chains]] | |
id = "consumer" | |
ccv_consumer_chain = true | |
account_prefix = "cosmos" | |
clock_drift = "5s" | |
gas_multiplier = 1.1 | |
grpc_addr = "tcp://${NODE_IP}:9071" | |
key_name = "relayer" | |
max_gas = 2000000 | |
rpc_addr = "http://${NODE_IP}:26638" | |
rpc_timeout = "10s" | |
store_prefix = "ibc" | |
trusting_period = "2days" | |
event_source = { mode = 'push', url = 'ws://${NODE_IP}:26638/websocket' , batch_delay = '50ms' } | |
[chains.gas_price] | |
denom = "stake" | |
price = 0.00 | |
[chains.trust_threshold] | |
denominator = "3" | |
numerator = "1" | |
[[chains]] | |
id = "provider" | |
account_prefix = "cosmos" | |
clock_drift = "5s" | |
gas_multiplier = 1.1 | |
grpc_addr = "tcp://${NODE_IP}:9091" | |
key_name = "relayer" | |
max_gas = 2000000 | |
rpc_addr = "http://${NODE_IP}:26658" | |
rpc_timeout = "10s" | |
store_prefix = "ibc" | |
trusting_period = "2days" | |
event_source = { mode = 'push', url = 'ws://${NODE_IP}:26658/websocket' , batch_delay = '50ms' } | |
[chains.gas_price] | |
denom = "stake" | |
price = 0.00 | |
[chains.trust_threshold] | |
denominator = "3" | |
numerator = "1" | |
EOF | |
rm -rf ~/.cometbft-light/ | |
read -r height hash < <( | |
curl -s "localhost:26648"/commit \ | |
| jq -r '(.result//.).signed_header.header.height + " " + (.result//.).signed_header.commit.block_id.hash') | |
diag "Height: ${height}, Hash: ${hash}" | |
sleep 10 | |
cp -r ${CONS_NODE_DIR} ${CONS_FORK_NODE_DIR} | |
# Set default client port | |
sed -i -r "/node =/ s/= .*/= \"tcp:\/\/${NODE_IP}:26638\"/" ${CONS_FORK_NODE_DIR}/config/client.toml | |
sed -i -r 's/block_sync = true/block_sync = false/g' ${CONS_FORK_NODE_DIR}/config/config.toml | |
# Find trusted state before fork | |
TRUSTED_HEIGHT=$($HERMES_BIN --json --config ~/.hermes/config.toml query client consensus --chain provider --client 07-tendermint-0 | tail -n 1 | jq '.result[2].revision_height') | |
# Start gaia | |
interchain-security-cd start --home ${CONS_FORK_NODE_DIR} \ | |
--rpc.laddr tcp://${NODE_IP}:26638 \ | |
--grpc.address ${NODE_IP}:9071 \ | |
--address tcp://${NODE_IP}:26635 \ | |
--p2p.laddr tcp://${NODE_IP}:26636 \ | |
--grpc-web.enable=false \ | |
&> ${CONS_FORK_NODE_DIR}/logs & | |
sleep 5 | |
diag "Start Hermes relayer multi-chain mode" | |
$HERMES_BIN --config ~/.hermes/config.toml start &> ~/.hermes/hermes-logs & | |
sleep 5 | |
diag "Running Hermes relayer evidence command" | |
# Run hermes in evidence mode | |
$HERMES_BIN --config ~/.hermes/config.toml evidence --chain consumer &> ~/.hermes/hermes-evidence-logs & | |
sleep 5 | |
diag "Updating client on forked chain using trusted height $TRUSTED_HEIGHT" | |
$HERMES_BIN --config ~/.hermes/config_fork.toml update client --client 07-tendermint-0 --host-chain provider --trusted-height $TRUSTED_HEIGHT | |
sleep 5 | |
# Check that the client state on provider and verify it is frozen | |
FROZEN_HEIGHT=$($HERMES_BIN --config ~/.hermes/config.toml --json query client state --chain provider --client 07-tendermint-0 | tail -n 1 | jq '.result.frozen_height.revision_height') | |
diag "Frozen height: $FROZEN_HEIGHT" | |
if [ "$FROZEN_HEIGHT" != "null" ]; then | |
diag "Client is frozen, success!" | |
else | |
diag "Client is not frozen, aborting." | |
exit 1 | |
fi | |
sleep 3 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment