mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-23 17:28:23 +00:00
test: ⚡️ CI Refactor (#59)
Eventually our CI will be required to run two private blockchains locally plus associated relayers. This PR is to prepare for this fate by improving run times and refactoring our existing CIs so they are a bit easier to reason about. ### Refactors - **_We now run ALL CIs on every PR!_** This is so that we decomplexify the logic around conditional builds and fetching built binaries from another source. This reduces the surface area of code we have to maintain at the cost of execution time - This penalty is ameliorated by a layered caching system. At best, it will be less than a minute to complete a build since everything will be cached. On GH runners this is about 6 minutes sadly. - We will no longer be at risk of important CIs being skipped erroneously which hide true failures. - Caching is a low-risk approach because at worst it has to build from scratch. A bad cache hit will never imply the wrong thing gets build since cargo is smart enough to just throw away any inappropriate build artefacts. - `setup-rust` action created so we have a unified way of setting up runner and unifying our approach to caching - Use a unique caching key for different activities and it will fallback to shared cache if no matches - we are using `mainnet` kurtosis config so that it works with relayer assumptions ### Additions - We can specify the ethereum block time via a new cli arg `--slot-time <seconds>` - We can specify arbitrary network_param args which get passed into the generated yaml - e.g. giving `bun cli --kurtosis-network-args="pet=cat food=fish" will add: ```yml network_params: # existing params... pet: cat food: fish ``` - We now have the ability to programmatically modify the yaml - This means we are back down to a single `minimal.yml` kurtosis config so we dont have to maintain changes between them - Flow is: `add new cli arg` -> `add if() block which mutates yaml` -> `profit` --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>
This commit is contained in:
parent
e16420f266
commit
3776d80a2e
28 changed files with 633 additions and 461 deletions
38
.github/workflows/CI.yml
vendored
Normal file
38
.github/workflows/CI.yml
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#! Main CI Specification for DataHaven Repository
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: pr-checks-${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# First Tier
|
||||
build-operator:
|
||||
uses: ./.github/workflows/task-build-operator.yml
|
||||
secrets: inherit # For demonstrative purposes, we don't use any secrets yet.
|
||||
ts-build:
|
||||
uses: ./.github/workflows/task-ts-build.yml
|
||||
ts-lint:
|
||||
uses: ./.github/workflows/task-ts-lint.yml
|
||||
unit-tests:
|
||||
uses: ./.github/workflows/task-rust-tests.yml
|
||||
contract-tests:
|
||||
uses: ./.github/workflows/task-foundry-tests.yml
|
||||
rust-lint:
|
||||
uses: ./.github/workflows/task-rust-lint.yml
|
||||
|
||||
# Second Tier
|
||||
e2e-tests:
|
||||
needs: [build-operator]
|
||||
uses: ./.github/workflows/task-e2e.yml
|
||||
with:
|
||||
binary-hash: ${{ needs.build-operator.outputs.binary-hash }}
|
||||
59
.github/workflows/actions/setup-env/action.yml
vendored
Normal file
59
.github/workflows/actions/setup-env/action.yml
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
name: "Setup Rust Environment"
|
||||
description: "Creates a Rust environment with the specified toolchain, cache, and dependencies"
|
||||
|
||||
inputs:
|
||||
cache-key:
|
||||
description: "Cache key used to retrieve built data. Usually matches the profile of the build"
|
||||
required: false
|
||||
default: "cache"
|
||||
|
||||
cache-targets:
|
||||
description: "Whether to cache targets"
|
||||
required: false
|
||||
default: "true"
|
||||
|
||||
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set Rust version
|
||||
shell: bash
|
||||
run: |
|
||||
echo "BUILD_RUST_VERSION=$(rustc --version)" >> $GITHUB_ENV
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.9
|
||||
|
||||
- name: Set Rust caching env vars
|
||||
if: github.event_name != 'release' && github.event_name != 'workflow_dispatch'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
|
||||
sccache --show-stats
|
||||
|
||||
- name: Cache cargo + target + sccache2
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-targets: true
|
||||
cache-all-crates: true
|
||||
shared-key: ${{ runner.os }}-${{inputs.cache-key}}-${{ hashFiles('operator/rust-toolchain.toml') }}-${{ hashFiles('operator/Cargo.lock') }}
|
||||
workspaces: |
|
||||
operator -> target
|
||||
cache-on-failure: true
|
||||
cache-bin: true
|
||||
cache-directories: |
|
||||
~/.cache/sccache
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt, clippy
|
||||
|
||||
- uses: rui314/setup-mold@v1
|
||||
- name: Install libpq-dev
|
||||
shell: bash
|
||||
run: sudo apt-get update && sudo apt-get install -y libpq-dev libclang-dev
|
||||
- name: Install Protoc
|
||||
uses: arduino/setup-protoc@v3
|
||||
55
.github/workflows/foundry-tests.yml
vendored
55
.github/workflows/foundry-tests.yml
vendored
|
|
@ -1,55 +0,0 @@
|
|||
# Foundry Tests: CI for Foundry components (smart contracts for EigenLayer and Snowbridge interaction)
|
||||
#
|
||||
# Overview:
|
||||
# 1. All Foundry Tests: Executes the full suite of Foundry tests found within the `./contracts` directory
|
||||
|
||||
name: Foundry AVS Smart Contract Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
FOUNDRY_PROFILE: ci
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
partition: [1]
|
||||
|
||||
name: Foundry Tests
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: contracts
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
|
||||
- name: Show Forge version
|
||||
run: |
|
||||
forge --version
|
||||
|
||||
- name: Run Forge fmt
|
||||
run: |
|
||||
forge fmt --check
|
||||
id: fmt
|
||||
|
||||
- name: Run Forge build
|
||||
run: |
|
||||
forge build --sizes
|
||||
id: build
|
||||
|
||||
- name: Run Forge tests
|
||||
run: |
|
||||
forge test -vvv
|
||||
id: test
|
||||
129
.github/workflows/rust-lint.yml
vendored
129
.github/workflows/rust-lint.yml
vendored
|
|
@ -1,129 +0,0 @@
|
|||
# Lint and Format: CI for Rust components (DataHaven runtime and node Rust tests)
|
||||
#
|
||||
# Overview:
|
||||
# 1. Check Rust Format: Check that the Rust code is formatted correctly
|
||||
# 2. Check Rust Lint: Check that the Rust code is linted correctly
|
||||
|
||||
name: Lint and Format
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- perm-*
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pull_request:
|
||||
description: set to pull_request number to execute on external pr
|
||||
required: false
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
WORKING_DIR: operator
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
node_changed: ${{ steps.node_check.outputs.changed }}
|
||||
env:
|
||||
SKIP_BUILD_LABEL_PRESENT: ${{ contains(github.event.pull_request.labels.*.name, 'skip-node-build') }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Check if Substrate Node needs rebuild
|
||||
id: node_check
|
||||
run: |
|
||||
BASE_SHA="${{ github.event.pull_request.base.sha || github.event.before }}"
|
||||
HEAD_SHA="${{ github.sha }}"
|
||||
|
||||
if [[ "${{ env.SKIP_BUILD_LABEL_PRESENT }}" != "true" ]] && git diff --name-only $BASE_SHA $HEAD_SHA | grep -E '^operator/(client|node|pallets|runtime)/|^operator/Cargo\.toml$'; then
|
||||
echo "changed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Comparing changes from $BASE_SHA to $HEAD_SHA"
|
||||
echo "changed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
cargo-fmt:
|
||||
needs: [ setup ]
|
||||
if: needs.setup.outputs.node_changed == 'true'
|
||||
name: "Check format with rustfmt"
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.WORKING_DIR }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
# ! If this action starts failing, it may be because of this,
|
||||
# ! For now this is not needed, and makes the workflow slower
|
||||
# - name: Install protoc
|
||||
# run: |
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y protobuf-compiler
|
||||
# protoc --version
|
||||
|
||||
- name: Run cargo fmt
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
check-rust-lint:
|
||||
needs: [ setup ]
|
||||
if: needs.setup.outputs.node_changed == 'true'
|
||||
name: "Check lint with clippy"
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.WORKING_DIR }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install protoc
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y protobuf-compiler
|
||||
protoc --version
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Install libpq-dev
|
||||
run: sudo apt-get update && sudo apt-get install -y libpq-dev
|
||||
|
||||
- name: Install protoc
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y protobuf-compiler
|
||||
protoc --version
|
||||
|
||||
- name: Run cargo clippy
|
||||
run: SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --features try-runtime,runtime-benchmarks --locked
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
check-cargo-sort:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.WORKING_DIR }}
|
||||
|
||||
steps:
|
||||
- name: Check out the repository to the runner
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Make script executable
|
||||
run: chmod +x scripts/sort-cargo-deps.sh
|
||||
|
||||
- name: Run the script on all Cargo.toml files
|
||||
run: find . -name "Cargo.toml" -print0 | xargs -0 -n1 -I{} bash -c 'scripts/sort-cargo-deps.sh "{}" check' || exit 1
|
||||
128
.github/workflows/rust-tests.yml
vendored
128
.github/workflows/rust-tests.yml
vendored
|
|
@ -1,128 +0,0 @@
|
|||
# Rust Tests: CI for Rust components (DataHaven runtime and node Rust tests)
|
||||
#
|
||||
# Overview:
|
||||
# 1. Prepare: This job handles the setup phase where the cargo nextest archive is created
|
||||
# and uploaded to the workflow for use in the subsequent jobs
|
||||
# 2. All Rust Tests: Executes the full suite of Rust tests across two partitions to
|
||||
# to reduce total execution time.
|
||||
|
||||
name: DataHave Operator Rust Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
node_changed: ${{ steps.node_check.outputs.changed }}
|
||||
env:
|
||||
SKIP_BUILD_LABEL_PRESENT: ${{ contains(github.event.pull_request.labels.*.name, 'skip-node-build') }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Check if Substrate Node needs rebuild
|
||||
id: node_check
|
||||
run: |
|
||||
BASE_SHA="${{ github.event.pull_request.base.sha || github.event.before }}"
|
||||
HEAD_SHA="${{ github.sha }}"
|
||||
|
||||
if [[ "${{ env.SKIP_BUILD_LABEL_PRESENT }}" != "true" ]] && git diff --name-only $BASE_SHA $HEAD_SHA | grep -E '^operator/(client|node|pallets|runtime)/|^operator/Cargo\.toml$'; then
|
||||
echo "changed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Comparing changes from $BASE_SHA to $HEAD_SHA"
|
||||
echo "changed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
prepare:
|
||||
needs: [setup]
|
||||
if: needs.setup.outputs.node_changed == 'true'
|
||||
name: Prepare artifacts for Rust tests
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
CARGO_INCREMENTAL: "0"
|
||||
CARGO_TERM_COLOR: always
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./operator
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# By default actions/checkout checks out a merge commit. Check out the PR head instead.
|
||||
# https://github.com/actions/checkout#checkout-pull-request-head-commit-instead-of-merge-commit
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: rui314/setup-mold@v1
|
||||
- name: Install nextest
|
||||
uses: taiki-e/install-action@nextest
|
||||
# Install libpq-dev
|
||||
- name: Install libpq-dev
|
||||
run: sudo apt-get update && sudo apt-get install -y libpq-dev
|
||||
- name: Install Protoc
|
||||
uses: arduino/setup-protoc@v3
|
||||
- name: Build and archive tests
|
||||
run: cargo nextest archive --archive-file nextest-archive.tar.zst
|
||||
- name: Upload archive to workflow
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nextest-archive
|
||||
path: ./operator/nextest-archive.tar.zst
|
||||
|
||||
all-rust-tests:
|
||||
needs: [setup, prepare]
|
||||
if: needs.setup.outputs.node_changed == 'true'
|
||||
name: Run all Operator Rust tests (/w partitioning)
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
partition: [1, 2]
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./operator
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install nextest
|
||||
uses: taiki-e/install-action@nextest
|
||||
- name: Download archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nextest-archive
|
||||
- name: Run Tests for All Projects!
|
||||
run: |
|
||||
~/.cargo/bin/cargo-nextest nextest run \
|
||||
--archive-file ../nextest-archive.tar.zst \
|
||||
--partition count:${{ matrix.partition }}/2
|
||||
|
||||
tests-result-checker:
|
||||
name: Check tests were successful
|
||||
needs: [setup, all-rust-tests]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Validate test results
|
||||
run: |
|
||||
echo "node_changed: ${{ needs.setup.outputs.node_changed }}"
|
||||
echo "matrix result: ${{ needs.all-rust-tests.result }}"
|
||||
|
||||
if [ "${{ needs.setup.outputs.node_changed }}" == "true" ]; then
|
||||
if [ "${{ needs.all-rust-tests.result }}" != "success" ]; then
|
||||
echo "Rust tests failed or were cancelled"
|
||||
exit 1
|
||||
else
|
||||
echo "Rust tests passed"
|
||||
fi
|
||||
else
|
||||
echo "No relevant changes — skipping rust tests"
|
||||
fi
|
||||
57
.github/workflows/task-build-operator.yml
vendored
Normal file
57
.github/workflows/task-build-operator.yml
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Build Operator: CI for building the operator binary
|
||||
|
||||
name: DataHave Operator Rust Tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
outputs:
|
||||
binary-hash:
|
||||
description: "The hash of the operator binary"
|
||||
value: ${{ jobs.build-node.outputs.binary-hash }}
|
||||
|
||||
jobs:
|
||||
build-node:
|
||||
outputs:
|
||||
binary-hash: ${{ steps.hash-binary.outputs.datahaven-node-hash }}
|
||||
name: Build operator binary
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
CARGO_INCREMENTAL: "0"
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTFLAGS: "-C linker=clang -C link-arg=-fuse-ld=mold"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./operator
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 1
|
||||
- uses: ./.github/workflows/actions/setup-env
|
||||
with:
|
||||
cache-key: CI
|
||||
- name: Build node binary
|
||||
run: cargo build --profile ci --locked
|
||||
- name: Hash binary
|
||||
id: hash-binary
|
||||
run: |
|
||||
TIMESTAMP=$(date +%s)
|
||||
|
||||
BINARY_PATH=./target/ci/datahaven-node
|
||||
HASH=$(echo "$TIMESTAMP" | cat - $BINARY_PATH | sha256sum | awk '{ print $1 }')
|
||||
echo "datahaven-node-hash=$HASH" >> $GITHUB_OUTPUT
|
||||
echo "Hash of the datahaven-node is: $HASH (with timestamp: $TIMESTAMP)"
|
||||
|
||||
- name: Upload binary to workflow
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: datahaven-node-${{ steps.hash-binary.outputs.datahaven-node-hash }}
|
||||
path: operator/target/ci/datahaven-node
|
||||
retention-days: 1
|
||||
|
||||
- name: Build Stats
|
||||
run: |
|
||||
sccache --show-stats
|
||||
|
||||
|
|
@ -8,15 +8,13 @@
|
|||
name: E2E - Kurtosis Deploy and Verify
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: "tests-${{ github.head_ref }}"
|
||||
cancel-in-progress: true
|
||||
workflow_call:
|
||||
inputs:
|
||||
binary-hash:
|
||||
description: "The hash of the operator binary"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
FOUNDRY_PROFILE: ci
|
||||
|
|
@ -50,12 +48,31 @@ jobs:
|
|||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- uses: actions/cache@v4
|
||||
- name: Cache Foundry libraries
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ~/.foundry/cache
|
||||
key: ${{ runner.os }}-foundry-${{ hashFiles('**/foundry.toml') }}
|
||||
path: ../contracts/lib
|
||||
key: ${{ runner.os }}-foundry-libs-${{ hashFiles('.gitmodules') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-foundry-
|
||||
${{ runner.os }}-foundry-libs-
|
||||
|
||||
- name: Cache Foundry build artifacts
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
../contracts/out
|
||||
../contracts/cache
|
||||
key: ${{ runner.os }}-foundry-build-${{ hashFiles('contracts/foundry.toml', 'contracts/**/*.sol') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-foundry-build-
|
||||
|
||||
- name: Download operator binary
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: datahaven-node-${{ inputs.binary-hash }}
|
||||
path: operator/target/release/
|
||||
- run: chmod +x ../operator/target/release/datahaven-node
|
||||
- run: ../operator/target/release/datahaven-node --help
|
||||
|
||||
- run: bun install
|
||||
- run: bun start:e2e:ci
|
||||
56
.github/workflows/task-foundry-tests.yml
vendored
Normal file
56
.github/workflows/task-foundry-tests.yml
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# Foundry Tests: CI for Foundry components (smart contracts for EigenLayer and Snowbridge interaction)
|
||||
#
|
||||
# Overview:
|
||||
# 1. All Foundry Tests: Executes the full suite of Foundry tests found within the `./contracts` directory
|
||||
|
||||
name: Foundry AVS Smart Contract Tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
FOUNDRY_PROFILE: ci
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
partition: [1]
|
||||
|
||||
name: Foundry Tests
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: contracts
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
|
||||
- name: Cache Foundry libraries
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: contracts/lib
|
||||
key: ${{ runner.os }}-foundry-libs-${{ hashFiles('contracts/.gitmodules') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-foundry-libs-
|
||||
|
||||
- name: Cache Foundry build artifacts
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
contracts/out
|
||||
contracts/cache
|
||||
key: ${{ runner.os }}-foundry-build-${{ hashFiles('contracts/foundry.toml', 'contracts/**/*.sol') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-foundry-build-
|
||||
|
||||
- run: forge --version
|
||||
- run: forge fmt --check
|
||||
- run: forge build --sizes
|
||||
- run: forge test -vvv
|
||||
72
.github/workflows/task-rust-lint.yml
vendored
Normal file
72
.github/workflows/task-rust-lint.yml
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# Lint and Format: CI for Rust components (DataHaven runtime and node Rust tests)
|
||||
#
|
||||
# Overview:
|
||||
# 1. Check Rust Format: Check that the Rust code is formatted correctly
|
||||
# 2. Check Rust Lint: Check that the Rust code is linted correctly
|
||||
|
||||
name: Lint and Format
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pull_request:
|
||||
description: set to pull_request number to execute on external pr
|
||||
required: false
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
WORKING_DIR: operator
|
||||
RUSTFLAGS: "-C linker=clang -C link-arg=-fuse-ld=mold"
|
||||
|
||||
jobs:
|
||||
cargo-fmt:
|
||||
name: "Check format with rustfmt"
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.WORKING_DIR }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: ./.github/workflows/actions/setup-env
|
||||
with:
|
||||
cache-key: FMT
|
||||
cache-targets: false
|
||||
|
||||
- name: Run cargo fmt
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
check-rust-lint:
|
||||
name: "Check lint with clippy"
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.WORKING_DIR }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: ./.github/workflows/actions/setup-env
|
||||
with:
|
||||
cache-key: LINT
|
||||
|
||||
- name: Run cargo clippy
|
||||
run: SKIP_WASM_BUILD=1 cargo clippy --features try-runtime,runtime-benchmarks --locked --release
|
||||
|
||||
check-cargo-sort:
|
||||
name: "Check Cargo sort"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.WORKING_DIR }}
|
||||
|
||||
steps:
|
||||
- name: Check out the repository to the runner
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Make script executable
|
||||
run: chmod +x scripts/sort-cargo-deps.sh
|
||||
|
||||
- name: Run the script on all Cargo.toml files
|
||||
run: find . -name "Cargo.toml" -print0 | xargs -0 -n1 -I{} bash -c 'scripts/sort-cargo-deps.sh "{}" check' || exit 1
|
||||
88
.github/workflows/task-rust-tests.yml
vendored
Normal file
88
.github/workflows/task-rust-tests.yml
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Rust Tests: CI for Rust components (DataHaven runtime and node Rust tests)
|
||||
#
|
||||
# Overview:
|
||||
# 1. Prepare: This job handles the setup phase where the cargo nextest archive is created
|
||||
# and uploaded to the workflow for use in the subsequent jobs
|
||||
# 2. All Rust Tests: Executes the full suite of Rust tests across two partitions to
|
||||
# to reduce total execution time.
|
||||
|
||||
name: DataHave Operator Rust Tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
|
||||
prepare:
|
||||
name: Prepare artifacts for Rust tests
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
CARGO_INCREMENTAL: "0"
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTFLAGS: "-C linker=clang -C link-arg=-fuse-ld=mold"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./operator
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/workflows/actions/setup-env
|
||||
with:
|
||||
cache-key: "TEST"
|
||||
- name: Install nextest
|
||||
uses: taiki-e/install-action@nextest
|
||||
- name: Build and archive tests
|
||||
run: cargo nextest archive --archive-file nextest-archive.tar.zst
|
||||
- name: Upload archive to workflow
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nextest-archive
|
||||
path: ./operator/nextest-archive.tar.zst
|
||||
|
||||
all-rust-tests:
|
||||
name: Run all Operator Rust tests (/w partitioning)
|
||||
needs: [prepare]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
partition: [1, 2]
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./operator
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install nextest
|
||||
uses: taiki-e/install-action@nextest
|
||||
- name: Download archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nextest-archive
|
||||
- name: Run Tests for All Projects!
|
||||
run: |
|
||||
~/.cargo/bin/cargo-nextest nextest run \
|
||||
--archive-file ../nextest-archive.tar.zst \
|
||||
--partition count:${{ matrix.partition }}/2
|
||||
|
||||
tests-result-checker:
|
||||
name: Check tests were successful
|
||||
needs: [all-rust-tests]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Validate test results
|
||||
run: |
|
||||
echo "matrix result: ${{ needs.all-rust-tests.result }}"
|
||||
|
||||
if [ "${{ needs.all-rust-tests.result }}" != "success" ]; then
|
||||
echo "Rust tests failed or were cancelled"
|
||||
exit 1
|
||||
else
|
||||
echo "Rust tests passed"
|
||||
fi
|
||||
|
||||
|
|
@ -1,11 +1,8 @@
|
|||
name: TS Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
generate-wagmi:
|
||||
|
|
@ -1,11 +1,8 @@
|
|||
name: TS Lint & Format
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
name: Audit Rust dependencies
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
push:
|
||||
24
contracts/src/DataHavenTest.sol
Normal file
24
contracts/src/DataHavenTest.sol
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// SPDX-License-Identifier: GPL-3.0
|
||||
// This is a test contract for the DataHaven project
|
||||
// It is deployed as pure bytecode in kurtosis
|
||||
pragma solidity >=0.8.2 <0.9.0;
|
||||
|
||||
contract DataHavenTest {
|
||||
uint256 public number;
|
||||
address public owner;
|
||||
|
||||
constructor() {
|
||||
number = 10;
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function decrement() external {
|
||||
require(number > 0, "Number should be greater than 0");
|
||||
number = number - 1;
|
||||
}
|
||||
|
||||
function reset() external {
|
||||
require(msg.sender == owner, "Only callable by owner!");
|
||||
number = 10;
|
||||
}
|
||||
}
|
||||
|
|
@ -206,3 +206,9 @@ fc-mapping-sync = { git = "https://github.com/polkadot-evm/frontier", branch = "
|
|||
fc-rpc = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
|
||||
fc-rpc-core = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
|
||||
fc-storage = { git = "https://github.com/polkadot-evm/frontier", branch = "stable2412", default-features = false }
|
||||
|
||||
[profile.ci]
|
||||
inherits = "release"
|
||||
incremental = false
|
||||
codegen-units = 16
|
||||
lto = false
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
"tiny-invariant": "^1.3.3",
|
||||
"viem": "^2.28.0",
|
||||
"wagmi": "^2.15.0",
|
||||
"yaml": "^2.7.1",
|
||||
"zod": "^3.24.3",
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -194,7 +195,7 @@
|
|||
|
||||
"@metamask/utils": ["@metamask/utils@8.5.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.0.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "debug": "^4.3.4", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ=="],
|
||||
|
||||
"@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="],
|
||||
"@noble/ciphers": ["@noble/ciphers@1.2.1", "", {}, "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA=="],
|
||||
|
||||
"@noble/curves": ["@noble/curves@1.8.2", "", { "dependencies": { "@noble/hashes": "1.7.2" } }, "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g=="],
|
||||
|
||||
|
|
@ -932,6 +933,8 @@
|
|||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yaml": ["yaml@2.7.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="],
|
||||
|
||||
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||
|
||||
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||
|
|
@ -942,6 +945,8 @@
|
|||
|
||||
"zustand": ["zustand@5.0.0", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ=="],
|
||||
|
||||
"@coinbase/wallet-sdk/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"@dotenvx/dotenvx/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
|
||||
|
||||
"@inquirer/core/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||
|
|
@ -956,6 +961,8 @@
|
|||
|
||||
"@metamask/sdk-communication-layer/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
|
||||
|
||||
"@metamask/utils/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"@metamask/utils/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
||||
|
||||
"@reown/appkit/@walletconnect/types": ["@walletconnect/types@2.19.2", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "events": "3.3.0" } }, "sha512-/LZWhkVCUN+fcTgQUxArxhn2R8DF+LSd/6Wh9FnpjeK/Sdupx1EPS8okWG6WPAqq2f404PRoNAfQytQ82Xdl3g=="],
|
||||
|
|
@ -992,8 +999,6 @@
|
|||
|
||||
"@walletconnect/time/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
|
||||
|
||||
"@walletconnect/utils/@noble/ciphers": ["@noble/ciphers@1.2.1", "", {}, "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA=="],
|
||||
|
||||
"@walletconnect/utils/@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="],
|
||||
|
||||
"@walletconnect/utils/@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
|
||||
|
|
@ -1016,6 +1021,8 @@
|
|||
|
||||
"cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"eciesjs/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"engine.io-client/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
||||
|
||||
"engine.io-client/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="],
|
||||
|
|
@ -1038,6 +1045,8 @@
|
|||
|
||||
"obj-multiplex/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"ox/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"qrcode/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="],
|
||||
|
||||
"restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
|
||||
|
|
@ -1060,6 +1069,8 @@
|
|||
|
||||
"@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/utils": ["@metamask/utils@8.5.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.0.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "debug": "^4.3.4", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ=="],
|
||||
|
||||
"@metamask/rpc-errors/@metamask/utils/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"@metamask/rpc-errors/@metamask/utils/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
||||
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/sign-client": ["@walletconnect/sign-client@2.19.2", "", { "dependencies": { "@walletconnect/core": "2.19.2", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/logger": "2.1.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.19.2", "@walletconnect/utils": "2.19.2", "events": "3.3.0" } }, "sha512-a/K5PRIFPCjfHq5xx3WYKHAAF8Ft2I1LtxloyibqiQOoUtNLfKgFB1r8sdMvXM7/PADNPe4iAw4uSE6PrARrfg=="],
|
||||
|
|
@ -1128,12 +1139,12 @@
|
|||
|
||||
"yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/utils/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/utils/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
||||
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.19.2", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.19.2", "@walletconnect/utils": "2.19.2", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.33.0", "events": "3.3.0", "uint8arrays": "3.1.0" } }, "sha512-iu0mgLj51AXcKpdNj8+4EdNNBd/mkNjLEhZn6UMc/r7BM9WbmpPMEydA39WeRLbdLO4kbpmq4wTbiskI1rg+HA=="],
|
||||
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/@noble/ciphers": ["@noble/ciphers@1.2.1", "", {}, "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA=="],
|
||||
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="],
|
||||
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
|
||||
|
|
@ -1142,8 +1153,6 @@
|
|||
|
||||
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.19.2", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.19.2", "@walletconnect/utils": "2.19.2", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.33.0", "events": "3.3.0", "uint8arrays": "3.1.0" } }, "sha512-iu0mgLj51AXcKpdNj8+4EdNNBd/mkNjLEhZn6UMc/r7BM9WbmpPMEydA39WeRLbdLO4kbpmq4wTbiskI1rg+HA=="],
|
||||
|
||||
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/@noble/ciphers": ["@noble/ciphers@1.2.1", "", {}, "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA=="],
|
||||
|
||||
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="],
|
||||
|
||||
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
|
||||
|
|
@ -1152,8 +1161,6 @@
|
|||
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.19.2", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.19.2", "@walletconnect/utils": "2.19.2", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.33.0", "events": "3.3.0", "uint8arrays": "3.1.0" } }, "sha512-iu0mgLj51AXcKpdNj8+4EdNNBd/mkNjLEhZn6UMc/r7BM9WbmpPMEydA39WeRLbdLO4kbpmq4wTbiskI1rg+HA=="],
|
||||
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/@noble/ciphers": ["@noble/ciphers@1.2.1", "", {}, "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA=="],
|
||||
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="],
|
||||
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
|
||||
|
|
@ -1162,7 +1169,7 @@
|
|||
|
||||
"@walletconnect/utils/viem/ox/@noble/curves": ["@noble/curves@1.8.2", "", { "dependencies": { "@noble/hashes": "1.7.2" } }, "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g=="],
|
||||
|
||||
"@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/hashes@1.7.2", "", {}, "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ=="],
|
||||
"@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"qrcode/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
|
|
@ -1184,20 +1191,28 @@
|
|||
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
|
||||
|
||||
"@walletconnect/utils/viem/ox/@noble/curves/@noble/hashes": ["@noble/hashes@1.7.2", "", {}, "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ=="],
|
||||
|
||||
"qrcode/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"qrcode/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves": ["@noble/curves@1.8.2", "", { "dependencies": { "@noble/hashes": "1.7.2" } }, "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g=="],
|
||||
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/hashes@1.7.2", "", {}, "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ=="],
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves": ["@noble/curves@1.8.2", "", { "dependencies": { "@noble/hashes": "1.7.2" } }, "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g=="],
|
||||
|
||||
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/hashes@1.7.2", "", {}, "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ=="],
|
||||
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves": ["@noble/curves@1.8.2", "", { "dependencies": { "@noble/hashes": "1.7.2" } }, "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g=="],
|
||||
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/hashes@1.7.2", "", {}, "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ=="],
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves/@noble/hashes": ["@noble/hashes@1.7.2", "", {}, "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ=="],
|
||||
|
||||
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves/@noble/hashes": ["@noble/hashes@1.7.2", "", {}, "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ=="],
|
||||
|
||||
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves/@noble/hashes": ["@noble/hashes@1.7.2", "", {}, "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ=="],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import type { Command } from "@commander-js/extra-typings";
|
||||
import { deployContracts } from "scripts/deploy-contracts";
|
||||
import { launchKurtosis } from "scripts/launch-kurtosis";
|
||||
import sendTxn from "scripts/send-txn";
|
||||
import invariant from "tiny-invariant";
|
||||
import {
|
||||
|
|
@ -12,6 +11,7 @@ import {
|
|||
} from "utils";
|
||||
import { checkDependencies } from "./checks";
|
||||
import { performDatahavenOperations } from "./datahaven";
|
||||
import { launchKurtosis } from "./kurtosis";
|
||||
import { LaunchedNetwork } from "./launchedNetwork";
|
||||
import { performRelayerOperations } from "./relayer";
|
||||
import { performSummaryOperations } from "./summary";
|
||||
|
|
@ -28,13 +28,16 @@ export interface LaunchOptions {
|
|||
relayer?: boolean;
|
||||
relayerBinPath?: string;
|
||||
skipCleaning?: boolean;
|
||||
alwaysClean?: boolean;
|
||||
datahavenBinPath?: string;
|
||||
datahaven?: boolean;
|
||||
kurtosisNetworkArgs?: string;
|
||||
slotTime?: number;
|
||||
}
|
||||
|
||||
export const BASE_SERVICES = [
|
||||
"cl-1-lighthouse-reth",
|
||||
"cl-1-lighthouse-reth",
|
||||
"cl-2-lighthouse-reth",
|
||||
"el-1-reth-lighthouse",
|
||||
"el-2-reth-lighthouse",
|
||||
"dora"
|
||||
|
|
@ -53,11 +56,7 @@ const launchFunction = async (options: LaunchOptions, launchedNetwork: LaunchedN
|
|||
await checkDependencies();
|
||||
|
||||
logger.trace("Launching Kurtosis enclave");
|
||||
await launchKurtosis({
|
||||
launchKurtosis: options.launchKurtosis,
|
||||
blockscout: options.blockscout,
|
||||
skipCleaning: options.skipCleaning
|
||||
});
|
||||
await launchKurtosis(options);
|
||||
logger.trace("Kurtosis enclave launched");
|
||||
|
||||
logger.trace("Send test transaction");
|
||||
|
|
@ -116,7 +115,9 @@ const launchFunction = async (options: LaunchOptions, launchedNetwork: LaunchedN
|
|||
printDivider();
|
||||
|
||||
performSummaryOperations(options, launchedNetwork);
|
||||
logger.debug("Launch function completed successfully");
|
||||
const fullEnd = performance.now();
|
||||
const fullMinutes = ((fullEnd - timeStart) / (1000 * 60)).toFixed(1);
|
||||
logger.info(`Launch function completed successfully in ${fullMinutes} minutes`);
|
||||
};
|
||||
|
||||
export const launch = async (options: LaunchOptions) => {
|
||||
|
|
@ -132,14 +133,7 @@ export const launch = async (options: LaunchOptions) => {
|
|||
export const launchPreActionHook = (
|
||||
thisCmd: Command<[], LaunchOptions & { [key: string]: any }>
|
||||
) => {
|
||||
const {
|
||||
blockscout,
|
||||
verified,
|
||||
fundValidators,
|
||||
setupValidators,
|
||||
updateValidatorSet,
|
||||
deployContracts
|
||||
} = thisCmd.opts();
|
||||
const { blockscout, verified, fundValidators, setupValidators, deployContracts } = thisCmd.opts();
|
||||
if (verified && !blockscout) {
|
||||
thisCmd.error("--verified requires --blockscout to be set");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { $ } from "bun";
|
||||
import type { LaunchOptions } from "cli/handlers";
|
||||
import invariant from "tiny-invariant";
|
||||
import {
|
||||
type KurtosisService,
|
||||
confirmWithTimeout,
|
||||
|
|
@ -7,27 +9,18 @@ import {
|
|||
printDivider,
|
||||
printHeader
|
||||
} from "utils";
|
||||
import { parse, stringify } from "yaml";
|
||||
|
||||
/**
|
||||
* Launches a Kurtosis Ethereum network enclave for testing.
|
||||
*
|
||||
* This function checks if a Kurtosis network is already running. If it is:
|
||||
* - With `launchKurtosis: false` - keeps the existing enclave
|
||||
* - With `launchKurtosis: true` - cleans and relaunches the enclave
|
||||
* - With `launchKurtosis: undefined` - prompts the user to decide whether to relaunch
|
||||
*
|
||||
* If no network is running, it launches a new one.
|
||||
*
|
||||
* @param options - Configuration options
|
||||
* @param options.launchKurtosis - Whether to forcibly launch Kurtosis (true), keep existing (false), or prompt user (undefined)
|
||||
* @param options.blockscout - Whether to add Blockscout service (true/undefined) or not (false)
|
||||
* @param options.skipCleaning - Whether to skip cleaning Kurtosis (true) or not (false)
|
||||
* @returns Object containing success status and Docker services information
|
||||
*/
|
||||
export const launchKurtosis = async (
|
||||
options: { launchKurtosis?: boolean; blockscout?: boolean; skipCleaning?: boolean } = {}
|
||||
options: LaunchOptions = {}
|
||||
): Promise<Record<string, KurtosisService>> => {
|
||||
if (await checkKurtosisRunning()) {
|
||||
if ((await checkKurtosisRunning()) && !options.alwaysClean) {
|
||||
logger.info("ℹ️ Kurtosis network is already running.");
|
||||
|
||||
logger.trace("Checking if launchKurtosis option was set via flags");
|
||||
|
|
@ -73,10 +66,9 @@ export const launchKurtosis = async (
|
|||
}
|
||||
|
||||
logger.info("🚀 Starting Kurtosis enclave...");
|
||||
const configFile =
|
||||
options.blockscout === true
|
||||
? "configs/kurtosis/minimal-with-bs.yaml"
|
||||
: "configs/kurtosis/minimal.yaml";
|
||||
|
||||
const configFile = await modifyConfig(options, "configs/kurtosis/minimal.yaml");
|
||||
|
||||
logger.info(`Using Kurtosis config file: ${configFile}`);
|
||||
|
||||
const { stderr, stdout, exitCode } =
|
||||
|
|
@ -107,3 +99,42 @@ const checkKurtosisRunning = async (): Promise<boolean> => {
|
|||
const text = await $`kurtosis enclave ls | grep "datahaven-ethereum" | grep RUNNING`.text();
|
||||
return text.length > 0;
|
||||
};
|
||||
|
||||
const modifyConfig = async (options: LaunchOptions, configFile: string) => {
|
||||
const outputDir = "tmp/configs";
|
||||
logger.debug(`Ensuring output directory exists: ${outputDir}`);
|
||||
await $`mkdir -p ${outputDir}`.quiet();
|
||||
|
||||
const file = Bun.file(configFile);
|
||||
invariant(file, `❌ Config file ${configFile} not found`);
|
||||
|
||||
const config = await file.text();
|
||||
logger.debug(`Parsing config at ${configFile}`);
|
||||
logger.trace(config);
|
||||
|
||||
const parsedConfig = parse(config);
|
||||
|
||||
if (options.blockscout) {
|
||||
parsedConfig.additional_services.push("blockscout");
|
||||
}
|
||||
|
||||
if (options.slotTime) {
|
||||
parsedConfig.network_params.seconds_per_slot = options.slotTime;
|
||||
}
|
||||
|
||||
if (options.kurtosisNetworkArgs) {
|
||||
logger.debug(`Using custom Kurtosis network args: ${options.kurtosisNetworkArgs}`);
|
||||
const args = options.kurtosisNetworkArgs.split(" ");
|
||||
for (const arg of args) {
|
||||
const [key, value] = arg.split("=");
|
||||
parsedConfig.network_params[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
logger.trace(parsedConfig);
|
||||
const outputFile = `${outputDir}/modified-config.yaml`;
|
||||
logger.debug(`Modified config saving to ${outputFile}`);
|
||||
|
||||
await Bun.write(outputFile, stringify(parsedConfig));
|
||||
return outputFile;
|
||||
};
|
||||
|
|
@ -1,7 +1,16 @@
|
|||
#!/usr/bin/env bun
|
||||
import { Command } from "@commander-js/extra-typings";
|
||||
import { Command, InvalidArgumentError } from "@commander-js/extra-typings";
|
||||
import { launch, launchPreActionHook } from "./handlers";
|
||||
|
||||
// Function to parse integer
|
||||
function parseIntValue(value: string): number {
|
||||
const parsedValue = Number.parseInt(value, 10);
|
||||
if (Number.isNaN(parsedValue)) {
|
||||
throw new InvalidArgumentError("Not a number.");
|
||||
}
|
||||
return parsedValue;
|
||||
}
|
||||
|
||||
// So far we only have the launch command
|
||||
// we can expand this to more commands in the future
|
||||
const program = new Command()
|
||||
|
|
@ -14,13 +23,16 @@ const program = new Command()
|
|||
.option("-u, --update-validator-set", "Update validator set")
|
||||
.option("--no-update-validator-set", "Skip update validator set")
|
||||
.option("-b, --blockscout", "Enable Blockscout")
|
||||
.option("--slot-time <number>", "Set slot time in seconds", parseIntValue)
|
||||
.option("--datahaven", "Enable Datahaven network to be launched")
|
||||
.option("--kurtosis-network-args <value>", "CustomKurtosis network args")
|
||||
.option(
|
||||
"--datahaven-bin-path <value>",
|
||||
"Path to the datahaven binary",
|
||||
"../operator/target/release/datahaven-node"
|
||||
)
|
||||
.option("-v, --verified", "Verify smart contracts with Blockscout")
|
||||
.option("--always-clean", "Always clean Kurtosis", false)
|
||||
.option("-q, --skip-cleaning", "Skip cleaning Kurtosis")
|
||||
.option("-r, --relayer", "Enable Relayer")
|
||||
.option(
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
# Ethereum Private Testnet Configuration
|
||||
# This configuration file is used with the ethPandaOps Ethereum Package for Kurtosis
|
||||
# (https://github.com/ethpandaops/ethereum-package)
|
||||
#
|
||||
# Purpose: Sets up a minimal Ethereum testnet with multiple execution and consensus clients
|
||||
# Usage: kurtosis run github.com/ethpandaops/ethereum-package --args-file configs/kurtosis/minimal-with-bs.yaml
|
||||
|
||||
participants:
|
||||
- el_type: reth
|
||||
cl_type: lighthouse
|
||||
count: 2
|
||||
|
||||
additional_services:
|
||||
- dora
|
||||
- blockscout
|
||||
|
||||
network_params:
|
||||
preset: minimal
|
||||
num_validator_keys_per_node: 128
|
||||
prefunded_accounts: '{"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": {"balance": "10ETH"}, "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc": {"balance": "10ETH"}, "0x70997970C51812dc3A010C7d01b50e0d17dc79C8": {"balance": "10ETH"},"0x976ea74026e726554db657fa54763abd0c3a0aa9": {"balance": "10ETH"}}'
|
||||
|
|
@ -1,10 +1,3 @@
|
|||
# Ethereum Private Testnet Configuration
|
||||
# This configuration file is used with the ethPandaOps Ethereum Package for Kurtosis
|
||||
# (https://github.com/ethpandaops/ethereum-package)
|
||||
#
|
||||
# Purpose: Sets up a minimal Ethereum testnet with multiple execution and consensus clients
|
||||
# Usage: kurtosis run github.com/ethpandaops/ethereum-package --args-file configs/kurtosis/minimal.yaml
|
||||
|
||||
participants:
|
||||
- el_type: reth
|
||||
cl_type: lighthouse
|
||||
|
|
@ -14,6 +7,25 @@ additional_services:
|
|||
- dora
|
||||
|
||||
network_params:
|
||||
preset: minimal
|
||||
preset: mainnet
|
||||
seconds_per_slot: 2
|
||||
num_validator_keys_per_node: 128
|
||||
prefunded_accounts: '{"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": {"balance": "10ETH"}, "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc": {"balance": "10ETH"}, "0x70997970C51812dc3A010C7d01b50e0d17dc79C8": {"balance": "10ETH"},"0x976ea74026e726554db657fa54763abd0c3a0aa9": {"balance": "10ETH"}}'
|
||||
prefunded_accounts: '{
|
||||
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": {"balance": "10ETH"},
|
||||
"0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc": {"balance": "10ETH"},
|
||||
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8": {"balance": "10ETH"},
|
||||
"0x976ea74026e726554db657fa54763abd0c3a0aa9": {"balance": "10ETH"}
|
||||
}'
|
||||
# Preloaded with DataHavenTest contract
|
||||
additional_preloaded_contracts: |
|
||||
{
|
||||
"0x1111111111111111111111111111111111111111": {
|
||||
"balance": "0ETH",
|
||||
"code": "0x608060405234801561000f575f5ffd5b506004361061004a575f3560e01c80632baeceb71461004e5780638381f58a146100585780638da5cb5b14610073578063d826f88f1461009e575b5f5ffd5b6100566100a6565b005b6100605f5481565b6040519081526020015b60405180910390f35b600154610086906001600160a01b031681565b6040516001600160a01b03909116815260200161006a565b61005661010d565b5f5f54116100fb5760405162461bcd60e51b815260206004820152601f60248201527f4e756d6265722073686f756c642062652067726561746572207468616e20300060448201526064015b60405180910390fd5b60015f54610109919061016d565b5f55565b6001546001600160a01b031633146101675760405162461bcd60e51b815260206004820152601760248201527f4f6e6c792063616c6c61626c65206279206f776e65722100000000000000000060448201526064016100f2565b600a5f55565b8181038181111561018c57634e487b7160e01b5f52601160045260245ffd5b9291505056fea2646970667358221220ac5899491afd834afd223fd632497d1c0c7593961eda22f04c58db4b504999cf64736f6c634300081c0033",
|
||||
"storage": {
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000000000000000000000000000000000000000000a",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266"
|
||||
},
|
||||
"nonce": "1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@
|
|||
"build:docker:relayer": "bun -e \"import build from './scripts/snowbridge-relayer.ts'; build()\"",
|
||||
"generate:wagmi": "wagmi generate",
|
||||
"generate:snowbridge-cfgs": "bun -e \"import {generateSnowbridgeConfigs} from './scripts/gen-snowbridge-cfgs.ts'; await generateSnowbridgeConfigs()\"",
|
||||
"start:e2e:verified": "bun cli --verified --blockscout --deploy-contracts",
|
||||
"start:e2e:minimal": "bun cli",
|
||||
"start:e2e:ci": "bun cli -d --setup-validators --update-validator-set --fund-validators",
|
||||
"start:e2e:verified": "bun cli --verified --blockscout --deploy-contracts --setup-validators --update-validator-set --fund-validators --slot-time 1",
|
||||
"start:e2e:ci": "bun cli -d --setup-validators --update-validator-set --fund-validators --always-clean --slot-time 2",
|
||||
"start:e2e:minrelayer": "bun cli --relayer -d --no-setup-validators --no-update-validator-set --no-fund-validators --datahaven",
|
||||
"stop:e2e": "pkill datahaven ; kurtosis enclave stop datahaven-ethereum && kurtosis clean && kurtosis engine stop && docker container prune -f",
|
||||
"stop:e2e:verified": "bun stop:e2e",
|
||||
|
|
@ -48,6 +47,7 @@
|
|||
"tiny-invariant": "^1.3.3",
|
||||
"viem": "^2.28.0",
|
||||
"wagmi": "^2.15.0",
|
||||
"yaml": "^2.7.1",
|
||||
"zod": "^3.24.3"
|
||||
},
|
||||
"trustedDependencies": [
|
||||
|
|
|
|||
|
|
@ -34,15 +34,9 @@ The first step involves setting up the testing infrastructure using Kurtosis, a
|
|||
```bash
|
||||
# Start the E2E CLI environment with the minimal configuration
|
||||
bun cli
|
||||
# Alternative
|
||||
bun start:e2e:minimal
|
||||
|
||||
# Start the E2E CLI environment with Blockscout and verified contracts
|
||||
bun start:e2e:verified
|
||||
|
||||
# Behind the scenes both commands run:
|
||||
bun run scripts/launch-kurtosis.ts
|
||||
# And then continue setting up the environment with the next steps.
|
||||
```
|
||||
|
||||
## 2. Ethereum-side Contract Deployment
|
||||
|
|
@ -85,12 +79,14 @@ In this phase, we register validators as operators in EigenLayer and sync the va
|
|||
### Steps
|
||||
|
||||
1. **Fund Validators with Tokens**
|
||||
|
||||
- Use `fund-validators.ts` script to fund validators with necessary tokens
|
||||
- Transfers 5% of creator's tokens to each validator
|
||||
- Transfers 1% of creator's ETH to validators with zero balance
|
||||
- Ensures validators have sufficient funds for operations
|
||||
|
||||
2. **Register Operators in EigenLayer**
|
||||
|
||||
- Use `setup-validators.ts` script to register validators
|
||||
- Deposits stake and registers for operator sets
|
||||
- Sets up the validator set in the Ethereum side
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { $ } from "bun";
|
||||
import invariant from "tiny-invariant";
|
||||
import { confirmWithTimeout, logger, printHeader } from "utils";
|
||||
import { confirmWithTimeout, logger, printHeader, runShellCommandWithLogger } from "utils";
|
||||
|
||||
interface DeployContractsOptions {
|
||||
rpcUrl: string;
|
||||
|
|
@ -63,12 +63,7 @@ export const deployContracts = async (options: DeployContractsOptions): Promise<
|
|||
}
|
||||
logger.debug(buildStdout.toString());
|
||||
|
||||
// Get forge path
|
||||
const { stdout: forgePath } = await $`which forge`.quiet();
|
||||
const forgeExecutable = forgePath.toString().trim();
|
||||
|
||||
// Prepare deployment command
|
||||
let deployCommand = `${forgeExecutable} script script/deploy/DeployLocal.s.sol --rpc-url ${rpcUrl} --color never -vv --no-rpc-rate-limit --non-interactive --broadcast`;
|
||||
let deployCommand = `forge script script/deploy/DeployLocal.s.sol --rpc-url ${rpcUrl} --color never -vv --no-rpc-rate-limit --non-interactive --broadcast`;
|
||||
|
||||
if (verified && blockscoutBackendUrl) {
|
||||
deployCommand += ` --verify --verifier blockscout --verifier-url ${blockscoutBackendUrl}/api/ --delay 0`;
|
||||
|
|
@ -77,14 +72,8 @@ export const deployContracts = async (options: DeployContractsOptions): Promise<
|
|||
|
||||
logger.info("⏳ Deploying contracts (this might take a few minutes)...");
|
||||
|
||||
const { exitCode: deployExitCode, stderr: deployStderr } = await $`sh -c ${deployCommand}`
|
||||
.cwd("../contracts")
|
||||
.nothrow();
|
||||
|
||||
if (deployExitCode !== 0) {
|
||||
logger.error(deployStderr.toString());
|
||||
throw Error("❌ Contracts have failed to deploy properly.");
|
||||
}
|
||||
// Using custom shell command to improve logging with forge's stdoutput
|
||||
await runShellCommandWithLogger(deployCommand, { cwd: "../contracts" });
|
||||
|
||||
logger.success("Contracts deployed successfully");
|
||||
return true;
|
||||
|
|
@ -121,7 +110,6 @@ if (import.meta.main) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check required parameters
|
||||
if (!options.rpcUrl) {
|
||||
console.error("Error: --rpc-url parameter is required");
|
||||
process.exit(1);
|
||||
|
|
@ -132,7 +120,6 @@ if (import.meta.main) {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
// Run deployment
|
||||
deployContracts({
|
||||
rpcUrl: options.rpcUrl,
|
||||
verified: options.verified,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
// Setup of validators for DataHaven
|
||||
import { $ } from "bun";
|
||||
import invariant from "tiny-invariant";
|
||||
import { confirmWithTimeout, logger, printHeader } from "../utils/index";
|
||||
import { confirmWithTimeout, logger, printHeader, runShellCommandWithLogger } from "../utils/index";
|
||||
|
||||
interface SetupValidatorsOptions {
|
||||
rpcUrl: string;
|
||||
|
|
@ -113,16 +112,11 @@ export const setupValidators = async (options: SetupValidatorsOptions): Promise<
|
|||
const validators = config.validators;
|
||||
logger.info(`Found ${validators.length} validators to register`);
|
||||
|
||||
// Get forge path
|
||||
const { stdout: forgePath } = await $`which forge`.quiet();
|
||||
const forgeExecutable = forgePath.toString().trim();
|
||||
|
||||
// Iterate through all validators to register them
|
||||
for (let i = 0; i < validators.length; i++) {
|
||||
const validator = validators[i];
|
||||
logger.info(`Setting up validator ${i} (${validator.publicKey})`);
|
||||
|
||||
// Setting up the environment variables directly
|
||||
const env = {
|
||||
...process.env,
|
||||
NETWORK: networkName,
|
||||
|
|
@ -133,20 +127,10 @@ export const setupValidators = async (options: SetupValidatorsOptions): Promise<
|
|||
};
|
||||
|
||||
// Prepare command to register validator
|
||||
const signupCommand = `${forgeExecutable} script script/transact/SignUpValidator.s.sol --rpc-url ${rpcUrl} --broadcast --no-rpc-rate-limit --non-interactive`;
|
||||
|
||||
const signupCommand = `forge script script/transact/SignUpValidator.s.sol --rpc-url ${rpcUrl} --broadcast --no-rpc-rate-limit --non-interactive`;
|
||||
logger.debug(`Running command: ${signupCommand}`);
|
||||
|
||||
// Run with environment variables directly passed to the environment
|
||||
const { exitCode, stderr } = await $`sh -c ${signupCommand}`
|
||||
.cwd("../contracts")
|
||||
.env(env)
|
||||
.nothrow();
|
||||
|
||||
if (exitCode !== 0) {
|
||||
logger.error(`Failed to register validator ${validator.publicKey}: ${stderr.toString()}`);
|
||||
continue;
|
||||
}
|
||||
await runShellCommandWithLogger(signupCommand, { env, cwd: "../contracts" });
|
||||
|
||||
logger.success(`Successfully registered validator ${validator.publicKey}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
export * from "./blockscout";
|
||||
export * from "./constants";
|
||||
export * from "./contracts";
|
||||
export * from "./docker";
|
||||
export * from "./input";
|
||||
export * from "./logger";
|
||||
export * from "./rpc";
|
||||
export * from "./viem";
|
||||
export * from "./kurtosis";
|
||||
export * from "./logger";
|
||||
export * from "./parser";
|
||||
export * from "./contracts";
|
||||
export * from "./rpc";
|
||||
export * from "./shell";
|
||||
export * from "./viem";
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export const timeoutConfirm = createPrompt<boolean, TimeoutConfirmConfig>((cfg,
|
|||
clearInterval(id);
|
||||
done(cfg.default ?? true);
|
||||
}
|
||||
}, 200);
|
||||
}, 500);
|
||||
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
|
@ -64,7 +64,7 @@ export const timeoutConfirm = createPrompt<boolean, TimeoutConfirmConfig>((cfg,
|
|||
|
||||
const main = `${prefix} ${theme.style.message(cfg.message, status)} \
|
||||
${defaultBadge} ${input}`;
|
||||
const border = chalk.yellow("=".repeat(cfg.message.length + 40));
|
||||
const border = chalk.yellow("=".repeat(80));
|
||||
const hint = theme.style.help(
|
||||
chalk.magenta(
|
||||
`⏱ Will default to ${chalk.bold(cfg.default ? "YES" : "NO")} in ${chalk.bold((left / 1000).toFixed(0))}s`
|
||||
|
|
@ -77,12 +77,14 @@ ${main}
|
|||
${border}`;
|
||||
});
|
||||
|
||||
export const confirmWithTimeout = (
|
||||
export const confirmWithTimeout = async (
|
||||
question: string,
|
||||
defaultValue: boolean,
|
||||
timeoutSeconds: number
|
||||
) =>
|
||||
timeoutConfirm({
|
||||
) => {
|
||||
await Bun.sleep(50); //debounce
|
||||
|
||||
return timeoutConfirm({
|
||||
message: question,
|
||||
default: defaultValue,
|
||||
timeoutMs: timeoutSeconds * 1000,
|
||||
|
|
@ -93,3 +95,4 @@ export const confirmWithTimeout = (
|
|||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
57
test/utils/shell.ts
Normal file
57
test/utils/shell.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { existsSync } from "node:fs";
|
||||
import { spawn } from "bun";
|
||||
import { logger } from "./logger";
|
||||
|
||||
export const runShellCommandWithLogger = async (
|
||||
command: string,
|
||||
options?: { cwd?: string; env?: object }
|
||||
) => {
|
||||
const { cwd = ".", env = {} } = options || {};
|
||||
|
||||
try {
|
||||
if (!existsSync(cwd)) {
|
||||
logger.error("❌ CWD does not exist:", cwd);
|
||||
throw new Error("❌ CWD does not exist");
|
||||
}
|
||||
|
||||
const proc = spawn(["sh", "-c", command], {
|
||||
cwd,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
env: {
|
||||
...process.env,
|
||||
...env
|
||||
}
|
||||
});
|
||||
|
||||
const stdoutReader = proc.stdout.getReader();
|
||||
const stderrReader = proc.stderr.getReader();
|
||||
|
||||
const readStream = async (
|
||||
reader: typeof stdoutReader | typeof stderrReader,
|
||||
streamName: string
|
||||
) => {
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
const text = new TextDecoder().decode(value);
|
||||
const trimmedText = text.trim();
|
||||
logger.info(trimmedText.includes("\n") ? `\n${trimmedText}` : trimmedText);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(`Error reading from ${streamName} stream:`, err);
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
};
|
||||
|
||||
Promise.all([readStream(stdoutReader, "stdout"), readStream(stderrReader, "stderr")]);
|
||||
|
||||
await proc.exited;
|
||||
} catch (err) {
|
||||
logger.error("❌ Error running shell command:", command, "in", cwd);
|
||||
logger.error(err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue