mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-08-25 03:11:21 +00:00
feat!(lee): add event selector field
BREAKING! Before: Program outputs carried and opaque vector of event blobs. After: Outputs now bear a vector of `ProgramOutputs` struct which also have selectors attached. Mitigation: Apply selectors to all event emissions for current programs.
This commit is contained in:
@@ -590,7 +590,7 @@ fn a_second_emit_at_the_same_slot_is_rejected() {
|
||||
let first = lock_tx(&holder_key, holder_id, zone_b, ordinal, 0);
|
||||
let diff = ValidatedStateDiff::from_public_transaction(&first, &state, 1, 0)
|
||||
.expect("the first lock executes");
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
|
||||
// Same slot, fresh nonce, so the only thing that can reject it is the slot
|
||||
// already holding a record. Matched on the guest's own message rather than
|
||||
@@ -646,7 +646,7 @@ fn two_emitters_share_an_ordinal_without_colliding() {
|
||||
let lock = lock_tx(&holder_key, holder_id, zone_b, ordinal, 0);
|
||||
let diff = ValidatedStateDiff::from_public_transaction(&lock, &state, 1, 0)
|
||||
.expect("the lock executes");
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
|
||||
let send = send_tx(
|
||||
vec![sender_config_account_id(sender_id), send_slot],
|
||||
@@ -936,7 +936,7 @@ fn the_bridge_pins_are_written_once_and_replayable() {
|
||||
0,
|
||||
)
|
||||
.expect("the first init claims the config PDA");
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
assert_eq!(
|
||||
bridge_lock_core::read_config(&state.get_account_by_id(config_id).data.into_inner()),
|
||||
Some((outbox_id, wrapped_token_id)),
|
||||
@@ -1042,7 +1042,7 @@ fn the_outbox_pin_is_written_once_and_replayable() {
|
||||
let first = init(outbox_id);
|
||||
let diff = ValidatedStateDiff::from_public_transaction(&first, &state, 1, 0)
|
||||
.expect("the first init claims the config PDA");
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
assert_eq!(
|
||||
read_outbox(&state.get_account_by_id(config_id).data.into_inner()),
|
||||
Some(outbox_id),
|
||||
@@ -1180,7 +1180,7 @@ fn the_token_authority_path_holds() {
|
||||
0,
|
||||
)
|
||||
.expect("the configured authority changes sources");
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
let cfg = wrapped_token_core::WrappedTokenConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
)
|
||||
@@ -1200,7 +1200,7 @@ fn the_token_authority_path_holds() {
|
||||
0,
|
||||
)
|
||||
.expect("the authority acts again");
|
||||
state.apply_state_diff(second);
|
||||
drop(state.apply_state_diff(second));
|
||||
let updated_cfg = wrapped_token_core::WrappedTokenConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
)
|
||||
@@ -1220,7 +1220,7 @@ fn the_token_authority_path_holds() {
|
||||
let renounced =
|
||||
ValidatedStateDiff::from_public_transaction(&renounce(authority, &key, 2), &state, 3, 0)
|
||||
.expect("the authority renounces itself");
|
||||
state.apply_state_diff(renounced);
|
||||
drop(state.apply_state_diff(renounced));
|
||||
let renounced_cfg = wrapped_token_core::WrappedTokenConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
)
|
||||
@@ -1431,7 +1431,7 @@ fn the_receiver_authority_path_holds() {
|
||||
let diff =
|
||||
ValidatedStateDiff::from_public_transaction(&update(authority, &key, 0), &state, 1, 0)
|
||||
.expect("the configured authority changes sources");
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
let cfg = ping_core::ReceiverConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
)
|
||||
@@ -1442,7 +1442,7 @@ fn the_receiver_authority_path_holds() {
|
||||
let renounce_diff =
|
||||
ValidatedStateDiff::from_public_transaction(&renounce(authority, &key, 1), &state, 2, 0)
|
||||
.expect("the authority renounces itself");
|
||||
state.apply_state_diff(renounce_diff);
|
||||
drop(state.apply_state_diff(renounce_diff));
|
||||
let renounced_cfg = ping_core::ReceiverConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
)
|
||||
@@ -1555,7 +1555,7 @@ fn the_governance_path_holds() {
|
||||
0,
|
||||
)
|
||||
.expect("the governance path changes sources");
|
||||
state.apply_state_diff(first);
|
||||
drop(state.apply_state_diff(first));
|
||||
|
||||
let cfg = wrapped_token_core::WrappedTokenConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
@@ -1570,7 +1570,7 @@ fn the_governance_path_holds() {
|
||||
|
||||
let second = ValidatedStateDiff::from_public_transaction(&update(vec![]), &state, 2, 0)
|
||||
.expect("the governance path acts again");
|
||||
state.apply_state_diff(second);
|
||||
drop(state.apply_state_diff(second));
|
||||
let cleared_cfg = wrapped_token_core::WrappedTokenConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
)
|
||||
@@ -1583,7 +1583,7 @@ fn the_governance_path_holds() {
|
||||
|
||||
let renounced = ValidatedStateDiff::from_public_transaction(&renounce(), &state, 3, 0)
|
||||
.expect("the governance path renounces");
|
||||
state.apply_state_diff(renounced);
|
||||
drop(state.apply_state_diff(renounced));
|
||||
let renounced_cfg = wrapped_token_core::WrappedTokenConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
)
|
||||
@@ -1723,7 +1723,7 @@ fn the_receiver_governance_path_holds() {
|
||||
|
||||
let diff = ValidatedStateDiff::from_public_transaction(&tx, &state, 1, 0)
|
||||
.expect("the receiver governance path changes sources");
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
let cfg = ping_core::ReceiverConfig::from_bytes(
|
||||
&state.get_account_by_id(config_id).data.into_inner(),
|
||||
)
|
||||
@@ -1767,7 +1767,7 @@ fn a_shared_authority_survives_the_first_claim() {
|
||||
);
|
||||
let first = ValidatedStateDiff::from_public_transaction(&token_update, &state, 1, 0)
|
||||
.expect("the token claims the shared authority");
|
||||
state.apply_state_diff(first);
|
||||
drop(state.apply_state_diff(first));
|
||||
assert_eq!(
|
||||
state.get_account_by_id(authority).program_owner,
|
||||
wrapped_token_id.into(),
|
||||
@@ -1786,7 +1786,7 @@ fn a_shared_authority_survives_the_first_claim() {
|
||||
);
|
||||
let second = ValidatedStateDiff::from_public_transaction(&receiver_update, &state, 2, 0)
|
||||
.expect("the other target still acts on the token-owned authority");
|
||||
state.apply_state_diff(second);
|
||||
drop(state.apply_state_diff(second));
|
||||
let receiver_cfg = ping_core::ReceiverConfig::from_bytes(
|
||||
&state
|
||||
.get_account_by_id(receiver_config_id)
|
||||
@@ -1814,7 +1814,7 @@ fn a_shared_authority_survives_the_first_claim() {
|
||||
);
|
||||
let third = ValidatedStateDiff::from_public_transaction(&receiver_renounce, &state, 3, 0)
|
||||
.expect("the other target renounces on the token-owned authority");
|
||||
state.apply_state_diff(third);
|
||||
drop(state.apply_state_diff(third));
|
||||
let renounced_cfg = ping_core::ReceiverConfig::from_bytes(
|
||||
&state
|
||||
.get_account_by_id(receiver_config_id)
|
||||
|
||||
@@ -468,6 +468,14 @@ impl<T> From<std::ops::RangeFull> for ValidityWindow<T> {
|
||||
#[error("Invalid window")]
|
||||
pub struct InvalidWindow;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, BorshSerialize, BorshDeserialize)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))]
|
||||
pub struct ProgramEvent {
|
||||
pub selector: [u8; 8],
|
||||
/// The arbitrary event-data emitted in the program output.
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))]
|
||||
#[must_use = "ProgramOutput does nothing unless written"]
|
||||
@@ -491,7 +499,7 @@ pub struct ProgramOutput {
|
||||
pub timestamp_validity_window: TimestampValidityWindow,
|
||||
/// A vector of event data. Dropped for private transaction for function
|
||||
/// privacy.
|
||||
pub events: Vec<Vec<u8>>,
|
||||
pub events: Vec<ProgramEvent>,
|
||||
}
|
||||
|
||||
impl ProgramOutput {
|
||||
@@ -524,7 +532,7 @@ impl ProgramOutput {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_events(mut self, events: Vec<Vec<u8>>) -> Self {
|
||||
pub fn with_events(mut self, events: Vec<ProgramEvent>) -> Self {
|
||||
self.events = events;
|
||||
self
|
||||
}
|
||||
@@ -582,11 +590,10 @@ impl ProgramOutput {
|
||||
/// A struct holding an event-output of a program.
|
||||
#[cfg(feature = "host")]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Event {
|
||||
pub struct TransactionEvent {
|
||||
/// Which program emitted the event.
|
||||
pub program_id: ProgramId,
|
||||
/// The arbitrary event-data emitted in the program output.
|
||||
pub data: Vec<u8>,
|
||||
pub event: ProgramEvent,
|
||||
}
|
||||
|
||||
/// Representation of a number as `lo + hi * 2^128`.
|
||||
|
||||
@@ -5,7 +5,7 @@ use lee_core::{
|
||||
BlockId, Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier,
|
||||
Timestamp,
|
||||
account::{Account, AccountId, Data},
|
||||
program::{Event, PROGRAM_STORAGE_OWNER, ProgramId},
|
||||
program::{PROGRAM_STORAGE_OWNER, ProgramId, TransactionEvent},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -204,7 +204,8 @@ impl V03State {
|
||||
self.public_state.insert(account_id, account);
|
||||
}
|
||||
|
||||
pub fn apply_state_diff(&mut self, diff: ValidatedStateDiff) -> Vec<Event> {
|
||||
#[must_use]
|
||||
pub fn apply_state_diff(&mut self, diff: ValidatedStateDiff) -> Vec<TransactionEvent> {
|
||||
let StateDiff {
|
||||
signer_account_ids,
|
||||
public_diff,
|
||||
@@ -238,7 +239,7 @@ impl V03State {
|
||||
tx: &PublicTransaction,
|
||||
block_id: BlockId,
|
||||
timestamp: Timestamp,
|
||||
) -> Result<Vec<Event>, LeeError> {
|
||||
) -> Result<Vec<TransactionEvent>, LeeError> {
|
||||
let diff = ValidatedStateDiff::from_public_transaction(tx, self, block_id, timestamp)?;
|
||||
Ok(self.apply_state_diff(diff))
|
||||
}
|
||||
@@ -251,7 +252,7 @@ impl V03State {
|
||||
) -> Result<(), LeeError> {
|
||||
let diff =
|
||||
ValidatedStateDiff::from_privacy_preserving_transaction(tx, self, block_id, timestamp)?;
|
||||
self.apply_state_diff(diff);
|
||||
drop(self.apply_state_diff(diff));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -260,7 +261,7 @@ impl V03State {
|
||||
tx: &ProgramDeploymentTransaction,
|
||||
) -> Result<(), LeeError> {
|
||||
let diff = ValidatedStateDiff::from_program_deployment_transaction(tx, self)?;
|
||||
self.apply_state_diff(diff);
|
||||
drop(self.apply_state_diff(diff));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,18 @@ fn program_transaction<T: serde::Serialize>(
|
||||
PublicTransaction::new(message, witness_set)
|
||||
}
|
||||
|
||||
fn payloads(events: &[lee_core::program::Event]) -> Vec<Vec<u8>> {
|
||||
events.iter().map(|event| event.data.clone()).collect()
|
||||
fn payloads(events: &[TransactionEvent]) -> Vec<Vec<u8>> {
|
||||
events
|
||||
.iter()
|
||||
.map(|event| event.event.data.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn emitted(n: u8) -> ProgramEvent {
|
||||
ProgramEvent {
|
||||
selector: [n; 8],
|
||||
data: vec![n; 4],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -26,7 +36,7 @@ fn emitted_events_are_returned_in_order_and_attributed_to_the_emitter() {
|
||||
emitter_id,
|
||||
account_id,
|
||||
EmitterInstruction {
|
||||
events: vec![vec![0; 4], vec![1; 4]],
|
||||
events: vec![emitted(0), emitted(1)],
|
||||
chain: vec![],
|
||||
},
|
||||
);
|
||||
@@ -34,6 +44,13 @@ fn emitted_events_are_returned_in_order_and_attributed_to_the_emitter() {
|
||||
let events = state.transition_from_public_transaction(&tx, 1, 0).unwrap();
|
||||
|
||||
assert_eq!(payloads(&events), vec![vec![0; 4], vec![1; 4]]);
|
||||
assert_eq!(
|
||||
events
|
||||
.iter()
|
||||
.map(|event| event.event.selector)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[0; 8], [1; 8]]
|
||||
);
|
||||
assert!(events.iter().all(|event| event.program_id == emitter_id));
|
||||
}
|
||||
|
||||
@@ -44,7 +61,7 @@ fn parent_events_precede_chained_callee_events() {
|
||||
let emitter_id = crate::test_methods::event_emitter().id();
|
||||
|
||||
let callee_instruction_data = Program::serialize_instruction(EmitterInstruction {
|
||||
events: vec![vec![1; 4], vec![2; 4]],
|
||||
events: vec![emitted(1), emitted(2)],
|
||||
chain: vec![],
|
||||
})
|
||||
.unwrap();
|
||||
@@ -53,7 +70,7 @@ fn parent_events_precede_chained_callee_events() {
|
||||
emitter_id,
|
||||
account_id,
|
||||
EmitterInstruction {
|
||||
events: vec![vec![0; 4]],
|
||||
events: vec![emitted(0)],
|
||||
chain: vec![(emitter_id, callee_instruction_data)],
|
||||
},
|
||||
);
|
||||
@@ -74,17 +91,17 @@ fn chained_events_follow_depth_first_pre_order() {
|
||||
let emitter_id = crate::test_methods::event_emitter().id();
|
||||
|
||||
let grandchild = Program::serialize_instruction(EmitterInstruction {
|
||||
events: vec![vec![2; 4]],
|
||||
events: vec![emitted(2)],
|
||||
chain: vec![],
|
||||
})
|
||||
.unwrap();
|
||||
let first_callee = Program::serialize_instruction(EmitterInstruction {
|
||||
events: vec![vec![1; 4]],
|
||||
events: vec![emitted(1)],
|
||||
chain: vec![(emitter_id, grandchild)],
|
||||
})
|
||||
.unwrap();
|
||||
let second_callee = Program::serialize_instruction(EmitterInstruction {
|
||||
events: vec![vec![3; 4]],
|
||||
events: vec![emitted(3)],
|
||||
chain: vec![],
|
||||
})
|
||||
.unwrap();
|
||||
@@ -93,7 +110,7 @@ fn chained_events_follow_depth_first_pre_order() {
|
||||
emitter_id,
|
||||
account_id,
|
||||
EmitterInstruction {
|
||||
events: vec![vec![0; 4]],
|
||||
events: vec![emitted(0)],
|
||||
chain: vec![(emitter_id, first_callee), (emitter_id, second_callee)],
|
||||
},
|
||||
);
|
||||
@@ -139,7 +156,7 @@ fn chained_callee_events_are_attributed_to_the_callee_not_the_caller() {
|
||||
// three sibling chained calls, so the only emitting program is neither the top-level
|
||||
// program nor its caller.
|
||||
let callback_instruction_data = Program::serialize_instruction(EmitterInstruction {
|
||||
events: vec![vec![0; 4]],
|
||||
events: vec![emitted(0)],
|
||||
chain: vec![],
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -14,7 +14,8 @@ use lee_core::{
|
||||
encryption::ViewingPublicKey,
|
||||
program::{
|
||||
BlockValidityWindow, ExecutionValidationError, InstructionData, MAX_NUMBER_CHAINED_CALLS,
|
||||
PdaSeed, ProgramId, TimestampValidityWindow, WrappedBalanceSum,
|
||||
PdaSeed, ProgramEvent, ProgramId, TimestampValidityWindow, TransactionEvent,
|
||||
WrappedBalanceSum,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -183,7 +184,7 @@ enum FlashSwapInstruction {
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
struct EmitterInstruction {
|
||||
events: Vec<Vec<u8>>,
|
||||
events: Vec<ProgramEvent>,
|
||||
chain: Vec<(ProgramId, InstructionData)>,
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use lee_core::{
|
||||
BlockId, Commitment, Nullifier, PrivacyPreservingCircuitOutput, PublicAction, Timestamp,
|
||||
account::{Account, AccountId, AccountWithMetadata},
|
||||
program::{
|
||||
CallerData, ChainedCall, Claim, DEFAULT_PROGRAM_OWNER, Event,
|
||||
CallerData, ChainedCall, Claim, DEFAULT_PROGRAM_OWNER, TransactionEvent,
|
||||
compute_public_authorized_pdas, validate_execution,
|
||||
},
|
||||
};
|
||||
@@ -32,7 +32,7 @@ pub struct StateDiff {
|
||||
pub new_commitments: Vec<Commitment>,
|
||||
pub new_nullifiers: Vec<Nullifier>,
|
||||
pub program: Option<Program>,
|
||||
pub events: Vec<Event>,
|
||||
pub events: Vec<TransactionEvent>,
|
||||
}
|
||||
|
||||
/// The validated output of executing or verifying a transaction, ready to be applied to the state.
|
||||
@@ -90,7 +90,7 @@ impl ValidatedStateDiff {
|
||||
.collect();
|
||||
|
||||
let mut state_diff: HashMap<AccountId, Account> = HashMap::new();
|
||||
let mut events: Vec<Event> = Vec::new();
|
||||
let mut events: Vec<TransactionEvent> = Vec::new();
|
||||
|
||||
let initial_call = ChainedCall {
|
||||
program_id: message.program_id,
|
||||
@@ -264,10 +264,15 @@ impl ValidatedStateDiff {
|
||||
|
||||
// Write all the output event data into a proper event struct,
|
||||
// marking its emitter program.
|
||||
events.extend(program_output.events.into_iter().map(|data| Event {
|
||||
program_id: chained_call.program_id,
|
||||
data,
|
||||
}));
|
||||
events.extend(
|
||||
program_output
|
||||
.events
|
||||
.into_iter()
|
||||
.map(|event| TransactionEvent {
|
||||
program_id: chained_call.program_id,
|
||||
event,
|
||||
}),
|
||||
);
|
||||
|
||||
// Source from `program_output.pre_states`, not `chained_call.pre_states`:
|
||||
// the loop above already gates program_output's `is_authorized` via the
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use lee_core::program::{
|
||||
AccountPostState, ChainedCall, InstructionData, ProgramId, ProgramInput, ProgramOutput,
|
||||
read_lee_inputs,
|
||||
AccountPostState, ChainedCall, InstructionData, ProgramEvent, ProgramId, ProgramInput,
|
||||
ProgramOutput, read_lee_inputs,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EmitterInstruction {
|
||||
pub events: Vec<Vec<u8>>,
|
||||
pub events: Vec<ProgramEvent>,
|
||||
pub chain: Vec<(ProgramId, InstructionData)>,
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ impl LeeTransaction {
|
||||
let diff = self
|
||||
.validate_on_state(state, block_id, timestamp)
|
||||
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ impl LeeTransaction {
|
||||
let diff = self
|
||||
.compute_state_diff(state, block_id, timestamp)
|
||||
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
|
||||
state.apply_state_diff(diff);
|
||||
drop(state.apply_state_diff(diff));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
|
||||
@@ -922,7 +922,7 @@ impl<BP: BlockPublisherTrait, S: StorageActorTrait> SequencerCore<BP, S> {
|
||||
withdrawals.push(withdraw_data);
|
||||
}
|
||||
|
||||
state.apply_state_diff(validated_diff);
|
||||
drop(state.apply_state_diff(validated_diff));
|
||||
}
|
||||
TransactionOrigin::Sequencer => {
|
||||
let LeeTransaction::Public(public_tx) = tx else {
|
||||
|
||||
Reference in New Issue
Block a user