SPIKE: Protocol 28 (CAP-0085) - #1929
Conversation
…cutable_ref Pin stellar-xdr -> sisuresh/rs-stellar-xdr@e1170cd9 (stellar#553) and the three soroban-env crates -> sisuresh/rs-soroban-env@78026e8b (stellar#1704), both on fork branch p28-cap-0085. Enable the env 'next' feature (which aggregates cap_0085_executable_ref) and the stellar-xdr 'cap_0085_executable_ref' feature across the workspace; forward 'next' through soroban-sdk-macros' soroban-env-common. env.rs: import the new ExecutableTagObject host object (CAP-0085 adds it plus 3 host fns, surfaced via call_macro_with_all_host_functions!). testutils: bump default test ledger protocol 27 -> 28. cost_estimate: regenerate expect![] metering values for env 28. deny.toml: allow the sisuresh git source for the SPIKE pins. Regenerate top-level and fuzz Cargo.lock.
Regenerated by cargo test: default ledger protocol 27 -> 28 and the contractenvmetav0 interface-version stamp in embedded contract wasm.
…apshot from semver-checks ed25519-dalek 3.0.0 breaks the cargo-semver-checks baseline rustdoc build; the 27->28 bump is MAJOR so no semver signal is lost. Mirrors the CAP-0084 SPIKE workaround. Remove once ed25519-dalek 3.0.0 is yanked or capped.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Re-point the env crates from the sisuresh/rs-soroban-env fork (stellar#1704, never merged) to stellar/rs-soroban-env main at 358d8baf, which carries the merged CAP-85 host implementation (stellar#1703) and its follow-up test (stellar#1711). Re-point stellar-xdr from the sisuresh fork (stellar#553, closed) to stellar/rs-stellar-xdr at a90de0c0 -- exactly the rev rs-soroban-env pins -- so the git source stays unified across the graph with no [patch] redirect. Both revs self-report their versions, so the exact '=' constraints are restored. deny.toml's temporary 'sisuresh' allow-org entry is reverted to just ['stellar']; no git source outside the stellar org remains in Cargo.lock. cargo check -p soroban-sdk passes.
The pin bump alone left CAP-85 unreachable from contract code: soroban-sdk declares 'mod env' privately and does not re-export the internal Env trait, so create_executable_tag, create_external_ref_contract and update_current_contract_executable_ref had no public caller. Add ExecutableTag, wrapping ExecutableTagObject, constructible only via ExecutableTag::new -> create_executable_tag, matching the protocol rule that a tag may not be forged. It converts to and from Val so it can be used directly as a storage key, which is how the owner contract writes the executable reference entry. Add Deployer::update_current_contract_executable_ref and DeployerWithAddress::deploy_external_ref alongside their Wasm counterparts. Docs state the trust relationship explicitly: the owner of a referenced entry can substitute arbitrary code into every contract referring to it. CAP-85 flags this as documentation-only, since the protocol cannot enforce it. Verified: probe contract builds to wasm32v1-none and its import table carries l.h, l.i and l.j -- the three CAP-85 host functions.
The SPIKE enabled soroban-env-{common,guest,host}/next because at the time env
main was still protocol 27 and CAP-85's host functions, gated on
min_supported_protocol 28, were only reachable from the next protocol.
env main is now 28.0.0, so 'next' no longer selects protocol 28 -- it selects
29. LEDGER_PROTOCOL_VERSION in soroban-env-macros is 28 without the feature and
29 with it, and that value is baked into every contract's env meta. The result
was that contracts built with this SDK were rejected outright by a protocol-28
host:
HostError: Error(WasmVm, InvalidInput)
"contract protocol number is newer than host", 29
Dropping the feature makes contracts declare 28, and the CAP-85 host functions
remain available because they are part of protocol 28 now.
The stellar-xdr cap_0085_executable_ref feature is unrelated to this and stays:
it gates the XDR types, not the protocol number.
Verified against stellar/quickstart:nightly-next running protocol 28: upload
now succeeds where it previously failed simulation.
|
Pushed three commits productionizing this SPIKE, after using it to validate CAP-0085 end to end against
Every contract built from this branch as it stood was unusable on a p28 network. Dropping the feature makes contracts declare 28; the CAP-85 host functions stay available because they're part of protocol 28 now. The TestingValidated against a locally built Contracts build to Not run: this repo's own test suite — The CLI counterpart is stellar/stellar-cli#2659, which patches its |
auth::ContractExecutable is what the host hands a custom account's
__check_auth inside CreateContractHostFnContext, and it had only
Wasm(BytesN<32>). CAP-85 requires the new variant here specifically so custom
accounts can take the reference into account when authorizing a creation.
Without it no custom account can authorize an external-ref creation at all,
whatever policy it wants: __check_auth fails while deserializing its own
arguments, because "ExternalRef" is not among the discriminants it knows.
Verified on futurenet against a Wasm-only account:
Error(Value, MissingValue) -> VM call trapped with HostError
-> Error(Auth, InvalidAction)
which is also exactly the backwards-incompatibility CAP-85 documents for
accounts predating the change. An account built with this variant parses the
same context and decides on it: two accounts differing only in their trusted
owner produced AUTHORIZED and REJECTED respectively.
Shape follows the CAP -- ContractExecutableRef { owner: Address, tag: String }
-- and matches the wire form observed in both the recorded auth entry and the
executable_update event: SCVec([SCSymbol("ExternalRef"), SCMap([owner, tag])]).
StellarAsset is deliberately not added; it was already absent from this enum
before CAP-85 and is out of scope here.
The type carries export = false on the non-spec-shaking path, as its siblings
do, so contract specs and their snapshots are unaffected.
|
Pushed a fourth commit,
This turned out to be load-bearing rather than cosmetic. Verified on futurenet with a Wasm-only account (i.e. one written as it would have been before CAP-85) authorizing an external-ref creation: It fails while deserializing its own arguments, because That is also exactly the backwards-incompatibility CAP-85 documents:
An account built with the variant parses the same context and decides on it. Two accounts differing only in their stored trusted owner, evaluated in enforce mode:
Shape follows the CAP —
Not verified: this repo's test suite. ValidationWhole CAP-85 matrix re-run against futurenet (protocol 28, core |
Changes
stellar-xdr→sisuresh/rs-stellar-xdr@e1170cd9(Bump version to 0.0.4 #553) and the threesoroban-envcrates →sisuresh/rs-soroban-env@78026e8b(Update expanded test files missed in #1699 #1704), both on fork branchp28-cap-0085.nextfeature (aggregatescap_0085_executable_ref) + the xdrcap_0085_executable_reffeature across the workspace; forwardnextthroughsoroban-sdk-macros'soroban-env-common.env.rs: import the newExecutableTagObjecthost object (CAP-0085 adds it plus 3 host fns, surfaced via the auto-generatedEnvbindings — the only source change the build required).expect![]+ JSON test snapshots; regen top-level and fuzzCargo.lock.deny.toml: allow thesisureshgit source; semver-checks excludessoroban-sdk+soroban-ledger-snapshot(ed25519-dalek 3.0.0 baseline break, mirrors CAP-0084).Deferred
tests-expanded/*regeneration — needs linux cross-compile + host-dependent wasm bytes; adopt the+lines from the CI (linux) job log rather than regenerating on macOS.create_external_ref_contract/update_current_contract_executable_ref/create_executable_tag) — none required by build/tests; flagged for human review.stellar/revs once Bump version to 0.0.4 #553 / Update expanded test files missed in #1699 #1704 land.Upstream: stellar/rs-stellar-xdr#553, stellar/rs-soroban-env#1704 (canonical draft: stellar/rs-soroban-env#1703).
Downstream: handled in separate per-repo release passes.