diff --git a/fuzz-tests/src/bin/system.rs b/fuzz-tests/src/bin/system.rs index 9b10bfdef01..e1148caf016 100644 --- a/fuzz-tests/src/bin/system.rs +++ b/fuzz-tests/src/bin/system.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "libfuzzer-sys", no_main)] + use arbitrary::Arbitrary; use fuzz_tests::fuzz_template; use native_sdk::modules::metadata::Metadata; @@ -7,40 +8,40 @@ use radix_engine::errors::RuntimeError; use radix_engine::kernel::kernel_api::{KernelNodeApi, KernelSubstateApi}; use radix_engine::system::system_callback::SystemLockData; use radix_engine::vm::{OverridePackageCode, VmInvoke}; -use radix_engine_common::manifest_args; +use radix_engine_common::{manifest_args, ManifestSbor}; use serde::{Deserialize, Serialize}; use radix_engine::prelude::ManifestArgs; use radix_engine::types::ScryptoSbor; -use radix_engine_common::prelude::{scrypto_encode, NodeId, Own, ScryptoCustomTypeKind}; +use radix_engine_common::constants::XRD; +use radix_engine_common::prelude::{ + scrypto_encode, GlobalAddress, NodeId, Own, ScryptoCustomTypeKind, +}; +use radix_engine_common::types::ComponentAddress; use radix_engine_interface::api::{ FieldValue, KeyValueStoreDataSchema, LockFlags, ACTOR_STATE_SELF, }; use radix_engine_interface::blueprints::package::PackageDefinition; use radix_engine_interface::prelude::{AttachedModuleId, ClientApi, OwnerRole}; -use radix_engine_interface::types::IndexedScryptoValue; +use radix_engine_interface::types::{IndexedScryptoValue, Level}; use sbor::basic_well_known_types::ANY_TYPE; use sbor::{generate_full_schema, LocalTypeId, TypeAggregator}; -use scrypto_unit::{InjectSystemCostingError, TestRunnerBuilder}; +use scrypto_unit::{InjectSystemCostingError, TestRunnerBuilder, TestRunnerSnapshot}; use transaction::builder::ManifestBuilder; use utils::indexmap; use utils::prelude::{index_set_new, IndexSet}; fuzz_template!(|actions: SystemActions| { fuzz_system(actions) }); -// Fuzzer entry points -fn fuzz_system(actions: SystemActions) { - let mut test_runner = TestRunnerBuilder::new() - .with_custom_extension(OverridePackageCode::new( - CUSTOM_PACKAGE_CODE_ID, - FuzzSystem(actions.clone()), - )) - .skip_receipt_check() - .build(); - - let component_address = { - let package_address = test_runner.publish_native_package( - CUSTOM_PACKAGE_CODE_ID, +lazy_static::lazy_static! { + static ref TEST_RUNNER_SNAPSHOT: (TestRunnerSnapshot, ComponentAddress) = { + let mut test_runner = TestRunnerBuilder::new() + .with_custom_extension(OverridePackageCode::new(CUSTOM_PACKAGE_CODE_ID, FuzzSystem)) + .without_trace() + .skip_receipt_check() + .build(); + let package_address = test_runner + .publish_native_package(CUSTOM_PACKAGE_CODE_ID, PackageDefinition::new_with_fields_test_definition( BLUEPRINT_NAME, 2, @@ -54,12 +55,25 @@ fn fuzz_system(actions: SystemActions) { .build(), vec![], ); - receipt.expect_commit_success().new_component_addresses()[0] + let component_address = receipt.expect_commit_success().new_component_addresses()[0]; + (test_runner.create_snapshot(), component_address) }; +} + +// Fuzzer entry points +fn fuzz_system(actions: SystemActions) { + let mut test_runner = TestRunnerBuilder::new() + .with_custom_extension(OverridePackageCode::new(CUSTOM_PACKAGE_CODE_ID, FuzzSystem)) + .without_trace() + .skip_receipt_check() + .build_from_snapshot(TEST_RUNNER_SNAPSHOT.0.clone()); + + // Setup + let component_address = TEST_RUNNER_SNAPSHOT.1.clone(); let manifest = ManifestBuilder::new() .lock_fee(test_runner.faucet_component(), 500u32) - .call_method(component_address, "test", manifest_args!()) + .call_method(component_address, "test", manifest_args!(actions.actions)) .build(); test_runner @@ -69,7 +83,7 @@ fn fuzz_system(actions: SystemActions) { actions.inject_err_after_count, ); - test_runner.check_database() + test_runner.check_database(); } #[derive(Debug, Clone, Arbitrary, Serialize, Deserialize)] @@ -78,13 +92,13 @@ struct SystemActions { pub actions: Vec, } -#[derive(Debug, Clone, Arbitrary, Serialize, Deserialize)] +#[derive(Debug, Clone, Arbitrary, Serialize, Deserialize, ScryptoSbor, ManifestSbor)] enum NodeValue { Own, Ref, } -#[derive(Debug, Clone, Arbitrary, Serialize, Deserialize)] +#[derive(Debug, Clone, Arbitrary, Serialize, Deserialize, ScryptoSbor, ManifestSbor)] enum SystemAction { FieldOpen(u8, u32), FieldRead(usize), @@ -99,6 +113,11 @@ enum SystemAction { KeyValueEntryRemove(usize), KeyValueEntryClose(usize), KeyValueEntryLock(usize), + SysLog(Level, String), + SysBech32EncodeAddress(GlobalAddress), + SysGetTransactionHash, + SysGenerateRuid, + SysPanic(String), } #[derive(Debug, Clone, ScryptoSbor)] @@ -244,6 +263,21 @@ impl SystemAction { api.key_value_entry_lock(handle)?; } } + SystemAction::SysLog(level, message) => { + api.emit_log(level.clone(), message.clone())?; + } + SystemAction::SysBech32EncodeAddress(address) => { + api.bech32_encode_address(address.clone())?; + } + SystemAction::SysGetTransactionHash => { + api.get_transaction_hash()?; + } + SystemAction::SysPanic(message) => { + api.panic(message.clone())?; + } + SystemAction::SysGenerateRuid => { + api.generate_ruid()?; + } } Ok(()) @@ -253,12 +287,12 @@ impl SystemAction { const BLUEPRINT_NAME: &str = "MyBlueprint"; const CUSTOM_PACKAGE_CODE_ID: u64 = 1024; #[derive(Clone)] -struct FuzzSystem(SystemActions); +struct FuzzSystem; impl VmInvoke for FuzzSystem { fn invoke( &mut self, export_name: &str, - _input: &IndexedScryptoValue, + input: &IndexedScryptoValue, api: &mut Y, ) -> Result where @@ -270,7 +304,8 @@ impl VmInvoke for FuzzSystem { handles: index_set_new(), nodes: index_set_new(), }; - for action in &self.0.actions { + let actions: (Vec,) = input.as_typed().unwrap(); + for action in &actions.0 { action.act(api, &mut state)?; } } @@ -356,4 +391,21 @@ fn test_system_generate_fuzz_input_data() { let serialized = serialize(&actions).unwrap(); fs::write(format!("system_{:03?}.raw", idx), serialized).expect("Unable to write file"); } + + { + let idx = 2; + let actions = SystemActions { + inject_err_after_count: 32u64, + actions: vec![ + SystemAction::SysPanic("panic".to_string()), + SystemAction::SysGetTransactionHash, + SystemAction::SysLog(Level::Error, "error".to_string()), + SystemAction::SysBech32EncodeAddress(XRD.into()), + SystemAction::SysGenerateRuid, + ], + }; + + let serialized = serialize(&actions).unwrap(); + fs::write(format!("system_{:03?}.raw", idx), serialized).expect("Unable to write file"); + } } diff --git a/radix-engine-common/src/types/addresses/global_address.rs b/radix-engine-common/src/types/addresses/global_address.rs index 0c9517ed67e..d2cd9fad30b 100644 --- a/radix-engine-common/src/types/addresses/global_address.rs +++ b/radix-engine-common/src/types/addresses/global_address.rs @@ -14,6 +14,10 @@ use sbor::*; use utils::{copy_u8_array, ContextualDisplay}; /// Address to a global entity +#[cfg_attr( + feature = "radix_engine_fuzzing", + derive(serde::Serialize, serde::Deserialize) +)] #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct GlobalAddress(NodeId); // private to ensure entity type check diff --git a/radix-engine-interface/src/types/level.rs b/radix-engine-interface/src/types/level.rs index 5c1d2cd1e5e..63becd67879 100644 --- a/radix-engine-interface/src/types/level.rs +++ b/radix-engine-interface/src/types/level.rs @@ -1,8 +1,14 @@ use crate::*; +#[cfg(feature = "radix_engine_fuzzing")] +use arbitrary::Arbitrary; use core::str::FromStr; use sbor::rust::prelude::*; /// Represents the level of a log message. +#[cfg_attr( + feature = "radix_engine_fuzzing", + derive(Arbitrary, serde::Serialize, serde::Deserialize) +)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Sbor, Ord, PartialOrd, Default)] pub enum Level { Error, diff --git a/radix-engine/src/system/checkers/component_royalty_db_checker.rs b/radix-engine/src/system/checkers/component_royalty_db_checker.rs index 59468f01af0..8f6b8fde1d8 100644 --- a/radix-engine/src/system/checkers/component_royalty_db_checker.rs +++ b/radix-engine/src/system/checkers/component_royalty_db_checker.rs @@ -23,7 +23,7 @@ impl ApplicationChecker for ComponentRoyaltyDatabaseChecker { value: &Vec, ) { // Ignore if the module id is not the royalty module. - if module_id == ModuleId::Royalty { + if module_id != ModuleId::Royalty { return; }