Skip to content

Commit

Permalink
feat(cli): add cmd to collect withdrawal events and submit as actions (
Browse files Browse the repository at this point in the history
…#1261)

## Summary
Adds `bridge collect-withdrawals` and `bridge submit-withdrawals`
subcommands to `astria-cli`.

## Background
The worker service `astria-bridge-withdrawer` is a closed system that
collects withdrawal event from the rollup and submits them to the
sequencer in a closed loop. But it can be desirable to inspect the
withdrawal events generated by the bridge contracts, and then submit
them manually. This functionality is now provided by `astria-cli`.

## Changes
- Add subcommands `bridge collect-withdrawal-s` to `astria-cli`, which
has two different modes of operation, depending on whether
`--to-rollup-height` is set:
- if set, it fetches all blocks between `--from-rollup-height` and
`--to-rollup-height` (inclusive), converts them to seuquencer actions,
and then writes them to a file.
- if not set, it fetches blocks from `--from-rollup-height` until SIGINT
(Ctrl-C) is received. After the signal, the converted actions are
written to a file.

## Testing
- Added `run-smoke-cli` in `charts/deploy.just` (@joroshiba)
- Added a `smoke-cli:` in `.github/workflows/docker-build.yaml`
(@joroshiba)

---------

Co-authored-by: Jordan Oroshiba <jordan@astria.org>
  • Loading branch information
SuperFluffy and joroshiba authored Jul 13, 2024
1 parent bb41dc4 commit 1555c03
Show file tree
Hide file tree
Showing 12 changed files with 993 additions and 61 deletions.
36 changes: 35 additions & 1 deletion .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,43 @@ jobs:
timeout-minutes: 3
run: just run-smoke-test

smoke-cli:
needs: [run_checker, composer, conductor, sequencer, sequencer-relayer, evm-bridge-withdrawer]
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'astriaorg/astria') && (github.event_name == 'merge_group' || needs.run_checker.outputs.run_docker == 'true')
runs-on: buildjet-8vcpu-ubuntu-2204
steps:
- uses: actions/checkout@v4
- name: Install just
uses: taiki-e/install-action@just
- name: Install kind
uses: helm/kind-action@v1
with:
install_only: true
- name: Install astria cli (rust)
run: |
just install-cli
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Smoke Test Environment
timeout-minutes: 5
run: |
TAG=sha-$(git rev-parse --short HEAD)
just deploy cluster
kubectl create secret generic regcred --from-file=.dockerconfigjson=$HOME/.docker/config.json --type=kubernetes.io/dockerconfigjson
echo -e "\n\nDeploying with astria images tagged $TAG"
just deploy smoke-cli $TAG
- name: Run Smoke test
timeout-minutes: 3
run: just run-smoke-cli


docker:
if: ${{ always() && !cancelled() }}
needs: [composer, conductor, sequencer, sequencer-relayer, evm-bridge-withdrawer, smoke-test]
needs: [composer, conductor, sequencer, sequencer-relayer, evm-bridge-withdrawer, smoke-test, smoke-cli]
uses: ./.github/workflows/reusable-success.yml
with:
success: ${{ !contains(needs.*.result, 'failure') }}
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

130 changes: 122 additions & 8 deletions charts/deploy.just
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ delete tool *ARGS:
init tool *ARGS:
@just init-{{tool}} {{ARGS}}

run-smoke type *ARGS:
@just run-smoke-{{type}} {{ARGS}}

load-image image:
kind load docker-image {{image}} --name astria-dev-cluster

Expand Down Expand Up @@ -148,7 +151,6 @@ deploy-local-metrics:
kubectl apply -f kubernetes/metrics-server-local.yml

defaultTag := ""

deploy-smoke-test tag=defaultTag:
@echo "Deploying ingress controller..." && just deploy ingress-controller > /dev/null
@just wait-for-ingress-controller > /dev/null
Expand All @@ -171,6 +173,25 @@ deploy-smoke-test tag=defaultTag:
{{ if tag != '' { replace('--set images.evmBridgeWithdrawer.devTag=#', '#', tag) } else { '' } }} > /dev/null
@just wait-for-rollup > /dev/null

deploy-smoke-cli tag=defaultTag:
@echo "Deploying ingress controller..." && just deploy ingress-controller > /dev/null
@just wait-for-ingress-controller > /dev/null
@echo "Deploying local celestia instance..." && just deploy celestia-local > /dev/null
@helm dependency update charts/sequencer > /dev/null
@helm dependency update charts/evm-rollup > /dev/null
@echo "Setting up single astria sequencer..." && helm install \
-n astria-validator-single single-sequencer-chart ./charts/sequencer \
-f dev/values/validators/all.yml \
-f dev/values/validators/single.yml \
{{ if tag != '' { replace('--set images.sequencer.devTag=# --set sequencer-relayer.images.sequencerRelayer.devTag=#', '#', tag) } else { '' } }} \
--create-namespace > /dev/null
@just wait-for-sequencer > /dev/null
@echo "Starting EVM rollup..." && helm install -n astria-dev-cluster astria-chain-chart ./charts/evm-rollup -f dev/values/rollup/dev.yaml \
{{ if tag != '' { replace('--set images.conductor.devTag=# --set images.composer.devTag=#', '#', tag) } else { '' } }} \
--set config.blockscout.enabled=false \
--set config.faucet.enabled=false > /dev/null
@just wait-for-dev-rollup > /dev/null


evm_destination_address := "0xaC21B97d35Bf75A7dAb16f35b111a50e78A72F30"
# 1 RIA is 10^9 nRIA
Expand All @@ -180,32 +201,33 @@ rollup_multiplier := "1000000000"
# 10 RIA
sequencer_transfer_amount := "10"
sequencer_rpc_url := "http://rpc.sequencer.localdev.me"
sequencer_bridge_address := "astria13ahqz4pjqfmynk9ylrqv4fwe4957x2p0h5782u"
sequencer_bridge_pkey := "dfa7108e38ab71f89f356c72afc38600d5758f11a8c337164713e4471411d2e0"
sequencer_chain_id := "sequencer-test-chain-0"
init-rollup-bridge rollupName=defaultRollupName evmDestinationAddress=evm_destination_address transferAmount=sequencer_transfer_amount:
#!/usr/bin/env bash
SEQUENCER_BRIDGE_PKEY="dfa7108e38ab71f89f356c72afc38600d5758f11a8c337164713e4471411d2e0"
SEQUENCER_FUNDS_PKEY="934ab488f9e1900f6a08f50605ce1409ca9d95ebdc400dafc2e8a4306419fd52"
SEQUENCER_BRIDGE_ADDRESS="astria13ahqz4pjqfmynk9ylrqv4fwe4957x2p0h5782u"
SEQUENCER_CHAIN_ID="sequencer-test-chain-0"
ASSET="nria"
FEE_ASSET="nria"
TRANSFER_AMOUNT=$(echo "{{transferAmount}} * {{sequencer_base_amount}}" | bc)
astria-cli sequencer init-bridge-account \
--rollup-name {{rollupName}} \
--private-key $SEQUENCER_BRIDGE_PKEY \
--sequencer.chain-id $SEQUENCER_CHAIN_ID \
--private-key {{sequencer_bridge_pkey}} \
--sequencer.chain-id {{sequencer_chain_id}} \
--sequencer-url {{sequencer_rpc_url}} \
--fee-asset=$FEE_ASSET --asset=$ASSET || exit 1
astria-cli sequencer bridge-lock $SEQUENCER_BRIDGE_ADDRESS \
astria-cli sequencer bridge-lock {{sequencer_bridge_address}} \
--amount $TRANSFER_AMOUNT \
--destination-chain-address {{evmDestinationAddress}} \
--private-key $SEQUENCER_FUNDS_PKEY \
--sequencer.chain-id $SEQUENCER_CHAIN_ID \
--sequencer.chain-id {{sequencer_chain_id}} \
--sequencer-url {{sequencer_rpc_url}} \
--fee-asset=$FEE_ASSET --asset=$ASSET || exit 1


eth_rpc_url := "http://executor.astria.localdev.me/"
eth_ws_url := "ws://ws-executor.astria.localdev.me/"
bridge_tx_bytes := "0xf8f280843c54e7f182898594a58639fb5458e65e4fa917ff951c390292c24a15880de0b6b3a7640000b884bab916d00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002d617374726961313777306164656736346b7930646178776432756779756e65656c6c6d6a676e786c333935303400000000000000000000000000000000000000820a96a086b85348c9816f6d34533669db3d3626cf55eecea6a380d4d072efb1839df443a04b8b60c8b91dd30add1ca4a96097238d73bab29b0a958322d9a51755d5a5f287"
bridge_tx_hash := "0x67db5b0825e8f60b926234e209d54e0336cd94defe6720e7acadf871e0377150"
run-smoke-test:
Expand Down Expand Up @@ -304,6 +326,98 @@ delete-smoke-test:
just delete sequencer
just delete rollup

evm_contract_address := "0xA58639fB5458e65E4fA917FF951C390292C24A15"
run-smoke-cli:
#!/usr/bin/env bash
MAX_CHECKS=30
# Checking starting balance
BALANCE=$(just evm-get-balance {{evm_destination_address}})
if [ $BALANCE -ne 0 ]; then
echo "Starting balance is not correct"
exit 1
fi

echo "Testing Bridge In..."
just init rollup-bridge
CHECKS=0
EXPECTED_BALANCE=$(echo "{{sequencer_transfer_amount}} * {{sequencer_base_amount}} * {{rollup_multiplier}}" | bc)
while [ $CHECKS -lt $MAX_CHECKS ]; do
CHECKS=$((CHECKS+1))
BALANCE=$(just evm-get-balance {{evm_destination_address}})
echo "Check $CHECKS, Balance: $BALANCE, Expected: $EXPECTED_BALANCE"
if [ "$BALANCE" == "$EXPECTED_BALANCE" ]; then
echo "Bridge In success"
break
else
sleep 1
fi
done
if [ $CHECKS -eq $MAX_CHECKS ]; then
echo "Bridge In failure"
exit 1
fi

echo "Testing Bridge Out..."
just evm-send-raw-transaction {{bridge_tx_bytes}}
TRANSFERED_BALANCE=$(echo "1 * {{sequencer_base_amount}} * {{rollup_multiplier}}" | bc)
EXPECTED_BALANCE=$(echo "$EXPECTED_BALANCE - $TRANSFERED_BALANCE" | bc)
CHECKS=0
while [ $CHECKS -lt $MAX_CHECKS ]; do
CHECKS=$((CHECKS+1))
BALANCE=$(just evm-get-balance {{evm_destination_address}})
echo "Check $CHECKS, Balance: $BALANCE, Expected: $EXPECTED_BALANCE"
if [ "$BALANCE" == "$EXPECTED_BALANCE" ]; then
echo "Bridge Out EVM success"
break
else
sleep 1
fi
done
if [ $CHECKS -eq $MAX_CHECKS ]; then
echo "Bridge Out EVM failure"
exit 1
fi

CURRENT_BLOCK_HEX=$(just evm-get-block-by-number latest | jq -r '.number')
CURRENT_BLOCK=$(just hex-to-dec $CURRENT_BLOCK_HEX)
echo {{sequencer_bridge_pkey}} > test_se

astria-cli bridge collect-withdrawals \
--rollup-endpoint {{eth_ws_url}} \
--contract-address {{evm_contract_address}} \
--from-rollup-height 1 \
--to-rollup-height $CURRENT_BLOCK \
--rollup-asset-denom nria \
--bridge-address {{sequencer_bridge_address}} \
--output ./withdrawals.json
astria-cli bridge submit-withdrawals \
--signing-key <(printf "%s" "{{sequencer_bridge_pkey}}") \
--sequencer-chain-id {{sequencer_chain_id}} \
--sequencer-url {{sequencer_rpc_url}} \
--input ./withdrawals.json


CHECKS=0
EXPECTED_BALANCE=$(echo "1 * {{sequencer_base_amount}}" | bc)
while [ $CHECKS -lt $MAX_CHECKS ]; do
CHECKS=$((CHECKS+1))
BALANCE=$(astria-cli sequencer account balance astria17w0adeg64ky0daxwd2ugyuneellmjgnxl39504 --sequencer-url {{sequencer_rpc_url}} | awk '/nria/{print $(NF-1)}')
echo "Check $CHECKS, Balance: $BALANCE, Expected: $EXPECTED_BALANCE"
if [ "$BALANCE" == "$EXPECTED_BALANCE" ]; then
echo "Bridge Out Sequencer success"
break
else
sleep 1
fi
done
if [ $CHECKS -gt $MAX_CHECKS ]; then
echo "Bridge Out Sequencer failure"
exit 1
fi

exit 0

#############################################
## EVM Curl Command Helper Functions ##
#############################################
Expand Down
13 changes: 11 additions & 2 deletions crates/astria-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,26 @@ name = "astria-cli"
[dependencies]
color-eyre = "0.6"

astria-core = { path = "../astria-core" }
astria-bridge-contracts = { path = "../astria-bridge-contracts" }
astria-core = { path = "../astria-core", features = ["serde"] }

clap = { workspace = true, features = ["derive", "env"] }
ethers = { workspace = true, features = ["ws"] }
hex = { workspace = true }
ibc-types = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_yaml = "0.9.25"
sha2 = { workspace = true }
tokio = { workspace = true, features = ["rt", "macros"] }
tendermint = { workspace = true }
tokio = { workspace = true, features = ["rt", "macros", "signal"] }
tracing = { workspace = true }
which = { workspace = true }
humantime.workspace = true
tryhard.workspace = true
serde_json.workspace = true
futures.workspace = true
tracing-subscriber = "0.3.18"

[dependencies.astria-sequencer-client]
package = "astria-sequencer-client"
Expand Down
22 changes: 22 additions & 0 deletions crates/astria-cli/src/cli/bridge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use clap::Subcommand;
use color_eyre::eyre;

/// Interact with a Sequencer node
// allow: these are one-shot variants. the size doesn't matter as they are
// passed around only once.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Subcommand)]
pub(crate) enum Command {
/// Commands for interacting with Sequencer accounts
CollectWithdrawals(crate::commands::bridge::collect::WithdrawalEvents),
SubmitWithdrawals(crate::commands::bridge::submit::WithdrawalEvents),
}

impl Command {
pub(crate) async fn run(self) -> eyre::Result<()> {
match self {
Command::CollectWithdrawals(args) => args.run().await,
Command::SubmitWithdrawals(args) => args.run().await,
}
}
}
9 changes: 7 additions & 2 deletions crates/astria-cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod bridge;
pub(crate) mod sequencer;

use clap::{
Expand All @@ -16,7 +17,7 @@ const DEFAULT_SEQUENCER_CHAIN_ID: &str = "astria-dusk-7";
#[command(name = "astria-cli", version)]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Command>,
pub(crate) command: Option<Command>,
}

impl Cli {
Expand All @@ -33,7 +34,11 @@ impl Cli {

/// Commands that can be run
#[derive(Debug, Subcommand)]
pub enum Command {
pub(crate) enum Command {
Bridge {
#[command(subcommand)]
command: bridge::Command,
},
Sequencer {
#[command(subcommand)]
command: SequencerCommand,
Expand Down
Loading

0 comments on commit 1555c03

Please sign in to comment.