Repository navigation
feat(admin): implement submit_upgrade_proposal for multi-sig WASM upgrades - #778
Open
odusanya03 wants to merge 6 commits into
Open
odusanya03 wants to merge 6 commits into
odusanya03 wants to merge 6 commits into
Conversation
|
@odusanya03 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
|
fix conflicts @odusanya03 |
…rades Resolves BCPathway#653 (epic: Multi-Sig Gated WASM Upgrades). Adds submit_upgrade_proposal to the admin access-control module. An authorized admin-pool member submits the 32-byte hash of a new WASM binary together with a non-empty description; the proposal is assigned a unique auto-incrementing ID from its own counter and saved to instance storage under AdminKey::UpgradeProposal(id). The creator is recorded as the first approval, mirroring create_proposal semantics. - New UpgradeProposal contracttype stored separately from Proposal so the encoding of already-persisted generic proposals stays stable (contracttype structs encode fields by name). - Appended AdminKey::UpgradeProposal(u64)/UpgradeProposalIdCounter and four ABI-stable AdminError variants: InvalidWasmHash (7), UpgradeProposalNotFound (8), NotAdminPoolMember (9), EmptyDescription (10). Input validation returns typed errors instead of panicking; the all-zero WASM-hash sentinel is rejected. - Emits upg_prop (proposal_id, creator, new_wasm_hash) via emit_upgrade_proposal_submitted. - Adds get_upgrade_proposal typed getter for downstream approve/ execute issues (BCPathway#654/BCPathway#655). - 11 new unit tests covering happy paths, unique IDs, creator auto- approval, fallback pool, TTL extension across ledger advances, event shape, and every error state. cargo fmt/clippy -D warnings clean; cargo test --all green.
p3ris0n
force-pushed
the
Implement-submit_upgrade_proposal-function
branch
from
October 21, 2026 10:18
6050aa9 to
1efbd1e
Compare
… and Storybook SDK stub
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #653
Summary
Implements
submit_upgrade_proposalin the admin access-control module (contracts/admin), the core submission step of the Multi-Sig Gated WASM Upgrades epic. An authorized admin-pool member can now submit the 32-byte hash of a new WASM binary together with a description; the proposal is assigned a unique auto-incrementing ID and saved to storage, ready for the downstreamapprove_upgrade(#654) andexecute_upgrade(#655) issues.Changes
New entry points (
contracts/admin/src/lib.rs)submit_upgrade_proposal(env, creator, new_wasm_hash, description) -> Result<u64, AdminError>Address::require_auth) — holding pool membership alone is not enough.AdminError::InvalidAddress[admin]pool)AdminError::NotAdminPoolMemberAdminError::InvalidWasmHashAdminError::EmptyDescriptionUpgradeProposalIdCounter(starts at0, increments once per submission, never reused) so generic and upgrade proposal IDs never collide.AdminKey::UpgradeProposal(id)and extends the instance TTL.create_proposalsemantics ([Core] Implementapprove_upgradefunction #654'sapprove_upgradecan build directly on this).get_upgrade_proposal(env, proposal_id) -> Result<UpgradeProposal, AdminError>— typed getter that reports missing proposals viaUpgradeProposalNotFoundrather than panicking; gives [Core] Implementapprove_upgradefunction #654/[Core] Implementexecute_upgradefunction #655 a read API.State
#[contracttype]structUpgradeProposal { creator, new_wasm_hash: BytesN<32>, description, approvals, executed }, stored under appendedAdminKey::UpgradeProposal(u64)/AdminKey::UpgradeProposalIdCountervariants (append-only, preserving existing discriminants).Proposal:#[contracttype]structs encode field-by-name, so extendingProposalin place would break decoding of entries already persisted on-chain. This also matches how PR feat(admin): define MultiSig upgrade proposal state #777 scopes its state work.AdminErrorvariants appended (codes 7–10) per the module's append-only convention.Eventing (
contracts/admin/src/events.rs)emit_upgrade_proposal_submittedpublishing topicupg_propwith data(proposal_id, creator, new_wasm_hash).Docs
AdminErrorcode table (now includes previously undocumented codes 4–6), event table, and a new "WASM Upgrade Proposals" guarantees section.docs/ACCESS_CONTROL.md: added the two operations to the protected-operations table and a "WASM upgrade proposals" section, per its "update the operation table in the same pull request" rule.Tests
11 new unit tests in the admin crate (105 → 116), covering happy paths and every expected error state:
assigns_unique_incrementing_idssaves_proposal_to_storageexecuted == falseauto_approves_creatorworks_with_fallback_admin_poolset_admin_poolextends_ttl_across_ledger_advancesemits_upg_prop_event(id, creator, hash)payloadrejects_non_pool_memberErr(NotAdminPoolMember), no state writtenrejects_zero_address_creatorErr(InvalidAddress)rejects_zero_wasm_hashErr(InvalidWasmHash), rejected proposal consumes no IDrejects_empty_descriptionErr(EmptyDescription)get_..._rejects_nonexistentErr(UpgradeProposalNotFound)One test-suite quirk worth noting:
env.events().all()reflects only the most recent contract invocation in soroban-sdk v22, so the event test usesinit_storage(which emits nothing) before submitting — the same pattern the existing proposal tests use to "avoid extra event overhead".Acceptance criteria checklist
cargo fmt --all -- --check✅cargo clippy --all-targets --all-features -- -D warnings✅cargo test --all✅ (116 admin tests green)cargo build --workspace --exclude bc-forge-e2e-tests --target wasm32-unknown-unknown --release✅Out of scope (per the epic's issue breakdown)
approve_upgrade, [Core] Implementapprove_upgradefunction #654) and execution againstenv.deployer().update_current_contract_wasm(execute_upgrade, [Core] Implementexecute_upgradefunction #655)create_proposal's pool-membership gate so [Guards] Only Admin can submit upgrade proposals #664 can tighten it)