From 278887d0565a521b948c8c545c9de9321884d1d4 Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Tue, 7 Feb 2023 14:55:47 +0100 Subject: [PATCH] soroban-rpc: Add auth-next information to simulateTransaction response (#395) Co-authored-by: Paul Bellamy --- .github/workflows/soroban-rpc.yml | 2 +- Cargo.lock | 152 ++++++++++++------ Cargo.toml | 10 +- .../test-wasms/custom_type/src/lib.rs | 6 +- .../test-wasms/hello_world/src/lib.rs | 7 +- .../invoker_account_exists/Cargo.toml | 18 --- .../invoker_account_exists/src/lib.rs | 39 ----- .../internal/methods/simulate_transaction.go | 40 +++-- .../internal/test/docker-compose.yml | 2 +- .../test/simulate_transaction_test.go | 102 +++++++++--- cmd/soroban-rpc/lib/preflight.h | 1 + cmd/soroban-rpc/lib/preflight/Cargo.toml | 1 + cmd/soroban-rpc/lib/preflight/src/lib.rs | 78 +++++++-- go.mod | 2 +- go.sum | 4 +- 15 files changed, 306 insertions(+), 158 deletions(-) delete mode 100644 cmd/soroban-cli/tests/fixtures/test-wasms/invoker_account_exists/Cargo.toml delete mode 100644 cmd/soroban-cli/tests/fixtures/test-wasms/invoker_account_exists/src/lib.rs diff --git a/.github/workflows/soroban-rpc.yml b/.github/workflows/soroban-rpc.yml index 6b713cf6..cbc0a3f7 100644 --- a/.github/workflows/soroban-rpc.yml +++ b/.github/workflows/soroban-rpc.yml @@ -89,7 +89,7 @@ jobs: env: SOROBAN_RPC_INTEGRATION_TESTS_ENABLED: true SOROBAN_RPC_INTEGRATION_TESTS_CAPTIVE_CORE_BIN: /usr/bin/stellar-core - PROTOCOL_20_CORE_DEBIAN_PKG_VERSION: 19.6.1-1158.c0ad35aa1.focal~soroban + PROTOCOL_20_CORE_DEBIAN_PKG_VERSION: 19.7.1-1178.e352f0012.focal~soroban runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 diff --git a/Cargo.lock b/Cargo.lock index 69d7d16e..734089ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1507,7 +1507,8 @@ name = "preflight" version = "0.1.0" dependencies = [ "libc", - "soroban-env-host", + "sha2 0.10.6", + "soroban-env-host 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0)", ] [[package]] @@ -1896,7 +1897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afe34ccbd1fb6fa0b2fc7cccb037bd3d3f1e484c3befe1b713d7611884f336a" dependencies = [ "slip10", - "stellar-strkey 0.0.7", + "stellar-strkey 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror", "tiny-bip39", ] @@ -2069,14 +2070,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "soroban-auth" -version = "0.4.3" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=e1c3de33942f0e997680645941787102ebf61e85#e1c3de33942f0e997680645941787102ebf61e85" -dependencies = [ - "soroban-sdk", -] - [[package]] name = "soroban-cli" version = "0.4.0" @@ -2105,12 +2098,12 @@ dependencies = [ "serde_derive", "serde_json", "sha2 0.10.6", - "soroban-env-host", + "soroban-env-host 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0)", "soroban-ledger-snapshot", "soroban-sdk", "soroban-spec", "soroban-token-spec", - "stellar-strkey 0.0.7", + "stellar-strkey 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor", "termcolor_output", "thiserror", @@ -2124,29 +2117,42 @@ dependencies = [ [[package]] name = "soroban-env-common" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=993c527abce72748405d71467498bffd63e061c1#993c527abce72748405d71467498bffd63e061c1" +source = "git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0#2431bd416010215cc9759b435662a7274206a4c0" dependencies = [ "crate-git-revision", "serde", - "soroban-env-macros", + "soroban-env-macros 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0)", "soroban-wasmi", "static_assertions", - "stellar-xdr", + "stellar-xdr 0.0.12 (git+https://github.com/stellar/rs-stellar-xdr?rev=ea8a54526fe896412b106c67c0ba35181ae12ee4)", +] + +[[package]] +name = "soroban-env-common" +version = "0.0.12" +source = "git+https://github.com/stellar/rs-soroban-env?rev=ade7d47#ade7d475675d694a142146cafb30140e0dca64dd" +dependencies = [ + "crate-git-revision", + "serde", + "soroban-env-macros 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=ade7d47)", + "soroban-wasmi", + "static_assertions", + "stellar-xdr 0.0.12 (git+https://github.com/stellar/rs-stellar-xdr?rev=02299043)", ] [[package]] name = "soroban-env-guest" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=993c527abce72748405d71467498bffd63e061c1#993c527abce72748405d71467498bffd63e061c1" +source = "git+https://github.com/stellar/rs-soroban-env?rev=ade7d47#ade7d475675d694a142146cafb30140e0dca64dd" dependencies = [ - "soroban-env-common", + "soroban-env-common 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=ade7d47)", "static_assertions", ] [[package]] name = "soroban-env-host" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=993c527abce72748405d71467498bffd63e061c1#993c527abce72748405d71467498bffd63e061c1" +source = "git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0#2431bd416010215cc9759b435662a7274206a4c0" dependencies = [ "backtrace", "curve25519-dalek", @@ -2158,8 +2164,30 @@ dependencies = [ "num-integer", "num-traits", "sha2 0.10.6", - "soroban-env-common", - "soroban-native-sdk-macros", + "soroban-env-common 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0)", + "soroban-native-sdk-macros 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0)", + "soroban-wasmi", + "static_assertions", + "tinyvec", +] + +[[package]] +name = "soroban-env-host" +version = "0.0.12" +source = "git+https://github.com/stellar/rs-soroban-env?rev=ade7d47#ade7d475675d694a142146cafb30140e0dca64dd" +dependencies = [ + "backtrace", + "curve25519-dalek", + "dyn-fmt", + "ed25519-dalek", + "hex", + "log", + "num-derive", + "num-integer", + "num-traits", + "sha2 0.10.6", + "soroban-env-common 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=ade7d47)", + "soroban-native-sdk-macros 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=ade7d47)", "soroban-wasmi", "static_assertions", "tinyvec", @@ -2168,14 +2196,29 @@ dependencies = [ [[package]] name = "soroban-env-macros" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=993c527abce72748405d71467498bffd63e061c1#993c527abce72748405d71467498bffd63e061c1" +source = "git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0#2431bd416010215cc9759b435662a7274206a4c0" dependencies = [ "itertools", "proc-macro2", "quote", "serde", "serde_json", - "stellar-xdr", + "stellar-xdr 0.0.12 (git+https://github.com/stellar/rs-stellar-xdr?rev=ea8a54526fe896412b106c67c0ba35181ae12ee4)", + "syn", + "thiserror", +] + +[[package]] +name = "soroban-env-macros" +version = "0.0.12" +source = "git+https://github.com/stellar/rs-soroban-env?rev=ade7d47#ade7d475675d694a142146cafb30140e0dca64dd" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "serde", + "serde_json", + "stellar-xdr 0.0.12 (git+https://github.com/stellar/rs-stellar-xdr?rev=02299043)", "syn", "thiserror", ] @@ -2183,18 +2226,29 @@ dependencies = [ [[package]] name = "soroban-ledger-snapshot" version = "0.4.3" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=e1c3de33942f0e997680645941787102ebf61e85#e1c3de33942f0e997680645941787102ebf61e85" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=8a11d747d969b137ef0dccbc37f23f2966f5fcd1#8a11d747d969b137ef0dccbc37f23f2966f5fcd1" dependencies = [ "serde", "serde_json", - "soroban-env-host", + "soroban-env-host 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=ade7d47)", "thiserror", ] [[package]] name = "soroban-native-sdk-macros" version = "0.0.12" -source = "git+https://github.com/stellar/rs-soroban-env?rev=993c527abce72748405d71467498bffd63e061c1#993c527abce72748405d71467498bffd63e061c1" +source = "git+https://github.com/stellar/rs-soroban-env?rev=2431bd416010215cc9759b435662a7274206a4c0#2431bd416010215cc9759b435662a7274206a4c0" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "soroban-native-sdk-macros" +version = "0.0.12" +source = "git+https://github.com/stellar/rs-soroban-env?rev=ade7d47#ade7d475675d694a142146cafb30140e0dca64dd" dependencies = [ "itertools", "proc-macro2", @@ -2205,38 +2259,38 @@ dependencies = [ [[package]] name = "soroban-sdk" version = "0.4.3" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=e1c3de33942f0e997680645941787102ebf61e85#e1c3de33942f0e997680645941787102ebf61e85" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=8a11d747d969b137ef0dccbc37f23f2966f5fcd1#8a11d747d969b137ef0dccbc37f23f2966f5fcd1" dependencies = [ "bytes-lit", "ed25519-dalek", "rand 0.8.5", "soroban-env-guest", - "soroban-env-host", + "soroban-env-host 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=ade7d47)", "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey 0.0.6", + "stellar-strkey 0.0.7 (git+https://github.com/stellar/rs-stellar-strkey)", ] [[package]] name = "soroban-sdk-macros" version = "0.4.3" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=e1c3de33942f0e997680645941787102ebf61e85#e1c3de33942f0e997680645941787102ebf61e85" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=8a11d747d969b137ef0dccbc37f23f2966f5fcd1#8a11d747d969b137ef0dccbc37f23f2966f5fcd1" dependencies = [ "darling", "itertools", "proc-macro2", "quote", "sha2 0.10.6", - "soroban-env-common", + "soroban-env-common 0.0.12 (git+https://github.com/stellar/rs-soroban-env?rev=ade7d47)", "soroban-spec", - "stellar-xdr", + "stellar-xdr 0.0.12 (git+https://github.com/stellar/rs-stellar-xdr?rev=ea8a54526fe896412b106c67c0ba35181ae12ee4)", "syn", ] [[package]] name = "soroban-spec" version = "0.4.3" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=e1c3de33942f0e997680645941787102ebf61e85#e1c3de33942f0e997680645941787102ebf61e85" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=8a11d747d969b137ef0dccbc37f23f2966f5fcd1#8a11d747d969b137ef0dccbc37f23f2966f5fcd1" dependencies = [ "base64 0.13.1", "darling", @@ -2248,7 +2302,7 @@ dependencies = [ "serde_derive", "serde_json", "sha2 0.10.6", - "stellar-xdr", + "stellar-xdr 0.0.12 (git+https://github.com/stellar/rs-stellar-xdr?rev=ea8a54526fe896412b106c67c0ba35181ae12ee4)", "syn", "thiserror", "wasmparser 0.88.0", @@ -2257,9 +2311,8 @@ dependencies = [ [[package]] name = "soroban-token-spec" version = "0.4.3" -source = "git+https://github.com/stellar/rs-soroban-sdk?rev=e1c3de33942f0e997680645941787102ebf61e85#e1c3de33942f0e997680645941787102ebf61e85" +source = "git+https://github.com/stellar/rs-soroban-sdk?rev=8a11d747d969b137ef0dccbc37f23f2966f5fcd1#8a11d747d969b137ef0dccbc37f23f2966f5fcd1" dependencies = [ - "soroban-auth", "soroban-sdk", ] @@ -2305,8 +2358,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-strkey" -version = "0.0.6" -source = "git+https://github.com/stellar/rs-stellar-strkey?rev=5e582a8b#5e582a8b48f85443df60dc78e2e98959862400d6" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0689070126ca7f2effc2c5726584446db52190f0cef043c02eb4040a711c11" dependencies = [ "base32", "thiserror", @@ -2315,8 +2369,7 @@ dependencies = [ [[package]] name = "stellar-strkey" version = "0.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0689070126ca7f2effc2c5726584446db52190f0cef043c02eb4040a711c11" +source = "git+https://github.com/stellar/rs-stellar-strkey#e6ba45c60c16de28c7522586b80ed0150157df73" dependencies = [ "base32", "thiserror", @@ -2325,7 +2378,19 @@ dependencies = [ [[package]] name = "stellar-xdr" version = "0.0.12" -source = "git+https://github.com/stellar/rs-stellar-xdr?rev=154e07e#154e07ebbb0ad307475fd665d5a0dcf169a9596f" +source = "git+https://github.com/stellar/rs-stellar-xdr?rev=02299043#0229904359bf47633b89612b6e21ae39a34dcbcf" +dependencies = [ + "base64 0.13.1", + "crate-git-revision", + "hex", + "serde", + "serde_with", +] + +[[package]] +name = "stellar-xdr" +version = "0.0.12" +source = "git+https://github.com/stellar/rs-stellar-xdr?rev=ea8a54526fe896412b106c67c0ba35181ae12ee4#ea8a54526fe896412b106c67c0ba35181ae12ee4" dependencies = [ "base64 0.13.1", "crate-git-revision", @@ -2447,13 +2512,6 @@ dependencies = [ "soroban-sdk", ] -[[package]] -name = "test_invoker_account_exists" -version = "0.4.0" -dependencies = [ - "soroban-sdk", -] - [[package]] name = "textwrap" version = "0.16.0" diff --git a/Cargo.toml b/Cargo.toml index 502b7aa2..76b7cdcd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,27 +10,27 @@ default-members = ["cmd/soroban-cli"] [workspace.dependencies.soroban-env-host] version = "0.0.12" git = "https://github.com/stellar/rs-soroban-env" -rev = "993c527abce72748405d71467498bffd63e061c1" +rev = "2431bd416010215cc9759b435662a7274206a4c0" [workspace.dependencies.soroban-spec] version = "0.4.1" git = "https://github.com/stellar/rs-soroban-sdk" -rev = "e1c3de33942f0e997680645941787102ebf61e85" +rev = "8a11d747d969b137ef0dccbc37f23f2966f5fcd1" [workspace.dependencies.soroban-token-spec] version = "0.4.1" git = "https://github.com/stellar/rs-soroban-sdk" -rev = "e1c3de33942f0e997680645941787102ebf61e85" +rev = "8a11d747d969b137ef0dccbc37f23f2966f5fcd1" [workspace.dependencies.soroban-sdk] version = "0.4.1" git = "https://github.com/stellar/rs-soroban-sdk" -rev = "e1c3de33942f0e997680645941787102ebf61e85" +rev = "8a11d747d969b137ef0dccbc37f23f2966f5fcd1" [workspace.dependencies.soroban-ledger-snapshot] version = "0.4.1" git = "https://github.com/stellar/rs-soroban-sdk" -rev = "e1c3de33942f0e997680645941787102ebf61e85" +rev = "8a11d747d969b137ef0dccbc37f23f2966f5fcd1" [workspace.dependencies.stellar-strkey] version = "0.0.7" diff --git a/cmd/soroban-cli/tests/fixtures/test-wasms/custom_type/src/lib.rs b/cmd/soroban-cli/tests/fixtures/test-wasms/custom_type/src/lib.rs index 94a125f7..5406c573 100644 --- a/cmd/soroban-cli/tests/fixtures/test-wasms/custom_type/src/lib.rs +++ b/cmd/soroban-cli/tests/fixtures/test-wasms/custom_type/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -use soroban_sdk::{contractimpl, contracttype, symbol, vec, AccountId, Bytes, Env, Symbol, Vec}; +use soroban_sdk::{contractimpl, contracttype, symbol, vec, Address, Bytes, Env, Symbol, Vec}; pub struct Contract; @@ -63,8 +63,8 @@ impl Contract { complex } - pub fn account(_env: Env, account: AccountId) -> AccountId { - account + pub fn account(_env: Env, address: Address) -> Address { + address } pub fn bytes(_env: Env, bytes: Bytes) -> Bytes { diff --git a/cmd/soroban-cli/tests/fixtures/test-wasms/hello_world/src/lib.rs b/cmd/soroban-cli/tests/fixtures/test-wasms/hello_world/src/lib.rs index f42c3c74..e10e345f 100644 --- a/cmd/soroban-cli/tests/fixtures/test-wasms/hello_world/src/lib.rs +++ b/cmd/soroban-cli/tests/fixtures/test-wasms/hello_world/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -use soroban_sdk::{contractimpl, symbol, vec, Env, Symbol, Vec}; +use soroban_sdk::{contractimpl, symbol, vec, Address, Env, Symbol, Vec}; pub struct Contract; @@ -16,6 +16,11 @@ impl Contract { pub fn not(env: Env, boolean: bool) -> Vec { vec![&env, !boolean] } + + pub fn auth(env: Env, addr: Address, world: Symbol) -> Vec { + addr.require_auth(); + vec![&env, symbol!("Hello"), world] + } } #[cfg(test)] diff --git a/cmd/soroban-cli/tests/fixtures/test-wasms/invoker_account_exists/Cargo.toml b/cmd/soroban-cli/tests/fixtures/test-wasms/invoker_account_exists/Cargo.toml deleted file mode 100644 index 3a7b7c86..00000000 --- a/cmd/soroban-cli/tests/fixtures/test-wasms/invoker_account_exists/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "test_invoker_account_exists" -version = "0.4.0" -authors = ["Stellar Development Foundation "] -license = "Apache-2.0" -edition = "2021" -publish = false -rust-version = "1.66" - -[lib] -crate-type = ["cdylib", "rlib"] -doctest = false - -[dependencies] -soroban-sdk = { workspace = true } - -[dev-dependencies] -soroban-sdk = { workspace = true, features = ["testutils"]} diff --git a/cmd/soroban-cli/tests/fixtures/test-wasms/invoker_account_exists/src/lib.rs b/cmd/soroban-cli/tests/fixtures/test-wasms/invoker_account_exists/src/lib.rs deleted file mode 100644 index 22106057..00000000 --- a/cmd/soroban-cli/tests/fixtures/test-wasms/invoker_account_exists/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] -use soroban_sdk::{contracterror, contractimpl, panic_with_error, Address, Env}; - -#[contracterror] -#[derive(Copy, Clone)] -#[repr(u32)] -pub enum Error { - InvokerIsContract = 1, -} - -pub struct Contract; - -#[contractimpl] -impl Contract { - pub fn invkexists(env: Env) -> bool { - match env.invoker() { - Address::Account(account_id) => env.accounts().get(&account_id).is_some(), - Address::Contract(_) => panic_with_error!(&env, Error::InvokerIsContract), - } - } -} - -#[cfg(test)] -mod test { - use soroban_sdk::{testutils::Accounts, Env}; - - use crate::{Contract, ContractClient}; - - #[test] - fn test_invoker() { - let env = Env::default(); - let contract_id = env.register_contract(None, Contract); - let client = ContractClient::new(&env, &contract_id); - - let addr = env.accounts().generate(); - let exists = client.with_source_account(&addr).invkexists(); - assert!(exists); - } -} diff --git a/cmd/soroban-rpc/internal/methods/simulate_transaction.go b/cmd/soroban-rpc/internal/methods/simulate_transaction.go index e25a5b5d..d674be90 100644 --- a/cmd/soroban-rpc/internal/methods/simulate_transaction.go +++ b/cmd/soroban-rpc/internal/methods/simulate_transaction.go @@ -97,16 +97,17 @@ type SimulateTransactionCost struct { MemoryBytes uint64 `json:"memBytes,string"` } -type InvokeHostFunctionResult struct { - XDR string `json:"xdr"` +type SimulateTransactionResult struct { + Auth []string `json:"auth"` + Footprint string `json:"footprint"` + XDR string `json:"xdr"` } type SimulateTransactionResponse struct { - Error string `json:"error,omitempty"` - Results []InvokeHostFunctionResult `json:"results,omitempty"` - Footprint string `json:"footprint"` - Cost SimulateTransactionCost `json:"cost"` - LatestLedger int64 `json:"latestLedger,string"` + Error string `json:"error,omitempty"` + Results []SimulateTransactionResult `json:"results,omitempty"` + Cost SimulateTransactionCost `json:"cost"` + LatestLedger int64 `json:"latestLedger,string"` } // NewSimulateTransactionHandler returns a json rpc handler to run preflight simulations @@ -199,9 +200,30 @@ func NewSimulateTransactionHandler(logger *log.Entry, networkPassphrase string, } } + // Get the auth data + var auth []string + if res.auth != nil { + + // CGo doesn't have an easy way to do pointer arithmetic so, + // we are better off transforming the memory buffer into a large slice + // and finding the NULL termination after that + for _, a := range unsafe.Slice(res.auth, 1<<20) { + if a == nil { + // we found the ending nil + break + } + auth = append(auth, C.GoString(a)) + } + } + return SimulateTransactionResponse{ - Results: []InvokeHostFunctionResult{{XDR: C.GoString(res.result)}}, - Footprint: C.GoString(res.preflight), + Results: []SimulateTransactionResult{ + { + Auth: auth, + Footprint: C.GoString(res.preflight), + XDR: C.GoString(res.result), + }, + }, Cost: SimulateTransactionCost{ CPUInstructions: uint64(res.cpu_instructions), MemoryBytes: uint64(res.memory_bytes), diff --git a/cmd/soroban-rpc/internal/test/docker-compose.yml b/cmd/soroban-rpc/internal/test/docker-compose.yml index 34655fb7..dd74d83f 100644 --- a/cmd/soroban-rpc/internal/test/docker-compose.yml +++ b/cmd/soroban-rpc/internal/test/docker-compose.yml @@ -15,7 +15,7 @@ services: # Note: Please keep the image pinned to an immutable tag matching the Captive Core version. # This avoid implicit updates which break compatibility between # the Core container and captive core. - image: ${CORE_IMAGE:-sreuland/stellar-core:19.5.1-1137.b3a6bc281.focal-soroban} + image: ${CORE_IMAGE:-2opremio/stellar-core:19.7.1-1178.e352f0012.focal-soroban} depends_on: - core-postgres restart: on-failure diff --git a/cmd/soroban-rpc/internal/test/simulate_transaction_test.go b/cmd/soroban-rpc/internal/test/simulate_transaction_test.go index f8dd9607..5943e13f 100644 --- a/cmd/soroban-rpc/internal/test/simulate_transaction_test.go +++ b/cmd/soroban-rpc/internal/test/simulate_transaction_test.go @@ -210,13 +210,15 @@ func TestSimulateTransactionSucceeds(t *testing.T) { assert.Equal( t, methods.SimulateTransactionResponse{ - Footprint: "AAAAAAAAAAEAAAAH6p/Lga5Uop9rO/KThH0/1+mjaf0cgKyv7Gq9VxMX4MI=", Cost: methods.SimulateTransactionCost{ CPUInstructions: result.Cost.CPUInstructions, MemoryBytes: result.Cost.MemoryBytes, }, - Results: []methods.InvokeHostFunctionResult{ - {XDR: "AAAABAAAAAEAAAAGAAAAIOqfy4GuVKKfazvyk4R9P9fpo2n9HICsr+xqvVcTF+DC"}, + Results: []methods.SimulateTransactionResult{ + { + Footprint: "AAAAAAAAAAEAAAAH6p/Lga5Uop9rO/KThH0/1+mjaf0cgKyv7Gq9VxMX4MI=", + XDR: "AAAABAAAAAEAAAAGAAAAIOqfy4GuVKKfazvyk4R9P9fpo2n9HICsr+xqvVcTF+DC", + }, }, LatestLedger: result.LatestLedger, }, @@ -320,15 +322,50 @@ func TestSimulateInvokeContractTransactionSucceeds(t *testing.T) { contractID := getContractID(t, address, testSalt, StandaloneNetworkPassphrase) contractFnParameterSym := xdr.ScSymbol("world") - contractFnParameter := xdr.ScVal{ - Type: xdr.ScValTypeScvSymbol, - Sym: &contractFnParameterSym, + authAddrArg := "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H" + authAccountIDArg := xdr.MustAddress(authAddrArg) + tx, err = txnbuild.NewTransaction(txnbuild.TransactionParams{ + SourceAccount: &account, + IncrementSequenceNum: true, + Operations: []txnbuild.Operation{ + &txnbuild.CreateAccount{ + Destination: authAddrArg, + Amount: "100000", + SourceAccount: address, + }, + }, + BaseFee: txnbuild.MinBaseFee, + Preconditions: txnbuild.Preconditions{ + TimeBounds: txnbuild.NewInfiniteTimeout(), + }, + }) + assert.NoError(t, err) + sendSuccessfulTransaction(t, client, sourceAccount, tx) + addressObject := &xdr.ScObject{ + Type: xdr.ScObjectTypeScoAddress, + Address: &xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeAccount, + AccountId: &authAccountIDArg, + }, } tx, err = txnbuild.NewTransaction(txnbuild.TransactionParams{ SourceAccount: &account, IncrementSequenceNum: true, Operations: []txnbuild.Operation{ - createInvokeHostOperation(address, xdr.LedgerFootprint{}, contractID, "hello", contractFnParameter), + createInvokeHostOperation( + address, + xdr.LedgerFootprint{}, + contractID, + "auth", + xdr.ScVal{ + Type: xdr.ScValTypeScvObject, + Obj: &addressObject, + }, + xdr.ScVal{ + Type: xdr.ScValTypeScvSymbol, + Sym: &contractFnParameterSym, + }, + ), }, BaseFee: txnbuild.MinBaseFee, Preconditions: txnbuild.Preconditions{ @@ -345,18 +382,34 @@ func TestSimulateInvokeContractTransactionSucceeds(t *testing.T) { assert.NoError(t, err) assert.Empty(t, response.Error) + // check the result + assert.Len(t, response.Results, 1) + var obtainedResult xdr.ScVal + err = xdr.SafeUnmarshalBase64(response.Results[0].XDR, &obtainedResult) + assert.NoError(t, err) + assert.Equal(t, xdr.ScValTypeScvObject, obtainedResult.Type) + obj := *obtainedResult.Obj + assert.Equal(t, xdr.ScObjectTypeScoVec, obj.Type) + assert.Len(t, *obj.Vec, 2) + world := (*obj.Vec)[1] + assert.Equal(t, xdr.ScValTypeScvSymbol, world.Type) + assert.Equal(t, xdr.ScSymbol("world"), *world.Sym) + // check the footprint var obtainedFootprint xdr.LedgerFootprint - err = xdr.SafeUnmarshalBase64(response.Footprint, &obtainedFootprint) + err = xdr.SafeUnmarshalBase64(response.Results[0].Footprint, &obtainedFootprint) assert.NoError(t, err) - assert.Len(t, obtainedFootprint.ReadWrite, 0) - assert.Len(t, obtainedFootprint.ReadOnly, 2) - ro1 := obtainedFootprint.ReadOnly[0] + assert.Len(t, obtainedFootprint.ReadWrite, 1) + assert.Len(t, obtainedFootprint.ReadOnly, 3) + ro0 := obtainedFootprint.ReadOnly[0] + assert.Equal(t, xdr.LedgerEntryTypeAccount, ro0.Type) + assert.Equal(t, authAddrArg, ro0.Account.AccountId.Address()) + ro1 := obtainedFootprint.ReadOnly[1] assert.Equal(t, xdr.LedgerEntryTypeContractData, ro1.Type) assert.Equal(t, xdr.Hash(contractID), ro1.ContractData.ContractId) assert.Equal(t, xdr.ScValTypeScvStatic, ro1.ContractData.Key.Type) assert.Equal(t, xdr.ScStaticScsLedgerKeyContractCode, *ro1.ContractData.Key.Ic) - ro2 := obtainedFootprint.ReadOnly[1] + ro2 := obtainedFootprint.ReadOnly[2] assert.Equal(t, xdr.LedgerEntryTypeContractCode, ro2.Type) installContractCodeArgs, err := xdr.InstallContractCodeArgs{Code: helloWorldContract}.MarshalBinary() assert.NoError(t, err) @@ -364,19 +417,24 @@ func TestSimulateInvokeContractTransactionSucceeds(t *testing.T) { assert.Equal(t, xdr.Hash(contractHash), ro2.ContractCode.Hash) assert.NoError(t, err) - // check the result - assert.Len(t, response.Results, 1) - var obtainedResult xdr.ScVal - err = xdr.SafeUnmarshalBase64(response.Results[0].XDR, &obtainedResult) + // check the auth + assert.Len(t, response.Results[0].Auth, 1) + var obtainedAuth xdr.ContractAuth + err = xdr.SafeUnmarshalBase64(response.Results[0].Auth[0], &obtainedAuth) assert.NoError(t, err) - assert.Equal(t, xdr.ScValTypeScvObject, obtainedResult.Type) - obj := *obtainedResult.Obj - assert.Equal(t, xdr.ScObjectTypeScoVec, obj.Type) - assert.Len(t, *obj.Vec, 2) - world := (*obj.Vec)[1] + assert.Nil(t, obtainedAuth.SignatureArgs) + + assert.Equal(t, xdr.Uint64(0), obtainedAuth.AddressWithNonce.Nonce) + assert.Equal(t, xdr.ScAddressTypeScAddressTypeAccount, obtainedAuth.AddressWithNonce.Address.Type) + assert.Equal(t, authAddrArg, obtainedAuth.AddressWithNonce.Address.AccountId.Address()) + + assert.Equal(t, xdr.Hash(contractID), obtainedAuth.RootInvocation.ContractId) + assert.Equal(t, xdr.ScSymbol("auth"), obtainedAuth.RootInvocation.FunctionName) + assert.Len(t, obtainedAuth.RootInvocation.Args, 2) + world = obtainedAuth.RootInvocation.Args[1] assert.Equal(t, xdr.ScValTypeScvSymbol, world.Type) assert.Equal(t, xdr.ScSymbol("world"), *world.Sym) - + assert.Nil(t, obtainedAuth.RootInvocation.SubInvocations) } func TestSimulateTransactionError(t *testing.T) { diff --git a/cmd/soroban-rpc/lib/preflight.h b/cmd/soroban-rpc/lib/preflight.h index 5ac44e98..0956b5dd 100644 --- a/cmd/soroban-rpc/lib/preflight.h +++ b/cmd/soroban-rpc/lib/preflight.h @@ -15,6 +15,7 @@ typedef struct CPreflightResult { char *error; // Error string in case of error, otherwise null char *result; // SCVal XDR in base64 char *preflight; // LedgerFootprint XDR in base64 + char **auth; // NULL terminated array of XDR ContractAuths in base64 uint64_t cpu_instructions; uint64_t memory_bytes; } CPreflightResult; diff --git a/cmd/soroban-rpc/lib/preflight/Cargo.toml b/cmd/soroban-rpc/lib/preflight/Cargo.toml index 44263bde..d82a7c09 100644 --- a/cmd/soroban-rpc/lib/preflight/Cargo.toml +++ b/cmd/soroban-rpc/lib/preflight/Cargo.toml @@ -7,5 +7,6 @@ crate-type = ["staticlib"] [dependencies] libc = "0.2.2" +sha2 = "0.10.6" soroban-env-host = {workspace = true, features = ["vm"]} diff --git a/cmd/soroban-rpc/lib/preflight/src/lib.rs b/cmd/soroban-rpc/lib/preflight/src/lib.rs index 9e78c0b1..16650d60 100644 --- a/cmd/soroban-rpc/lib/preflight/src/lib.rs +++ b/cmd/soroban-rpc/lib/preflight/src/lib.rs @@ -1,23 +1,25 @@ extern crate libc; +extern crate sha2; extern crate soroban_env_host; +use sha2::{Digest, Sha256}; +use soroban_env_host::auth::RecordedAuthPayload; use soroban_env_host::budget::Budget; use soroban_env_host::storage::{self, AccessType, SnapshotSource, Storage}; use soroban_env_host::xdr::ScUnknownErrorCode::{General, Xdr}; use soroban_env_host::xdr::{ - self, AccountId, HostFunction, LedgerEntry, LedgerKey, ReadXdr, ScHostStorageErrorCode, - ScStatus, WriteXdr, + self, AccountId, AddressWithNonce, ContractAuth, HostFunction, LedgerEntry, LedgerKey, ReadXdr, + ScHostStorageErrorCode, ScStatus, WriteXdr, }; use soroban_env_host::{Host, HostError, LedgerInfo}; use std::convert::TryInto; -use std::error; use std::ffi::{CStr, CString}; use std::panic; use std::ptr::null_mut; use std::rc::Rc; +use std::{error, mem}; use xdr::LedgerFootprint; -// TODO: we may want to pass callbacks instead of using global functions extern "C" { // LedgerKey XDR in base64 string to LedgerEntry XDR in base64 string fn SnapshotSourceGet( @@ -82,11 +84,7 @@ impl From for LedgerInfo { protocol_version: c.protocol_version, sequence_number: c.sequence_number, timestamp: c.timestamp, - network_passphrase: network_passphrase_cstr - .to_str() - .unwrap() - .as_bytes() - .to_vec(), + network_id: Sha256::digest(network_passphrase_cstr.to_str().unwrap().as_bytes()).into(), base_reserve: c.base_reserve, } } @@ -114,6 +112,7 @@ pub struct CPreflightResult { pub error: *mut libc::c_char, // Error string in case of error, otherwise null pub result: *mut libc::c_char, // SCVal XDR in base64 pub footprint: *mut libc::c_char, // LedgerFootprint XDR in base64 + pub auth: *mut *mut libc::c_char, // NULL terminated array of XDR ContractAuths in base64 pub cpu_instructions: u64, pub memory_bytes: u64, } @@ -126,6 +125,7 @@ fn preflight_error(str: String) -> *mut CPreflightResult { error: c_str.into_raw(), result: null_mut(), footprint: null_mut(), + auth: null_mut(), cpu_instructions: 0, memory_bytes: 0, })) @@ -176,11 +176,13 @@ fn preflight_host_function_or_maybe_panic( let budget = Budget::default(); let host = Host::with_storage_and_budget(storage, budget); + host.switch_to_recording_auth(); host.set_source_account(source_account); host.set_ledger_info(ledger_info.into()); // Run the preflight. let result = host.invoke_function(hf)?; + let auth_payloads = host.get_recorded_auth_payloads()?; // Recover, convert and return the storage footprint and other values to C. let (storage, budget, _) = host.try_finish().unwrap(); @@ -192,11 +194,53 @@ fn preflight_host_function_or_maybe_panic( error: null_mut(), result: result_cstr.into_raw(), footprint: fp_cstr.into_raw(), + auth: recorded_auth_payloads_to_c(auth_payloads)?, cpu_instructions: budget.get_cpu_insns_count(), memory_bytes: budget.get_mem_bytes_count(), }) } +fn recorded_auth_payloads_to_c( + payloads: Vec, +) -> Result<*mut *mut libc::c_char, Box> { + // Get a vector of base64-encoded ContractAuths + let mut out_vec: Vec<*mut libc::c_char> = Vec::new(); + for p in payloads.iter() { + let c_str = CString::new(recorded_auth_payload_to_xdr(p).to_xdr_base64()?)?.into_raw(); + out_vec.push(c_str); + } + + // Add the ending NULL + out_vec.push(null_mut()); + + // Make sure length and capacity are the same + // (this allows using the length as the capacity when deallocating the vector) + out_vec.shrink_to_fit(); + assert!(out_vec.len() == out_vec.capacity()); + + // Get the pointer to our vector, we will deallocate it in free_preflight_result() + // TODO: replace by `out_vec.into_raw_parts()` once the API stabilizes + let ptr = out_vec.as_mut_ptr(); + mem::forget(out_vec); + + Ok(ptr) +} + +fn recorded_auth_payload_to_xdr(payload: &RecordedAuthPayload) -> ContractAuth { + let address_with_nonce = match (payload.address.clone(), payload.nonce) { + (Some(address), Some(nonce)) => Some(AddressWithNonce { address, nonce }), + // TODO: can the address and the nonce really be present independently? + _ => None, + }; + ContractAuth { + address_with_nonce, + root_invocation: payload.invocation.clone(), + // signature_args is left empty. This is where the client will put their signatures when + // submitting the transaction. + signature_args: Default::default(), + } +} + /// . /// /// # Safety @@ -217,6 +261,22 @@ pub unsafe extern "C" fn free_preflight_result(result: *mut CPreflightResult) { if !(*result).footprint.is_null() { let _ = CString::from_raw((*result).footprint); } + if !(*result).auth.is_null() { + // Iterate until we find a null value + let auth = (*result).auth; + let mut i: usize = 0; + loop { + let c_char_ptr = *(auth.offset(i as isize)); + if c_char_ptr.is_null() { + break; + } + // deallocate each base64 string + let _ = CString::from_raw(c_char_ptr); + i += 1; + } + // deallocate the containing vector + let _ = Vec::from_raw_parts(auth, i + 1, i + 1); + } let _ = Box::from_raw(result); } } diff --git a/go.mod b/go.mod index 51ee7e88..53beadd3 100644 --- a/go.mod +++ b/go.mod @@ -64,7 +64,7 @@ require ( github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94 // indirect github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431 // indirect github.com/spf13/pflag v0.0.0-20161005214240-4bd69631f475 // indirect - github.com/stellar/go v0.0.0-20230126104422-77cf2ca9d550 + github.com/stellar/go v0.0.0-20230202232356-8c3f4c0c23e9 github.com/stellar/go-xdr v0.0.0-20211103144802-8017fc4bdfee // indirect github.com/stretchr/objx v0.4.0 // indirect github.com/xanzy/ssh-agent v0.3.0 // indirect diff --git a/go.sum b/go.sum index bb95fa82..b8dacab7 100644 --- a/go.sum +++ b/go.sum @@ -169,8 +169,8 @@ github.com/spf13/pflag v0.0.0-20161005214240-4bd69631f475 h1:RtZIgreTwcayPTOw7G5 github.com/spf13/pflag v0.0.0-20161005214240-4bd69631f475/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v0.0.0-20150621231900-db7ff930a189 h1:fvB1AFbBd6SfI9Rd0ooAJp8uLkZDbZaLFHi7ZnNP6uI= github.com/spf13/viper v0.0.0-20150621231900-db7ff930a189/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= -github.com/stellar/go v0.0.0-20230126104422-77cf2ca9d550 h1:GTz5CZnj0dhXin0zyTt9jZixS6X0B/aDcNn7bkKt9IU= -github.com/stellar/go v0.0.0-20230126104422-77cf2ca9d550/go.mod h1:QXwuKmYVvqQZlByv0EeNb0Rgog9AP+eMmARcdt3h2rI= +github.com/stellar/go v0.0.0-20230202232356-8c3f4c0c23e9 h1:MztElpcOTUdgP/VbTuNnYKcR3vzLsab+ACRgezyilgo= +github.com/stellar/go v0.0.0-20230202232356-8c3f4c0c23e9/go.mod h1:QXwuKmYVvqQZlByv0EeNb0Rgog9AP+eMmARcdt3h2rI= github.com/stellar/go-xdr v0.0.0-20211103144802-8017fc4bdfee h1:fbVs0xmXpBvVS4GBeiRmAE3Le70ofAqFMch1GTiq/e8= github.com/stellar/go-xdr v0.0.0-20211103144802-8017fc4bdfee/go.mod h1:yoxyU/M8nl9LKeWIoBrbDPQ7Cy+4jxRcWcOayZ4BMps= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=