diff --git a/Cargo.lock b/Cargo.lock index ec72ce93fc..9583c1080b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7375,8 +7375,11 @@ name = "papyrus_consensus_orchestrator" version = "0.0.0" dependencies = [ "async-trait", + "blockifier", "chrono", "futures", + "indexmap 2.6.0", + "infra_utils", "lazy_static", "mockall", "papyrus_consensus", @@ -7384,6 +7387,8 @@ dependencies = [ "papyrus_protobuf", "papyrus_storage", "papyrus_test_utils", + "serde", + "serde_json", "starknet-types-core", "starknet_api", "starknet_batcher_types", diff --git a/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml b/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml index 6fb31cdd99..723397976d 100644 --- a/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml +++ b/crates/sequencing/papyrus_consensus_orchestrator/Cargo.toml @@ -8,12 +8,15 @@ description = "Implements the consensus context and orchestrates the node's comp [dependencies] async-trait.workspace = true +blockifier.workspace = true chrono.workspace = true +indexmap.workspace = true futures.workspace = true papyrus_consensus.workspace = true papyrus_network.workspace = true papyrus_protobuf.workspace = true papyrus_storage.workspace = true +serde.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true starknet_batcher_types = { workspace = true, features = ["testing"] } @@ -22,10 +25,12 @@ tracing.workspace = true [dev-dependencies] lazy_static.workspace = true +infra_utils.workspace = true mockall.workspace = true papyrus_network = { workspace = true, features = ["testing"] } papyrus_storage = { workspace = true, features = ["testing"] } papyrus_test_utils.workspace = true +serde_json.workspace = true starknet_batcher_types = { workspace = true, features = ["testing"] } test-case.workspace = true diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication.rs new file mode 100644 index 0000000000..a396ee7d85 --- /dev/null +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication.rs @@ -0,0 +1,3 @@ +mod central_objects; +#[cfg(test)] +mod central_objects_test; diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/central_objects.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/central_objects.rs new file mode 100644 index 0000000000..97431b1bc3 --- /dev/null +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/central_objects.rs @@ -0,0 +1,84 @@ +use blockifier::state::cached_state::CommitmentStateDiff; +use indexmap::{indexmap, IndexMap}; +use serde::{Deserialize, Serialize}; +use starknet_api::block::{ + BlockInfo, + BlockNumber, + BlockTimestamp, + NonzeroGasPrice, + StarknetVersion, +}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::state::StorageKey; +use starknet_types_core::felt::Felt; + +#[derive(Debug, PartialEq, Deserialize, Serialize)] +pub struct CentralResourcePrice { + pub price_in_wei: NonzeroGasPrice, + pub price_in_fri: NonzeroGasPrice, +} + +#[derive(Debug, PartialEq, Deserialize, Serialize)] +pub struct CentralBlockInfo { + pub block_number: BlockNumber, + pub block_timestamp: BlockTimestamp, + pub sequencer_address: ContractAddress, + pub l1_gas_price: CentralResourcePrice, + pub l1_data_gas_price: CentralResourcePrice, + pub l2_gas_price: CentralResourcePrice, + pub use_kzg_da: bool, + pub starknet_version: Option, +} + +impl From<(BlockInfo, StarknetVersion)> for CentralBlockInfo { + fn from((block_info, starknet_version): (BlockInfo, StarknetVersion)) -> CentralBlockInfo { + CentralBlockInfo { + block_number: block_info.block_number, + block_timestamp: block_info.block_timestamp, + sequencer_address: block_info.sequencer_address, + l1_gas_price: CentralResourcePrice { + price_in_wei: block_info.gas_prices.eth_gas_prices.l1_gas_price, + price_in_fri: block_info.gas_prices.strk_gas_prices.l1_gas_price, + }, + l1_data_gas_price: CentralResourcePrice { + price_in_wei: block_info.gas_prices.eth_gas_prices.l1_data_gas_price, + price_in_fri: block_info.gas_prices.strk_gas_prices.l1_data_gas_price, + }, + l2_gas_price: CentralResourcePrice { + price_in_wei: block_info.gas_prices.eth_gas_prices.l2_gas_price, + price_in_fri: block_info.gas_prices.strk_gas_prices.l2_gas_price, + }, + use_kzg_da: block_info.use_kzg_da, + starknet_version: Some(starknet_version), + } + } +} + +#[derive(Debug, PartialEq, Deserialize, Serialize)] +pub struct CentralStateDiff { + pub address_to_class_hash: IndexMap, + pub nonces: IndexMap>, + pub storage_updates: + IndexMap>>, + pub declared_classes: IndexMap, + pub block_info: CentralBlockInfo, +} + +impl From<(CommitmentStateDiff, BlockInfo, StarknetVersion)> for CentralStateDiff { + fn from( + (state_diff, block_info, starknet_version): ( + CommitmentStateDiff, + BlockInfo, + StarknetVersion, + ), + ) -> CentralStateDiff { + CentralStateDiff { + address_to_class_hash: state_diff.address_to_class_hash, + nonces: indexmap!(DataAvailabilityMode::L1=> state_diff.address_to_nonce), + storage_updates: indexmap!(DataAvailabilityMode::L1=> state_diff.storage_updates), + declared_classes: state_diff.class_hash_to_compiled_class_hash, + block_info: CentralBlockInfo::from((block_info, starknet_version)), + } + } +} diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/central_objects_test.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/central_objects_test.rs new file mode 100644 index 0000000000..8ebb5585bf --- /dev/null +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/central_objects_test.rs @@ -0,0 +1,74 @@ +use std::fs; + +use indexmap::indexmap; +use infra_utils::path::resolve_project_relative_path; +use serde_json::Value; +use starknet_api::block::{ + BlockNumber, + BlockTimestamp, + GasPrice, + NonzeroGasPrice, + StarknetVersion, +}; +use starknet_api::core::{ClassHash, CompiledClassHash, Nonce}; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::{contract_address, felt, storage_key}; + +use super::central_objects::{CentralBlockInfo, CentralResourcePrice, CentralStateDiff}; + +pub const CENTRAL_STATE_DIFF_JSON_PATH: &str = "crates/sequencing/papyrus_consensus_orchestrator/\ + src/central_communication/resources/\ + central_state_diff.json"; + +fn central_state_diff() -> CentralStateDiff { + let rust_central_state_diff = CentralStateDiff { + address_to_class_hash: indexmap! { + contract_address!(1_u8) => + ClassHash(felt!(1_u8)), + }, + nonces: indexmap!( + DataAvailabilityMode::L1 => + indexmap!(contract_address!(2_u8)=> Nonce(felt!(2_u8))), + ), + storage_updates: indexmap!( + DataAvailabilityMode::L1=> + indexmap!(contract_address!(3_u8) => indexmap!(storage_key!(3_u8) => felt!(3_u8))), + ), + declared_classes: indexmap!(ClassHash(felt!(4_u8))=> CompiledClassHash(felt!(4_u8))), + block_info: CentralBlockInfo { + block_number: BlockNumber(5), + block_timestamp: BlockTimestamp(6), + sequencer_address: contract_address!(7_u8), + l1_gas_price: CentralResourcePrice { + price_in_wei: NonzeroGasPrice::new(GasPrice(8)).unwrap(), + price_in_fri: NonzeroGasPrice::new(GasPrice(9)).unwrap(), + }, + l1_data_gas_price: CentralResourcePrice { + price_in_wei: NonzeroGasPrice::new(GasPrice(10)).unwrap(), + price_in_fri: NonzeroGasPrice::new(GasPrice(11)).unwrap(), + }, + l2_gas_price: CentralResourcePrice { + price_in_wei: NonzeroGasPrice::new(GasPrice(12)).unwrap(), + price_in_fri: NonzeroGasPrice::new(GasPrice(13)).unwrap(), + }, + use_kzg_da: true, + starknet_version: Some(StarknetVersion::default()), + }, + }; + rust_central_state_diff +} + +#[test] +fn serialize_central_state_diff() { + let rust_central_state_diff = central_state_diff(); + + let rust_serialized = serde_json::to_string(&rust_central_state_diff).unwrap(); + let rust_json: Value = serde_json::from_str(&rust_serialized).unwrap(); + + let python_json_string = + fs::read_to_string(resolve_project_relative_path(CENTRAL_STATE_DIFF_JSON_PATH).unwrap()) + .unwrap(); + let python_json: Value = serde_json::from_str(&python_json_string).unwrap(); + + assert_eq!(rust_json, python_json,); +} diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/resources/central_state_diff.json b/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/resources/central_state_diff.json new file mode 100644 index 0000000000..2a96fcf441 --- /dev/null +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/central_communication/resources/central_state_diff.json @@ -0,0 +1,39 @@ +{ + "address_to_class_hash": { + "0x1": "0x1" + }, + "nonces": { + "L1": { + "0x2": "0x2" + } + }, + "storage_updates": { + "L1": { + "0x3": { + "0x3": "0x3" + } + } + }, + "declared_classes": { + "0x4": "0x4" + }, + "block_info": { + "block_number": 5, + "block_timestamp": 6, + "l1_gas_price": { + "price_in_wei": "0x8", + "price_in_fri": "0x9" + }, + "l1_data_gas_price": { + "price_in_wei": "0xa", + "price_in_fri": "0xb" + }, + "l2_gas_price": { + "price_in_wei": "0xc", + "price_in_fri": "0xd" + }, + "sequencer_address": "0x7", + "starknet_version": "0.13.4", + "use_kzg_da": true + } +} diff --git a/crates/sequencing/papyrus_consensus_orchestrator/src/lib.rs b/crates/sequencing/papyrus_consensus_orchestrator/src/lib.rs index ff7de38c70..2794745251 100644 --- a/crates/sequencing/papyrus_consensus_orchestrator/src/lib.rs +++ b/crates/sequencing/papyrus_consensus_orchestrator/src/lib.rs @@ -2,6 +2,7 @@ //! An orchestrator for a StarkNet node. //! Implements the consensus context - the interface for consensus to call out to the node. +mod central_communication; #[allow(missing_docs)] // TODO: this is test code, rename accordingly. pub mod papyrus_consensus_context;