diff --git a/.gitmodules b/.gitmodules index 4d03193577..83ff73dd7c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,8 +25,8 @@ ignore = dirty [submodule "src/protocol-curr/xdr"] path = src/protocol-curr/xdr - url = https://github.com/stellar/stellar-xdr - branch = main + url = https://github.com/sisuresh/stellar-xdr-next.git + branch = p28-cap-0084 [submodule "src/rust/soroban/p21"] path = src/rust/soroban/p21 url = https://github.com/stellar/rs-soroban-env @@ -51,7 +51,8 @@ url = https://github.com/stellar/rs-soroban-env.git [submodule "src/rust/soroban/p28"] path = src/rust/soroban/p28 - url = https://github.com/stellar/rs-soroban-env.git + url = https://github.com/sisuresh/rs-soroban-env.git + branch = p28-cap-0084 [submodule "lib/gperftools"] path = lib/gperftools url = https://github.com/gperftools/gperftools.git diff --git a/Cargo.lock b/Cargo.lock index 06960d3b71..a21b9f9d11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1452,7 +1452,7 @@ dependencies = [ [[package]] name = "soroban-builtin-sdk-macros" version = "27.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=883fd56374fc619afaa4c4c7489563555b7173f2#883fd56374fc619afaa4c4c7489563555b7173f2" +source = "git+https://github.com/sisuresh/rs-soroban-env?rev=0df250f37aaae74e210c9016583c943fecdaba42#0df250f37aaae74e210c9016583c943fecdaba42" dependencies = [ "itertools 0.13.0", "proc-macro2", @@ -1570,16 +1570,16 @@ dependencies = [ [[package]] name = "soroban-env-common" version = "27.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=883fd56374fc619afaa4c4c7489563555b7173f2#883fd56374fc619afaa4c4c7489563555b7173f2" +source = "git+https://github.com/sisuresh/rs-soroban-env?rev=0df250f37aaae74e210c9016583c943fecdaba42#0df250f37aaae74e210c9016583c943fecdaba42" dependencies = [ "crate-git-revision 0.0.9", "ethnum", "num-derive", "num-traits", - "soroban-env-macros 27.0.0 (git+https://github.com/stellar/rs-soroban-env?rev=883fd56374fc619afaa4c4c7489563555b7173f2)", + "soroban-env-macros 27.0.0 (git+https://github.com/sisuresh/rs-soroban-env?rev=0df250f37aaae74e210c9016583c943fecdaba42)", "soroban-wasmi", "static_assertions", - "stellar-xdr 27.0.0", + "stellar-xdr 28.0.0", "wasmparser", ] @@ -1811,7 +1811,7 @@ dependencies = [ [[package]] name = "soroban-env-host" version = "27.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=883fd56374fc619afaa4c4c7489563555b7173f2#883fd56374fc619afaa4c4c7489563555b7173f2" +source = "git+https://github.com/sisuresh/rs-soroban-env?rev=0df250f37aaae74e210c9016583c943fecdaba42#0df250f37aaae74e210c9016583c943fecdaba42" dependencies = [ "ark-bls12-381 0.5.0", "ark-bn254 0.5.0", @@ -1836,8 +1836,8 @@ dependencies = [ "sec1", "sha2", "sha3", - "soroban-builtin-sdk-macros 27.0.0 (git+https://github.com/stellar/rs-soroban-env?rev=883fd56374fc619afaa4c4c7489563555b7173f2)", - "soroban-env-common 27.0.0 (git+https://github.com/stellar/rs-soroban-env?rev=883fd56374fc619afaa4c4c7489563555b7173f2)", + "soroban-builtin-sdk-macros 27.0.0 (git+https://github.com/sisuresh/rs-soroban-env?rev=0df250f37aaae74e210c9016583c943fecdaba42)", + "soroban-env-common 27.0.0 (git+https://github.com/sisuresh/rs-soroban-env?rev=0df250f37aaae74e210c9016583c943fecdaba42)", "soroban-wasmi", "static_assertions", "stellar-strkey 0.0.13", @@ -1967,14 +1967,14 @@ dependencies = [ [[package]] name = "soroban-env-macros" version = "27.0.0" -source = "git+https://github.com/stellar/rs-soroban-env?rev=883fd56374fc619afaa4c4c7489563555b7173f2#883fd56374fc619afaa4c4c7489563555b7173f2" +source = "git+https://github.com/sisuresh/rs-soroban-env?rev=0df250f37aaae74e210c9016583c943fecdaba42#0df250f37aaae74e210c9016583c943fecdaba42" dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", "serde", "serde_json", - "stellar-xdr 27.0.0", + "stellar-xdr 28.0.0", "syn 2.0.39", ] @@ -2075,7 +2075,7 @@ dependencies = [ "soroban-env-host 24.0.0", "soroban-env-host 25.0.0", "soroban-env-host 26.0.0", - "soroban-env-host 27.0.0 (git+https://github.com/stellar/rs-soroban-env?rev=883fd56374fc619afaa4c4c7489563555b7173f2)", + "soroban-env-host 27.0.0 (git+https://github.com/sisuresh/rs-soroban-env?rev=0df250f37aaae74e210c9016583c943fecdaba42)", "soroban-env-host 27.0.0 (git+https://github.com/stellar/rs-soroban-env?rev=b03d2563f3a08d51095a19bdbb6d90364b8ce04a)", "soroban-fuzz-targets", "soroban-synth-wasm", @@ -2234,6 +2234,20 @@ dependencies = [ "stellar-strkey 0.0.13", ] +[[package]] +name = "stellar-xdr" +version = "28.0.0" +source = "git+https://github.com/sisuresh/rs-stellar-xdr?rev=3d2ad659a3a285aae9543069ee18cb6245a427ce#3d2ad659a3a285aae9543069ee18cb6245a427ce" +dependencies = [ + "base64 0.22.1", + "crate-git-revision 0.0.9", + "escape-bytes", + "ethnum", + "hex", + "sha2", + "stellar-strkey 0.0.13", +] + [[package]] name = "subtle" version = "2.6.1" diff --git a/common.mk b/common.mk index 5efaefbaff..f8cc2050f6 100644 --- a/common.mk +++ b/common.mk @@ -49,4 +49,8 @@ endif # ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION if CAP_0083 AM_CPPFLAGS += -DCAP_0083 +endif + +if CAP_0084_MUXED_CONTRACT +AM_CPPFLAGS += -DCAP_0084_MUXED_CONTRACT endif \ No newline at end of file diff --git a/configure.ac b/configure.ac index 01ed39746e..4e4b456394 100644 --- a/configure.ac +++ b/configure.ac @@ -584,6 +584,9 @@ AM_CONDITIONAL(ENABLE_NEXT_PROTOCOL_VERSION_UNSAFE_FOR_PRODUCTION, AM_CONDITIONAL(CAP_0083, [test x$enable_next_protocol_version_unsafe_for_production = xyes]) +AM_CONDITIONAL(CAP_0084_MUXED_CONTRACT, + [test x$enable_next_protocol_version_unsafe_for_production = xyes]) + AC_PATH_PROG(CARGO, cargo) if test x"$CARGO" = x; then AC_MSG_ERROR([cannot find cargo, needed for rust code]) diff --git a/src/Makefile.am b/src/Makefile.am index 678016666e..add8408a85 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -106,6 +106,9 @@ XDR_FEATURE_FLAGS = if CAP_0083 XDR_FEATURE_FLAGS += -DCAP_0083 endif +if CAP_0084_MUXED_CONTRACT +XDR_FEATURE_FLAGS += -DCAP_0084_MUXED_CONTRACT +endif SUFFIXES = .x .h .rs .x.h: @@ -221,6 +224,12 @@ endif WIP_SOROBAN_PROTOCOL= CARGO_XDR_FEATURE_FLAGS = +if CAP_0084_MUXED_CONTRACT +# CAP-0084 host code is gated on the per-cap leaf feature `cap_0084_muxed_contract` +# (rs-soroban-env#1700), which the umbrella `next` feature aggregates; building the +# p28 host with `next` enables it and pulls in the matching stellar-xdr XDR variant. +CARGO_XDR_FEATURE_FLAGS += --features next +endif if ENABLE_NEXT_PROTOCOL_VERSION_UNSAFE_FOR_PRODUCTION ALL_SOROBAN_PROTOCOLS+=$(WIP_SOROBAN_PROTOCOL) diff --git a/src/ledger/LedgerHashUtils.h b/src/ledger/LedgerHashUtils.h index b9748d5935..4c394b7e05 100644 --- a/src/ledger/LedgerHashUtils.h +++ b/src/ledger/LedgerHashUtils.h @@ -128,6 +128,12 @@ template <> class hash stellar::hashMix( res, std::hash()(addr.liquidityPoolId())); break; +#ifdef CAP_0084_MUXED_CONTRACT + case stellar::SC_ADDRESS_TYPE_MUXED_CONTRACT: + stellar::hashMix( + res, stellar::shortHash::xdrComputeHash(addr.muxedContract())); + break; +#endif } return res; } diff --git a/src/protocol-curr/xdr b/src/protocol-curr/xdr index 68fa1ac556..787382ef20 160000 --- a/src/protocol-curr/xdr +++ b/src/protocol-curr/xdr @@ -1 +1 @@ -Subproject commit 68fa1ac55692f68ad2a2ca549d0a283273554439 +Subproject commit 787382ef2099cca168ca1cb282730d6b7b9e2f16 diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 307ba48a6d..ef6b4aba02 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -116,9 +116,9 @@ tracy-client = { version = "=0.17.0", features = [ [dependencies.soroban-env-host-p28] version = "=27.0.0" -git = "https://github.com/stellar/rs-soroban-env" +git = "https://github.com/sisuresh/rs-soroban-env" package = "soroban-env-host" -rev = "883fd56374fc619afaa4c4c7489563555b7173f2" +rev = "0df250f37aaae74e210c9016583c943fecdaba42" optional = true features = ["next"] diff --git a/src/rust/soroban/p28 b/src/rust/soroban/p28 index 883fd56374..0df250f37a 160000 --- a/src/rust/soroban/p28 +++ b/src/rust/soroban/p28 @@ -1 +1 @@ -Subproject commit 883fd56374fc619afaa4c4c7489563555b7173f2 +Subproject commit 0df250f37aaae74e210c9016583c943fecdaba42 diff --git a/src/rust/src/dep-trees/p28-expect.txt b/src/rust/src/dep-trees/p28-expect.txt index 2ccc9a9ba3..e6ad41d338 100644 --- a/src/rust/src/dep-trees/p28-expect.txt +++ b/src/rust/src/dep-trees/p28-expect.txt @@ -259,7 +259,7 @@ soroban-env-host v27.0.0 (src/rust/soroban/p28/soroban-env-host) │ │ │ ├── itoa v1.0.6 │ │ │ ├── ryu v1.0.13 │ │ │ └── serde v1.0.192 (*) -│ │ ├── stellar-xdr v27.0.0 +│ │ ├── stellar-xdr v28.0.0 (https://github.com/sisuresh/rs-stellar-xdr?rev=3d2ad659a3a285aae9543069ee18cb6245a427ce#3d2ad659) │ │ │ ├── escape-bytes v0.1.1 │ │ │ ├── ethnum v1.5.3 │ │ │ ├── hex v0.4.3 @@ -272,7 +272,10 @@ soroban-env-host v27.0.0 (src/rust/soroban/p28/soroban-env-host) │ │ │ ├── serde_derive v1.0.192 (proc-macro) (*) │ │ │ └── serde_json v1.0.108 (*) │ │ │ [build-dependencies] -│ │ │ └── crate-git-revision v0.0.6 (*) +│ │ │ └── crate-git-revision v0.0.9 +│ │ │ ├── serde v1.0.192 (*) +│ │ │ ├── serde_derive v1.0.192 (proc-macro) (*) +│ │ │ └── serde_json v1.0.108 (*) │ │ └── syn v2.0.39 (*) │ ├── soroban-wasmi v0.31.1-soroban.20.0.1 (https://github.com/stellar/wasmi?rev=0ed3f3dee30dc41ebe21972399e0a73a41944aa0#0ed3f3de) │ │ ├── smallvec v1.13.2 @@ -286,7 +289,7 @@ soroban-env-host v27.0.0 (src/rust/soroban/p28/soroban-env-host) │ │ └── wasmparser-nostd v0.100.2 │ │ └── indexmap-nostd v0.4.0 │ ├── static_assertions v1.1.0 -│ ├── stellar-xdr v27.0.0 +│ ├── stellar-xdr v28.0.0 (https://github.com/sisuresh/rs-stellar-xdr?rev=3d2ad659a3a285aae9543069ee18cb6245a427ce#3d2ad659) │ │ ├── base64 v0.22.1 │ │ ├── escape-bytes v0.1.1 │ │ ├── ethnum v1.5.3 @@ -294,17 +297,14 @@ soroban-env-host v27.0.0 (src/rust/soroban/p28/soroban-env-host) │ │ ├── sha2 v0.10.9 (*) │ │ └── stellar-strkey v0.0.13 (*) │ │ [build-dependencies] -│ │ └── crate-git-revision v0.0.6 (*) +│ │ └── crate-git-revision v0.0.9 (*) │ └── wasmparser v0.116.1 │ ├── indexmap v2.0.2 │ │ ├── equivalent v1.0.1 │ │ └── hashbrown v0.14.1 │ └── semver v1.0.17 │ [build-dependencies] -│ └── crate-git-revision v0.0.9 -│ ├── serde v1.0.192 (*) -│ ├── serde_derive v1.0.192 (proc-macro) (*) -│ └── serde_json v1.0.108 (*) +│ └── crate-git-revision v0.0.9 (*) ├── soroban-wasmi v0.31.1-soroban.20.0.1 (https://github.com/stellar/wasmi?rev=0ed3f3dee30dc41ebe21972399e0a73a41944aa0#0ed3f3de) (*) ├── static_assertions v1.1.0 ├── stellar-strkey v0.0.13 (*) diff --git a/src/rust/src/soroban_module_cache.rs b/src/rust/src/soroban_module_cache.rs index e8e0b221ed..46bc7901e3 100644 --- a/src/rust/src/soroban_module_cache.rs +++ b/src/rust/src/soroban_module_cache.rs @@ -14,6 +14,8 @@ // current-protocol cache as soon as we start, as well as the next-protocol // cache (if it exists) so that we can upgrade without stalling. +#[cfg(feature = "next")] +use crate::soroban_proto_all::p28; use crate::{ rust_bridge::CxxBuf, soroban_proto_all::{get_host_module_for_protocol, p27, protocol_agnostic}, @@ -22,9 +24,6 @@ use crate::{ #[cfg(not(feature = "fastdev"))] use crate::soroban_proto_all::{p23, p24, p25, p26}; -#[cfg(feature = "next")] -use crate::soroban_proto_all::p28; - pub(crate) struct SorobanModuleCache { #[cfg(not(feature = "fastdev"))] pub(crate) p23_cache: p23::soroban_proto_any::ProtocolSpecificModuleCache, diff --git a/src/transactions/test/InvokeHostFunctionTests.cpp b/src/transactions/test/InvokeHostFunctionTests.cpp index 9050c9d628..4e45317177 100644 --- a/src/transactions/test/InvokeHostFunctionTests.cpp +++ b/src/transactions/test/InvokeHostFunctionTests.cpp @@ -629,7 +629,14 @@ TEST_CASE("Stellar asset contract transfer with CAP-67 address types", SorobanTest test(cfg); auto& root = test.getRoot(); +#ifdef CAP_0084_MUXED_CONTRACT + // a1 makes several native transfers within a single run (100M + 300M + + // 400M for the muxed-contract case), so it needs enough balance to stay + // above its account reserve after all of them. + auto a1 = root.create("a1", 2'000'000'000); +#else auto a1 = root.create("a1", 1'000'000'000); +#endif auto a2 = root.create("a2", 1'000'000'000); Asset asset = makeAsset(root.getSecretKey(), "USDC"); a1.changeTrust(asset, 2'000'000'000); @@ -714,6 +721,45 @@ TEST_CASE("Stellar asset contract transfer with CAP-67 address types", a1, makeClaimableBalanceAddress(ClaimableBalanceID()), 1)); REQUIRE(client.lastEvent() == std::nullopt); } +#ifdef CAP_0084_MUXED_CONTRACT + { + INFO("transfer to muxed contract (CAP-0084)"); + // The destination is the SAC-transfer contract wrapped in a muxed + // contract address; the SAC de-muxes to the underlying contract for + // the balance and surfaces the id via the `to_muxed_id` event. + REQUIRE( + client.transfer(a1, + makeMuxedContractAddress( + transferContract.getAddress().contractId(), + 987'654'321'987'654'321ULL), + 400'000'000)); + REQUIRE(*client.lastEvent() == + client.makeTransferEvent( + a1Address, transferContract.getAddress(), 400'000'000, + 987'654'321'987'654'321ULL)); + } + if (!useNativeAsset) + { + INFO("mint to muxed contract (CAP-0084)"); + // Mint to a muxed-contract destination: the SAC de-muxes to the + // underlying contract for the balance (asserted inside mint() via + // the de-muxed getBalance) and surfaces the id via `to_muxed_id`. + // Native has no admin, so mint only applies to the issued asset. + uint64_t const toMuxId = 111'222'333'444'555'666ULL; + REQUIRE(client.mint( + root, + makeMuxedContractAddress( + transferContract.getAddress().contractId(), toMuxId), + 500'000'000)); + REQUIRE(*client.lastEvent() == + makeMintOrBurnEvent( + /*isMint=*/true, + client.getContract().getAddress().contractId(), + tokenAsset, transferContract.getAddress(), 500'000'000, + SCMapEntry(makeSymbolSCVal("to_muxed_id"), + makeU64(toMuxId)))); + } +#endif }; SECTION("native asset") @@ -7787,6 +7833,11 @@ TEST_CASE("Module cache across protocol versions", "[tx][soroban][modulecache]") // work-in-progress next host, in which case there _is_ a separate module // cache and the following line of code should be commented-out. // + // p28 (CAP-0084) ships its own work-in-progress next host with a separate + // module cache (see p28_cache in soroban_module_cache.rs), so the next + // protocol version _does_ add to the module cache count and the following + // line stays commented-out. + // // moduleCacheProtocolCount -= 1; #endif REQUIRE(app->getLedgerManager() diff --git a/src/transactions/test/SorobanTxTestUtils.cpp b/src/transactions/test/SorobanTxTestUtils.cpp index 4615593862..616cfff8b1 100644 --- a/src/transactions/test/SorobanTxTestUtils.cpp +++ b/src/transactions/test/SorobanTxTestUtils.cpp @@ -66,6 +66,33 @@ makeMuxedAccountAddress(AccountID const& accountID, uint64_t id) return addr; } +#ifdef CAP_0084_MUXED_CONTRACT +SCAddress +makeMuxedContractAddress(Hash const& contractId, uint64_t id) +{ + SCAddress addr(SC_ADDRESS_TYPE_MUXED_CONTRACT); + addr.muxedContract().contractId = contractId; + addr.muxedContract().id = id; + return addr; +} + +// CAP-0084: resolve a muxed contract address to its underlying contract id. +// The SAC keys balances on the underlying contract, so every balance +// key/value built from an SCAddress must de-mux first. Non-muxed-contract +// addresses are returned unchanged. +static SCAddress +demuxContractAddress(SCAddress const& addr) +{ + if (addr.type() == SC_ADDRESS_TYPE_MUXED_CONTRACT) + { + SCAddress c(SC_ADDRESS_TYPE_CONTRACT); + c.contractId() = addr.muxedContract().contractId; + return c; + } + return addr; +} +#endif + SCVal makeI32(int32_t i32) { @@ -1576,7 +1603,11 @@ LedgerKey AssetContractTestClient::makeContractDataBalanceKey(SCAddress const& addr) { SCVal val(SCV_ADDRESS); +#ifdef CAP_0084_MUXED_CONTRACT + val.address() = demuxContractAddress(addr); +#else val.address() = addr; +#endif LedgerKey balanceKey(CONTRACT_DATA); balanceKey.contractData().contract = mContract.getAddress(); @@ -1628,7 +1659,11 @@ int64_t AssetContractTestClient::getBalance(SCAddress const& addr) { SCVal val(SCV_ADDRESS); +#ifdef CAP_0084_MUXED_CONTRACT + val.address() = demuxContractAddress(addr); +#else val.address() = addr; +#endif return addr.type() == SC_ADDRESS_TYPE_ACCOUNT ? txtest::getBalance(mApp, addr.accountId(), mAsset) diff --git a/src/transactions/test/SorobanTxTestUtils.h b/src/transactions/test/SorobanTxTestUtils.h index b61d2d4043..2de6daf02e 100644 --- a/src/transactions/test/SorobanTxTestUtils.h +++ b/src/transactions/test/SorobanTxTestUtils.h @@ -19,6 +19,9 @@ namespace txtest SCAddress makeContractAddress(Hash const& hash); SCAddress makeMuxedAccountAddress(AccountID const& accountID, uint64_t id); +#ifdef CAP_0084_MUXED_CONTRACT +SCAddress makeMuxedContractAddress(Hash const& contractId, uint64_t id); +#endif SCVal makeI32(int32_t i32); SCVal makeI128(uint64_t u64); SCSymbol makeSymbol(std::string const& str); diff --git a/src/util/XDRCereal.cpp b/src/util/XDRCereal.cpp index 596831f71a..fb499feb5f 100644 --- a/src/util/XDRCereal.cpp +++ b/src/util/XDRCereal.cpp @@ -59,6 +59,19 @@ cereal_override(cereal::JSONOutputArchive& ar, stellar::SCAddress const& addr, addr.liquidityPoolId().data(), addr.liquidityPoolId().size())), field); return; +#ifdef CAP_0084_MUXED_CONTRACT + case stellar::SC_ADDRESS_TYPE_MUXED_CONTRACT: + ar.setNextName(field); + ar.startNode(); + xdr::archive(ar, addr.muxedContract().id, "id"); + xdr::archive(ar, + stellar::strKey::toStrKey(stellar::strKey::STRKEY_CONTRACT, + addr.muxedContract().contractId) + .value, + "contractId"); + ar.finishNode(); + return; +#endif default: // Unknown address type - serialize as "Unknown(type_id)" xdr::archive(ar, diff --git a/test-tx-meta-baseline-next/InvokeHostFunctionTests.json b/test-tx-meta-baseline-next/InvokeHostFunctionTests.json index f1c1e2b3f4..80085b5c43 100644 --- a/test-tx-meta-baseline-next/InvokeHostFunctionTests.json +++ b/test-tx-meta-baseline-next/InvokeHostFunctionTests.json @@ -1359,19 +1359,19 @@ "Stellar asset contract transfer with CAP-67 address types" : [ "+cR3oq2qY0I=", - "Rs/PGnv73JY=", - "10hZi1wChI0=", - "NjESxGWSAbY=", + "nf41aXcp3cc=", + "OtySRiV3oo0=", + "+WE3Fz5pS1M=", "bFkjDfabs9w=", - "N+Zof/XqwL8=", - "g6OoL0u5VkM=", + "EhSVUb6F5Q8=", + "c3zLocFSVRo=", "+cR3oq2qY0I=", - "Rs/PGnv73JY=", - "10hZi1wChI0=", - "NjESxGWSAbY=", + "nf41aXcp3cc=", + "OtySRiV3oo0=", + "+WE3Fz5pS1M=", "bFkjDfabs9w=", - "N+Zof/XqwL8=", - "g6OoL0u5VkM=" + "EhSVUb6F5Q8=", + "c3zLocFSVRo=" ], "Trustline stellar asset contract|protocol version 20" : [