radix-engine 1.3.1

Reference implementation of Radix Engine, from the Radix DLT project.
Documentation
use crate::internal_prelude::*;
use crate::system::system_db_reader::{SystemDatabaseReader, SystemReaderError};
use crate::system::system_type_checker::{BlueprintTypeTarget, SchemaValidationMeta};
use radix_common::constants::BLUEPRINT_PAYLOAD_MAX_DEPTH;
use radix_engine_interface::blueprints::package::{BlueprintPayloadIdentifier, BlueprintVersion};
use radix_engine_interface::types::Emitter;
use radix_substate_store_interface::interface::SubstateDatabase;

pub trait ApplicationEventChecker: Default {
    type ApplicationEventCheckerResults: Debug + Default;

    fn on_event(&mut self, _info: BlueprintInfo, _event_id: EventTypeIdentifier, _event: &Vec<u8>) {
    }

    fn on_finish(&self) -> Self::ApplicationEventCheckerResults {
        Self::ApplicationEventCheckerResults::default()
    }
}

impl ApplicationEventChecker for () {
    type ApplicationEventCheckerResults = ();
}

#[derive(Debug)]
pub enum SystemEventCheckerError {
    MissingObjectTypeTarget,
    MissingPayloadSchema(SystemReaderError),
    InvalidEvent,
}

pub struct SystemEventChecker<A: ApplicationEventChecker> {
    application_checker: A,
}

impl<A: ApplicationEventChecker> SystemEventChecker<A> {
    pub fn new() -> Self {
        Self {
            application_checker: A::default(),
        }
    }

    pub fn check_all_events<S: SubstateDatabase>(
        &mut self,
        substate_db: &S,
        events: &[Vec<(EventTypeIdentifier, Vec<u8>)>],
    ) -> Result<A::ApplicationEventCheckerResults, SystemEventCheckerError> {
        let reader = SystemDatabaseReader::new(substate_db);

        for (event_id, event_payload) in events.iter().flatten() {
            let type_target = match &event_id.0 {
                Emitter::Method(node_id, module_id) => reader
                    .get_blueprint_type_target(node_id, *module_id)
                    .map_err(|_| SystemEventCheckerError::MissingObjectTypeTarget)?,
                Emitter::Function(blueprint_id) => BlueprintTypeTarget {
                    blueprint_info: BlueprintInfo {
                        blueprint_id: blueprint_id.clone(),
                        blueprint_version: BlueprintVersion::default(),
                        outer_obj_info: OuterObjectInfo::None,
                        features: indexset!(),
                        generic_substitutions: vec![],
                    },
                    meta: SchemaValidationMeta::Blueprint,
                },
            };

            let event_schema = reader
                .get_blueprint_payload_schema(
                    &type_target,
                    &BlueprintPayloadIdentifier::Event(event_id.1.clone()),
                )
                .map_err(SystemEventCheckerError::MissingPayloadSchema)?;

            reader
                .validate_payload(event_payload, &event_schema, BLUEPRINT_PAYLOAD_MAX_DEPTH)
                .map_err(|_| SystemEventCheckerError::InvalidEvent)?;

            self.application_checker.on_event(
                type_target.blueprint_info,
                event_id.clone(),
                event_payload,
            );
        }

        let results = self.application_checker.on_finish();

        Ok(results)
    }
}

impl<A: ApplicationEventChecker> Default for SystemEventChecker<A> {
    fn default() -> Self {
        Self::new()
    }
}