From 647e64fee3fa09ac648a9ad052869c16d0ce5b66 Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Mon, 17 Jun 2024 18:10:51 +0200 Subject: [PATCH] Remove rpc-client crate (#218) --- .github/workflows/bump-version.yml | 15 - .github/workflows/publish.yml | 74 - .github/workflows/required_status_check.yml | 18 + .github/workflows/rust.yml | 101 +- .github/workflows/soroban-rpc.yml | 25 +- Cargo.lock | 1295 +---------------- Cargo.toml | 20 +- Makefile | 46 +- cmd/crates/stellar-rpc-client/Cargo.toml | 41 - cmd/crates/stellar-rpc-client/README.md | 3 - .../src/fixtures/event_response.json | 39 - cmd/crates/stellar-rpc-client/src/lib.rs | 1272 ---------------- cmd/crates/stellar-rpc-client/src/log.rs | 2 - .../src/log/diagnostic_events.rs | 11 - cmd/crates/stellar-rpc-client/src/txn.rs | 509 ------- cmd/soroban-rpc/lib/preflight/Cargo.toml | 6 +- cmd/soroban-rpc/lib/preflight/src/lib.rs | 124 +- 17 files changed, 179 insertions(+), 3422 deletions(-) delete mode 100644 .github/workflows/bump-version.yml delete mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/required_status_check.yml delete mode 100644 cmd/crates/stellar-rpc-client/Cargo.toml delete mode 100644 cmd/crates/stellar-rpc-client/README.md delete mode 100644 cmd/crates/stellar-rpc-client/src/fixtures/event_response.json delete mode 100644 cmd/crates/stellar-rpc-client/src/lib.rs delete mode 100644 cmd/crates/stellar-rpc-client/src/log.rs delete mode 100644 cmd/crates/stellar-rpc-client/src/log/diagnostic_events.rs delete mode 100644 cmd/crates/stellar-rpc-client/src/txn.rs diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml deleted file mode 100644 index a79b1912..00000000 --- a/.github/workflows/bump-version.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Bump Version - -on: - workflow_dispatch: - inputs: - version: - description: 'Version to bump to' - required: true - -jobs: - - bump-version: - uses: stellar/actions/.github/workflows/rust-bump-version.yml@main - with: - version: ${{ inputs.version }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index bdaa4c9d..00000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Publish - -on: - release: - types: [published] - -defaults: - run: - shell: bash - -jobs: - - publish: - uses: stellar/actions/.github/workflows/rust-publish.yml@main - secrets: - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - - upload: - needs: publish - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-20.04 # Use 20.04 to get an older version of glibc for increased compat - target: x86_64-unknown-linux-gnu - - os: ubuntu-20.04 # Use 20.04 to get an older version of glibc for increased compat - target: aarch64-unknown-linux-gnu - - os: macos-latest - target: x86_64-apple-darwin - - os: macos-latest - target: aarch64-apple-darwin - - os: windows-latest - target: x86_64-pc-windows-msvc - ext: .exe - runs-on: ${{ matrix.os }} - env: - VERSION: '${{ github.event.release.name }}' - NAME: 'stellar-rpc-client-${{ github.event.release.name }}-${{ matrix.target }}' - steps: - - uses: actions/checkout@v3 - - run: rustup update - - run: rustup target add ${{ matrix.target }} - - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: sudo apt-get update && sudo apt-get -y install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu - - name: Package - run: cargo package --no-verify - - name: Build - env: - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - run: | - cd target/package - tar xvfz stellar-rpc-client-$VERSION.crate - cd stellar-rpc-client-$VERSION - cargo build --target-dir=../.. --release --target ${{ matrix.target }} - - name: Compress - run: | - cd target/${{ matrix.target }}/release - tar czvf $NAME.tar.gz soroban${{ matrix.ext }} - - uses: actions/upload-artifact@v3 - with: - name: ${{ env.NAME }} - path: 'target/${{ matrix.target }}/release/${{ env.NAME }}.tar.gz' - - name: Upload - uses: actions/github-script@v6 - with: - script: | - const fs = require('fs'); - await github.rest.repos.uploadReleaseAsset({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: ${{ github.event.release.id }}, - name: '${{ env.NAME }}.tar.gz', - data: fs.readFileSync('target/${{ matrix.target }}/release/${{ env.NAME }}.tar.gz'), - }); diff --git a/.github/workflows/required_status_check.yml b/.github/workflows/required_status_check.yml new file mode 100644 index 00000000..dd92d47f --- /dev/null +++ b/.github/workflows/required_status_check.yml @@ -0,0 +1,18 @@ +# workaround to simplify terraform management of required status checks, +# see https://github.com/orgs/community/discussions/12377 +name: "Required status check" +on: + pull_request: + +jobs: + complete: + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - uses: int128/wait-for-workflows-action@v1 + with: + filter-workflow-names: | + Dependency sanity checker* + Linters* + Rust* + Soroban RPC* diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 54499d14..87c5afe8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,106 +10,11 @@ defaults: shell: bash jobs: - - complete: - if: always() - needs: [ fmt, build-and-test, publish-dry-run ] - runs-on: ubuntu-latest - steps: - - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') - run: exit 1 - - fmt: + test: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - run: rustup update - - run: cargo fmt --all --check - - build-and-test: - strategy: - fail-fast: false - matrix: - rust: [ msrv, latest ] - include: - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - - os: macos-latest - target: x86_64-apple-darwin - - os: macos-latest - target: aarch64-apple-darwin - - os: windows-latest-8-cores - target: x86_64-pc-windows-msvc - runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - uses: stellar/actions/rust-cache@main - - name: Use the minimum supported Rust version - if: matrix.rust == 'msrv' - run: | - msrv="$(cargo metadata --format-version 1 --no-deps | jq -r '.packages | map(.rust_version) | map(values) | min')" - rustup override set $msrv - rustup component add clippy --toolchain $msrv - - name: Error on warnings and clippy checks - # Only error on warnings and checks for the msrv, because new versions of - # Rust will frequently add new warnings and checks. - if: matrix.rust == 'msrv' - run: echo RUSTFLAGS='-Dwarnings -Dclippy::all -Dclippy::pedantic' >> $GITHUB_ENV - run: rustup update - - run: cargo version - - run: rustup target add ${{ matrix.target }} - - run: rustup target add wasm32-unknown-unknown - - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: sudo apt-get update && sudo apt-get -y install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu - - run: cargo clippy --all-targets --target ${{ matrix.target }} - - run: make build-test - - if: startsWith(matrix.target, 'x86_64') - # specify directories explicitly to avoid building the preflight library (otherwise it will fail with missing symbols) - run: | - for I in cmd/crates/* ; do - cargo test --target ${{ matrix.target }} --manifest-path $I/Cargo.toml - done - - publish-dry-run: - if: github.event_name == 'push' || startsWith(github.head_ref, 'release/') - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - cargo-hack-feature-options: --feature-powerset - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - cargo-hack-feature-options: --feature-powerset - - os: macos-latest - target: x86_64-apple-darwin - cargo-hack-feature-options: --feature-powerset - - os: macos-latest - target: aarch64-apple-darwin - cargo-hack-feature-options: --feature-powerset - # Windows builds notes: - # - # The different features that need testing are split over unique - # isolated builds for Windows, because there's a bug in Cargo [1] that - # causes builds of wasm-opt [2] to fail when run one after the other and - # attempting to clean up artifacts in between. The bug has been fixed, - # but will not make it into a stable release of Cargo until ~August - # 2023. - # - # [1]: https://github.com/rust-lang/cargo/pull/11442 - # [2]: https://github.com/brson/wasm-opt-rs/issues/116 - - os: windows-latest-8-cores - target: x86_64-pc-windows-msvc - cargo-hack-feature-options: '' - - os: windows-latest-8-cores - target: x86_64-pc-windows-msvc - cargo-hack-feature-options: --features opt --ignore-unknown-features - uses: stellar/actions/.github/workflows/rust-publish-dry-run-v2.yml@main - with: - crates: stellar-rpc-client - runs-on: ${{ matrix.os }} - target: ${{ matrix.target }} - cargo-hack-feature-options: ${{ matrix.cargo-hack-feature-options }} + - run: make rust-check + - run: make rust-test diff --git a/.github/workflows/soroban-rpc.yml b/.github/workflows/soroban-rpc.yml index fabc9835..b2a962cc 100644 --- a/.github/workflows/soroban-rpc.yml +++ b/.github/workflows/soroban-rpc.yml @@ -28,11 +28,7 @@ jobs: - uses: ./.github/actions/setup-go with: go-version: ${{ matrix.go }} - - name: Build soroban contract fixtures - run: | - rustup update - rustup target add wasm32-unknown-unknown - make build-test-wasms + - run: rustup update - run: make build-libpreflight - run: go test -race -cover -timeout 25m -v ./cmd/soroban-rpc/... @@ -65,10 +61,6 @@ jobs: with: go-version: 1.22 - - run: | - rustup target add ${{ matrix.rust_target }} - rustup update - # On windows, make sure we have the same compiler (linker) used by rust. # This is important since the symbols names won't match otherwise. - if: matrix.os == 'windows-latest' @@ -86,6 +78,10 @@ jobs: sudo apt-get install -y gcc-10-aarch64-linux-gnu echo 'CC=aarch64-linux-gnu-gcc-10' >> $GITHUB_ENV + - run: | + rustup target add ${{ matrix.rust_target }} + rustup update + - name: Build libpreflight run: make build-libpreflight env: @@ -138,14 +134,6 @@ jobs: - uses: stellar/actions/rust-cache@main - - name: Build soroban contract fixtures - shell: bash - run: | - rustup update - rustup target add wasm32-unknown-unknown - make build_rust - make build-test-wasms - - name: Install Captive Core shell: bash run: | @@ -187,11 +175,12 @@ jobs: echo "Docker Compose Version:" docker-compose version + - run: rustup update + - name: Build libpreflight shell: bash run: make build-libpreflight - name: Run Soroban RPC Integration Tests run: | - make install_rust go test -race -timeout 60m -v ./cmd/soroban-rpc/internal/test/... diff --git a/Cargo.lock b/Cargo.lock index e83dcef1..0b4a4cc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,69 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - [[package]] name = "anyhow" version = "1.0.79" @@ -95,17 +32,6 @@ dependencies = [ "derive_arbitrary", ] -[[package]] -name = "async-trait" -version = "0.1.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -145,12 +71,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.0" @@ -163,21 +83,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "block-buffer" version = "0.10.4" @@ -193,12 +98,6 @@ version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - [[package]] name = "cc" version = "1.0.83" @@ -214,87 +113,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "windows-targets 0.52.0", -] - -[[package]] -name = "clap" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim 0.11.1", -] - -[[package]] -name = "clap_derive" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - [[package]] name = "cpufeatures" version = "0.2.12" @@ -365,41 +189,6 @@ dependencies = [ "syn", ] -[[package]] -name = "darling" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" -dependencies = [ - "darling_core", - "quote", - "syn", -] - [[package]] name = "der" version = "0.7.8" @@ -410,16 +199,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - [[package]] name = "derive_arbitrary" version = "1.3.2" @@ -544,61 +323,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-core", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -640,51 +364,17 @@ dependencies = [ "subtle", ] -[[package]] -name = "h2" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.11", - "indexmap 2.2.3", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] [[package]] name = "hex-literal" @@ -702,333 +392,118 @@ dependencies = [ ] [[package]] -name = "http" -version = "0.2.11" +name = "indexmap" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ - "bytes", - "fnv", - "itoa", + "equivalent", + "hashbrown", ] [[package]] -name = "http" -version = "1.0.0" +name = "indexmap-nostd" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" -dependencies = [ - "bytes", - "fnv", - "itoa", -] +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] -name = "http-body" -version = "0.4.6" +name = "itertools" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ - "bytes", - "http 0.2.11", - "pin-project-lite", + "either", ] [[package]] -name = "httparse" -version = "1.8.0" +name = "itoa" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] -name = "httpdate" -version = "1.0.3" +name = "js-sys" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +dependencies = [ + "wasm-bindgen", +] [[package]] -name = "hyper" -version = "0.14.28" +name = "k256" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http 0.2.11", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", ] [[package]] -name = "hyper-rustls" -version = "0.24.2" +name = "keccak" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ - "futures-util", - "http 0.2.11", - "hyper", - "log", - "rustls", - "rustls-native-certs", - "tokio", - "tokio-rustls", + "cpufeatures", ] [[package]] -name = "iana-time-zone" -version = "0.1.60" +name = "libc" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "libm" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] -name = "ident_case" -version = "1.0.1" +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] -name = "idna" -version = "0.5.0" +name = "miniz_oxide" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "adler", ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "num-derive" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "indexmap" -version = "2.2.3" +name = "num-integer" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "equivalent", - "hashbrown 0.14.3", - "serde", -] - -[[package]] -name = "indexmap-nostd" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "js-sys" -version = "0.3.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonrpsee-core" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" -dependencies = [ - "anyhow", - "async-trait", - "beef", - "futures-util", - "hyper", - "jsonrpsee-types", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "jsonrpsee-http-client" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" -dependencies = [ - "async-trait", - "hyper", - "hyper-rustls", - "jsonrpsee-core", - "jsonrpsee-types", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "k256" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", + "autocfg", + "num-traits", ] [[package]] @@ -1055,12 +530,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - [[package]] name = "p256" version = "0.13.2" @@ -1079,44 +548,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "pkcs8" version = "0.10.2" @@ -1133,12 +564,6 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1225,20 +650,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.48.0", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1254,74 +665,12 @@ dependencies = [ "semver", ] -[[package]] -name = "rustls" -version = "0.21.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "ryu" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sec1" version = "0.7.2" @@ -1335,29 +684,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "1.0.21" @@ -1373,17 +699,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-aux" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86348501c129f3ad50c2f4635a01971f76974cd8a3f335988a0f1581c082765" -dependencies = [ - "chrono", - "serde", - "serde_json", -] - [[package]] name = "serde_derive" version = "1.0.192" @@ -1406,36 +721,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" -dependencies = [ - "base64 0.21.7", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.2.3", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "sha2" version = "0.10.8" @@ -1467,38 +752,19 @@ dependencies = [ "rand_core", ] -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - [[package]] name = "smallvec" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "soroban-builtin-sdk-macros" version = "21.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "084aab008009e712c445a9d7eab837a86559a6c2341f30bc4f33e9b258947688" dependencies = [ - "itertools 0.11.0", + "itertools", "proc-macro2", "quote", "syn", @@ -1561,7 +827,7 @@ version = "21.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06d0581e3aba14892ee0ce63788f3d3e5d9eb1ab18906a9b7c66d77dae9e9fea" dependencies = [ - "itertools 0.11.0", + "itertools", "proc-macro2", "quote", "serde", @@ -1618,29 +884,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stellar-rpc-client" -version = "21.3.0" -dependencies = [ - "clap", - "hex", - "http 1.0.0", - "itertools 0.10.5", - "jsonrpsee-core", - "jsonrpsee-http-client", - "serde", - "serde-aux", - "serde_json", - "sha2", - "stellar-strkey", - "stellar-xdr", - "termcolor", - "termcolor_output", - "thiserror", - "tokio", - "tracing", -] - [[package]] name = "stellar-strkey" version = "0.0.8" @@ -1663,23 +906,9 @@ dependencies = [ "crate-git-revision", "escape-bytes", "hex", - "serde", - "serde_with", "stellar-strkey", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "subtle" version = "2.5.0" @@ -1697,31 +926,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "termcolor_output" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0363afbf20990ea53a69c03b71800480aaf90e8f49f6fd5385ecc302062895ff" -dependencies = [ - "termcolor", - "termcolor_output_impl", -] - -[[package]] -name = "termcolor_output_impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34dde0bb841eb3762b42bdff8db11bbdbc0a3bd7b32012955f5ce1d081f86c1" - [[package]] name = "thiserror" version = "1.0.55" @@ -1742,221 +946,24 @@ dependencies = [ "syn", ] -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2041,7 +1048,7 @@ version = "0.116.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" dependencies = [ - "indexmap 2.2.3", + "indexmap", "semver", ] @@ -2054,178 +1061,6 @@ dependencies = [ "indexmap-nostd", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 5d5f7004..5a1c0e24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,10 @@ [workspace] resolver = "2" members = [ - "cmd/crates/stellar-rpc-client", "cmd/soroban-rpc/lib/preflight", ] -default-members = ["cmd/crates/stellar-rpc-client"] [workspace.package] -version = "21.3.0" rust-version = "1.74.0" [workspace.dependencies.soroban-env-host] @@ -16,23 +13,12 @@ version = "=21.1.0" [workspace.dependencies.soroban-simulation] version = "=21.1.0" -[workspace.dependencies.stellar-xdr] -version = "=21.1.0" - [workspace.dependencies] base64 = "0.22.0" sha2 = "0.10.7" - -[profile.test-wasms] -inherits = "release" -opt-level = "z" -overflow-checks = true -debug = 0 -strip = "symbols" -debug-assertions = true -panic = "abort" -codegen-units = 1 -lto = true +libc = "0.2.147" +anyhow = "1.0.75" +rand = { version = "0.8.5", features = [] } [profile.release-with-panic-unwind] inherits = 'release' diff --git a/Makefile b/Makefile index 278f6713..c9e37996 100644 --- a/Makefile +++ b/Makefile @@ -40,63 +40,53 @@ CARGO_BUILD_TARGET ?= $(shell rustc -vV | sed -n 's|host: ||p') Cargo.lock: Cargo.toml cargo update --workspace -install_rust: Cargo.lock - #cargo install soroban-cli --version 20.2.0 - #cargo install --path ./cmd/crates/soroban-test/tests/fixtures/hello --root ./target --debug --quiet - -install: install_rust build-libpreflight +install: build-libpreflight go install -ldflags="${GOLDFLAGS}" ${MACOS_MIN_VER} ./... -build_rust: Cargo.lock - cargo build -build_go: build-libpreflight +build: build-libpreflight go build -ldflags="${GOLDFLAGS}" ${MACOS_MIN_VER} ./... -build: build_rust build_go - build-libpreflight: Cargo.lock cd cmd/soroban-rpc/lib/preflight && cargo build --target $(CARGO_BUILD_TARGET) --profile release-with-panic-unwind -build-test-wasms: Cargo.lock - #cargo build --package 'test_*' --profile test-wasms --target wasm32-unknown-unknown - -build-test: build-test-wasms install_rust - -test: build-test - cargo test - -e2e-test: - cargo test --test it -- --ignored +check: rust-check go-check -check: Cargo.lock - cargo clippy --all-targets +rust-check: Cargo.lock + cargo fmt --all --check + cargo clippy watch: cargo watch --clear --watch-when-idle --shell '$(MAKE)' fmt: + go fmt ./... cargo fmt --all +rust-test: + cargo test + +go-test: build-libpreflight + go test ./... + +test: go-test rust-test + clean: cargo clean go clean ./... -publish: - cargo workspaces publish --all --force '*' --from-git --yes - # the build-soroban-rpc build target is an optimized build target used by # https://github.com/stellar/pipelines/stellar-horizon/Jenkinsfile-soroban-rpc-package-builder # as part of the package building. build-soroban-rpc: build-libpreflight go build -ldflags="${GOLDFLAGS}" ${MACOS_MIN_VER} -o soroban-rpc -trimpath -v ./cmd/soroban-rpc -lint-changes: +go-check-changes: golangci-lint run ./... --new-from-rev $$(git rev-parse HEAD) -lint: +go-check: golangci-lint run ./... # PHONY lists all the targets that aren't file names, so that make would skip the timestamp based check. -.PHONY: publish clean fmt watch check e2e-test test build-test-wasms install build build-soroban-rpc build-libpreflight lint lint-changes +.PHONY: clean fmt watch test rust-test go-test check rust-check go-check install build build-soroban-rpc build-libpreflight lint lint-changes diff --git a/cmd/crates/stellar-rpc-client/Cargo.toml b/cmd/crates/stellar-rpc-client/Cargo.toml deleted file mode 100644 index 05b40b98..00000000 --- a/cmd/crates/stellar-rpc-client/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "stellar-rpc-client" -description = "Stellar RPC client for rust" -homepage = "https://github.com/stellar/soroban-rpc" -repository = "https://github.com/stellar/soroban-rpc" -authors = ["Stellar Development Foundation "] -license = "Apache-2.0" -readme = "README.md" -version.workspace = true -edition = "2021" -rust-version.workspace = true -autobins = false - - -[lib] -crate-type = ["rlib"] - - -[dependencies] -stellar-strkey = "0.0.8" -stellar-xdr = { workspace = true, features = ["curr", "std", "serde", "base64"] } - - -termcolor = "1.1.3" -termcolor_output = "1.0.1" -clap = { version = "4.1.8", features = ["derive"] } -serde_json = "1.0.82" -serde-aux = "4.1.2" -itertools = "0.10.0" -hex = "0.4.3" -thiserror = "1.0.46" -serde = "1.0.82" -tokio = "1.28.1" -sha2 = "0.10.7" -tracing = "0.1.40" - -# networking -jsonrpsee-http-client = "0.20.1" -jsonrpsee-core = "0.20.1" -http = "1.0.0" - diff --git a/cmd/crates/stellar-rpc-client/README.md b/cmd/crates/stellar-rpc-client/README.md deleted file mode 100644 index a0bf1502..00000000 --- a/cmd/crates/stellar-rpc-client/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# stellar-rpc-client - -A rust client for communicating with the soroban-rpc. diff --git a/cmd/crates/stellar-rpc-client/src/fixtures/event_response.json b/cmd/crates/stellar-rpc-client/src/fixtures/event_response.json deleted file mode 100644 index 6f520fdf..00000000 --- a/cmd/crates/stellar-rpc-client/src/fixtures/event_response.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "events": [{ - "eventType": "system", - "ledger": "43601283", - "ledgerClosedAt": "2022-11-16T16:10:41Z", - "contractId": "CDR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OO5Z", - "id": "0164090849041387521-0000000003", - "pagingToken": "164090849041387521-3", - "topic": [ - "AAAABQAAAAh0cmFuc2Zlcg==", - "AAAAAQB6Mcc=" - ], - "value": "AAAABQAAAApHaWJNb255UGxzAAA=" - }, { - "eventType": "contract", - "ledger": "43601284", - "ledgerClosedAt": "2022-11-16T16:10:41Z", - "contractId": "CDR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OO5Z", - "id": "0164090849041387521-0000000003", - "pagingToken": "164090849041387521-3", - "topic": [ - "AAAABQAAAAh0cmFuc2Zlcg==", - "AAAAAQB6Mcc=" - ], - "value": "AAAABQAAAApHaWJNb255UGxzAAA=" - }, { - "eventType": "system", - "ledger": "43601285", - "ledgerClosedAt": "2022-11-16T16:10:41Z", - "contractId": "CCR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OTE2", - "id": "0164090849041387521-0000000003", - "pagingToken": "164090849041387521-3", - "topic": [ - "AAAABQAAAAh0cmFuc2Zlcg==", - "AAAAAQB6Mcc=" - ], - "value": "AAAABQAAAApHaWJNb255UGxzAAA=" - }] -} \ No newline at end of file diff --git a/cmd/crates/stellar-rpc-client/src/lib.rs b/cmd/crates/stellar-rpc-client/src/lib.rs deleted file mode 100644 index 799e5a00..00000000 --- a/cmd/crates/stellar-rpc-client/src/lib.rs +++ /dev/null @@ -1,1272 +0,0 @@ -use http::{uri::Authority, Uri}; -use itertools::Itertools; -use jsonrpsee_core::params::ObjectParams; -use jsonrpsee_core::{self, client::ClientT}; -use jsonrpsee_http_client::{HeaderMap, HttpClient, HttpClientBuilder}; -use serde_aux::prelude::{ - deserialize_default_from_null, deserialize_number_from_string, - deserialize_option_number_from_string, -}; -use stellar_xdr::curr::{ - self as xdr, AccountEntry, AccountId, ContractDataEntry, ContractEventType, DiagnosticEvent, - Error as XdrError, Hash, LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount, - Limited, Limits, PublicKey, ReadXdr, ScContractInstance, SorobanAuthorizationEntry, - SorobanResources, SorobanTransactionData, Transaction, TransactionEnvelope, TransactionMeta, - TransactionMetaV3, TransactionResult, TransactionV1Envelope, Uint256, VecM, WriteXdr, -}; - -use std::{ - f64::consts::E, - fmt::Display, - str::FromStr, - sync::Arc, - time::{Duration, Instant}, -}; - -use termcolor::{Color, ColorChoice, StandardStream, WriteColor}; -use termcolor_output::colored; -use tokio::time::sleep; - -pub mod log; -mod txn; - -pub use txn::Assembled; - -const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION"); -pub(crate) const DEFAULT_TRANSACTION_FEES: u32 = 100; - -pub type LogEvents = fn( - footprint: &LedgerFootprint, - auth: &[VecM], - events: &[DiagnosticEvent], -) -> (); - -pub type LogResources = fn(resources: &SorobanResources) -> (); - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error(transparent)] - InvalidAddress(#[from] stellar_strkey::DecodeError), - #[error("invalid response from server")] - InvalidResponse, - #[error("provided network passphrase {expected:?} does not match the server: {server:?}")] - InvalidNetworkPassphrase { expected: String, server: String }, - #[error("xdr processing error: {0}")] - Xdr(#[from] XdrError), - #[error("invalid rpc url: {0}")] - InvalidRpcUrl(http::uri::InvalidUri), - #[error("invalid rpc url: {0}")] - InvalidRpcUrlFromUriParts(http::uri::InvalidUriParts), - #[error("invalid friendbot url: {0}")] - InvalidUrl(String), - #[error(transparent)] - JsonRpc(#[from] jsonrpsee_core::Error), - #[error("json decoding error: {0}")] - Serde(#[from] serde_json::Error), - #[error("transaction failed: {0}")] - TransactionFailed(String), - #[error("transaction submission failed: {0}")] - TransactionSubmissionFailed(String), - #[error("expected transaction status: {0}")] - UnexpectedTransactionStatus(String), - #[error("transaction submission timeout")] - TransactionSubmissionTimeout, - #[error("transaction simulation failed: {0}")] - TransactionSimulationFailed(String), - #[error("{0} not found: {1}")] - NotFound(String, String), - #[error("Missing result in successful response")] - MissingResult, - #[error("Failed to read Error response from server")] - MissingError, - #[error("Missing signing key for account {address}")] - MissingSignerForAddress { address: String }, - #[error("cursor is not valid")] - InvalidCursor, - #[error("unexpected ({length}) simulate transaction result length")] - UnexpectedSimulateTransactionResultSize { length: usize }, - #[error("unexpected ({count}) number of operations")] - UnexpectedOperationCount { count: usize }, - #[error("Transaction contains unsupported operation type")] - UnsupportedOperationType, - #[error("unexpected contract code data type: {0:?}")] - UnexpectedContractCodeDataType(LedgerEntryData), - #[error("unexpected contract instance type: {0:?}")] - UnexpectedContractInstance(xdr::ScVal), - #[error("unexpected contract code got token")] - UnexpectedToken(ContractDataEntry), - #[error("Fee was too large {0}")] - LargeFee(u64), - #[error("Cannot authorize raw transactions")] - CannotAuthorizeRawTransaction, - - #[error("Missing result for tnx")] - MissingOp, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct SendTransactionResponse { - pub hash: String, - pub status: String, - #[serde( - rename = "errorResultXdr", - skip_serializing_if = "Option::is_none", - default - )] - pub error_result_xdr: Option, - #[serde(rename = "latestLedger")] - pub latest_ledger: u32, - #[serde( - rename = "latestLedgerCloseTime", - deserialize_with = "deserialize_number_from_string" - )] - pub latest_ledger_close_time: u32, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct GetTransactionResponseRaw { - pub status: String, - #[serde( - rename = "envelopeXdr", - skip_serializing_if = "Option::is_none", - default - )] - pub envelope_xdr: Option, - #[serde(rename = "resultXdr", skip_serializing_if = "Option::is_none", default)] - pub result_xdr: Option, - #[serde( - rename = "resultMetaXdr", - skip_serializing_if = "Option::is_none", - default - )] - pub result_meta_xdr: Option, - // TODO: add ledger info and application order -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct GetTransactionResponse { - pub status: String, - pub envelope: Option, - pub result: Option, - pub result_meta: Option, -} - -impl TryInto for GetTransactionResponseRaw { - type Error = xdr::Error; - - fn try_into(self) -> Result { - Ok(GetTransactionResponse { - status: self.status, - envelope: self - .envelope_xdr - .map(|v| ReadXdr::from_xdr_base64(v, Limits::none())) - .transpose()?, - result: self - .result_xdr - .map(|v| ReadXdr::from_xdr_base64(v, Limits::none())) - .transpose()?, - result_meta: self - .result_meta_xdr - .map(|v| ReadXdr::from_xdr_base64(v, Limits::none())) - .transpose()?, - }) - } -} - -impl GetTransactionResponse { - /// - /// # Errors - pub fn return_value(&self) -> Result { - if let Some(xdr::TransactionMeta::V3(xdr::TransactionMetaV3 { - soroban_meta: Some(xdr::SorobanTransactionMeta { return_value, .. }), - .. - })) = &self.result_meta - { - Ok(return_value.clone()) - } else { - Err(Error::MissingOp) - } - } - - /// - /// # Errors - pub fn events(&self) -> Result, Error> { - self.result_meta - .as_ref() - .map(extract_events) - .ok_or(Error::MissingOp) - } - - /// - /// # Errors - pub fn contract_events(&self) -> Result, Error> { - Ok(self - .events()? - .into_iter() - .filter(|e| matches!(e.event.type_, ContractEventType::Contract)) - .collect::>()) - } -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct LedgerEntryResult { - pub key: String, - pub xdr: String, - #[serde(rename = "lastModifiedLedgerSeq")] - pub last_modified_ledger: u32, - #[serde( - rename = "liveUntilLedgerSeq", - skip_serializing_if = "Option::is_none", - deserialize_with = "deserialize_option_number_from_string", - default - )] - pub live_until_ledger_seq_ledger_seq: Option, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct GetLedgerEntriesResponse { - pub entries: Option>, - #[serde(rename = "latestLedger")] - pub latest_ledger: i64, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct GetNetworkResponse { - #[serde( - rename = "friendbotUrl", - skip_serializing_if = "Option::is_none", - default - )] - pub friendbot_url: Option, - pub passphrase: String, - #[serde(rename = "protocolVersion")] - pub protocol_version: u32, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct GetLatestLedgerResponse { - pub id: String, - #[serde(rename = "protocolVersion")] - pub protocol_version: u32, - pub sequence: u32, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Default, Clone)] -pub struct Cost { - #[serde( - rename = "cpuInsns", - deserialize_with = "deserialize_number_from_string" - )] - pub cpu_insns: u64, - #[serde( - rename = "memBytes", - deserialize_with = "deserialize_number_from_string" - )] - pub mem_bytes: u64, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct SimulateHostFunctionResultRaw { - #[serde(deserialize_with = "deserialize_default_from_null")] - pub auth: Vec, - pub xdr: String, -} - -#[derive(Debug, Clone)] -pub struct SimulateHostFunctionResult { - pub auth: Vec, - pub xdr: xdr::ScVal, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, PartialEq)] -#[serde(tag = "type")] -pub enum LedgerEntryChange { - #[serde(rename = "created")] - Created { key: String, after: String }, - #[serde(rename = "deleted")] - Deleted { key: String, before: String }, - #[serde(rename = "updated")] - Updated { - key: String, - before: String, - after: String, - }, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Default, Clone)] -pub struct SimulateTransactionResponse { - #[serde( - rename = "minResourceFee", - deserialize_with = "deserialize_number_from_string", - default - )] - pub min_resource_fee: u64, - #[serde(default)] - pub cost: Cost, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub results: Vec, - #[serde(rename = "transactionData", default)] - pub transaction_data: String, - #[serde( - deserialize_with = "deserialize_default_from_null", - skip_serializing_if = "Vec::is_empty", - default - )] - pub events: Vec, - #[serde( - rename = "restorePreamble", - skip_serializing_if = "Option::is_none", - default - )] - pub restore_preamble: Option, - #[serde( - rename = "stateChanges", - skip_serializing_if = "Option::is_none", - default - )] - pub state_changes: Option>, - #[serde(rename = "latestLedger")] - pub latest_ledger: u32, - #[serde(skip_serializing_if = "Option::is_none", default)] - pub error: Option, -} - -impl SimulateTransactionResponse { - /// - /// # Errors - pub fn results(&self) -> Result, Error> { - self.results - .iter() - .map(|r| { - Ok(SimulateHostFunctionResult { - auth: r - .auth - .iter() - .map(|a| { - Ok(SorobanAuthorizationEntry::from_xdr_base64( - a, - Limits::none(), - )?) - }) - .collect::>()?, - xdr: xdr::ScVal::from_xdr_base64(&r.xdr, Limits::none())?, - }) - }) - .collect() - } - - /// - /// # Errors - pub fn events(&self) -> Result, Error> { - self.events - .iter() - .map(|e| Ok(DiagnosticEvent::from_xdr_base64(e, Limits::none())?)) - .collect() - } - - /// - /// # Errors - pub fn transaction_data(&self) -> Result { - Ok(SorobanTransactionData::from_xdr_base64( - &self.transaction_data, - Limits::none(), - )?) - } -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Default, Clone)] -pub struct RestorePreamble { - #[serde(rename = "transactionData")] - pub transaction_data: String, - #[serde( - rename = "minResourceFee", - deserialize_with = "deserialize_number_from_string" - )] - pub min_resource_fee: u64, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct GetEventsResponse { - #[serde(deserialize_with = "deserialize_default_from_null")] - pub events: Vec, - #[serde(rename = "latestLedger")] - pub latest_ledger: u32, -} - -// Determines whether or not a particular filter matches a topic based on the -// same semantics as the RPC server: -// -// - for an exact segment match, the filter is a base64-encoded ScVal -// - for a wildcard, single-segment match, the string "*" matches exactly one -// segment -// -// The expectation is that a `filter` is a comma-separated list of segments that -// has previously been validated, and `topic` is the list of segments applicable -// for this event. -// -// [API -// Reference](https://docs.google.com/document/d/1TZUDgo_3zPz7TiPMMHVW_mtogjLyPL0plvzGMsxSz6A/edit#bookmark=id.35t97rnag3tx) -// [Code -// Reference](https://github.com/stellar/soroban-tools/blob/bac1be79e8c2590c9c35ad8a0168aab0ae2b4171/cmd/soroban-rpc/internal/methods/get_events.go#L182-L203) -#[must_use] -pub fn does_topic_match(topic: &[String], filter: &[String]) -> bool { - filter.len() == topic.len() - && filter - .iter() - .enumerate() - .all(|(i, s)| *s == "*" || topic[i] == *s) -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub struct Event { - #[serde(rename = "type")] - pub event_type: String, - - pub ledger: u32, - #[serde(rename = "ledgerClosedAt")] - pub ledger_closed_at: String, - - pub id: String, - #[serde(rename = "pagingToken")] - pub paging_token: String, - - #[serde(rename = "contractId")] - pub contract_id: String, - pub topic: Vec, - pub value: String, -} - -impl Display for Event { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!( - f, - "Event {} [{}]:", - self.paging_token, - self.event_type.to_ascii_uppercase() - )?; - writeln!( - f, - " Ledger: {} (closed at {})", - self.ledger, self.ledger_closed_at - )?; - writeln!(f, " Contract: {}", self.contract_id)?; - writeln!(f, " Topics:")?; - for topic in &self.topic { - let scval = - xdr::ScVal::from_xdr_base64(topic, Limits::none()).map_err(|_| std::fmt::Error)?; - writeln!(f, " {scval:?}")?; - } - let scval = xdr::ScVal::from_xdr_base64(&self.value, Limits::none()) - .map_err(|_| std::fmt::Error)?; - writeln!(f, " Value: {scval:?}") - } -} - -impl Event { - /// - /// # Errors - pub fn parse_cursor(&self) -> Result<(u64, i32), Error> { - parse_cursor(&self.id) - } - /// - /// # Errors - pub fn pretty_print(&self) -> Result<(), Box> { - let mut stdout = StandardStream::stdout(ColorChoice::Auto); - if !stdout.supports_color() { - println!("{self}"); - return Ok(()); - } - - let color = match self.event_type.as_str() { - "system" => Color::Yellow, - _ => Color::Blue, - }; - colored!( - stdout, - "{}Event{} {}{}{} [{}{}{}{}]:\n", - bold!(true), - bold!(false), - fg!(Some(Color::Green)), - self.paging_token, - reset!(), - bold!(true), - fg!(Some(color)), - self.event_type.to_ascii_uppercase(), - reset!(), - )?; - - colored!( - stdout, - " Ledger: {}{}{} (closed at {}{}{})\n", - fg!(Some(Color::Green)), - self.ledger, - reset!(), - fg!(Some(Color::Green)), - self.ledger_closed_at, - reset!(), - )?; - - colored!( - stdout, - " Contract: {}{}{}\n", - fg!(Some(Color::Green)), - self.contract_id, - reset!(), - )?; - - colored!(stdout, " Topics:\n")?; - for topic in &self.topic { - let scval = xdr::ScVal::from_xdr_base64(topic, Limits::none())?; - colored!( - stdout, - " {}{:?}{}\n", - fg!(Some(Color::Green)), - scval, - reset!(), - )?; - } - - let scval = xdr::ScVal::from_xdr_base64(&self.value, Limits::none())?; - colored!( - stdout, - " Value: {}{:?}{}\n", - fg!(Some(Color::Green)), - scval, - reset!(), - )?; - - Ok(()) - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, clap::ValueEnum)] -pub enum EventType { - All, - Contract, - System, -} - -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub enum EventStart { - Ledger(u32), - Cursor(String), -} - -#[derive(Debug, Clone)] -pub struct FullLedgerEntry { - pub key: LedgerKey, - pub val: LedgerEntryData, - pub last_modified_ledger: u32, - pub live_until_ledger_seq: u32, -} - -#[derive(Debug, Clone)] -pub struct FullLedgerEntries { - pub entries: Vec, - pub latest_ledger: i64, -} - -#[derive(Debug, Clone)] -pub struct Client { - base_url: Arc, - timeout_in_secs: u64, - http_client: Arc, -} - -impl Client { - /// - /// # Errors - pub fn new(base_url: &str) -> Result { - // Add the port to the base URL if there is no port explicitly included - // in the URL and the scheme allows us to infer a default port. - // Jsonrpsee requires a port to always be present even if one can be - // inferred. This may change: https://github.com/paritytech/jsonrpsee/issues/1048. - let uri = base_url.parse::().map_err(Error::InvalidRpcUrl)?; - let mut parts = uri.into_parts(); - if let (Some(scheme), Some(authority)) = (&parts.scheme, &parts.authority) { - if authority.port().is_none() { - let port = match scheme.as_str() { - "http" => Some(80), - "https" => Some(443), - _ => None, - }; - if let Some(port) = port { - let host = authority.host(); - parts.authority = Some( - Authority::from_str(&format!("{host}:{port}")) - .map_err(Error::InvalidRpcUrl)?, - ); - } - } - } - let uri = Uri::from_parts(parts).map_err(Error::InvalidRpcUrlFromUriParts)?; - let base_url = Arc::from(uri.to_string()); - tracing::trace!(?uri); - let mut headers = HeaderMap::new(); - headers.insert("X-Client-Name", unsafe { - "soroban-cli".parse().unwrap_unchecked() - }); - let version = VERSION.unwrap_or("devel"); - headers.insert("X-Client-Version", unsafe { - version.parse().unwrap_unchecked() - }); - let http_client = Arc::new( - HttpClientBuilder::default() - .set_headers(headers) - .build(&base_url)?, - ); - Ok(Self { - base_url, - timeout_in_secs: 30, - http_client, - }) - } - - #[must_use] - pub fn base_url(&self) -> &str { - &self.base_url - } - - /// Create a new client with a timeout in seconds - /// # Errors - pub fn new_with_timeout(base_url: &str, timeout: u64) -> Result { - let mut client = Self::new(base_url)?; - client.timeout_in_secs = timeout; - Ok(client) - } - - #[must_use] - pub fn client(&self) -> &HttpClient { - &self.http_client - } - - /// - /// # Errors - pub async fn friendbot_url(&self) -> Result { - let network = self.get_network().await?; - tracing::trace!("{network:#?}"); - network.friendbot_url.ok_or_else(|| { - Error::NotFound( - "Friendbot".to_string(), - "Friendbot is not available on this network".to_string(), - ) - }) - } - /// - /// # Errors - pub async fn verify_network_passphrase(&self, expected: Option<&str>) -> Result { - let server = self.get_network().await?.passphrase; - if let Some(expected) = expected { - if expected != server { - return Err(Error::InvalidNetworkPassphrase { - expected: expected.to_string(), - server, - }); - } - } - Ok(server) - } - - /// - /// # Errors - pub async fn get_network(&self) -> Result { - tracing::trace!("Getting network"); - Ok(self - .client() - .request("getNetwork", ObjectParams::new()) - .await?) - } - - /// - /// # Errors - pub async fn get_latest_ledger(&self) -> Result { - tracing::trace!("Getting latest ledger"); - Ok(self - .client() - .request("getLatestLedger", ObjectParams::new()) - .await?) - } - - /// - /// # Errors - pub async fn get_account(&self, address: &str) -> Result { - tracing::trace!("Getting address {}", address); - let key = LedgerKey::Account(LedgerKeyAccount { - account_id: AccountId(PublicKey::PublicKeyTypeEd25519(Uint256( - stellar_strkey::ed25519::PublicKey::from_string(address)?.0, - ))), - }); - let keys = Vec::from([key]); - let response = self.get_ledger_entries(&keys).await?; - let entries = response.entries.unwrap_or_default(); - if entries.is_empty() { - return Err(Error::NotFound("Account".to_string(), address.to_owned())); - } - let ledger_entry = &entries[0]; - let mut read = Limited::new(ledger_entry.xdr.as_bytes(), Limits::none()); - if let LedgerEntryData::Account(entry) = LedgerEntryData::read_xdr_base64(&mut read)? { - tracing::trace!(account=?entry); - Ok(entry) - } else { - Err(Error::InvalidResponse) - } - } - - /// Send a transaction to the network and get back the hash of the transaction. - /// # Errors - pub async fn send_transaction(&self, tx: &TransactionEnvelope) -> Result { - tracing::trace!("Sending:\n{tx:#?}"); - let mut oparams = ObjectParams::new(); - oparams.insert("transaction", tx.to_xdr_base64(Limits::none())?)?; - let SendTransactionResponse { - hash, - error_result_xdr, - status, - .. - } = self - .client() - .request("sendTransaction", oparams) - .await - .map_err(|err| { - Error::TransactionSubmissionFailed(format!("No status yet:\n {err:#?}")) - })?; - - if status == "ERROR" { - let error = error_result_xdr - .ok_or(Error::MissingError) - .and_then(|x| { - TransactionResult::read_xdr_base64(&mut Limited::new( - x.as_bytes(), - Limits::none(), - )) - .map_err(|_| Error::InvalidResponse) - }) - .map(|r| r.result); - tracing::error!("TXN {hash} failed:\n {error:#?}"); - return Err(Error::TransactionSubmissionFailed(format!("{:#?}", error?))); - } - Ok(Hash::from_str(&hash)?) - } - - /// - /// # Errors - pub async fn send_transaction_polling( - &self, - tx: &TransactionEnvelope, - ) -> Result { - let hash = self.send_transaction(tx).await?; - self.get_transaction_polling(&hash, None).await - } - - /// - /// # Errors - pub async fn simulate_and_assemble_transaction( - &self, - tx: &Transaction, - ) -> Result { - let sim_res = self - .simulate_transaction_envelope(&TransactionEnvelope::Tx(TransactionV1Envelope { - tx: tx.clone(), - signatures: VecM::default(), - })) - .await?; - match sim_res.error { - None => Ok(Assembled::new(tx, sim_res)?), - Some(e) => { - log::diagnostic_events(&sim_res.events, tracing::Level::ERROR); - Err(Error::TransactionSimulationFailed(e)) - } - } - } - - /// - /// # Errors - pub async fn simulate_transaction_envelope( - &self, - tx: &TransactionEnvelope, - ) -> Result { - tracing::trace!("Simulating:\n{tx:#?}"); - let base64_tx = tx.to_xdr_base64(Limits::none())?; - let mut oparams = ObjectParams::new(); - oparams.insert("transaction", base64_tx)?; - let sim_res = self - .client() - .request("simulateTransaction", oparams) - .await?; - tracing::trace!("Simulation response:\n {sim_res:#?}"); - Ok(sim_res) - } - - /// - /// # Errors - pub async fn get_transaction(&self, tx_id: &Hash) -> Result { - let mut oparams = ObjectParams::new(); - oparams.insert("hash", tx_id)?; - let resp: GetTransactionResponseRaw = - self.client().request("getTransaction", oparams).await?; - Ok(resp.try_into()?) - } - - /// Poll the transaction status. Can provide a timeout in seconds, otherwise uses the default timeout. - /// - /// It uses exponential backoff with a base of 1 second and a maximum of 30 seconds. - /// - /// # Errors - /// - `Error::TransactionSubmissionTimeout` if the transaction status is not found within the timeout - /// - `Error::TransactionSubmissionFailed` if the transaction status is "FAILED" - /// - `Error::UnexpectedTransactionStatus` if the transaction status is not one of "SUCCESS", "FAILED", or ``NOT_FOUND`` - /// - `json_rpsee` Errors - pub async fn get_transaction_polling( - &self, - tx_id: &Hash, - timeout_s: Option, - ) -> Result { - // Poll the transaction status - let start = Instant::now(); - let timeout = timeout_s.unwrap_or(Duration::from_secs(self.timeout_in_secs)); - // see https://tsapps.nist.gov/publication/get_pdf.cfm?pub_id=50731 - // Is optimimal exponent for expontial backoff - let exponential_backoff: f64 = 1.0 / (1.0 - E.powf(-1.0)); - let mut sleep_time = Duration::from_secs(1); - loop { - let response = self.get_transaction(tx_id).await?; - match response.status.as_str() { - "SUCCESS" => { - // TODO: the caller should probably be printing this - tracing::trace!("{response:#?}"); - return Ok(response); - } - "FAILED" => { - tracing::error!("{response:#?}"); - // TODO: provide a more elaborate error - return Err(Error::TransactionSubmissionFailed(format!( - "{:#?}", - response.result - ))); - } - "NOT_FOUND" => (), - _ => { - return Err(Error::UnexpectedTransactionStatus(response.status)); - } - }; - if start.elapsed() > timeout { - return Err(Error::TransactionSubmissionTimeout); - } - sleep(sleep_time).await; - sleep_time = Duration::from_secs_f64(sleep_time.as_secs_f64() * exponential_backoff); - } - } - - /// - /// # Errors - pub async fn get_ledger_entries( - &self, - keys: &[LedgerKey], - ) -> Result { - let mut base64_keys: Vec = vec![]; - for k in keys { - let base64_result = k.to_xdr_base64(Limits::none()); - if base64_result.is_err() { - return Err(Error::Xdr(XdrError::Invalid)); - } - base64_keys.push(k.to_xdr_base64(Limits::none())?); - } - let mut oparams = ObjectParams::new(); - oparams.insert("keys", base64_keys)?; - Ok(self.client().request("getLedgerEntries", oparams).await?) - } - - /// - /// # Errors - pub async fn get_full_ledger_entries( - &self, - ledger_keys: &[LedgerKey], - ) -> Result { - let keys = ledger_keys - .iter() - .filter(|key| !matches!(key, LedgerKey::Ttl(_))) - .map(Clone::clone) - .collect::>(); - tracing::trace!("keys: {keys:#?}"); - let GetLedgerEntriesResponse { - entries, - latest_ledger, - } = self.get_ledger_entries(&keys).await?; - tracing::trace!("raw: {entries:#?}"); - let entries = entries - .unwrap_or_default() - .iter() - .map( - |LedgerEntryResult { - key, - xdr, - last_modified_ledger, - live_until_ledger_seq_ledger_seq, - }| { - Ok(FullLedgerEntry { - key: LedgerKey::from_xdr_base64(key, Limits::none())?, - val: LedgerEntryData::from_xdr_base64(xdr, Limits::none())?, - live_until_ledger_seq: live_until_ledger_seq_ledger_seq.unwrap_or_default(), - last_modified_ledger: *last_modified_ledger, - }) - }, - ) - .collect::, Error>>()?; - tracing::trace!("parsed: {entries:#?}"); - Ok(FullLedgerEntries { - entries, - latest_ledger, - }) - } - /// - /// # Errors - pub async fn get_events( - &self, - start: EventStart, - event_type: Option, - contract_ids: &[String], - topics: &[String], - limit: Option, - ) -> Result { - let mut filters = serde_json::Map::new(); - - event_type - .and_then(|t| match t { - EventType::All => None, // all is the default, so avoid incl. the param - EventType::Contract => Some("contract"), - EventType::System => Some("system"), - }) - .map(|t| filters.insert("type".to_string(), t.into())); - - filters.insert("topics".to_string(), topics.into()); - filters.insert("contractIds".to_string(), contract_ids.into()); - - let mut pagination = serde_json::Map::new(); - if let Some(limit) = limit { - pagination.insert("limit".to_string(), limit.into()); - } - - let mut oparams = ObjectParams::new(); - match start { - EventStart::Ledger(l) => oparams.insert("startLedger", l)?, - EventStart::Cursor(c) => { - pagination.insert("cursor".to_string(), c.into()); - } - }; - oparams.insert("filters", vec![filters])?; - oparams.insert("pagination", pagination)?; - - Ok(self.client().request("getEvents", oparams).await?) - } - - /// - /// # Errors - pub async fn get_contract_data( - &self, - contract_id: &[u8; 32], - ) -> Result { - // Get the contract from the network - let contract_key = LedgerKey::ContractData(xdr::LedgerKeyContractData { - contract: xdr::ScAddress::Contract(xdr::Hash(*contract_id)), - key: xdr::ScVal::LedgerKeyContractInstance, - durability: xdr::ContractDataDurability::Persistent, - }); - let contract_ref = self.get_ledger_entries(&[contract_key]).await?; - let entries = contract_ref.entries.unwrap_or_default(); - if entries.is_empty() { - let contract_address = stellar_strkey::Contract(*contract_id).to_string(); - return Err(Error::NotFound("Contract".to_string(), contract_address)); - } - let contract_ref_entry = &entries[0]; - match LedgerEntryData::from_xdr_base64(&contract_ref_entry.xdr, Limits::none())? { - LedgerEntryData::ContractData(contract_data) => Ok(contract_data), - scval => Err(Error::UnexpectedContractCodeDataType(scval)), - } - } - - /// - /// # Errors - pub async fn get_remote_wasm(&self, contract_id: &[u8; 32]) -> Result, Error> { - match self.get_contract_data(contract_id).await? { - xdr::ContractDataEntry { - val: - xdr::ScVal::ContractInstance(xdr::ScContractInstance { - executable: xdr::ContractExecutable::Wasm(hash), - .. - }), - .. - } => self.get_remote_wasm_from_hash(hash).await, - scval => Err(Error::UnexpectedToken(scval)), - } - } - - /// - /// # Errors - pub async fn get_remote_wasm_from_hash(&self, hash: xdr::Hash) -> Result, Error> { - let code_key = LedgerKey::ContractCode(xdr::LedgerKeyContractCode { hash: hash.clone() }); - let contract_data = self.get_ledger_entries(&[code_key]).await?; - let entries = contract_data.entries.unwrap_or_default(); - if entries.is_empty() { - return Err(Error::NotFound( - "Contract Code".to_string(), - hex::encode(hash), - )); - } - let contract_data_entry = &entries[0]; - match LedgerEntryData::from_xdr_base64(&contract_data_entry.xdr, Limits::none())? { - LedgerEntryData::ContractCode(xdr::ContractCodeEntry { code, .. }) => Ok(code.into()), - scval => Err(Error::UnexpectedContractCodeDataType(scval)), - } - } - - /// Get the contract instance from the network. Could be normal contract or native Stellar Asset Contract (SAC) - /// - /// # Errors - /// - Could fail to find contract or have a network error - pub async fn get_contract_instance( - &self, - contract_id: &[u8; 32], - ) -> Result { - let contract_data = self.get_contract_data(contract_id).await?; - match contract_data.val { - xdr::ScVal::ContractInstance(instance) => Ok(instance), - scval => Err(Error::UnexpectedContractInstance(scval)), - } - } -} - -fn extract_events(tx_meta: &TransactionMeta) -> Vec { - match tx_meta { - TransactionMeta::V3(TransactionMetaV3 { - soroban_meta: Some(meta), - .. - }) => { - // NOTE: we assume there can only be one operation, since we only send one - if meta.diagnostic_events.len() == 1 { - meta.diagnostic_events.clone().into() - } else if meta.events.len() == 1 { - meta.events - .iter() - .map(|e| DiagnosticEvent { - in_successful_contract_call: true, - event: e.clone(), - }) - .collect() - } else { - Vec::new() - } - } - _ => Vec::new(), - } -} - -pub(crate) fn parse_cursor(c: &str) -> Result<(u64, i32), Error> { - let (toid_part, event_index) = c.split('-').collect_tuple().ok_or(Error::InvalidCursor)?; - let toid_part: u64 = toid_part.parse().map_err(|_| Error::InvalidCursor)?; - let start_index: i32 = event_index.parse().map_err(|_| Error::InvalidCursor)?; - Ok((toid_part, start_index)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn simulation_transaction_response_parsing() { - let s = r#"{ - "minResourceFee": "100000000", - "cost": { "cpuInsns": "1000", "memBytes": "1000" }, - "transactionData": "", - "latestLedger": 1234, - "stateChanges": [{ - "type": "created", - "key": "AAAAAAAAAABuaCbVXZ2DlXWarV6UxwbW3GNJgpn3ASChIFp5bxSIWg==", - "before": null, - "after": "AAAAZAAAAAAAAAAAbmgm1V2dg5V1mq1elMcG1txjSYKZ9wEgoSBaeW8UiFoAAAAAAAAAZAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - }] - }"#; - - let resp: SimulateTransactionResponse = serde_json::from_str(s).unwrap(); - assert_eq!( - resp.state_changes.unwrap()[0], - LedgerEntryChange::Created { key: "AAAAAAAAAABuaCbVXZ2DlXWarV6UxwbW3GNJgpn3ASChIFp5bxSIWg==".to_string(), after: "AAAAZAAAAAAAAAAAbmgm1V2dg5V1mq1elMcG1txjSYKZ9wEgoSBaeW8UiFoAAAAAAAAAZAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_string() }, - ); - assert_eq!(resp.min_resource_fee, 100_000_000); - } - - #[test] - fn simulation_transaction_response_parsing_mostly_empty() { - let s = r#"{ - "latestLedger": 1234 - }"#; - - let resp: SimulateTransactionResponse = serde_json::from_str(s).unwrap(); - assert_eq!(resp.latest_ledger, 1_234); - } - - #[test] - fn test_rpc_url_default_ports() { - // Default ports are added. - let client = Client::new("http://example.com").unwrap(); - assert_eq!(client.base_url(), "http://example.com:80/"); - let client = Client::new("https://example.com").unwrap(); - assert_eq!(client.base_url(), "https://example.com:443/"); - - // Ports are not added when already present. - let client = Client::new("http://example.com:8080").unwrap(); - assert_eq!(client.base_url(), "http://example.com:8080/"); - let client = Client::new("https://example.com:8080").unwrap(); - assert_eq!(client.base_url(), "https://example.com:8080/"); - - // Paths are not modified. - let client = Client::new("http://example.com/a/b/c").unwrap(); - assert_eq!(client.base_url(), "http://example.com:80/a/b/c"); - let client = Client::new("https://example.com/a/b/c").unwrap(); - assert_eq!(client.base_url(), "https://example.com:443/a/b/c"); - let client = Client::new("http://example.com/a/b/c/").unwrap(); - assert_eq!(client.base_url(), "http://example.com:80/a/b/c/"); - let client = Client::new("https://example.com/a/b/c/").unwrap(); - assert_eq!(client.base_url(), "https://example.com:443/a/b/c/"); - let client = Client::new("http://example.com/a/b:80/c/").unwrap(); - assert_eq!(client.base_url(), "http://example.com:80/a/b:80/c/"); - let client = Client::new("https://example.com/a/b:80/c/").unwrap(); - assert_eq!(client.base_url(), "https://example.com:443/a/b:80/c/"); - } - - #[test] - // Taken from [RPC server - // tests](https://github.com/stellar/soroban-tools/blob/main/cmd/soroban-rpc/internal/methods/get_events_test.go#L21). - fn test_does_topic_match() { - struct TestCase<'a> { - name: &'a str, - filter: Vec<&'a str>, - includes: Vec>, - excludes: Vec>, - } - - let xfer = "AAAABQAAAAh0cmFuc2Zlcg=="; - let number = "AAAAAQB6Mcc="; - let star = "*"; - - for tc in vec![ - // No filter means match nothing. - TestCase { - name: "", - filter: vec![], - includes: vec![], - excludes: vec![vec![xfer]], - }, - // "*" should match "transfer/" but not "transfer/transfer" or - // "transfer/amount", because * is specified as a SINGLE segment - // wildcard. - TestCase { - name: "*", - filter: vec![star], - includes: vec![vec![xfer]], - excludes: vec![vec![xfer, xfer], vec![xfer, number]], - }, - // "*/transfer" should match anything preceding "transfer", but - // nothing that isn't exactly two segments long. - TestCase { - name: "*/transfer", - filter: vec![star, xfer], - includes: vec![vec![number, xfer], vec![xfer, xfer]], - excludes: vec![ - vec![number], - vec![number, number], - vec![number, xfer, number], - vec![xfer], - vec![xfer, number], - vec![xfer, xfer, xfer], - ], - }, - // The inverse case of before: "transfer/*" should match any single - // segment after a segment that is exactly "transfer", but no - // additional segments. - TestCase { - name: "transfer/*", - filter: vec![xfer, star], - includes: vec![vec![xfer, number], vec![xfer, xfer]], - excludes: vec![ - vec![number], - vec![number, number], - vec![number, xfer, number], - vec![xfer], - vec![number, xfer], - vec![xfer, xfer, xfer], - ], - }, - // Here, we extend to exactly two wild segments after transfer. - TestCase { - name: "transfer/*/*", - filter: vec![xfer, star, star], - includes: vec![vec![xfer, number, number], vec![xfer, xfer, xfer]], - excludes: vec![ - vec![number], - vec![number, number], - vec![number, xfer], - vec![number, xfer, number, number], - vec![xfer], - vec![xfer, xfer, xfer, xfer], - ], - }, - // Here, we ensure wildcards can be in the middle of a filter: only - // exact matches happen on the ends, while the middle can be - // anything. - TestCase { - name: "transfer/*/number", - filter: vec![xfer, star, number], - includes: vec![vec![xfer, number, number], vec![xfer, xfer, number]], - excludes: vec![ - vec![number], - vec![number, number], - vec![number, number, number], - vec![number, xfer, number], - vec![xfer], - vec![number, xfer], - vec![xfer, xfer, xfer], - vec![xfer, number, xfer], - ], - }, - ] { - for topic in tc.includes { - assert!( - does_topic_match( - &topic - .iter() - .map(std::string::ToString::to_string) - .collect::>(), - &tc.filter - .iter() - .map(std::string::ToString::to_string) - .collect::>() - ), - "test: {}, topic ({:?}) should be matched by filter ({:?})", - tc.name, - topic, - tc.filter - ); - } - - for topic in tc.excludes { - assert!( - !does_topic_match( - // make deep copies of the vecs - &topic - .iter() - .map(std::string::ToString::to_string) - .collect::>(), - &tc.filter - .iter() - .map(std::string::ToString::to_string) - .collect::>() - ), - "test: {}, topic ({:?}) should NOT be matched by filter ({:?})", - tc.name, - topic, - tc.filter - ); - } - } - } -} diff --git a/cmd/crates/stellar-rpc-client/src/log.rs b/cmd/crates/stellar-rpc-client/src/log.rs deleted file mode 100644 index 36126814..00000000 --- a/cmd/crates/stellar-rpc-client/src/log.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod diagnostic_events; -pub use diagnostic_events::*; diff --git a/cmd/crates/stellar-rpc-client/src/log/diagnostic_events.rs b/cmd/crates/stellar-rpc-client/src/log/diagnostic_events.rs deleted file mode 100644 index 68af67a4..00000000 --- a/cmd/crates/stellar-rpc-client/src/log/diagnostic_events.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub fn diagnostic_events(events: &[impl std::fmt::Debug], level: tracing::Level) { - for (i, event) in events.iter().enumerate() { - if level == tracing::Level::TRACE { - tracing::trace!("{i}: {event:#?}"); - } else if level == tracing::Level::INFO { - tracing::info!("{i}: {event:#?}"); - } else if level == tracing::Level::ERROR { - tracing::error!("{i}: {event:#?}"); - } - } -} diff --git a/cmd/crates/stellar-rpc-client/src/txn.rs b/cmd/crates/stellar-rpc-client/src/txn.rs deleted file mode 100644 index f80202b7..00000000 --- a/cmd/crates/stellar-rpc-client/src/txn.rs +++ /dev/null @@ -1,509 +0,0 @@ -// use ed25519_dalek::Signer; -use sha2::{Digest, Sha256}; -use stellar_xdr::curr::{ - self as xdr, ExtensionPoint, Hash, InvokeHostFunctionOp, LedgerFootprint, Limits, Memo, - Operation, OperationBody, Preconditions, ReadXdr, RestoreFootprintOp, - SorobanAuthorizationEntry, SorobanAuthorizedFunction, SorobanResources, SorobanTransactionData, - Transaction, TransactionExt, TransactionSignaturePayload, - TransactionSignaturePayloadTaggedTransaction, VecM, WriteXdr, -}; - -use super::{Error, RestorePreamble, SimulateTransactionResponse}; - -use super::{LogEvents, LogResources}; - -pub struct Assembled { - pub(crate) txn: Transaction, - pub(crate) sim_res: SimulateTransactionResponse, -} - -/// Represents an assembled transaction ready to be signed and submitted to the network. -impl Assembled { - /// - /// Creates a new `Assembled` transaction. - /// - /// # Arguments - /// - /// * `txn` - The original transaction. - /// * `client` - The client used for simulation and submission. - /// - /// # Errors - /// - /// Returns an error if simulation fails or if assembling the transaction fails. - pub fn new(txn: &Transaction, sim_res: SimulateTransactionResponse) -> Result { - let txn = assemble(txn, &sim_res)?; - Ok(Self { txn, sim_res }) - } - - /// - /// Calculates the hash of the assembled transaction. - /// - /// # Arguments - /// - /// * `network_passphrase` - The network passphrase. - /// - /// # Errors - /// - /// Returns an error if generating the hash fails. - pub fn hash(&self, network_passphrase: &str) -> Result<[u8; 32], xdr::Error> { - let signature_payload = TransactionSignaturePayload { - network_id: Hash(Sha256::digest(network_passphrase).into()), - tagged_transaction: TransactionSignaturePayloadTaggedTransaction::Tx(self.txn.clone()), - }; - Ok(Sha256::digest(signature_payload.to_xdr(Limits::none())?).into()) - } - - /// Create a transaction for restoring any data in the `restore_preamble` field of the `SimulateTransactionResponse`. - /// - /// # Errors - pub fn restore_txn(&self) -> Result, Error> { - if let Some(restore_preamble) = &self.sim_res.restore_preamble { - restore(self.transaction(), restore_preamble).map(Option::Some) - } else { - Ok(None) - } - } - - /// Returns a reference to the original transaction. - #[must_use] - pub fn transaction(&self) -> &Transaction { - &self.txn - } - - /// Returns a reference to the simulation response. - #[must_use] - pub fn sim_response(&self) -> &SimulateTransactionResponse { - &self.sim_res - } - - #[must_use] - pub fn bump_seq_num(mut self) -> Self { - self.txn.seq_num.0 += 1; - self - } - - /// - /// # Errors - #[must_use] - pub fn auth_entries(&self) -> VecM { - self.txn - .operations - .first() - .and_then(|op| match op.body { - OperationBody::InvokeHostFunction(ref body) => (matches!( - body.auth.first().map(|x| &x.root_invocation.function), - Some(&SorobanAuthorizedFunction::ContractFn(_)) - )) - .then_some(body.auth.clone()), - _ => None, - }) - .unwrap_or_default() - } - - /// - /// # Errors - pub fn log( - &self, - log_events: Option, - log_resources: Option, - ) -> Result<(), Error> { - if let TransactionExt::V1(SorobanTransactionData { - resources: resources @ SorobanResources { footprint, .. }, - .. - }) = &self.txn.ext - { - if let Some(log) = log_resources { - log(resources); - } - if let Some(log) = log_events { - log(footprint, &[self.auth_entries()], &self.sim_res.events()?); - }; - } - Ok(()) - } - - #[must_use] - pub fn requires_auth(&self) -> bool { - requires_auth(&self.txn).is_some() - } - - #[must_use] - pub fn is_view(&self) -> bool { - let TransactionExt::V1(SorobanTransactionData { - resources: - SorobanResources { - footprint: LedgerFootprint { read_write, .. }, - .. - }, - .. - }) = &self.txn.ext - else { - return false; - }; - read_write.is_empty() - } - - #[must_use] - pub fn set_max_instructions(mut self, instructions: u32) -> Self { - if let TransactionExt::V1(SorobanTransactionData { - resources: - SorobanResources { - instructions: ref mut i, - .. - }, - .. - }) = &mut self.txn.ext - { - tracing::trace!("setting max instructions to {instructions} from {i}"); - *i = instructions; - } - self - } -} - -// Apply the result of a simulateTransaction onto a transaction envelope, preparing it for -// submission to the network. -/// -/// # Errors -fn assemble( - raw: &Transaction, - simulation: &SimulateTransactionResponse, -) -> Result { - let mut tx = raw.clone(); - - // Right now simulate.results is one-result-per-function, and assumes there is only one - // operation in the txn, so we need to enforce that here. I (Paul) think that is a bug - // in soroban-rpc.simulateTransaction design, and we should fix it there. - // TODO: We should to better handling so non-soroban txns can be a passthrough here. - if tx.operations.len() != 1 { - return Err(Error::UnexpectedOperationCount { - count: tx.operations.len(), - }); - } - - let transaction_data = simulation.transaction_data()?; - - let mut op = tx.operations[0].clone(); - if let OperationBody::InvokeHostFunction(ref mut body) = &mut op.body { - if body.auth.is_empty() { - if simulation.results.len() != 1 { - return Err(Error::UnexpectedSimulateTransactionResultSize { - length: simulation.results.len(), - }); - } - - let auths = simulation - .results - .iter() - .map(|r| { - VecM::try_from( - r.auth - .iter() - .map(|v| SorobanAuthorizationEntry::from_xdr_base64(v, Limits::none())) - .collect::, _>>()?, - ) - }) - .collect::, _>>()?; - if !auths.is_empty() { - body.auth = auths[0].clone(); - } - } - } - - // Update transaction fees to meet the minimum resource fees. - let classic_tx_fee: u64 = crate::DEFAULT_TRANSACTION_FEES.into(); - - // Choose larger of existing fee or inclusion + resource fee. - tx.fee = tx.fee.max( - u32::try_from(classic_tx_fee + simulation.min_resource_fee) - .map_err(|_| Error::LargeFee(simulation.min_resource_fee + classic_tx_fee))?, - ); - - tx.operations = vec![op].try_into()?; - tx.ext = TransactionExt::V1(transaction_data); - Ok(tx) -} - -fn requires_auth(txn: &Transaction) -> Option { - let [op @ Operation { - body: OperationBody::InvokeHostFunction(InvokeHostFunctionOp { auth, .. }), - .. - }] = txn.operations.as_slice() - else { - return None; - }; - matches!( - auth.first().map(|x| &x.root_invocation.function), - Some(&SorobanAuthorizedFunction::ContractFn(_)) - ) - .then(move || op.clone()) -} - -fn restore(parent: &Transaction, restore: &RestorePreamble) -> Result { - let transaction_data = - SorobanTransactionData::from_xdr_base64(&restore.transaction_data, Limits::none())?; - let fee = u32::try_from(restore.min_resource_fee) - .map_err(|_| Error::LargeFee(restore.min_resource_fee))?; - Ok(Transaction { - source_account: parent.source_account.clone(), - fee: parent - .fee - .checked_add(fee) - .ok_or(Error::LargeFee(restore.min_resource_fee))?, - seq_num: parent.seq_num.clone(), - cond: Preconditions::None, - memo: Memo::None, - operations: vec![Operation { - source_account: None, - body: OperationBody::RestoreFootprint(RestoreFootprintOp { - ext: ExtensionPoint::V0, - }), - }] - .try_into()?, - ext: TransactionExt::V1(transaction_data), - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - use super::super::SimulateHostFunctionResultRaw; - use stellar_strkey::ed25519::PublicKey as Ed25519PublicKey; - use stellar_xdr::curr::{ - AccountId, ChangeTrustAsset, ChangeTrustOp, ExtensionPoint, Hash, HostFunction, - InvokeContractArgs, InvokeHostFunctionOp, LedgerFootprint, Memo, MuxedAccount, Operation, - Preconditions, PublicKey, ScAddress, ScSymbol, ScVal, SequenceNumber, - SorobanAuthorizedFunction, SorobanAuthorizedInvocation, SorobanResources, - SorobanTransactionData, Uint256, WriteXdr, - }; - - const SOURCE: &str = "GBZXN7PIRZGNMHGA7MUUUF4GWPY5AYPV6LY4UV2GL6VJGIQRXFDNMADI"; - - fn transaction_data() -> SorobanTransactionData { - SorobanTransactionData { - resources: SorobanResources { - footprint: LedgerFootprint { - read_only: VecM::default(), - read_write: VecM::default(), - }, - instructions: 0, - read_bytes: 5, - write_bytes: 0, - }, - resource_fee: 0, - ext: ExtensionPoint::V0, - } - } - - fn simulation_response() -> SimulateTransactionResponse { - let source_bytes = Ed25519PublicKey::from_string(SOURCE).unwrap().0; - let fn_auth = &SorobanAuthorizationEntry { - credentials: xdr::SorobanCredentials::Address(xdr::SorobanAddressCredentials { - address: ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256( - source_bytes, - )))), - nonce: 0, - signature_expiration_ledger: 0, - signature: ScVal::Void, - }), - root_invocation: SorobanAuthorizedInvocation { - function: SorobanAuthorizedFunction::ContractFn(InvokeContractArgs { - contract_address: ScAddress::Contract(Hash([0; 32])), - function_name: ScSymbol("fn".try_into().unwrap()), - args: VecM::default(), - }), - sub_invocations: VecM::default(), - }, - }; - - SimulateTransactionResponse { - min_resource_fee: 115, - latest_ledger: 3, - results: vec![SimulateHostFunctionResultRaw { - auth: vec![fn_auth.to_xdr_base64(Limits::none()).unwrap()], - xdr: ScVal::U32(0).to_xdr_base64(Limits::none()).unwrap(), - }], - transaction_data: transaction_data().to_xdr_base64(Limits::none()).unwrap(), - ..Default::default() - } - } - - fn single_contract_fn_transaction() -> Transaction { - let source_bytes = Ed25519PublicKey::from_string(SOURCE).unwrap().0; - Transaction { - source_account: MuxedAccount::Ed25519(Uint256(source_bytes)), - fee: 100, - seq_num: SequenceNumber(0), - cond: Preconditions::None, - memo: Memo::None, - operations: vec![Operation { - source_account: None, - body: OperationBody::InvokeHostFunction(InvokeHostFunctionOp { - host_function: HostFunction::InvokeContract(InvokeContractArgs { - contract_address: ScAddress::Contract(Hash([0x0; 32])), - function_name: ScSymbol::default(), - args: VecM::default(), - }), - auth: VecM::default(), - }), - }] - .try_into() - .unwrap(), - ext: TransactionExt::V0, - } - } - - #[test] - fn test_assemble_transaction_updates_tx_data_from_simulation_response() { - let sim = simulation_response(); - let txn = single_contract_fn_transaction(); - let Ok(result) = assemble(&txn, &sim) else { - panic!("assemble failed"); - }; - - // validate it auto updated the tx fees from sim response fees - // since it was greater than tx.fee - assert_eq!(215, result.fee); - - // validate it updated sorobantransactiondata block in the tx ext - assert_eq!(TransactionExt::V1(transaction_data()), result.ext); - } - - #[test] - fn test_assemble_transaction_adds_the_auth_to_the_host_function() { - let sim = simulation_response(); - let txn = single_contract_fn_transaction(); - let Ok(result) = assemble(&txn, &sim) else { - panic!("assemble failed"); - }; - - assert_eq!(1, result.operations.len()); - let OperationBody::InvokeHostFunction(ref op) = result.operations[0].body else { - panic!("unexpected operation type: {:#?}", result.operations[0]); - }; - - assert_eq!(1, op.auth.len()); - let auth = &op.auth[0]; - - let xdr::SorobanAuthorizedFunction::ContractFn(xdr::InvokeContractArgs { - ref function_name, - .. - }) = auth.root_invocation.function - else { - panic!("unexpected function type"); - }; - assert_eq!("fn".to_string(), format!("{}", function_name.0)); - - let xdr::SorobanCredentials::Address(xdr::SorobanAddressCredentials { - address: - xdr::ScAddress::Account(xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(address))), - .. - }) = &auth.credentials - else { - panic!("unexpected credentials type"); - }; - assert_eq!( - SOURCE.to_string(), - stellar_strkey::ed25519::PublicKey(address.0).to_string() - ); - } - - #[test] - fn test_assemble_transaction_errors_for_non_invokehostfn_ops() { - let source_bytes = Ed25519PublicKey::from_string(SOURCE).unwrap().0; - let txn = Transaction { - source_account: MuxedAccount::Ed25519(Uint256(source_bytes)), - fee: 100, - seq_num: SequenceNumber(0), - cond: Preconditions::None, - memo: Memo::None, - operations: vec![Operation { - source_account: None, - body: OperationBody::ChangeTrust(ChangeTrustOp { - line: ChangeTrustAsset::Native, - limit: 0, - }), - }] - .try_into() - .unwrap(), - ext: TransactionExt::V0, - }; - - let result = assemble( - &txn, - &SimulateTransactionResponse { - min_resource_fee: 115, - transaction_data: transaction_data().to_xdr_base64(Limits::none()).unwrap(), - latest_ledger: 3, - ..Default::default() - }, - ); - - match result { - Ok(_) => {} - Err(e) => panic!("expected assembled operation, got: {e:#?}"), - } - } - - #[test] - fn test_assemble_transaction_errors_for_errors_for_mismatched_simulation() { - let txn = single_contract_fn_transaction(); - - let result = assemble( - &txn, - &SimulateTransactionResponse { - min_resource_fee: 115, - transaction_data: transaction_data().to_xdr_base64(Limits::none()).unwrap(), - latest_ledger: 3, - ..Default::default() - }, - ); - - match result { - Err(Error::UnexpectedSimulateTransactionResultSize { length }) => { - assert_eq!(0, length); - } - r => panic!("expected UnexpectedSimulateTransactionResultSize error, got: {r:#?}"), - } - } - - #[test] - fn test_assemble_transaction_overflow_behavior() { - // - // Test two separate cases: - // - // 1. Given a near-max (u32::MAX - 100) resource fee make sure the tx - // fee does not overflow after adding the base inclusion fee (100). - // 2. Given a large resource fee that WILL exceed u32::MAX with the - // base inclusion fee, ensure the overflow is caught with an error - // rather than silently ignored. - let txn = single_contract_fn_transaction(); - let mut response = simulation_response(); - - // sanity check so these can be adjusted if the above helper changes - assert_eq!(txn.fee, 100, "modified txn.fee: update the math below"); - - // 1: wiggle room math overflows but result fits - response.min_resource_fee = (u32::MAX - 100).into(); - - match assemble(&txn, &response) { - Ok(asstxn) => { - let expected = u32::MAX; - assert_eq!(asstxn.fee, expected); - } - r => panic!("expected success, got: {r:#?}"), - } - - // 2: combo overflows, should throw - response.min_resource_fee = (u32::MAX - 99).into(); - - match assemble(&txn, &response) { - Err(Error::LargeFee(fee)) => { - let expected = u64::from(u32::MAX) + 1; - assert_eq!(expected, fee, "expected {expected} != {fee} actual"); - } - r => panic!("expected LargeFee error, got: {r:#?}"), - } - } -} diff --git a/cmd/soroban-rpc/lib/preflight/Cargo.toml b/cmd/soroban-rpc/lib/preflight/Cargo.toml index e169487e..f3f4193f 100644 --- a/cmd/soroban-rpc/lib/preflight/Cargo.toml +++ b/cmd/soroban-rpc/lib/preflight/Cargo.toml @@ -8,11 +8,11 @@ crate-type = ["staticlib"] [dependencies] base64 = { workspace = true } -libc = "0.2.147" +libc = { workspace = true } sha2 = { workspace = true } # we need the testutils feature in order to get backtraces in the preflight library # when soroban rpc is configured to run with --preflight-enable-debug soroban-env-host = { workspace = true, features = ["recording_mode", "testutils", "unstable-next-api"]} soroban-simulation = { workspace = true } -anyhow = "1.0.75" -rand = { version = "0.8.5", features = [] } +anyhow = { workspace = true } +rand = { workspace = true } diff --git a/cmd/soroban-rpc/lib/preflight/src/lib.rs b/cmd/soroban-rpc/lib/preflight/src/lib.rs index 0c0fef90..e84bb5cf 100644 --- a/cmd/soroban-rpc/lib/preflight/src/lib.rs +++ b/cmd/soroban-rpc/lib/preflight/src/lib.rs @@ -21,6 +21,7 @@ use soroban_simulation::simulation::{ }; use soroban_simulation::{AutoRestoringSnapshotSource, NetworkConfig, SnapshotSourceWithArchive}; use std::cell::RefCell; +use std::convert::TryFrom; use std::ffi::{CStr, CString}; use std::panic; use std::ptr::null_mut; @@ -144,16 +145,16 @@ impl Default for CPreflightResult { fn default() -> Self { Self { error: CString::new(String::new()).unwrap().into_raw(), - auth: Default::default(), - result: Default::default(), - transaction_data: Default::default(), + auth: CXDRVector::default(), + result: CXDR::default(), + transaction_data: CXDR::default(), min_fee: 0, - events: Default::default(), + events: CXDRVector::default(), cpu_instructions: 0, memory_bytes: 0, - pre_restore_transaction_data: Default::default(), + pre_restore_transaction_data: CXDR::default(), pre_restore_min_fee: 0, - ledger_entry_diff: Default::default(), + ledger_entry_diff: CXDRDiffVector::default(), } } } @@ -166,46 +167,42 @@ impl CPreflightResult { ) -> Self { let mut result = Self { error: string_to_c(error), - auth: xdr_vec_to_c(invoke_hf_result.auth), - result: option_xdr_to_c( - invoke_hf_result - .invoke_result - .map_or_else(|_| None, |v| Some(v)), - ), + auth: xdr_vec_to_c(&invoke_hf_result.auth), + result: option_xdr_to_c(invoke_hf_result.invoke_result.ok().as_ref()), min_fee: invoke_hf_result .transaction_data .as_ref() .map_or_else(|| 0, |r| r.resource_fee), - transaction_data: option_xdr_to_c(invoke_hf_result.transaction_data), + transaction_data: option_xdr_to_c(invoke_hf_result.transaction_data.as_ref()), // TODO: Diagnostic and contract events should be separated in the response - events: xdr_vec_to_c(invoke_hf_result.diagnostic_events), - cpu_instructions: invoke_hf_result.simulated_instructions as u64, - memory_bytes: invoke_hf_result.simulated_memory as u64, - ledger_entry_diff: ledger_entry_diff_vec_to_c(invoke_hf_result.modified_entries), + events: xdr_vec_to_c(&invoke_hf_result.diagnostic_events), + cpu_instructions: u64::from(invoke_hf_result.simulated_instructions), + memory_bytes: u64::from(invoke_hf_result.simulated_memory), + ledger_entry_diff: ledger_entry_diff_vec_to_c(&invoke_hf_result.modified_entries), ..Default::default() }; if let Some(p) = restore_preamble { result.pre_restore_min_fee = p.transaction_data.resource_fee; - result.pre_restore_transaction_data = xdr_to_c(p.transaction_data); + result.pre_restore_transaction_data = xdr_to_c(&p.transaction_data); }; result } fn new_from_transaction_data( - transaction_data: Option, - restore_preamble: Option, + transaction_data: &Option, + restore_preamble: &Option, error: String, ) -> Self { let min_fee = transaction_data.as_ref().map_or(0, |d| d.resource_fee); let mut result = Self { error: string_to_c(error), - transaction_data: option_xdr_to_c(transaction_data), + transaction_data: option_xdr_to_c(transaction_data.as_ref()), min_fee, ..Default::default() }; if let Some(p) = restore_preamble { result.pre_restore_min_fee = p.transaction_data.resource_fee; - result.pre_restore_transaction_data = xdr_to_c(p.transaction_data); + result.pre_restore_transaction_data = xdr_to_c(&p.transaction_data); }; result } @@ -256,10 +253,12 @@ fn preflight_invoke_hf_op_or_maybe_panic( let mut adjustment_config = SimulationAdjustmentConfig::default_adjustment(); // It would be reasonable to extend `resource_config` to be compatible with `adjustment_config` // in order to let the users customize the resource/fee adjustments in a more granular fashion. + + let instruction_leeway = u32::try_from(resource_config.instruction_leeway)?; adjustment_config.instructions.additive_factor = adjustment_config .instructions .additive_factor - .max(resource_config.instruction_leeway.min(u32::MAX as u64) as u32); + .max(instruction_leeway); // Here we assume that no input auth means that the user requests the recording auth. let auth_entries = if invoke_hf_op.auth.is_empty() { None @@ -319,34 +318,34 @@ fn preflight_footprint_ttl_op_or_maybe_panic( let network_config = NetworkConfig::load_from_snapshot(go_storage.as_ref(), c_ledger_info.bucket_list_size)?; let ledger_info = fill_ledger_info(c_ledger_info, &network_config); - // TODO: It would make for a better UX if the user passed only the neccesary fields for every operation. + // TODO: It would make for a better UX if the user passed only the necessary fields for every operation. // That would remove a possibility of providing bad operation body, or a possibility of filling wrong footprint // field. match op_body { OperationBody::ExtendFootprintTtl(extend_op) => { - preflight_extend_ttl_op(extend_op, footprint.read_only.as_slice(), go_storage, &network_config, &ledger_info) + preflight_extend_ttl_op(&extend_op, footprint.read_only.as_slice(), &go_storage, &network_config, &ledger_info) } OperationBody::RestoreFootprint(_) => { - preflight_restore_op(footprint.read_write.as_slice(), go_storage, &network_config, &ledger_info) + Ok(preflight_restore_op(footprint.read_write.as_slice(), &go_storage, &network_config, &ledger_info)) } _ => Err(anyhow!("encountered unsupported operation type: '{:?}', instead of 'ExtendFootprintTtl' or 'RestoreFootprint' operations.", - op_body.discriminant()).into()) + op_body.discriminant())) } } fn preflight_extend_ttl_op( - extend_op: ExtendFootprintTtlOp, + extend_op: &ExtendFootprintTtlOp, keys_to_extend: &[LedgerKey], - go_storage: Rc, + go_storage: &Rc, network_config: &NetworkConfig, ledger_info: &LedgerInfo, ) -> Result { let auto_restore_snapshot = AutoRestoringSnapshotSource::new(go_storage.clone(), ledger_info)?; let simulation_result = simulate_extend_ttl_op( &auto_restore_snapshot, - &network_config, + network_config, &SimulationAdjustmentConfig::default_adjustment(), - &ledger_info, + ledger_info, keys_to_extend, extend_op.extend_to, ); @@ -354,9 +353,9 @@ fn preflight_extend_ttl_op( Ok(r) => ( Some(r.transaction_data), auto_restore_snapshot.simulate_restore_keys_op( - &network_config, + network_config, &SimulationAdjustmentConfig::default_adjustment(), - &ledger_info, + ledger_info, ), ), Err(e) => (None, Err(e)), @@ -364,33 +363,33 @@ fn preflight_extend_ttl_op( let error_str = extract_error_string(&maybe_restore_result, go_storage.as_ref()); Ok(CPreflightResult::new_from_transaction_data( - maybe_transaction_data, - maybe_restore_result.unwrap_or(None), + &maybe_transaction_data, + &maybe_restore_result.unwrap_or(None), error_str, )) } fn preflight_restore_op( keys_to_restore: &[LedgerKey], - go_storage: Rc, + go_storage: &Rc, network_config: &NetworkConfig, ledger_info: &LedgerInfo, -) -> Result { +) -> CPreflightResult { let simulation_result = simulate_restore_op( go_storage.as_ref(), - &network_config, + network_config, &SimulationAdjustmentConfig::default_adjustment(), - &ledger_info, + ledger_info, keys_to_restore, ); let error_str = extract_error_string(&simulation_result, go_storage.as_ref()); - Ok(CPreflightResult::new_from_transaction_data( - simulation_result + CPreflightResult::new_from_transaction_data( + &simulation_result .map(|r| Some(r.transaction_data)) .unwrap_or(None), - None, + &None, error_str, - )) + ) } fn preflight_error(str: String) -> CPreflightResult { @@ -422,13 +421,12 @@ fn catch_preflight_panic(op: Box Result>) -> *mut // TODO: We could use something like https://github.com/sonos/ffi-convert-rs // to replace all the free_* , *_to_c and from_c_* functions by implementations of CDrop, // CReprOf and AsRust - -fn xdr_to_c(v: impl WriteXdr) -> CXDR { +fn xdr_to_c(v: &impl WriteXdr) -> CXDR { let (xdr, len) = vec_to_c_array(v.to_xdr(DEFAULT_XDR_RW_LIMITS).unwrap()); CXDR { xdr, len } } -fn option_xdr_to_c(v: Option) -> CXDR { +fn option_xdr_to_c(v: Option<&impl WriteXdr>) -> CXDR { v.map_or( CXDR { xdr: null_mut(), @@ -438,15 +436,15 @@ fn option_xdr_to_c(v: Option) -> CXDR { ) } -fn ledger_entry_diff_to_c(v: LedgerEntryDiff) -> CXDRDiff { +fn ledger_entry_diff_to_c(v: &LedgerEntryDiff) -> CXDRDiff { CXDRDiff { - before: option_xdr_to_c(v.state_before), - after: option_xdr_to_c(v.state_after), + before: option_xdr_to_c(v.state_before.as_ref()), + after: option_xdr_to_c(v.state_after.as_ref()), } } -fn xdr_vec_to_c(v: Vec) -> CXDRVector { - let c_v = v.into_iter().map(xdr_to_c).collect(); +fn xdr_vec_to_c(v: &[impl WriteXdr]) -> CXDRVector { + let c_v = v.iter().map(xdr_to_c).collect(); let (array, len) = vec_to_c_array(c_v); CXDRVector { array, len } } @@ -470,9 +468,9 @@ fn vec_to_c_array(mut v: Vec) -> (*mut T, libc::size_t) { (ptr, len) } -fn ledger_entry_diff_vec_to_c(modified_entries: Vec) -> CXDRDiffVector { +fn ledger_entry_diff_vec_to_c(modified_entries: &[LedgerEntryDiff]) -> CXDRDiffVector { let c_diffs = modified_entries - .into_iter() + .iter() .map(ledger_entry_diff_to_c) .collect(); let (array, len) = vec_to_c_array(c_diffs); @@ -591,7 +589,7 @@ impl GoLedgerStorage { // Gets a ledger entry by key, including the archived/removed entries. // The failures of this function are not recoverable and should only happen when // the underlying storage is somehow corrupted. - fn get_fallible(&self, key: &LedgerKey) -> anyhow::Result> { + fn get_fallible(&self, key: &LedgerKey) -> Result> { let mut key_xdr = key.to_xdr(DEFAULT_XDR_RW_LIMITS)?; let Some(xdr) = self.get_xdr_internal(&mut key_xdr) else { return Ok(None); @@ -644,11 +642,11 @@ impl SnapshotSourceWithArchive for GoLedgerStorage { Err(e) => { // Store the internal error in the storage as the info won't be propagated from simulation. if let Ok(mut err) = self.internal_error.try_borrow_mut() { - *err = Some(e.into()); + *err = Some(e); } // Errors that occur in storage are not recoverable, so we force host to halt by passing // it an internal error. - return Err((ScErrorType::Storage, ScErrorCode::InternalError).into()); + Err((ScErrorType::Storage, ScErrorCode::InternalError).into()) } } } @@ -657,12 +655,14 @@ impl SnapshotSourceWithArchive for GoLedgerStorage { fn extract_error_string(simulation_result: &Result, go_storage: &GoLedgerStorage) -> String { match simulation_result { Ok(_) => String::new(), - Err(e) => { - // Override any simulation result with a storage error (if any). Simulation does not propagate the storage - // errors, but these provide more exact information on the root cause. - match go_storage.internal_error.borrow().as_ref() { - Some(e) => format!("{e:?}"), - None => format!("{e:?}"), + Err(e) => + // Override any simulation result with a storage error (if any). Simulation does not propagate the storage + // errors, but these provide more exact information on the root cause. + { + if let Some(e) = go_storage.internal_error.borrow().as_ref() { + format!("{e:?}") + } else { + format!("{e:?}") } } }