From fb5ded6b5072b8040bb7046aac5329a9d641578b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:22:15 +0000 Subject: [PATCH 1/2] fix: enforce multi-sig upgrades with governance FSM - Implemented VeroCore Soroban contract with multi-sig upgrade logic. - Introduced Proposal FSM: Pending -> Approved -> Executed. - Enforced quorum and timelock for contract upgrades. - Added re-initialization protection to init. - Ensured require_auth on all administrative entry points. - Refactored audit hashing to use env.crypto() for WASM compatibility. - Restored and updated unit tests for all modules. Co-authored-by: gloskull <189399494+gloskull@users.noreply.github.com> --- Cargo.lock | 2 - engine-core/Cargo.toml | 2 - engine-core/src/audit.rs | 67 +- engine-core/src/circuit_breaker.rs | 40 +- engine-core/src/governance.rs | 21 +- engine-core/src/governance_tests.rs | 142 ++-- engine-core/src/lib.rs | 75 +- .../audit/tests/replay_is_rejected.1.json | 672 +++++++++++++++ .../audit/tests/valid_first_commitment.1.json | 423 +++++++++ .../tests/non_guardian_cannot_trip.1.json | 383 +++++++++ .../tests/trip_and_reset.1.json | 454 ++++++++++ .../test_circuit_breaker_halts_propose.1.json | 803 ++++++++++++++++++ ...test_proposal_lifecycle_and_upgrade.1.json | 407 +++++++++ .../tests/test_propose_unauthorized.1.json | 385 +++++++++ 14 files changed, 3727 insertions(+), 149 deletions(-) create mode 100644 engine-core/test_snapshots/audit/tests/replay_is_rejected.1.json create mode 100644 engine-core/test_snapshots/audit/tests/valid_first_commitment.1.json create mode 100644 engine-core/test_snapshots/circuit_breaker/tests/non_guardian_cannot_trip.1.json create mode 100644 engine-core/test_snapshots/circuit_breaker/tests/trip_and_reset.1.json create mode 100644 engine-core/test_snapshots/governance_tests/tests/test_circuit_breaker_halts_propose.1.json create mode 100644 engine-core/test_snapshots/governance_tests/tests/test_proposal_lifecycle_and_upgrade.1.json create mode 100644 engine-core/test_snapshots/governance_tests/tests/test_propose_unauthorized.1.json diff --git a/Cargo.lock b/Cargo.lock index 39c1b4e..065b5e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -430,8 +430,6 @@ dependencies = [ name = "engine-core" version = "0.1.0" dependencies = [ - "hex", - "sha2", "soroban-sdk", ] diff --git a/engine-core/Cargo.toml b/engine-core/Cargo.toml index 7422c2a..218d40a 100644 --- a/engine-core/Cargo.toml +++ b/engine-core/Cargo.toml @@ -9,8 +9,6 @@ crate-type = ["cdylib", "rlib"] [dependencies] soroban-sdk = { version = "21.0.0", features = ["testutils"] } -sha2 = { version = "0.10", default-features = false } -hex = { version = "0.4", default-features = false } [dev-dependencies] soroban-sdk = { version = "21.0.0", features = ["testutils"] } diff --git a/engine-core/src/audit.rs b/engine-core/src/audit.rs index 0774058..c99c821 100644 --- a/engine-core/src/audit.rs +++ b/engine-core/src/audit.rs @@ -4,16 +4,16 @@ //! Off-chain provers submit `StateCommitment`s; this module verifies ordering //! and hash integrity before they are persisted. -use soroban_sdk::{contracttype, panic_with_error, symbol_short, Env, Symbol}; -use sha2::{Digest, Sha256}; +use soroban_sdk::{contracterror, panic_with_error, symbol_short, Bytes, Env, Symbol}; use crate::types::StateCommitment; const KEY_SEQ: Symbol = symbol_short!("SEQ"); const KEY_PREV: Symbol = symbol_short!("PREV_H"); -#[contracttype] -#[derive(Copy, Clone)] +#[contracterror] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u32)] pub enum AuditError { ReplayedSequence = 1, HashMismatch = 2, @@ -21,12 +21,12 @@ pub enum AuditError { } /// Compute the SHA-256 commitment hash over (prev_hash ‖ sequence ‖ payload). -pub fn compute_commitment(prev_hash: &[u8; 32], sequence: u64, payload: &[u8]) -> [u8; 32] { - let mut h = Sha256::new(); - h.update(prev_hash); - h.update(sequence.to_be_bytes()); - h.update(payload); - h.finalize().into() +pub fn compute_commitment(env: &Env, prev_hash: &[u8; 32], sequence: u64, payload: &Bytes) -> [u8; 32] { + let mut data = Bytes::new(env); + data.append(&Bytes::from_array(env, prev_hash)); + data.append(&Bytes::from_array(env, &sequence.to_be_bytes())); + data.append(payload); + env.crypto().sha256(&data).to_array() } /// Validate and record a new `StateCommitment`. @@ -34,7 +34,7 @@ pub fn compute_commitment(prev_hash: &[u8; 32], sequence: u64, payload: &[u8]) - /// Panics if: /// - `commitment.sequence` ≤ last recorded sequence (replay guard) /// - `commitment.state_hash` doesn't match the expected derivation -pub fn validate_transition(env: &Env, commitment: &StateCommitment, payload: &[u8]) { +pub fn validate_transition(env: &Env, commitment: &StateCommitment, payload: &Bytes) { let last_seq: u64 = env.storage().instance().get(&KEY_SEQ).unwrap_or(0); if commitment.sequence <= last_seq { panic_with_error!(env, AuditError::ReplayedSequence); @@ -46,7 +46,7 @@ pub fn validate_transition(env: &Env, commitment: &StateCommitment, payload: &[u .get::(&KEY_PREV) .unwrap_or([0u8; 32]); - let expected = compute_commitment(&prev_hash, commitment.sequence, payload); + let expected = compute_commitment(env, &prev_hash, commitment.sequence, payload); let actual: [u8; 32] = commitment.state_hash.to_array(); if expected != actual { panic_with_error!(env, AuditError::HashMismatch); @@ -63,37 +63,56 @@ pub fn validate_transition(env: &Env, commitment: &StateCommitment, payload: &[u #[cfg(test)] mod tests { - use super::*; - use soroban_sdk::{testutils::Address as _, Address, BytesN, Env}; + use crate::VeroCore; + use crate::VeroCoreClient; + use crate::types::StateCommitment; + use soroban_sdk::{testutils::Address as _, Address, Bytes, BytesN, Env, vec}; + use super::compute_commitment; #[test] fn valid_first_commitment() { let env = Env::default(); - let payload = b"state_payload_v1"; - let hash = compute_commitment(&[0u8; 32], 1, payload); + env.mock_all_auths(); + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); + + let author = Address::generate(&env); + let signers = vec![&env, Address::generate(&env)]; + client.init(&signers, &1, &vec![&env]); + + let payload = Bytes::from_slice(&env, b"state_payload_v1"); + let hash = compute_commitment(&env, &[0u8; 32], 1, &payload); let c = StateCommitment { state_hash: BytesN::from_array(&env, &hash), sequence: 1, ledger: 100, - author: Address::generate(&env), + author: author.clone(), }; - validate_transition(&env, &c, payload); // must not panic + client.commit(&c, &payload); // must not panic } #[test] - #[should_panic] + #[should_panic(expected = "Error(Contract, #1)")] // ReplayedSequence fn replay_is_rejected() { let env = Env::default(); - let payload = b"payload"; - let hash = compute_commitment(&[0u8; 32], 1, payload); + env.mock_all_auths(); + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); + + let author = Address::generate(&env); + let signers = vec![&env, Address::generate(&env)]; + client.init(&signers, &1, &vec![&env]); + + let payload = Bytes::from_slice(&env, b"payload"); + let hash = compute_commitment(&env, &[0u8; 32], 1, &payload); let c = StateCommitment { state_hash: BytesN::from_array(&env, &hash), sequence: 1, ledger: 100, - author: Address::generate(&env), + author: author.clone(), }; - validate_transition(&env, &c, payload); - validate_transition(&env, &c, payload); // second call must panic + client.commit(&c, &payload); + client.commit(&c, &payload); // second call must panic } } diff --git a/engine-core/src/circuit_breaker.rs b/engine-core/src/circuit_breaker.rs index 34391de..7fe6e93 100644 --- a/engine-core/src/circuit_breaker.rs +++ b/engine-core/src/circuit_breaker.rs @@ -3,15 +3,16 @@ //! Only authorised guardians may open or close the breaker. //! All stateful entry-points must call `assert_closed` before proceeding. -use soroban_sdk::{contracttype, panic_with_error, symbol_short, vec, Address, Env, Symbol, Vec}; +use soroban_sdk::{contracterror, panic_with_error, symbol_short, vec, Address, Env, Symbol, Vec}; use crate::types::BreakerState; const KEY_STATE: Symbol = symbol_short!("CB_STATE"); const KEY_GUARDIAN: Symbol = symbol_short!("CB_GUARD"); -#[contracttype] -#[derive(Copy, Clone)] +#[contracterror] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u32)] pub enum BreakerError { CircuitOpen = 1, NotGuardian = 2, @@ -37,7 +38,6 @@ pub fn assert_closed(env: &Env) { /// Trip the breaker — halts the engine. Requires guardian auth. pub fn trip(env: &Env, guardian: &Address) { - guardian.require_auth(); require_guardian(env, guardian); set_state(env, BreakerState::Open); env.events().publish( @@ -48,7 +48,6 @@ pub fn trip(env: &Env, guardian: &Address) { /// Reset the breaker — resumes normal operation. Requires guardian auth. pub fn reset(env: &Env, guardian: &Address) { - guardian.require_auth(); require_guardian(env, guardian); set_state(env, BreakerState::Closed); env.events().publish( @@ -82,34 +81,37 @@ fn require_guardian(env: &Env, caller: &Address) { #[cfg(test)] mod tests { - use super::*; - use soroban_sdk::{testutils::Address as _, vec, Env}; + use crate::VeroCore; + use crate::VeroCoreClient; + use soroban_sdk::{testutils::Address as _, vec, Address, Env}; #[test] fn trip_and_reset() { let env = Env::default(); env.mock_all_auths(); - let g = Address::generate(&env); - init(&env, vec![&env, g.clone()]); - - assert_closed(&env); // should not panic - trip(&env, &g); + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); - let state: BreakerState = env.storage().instance().get(&KEY_STATE).unwrap(); - assert_eq!(state, BreakerState::Open); + let g = Address::generate(&env); + let signers = vec![&env, Address::generate(&env)]; + client.init(&signers, &1, &vec![&env, g.clone()]); - reset(&env, &g); - assert_closed(&env); // back to closed — no panic + client.trip(&g); + client.reset(&g); } #[test] - #[should_panic] + #[should_panic(expected = "Error(Contract, #2)")] // NotGuardian fn non_guardian_cannot_trip() { let env = Env::default(); env.mock_all_auths(); + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); + let g = Address::generate(&env); let rogue = Address::generate(&env); - init(&env, vec![&env, g.clone()]); - trip(&env, &rogue); + let signers = vec![&env, Address::generate(&env)]; + client.init(&signers, &1, &vec![&env, g.clone()]); + client.trip(&rogue); } } diff --git a/engine-core/src/governance.rs b/engine-core/src/governance.rs index e96ef16..ab5c30f 100644 --- a/engine-core/src/governance.rs +++ b/engine-core/src/governance.rs @@ -5,13 +5,13 @@ //! full approval and execution, giving stakeholders a veto window. //! //! ## Proposal State Machine -//! ``` -//! Pending ─ (on approve, threshold met) → Approved ─ (on execute, timelock elapsed) → Executed +//! ```text +//! Pending -> (on approve, threshold met) -> Approved -> (on execute, timelock elapsed) -> Executed //! ``` //! Invalid transitions trigger contract panics. use soroban_sdk::{ - contracttype, panic_with_error, symbol_short, vec, Address, Env, Map, Symbol, Vec, + contracterror, panic_with_error, symbol_short, vec, Address, Env, Map, Symbol, Vec, }; use crate::types::{Proposal, ProposalState}; @@ -19,11 +19,13 @@ use crate::types::{Proposal, ProposalState}; const KEY_PROPOSALS: Symbol = symbol_short!("PROPS"); const KEY_SIGNERS: Symbol = symbol_short!("SIGNERS"); const KEY_THRESH: Symbol = symbol_short!("THRESH"); +const KEY_NEXT_ID: Symbol = symbol_short!("NEXT_ID"); /// Ledgers to wait after full approval before execution (~1 hour on Stellar). const TIMELOCK_LEDGERS: u32 = 720; -#[contracttype] -#[derive(Copy, Clone)] +#[contracterror] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u32)] pub enum GovError { NotASigner = 1, AlreadyApproved = 2, @@ -35,9 +37,10 @@ pub enum GovError { /// Initialise governance with an ordered signer set and approval threshold. pub fn init(env: &Env, signers: Vec
, threshold: u32) { - assert!(threshold as usize <= signers.len(), "threshold > signer count"); + assert!(threshold <= signers.len(), "threshold > signer count"); env.storage().instance().set(&KEY_SIGNERS, &signers); env.storage().instance().set(&KEY_THRESH, &threshold); + env.storage().instance().set(&KEY_NEXT_ID, &1u64); let empty: Map = Map::new(env); env.storage().instance().set(&KEY_PROPOSALS, &empty); } @@ -52,6 +55,11 @@ pub fn propose(env: &Env, mut proposal: Proposal) -> u64 { if !signers.contains(&proposal.proposer) { panic_with_error!(env, GovError::NotASigner); } + + let id: u64 = env.storage().instance().get(&KEY_NEXT_ID).unwrap_or(1); + proposal.id = id; + env.storage().instance().set(&KEY_NEXT_ID, &(id + 1)); + // Initialize state to Pending proposal.state = ProposalState::Pending; @@ -130,4 +138,3 @@ pub fn execute(env: &Env, proposal_id: u64) -> Proposal { ); prop } - diff --git a/engine-core/src/governance_tests.rs b/engine-core/src/governance_tests.rs index db34b4e..5bbbd67 100644 --- a/engine-core/src/governance_tests.rs +++ b/engine-core/src/governance_tests.rs @@ -5,114 +5,68 @@ #[cfg(test)] mod tests { - use crate::governance::{self, GovError}; - use crate::types::{Proposal, ProposalState}; - use soroban_sdk::{BytesN, Env}; + use crate::VeroCore; + use crate::VeroCoreClient; + use soroban_sdk::{vec, Address, BytesN, Env}; - /// Test: Proposal starts in Pending state #[test] - fn test_proposal_initial_state_pending() { - // When a proposal is created, it should be in Pending state - // Verified in: governance::propose() → proposal.state = ProposalState::Pending - } + fn test_proposal_lifecycle_and_upgrade() { + let env = Env::default(); - /// Test: Pending → Approved transition on threshold met - #[test] - fn test_state_transition_pending_to_approved() { - // GIVEN: A proposal in Pending state with N-1 approvals - // WHEN: The Nth approval is received (threshold met) - // THEN: State should transition to Approved - // AND: "GOV/approved" event should be emitted - // Verified in: governance::approve() → state auto-transitions when threshold met - } + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); - /// Test: Approved → Executed transition on timelock expiry - #[test] - fn test_state_transition_approved_to_executed() { - // GIVEN: A proposal in Approved state - // AND: Current ledger >= unlock_ledger - // WHEN: execute() is called - // THEN: State should transition to Executed - // AND: "GOV/execute" event should be emitted - // Verified in: governance::execute() → prop.state = ProposalState::Executed - } + let signer1 =
::generate(&env); + let signer2 =
::generate(&env); + let signers = vec![&env, signer1.clone(), signer2.clone()]; + let threshold = 2; + let guardian =
::generate(&env); - /// Test: Rejecting approvals on Approved proposals (invalid transition) - #[test] - fn test_reject_approval_on_approved_proposal() { - // GIVEN: A proposal in Approved state - // WHEN: approve() is called on that proposal - // THEN: Must panic with InvalidStateTransition - // Verified in: governance::approve() → checks prop.state != Pending - } + client.init(&signers, &threshold, &vec![&env, guardian.clone()]); - /// Test: Rejecting execution of Pending proposals - #[test] - fn test_reject_execution_of_pending_proposal() { - // GIVEN: A proposal in Pending state (threshold not met) - // WHEN: execute() is called - // THEN: Must panic with InvalidStateTransition - // Verified in: governance::execute() → checks prop.state == Approved - } + let wasm_hash = BytesN::from_array(&env, &[1u8; 32]); - /// Test: Rejecting double-execution of Executed proposals - #[test] - fn test_reject_double_execution() { - // GIVEN: A proposal in Executed state - // WHEN: execute() is called again - // THEN: Must panic with InvalidStateTransition - // Verified in: governance::execute() → checks prop.state == Approved + // 1. Propose + env.mock_all_auths(); + let proposal_id = client.propose(&signer1, &wasm_hash); + assert_eq!(proposal_id, 1); } - /// Test: Rejecting approval of Executed proposals #[test] - fn test_reject_approval_of_executed_proposal() { - // GIVEN: A proposal in Executed state - // WHEN: approve() is called on that proposal - // THEN: Must panic with InvalidStateTransition - // Verified in: governance::approve() → checks prop.state == Pending - } + #[should_panic(expected = "Error(Contract, #1)")] // NotASigner + fn test_propose_unauthorized() { + let env = Env::default(); + env.mock_all_auths(); + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); - /// Test: Full lifecycle - Pending → Approved → Executed - #[test] - fn test_full_proposal_lifecycle() { - // GIVEN: A freshly created proposal (state = Pending) - // WHEN: Approvals are collected until threshold - // THEN: State transitions to Approved - // AND: "GOV/approved" event is emitted - // WHEN: Timelock expires and execute() is called - // THEN: State transitions to Executed - // AND: "GOV/execute" event is emitted - // All transitions are validated by governance module - } + let signer1 =
::generate(&env); + let signers = vec![&env, signer1.clone()]; + client.init(&signers, &1, &vec![&env]); - /// Test: Error code for invalid transitions - #[test] - fn test_invalid_transition_error_code() { - // InvalidStateTransition error code = 5 - // (replaces the removed AlreadyExecuted error) - // Verified in: GovError::InvalidStateTransition = 5 + let rogue =
::generate(&env); + client.propose(&rogue, &BytesN::from_array(&env, &[0u8; 32])); } - /// Test: Duplicate approval check still works after state changes #[test] - fn test_duplicate_approval_detection() { - // GIVEN: A proposal in Pending state with one approval from Alice - // WHEN: approve() is called again by Alice - // THEN: Must panic with AlreadyApproved (not state-related) - // Verified in: governance::approve() → checks approved_by.contains(signer) + fn test_circuit_breaker_halts_propose() { + let env = Env::default(); + env.mock_all_auths(); + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); + + let signer1 =
::generate(&env); + let guardian =
::generate(&env); + let signers = vec![&env, signer1.clone()]; + client.init(&signers, &1, &vec![&env, guardian.clone()]); + + client.trip(&guardian); + + let result = client.try_propose(&signer1, &BytesN::from_array(&env, &[0u8; 32])); + assert!(result.is_err()); + + client.reset(&guardian); + let id = client.propose(&signer1, &BytesN::from_array(&env, &[0u8; 32])); + assert_eq!(id, 1); } } - -/// State Transition Matrix (for documentation) -/// -/// | Current State | Operation | Target State | Allowed | Error | -/// |---|---|---|---|---| -/// | Pending | approve (< threshold) | Pending | Yes | — | -/// | Pending | approve (>= threshold) | Approved | Yes | — | -/// | Pending | execute | — | No | InvalidStateTransition | -/// | Approved | approve | — | No | InvalidStateTransition | -/// | Approved | execute (timelock OK) | Executed | Yes | — | -/// | Approved | execute (timelock active) | — | No | TimelockActive | -/// | Executed | approve | — | No | InvalidStateTransition | -/// | Executed | execute | — | No | InvalidStateTransition | diff --git a/engine-core/src/lib.rs b/engine-core/src/lib.rs index 8a19c8b..d4e36d3 100644 --- a/engine-core/src/lib.rs +++ b/engine-core/src/lib.rs @@ -1,4 +1,77 @@ +use soroban_sdk::{contract, contractimpl, symbol_short, Address, Bytes, BytesN, Env, Symbol, Vec}; + pub mod audit; -pub mod governance; pub mod circuit_breaker; +pub mod governance; pub mod types; + +#[cfg(test)] +mod governance_tests; + +const KEY_INIT: Symbol = symbol_short!("INIT"); + +use crate::types::{Proposal, StateCommitment}; + +#[contract] +pub struct VeroCore; + +#[contractimpl] +impl VeroCore { + /// Initialise the Vero Protocol engine. + pub fn init(env: Env, signers: Vec
, threshold: u32, guardians: Vec
) { + if env.storage().instance().has(&KEY_INIT) { + panic!("Already initialized"); + } + env.storage().instance().set(&KEY_INIT, &true); + + governance::init(&env, signers, threshold); + circuit_breaker::init(&env, guardians); + } + + /// Trip the breaker — halts the engine. Requires guardian auth. + pub fn trip(env: Env, guardian: Address) { + guardian.require_auth(); + circuit_breaker::trip(&env, &guardian); + } + + /// Reset the breaker — resumes normal operation. Requires guardian auth. + pub fn reset(env: Env, guardian: Address) { + guardian.require_auth(); + circuit_breaker::reset(&env, &guardian); + } + + /// Submit a new governance proposal. + pub fn propose(env: Env, proposer: Address, action_hash: BytesN<32>) -> u64 { + circuit_breaker::assert_closed(&env); + proposer.require_auth(); + let proposal = Proposal { + id: 0, // Assigned by governance module + action_hash, + proposer, + approved_by: Vec::new(&env), + state: types::ProposalState::Pending, + }; + governance::propose(&env, proposal) + } + + /// Record a signer's approval for `proposal_id`. + pub fn approve(env: Env, signer: Address, proposal_id: u64) { + circuit_breaker::assert_closed(&env); + signer.require_auth(); + governance::approve(&env, &signer, proposal_id); + } + + /// Execute a contract upgrade proposal. + pub fn upgrade(env: Env, proposal_id: u64) { + circuit_breaker::assert_closed(&env); + let prop = governance::execute(&env, proposal_id); + env.deployer().update_current_contract_wasm(prop.action_hash); + } + + /// Validate and record a new state transition. + pub fn commit(env: Env, commitment: StateCommitment, payload: Bytes) { + circuit_breaker::assert_closed(&env); + commitment.author.require_auth(); + audit::validate_transition(&env, &commitment, &payload); + } +} diff --git a/engine-core/test_snapshots/audit/tests/replay_is_rejected.1.json b/engine-core/test_snapshots/audit/tests/replay_is_rejected.1.json new file mode 100644 index 0000000..b59e9d3 --- /dev/null +++ b/engine-core/test_snapshots/audit/tests/replay_is_rejected.1.json @@ -0,0 +1,672 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "commit", + "args": [ + { + "map": [ + { + "key": { + "symbol": "author" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "ledger" + }, + "val": { + "u32": 100 + } + }, + { + "key": { + "symbol": "sequence" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "state_hash" + }, + "val": { + "bytes": "9dcbcf21a5a9d8a551075709cee7265d2abfe3225ee3646c7b12dcf93b79fd4e" + } + } + ] + }, + { + "bytes": "7061796c6f6164" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "PREV_H" + }, + "val": { + "bytes": "9dcbcf21a5a9d8a551075709cee7265d2abfe3225ee3646c7b12dcf93b79fd4e" + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [] + } + }, + { + "key": { + "symbol": "SEQ" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + { + "u32": 1 + }, + { + "vec": [] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "commit" + } + ], + "data": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "author" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "ledger" + }, + "val": { + "u32": 100 + } + }, + { + "key": { + "symbol": "sequence" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "state_hash" + }, + "val": { + "bytes": "9dcbcf21a5a9d8a551075709cee7265d2abfe3225ee3646c7b12dcf93b79fd4e" + } + } + ] + }, + { + "bytes": "7061796c6f6164" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "AUDIT" + }, + { + "symbol": "commit" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "bytes": "9dcbcf21a5a9d8a551075709cee7265d2abfe3225ee3646c7b12dcf93b79fd4e" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "commit" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "commit" + } + ], + "data": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "author" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "ledger" + }, + "val": { + "u32": 100 + } + }, + { + "key": { + "symbol": "sequence" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "state_hash" + }, + "val": { + "bytes": "9dcbcf21a5a9d8a551075709cee7265d2abfe3225ee3646c7b12dcf93b79fd4e" + } + } + ] + }, + { + "bytes": "7061796c6f6164" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 1 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "vec": [ + { + "string": "contract call failed" + }, + { + "symbol": "commit" + }, + { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "author" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "ledger" + }, + "val": { + "u32": 100 + } + }, + { + "key": { + "symbol": "sequence" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "state_hash" + }, + "val": { + "bytes": "9dcbcf21a5a9d8a551075709cee7265d2abfe3225ee3646c7b12dcf93b79fd4e" + } + } + ] + }, + { + "bytes": "7061796c6f6164" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/engine-core/test_snapshots/audit/tests/valid_first_commitment.1.json b/engine-core/test_snapshots/audit/tests/valid_first_commitment.1.json new file mode 100644 index 0000000..efd67a9 --- /dev/null +++ b/engine-core/test_snapshots/audit/tests/valid_first_commitment.1.json @@ -0,0 +1,423 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "commit", + "args": [ + { + "map": [ + { + "key": { + "symbol": "author" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "ledger" + }, + "val": { + "u32": 100 + } + }, + { + "key": { + "symbol": "sequence" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "state_hash" + }, + "val": { + "bytes": "31b5ccceb7b2eece59647ed1c647b5cd692422ef2e6043a4b514677cf35cfbb9" + } + } + ] + }, + { + "bytes": "73746174655f7061796c6f61645f7631" + } + ] + } + }, + "sub_invocations": [] + } + ] + ] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "PREV_H" + }, + "val": { + "bytes": "31b5ccceb7b2eece59647ed1c647b5cd692422ef2e6043a4b514677cf35cfbb9" + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [] + } + }, + { + "key": { + "symbol": "SEQ" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + { + "u32": 1 + }, + { + "vec": [] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "commit" + } + ], + "data": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "author" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "ledger" + }, + "val": { + "u32": 100 + } + }, + { + "key": { + "symbol": "sequence" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "state_hash" + }, + "val": { + "bytes": "31b5ccceb7b2eece59647ed1c647b5cd692422ef2e6043a4b514677cf35cfbb9" + } + } + ] + }, + { + "bytes": "73746174655f7061796c6f61645f7631" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "AUDIT" + }, + { + "symbol": "commit" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "bytes": "31b5ccceb7b2eece59647ed1c647b5cd692422ef2e6043a4b514677cf35cfbb9" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "commit" + } + ], + "data": "void" + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/engine-core/test_snapshots/circuit_breaker/tests/non_guardian_cannot_trip.1.json b/engine-core/test_snapshots/circuit_breaker/tests/non_guardian_cannot_trip.1.json new file mode 100644 index 0000000..741a909 --- /dev/null +++ b/engine-core/test_snapshots/circuit_breaker/tests/non_guardian_cannot_trip.1.json @@ -0,0 +1,383 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [] + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + { + "u32": 1 + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "trip" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 2 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 2 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 2 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 2 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 2 + } + } + ], + "data": { + "vec": [ + { + "string": "contract call failed" + }, + { + "symbol": "trip" + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 2 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/engine-core/test_snapshots/circuit_breaker/tests/trip_and_reset.1.json b/engine-core/test_snapshots/circuit_breaker/tests/trip_and_reset.1.json new file mode 100644 index 0000000..cd2a04f --- /dev/null +++ b/engine-core/test_snapshots/circuit_breaker/tests/trip_and_reset.1.json @@ -0,0 +1,454 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "trip", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "reset", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [] + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + { + "u32": 1 + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "trip" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "CB" + }, + { + "symbol": "tripped" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "trip" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "reset" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "CB" + }, + { + "symbol": "reset" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "reset" + } + ], + "data": "void" + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/engine-core/test_snapshots/governance_tests/tests/test_circuit_breaker_halts_propose.1.json b/engine-core/test_snapshots/governance_tests/tests/test_circuit_breaker_halts_propose.1.json new file mode 100644 index 0000000..a21e737 --- /dev/null +++ b/engine-core/test_snapshots/governance_tests/tests/test_circuit_breaker_halts_propose.1.json @@ -0,0 +1,803 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "trip", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "reset", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "propose", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + }, + "sub_invocations": [] + } + ] + ] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 2 + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [ + { + "key": { + "u64": 1 + }, + "val": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "action_hash" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "approved_by" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proposer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 0 + } + } + ] + }, + { + "u32": 720 + } + ] + } + } + ] + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + { + "u32": 1 + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "trip" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "CB" + }, + { + "symbol": "tripped" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "trip" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "propose" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 1 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "vec": [ + { + "string": "contract try_call failed" + }, + { + "symbol": "propose" + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "reset" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "CB" + }, + { + "symbol": "reset" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "reset" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "propose" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "GOV" + }, + { + "symbol": "propose" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "propose" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/engine-core/test_snapshots/governance_tests/tests/test_proposal_lifecycle_and_upgrade.1.json b/engine-core/test_snapshots/governance_tests/tests/test_proposal_lifecycle_and_upgrade.1.json new file mode 100644 index 0000000..c6884b4 --- /dev/null +++ b/engine-core/test_snapshots/governance_tests/tests/test_proposal_lifecycle_and_upgrade.1.json @@ -0,0 +1,407 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "propose", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + } + ] + } + }, + "sub_invocations": [] + } + ] + ] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 2 + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [ + { + "key": { + "u64": 1 + }, + "val": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "action_hash" + }, + "val": { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + } + }, + { + "key": { + "symbol": "approved_by" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proposer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 0 + } + } + ] + }, + { + "u32": 720 + } + ] + } + } + ] + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + { + "u32": 2 + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "propose" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "GOV" + }, + { + "symbol": "propose" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "propose" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/engine-core/test_snapshots/governance_tests/tests/test_propose_unauthorized.1.json b/engine-core/test_snapshots/governance_tests/tests/test_propose_unauthorized.1.json new file mode 100644 index 0000000..da6e697 --- /dev/null +++ b/engine-core/test_snapshots/governance_tests/tests/test_propose_unauthorized.1.json @@ -0,0 +1,385 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [] + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + { + "u32": 1 + }, + { + "vec": [] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "propose" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 1 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "vec": [ + { + "string": "contract call failed" + }, + { + "symbol": "propose" + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 1 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file From 464e226e00ebb59baa9c80e5c53cc94e113bc897 Mon Sep 17 00:00:00 2001 From: gloskull Date: Thu, 25 Jun 2026 22:50:30 +0100 Subject: [PATCH 2/2] fix: enforce multi-sig upgrade quorum --- engine-core/src/audit.rs | 31 +- engine-core/src/circuit_breaker.rs | 12 +- engine-core/src/governance.rs | 73 +- engine-core/src/governance_tests.rs | 62 +- engine-core/src/lib.rs | 3 +- engine-core/src/types.rs | 16 +- ..._reaches_wasm_update_after_timelock.1.json | 818 ++++++++++++ ...orum_before_timelock_or_wasm_update.1.json | 1097 +++++++++++++++++ 8 files changed, 2056 insertions(+), 56 deletions(-) create mode 100644 engine-core/test_snapshots/governance_tests/tests/quorum_approved_proposal_reaches_wasm_update_after_timelock.1.json create mode 100644 engine-core/test_snapshots/governance_tests/tests/upgrade_requires_quorum_before_timelock_or_wasm_update.1.json diff --git a/engine-core/src/audit.rs b/engine-core/src/audit.rs index c99c821..9adc457 100644 --- a/engine-core/src/audit.rs +++ b/engine-core/src/audit.rs @@ -8,20 +8,25 @@ use soroban_sdk::{contracterror, panic_with_error, symbol_short, Bytes, Env, Sym use crate::types::StateCommitment; -const KEY_SEQ: Symbol = symbol_short!("SEQ"); +const KEY_SEQ: Symbol = symbol_short!("SEQ"); const KEY_PREV: Symbol = symbol_short!("PREV_H"); #[contracterror] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum AuditError { - ReplayedSequence = 1, - HashMismatch = 2, + ReplayedSequence = 1, + HashMismatch = 2, AuthorUnauthorised = 3, } /// Compute the SHA-256 commitment hash over (prev_hash ‖ sequence ‖ payload). -pub fn compute_commitment(env: &Env, prev_hash: &[u8; 32], sequence: u64, payload: &Bytes) -> [u8; 32] { +pub fn compute_commitment( + env: &Env, + prev_hash: &[u8; 32], + sequence: u64, + payload: &Bytes, +) -> [u8; 32] { let mut data = Bytes::new(env); data.append(&Bytes::from_array(env, prev_hash)); data.append(&Bytes::from_array(env, &sequence.to_be_bytes())); @@ -63,11 +68,11 @@ pub fn validate_transition(env: &Env, commitment: &StateCommitment, payload: &By #[cfg(test)] mod tests { + use super::compute_commitment; + use crate::types::StateCommitment; use crate::VeroCore; use crate::VeroCoreClient; - use crate::types::StateCommitment; - use soroban_sdk::{testutils::Address as _, Address, Bytes, BytesN, Env, vec}; - use super::compute_commitment; + use soroban_sdk::{testutils::Address as _, vec, Address, Bytes, BytesN, Env}; #[test] fn valid_first_commitment() { @@ -85,9 +90,9 @@ mod tests { let c = StateCommitment { state_hash: BytesN::from_array(&env, &hash), - sequence: 1, - ledger: 100, - author: author.clone(), + sequence: 1, + ledger: 100, + author: author.clone(), }; client.commit(&c, &payload); // must not panic } @@ -108,9 +113,9 @@ mod tests { let hash = compute_commitment(&env, &[0u8; 32], 1, &payload); let c = StateCommitment { state_hash: BytesN::from_array(&env, &hash), - sequence: 1, - ledger: 100, - author: author.clone(), + sequence: 1, + ledger: 100, + author: author.clone(), }; client.commit(&c, &payload); client.commit(&c, &payload); // second call must panic diff --git a/engine-core/src/circuit_breaker.rs b/engine-core/src/circuit_breaker.rs index 7fe6e93..8fd05d1 100644 --- a/engine-core/src/circuit_breaker.rs +++ b/engine-core/src/circuit_breaker.rs @@ -7,20 +7,22 @@ use soroban_sdk::{contracterror, panic_with_error, symbol_short, vec, Address, E use crate::types::BreakerState; -const KEY_STATE: Symbol = symbol_short!("CB_STATE"); +const KEY_STATE: Symbol = symbol_short!("CB_STATE"); const KEY_GUARDIAN: Symbol = symbol_short!("CB_GUARD"); #[contracterror] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum BreakerError { - CircuitOpen = 1, - NotGuardian = 2, - AlreadyInState = 3, + CircuitOpen = 1, + NotGuardian = 2, + AlreadyInState = 3, } pub fn init(env: &Env, guardians: Vec
) { - env.storage().instance().set(&KEY_STATE, &BreakerState::Closed); + env.storage() + .instance() + .set(&KEY_STATE, &BreakerState::Closed); env.storage().instance().set(&KEY_GUARDIAN, &guardians); } diff --git a/engine-core/src/governance.rs b/engine-core/src/governance.rs index ab5c30f..3f9dd69 100644 --- a/engine-core/src/governance.rs +++ b/engine-core/src/governance.rs @@ -17,9 +17,9 @@ use soroban_sdk::{ use crate::types::{Proposal, ProposalState}; const KEY_PROPOSALS: Symbol = symbol_short!("PROPS"); -const KEY_SIGNERS: Symbol = symbol_short!("SIGNERS"); -const KEY_THRESH: Symbol = symbol_short!("THRESH"); -const KEY_NEXT_ID: Symbol = symbol_short!("NEXT_ID"); +const KEY_SIGNERS: Symbol = symbol_short!("SIGNERS"); +const KEY_THRESH: Symbol = symbol_short!("THRESH"); +const KEY_NEXT_ID: Symbol = symbol_short!("NEXT_ID"); /// Ledgers to wait after full approval before execution (~1 hour on Stellar). const TIMELOCK_LEDGERS: u32 = 720; @@ -27,17 +27,20 @@ const TIMELOCK_LEDGERS: u32 = 720; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u32)] pub enum GovError { - NotASigner = 1, - AlreadyApproved = 2, - ThresholdNotMet = 3, - TimelockActive = 4, + NotASigner = 1, + AlreadyApproved = 2, + ThresholdNotMet = 3, + TimelockActive = 4, InvalidStateTransition = 5, - ProposalNotFound = 6, + ProposalNotFound = 6, + InvalidThreshold = 7, } /// Initialise governance with an ordered signer set and approval threshold. pub fn init(env: &Env, signers: Vec
, threshold: u32) { - assert!(threshold <= signers.len(), "threshold > signer count"); + if threshold == 0 || threshold > signers.len() { + panic_with_error!(env, GovError::InvalidThreshold); + } env.storage().instance().set(&KEY_SIGNERS, &signers); env.storage().instance().set(&KEY_THRESH, &threshold); env.storage().instance().set(&KEY_NEXT_ID, &1u64); @@ -46,12 +49,19 @@ pub fn init(env: &Env, signers: Vec
, threshold: u32) { } fn load_proposals(env: &Env) -> Map { - env.storage().instance().get(&KEY_PROPOSALS).unwrap_or(Map::new(env)) + env.storage() + .instance() + .get(&KEY_PROPOSALS) + .unwrap_or(Map::new(env)) } /// Submit a new proposal. Returns the assigned proposal id. pub fn propose(env: &Env, mut proposal: Proposal) -> u64 { - let signers: Vec
= env.storage().instance().get(&KEY_SIGNERS).unwrap_or(vec![env]); + let signers: Vec
= env + .storage() + .instance() + .get(&KEY_SIGNERS) + .unwrap_or(vec![env]); if !signers.contains(&proposal.proposer) { panic_with_error!(env, GovError::NotASigner); } @@ -62,7 +72,7 @@ pub fn propose(env: &Env, mut proposal: Proposal) -> u64 { // Initialize state to Pending proposal.state = ProposalState::Pending; - + let mut props = load_proposals(env); let unlock_ledger = env.ledger().sequence() + TIMELOCK_LEDGERS; props.set(proposal.id, (proposal.clone(), unlock_ledger)); @@ -77,37 +87,40 @@ pub fn propose(env: &Env, mut proposal: Proposal) -> u64 { /// Record a signer's approval for `proposal_id`. /// Transitions state from Pending → Approved when threshold is met. pub fn approve(env: &Env, signer: &Address, proposal_id: u64) { - signer.require_auth(); - let signers: Vec
= env.storage().instance().get(&KEY_SIGNERS).unwrap_or(vec![env]); + let signers: Vec
= env + .storage() + .instance() + .get(&KEY_SIGNERS) + .unwrap_or(vec![env]); if !signers.contains(signer) { panic_with_error!(env, GovError::NotASigner); } let threshold: u32 = env.storage().instance().get(&KEY_THRESH).unwrap_or(1); let mut props = load_proposals(env); - let (mut prop, unlock) = props.get(proposal_id).unwrap_or_else(|| { - panic_with_error!(env, GovError::ProposalNotFound) - }); - + let (mut prop, unlock) = props + .get(proposal_id) + .unwrap_or_else(|| panic_with_error!(env, GovError::ProposalNotFound)); + // Only pending proposals can receive approvals if prop.state != ProposalState::Pending { panic_with_error!(env, GovError::InvalidStateTransition); } - + if prop.approved_by.contains(signer) { panic_with_error!(env, GovError::AlreadyApproved); } prop.approved_by.push_back(signer.clone()); - + // Transition to Approved when threshold is met - if (prop.approved_by.len() as u32) >= threshold { + if prop.approved_by.len() >= threshold { prop.state = ProposalState::Approved; env.events().publish( (symbol_short!("GOV"), symbol_short!("approved")), proposal_id, ); } - + props.set(proposal_id, (prop, unlock)); env.storage().instance().set(&KEY_PROPOSALS, &props); } @@ -116,19 +129,23 @@ pub fn approve(env: &Env, signer: &Address, proposal_id: u64) { /// Transitions state from Approved → Executed. pub fn execute(env: &Env, proposal_id: u64) -> Proposal { let mut props = load_proposals(env); - let (mut prop, unlock) = props.get(proposal_id).unwrap_or_else(|| { - panic_with_error!(env, GovError::ProposalNotFound) - }); - + let (mut prop, unlock) = props + .get(proposal_id) + .unwrap_or_else(|| panic_with_error!(env, GovError::ProposalNotFound)); + let threshold: u32 = env.storage().instance().get(&KEY_THRESH).unwrap_or(1); + if prop.approved_by.len() < threshold { + panic_with_error!(env, GovError::ThresholdNotMet); + } + // Only approved proposals can be executed if prop.state != ProposalState::Approved { panic_with_error!(env, GovError::InvalidStateTransition); } - + if env.ledger().sequence() < unlock { panic_with_error!(env, GovError::TimelockActive); } - + prop.state = ProposalState::Executed; props.set(proposal_id, (prop.clone(), unlock)); env.storage().instance().set(&KEY_PROPOSALS, &props); diff --git a/engine-core/src/governance_tests.rs b/engine-core/src/governance_tests.rs index 5bbbd67..93a145d 100644 --- a/engine-core/src/governance_tests.rs +++ b/engine-core/src/governance_tests.rs @@ -7,7 +7,9 @@ mod tests { use crate::VeroCore; use crate::VeroCoreClient; - use soroban_sdk::{vec, Address, BytesN, Env}; + use soroban_sdk::{testutils::Ledger, vec, Address, BytesN, Env}; + + const TIMELOCK_LEDGERS: u32 = 720; #[test] fn test_proposal_lifecycle_and_upgrade() { @@ -32,6 +34,64 @@ mod tests { assert_eq!(proposal_id, 1); } + #[test] + fn upgrade_requires_quorum_before_timelock_or_wasm_update() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); + + let signer1 =
::generate(&env); + let signer2 =
::generate(&env); + let signer3 =
::generate(&env); + let signers = vec![&env, signer1.clone(), signer2.clone(), signer3.clone()]; + let threshold = 2; + client.init(&signers, &threshold, &vec![&env]); + + let wasm_hash = BytesN::from_array(&env, &[7u8; 32]); + let proposal_id = client.propose(&signer1, &wasm_hash); + + let no_signature_upgrade = client.try_upgrade(&proposal_id); + assert!(no_signature_upgrade.is_err()); + + client.approve(&signer1, &proposal_id); + let one_signature_upgrade = client.try_upgrade(&proposal_id); + assert!(one_signature_upgrade.is_err()); + + client.approve(&signer2, &proposal_id); + let timelocked_upgrade = client.try_upgrade(&proposal_id); + assert!(timelocked_upgrade.is_err()); + } + + #[test] + fn quorum_approved_proposal_reaches_wasm_update_after_timelock() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register_contract(None, VeroCore); + let client = VeroCoreClient::new(&env, &contract_id); + + let signer1 =
::generate(&env); + let signer2 =
::generate(&env); + let signers = vec![&env, signer1.clone(), signer2.clone()]; + let threshold = 2; + client.init(&signers, &threshold, &vec![&env]); + + let wasm_hash = BytesN::from_array(&env, &[9u8; 32]); + let proposal_id = client.propose(&signer1, &wasm_hash); + client.approve(&signer1, &proposal_id); + client.approve(&signer2, &proposal_id); + + env.ledger() + .set_sequence_number(env.ledger().sequence() + TIMELOCK_LEDGERS); + + // The bogus WASM hash should only be reached after quorum and timelock + // validation pass, proving a single signer cannot trigger this path. + let reached_wasm_update = client.try_upgrade(&proposal_id); + assert!(reached_wasm_update.is_err()); + } + #[test] #[should_panic(expected = "Error(Contract, #1)")] // NotASigner fn test_propose_unauthorized() { diff --git a/engine-core/src/lib.rs b/engine-core/src/lib.rs index d4e36d3..3d61e77 100644 --- a/engine-core/src/lib.rs +++ b/engine-core/src/lib.rs @@ -65,7 +65,8 @@ impl VeroCore { pub fn upgrade(env: Env, proposal_id: u64) { circuit_breaker::assert_closed(&env); let prop = governance::execute(&env, proposal_id); - env.deployer().update_current_contract_wasm(prop.action_hash); + env.deployer() + .update_current_contract_wasm(prop.action_hash); } /// Validate and record a new state transition. diff --git a/engine-core/src/types.rs b/engine-core/src/types.rs index 49724e7..8bea02f 100644 --- a/engine-core/src/types.rs +++ b/engine-core/src/types.rs @@ -7,11 +7,11 @@ pub struct StateCommitment { /// SHA-256 of serialised state payload (32 bytes). pub state_hash: BytesN<32>, /// Sequence number — monotonically increasing, prevents replay. - pub sequence: u64, + pub sequence: u64, /// Ledger at which this commitment was recorded. - pub ledger: u32, + pub ledger: u32, /// Signer that produced this commitment. - pub author: Address, + pub author: Address, } /// Proposal state machine for multi-sig governance. @@ -31,17 +31,17 @@ pub enum ProposalState { #[contracttype] #[derive(Clone, Debug)] pub struct Proposal { - pub id: u64, + pub id: u64, pub action_hash: BytesN<32>, - pub proposer: Address, + pub proposer: Address, pub approved_by: soroban_sdk::Vec
, - pub state: ProposalState, + pub state: ProposalState, } /// Circuit-breaker state persisted in contract storage. #[contracttype] #[derive(Clone, Debug, PartialEq)] pub enum BreakerState { - Closed, // normal operation - Open, // halted — no state transitions allowed + Closed, // normal operation + Open, // halted — no state transitions allowed } diff --git a/engine-core/test_snapshots/governance_tests/tests/quorum_approved_proposal_reaches_wasm_update_after_timelock.1.json b/engine-core/test_snapshots/governance_tests/tests/quorum_approved_proposal_reaches_wasm_update_after_timelock.1.json new file mode 100644 index 0000000..5ac8946 --- /dev/null +++ b/engine-core/test_snapshots/governance_tests/tests/quorum_approved_proposal_reaches_wasm_update_after_timelock.1.json @@ -0,0 +1,818 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "propose", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0909090909090909090909090909090909090909090909090909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "u64": 1 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 1 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 720, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 2 + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [ + { + "key": { + "u64": 1 + }, + "val": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "action_hash" + }, + "val": { + "bytes": "0909090909090909090909090909090909090909090909090909090909090909" + } + }, + { + "key": { + "symbol": "approved_by" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proposer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 1 + } + } + ] + }, + { + "u32": 720 + } + ] + } + } + ] + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + { + "u32": 2 + }, + { + "vec": [] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "propose" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0909090909090909090909090909090909090909090909090909090909090909" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "GOV" + }, + { + "symbol": "propose" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "propose" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "approve" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "u64": 1 + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "approve" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "approve" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 1 + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "GOV" + }, + { + "symbol": "approved" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "approve" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "upgrade" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "GOV" + }, + { + "symbol": "execute" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "storage": "missing_value" + } + } + ], + "data": { + "vec": [ + { + "string": "Wasm does not exist" + }, + { + "bytes": "0909090909090909090909090909090909090909090909090909090909090909" + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "storage": "missing_value" + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "storage": "missing_value" + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "storage": "missing_value" + } + } + ], + "data": { + "vec": [ + { + "string": "contract try_call failed" + }, + { + "symbol": "upgrade" + }, + { + "vec": [ + { + "u64": 1 + } + ] + } + ] + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/engine-core/test_snapshots/governance_tests/tests/upgrade_requires_quorum_before_timelock_or_wasm_update.1.json b/engine-core/test_snapshots/governance_tests/tests/upgrade_requires_quorum_before_timelock_or_wasm_update.1.json new file mode 100644 index 0000000..a727286 --- /dev/null +++ b/engine-core/test_snapshots/governance_tests/tests/upgrade_requires_quorum_before_timelock_or_wasm_update.1.json @@ -0,0 +1,1097 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "propose", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0707070707070707070707070707070707070707070707070707070707070707" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "u64": 1 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 1 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "CB_GUARD" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "CB_STATE" + }, + "val": { + "vec": [ + { + "symbol": "Closed" + } + ] + } + }, + { + "key": { + "symbol": "INIT" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "NEXT_ID" + }, + "val": { + "u64": 2 + } + }, + { + "key": { + "symbol": "PROPS" + }, + "val": { + "map": [ + { + "key": { + "u64": 1 + }, + "val": { + "vec": [ + { + "map": [ + { + "key": { + "symbol": "action_hash" + }, + "val": { + "bytes": "0707070707070707070707070707070707070707070707070707070707070707" + } + }, + { + "key": { + "symbol": "approved_by" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proposer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 1 + } + } + ] + }, + { + "u32": 720 + } + ] + } + } + ] + } + }, + { + "key": { + "symbol": "SIGNERS" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + }, + { + "key": { + "symbol": "THRESH" + }, + "val": { + "u32": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "init" + } + ], + "data": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + { + "u32": 2 + }, + { + "vec": [] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "init" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "propose" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "0707070707070707070707070707070707070707070707070707070707070707" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "GOV" + }, + { + "symbol": "propose" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "propose" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "upgrade" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 3 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 3 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 3 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 3 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 3 + } + } + ], + "data": { + "vec": [ + { + "string": "contract try_call failed" + }, + { + "symbol": "upgrade" + }, + { + "vec": [ + { + "u64": 1 + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "approve" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "u64": 1 + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "approve" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "upgrade" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 3 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 3 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 3 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 3 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 3 + } + } + ], + "data": { + "vec": [ + { + "string": "contract try_call failed" + }, + { + "symbol": "upgrade" + }, + { + "vec": [ + { + "u64": 1 + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "approve" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 1 + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "GOV" + }, + { + "symbol": "approved" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "approve" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "symbol": "upgrade" + } + ], + "data": { + "u64": 1 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 4 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 4 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 4 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 4 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 4 + } + } + ], + "data": { + "vec": [ + { + "string": "contract try_call failed" + }, + { + "symbol": "upgrade" + }, + { + "vec": [ + { + "u64": 1 + } + ] + } + ] + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file