From 73d9b041aaeb9bc701e3b674bb110df20cf9bc84 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Tue, 24 Dec 2024 15:37:06 +0530 Subject: [PATCH 01/11] update: bot executions --- Cargo.lock | 6 + configs/presets/devnet.yaml | 4 +- crates/client/analytics/src/lib.rs | 4 +- crates/client/block_production/Cargo.toml | 6 +- crates/client/block_production/src/lib.rs | 408 +++++++++++++++++++++- crates/client/db/Cargo.toml | 1 + crates/client/db/src/game_db.rs | 336 ++++++++++++++++++ crates/client/db/src/lib.rs | 6 + crates/client/devnet/src/entrypoint.rs | 4 + crates/client/mempool/src/lib.rs | 18 + 10 files changed, 786 insertions(+), 7 deletions(-) create mode 100644 crates/client/db/src/game_db.rs diff --git a/Cargo.lock b/Cargo.lock index 55cd7ea83c..4841c7e51e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5509,6 +5509,7 @@ dependencies = [ "mc-analytics", "mc-block-import", "mc-db", + "mc-devnet", "mc-exec", "mc-mempool", "mockall", @@ -5529,10 +5530,14 @@ dependencies = [ "opentelemetry_sdk", "proptest", "proptest-derive", + "rand", "rstest 0.18.2", + "serde", "serde_json", + "starknet", "starknet-core", "starknet-types-core 0.1.7 (git+https://github.com/kasarlabs/types-rs.git?branch=feat-deserialize-v0.1.7)", + "starknet-types-rpc", "starknet_api", "thiserror 2.0.3", "tokio", @@ -5569,6 +5574,7 @@ dependencies = [ "rayon", "rocksdb", "serde", + "serde_json", "starknet-types-core 0.1.7 (git+https://github.com/kasarlabs/types-rs.git?branch=feat-deserialize-v0.1.7)", "starknet_api", "tempfile", diff --git a/configs/presets/devnet.yaml b/configs/presets/devnet.yaml index 4e562cbc9d..8cb18c3fec 100644 --- a/configs/presets/devnet.yaml +++ b/configs/presets/devnet.yaml @@ -5,8 +5,8 @@ gateway_url: "http://localhost:8080/gateway/" native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" latest_protocol_version: "0.13.2" -block_time: "10s" -pending_block_update_time: "2s" +block_time: "5s" +pending_block_update_time: "1s" execution_batch_size: 16 bouncer_config: block_max_capacity: diff --git a/crates/client/analytics/src/lib.rs b/crates/client/analytics/src/lib.rs index b75a90b68b..ce20705d89 100644 --- a/crates/client/analytics/src/lib.rs +++ b/crates/client/analytics/src/lib.rs @@ -51,7 +51,9 @@ impl Analytics { self.meter_provider = Some(self.init_metric_provider()?); let layer = OpenTelemetryTracingBridge::new(&logger_provider); - tracing_subscriber.with(OpenTelemetryLayer::new(tracer)).with(layer).init(); + tracing_subscriber.with(OpenTelemetryLayer::new(tracer)).init(); + + tracing::info!("OTEL initialized"); Ok(()) } diff --git a/crates/client/block_production/Cargo.toml b/crates/client/block_production/Cargo.toml index ca4311a1a2..9d8ef7d902 100644 --- a/crates/client/block_production/Cargo.toml +++ b/crates/client/block_production/Cargo.toml @@ -26,6 +26,7 @@ blockifier = { workspace = true, features = ["testing"] } mockall.workspace = true assert_matches.workspace = true lazy_static.workspace = true +serde = { workspace = true, default-features = true } serde_json.workspace = true [features] @@ -37,6 +38,7 @@ testing = ["blockifier/testing", "mc-db/testing", "mockall"] mc-analytics.workspace = true mc-block-import.workspace = true mc-db.workspace = true +mc-devnet.workspace = true mc-exec.workspace = true mc-mempool.workspace = true mp-block.workspace = true @@ -53,7 +55,8 @@ blockifier.workspace = true starknet-core.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true - +starknet.workspace = true +starknet-types-rpc = { workspace = true } # Other anyhow.workspace = true mockall = { workspace = true, optional = true } @@ -76,3 +79,4 @@ tracing = { workspace = true } tracing-core = { workspace = true, default-features = false } tracing-opentelemetry = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } +rand.workspace = true diff --git a/crates/client/block_production/src/lib.rs b/crates/client/block_production/src/lib.rs index 81e18645cc..8d80aab8b8 100644 --- a/crates/client/block_production/src/lib.rs +++ b/crates/client/block_production/src/lib.rs @@ -24,22 +24,28 @@ use finalize_execution_state::StateDiffToStateMapError; use mc_block_import::{BlockImportError, BlockImporter}; use mc_db::db_block_id::DbBlockId; use mc_db::{MadaraBackend, MadaraStorageError}; +use mc_devnet::{Call, Multicall, Selector}; use mc_exec::{BlockifierStateAdapter, ExecutionContext}; use mc_mempool::header::make_pending_header; -use mc_mempool::{L1DataProvider, MempoolProvider}; +use mc_mempool::{transaction_hash, L1DataProvider, MempoolProvider}; use mp_block::{BlockId, BlockTag, MadaraPendingBlock, VisitedSegments}; use mp_class::compile::ClassCompilationError; use mp_class::ConvertedClass; use mp_convert::ToFelt; use mp_receipt::from_blockifier_execution_info; use mp_state_update::{ContractStorageDiffItem, StateDiff, StorageEntry}; -use mp_transactions::TransactionWithHash; +use mp_transactions::{BroadcastedTransactionExt, TransactionWithHash}; use mp_utils::service::ServiceContext; use opentelemetry::KeyValue; +use rand::{thread_rng, Rng}; +use starknet::signers::SigningKey; +use starknet_api::transaction::EventKey; use starknet_types_core::felt::Felt; +use starknet_types_rpc::{BroadcastedInvokeTxn, BroadcastedTxn, InvokeTxnV1}; use std::borrow::Cow; use std::collections::VecDeque; use std::mem; +use std::str::FromStr as _; use std::sync::Arc; use std::time::Instant; @@ -60,6 +66,21 @@ struct ContinueBlockStats { pub n_rejected: usize, } +// TODO: might wanna remove the 0 in the start +const SPAWNED_BOT_EVENT_SELECTOR: &str = "0x2cd0383e81a65036ae8acc94ac89e891d1385ce01ae6cc127c27615f5420fa3"; +const BOMB_FOUND_EVENT_SELECTOR: &str = "0x111861367b42e77c11a98efb6d09a14c2dc470eee1a4d2c3c1e8c54015da2e5"; +const DIAMOND_FOUND_EVENT_SELECTOR: &str = "0x14528085c8fd64b9210572c5b6015468f8352c17c9c22f5b7aa62a55a56d8d7"; +const TILE_MINED_SELECTOR: &str = "0xd5efc9cfb6a4f6bb9eae0ce39d32480473877bb3f7a4eaa3944c881a2c8d25"; +const TILE_ALREADY_MINED_SELECTOR: &str = "0x01b74d97806c93468070e49a1626aba00f8e89dfb07246492af4566f898de982"; +const SUSPEND_BOT_SELECTOR: &str = "0x01dcca826eea45d96bfbf26e9aabf510e94c6de62d0ce5e5b6e60c51c7640af8"; +const REVIVE_BOT_SELECTOR: &str = "0x01d6a6a42fd13b206a721dbca3ae720621707ef3016850e2c5536244e5a7858a"; +const EXECUTOR_ADDRESS: &str = "0x055be462e718c4166d656d11f89e341115b8bc82389c3762a10eade04fcb225d"; +const EXECUTOR_PRIVATE_KEY: &str = "0x077e56c6dc32d40a67f6f7e6625c8dc5e570abe49c0a24e9202e4ae906abcc07"; +const GAME_CONTRACT_ADDRESS: &str = "0x1d403911bd0f8c4a83e6504f7a84a4fbb1a255ce9b36b67edfb53a110fca5f4"; +// Game Config +const GAME_WIDTH: u64 = 100; +const GAME_HEIGHT: u64 = 100; + #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Storage error: {0:#}")] @@ -220,7 +241,19 @@ impl BlockProductionTask { stats.n_batches += 1; // Execute the transactions. + let start = Instant::now(); let all_results = self.executor.execute_txs(&txs_to_process_blockifier); + let end = start.elapsed(); + + println!(">>> Execution returned with : {:?} within {:?} ", all_results.len(), end); + + // println!(">>> TXNS TO PROCESS BLOCKFIER LENGTH : {:?} ", txs_to_process_blockifier.len()); + // println!(">>> TXNS TO PROCESS BLOCKFIER : {:?} ", txs_to_process_blockifier); + + // println!(">>> Txn Receipt {:?}", all_results); + + let _ress = self.listen_for_bot_events(&all_results).expect("Couldn't ingest Bot events"); + // When the bouncer cap is reached, blockifier will return fewer results than what we asked for. block_now_full = all_results.len() < txs_to_process_blockifier.len(); @@ -247,6 +280,8 @@ impl BlockProductionTask { self.declared_classes.push(class); } + // TODO: add here the event listening logic + self.block .inner .receipts @@ -297,6 +332,160 @@ impl BlockProductionTask { Ok(ContinueBlockResult { state_diff, visited_segments, bouncer_weights, stats, block_now_full }) } + pub fn listen_for_bot_events( + &mut self, + all_txns: &Vec< + Result< + blockifier::transaction::objects::TransactionExecutionInfo, + blockifier::blockifier::transaction_executor::TransactionExecutorError, + >, + >, + ) -> Result<(), Error> { + // search through all_txns and get SpawnedBot or BombFound events + + let mut spawned_bots: Vec = Vec::new(); + let mut killed_bots: Vec = Vec::new(); + + // events: [OrderedEvent { order: 0, event: EventContent { keys: [EventKey(0x2cd0383e81a65036ae8acc94ac89e891d1385ce01ae6cc127c27615f5420fa3)], + // data: EventData([0x7484e8e3af210b2ead47fa08c96f8d18b616169b350a8b75fe0dc4d2e01d493, 0x1c9, 0x66dbd884899534c3ba7216743e8d0a683e3c5b5b8cac37441f55c1b43a8019c]) } }], + + // The logic below is written assuming that the event will have one key and 3 values. + + for tx in all_txns { + if tx.is_err() { + continue; + } + let tx = tx.as_ref().unwrap(); + + let execute_call_info = &tx.execute_call_info.as_ref(); + + if let Some(execute_call) = execute_call_info { + let inner_calls: &Vec = execute_call.inner_calls.as_ref(); + + for values in inner_calls { + let ordered_events: &Vec = + values.execution.events.as_ref(); + + for ordered_event in ordered_events.iter() { + let event = ordered_event.event.to_owned(); + + let spawned_bot_felt = Felt::from_str(SPAWNED_BOT_EVENT_SELECTOR) + .expect("Unable to convert selector string to felt"); // Or however you get your Felt value + + let bomb_found_felt = Felt::from_str(BOMB_FOUND_EVENT_SELECTOR) + .expect("Unable to convert selector string to felt"); // Or however you get your Felt value + + let diamond_found_felt = Felt::from_str(DIAMOND_FOUND_EVENT_SELECTOR) + .expect("Unable to convert selector string to felt"); // Or however you get your Felt value + + let tile_mined_felt = + Felt::from_str(TILE_MINED_SELECTOR).expect("Unable to convert selector string to felt"); // Or however you get your Felt value + + let tile_already_mined_felt = Felt::from_str(TILE_ALREADY_MINED_SELECTOR) + .expect("Unable to convert selector string to felt"); // Or however you get your Felt value + + let suspend_bot_felt = + Felt::from_str(SUSPEND_BOT_SELECTOR).expect("Unable to convert selector string to felt"); // Or however you get your Felt value + + let revive_bot_felt = + Felt::from_str(REVIVE_BOT_SELECTOR).expect("Unable to convert selector string to felt"); // Or however you get your Felt value + + for key in event.keys { + // BombFound + if key == EventKey(bomb_found_felt) { + let bot_address = event.data.0[0].to_string(); + let bot_location = event.data.0[1].to_string(); + println!( + ">>> Event : BombFound by {:?} at {:?}", + Felt::from_str(bot_address.as_str()).expect("Could not get address"), + bot_location + ); + killed_bots.push(bot_address); + } + // DiamondFound + else if key == EventKey(diamond_found_felt) { + let bot_address = event.data.0[0].to_string(); + let bot_points = event.data.0[1].to_string(); + let bot_location = event.data.0[2].to_string(); + println!( + ">>> Event : DiamondFound by {:?} at {:?} for {:?}", + Felt::from_str(bot_address.as_str()).expect("Could not get address"), + bot_location, + bot_points + ); + } + // TileMined + else if key == EventKey(tile_mined_felt) { + let bot_address = event.data.0[0].to_string(); + let points = event.data.0[1].to_string(); + let location = event.data.0[2].to_string(); + println!( + ">>> Event : TileMined by {:?} at {:?} for {:?}", + Felt::from_str(bot_address.as_str()).expect("Could not get address"), + location, + points + ); + self.backend + .update_game_metadata(|meta| { + meta.tiles_mined += 1; + }) + .expect("could not update the tiles mined number"); + } + // TileAlreadyMined + else if key == EventKey(tile_already_mined_felt) { + let bot_address = event.data.0[0].to_string(); + let bot_location = event.data.0[1].to_string(); + println!( + ">>> Event : TileAlreadyMined {:?} at {:?}", + Felt::from_str(bot_address.as_str()), + bot_location + ); + } + // SpawnedBot + else if key == EventKey(spawned_bot_felt) { + let bot_address = event.data.0[0].to_string(); + let player = event.data.0[1].to_string(); + let bot_location = event.data.0[2].to_string(); + println!( + ">>> Event : SpawnedBot {:?} at {:?} by {:?}", + Felt::from_str(bot_address.as_str()), + bot_location, + player + ); + spawned_bots.push(bot_address); + } + // SuspendBot + else if key == EventKey(suspend_bot_felt) { + let bot_address = event.data.0[0].to_string(); + println!(">>> Event : SuspendBot {:?}", Felt::from_str(bot_address.as_str())); + // TODO: add kill bot here if needed. + } + // ReviveBot + else if key == EventKey(revive_bot_felt) { + let bot_address = event.data.0[0].to_string(); + println!(">>> Event : ReviveBot {:?}", Felt::from_str(bot_address.as_str())); + // TODO: add spawned bot here if needed. + } + } + } + } + } + } + + // Kill all the bots ! + // TODO: these are multiple DB operations, can it be clubbed to a single operation + for killed_bot in killed_bots { + let _ = self.backend.delete_game_address(&killed_bot.as_str()).expect("Could not remove the bot"); + } + + // Add new bots ! + for spawned_bot in spawned_bots { + let _ = self.backend.add_game_address(&spawned_bot.as_str()).expect("Could not add the bot"); + } + + Ok(()) + } + /// Closes the current block and prepares for the next one #[tracing::instrument(skip(self), fields(module = "BlockProductionTask"))] async fn close_and_prepare_next_block( @@ -358,8 +547,10 @@ impl BlockProductionTask { Ok(()) } + /// Each "tick" of the block time updates the pending block but only with the appropriate fraction of the total bouncer capacity. #[tracing::instrument(skip(self), fields(module = "BlockProductionTask"))] pub async fn on_pending_time_tick(&mut self) -> Result { + let start = Instant::now(); let current_pending_tick = self.current_pending_tick; if current_pending_tick == 0 { return Ok(false); @@ -401,6 +592,41 @@ impl BlockProductionTask { // do not forget to flush :) self.backend.flush().map_err(|err| BlockImportError::Internal(format!("DB flushing error: {err:#}").into()))?; + // TODO: Measure the transactions time -------------------------------------------------- + // TODO: Do all of it inside a function + // ========================================================================================= + // Execute BOT transactions : + + let game_metadata = self.backend.get_game_metadata().expect("Unable to fetch last start index"); + let bot_addresses = self.backend.get_bots_list().expect("Could not get bots' list"); + if game_metadata.tiles_mined < GAME_HEIGHT * GAME_WIDTH && bot_addresses.len() > 0 { + println!(">>> Triggering bot transactions"); + println!( + ">>> Current Tiles mined : {:?} vs total to be mined : {:?}", + game_metadata.tiles_mined, + GAME_HEIGHT * GAME_WIDTH + ); + let addresses_clone = bot_addresses.clone(); + + let c = bot_addresses + .iter() + .map(|x| Felt::from_str(x).expect("could not convert string to felt")) + .collect::>(); + + println!(">>> DB bots list : {:?}", c); + // Do nothing if 0 bots to execute + if bot_addresses.is_empty() { + return Ok(false); + } + // TODO: check if game is active or not + // TODO: what is bot is disabled ? + + let txn = self.generate_txns(addresses_clone); + self.mempool.accept_invoke_tx_broadcast_txn(txn).expect("Unable to accept invoke tx"); + println!(">>> Time taken to run on_pending_tick: {:?}", start.elapsed().as_millis()); + + // ========================================================================================= + } Ok(false) } @@ -511,6 +737,61 @@ impl BlockProductionTask { Ok(()) } + fn generate_txns(&self, contract_addresses: Vec) -> BroadcastedTxn { + let sequencer_priv_key = Felt::from_hex(EXECUTOR_PRIVATE_KEY).expect("Unable to extract priv key from hex"); + let sequencer_address = Felt::from_hex(EXECUTOR_ADDRESS).expect("Unable to extract public key from hex"); + let game_address = Felt::from_hex(GAME_CONTRACT_ADDRESS).expect("Unable to extract public key from hex"); + + let signing_key = SigningKey::from_secret_scalar(sequencer_priv_key); + + // TODO: Either fetch nonce from code or from db, don't use the current incode storage method + let nonce = self + .backend + .get_contract_nonce_at(&DbBlockId::Pending, &sequencer_address) + .expect("Unable to fetch nonce from the block.") + .expect("Nonce is none"); + + println!(">>> TXN NONCE {:?}", nonce); + + let mut call_vec = Vec::new(); + for address in contract_addresses { + let random_seed: u64 = thread_rng().gen(); + call_vec.push(Call { + to: game_address, + selector: Selector::from("mine"), + calldata: vec![Felt::from_str(&address).unwrap(), Felt::from(random_seed)], + }) + } + + // TODO: This is using devnet dependencies, might not be ideal + let txn = BroadcastedTxn::Invoke(BroadcastedInvokeTxn::V1(InvokeTxnV1 { + sender_address: sequencer_address, + calldata: Multicall::with_vec(call_vec).flatten().collect(), + max_fee: Felt::from_hex("2386f26fc10000").unwrap(), + signature: vec![], // will be added when signing + nonce, + })); + self.sign_tx(txn, signing_key.clone()).expect("Not able to sign the transaction.") + } + + fn sign_tx(&self, mut tx: BroadcastedTxn, signing_key: SigningKey) -> anyhow::Result> { + let (blockifier_tx, _) = BroadcastedTxn::into_blockifier( + tx.clone(), + self.backend.chain_config().chain_id.to_felt(), + self.backend.chain_config().latest_protocol_version, + )?; + let signature = signing_key.sign(&transaction_hash(&blockifier_tx))?; + let tx_signature = match &mut tx { + BroadcastedTxn::Invoke(tx) => match tx { + BroadcastedInvokeTxn::V1(tx) => &mut tx.signature, + _ => panic!("Invalid Txn"), + }, + _ => panic!("Invalid Txn"), + }; + *tx_signature = vec![signature.r, signature.s]; + Ok(tx) + } + fn block_n(&self) -> u64 { self.executor.block_context.block_info().block_number.0 } @@ -518,6 +799,128 @@ impl BlockProductionTask { #[cfg(test)] mod tests { + use std::str::FromStr; + + use super::*; + use starknet_types_core::felt::Felt; + + // Helper function to create test bots + fn create_test_bots(count: i64) -> Vec { + // format : 0x + (0..count).map(|i| Felt::from_str(&format!("0x{i}")).unwrap()).collect() + } + + // Helper function to verify distribution properties + fn verify_distribution(result: &Vec, expected_len: i64, original_bots: &Vec) { + assert_eq!(result.len(), expected_len as usize, "Result length should match MINES_PER_TRANSACTION"); + + for bot in result { + assert!(original_bots.contains(bot), "Every bot in result should exist in original list"); + } + } + + // These tests can be more stressing + // #[test] + // fn test_less_bots_than_mines() { + // let num_bots: i64 = 137; + // let bots = create_test_bots(num_bots); // 100 bots < 500 MINES_PER_TRANSACTION + // let start_index = 124; + + // // Array : 51 to 100, then 1 to 100 4 times, then 1 to 50 + + // let (result, new_start_index) = get_bots_list(); + + // verify_distribution(&result, MINES_PER_TRANSACTION, &bots); + + // // Each bot should appear multiple times + // let repetitions = MINES_PER_TRANSACTION / num_bots; + // let mut count_map = std::collections::HashMap::new(); + // for bot in &result { + // *count_map.entry(bot).or_insert(0) += 1; + // } + + // println!("test_less_bots_than_mines : {:?}", result); + // println!("test_less_bots_than_mines last index : {:?}", new_start_index); + + // // Check if each bot appears at least the minimum number of times + // for count in count_map.values() { + // assert!(*count >= repetitions, "Each bot should appear at least {} times", repetitions); + // } + // } + + // #[test] + // fn test_equal_bots_to_mines() { + // let bots = create_test_bots(MINES_PER_TRANSACTION); + // let start_index = 36; + + // let (result, new_start_index) = get_bots_list(bots.clone(), start_index); + + // verify_distribution(&result, MINES_PER_TRANSACTION, &bots); + + // // Each bot should appear exactly once + // let mut count_map = std::collections::HashMap::new(); + // for bot in &result { + // *count_map.entry(bot).or_insert(0) += 1; + // } + + // println!("test_equal_bots_to_mines : {:?}", result); + // println!("test_equal_bots_to_mines last index : {:?}", new_start_index); + + // for count in count_map.values() { + // assert_eq!(*count, 1, "Each bot should appear exactly once"); + // } + // } + + // #[test] + // fn test_more_bots_than_mines() { + // let bots = create_test_bots(3110); // 1000 bots > 500 MINES_PER_TRANSACTION + // let start_index = 457; + + // let (result, new_start_index) = get_bots_list(bots.clone(), start_index); + + // verify_distribution(&result, MINES_PER_TRANSACTION, &bots); + + // // Each bot should appear at most once + // let mut count_map = std::collections::HashMap::new(); + // for bot in &result { + // *count_map.entry(bot).or_insert(0) += 1; + // } + + // println!("test_more_bots_than_mines : {:?}", result); + // println!("test_more_bots_than_mines last index : {:?}", new_start_index); + + // for count in count_map.values() { + // assert_eq!(*count, 1, "Each bot should appear exactly once"); + // } + + // // Verify that we start from last_index + // assert_eq!(result[0], bots[start_index as usize], "First bot should match the last_index position"); + // } + + // #[test] + // fn test_empty_bots_list() { + // let bots = Vec::new(); + // let last_index = 0; + + // let (result, new_index) = get_bots_list(bots, last_index); + + // assert_eq!(result.len(), 0, "Result should be empty for empty input"); + // assert_eq!(new_index, 0, "New index should be 0 for empty input"); + // } + + // #[test] + // fn test_index_wrapping() { + // let bots = create_test_bots(200); + // let last_index = 150; // Near the end of the list + + // let (result, new_index) = get_bots_list(bots.clone(), last_index); + + // verify_distribution(&result, MINES_PER_TRANSACTION, &bots); + + // // Verify that the list wraps around correctly + // assert!(new_index < bots.len() as i64, "New index should wrap around"); + // } + use std::{collections::HashMap, sync::Arc}; use blockifier::{compiled_class_hash, nonce, state::cached_state::StateMaps, storage_key}; @@ -532,7 +935,6 @@ mod tests { core::{ClassHash, ContractAddress, PatriciaKey}, felt, patricia_key, }; - use starknet_types_core::felt::Felt; use crate::finalize_execution_state::state_map_to_state_diff; diff --git a/crates/client/db/Cargo.toml b/crates/client/db/Cargo.toml index f78e62c542..5645e43899 100644 --- a/crates/client/db/Cargo.toml +++ b/crates/client/db/Cargo.toml @@ -41,6 +41,7 @@ librocksdb-sys = { workspace = true } rayon = { workspace = true } rocksdb.workspace = true serde = { workspace = true } +serde_json = { workspace = true } tempfile = { workspace = true, optional = true } thiserror = { workspace = true } tokio = { workspace = true, features = [ diff --git a/crates/client/db/src/game_db.rs b/crates/client/db/src/game_db.rs new file mode 100644 index 0000000000..e91e6f22fe --- /dev/null +++ b/crates/client/db/src/game_db.rs @@ -0,0 +1,336 @@ +// use std::str::FromStr as _; + +// use crate::DatabaseExt; +// use crate::{Column, MadaraBackend, MadaraStorageError}; +// use rocksdb::{WriteBatch, WriteOptions}; +// use serde::{Deserialize, Serialize}; +// use starknet_types_core::felt::Felt; + +// // TODO: add a single key value pair, that stores the start_index + +// const COUNTER_KEY: &[u8] = b"bot_address_counter"; +// const NEXT_START_INDEX_KEY: &'static [u8] = b"last_start_index"; + +// type Result = std::result::Result; + +// impl MadaraBackend { +// /// Add address to the end of sequence +// /// Time Complexity: O(log N) +// #[tracing::instrument(skip(self), fields(module = "GameDB"))] +// pub fn add_game_address(&self, address: &str) -> Result<(), rocksdb::Error> { +// let col = self.db.get_column(Column::Game); + +// // Get the counter +// let current_seq = self +// .db +// .get_cf(&col, COUNTER_KEY)? +// .and_then(|bytes| String::from_utf8(bytes).ok()) +// .and_then(|s| s.parse::().ok()) +// .unwrap_or(0); + +// // Create key with padded sequence +// let key = format!("{:020}", current_seq); + +// // Batch write (Address and Current Sequence) +// let mut batch = WriteBatch::default(); + +// // increment the counter +// batch.put_cf(&col, COUNTER_KEY, (current_seq + 1).to_string().as_bytes()); +// // add the address +// batch.put_cf(&col, key.as_bytes(), address.as_bytes()); + +// self.db.write(batch) +// } + +// /// Delete specific address +// /// Time Complexity: O(N) +// pub fn delete_game_address(&self, target_address: &str) -> Result<(), rocksdb::Error> { +// let col = self.db.get_column(Column::Game); + +// let target_bytes = target_address.as_bytes(); + +// // Iterate to find matching address +// let iter = self.db.iterator_cf(&col, rocksdb::IteratorMode::Start); +// for result in iter { +// let (key, value) = result?; +// if key != COUNTER_KEY.into() && value == target_bytes.into() { +// return self.db.delete_cf(&col, key); +// } +// } +// // TODO: this counter logic is flawed +// // TODO: need to manage a manual indexing + +// // TODO: We also need to update the start_index accordingly + +// Ok(()) // Address not found +// } + +// /// Get all addresses in order of addition +// /// Time Complexity: O(N) +// pub fn get_all_game_addresses(&self) -> Result, rocksdb::Error> { +// let col = self.db.get_column(Column::Game); +// let mut addresses = Vec::new(); + +// let iter = self.db.iterator_cf(&col, rocksdb::IteratorMode::Start); +// for result in iter { +// let (key, value) = result?; +// println!(" >>> Values >>> {:?} : {:?}", String::from_utf8_lossy(&key), String::from_utf8_lossy(&value)); +// if key != COUNTER_KEY.into() && key != NEXT_START_INDEX_KEY.into() { +// if let Ok(address) = String::from_utf8(value.to_vec()) { +// addresses.push(Felt::from_str(&address).expect("Could not convert address to Felt")); +// } +// } +// } + +// Ok(addresses) +// } + +// // Add new methods for next_start_index +// pub fn update_game_next_start_index(&self, index: i64) -> Result<(), rocksdb::Error> { +// let col = self.db.get_column(Column::Game); +// self.db.put_cf(&col, NEXT_START_INDEX_KEY, index.to_string().as_bytes()) +// } + +// pub fn get_game_next_start_index(&self) -> Result, rocksdb::Error> { +// let col = self.db.get_column(Column::Game); + +// let next_start_index = self +// .db +// .get_cf(&col, NEXT_START_INDEX_KEY)? +// .and_then(|bytes| String::from_utf8(bytes).ok()) +// .and_then(|s| s.parse::().ok()); + +// Ok(next_start_index) +// } +// } + +use crate::DatabaseExt; +use crate::{Column, MadaraBackend}; +use rocksdb::WriteBatch; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct AddressNode { + address: String, + next: Option, // Next address in sequence + previous: Option, // Previous address in sequence +} + +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct ListMetadata { + head: Option, // First address + tail: Option, // Last address + pub next_iter_addr: Option, // Next address for iterator + pub length: u64, // Number of addresses in list + pub tiles_mined: u64, // Number of tiles mined +} + +const MINES_PER_TRANSACTION: i64 = 50; +const METADATA_KEY: &[u8] = b"list_metadata"; + +impl MadaraBackend { + pub fn get_game_metadata(&self) -> Result { + let col = self.db.get_column(Column::Game); + let meta = self + .db + .get_cf(&col, METADATA_KEY)? + .map(|bytes| serde_json::from_slice(&bytes).unwrap()) + .unwrap_or(ListMetadata::default()); + Ok(meta) + } + + pub fn update_game_metadata(&self, updates: impl FnOnce(&mut ListMetadata)) -> Result<(), rocksdb::Error> { + let col = self.db.get_column(Column::Game); + let mut batch = WriteBatch::default(); + + // Get current metadata or create default if none exists + let mut metadata = self + .db + .get_cf(&col, METADATA_KEY)? + .map(|bytes| serde_json::from_slice(&bytes).unwrap()) + .unwrap_or(ListMetadata::default()); + + // Apply the updates to the metadata + updates(&mut metadata); + + // Serialize and write the updated metadata + let serialized = serde_json::to_vec(&metadata).unwrap(); + batch.put_cf(&col, METADATA_KEY, serialized); + + // Write the batch to the database + self.db.write(batch)?; + + Ok(()) + } + + /// Add new game address to the linked list + /// 1. Create new node with current address, with previous pointing to old tail + /// 2. Add new node to the database + /// 3. If it's first address, set head & tail to this address + /// 4. Update old tail's next field to point to new address + /// 5. Update tail to the new address + /// 6. Update metadata, including tail and length + /// 7. Write batch to the database + pub fn add_game_address(&self, address: &str) -> Result<(), rocksdb::Error> { + let col = self.db.get_column(Column::Game); + let mut meta = self.get_game_metadata()?; + + let new_node = AddressNode { + address: address.to_string(), + next: None, + previous: meta.tail.clone(), // Point to old tail + }; + + let mut batch = WriteBatch::default(); + + // If list is empty + if meta.head.is_none() { + meta.head = Some(address.to_string()); + meta.tail = Some(address.to_string()); + } else { + // Update old tail to point to new address + if let Some(old_tail) = &meta.tail { + let mut old_tail_node: AddressNode = + serde_json::from_slice(&self.db.get_cf(&col, old_tail.as_bytes())?.unwrap()).unwrap(); + old_tail_node.next = Some(address.to_string()); + batch.put_cf(&col, old_tail.as_bytes(), serde_json::to_vec(&old_tail_node).unwrap()); + } + meta.tail = Some(address.to_string()); + } + + meta.length += 1; + + batch.put_cf(&col, address.as_bytes(), serde_json::to_vec(&new_node).unwrap()); + batch.put_cf(&col, METADATA_KEY, serde_json::to_vec(&meta).unwrap()); + + // Added New Node + // Updated old tail to point to new node + // Incremented metadata length by 1 + + self.db.write(batch) + } + + /// Delete a game address from the list + /// 1. Modify next pointer of previous node to point to node after this one + /// 2. Modify previous pointer of next node to point to node before this one + /// 3. Delete provided node. Reduce length by 1 in metadata + /// 4. Write batch to the database + pub fn delete_game_address(&self, address: &str) -> Result<(), rocksdb::Error> { + let col = self.db.get_column(Column::Game); + let mut meta = self.get_game_metadata()?; + + // Get the node to delete + if let Some(node_bytes) = self.db.get_cf(&col, address.as_bytes())? { + let node: AddressNode = serde_json::from_slice(&node_bytes).unwrap(); + let mut batch = WriteBatch::default(); + + // Update previous node's next pointer + if let Some(prev_addr) = &node.previous { + let mut prev_node: AddressNode = + serde_json::from_slice(&self.db.get_cf(&col, prev_addr.as_bytes())?.unwrap()).unwrap(); + prev_node.next = node.next.clone(); + batch.put_cf(&col, prev_addr.as_bytes(), serde_json::to_vec(&prev_node).unwrap()); + } else { + // Deleting head + meta.head = node.next.clone(); + } + + // Update next node's previous pointer + if let Some(next_addr) = &node.next { + let mut next_node: AddressNode = + serde_json::from_slice(&self.db.get_cf(&col, next_addr.as_bytes())?.unwrap()).unwrap(); + next_node.previous = node.previous; + batch.put_cf(&col, next_addr.as_bytes(), serde_json::to_vec(&next_node).unwrap()); + } else { + // Deleting tail + meta.tail = node.previous; + } + + meta.length -= 1; + + // If the deleted node was the one being iterated over, update the next iteration pointer + if let Some(next_iter_addr) = meta.next_iter_addr.as_ref() { + if next_iter_addr == &address { + meta.next_iter_addr = node.next; + } + } + + batch.delete_cf(&col, address.as_bytes()); + batch.put_cf(&col, METADATA_KEY, serde_json::to_vec(&meta).unwrap()); + + // Delete the node + // Updated previous node to point to next node + // Decremented metadata length by 1 + + return self.db.write(batch); + } + + Ok(()) // Address not found + } + + pub fn get_all_game_addresses(&self) -> Result, rocksdb::Error> { + let col = self.db.get_column(Column::Game); + let meta = self.get_game_metadata()?; + let mut addresses = Vec::new(); + + let mut current = meta.head; + while let Some(addr) = current { + addresses.push(addr.clone()); + let node: AddressNode = serde_json::from_slice(&self.db.get_cf(&col, addr.as_bytes())?.unwrap()).unwrap(); + current = node.next; + } + + assert!( + addresses.len() == meta.length as usize, + "fetched addresses list != stored addresses length in metadata" + ); + + Ok(addresses) + } + + pub fn get_bots_list(&self) -> Result, rocksdb::Error> { + let col = self.db.get_column(Column::Game); + let meta = self.get_game_metadata()?; + + let next_start_address = meta.next_iter_addr; + + // Handle empty list case + if meta.length == 0 { + return Ok(vec![]); + } + let mut return_bots = Vec::with_capacity(MINES_PER_TRANSACTION as usize); + + // Start from the given address or head if None + let mut current_address = match next_start_address { + Some(addr) => Some(addr), + None => meta.head.clone(), + }; + + // Keep adding bots until we reach MINES_PER_TRANSACTION + while return_bots.len() < MINES_PER_TRANSACTION as usize { + if let Some(addr) = ¤t_address { + // Add current address + return_bots.push(addr.clone()); + + // Get next address, if we reach end, start from head + let node: AddressNode = + serde_json::from_slice(&self.db.get_cf(&col, addr.as_bytes())?.unwrap()).unwrap(); + + current_address = match node.next { + Some(next) => Some(next), + None => meta.head.clone(), // Wrap around to start + }; + } else { + break; // Should never happen if meta.length > 0 + } + } + + let mut meta = self.get_game_metadata()?; + // Update metadata with next start address + meta.next_iter_addr = current_address; + self.db.put_cf(&col, METADATA_KEY, serde_json::to_vec(&meta).unwrap())?; + // The next start address will be current_address + + Ok(return_bots) + } +} diff --git a/crates/client/db/src/lib.rs b/crates/client/db/src/lib.rs index 6811cf3f61..c7395cb3ad 100644 --- a/crates/client/db/src/lib.rs +++ b/crates/client/db/src/lib.rs @@ -31,6 +31,7 @@ pub mod contract_db; pub mod db_block_id; pub mod db_metrics; pub mod devnet_db; +pub mod game_db; pub mod l1_db; pub mod mempool_db; pub mod storage_updates; @@ -151,6 +152,8 @@ pub enum Column { Devnet, MempoolTransactions, + /// Game DB for Gridy + Game, } impl fmt::Debug for Column { @@ -165,6 +168,7 @@ impl fmt::Display for Column { } } +// TODO: why do I need to explicitly add Column memeber here, can't we fetch it dynamically from Column impl Column { pub const ALL: &'static [Self] = { use Column::*; @@ -198,6 +202,7 @@ impl Column { PendingContractStorage, Devnet, MempoolTransactions, + Game, ] }; pub const NUM_COLUMNS: usize = Self::ALL.len(); @@ -234,6 +239,7 @@ impl Column { PendingContractStorage => "pending_contract_storage", Devnet => "devnet", MempoolTransactions => "mempool_transactions", + Game => "game", } } } diff --git a/crates/client/devnet/src/entrypoint.rs b/crates/client/devnet/src/entrypoint.rs index 3a22ae2ebe..f58de9d528 100644 --- a/crates/client/devnet/src/entrypoint.rs +++ b/crates/client/devnet/src/entrypoint.rs @@ -21,6 +21,10 @@ impl Multicall { self } + pub fn with_vec(calls: Vec) -> Self { + Multicall(calls) + } + pub fn flatten(&self) -> impl Iterator + '_ { [self.0.len().into()].into_iter().chain(self.0.iter().flat_map(|c| c.flatten())) } diff --git a/crates/client/mempool/src/lib.rs b/crates/client/mempool/src/lib.rs index 6103be0cd0..6542072e9c 100644 --- a/crates/client/mempool/src/lib.rs +++ b/crates/client/mempool/src/lib.rs @@ -64,6 +64,10 @@ impl Error { #[cfg_attr(test, mockall::automock)] pub trait MempoolProvider: Send + Sync { fn accept_invoke_tx(&self, tx: BroadcastedInvokeTxn) -> Result, Error>; + fn accept_invoke_tx_broadcast_txn( + &self, + tx: BroadcastedTxn, + ) -> Result, Error>; fn accept_declare_v0_tx(&self, tx: BroadcastedDeclareTransactionV0) -> Result, Error>; fn accept_declare_tx(&self, tx: BroadcastedDeclareTxn) -> Result, Error>; fn accept_deploy_account_tx( @@ -231,10 +235,24 @@ impl MempoolProvider for Mempool { let (btx, class) = tx.into_blockifier(self.chain_id(), self.backend.chain_config().latest_protocol_version)?; let res = AddInvokeTransactionResult { transaction_hash: transaction_hash(&btx) }; + self.accept_tx(btx, class, ArrivedAtTimestamp::now())?; Ok(res) } + /// Custom method to add transaction to the block + fn accept_invoke_tx_broadcast_txn( + &self, + tx: BroadcastedTxn, + ) -> Result, Error> { + let res = + BroadcastedTxn::into_blockifier(tx, self.chain_id(), self.backend.chain_config().latest_protocol_version); + let (tx, classes) = res?; + let res = AddInvokeTransactionResult { transaction_hash: transaction_hash(&tx) }; + self.accept_tx(tx, classes, ArrivedAtTimestamp::now())?; + Ok(res) + } + #[tracing::instrument(skip(self), fields(module = "Mempool"))] fn accept_declare_v0_tx(&self, tx: BroadcastedDeclareTransactionV0) -> Result, Error> { let (btx, class) = tx.into_blockifier(self.chain_id(), self.backend.chain_config().latest_protocol_version)?; From 530c9a7fa7c501de0e6df02004e46e6e5755937d Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Fri, 3 Jan 2025 10:39:12 +0530 Subject: [PATCH 02/11] update: better naming for game_db --- configs/presets/devnet.yaml | 4 +- crates/client/block_production/src/lib.rs | 63 +++++++++++++---------- crates/client/db/src/game_db.rs | 27 +++++----- 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/configs/presets/devnet.yaml b/configs/presets/devnet.yaml index 8cb18c3fec..50e678d48f 100644 --- a/configs/presets/devnet.yaml +++ b/configs/presets/devnet.yaml @@ -2,8 +2,8 @@ chain_name: "Madara" chain_id: "MADARA_DEVNET" feeder_gateway_url: "http://localhost:8080/feeder_gateway/" gateway_url: "http://localhost:8080/gateway/" -native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" -parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" +# native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" +# parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" latest_protocol_version: "0.13.2" block_time: "5s" pending_block_update_time: "1s" diff --git a/crates/client/block_production/src/lib.rs b/crates/client/block_production/src/lib.rs index 8d80aab8b8..ba3c9969ca 100644 --- a/crates/client/block_production/src/lib.rs +++ b/crates/client/block_production/src/lib.rs @@ -17,9 +17,10 @@ use crate::close_block::close_block; use crate::metrics::BlockProductionMetrics; -use blockifier::blockifier::transaction_executor::{TransactionExecutor, BLOCK_STATE_ACCESS_ERR}; +use blockifier::blockifier::transaction_executor::{TransactionExecutor, TransactionExecutorError, BLOCK_STATE_ACCESS_ERR}; use blockifier::bouncer::BouncerWeights; use blockifier::transaction::errors::TransactionExecutionError; +use blockifier::transaction::objects::TransactionExecutionInfo; use finalize_execution_state::StateDiffToStateMapError; use mc_block_import::{BlockImportError, BlockImporter}; use mc_db::db_block_id::DbBlockId; @@ -71,15 +72,17 @@ const SPAWNED_BOT_EVENT_SELECTOR: &str = "0x2cd0383e81a65036ae8acc94ac89e891d138 const BOMB_FOUND_EVENT_SELECTOR: &str = "0x111861367b42e77c11a98efb6d09a14c2dc470eee1a4d2c3c1e8c54015da2e5"; const DIAMOND_FOUND_EVENT_SELECTOR: &str = "0x14528085c8fd64b9210572c5b6015468f8352c17c9c22f5b7aa62a55a56d8d7"; const TILE_MINED_SELECTOR: &str = "0xd5efc9cfb6a4f6bb9eae0ce39d32480473877bb3f7a4eaa3944c881a2c8d25"; -const TILE_ALREADY_MINED_SELECTOR: &str = "0x01b74d97806c93468070e49a1626aba00f8e89dfb07246492af4566f898de982"; -const SUSPEND_BOT_SELECTOR: &str = "0x01dcca826eea45d96bfbf26e9aabf510e94c6de62d0ce5e5b6e60c51c7640af8"; -const REVIVE_BOT_SELECTOR: &str = "0x01d6a6a42fd13b206a721dbca3ae720621707ef3016850e2c5536244e5a7858a"; -const EXECUTOR_ADDRESS: &str = "0x055be462e718c4166d656d11f89e341115b8bc82389c3762a10eade04fcb225d"; -const EXECUTOR_PRIVATE_KEY: &str = "0x077e56c6dc32d40a67f6f7e6625c8dc5e570abe49c0a24e9202e4ae906abcc07"; -const GAME_CONTRACT_ADDRESS: &str = "0x1d403911bd0f8c4a83e6504f7a84a4fbb1a255ce9b36b67edfb53a110fca5f4"; +const TILE_ALREADY_MINED_SELECTOR: &str = "0x1b74d97806c93468070e49a1626aba00f8e89dfb07246492af4566f898de982"; +const SUSPEND_BOT_SELECTOR: &str = "0x1dcca826eea45d96bfbf26e9aabf510e94c6de62d0ce5e5b6e60c51c7640af8"; +const REVIVE_BOT_SELECTOR: &str = "0x1d6a6a42fd13b206a721dbca3ae720621707ef3016850e2c5536244e5a7858a"; + +const SEQUENCER_ADDRESS: &str = "0x008a1719e7ca19f3d91e8ef50a48fc456575f645497a1d55f30e3781f786afe4"; +const SEQUENCER_PRIVATE_KEY: &str = "0x0514977443078cf1e0c36bc88b89ada9a46061a5cf728f40274caea21d76f174"; + +const GAME_CONTRACT_ADDRESS: &str = "0x647ce284953bd650be96bf641bfe9bf55a3fed73f63ab7a2ff3c7c49719e7d"; // Game Config -const GAME_WIDTH: u64 = 100; -const GAME_HEIGHT: u64 = 100; +const GAME_WIDTH: u64 = 10000; +const GAME_HEIGHT: u64 = 1000; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -250,7 +253,10 @@ impl BlockProductionTask { // println!(">>> TXNS TO PROCESS BLOCKFIER LENGTH : {:?} ", txs_to_process_blockifier.len()); // println!(">>> TXNS TO PROCESS BLOCKFIER : {:?} ", txs_to_process_blockifier); - // println!(">>> Txn Receipt {:?}", all_results); + let result: &Vec> = &all_results.as_ref(); + let x = result.iter().map(|x| x.as_ref().unwrap()).collect::>()[0]; + let n_steps = x.transaction_receipt.resources.vm_resources.n_steps; + println!(">>> N_STEPS {:?}", n_steps); let _ress = self.listen_for_bot_events(&all_results).expect("Couldn't ingest Bot events"); @@ -426,7 +432,7 @@ impl BlockProductionTask { points ); self.backend - .update_game_metadata(|meta| { + .game_update_metadata(|meta| { meta.tiles_mined += 1; }) .expect("could not update the tiles mined number"); @@ -437,7 +443,7 @@ impl BlockProductionTask { let bot_location = event.data.0[1].to_string(); println!( ">>> Event : TileAlreadyMined {:?} at {:?}", - Felt::from_str(bot_address.as_str()), + Felt::from_str(bot_address.as_str()).expect("Could not get address"), bot_location ); } @@ -448,22 +454,22 @@ impl BlockProductionTask { let bot_location = event.data.0[2].to_string(); println!( ">>> Event : SpawnedBot {:?} at {:?} by {:?}", - Felt::from_str(bot_address.as_str()), + Felt::from_str(bot_address.as_str()).expect("Could not get address"), bot_location, - player + Felt::from_str(player.as_str()).expect("Could not get address") ); spawned_bots.push(bot_address); } // SuspendBot else if key == EventKey(suspend_bot_felt) { let bot_address = event.data.0[0].to_string(); - println!(">>> Event : SuspendBot {:?}", Felt::from_str(bot_address.as_str())); + println!(">>> Event : SuspendBot {:?}", Felt::from_str(bot_address.as_str()).expect("Could not get address")); // TODO: add kill bot here if needed. } // ReviveBot else if key == EventKey(revive_bot_felt) { let bot_address = event.data.0[0].to_string(); - println!(">>> Event : ReviveBot {:?}", Felt::from_str(bot_address.as_str())); + println!(">>> Event : ReviveBot {:?}", Felt::from_str(bot_address.as_str()).expect("Could not get address")); // TODO: add spawned bot here if needed. } } @@ -475,12 +481,12 @@ impl BlockProductionTask { // Kill all the bots ! // TODO: these are multiple DB operations, can it be clubbed to a single operation for killed_bot in killed_bots { - let _ = self.backend.delete_game_address(&killed_bot.as_str()).expect("Could not remove the bot"); + let _ = self.backend.game_delete_bot_address(&killed_bot.as_str()).expect("Could not remove the bot"); } // Add new bots ! for spawned_bot in spawned_bots { - let _ = self.backend.add_game_address(&spawned_bot.as_str()).expect("Could not add the bot"); + let _ = self.backend.game_add_bot_address(&spawned_bot.as_str()).expect("Could not add the bot"); } Ok(()) @@ -597,8 +603,8 @@ impl BlockProductionTask { // ========================================================================================= // Execute BOT transactions : - let game_metadata = self.backend.get_game_metadata().expect("Unable to fetch last start index"); - let bot_addresses = self.backend.get_bots_list().expect("Could not get bots' list"); + let game_metadata = self.backend.game_get_metadata().expect("Unable to fetch last start index"); + let bot_addresses = self.backend.game_get_bots_list().expect("Could not get bots' list"); if game_metadata.tiles_mined < GAME_HEIGHT * GAME_WIDTH && bot_addresses.len() > 0 { println!(">>> Triggering bot transactions"); println!( @@ -608,12 +614,12 @@ impl BlockProductionTask { ); let addresses_clone = bot_addresses.clone(); - let c = bot_addresses - .iter() - .map(|x| Felt::from_str(x).expect("could not convert string to felt")) - .collect::>(); + // let c = bot_addresses + // .iter() + // .map(|x| Felt::from_str(x).expect("could not convert string to felt")) + // .collect::>(); - println!(">>> DB bots list : {:?}", c); + // println!(">>> DB bots list : {:?}", c); // Do nothing if 0 bots to execute if bot_addresses.is_empty() { return Ok(false); @@ -738,8 +744,8 @@ impl BlockProductionTask { } fn generate_txns(&self, contract_addresses: Vec) -> BroadcastedTxn { - let sequencer_priv_key = Felt::from_hex(EXECUTOR_PRIVATE_KEY).expect("Unable to extract priv key from hex"); - let sequencer_address = Felt::from_hex(EXECUTOR_ADDRESS).expect("Unable to extract public key from hex"); + let sequencer_address = Felt::from_hex(SEQUENCER_ADDRESS).expect("Unable to extract public key from hex"); + let sequencer_priv_key = Felt::from_hex(SEQUENCER_PRIVATE_KEY).expect("Unable to extract priv key from hex"); let game_address = Felt::from_hex(GAME_CONTRACT_ADDRESS).expect("Unable to extract public key from hex"); let signing_key = SigningKey::from_secret_scalar(sequencer_priv_key); @@ -749,7 +755,8 @@ impl BlockProductionTask { .backend .get_contract_nonce_at(&DbBlockId::Pending, &sequencer_address) .expect("Unable to fetch nonce from the block.") - .expect("Nonce is none"); + // if nonce is not found, use 0 + .unwrap_or(Felt::from(0)); println!(">>> TXN NONCE {:?}", nonce); diff --git a/crates/client/db/src/game_db.rs b/crates/client/db/src/game_db.rs index e91e6f22fe..80c5c1b095 100644 --- a/crates/client/db/src/game_db.rs +++ b/crates/client/db/src/game_db.rs @@ -118,6 +118,7 @@ pub struct AddressNode { #[derive(Serialize, Deserialize, Debug, Default)] pub struct ListMetadata { + game_address : String, head: Option, // First address tail: Option, // Last address pub next_iter_addr: Option, // Next address for iterator @@ -125,11 +126,11 @@ pub struct ListMetadata { pub tiles_mined: u64, // Number of tiles mined } -const MINES_PER_TRANSACTION: i64 = 50; +const MINES_PER_TRANSACTION: i64 = 500; const METADATA_KEY: &[u8] = b"list_metadata"; impl MadaraBackend { - pub fn get_game_metadata(&self) -> Result { + pub fn game_get_metadata(&self) -> Result { let col = self.db.get_column(Column::Game); let meta = self .db @@ -139,7 +140,7 @@ impl MadaraBackend { Ok(meta) } - pub fn update_game_metadata(&self, updates: impl FnOnce(&mut ListMetadata)) -> Result<(), rocksdb::Error> { + pub fn game_update_metadata(&self, updates: impl FnOnce(&mut ListMetadata)) -> Result<(), rocksdb::Error> { let col = self.db.get_column(Column::Game); let mut batch = WriteBatch::default(); @@ -163,7 +164,7 @@ impl MadaraBackend { Ok(()) } - /// Add new game address to the linked list + /// Add new bot address to the linked list /// 1. Create new node with current address, with previous pointing to old tail /// 2. Add new node to the database /// 3. If it's first address, set head & tail to this address @@ -171,9 +172,9 @@ impl MadaraBackend { /// 5. Update tail to the new address /// 6. Update metadata, including tail and length /// 7. Write batch to the database - pub fn add_game_address(&self, address: &str) -> Result<(), rocksdb::Error> { + pub fn game_add_bot_address(&self, address: &str) -> Result<(), rocksdb::Error> { let col = self.db.get_column(Column::Game); - let mut meta = self.get_game_metadata()?; + let mut meta = self.game_get_metadata()?; let new_node = AddressNode { address: address.to_string(), @@ -215,9 +216,9 @@ impl MadaraBackend { /// 2. Modify previous pointer of next node to point to node before this one /// 3. Delete provided node. Reduce length by 1 in metadata /// 4. Write batch to the database - pub fn delete_game_address(&self, address: &str) -> Result<(), rocksdb::Error> { + pub fn game_delete_bot_address(&self, address: &str) -> Result<(), rocksdb::Error> { let col = self.db.get_column(Column::Game); - let mut meta = self.get_game_metadata()?; + let mut meta = self.game_get_metadata()?; // Get the node to delete if let Some(node_bytes) = self.db.get_cf(&col, address.as_bytes())? { @@ -268,9 +269,9 @@ impl MadaraBackend { Ok(()) // Address not found } - pub fn get_all_game_addresses(&self) -> Result, rocksdb::Error> { + pub fn game_get_all_bot_addresses(&self) -> Result, rocksdb::Error> { let col = self.db.get_column(Column::Game); - let meta = self.get_game_metadata()?; + let meta = self.game_get_metadata()?; let mut addresses = Vec::new(); let mut current = meta.head; @@ -288,9 +289,9 @@ impl MadaraBackend { Ok(addresses) } - pub fn get_bots_list(&self) -> Result, rocksdb::Error> { + pub fn game_get_bots_list(&self) -> Result, rocksdb::Error> { let col = self.db.get_column(Column::Game); - let meta = self.get_game_metadata()?; + let meta = self.game_get_metadata()?; let next_start_address = meta.next_iter_addr; @@ -325,7 +326,7 @@ impl MadaraBackend { } } - let mut meta = self.get_game_metadata()?; + let mut meta = self.game_get_metadata()?; // Update metadata with next start address meta.next_iter_addr = current_address; self.db.put_cf(&col, METADATA_KEY, serde_json::to_vec(&meta).unwrap())?; From 29f00258dc1adc98a23dac5b63d97971da5ebe76 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Mon, 6 Jan 2025 18:29:59 +0530 Subject: [PATCH 03/11] update: fix commented code --- configs/presets/devnet.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configs/presets/devnet.yaml b/configs/presets/devnet.yaml index 50e678d48f..8cb18c3fec 100644 --- a/configs/presets/devnet.yaml +++ b/configs/presets/devnet.yaml @@ -2,8 +2,8 @@ chain_name: "Madara" chain_id: "MADARA_DEVNET" feeder_gateway_url: "http://localhost:8080/feeder_gateway/" gateway_url: "http://localhost:8080/gateway/" -# native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" -# parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" +native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" +parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" latest_protocol_version: "0.13.2" block_time: "5s" pending_block_update_time: "1s" From ae269211ab9b498bdbaf42e0bd6952ff5e7c5f14 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Tue, 7 Jan 2025 10:09:38 +0530 Subject: [PATCH 04/11] update: remove accept_broadcast_txns --- .../madara/client/block_production/src/lib.rs | 36 ++++-- crates/madara/client/db/src/game_db.rs | 110 +----------------- crates/madara/client/mempool/src/lib.rs | 17 --- 3 files changed, 27 insertions(+), 136 deletions(-) diff --git a/crates/madara/client/block_production/src/lib.rs b/crates/madara/client/block_production/src/lib.rs index ba3c9969ca..6969acd443 100644 --- a/crates/madara/client/block_production/src/lib.rs +++ b/crates/madara/client/block_production/src/lib.rs @@ -17,7 +17,9 @@ use crate::close_block::close_block; use crate::metrics::BlockProductionMetrics; -use blockifier::blockifier::transaction_executor::{TransactionExecutor, TransactionExecutorError, BLOCK_STATE_ACCESS_ERR}; +use blockifier::blockifier::transaction_executor::{ + TransactionExecutor, TransactionExecutorError, BLOCK_STATE_ACCESS_ERR, +}; use blockifier::bouncer::BouncerWeights; use blockifier::transaction::errors::TransactionExecutionError; use blockifier::transaction::objects::TransactionExecutionInfo; @@ -76,12 +78,12 @@ const TILE_ALREADY_MINED_SELECTOR: &str = "0x1b74d97806c93468070e49a1626aba00f8e const SUSPEND_BOT_SELECTOR: &str = "0x1dcca826eea45d96bfbf26e9aabf510e94c6de62d0ce5e5b6e60c51c7640af8"; const REVIVE_BOT_SELECTOR: &str = "0x1d6a6a42fd13b206a721dbca3ae720621707ef3016850e2c5536244e5a7858a"; -const SEQUENCER_ADDRESS: &str = "0x008a1719e7ca19f3d91e8ef50a48fc456575f645497a1d55f30e3781f786afe4"; -const SEQUENCER_PRIVATE_KEY: &str = "0x0514977443078cf1e0c36bc88b89ada9a46061a5cf728f40274caea21d76f174"; +const SEQUENCER_ADDRESS: &str = "0x618e3a340ccc92b620e9ce24deb10bb984f1b4eff62674d777f2a95c12ae309"; +const SEQUENCER_PRIVATE_KEY: &str = "0x6d66835cdd46c3671e2f2830395c1f342ca7fff217a15d10f8fdcdf8b28e454"; -const GAME_CONTRACT_ADDRESS: &str = "0x647ce284953bd650be96bf641bfe9bf55a3fed73f63ab7a2ff3c7c49719e7d"; +const GAME_CONTRACT_ADDRESS: &str = "0x32063c0a85fbdbb0d9f1744c7b0756fdce885b43fdb397e80ece66464477486"; // Game Config -const GAME_WIDTH: u64 = 10000; +const GAME_WIDTH: u64 = 1000; const GAME_HEIGHT: u64 = 1000; #[derive(Debug, thiserror::Error)] @@ -463,13 +465,19 @@ impl BlockProductionTask { // SuspendBot else if key == EventKey(suspend_bot_felt) { let bot_address = event.data.0[0].to_string(); - println!(">>> Event : SuspendBot {:?}", Felt::from_str(bot_address.as_str()).expect("Could not get address")); + println!( + ">>> Event : SuspendBot {:?}", + Felt::from_str(bot_address.as_str()).expect("Could not get address") + ); // TODO: add kill bot here if needed. } // ReviveBot else if key == EventKey(revive_bot_felt) { let bot_address = event.data.0[0].to_string(); - println!(">>> Event : ReviveBot {:?}", Felt::from_str(bot_address.as_str()).expect("Could not get address")); + println!( + ">>> Event : ReviveBot {:?}", + Felt::from_str(bot_address.as_str()).expect("Could not get address") + ); // TODO: add spawned bot here if needed. } } @@ -628,7 +636,7 @@ impl BlockProductionTask { // TODO: what is bot is disabled ? let txn = self.generate_txns(addresses_clone); - self.mempool.accept_invoke_tx_broadcast_txn(txn).expect("Unable to accept invoke tx"); + self.mempool.accept_invoke_tx(txn).expect("Unable to accept invoke tx"); println!(">>> Time taken to run on_pending_tick: {:?}", start.elapsed().as_millis()); // ========================================================================================= @@ -743,7 +751,7 @@ impl BlockProductionTask { Ok(()) } - fn generate_txns(&self, contract_addresses: Vec) -> BroadcastedTxn { + fn generate_txns(&self, contract_addresses: Vec) -> BroadcastedInvokeTxn { let sequencer_address = Felt::from_hex(SEQUENCER_ADDRESS).expect("Unable to extract public key from hex"); let sequencer_priv_key = Felt::from_hex(SEQUENCER_PRIVATE_KEY).expect("Unable to extract priv key from hex"); let game_address = Felt::from_hex(GAME_CONTRACT_ADDRESS).expect("Unable to extract public key from hex"); @@ -774,11 +782,17 @@ impl BlockProductionTask { let txn = BroadcastedTxn::Invoke(BroadcastedInvokeTxn::V1(InvokeTxnV1 { sender_address: sequencer_address, calldata: Multicall::with_vec(call_vec).flatten().collect(), - max_fee: Felt::from_hex("2386f26fc10000").unwrap(), + max_fee: Felt::from_str("100000000").unwrap(), signature: vec![], // will be added when signing nonce, })); - self.sign_tx(txn, signing_key.clone()).expect("Not able to sign the transaction.") + + let signed_transaction = self.sign_tx(txn, signing_key.clone()).expect("Not able to sign the transaction."); + + match signed_transaction { + BroadcastedTxn::Invoke(tx) => tx, + _ => panic!("Invalid Txn"), + } } fn sign_tx(&self, mut tx: BroadcastedTxn, signing_key: SigningKey) -> anyhow::Result> { diff --git a/crates/madara/client/db/src/game_db.rs b/crates/madara/client/db/src/game_db.rs index 80c5c1b095..ae58a403e2 100644 --- a/crates/madara/client/db/src/game_db.rs +++ b/crates/madara/client/db/src/game_db.rs @@ -1,109 +1,3 @@ -// use std::str::FromStr as _; - -// use crate::DatabaseExt; -// use crate::{Column, MadaraBackend, MadaraStorageError}; -// use rocksdb::{WriteBatch, WriteOptions}; -// use serde::{Deserialize, Serialize}; -// use starknet_types_core::felt::Felt; - -// // TODO: add a single key value pair, that stores the start_index - -// const COUNTER_KEY: &[u8] = b"bot_address_counter"; -// const NEXT_START_INDEX_KEY: &'static [u8] = b"last_start_index"; - -// type Result = std::result::Result; - -// impl MadaraBackend { -// /// Add address to the end of sequence -// /// Time Complexity: O(log N) -// #[tracing::instrument(skip(self), fields(module = "GameDB"))] -// pub fn add_game_address(&self, address: &str) -> Result<(), rocksdb::Error> { -// let col = self.db.get_column(Column::Game); - -// // Get the counter -// let current_seq = self -// .db -// .get_cf(&col, COUNTER_KEY)? -// .and_then(|bytes| String::from_utf8(bytes).ok()) -// .and_then(|s| s.parse::().ok()) -// .unwrap_or(0); - -// // Create key with padded sequence -// let key = format!("{:020}", current_seq); - -// // Batch write (Address and Current Sequence) -// let mut batch = WriteBatch::default(); - -// // increment the counter -// batch.put_cf(&col, COUNTER_KEY, (current_seq + 1).to_string().as_bytes()); -// // add the address -// batch.put_cf(&col, key.as_bytes(), address.as_bytes()); - -// self.db.write(batch) -// } - -// /// Delete specific address -// /// Time Complexity: O(N) -// pub fn delete_game_address(&self, target_address: &str) -> Result<(), rocksdb::Error> { -// let col = self.db.get_column(Column::Game); - -// let target_bytes = target_address.as_bytes(); - -// // Iterate to find matching address -// let iter = self.db.iterator_cf(&col, rocksdb::IteratorMode::Start); -// for result in iter { -// let (key, value) = result?; -// if key != COUNTER_KEY.into() && value == target_bytes.into() { -// return self.db.delete_cf(&col, key); -// } -// } -// // TODO: this counter logic is flawed -// // TODO: need to manage a manual indexing - -// // TODO: We also need to update the start_index accordingly - -// Ok(()) // Address not found -// } - -// /// Get all addresses in order of addition -// /// Time Complexity: O(N) -// pub fn get_all_game_addresses(&self) -> Result, rocksdb::Error> { -// let col = self.db.get_column(Column::Game); -// let mut addresses = Vec::new(); - -// let iter = self.db.iterator_cf(&col, rocksdb::IteratorMode::Start); -// for result in iter { -// let (key, value) = result?; -// println!(" >>> Values >>> {:?} : {:?}", String::from_utf8_lossy(&key), String::from_utf8_lossy(&value)); -// if key != COUNTER_KEY.into() && key != NEXT_START_INDEX_KEY.into() { -// if let Ok(address) = String::from_utf8(value.to_vec()) { -// addresses.push(Felt::from_str(&address).expect("Could not convert address to Felt")); -// } -// } -// } - -// Ok(addresses) -// } - -// // Add new methods for next_start_index -// pub fn update_game_next_start_index(&self, index: i64) -> Result<(), rocksdb::Error> { -// let col = self.db.get_column(Column::Game); -// self.db.put_cf(&col, NEXT_START_INDEX_KEY, index.to_string().as_bytes()) -// } - -// pub fn get_game_next_start_index(&self) -> Result, rocksdb::Error> { -// let col = self.db.get_column(Column::Game); - -// let next_start_index = self -// .db -// .get_cf(&col, NEXT_START_INDEX_KEY)? -// .and_then(|bytes| String::from_utf8(bytes).ok()) -// .and_then(|s| s.parse::().ok()); - -// Ok(next_start_index) -// } -// } - use crate::DatabaseExt; use crate::{Column, MadaraBackend}; use rocksdb::WriteBatch; @@ -118,7 +12,7 @@ pub struct AddressNode { #[derive(Serialize, Deserialize, Debug, Default)] pub struct ListMetadata { - game_address : String, + game_address: String, head: Option, // First address tail: Option, // Last address pub next_iter_addr: Option, // Next address for iterator @@ -126,7 +20,7 @@ pub struct ListMetadata { pub tiles_mined: u64, // Number of tiles mined } -const MINES_PER_TRANSACTION: i64 = 500; +const MINES_PER_TRANSACTION: i64 = 5; const METADATA_KEY: &[u8] = b"list_metadata"; impl MadaraBackend { diff --git a/crates/madara/client/mempool/src/lib.rs b/crates/madara/client/mempool/src/lib.rs index 6542072e9c..a2839d8f0a 100644 --- a/crates/madara/client/mempool/src/lib.rs +++ b/crates/madara/client/mempool/src/lib.rs @@ -64,10 +64,6 @@ impl Error { #[cfg_attr(test, mockall::automock)] pub trait MempoolProvider: Send + Sync { fn accept_invoke_tx(&self, tx: BroadcastedInvokeTxn) -> Result, Error>; - fn accept_invoke_tx_broadcast_txn( - &self, - tx: BroadcastedTxn, - ) -> Result, Error>; fn accept_declare_v0_tx(&self, tx: BroadcastedDeclareTransactionV0) -> Result, Error>; fn accept_declare_tx(&self, tx: BroadcastedDeclareTxn) -> Result, Error>; fn accept_deploy_account_tx( @@ -240,19 +236,6 @@ impl MempoolProvider for Mempool { Ok(res) } - /// Custom method to add transaction to the block - fn accept_invoke_tx_broadcast_txn( - &self, - tx: BroadcastedTxn, - ) -> Result, Error> { - let res = - BroadcastedTxn::into_blockifier(tx, self.chain_id(), self.backend.chain_config().latest_protocol_version); - let (tx, classes) = res?; - let res = AddInvokeTransactionResult { transaction_hash: transaction_hash(&tx) }; - self.accept_tx(tx, classes, ArrivedAtTimestamp::now())?; - Ok(res) - } - #[tracing::instrument(skip(self), fields(module = "Mempool"))] fn accept_declare_v0_tx(&self, tx: BroadcastedDeclareTransactionV0) -> Result, Error> { let (btx, class) = tx.into_blockifier(self.chain_id(), self.backend.chain_config().latest_protocol_version)?; From 0eaf8241ec1a04b8f63bd4a6b0c33b8712af6c47 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Tue, 7 Jan 2025 22:46:46 +0530 Subject: [PATCH 05/11] update cleanup --- .../madara/client/block_production/src/lib.rs | 24 ++++++++----------- crates/madara/client/db/src/game_db.rs | 2 +- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/crates/madara/client/block_production/src/lib.rs b/crates/madara/client/block_production/src/lib.rs index 6969acd443..d04083a287 100644 --- a/crates/madara/client/block_production/src/lib.rs +++ b/crates/madara/client/block_production/src/lib.rs @@ -78,13 +78,13 @@ const TILE_ALREADY_MINED_SELECTOR: &str = "0x1b74d97806c93468070e49a1626aba00f8e const SUSPEND_BOT_SELECTOR: &str = "0x1dcca826eea45d96bfbf26e9aabf510e94c6de62d0ce5e5b6e60c51c7640af8"; const REVIVE_BOT_SELECTOR: &str = "0x1d6a6a42fd13b206a721dbca3ae720621707ef3016850e2c5536244e5a7858a"; -const SEQUENCER_ADDRESS: &str = "0x618e3a340ccc92b620e9ce24deb10bb984f1b4eff62674d777f2a95c12ae309"; -const SEQUENCER_PRIVATE_KEY: &str = "0x6d66835cdd46c3671e2f2830395c1f342ca7fff217a15d10f8fdcdf8b28e454"; +const SEQUENCER_ADDRESS: &str = "0x115168e0a250468a4e451fc90f9f64c321488b86ef22a0ba40369bf0630548"; +const SEQUENCER_PRIVATE_KEY: &str = "0x55a5facd0772ba2a534367edcdaeb27f3390d94280c462b7cf604a7eaba8b73"; -const GAME_CONTRACT_ADDRESS: &str = "0x32063c0a85fbdbb0d9f1744c7b0756fdce885b43fdb397e80ece66464477486"; +const GAME_CONTRACT_ADDRESS: &str = "0x7b5b5c15d4f3c454702961631bc10943f59809d0a9558e14e68855b17eeae38"; // Game Config -const GAME_WIDTH: u64 = 1000; -const GAME_HEIGHT: u64 = 1000; +const GAME_WIDTH: u64 = 100; +const GAME_HEIGHT: u64 = 100; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -246,19 +246,17 @@ impl BlockProductionTask { stats.n_batches += 1; // Execute the transactions. - let start = Instant::now(); let all_results = self.executor.execute_txs(&txs_to_process_blockifier); - let end = start.elapsed(); - println!(">>> Execution returned with : {:?} within {:?} ", all_results.len(), end); + // println!(">>> Execution returned with : {:?} within {:?} ", all_results.len(), end); // println!(">>> TXNS TO PROCESS BLOCKFIER LENGTH : {:?} ", txs_to_process_blockifier.len()); // println!(">>> TXNS TO PROCESS BLOCKFIER : {:?} ", txs_to_process_blockifier); - let result: &Vec> = &all_results.as_ref(); - let x = result.iter().map(|x| x.as_ref().unwrap()).collect::>()[0]; - let n_steps = x.transaction_receipt.resources.vm_resources.n_steps; - println!(">>> N_STEPS {:?}", n_steps); + // let result: &Vec> = &all_results.as_ref(); + // let x = result.iter().map(|x| x.as_ref().unwrap()).collect::>()[0]; + // let n_steps = x.transaction_receipt.resources.vm_resources.n_steps; + // println!(">>> N_STEPS {:?}", n_steps); let _ress = self.listen_for_bot_events(&all_results).expect("Couldn't ingest Bot events"); @@ -758,7 +756,6 @@ impl BlockProductionTask { let signing_key = SigningKey::from_secret_scalar(sequencer_priv_key); - // TODO: Either fetch nonce from code or from db, don't use the current incode storage method let nonce = self .backend .get_contract_nonce_at(&DbBlockId::Pending, &sequencer_address) @@ -778,7 +775,6 @@ impl BlockProductionTask { }) } - // TODO: This is using devnet dependencies, might not be ideal let txn = BroadcastedTxn::Invoke(BroadcastedInvokeTxn::V1(InvokeTxnV1 { sender_address: sequencer_address, calldata: Multicall::with_vec(call_vec).flatten().collect(), diff --git a/crates/madara/client/db/src/game_db.rs b/crates/madara/client/db/src/game_db.rs index ae58a403e2..b270578ff1 100644 --- a/crates/madara/client/db/src/game_db.rs +++ b/crates/madara/client/db/src/game_db.rs @@ -20,7 +20,7 @@ pub struct ListMetadata { pub tiles_mined: u64, // Number of tiles mined } -const MINES_PER_TRANSACTION: i64 = 5; +const MINES_PER_TRANSACTION: i64 = 500; const METADATA_KEY: &[u8] = b"list_metadata"; impl MadaraBackend { From dec3ee2c0c5c453eb81a88a4170770d0902a65c4 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Wed, 8 Jan 2025 13:17:40 +0530 Subject: [PATCH 06/11] Merge branch fix/dynamic-block-time to chain/gridy --- .github/dependabot.yml | 7 -- .github/workflows/rust-test.yml | 10 --- CHANGELOG.md | 2 + Cargo.lock | 1 + .../madara/client/block_production/src/lib.rs | 64 +++++++++++-------- crates/madara/client/db/src/lib.rs | 6 +- .../madara/client/db/src/tests/common/mod.rs | 2 +- crates/madara/client/eth/Cargo.toml | 1 + crates/madara/primitives/oracle/Cargo.toml | 1 + crates/madara/primitives/oracle/src/pragma.rs | 7 +- crates/madara/primitives/utils/src/serde.rs | 18 +++++- scripts/e2e-coverage.sh | 40 +++++------- scripts/e2e-tests.sh | 30 ++------- 13 files changed, 90 insertions(+), 99 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ccc65108df..e2f1deb4d0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,10 +5,3 @@ updates: schedule: interval: "weekly" # can be `daily` or `monthly` also open-pull-requests-limit: 10 - ignore: - # match all substrate dependencies - - dependency-name: "frame-*" - - dependency-name: "sp-*" - - dependency-name: "sc-*" - - dependency-name: "substrate-*" - - dependency-name: "pallet-*" diff --git a/.github/workflows/rust-test.yml b/.github/workflows/rust-test.yml index 3a76b05d12..6d13fd4ed1 100644 --- a/.github/workflows/rust-test.yml +++ b/.github/workflows/rust-test.yml @@ -20,16 +20,6 @@ jobs: - uses: foundry-rs/foundry-toolchain@v1 with: version: nightly - - name: Launch Anvil - run: anvil --fork-url $ANVIL_FORK_URL --fork-block-number $ANVIL_BLOCK_NUMBER & - env: - ANVIL_FORK_URL: "https://eth.merkle.io" - ANVIL_BLOCK_NUMBER: 20395662 - - name: Wait for Anvil to be ready - run: | - while ! nc -z localhost 8545; do - sleep 1 - done - name: Run unit tests run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ac02bfcc9..41234439a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Next release +- fix(block_production): dynamic block closing now adds special address with prev block hash +- fix(compilation): crate-level compilation - chore: Move crates under a madara subdir - chore(nix): resolve flake and direnv compatibility issues - fix: Gateway path fix diff --git a/Cargo.lock b/Cargo.lock index 4841c7e51e..57db072ef0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6117,6 +6117,7 @@ version = "0.7.0" dependencies = [ "anyhow", "async-trait", + "mp-utils", "reqwest 0.12.8", "serde", ] diff --git a/crates/madara/client/block_production/src/lib.rs b/crates/madara/client/block_production/src/lib.rs index d04083a287..14cded97af 100644 --- a/crates/madara/client/block_production/src/lib.rs +++ b/crates/madara/client/block_production/src/lib.rs @@ -559,6 +559,29 @@ impl BlockProductionTask { Ok(()) } + fn maybe_add_prev_block_hash(&self, state_diff: &mut StateDiff, block_n: u64) -> Result<(), Error> { + if block_n >= 10 { + let prev_block_number = block_n - 10; + let prev_block_hash = self + .backend + .get_block_hash(&BlockId::Number(prev_block_number)) + .map_err(|err| { + Error::Unexpected( + format!("Error fetching block hash for block {prev_block_number}: {err:#}").into(), + ) + })? + .ok_or_else(|| { + Error::Unexpected(format!("No block hash found for block number {prev_block_number}").into()) + })?; + + state_diff.storage_diffs.push(ContractStorageDiffItem { + address: Felt::ONE, + storage_entries: vec![StorageEntry { key: Felt::from(prev_block_number), value: prev_block_hash }], + }); + } + Ok(()) + } + /// Each "tick" of the block time updates the pending block but only with the appropriate fraction of the total bouncer capacity. #[tracing::instrument(skip(self), fields(module = "BlockProductionTask"))] pub async fn on_pending_time_tick(&mut self) -> Result { @@ -568,13 +591,15 @@ impl BlockProductionTask { return Ok(false); } - // Use full bouncer capacity - let bouncer_cap = self.backend.chain_config().bouncer_config.block_max_capacity; - let start_time = Instant::now(); - let ContinueBlockResult { state_diff, visited_segments, bouncer_weights, stats, block_now_full } = - self.continue_block(bouncer_cap)?; + let ContinueBlockResult { + state_diff: mut new_state_diff, + visited_segments, + bouncer_weights, + stats, + block_now_full, + } = self.continue_block(self.backend.chain_config().bouncer_config.block_max_capacity)?; if stats.n_added_to_block > 0 { tracing::info!( @@ -587,8 +612,11 @@ impl BlockProductionTask { // Check if block is full if block_now_full { + let block_n = self.block_n(); + self.maybe_add_prev_block_hash(&mut new_state_diff, block_n)?; + tracing::info!("Resource limits reached, closing block early"); - self.close_and_prepare_next_block(state_diff, visited_segments, start_time).await?; + self.close_and_prepare_next_block(new_state_diff, visited_segments, start_time).await?; return Ok(true); } @@ -596,7 +624,7 @@ impl BlockProductionTask { // todo, prefer using the block import pipeline? self.backend.store_block( self.block.clone().into(), - state_diff, + new_state_diff, self.declared_classes.clone(), Some(visited_segments), Some(bouncer_weights), @@ -658,27 +686,7 @@ impl BlockProductionTask { block_now_full: _block_now_full, } = self.continue_block(self.backend.chain_config().bouncer_config.block_max_capacity)?; - // SNOS requirement: For blocks >= 10, the hash of the block 10 blocks prior - // at address 0x1 with the block number as the key - if block_n >= 10 { - let prev_block_number = block_n - 10; - let prev_block_hash = self - .backend - .get_block_hash(&BlockId::Number(prev_block_number)) - .map_err(|err| { - Error::Unexpected( - format!("Error fetching block hash for block {prev_block_number}: {err:#}").into(), - ) - })? - .ok_or_else(|| { - Error::Unexpected(format!("No block hash found for block number {prev_block_number}").into()) - })?; - - new_state_diff.storage_diffs.push(ContractStorageDiffItem { - address: Felt::ONE, - storage_entries: vec![StorageEntry { key: Felt::from(prev_block_number), value: prev_block_hash }], - }); - } + self.maybe_add_prev_block_hash(&mut new_state_diff, block_n)?; self.close_and_prepare_next_block(new_state_diff, visited_segments, start_time).await } diff --git a/crates/madara/client/db/src/lib.rs b/crates/madara/client/db/src/lib.rs index add14670df..50fa087d97 100644 --- a/crates/madara/client/db/src/lib.rs +++ b/crates/madara/client/db/src/lib.rs @@ -288,7 +288,7 @@ pub struct MadaraBackend { trie_log_config: TrieLogConfig, sender_block_info: tokio::sync::broadcast::Sender, write_opt_no_wal: WriteOptions, - #[cfg(feature = "testing")] + #[cfg(any(test, feature = "testing"))] _temp_dir: Option, } @@ -379,7 +379,7 @@ impl MadaraBackend { &self.chain_config } - #[cfg(feature = "testing")] + #[cfg(any(test, feature = "testing"))] pub fn open_for_testing(chain_config: Arc) -> Arc { let temp_dir = tempfile::TempDir::with_prefix("madara-test").unwrap(); let db = open_rocksdb(temp_dir.as_ref()).unwrap(); @@ -452,7 +452,7 @@ impl MadaraBackend { trie_log_config, sender_block_info: tokio::sync::broadcast::channel(100).0, write_opt_no_wal: make_write_opt_no_wal(), - #[cfg(feature = "testing")] + #[cfg(any(test, feature = "testing"))] _temp_dir: None, }); backend.check_configuration()?; diff --git a/crates/madara/client/db/src/tests/common/mod.rs b/crates/madara/client/db/src/tests/common/mod.rs index 26e76eef1f..d81d38a152 100644 --- a/crates/madara/client/db/src/tests/common/mod.rs +++ b/crates/madara/client/db/src/tests/common/mod.rs @@ -13,7 +13,7 @@ use mp_transactions::{ use starknet_api::felt; use starknet_types_core::felt::Felt; -#[cfg(feature = "testing")] +#[cfg(any(test, feature = "testing"))] pub mod temp_db { use crate::DatabaseService; use mp_chain_config::ChainConfig; diff --git a/crates/madara/client/eth/Cargo.toml b/crates/madara/client/eth/Cargo.toml index c424a75f1b..d46f3a436b 100644 --- a/crates/madara/client/eth/Cargo.toml +++ b/crates/madara/client/eth/Cargo.toml @@ -84,3 +84,4 @@ tracing-test = "0.2.5" serial_test.workspace = true lazy_static.workspace = true mp-utils = { workspace = true, features = ["testing"] } +mc-mempool = { workspace = true, features = ["testing"] } diff --git a/crates/madara/primitives/oracle/Cargo.toml b/crates/madara/primitives/oracle/Cargo.toml index 898e3735ea..ac17ca6284 100644 --- a/crates/madara/primitives/oracle/Cargo.toml +++ b/crates/madara/primitives/oracle/Cargo.toml @@ -19,5 +19,6 @@ targets = ["x86_64-unknown-linux-gnu"] # Other anyhow.workspace = true async-trait.workspace = true +mp-utils.workspace = true reqwest.workspace = true serde = { workspace = true, features = ["derive"] } diff --git a/crates/madara/primitives/oracle/src/pragma.rs b/crates/madara/primitives/oracle/src/pragma.rs index 5a72b0c044..c93e7da9c1 100644 --- a/crates/madara/primitives/oracle/src/pragma.rs +++ b/crates/madara/primitives/oracle/src/pragma.rs @@ -2,6 +2,7 @@ use std::fmt; use anyhow::{bail, Context}; use async_trait::async_trait; +use mp_utils::serde::{deserialize_url, serialize_url}; use reqwest::Url; use serde::{Deserialize, Serialize}; @@ -11,7 +12,11 @@ pub const DEFAULT_API_URL: &str = "https://api.dev.pragma.build/node/v1/data/"; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PragmaOracle { - #[serde(default = "default_oracle_api_url")] + #[serde( + default = "default_oracle_api_url", + serialize_with = "serialize_url", + deserialize_with = "deserialize_url" + )] pub api_url: Url, #[serde(default)] pub api_key: String, diff --git a/crates/madara/primitives/utils/src/serde.rs b/crates/madara/primitives/utils/src/serde.rs index 54eb458630..df4339e81f 100644 --- a/crates/madara/primitives/utils/src/serde.rs +++ b/crates/madara/primitives/utils/src/serde.rs @@ -2,8 +2,9 @@ use std::time::Duration; use serde::{Deserialize, Deserializer}; use starknet_types_core::felt::Felt; +use url::Url; -use crate::{crypto::ZeroingPrivateKey, parsers::parse_duration}; +use crate::{crypto::ZeroingPrivateKey, parsers::parse_duration, parsers::parse_url}; pub fn deserialize_duration<'de, D>(deserializer: D) -> Result where @@ -23,6 +24,14 @@ where parse_duration(&s).map_err(serde::de::Error::custom).map(Some) } +pub fn deserialize_url<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + parse_url(&s).map_err(serde::de::Error::custom) +} + pub fn serialize_optional_duration(duration: &Option, serializer: S) -> Result where S: serde::Serializer, @@ -45,6 +54,13 @@ where } } +pub fn serialize_url(url: &Url, serializer: S) -> Result +where + S: serde::Serializer, +{ + serializer.serialize_str(url.as_str()) +} + pub fn deserialize_private_key<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/scripts/e2e-coverage.sh b/scripts/e2e-coverage.sh index acfed971ed..60e6c271c0 100755 --- a/scripts/e2e-coverage.sh +++ b/scripts/e2e-coverage.sh @@ -1,33 +1,23 @@ #!/bin/bash set -e -anvil --fork-url https://eth.merkle.io --fork-block-number 20395662 & +# Configuration +export PROPTEST_CASES=5 +export ETH_FORK_URL=https://eth.merkle.io -subshell() { - set -e - rm -f target/madara-* lcov.info +# Clean up previous coverage data +rm -f target/madara-* lcov.info - source <(cargo llvm-cov show-env --export-prefix) +# Set up LLVM coverage environment +source <(cargo llvm-cov show-env --export-prefix) - cargo build --bin madara --profile dev +# Build the binary with coverage instrumentation +cargo build --bin madara --profile dev +export COVERAGE_BIN=$(realpath target/debug/madara) - export COVERAGE_BIN=$(realpath target/debug/madara) - export ETH_FORK_URL=https://eth.merkle.io +# Run tests with coverage collection +cargo test --profile dev "${@:-"--workspace"}" - # wait for anvil - while ! nc -z localhost 8545; do - sleep 1 - done - - - ARGS=$@ - export PROPTEST_CASES=5 - cargo test --profile dev ${ARGS:=--workspace} - - cargo llvm-cov report --lcov --output-path lcov.info - cargo llvm-cov report -} - -(subshell $@ && r=$?) || r=$? -pkill -P $$ -exit $r +# Generate coverage reports +cargo llvm-cov report --lcov --output-path lcov.info # Generate LCOV report +cargo llvm-cov report # Display coverage summary in terminal \ No newline at end of file diff --git a/scripts/e2e-tests.sh b/scripts/e2e-tests.sh index 362d5989d1..9baf73c590 100755 --- a/scripts/e2e-tests.sh +++ b/scripts/e2e-tests.sh @@ -4,29 +4,13 @@ # Usage: ``./scripts/e2e-tests.sh ` set -e -# will also launch anvil and automatically close it down on error or success - +# Configuration export PROPTEST_CASES=10 +export ETH_FORK_URL=https://eth.merkle.io -anvil --fork-url https://eth.merkle.io --fork-block-number 20395662 & - -subshell() { - set -e - cargo build --bin madara --profile dev - - export COVERAGE_BIN=$(realpath target/debug/madara) - export ETH_FORK_URL=https://eth.merkle.io - - # wait for anvil - while ! nc -z localhost 8545; do - sleep 1 - done - - ARGS=$@ - export PROPTEST_CASES=5 - cargo test --profile dev ${ARGS:=--workspace} -} +# Build the binary +cargo build --bin madara --profile dev +export BINARY_PATH=$(realpath target/debug/madara) -(subshell $@ && r=$?) || r=$? -pkill -P $$ -exit $r +# Run the tests +cargo test --profile dev "${@:-"--workspace"}" From 440b3002c938ec9a8e49b79ad9773f58d381e233 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Wed, 8 Jan 2025 16:14:35 +0530 Subject: [PATCH 07/11] update: gridy latest config --- configs/presets/devnet.yaml | 2 +- crates/madara/client/block_production/src/lib.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configs/presets/devnet.yaml b/configs/presets/devnet.yaml index 8cb18c3fec..b820e4182f 100644 --- a/configs/presets/devnet.yaml +++ b/configs/presets/devnet.yaml @@ -5,7 +5,7 @@ gateway_url: "http://localhost:8080/gateway/" native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" latest_protocol_version: "0.13.2" -block_time: "5s" +block_time: "1h" pending_block_update_time: "1s" execution_batch_size: 16 bouncer_config: diff --git a/crates/madara/client/block_production/src/lib.rs b/crates/madara/client/block_production/src/lib.rs index 14cded97af..0316617828 100644 --- a/crates/madara/client/block_production/src/lib.rs +++ b/crates/madara/client/block_production/src/lib.rs @@ -78,12 +78,12 @@ const TILE_ALREADY_MINED_SELECTOR: &str = "0x1b74d97806c93468070e49a1626aba00f8e const SUSPEND_BOT_SELECTOR: &str = "0x1dcca826eea45d96bfbf26e9aabf510e94c6de62d0ce5e5b6e60c51c7640af8"; const REVIVE_BOT_SELECTOR: &str = "0x1d6a6a42fd13b206a721dbca3ae720621707ef3016850e2c5536244e5a7858a"; -const SEQUENCER_ADDRESS: &str = "0x115168e0a250468a4e451fc90f9f64c321488b86ef22a0ba40369bf0630548"; -const SEQUENCER_PRIVATE_KEY: &str = "0x55a5facd0772ba2a534367edcdaeb27f3390d94280c462b7cf604a7eaba8b73"; +const SEQUENCER_ADDRESS: &str = "0x5fb180bdcc8ce0a713dc9d3f86996e86283877c10584d2890aa13e7f858cc49"; +const SEQUENCER_PRIVATE_KEY: &str = "0x646dd016bbdfe5ecec953f7ee476d52b1e3ad8a63b80b69c7cba55bbd41254c"; -const GAME_CONTRACT_ADDRESS: &str = "0x7b5b5c15d4f3c454702961631bc10943f59809d0a9558e14e68855b17eeae38"; +const GAME_CONTRACT_ADDRESS: &str = "0x717d83b72b2bded6509bd4d1375fb4f96381f44347222288c333bd3a8b3e2b2"; // Game Config -const GAME_WIDTH: u64 = 100; +const GAME_WIDTH: u64 = 1000; const GAME_HEIGHT: u64 = 100; #[derive(Debug, thiserror::Error)] From 018463b205fca000fba6f375f221a9e0c74b6e94 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Wed, 15 Jan 2025 00:37:42 +0530 Subject: [PATCH 08/11] update: madara new db --- crates/madara/client/block_production/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/madara/client/block_production/src/lib.rs b/crates/madara/client/block_production/src/lib.rs index 0316617828..525444788b 100644 --- a/crates/madara/client/block_production/src/lib.rs +++ b/crates/madara/client/block_production/src/lib.rs @@ -78,10 +78,10 @@ const TILE_ALREADY_MINED_SELECTOR: &str = "0x1b74d97806c93468070e49a1626aba00f8e const SUSPEND_BOT_SELECTOR: &str = "0x1dcca826eea45d96bfbf26e9aabf510e94c6de62d0ce5e5b6e60c51c7640af8"; const REVIVE_BOT_SELECTOR: &str = "0x1d6a6a42fd13b206a721dbca3ae720621707ef3016850e2c5536244e5a7858a"; -const SEQUENCER_ADDRESS: &str = "0x5fb180bdcc8ce0a713dc9d3f86996e86283877c10584d2890aa13e7f858cc49"; -const SEQUENCER_PRIVATE_KEY: &str = "0x646dd016bbdfe5ecec953f7ee476d52b1e3ad8a63b80b69c7cba55bbd41254c"; +const SEQUENCER_ADDRESS: &str = "0x1bf17dc0a448c77dd4b3e44ab9383fec376f606adcbe7d493b192bbe56dd954"; +const SEQUENCER_PRIVATE_KEY: &str = "0x6a4019e9fadb46a58c5074b0a48d6c7b5a6bcd5387f63a9422764be9c6762d4"; -const GAME_CONTRACT_ADDRESS: &str = "0x717d83b72b2bded6509bd4d1375fb4f96381f44347222288c333bd3a8b3e2b2"; +const GAME_CONTRACT_ADDRESS: &str = "0x704073fac0a0a4bb1e970a19b83ac2bc1f47b627e961c1606483b294afe2062"; // Game Config const GAME_WIDTH: u64 = 1000; const GAME_HEIGHT: u64 = 100; From 0e76ac200958a0f730099d6ecfc34574e3752182 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Wed, 15 Jan 2025 09:39:22 +0530 Subject: [PATCH 09/11] update: from env --- Cargo.lock | 1 + Dockerfile | 2 +- .../madara/client/block_production/Cargo.toml | 1 + .../madara/client/block_production/src/lib.rs | 40 +++++++++++-------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57db072ef0..6d961191b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5505,6 +5505,7 @@ dependencies = [ "assert_matches", "bitvec", "blockifier", + "dotenv", "lazy_static", "mc-analytics", "mc-block-import", diff --git a/Dockerfile b/Dockerfile index 80a7605af1..165e149c29 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN apt-get -y update && \ # Set the working directory WORKDIR /usr/src/madara/ # Copy the source code into the container -COPY Cargo.toml Cargo.lock ./ +COPY Cargo.toml Cargo.lock .db-versions.yml ./ COPY crates crates COPY cairo-artifacts cairo-artifacts diff --git a/crates/madara/client/block_production/Cargo.toml b/crates/madara/client/block_production/Cargo.toml index 9d8ef7d902..7214377e53 100644 --- a/crates/madara/client/block_production/Cargo.toml +++ b/crates/madara/client/block_production/Cargo.toml @@ -80,3 +80,4 @@ tracing-core = { workspace = true, default-features = false } tracing-opentelemetry = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } rand.workspace = true +dotenv.workspace = true diff --git a/crates/madara/client/block_production/src/lib.rs b/crates/madara/client/block_production/src/lib.rs index 525444788b..0cea50d133 100644 --- a/crates/madara/client/block_production/src/lib.rs +++ b/crates/madara/client/block_production/src/lib.rs @@ -56,6 +56,8 @@ mod close_block; mod finalize_execution_state; pub mod metrics; mod re_add_finalized_to_blockifier; +use dotenv::dotenv; +use std::env; #[derive(Default, Clone)] struct ContinueBlockStats { @@ -78,14 +80,6 @@ const TILE_ALREADY_MINED_SELECTOR: &str = "0x1b74d97806c93468070e49a1626aba00f8e const SUSPEND_BOT_SELECTOR: &str = "0x1dcca826eea45d96bfbf26e9aabf510e94c6de62d0ce5e5b6e60c51c7640af8"; const REVIVE_BOT_SELECTOR: &str = "0x1d6a6a42fd13b206a721dbca3ae720621707ef3016850e2c5536244e5a7858a"; -const SEQUENCER_ADDRESS: &str = "0x1bf17dc0a448c77dd4b3e44ab9383fec376f606adcbe7d493b192bbe56dd954"; -const SEQUENCER_PRIVATE_KEY: &str = "0x6a4019e9fadb46a58c5074b0a48d6c7b5a6bcd5387f63a9422764be9c6762d4"; - -const GAME_CONTRACT_ADDRESS: &str = "0x704073fac0a0a4bb1e970a19b83ac2bc1f47b627e961c1606483b294afe2062"; -// Game Config -const GAME_WIDTH: u64 = 1000; -const GAME_HEIGHT: u64 = 100; - #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Storage error: {0:#}")] @@ -585,6 +579,7 @@ impl BlockProductionTask { /// Each "tick" of the block time updates the pending block but only with the appropriate fraction of the total bouncer capacity. #[tracing::instrument(skip(self), fields(module = "BlockProductionTask"))] pub async fn on_pending_time_tick(&mut self) -> Result { + dotenv().ok(); let start = Instant::now(); let current_pending_tick = self.current_pending_tick; if current_pending_tick == 0 { @@ -637,15 +632,18 @@ impl BlockProductionTask { // ========================================================================================= // Execute BOT transactions : + let game_width = env::var("MADARA_GAME_WIDTH").expect("MADARA_GAME_WIDTH not set").parse::().unwrap(); + let game_height = env::var("MADARA_GAME_HEIGHT").expect("MADARA_GAME_HEIGHT not set").parse::().unwrap(); + + println!(">>> Game width : {:?} and height : {:?}", game_width, game_height); + + let area = game_width * game_height; + let game_metadata = self.backend.game_get_metadata().expect("Unable to fetch last start index"); let bot_addresses = self.backend.game_get_bots_list().expect("Could not get bots' list"); - if game_metadata.tiles_mined < GAME_HEIGHT * GAME_WIDTH && bot_addresses.len() > 0 { + if game_metadata.tiles_mined < area && bot_addresses.len() > 0 { println!(">>> Triggering bot transactions"); - println!( - ">>> Current Tiles mined : {:?} vs total to be mined : {:?}", - game_metadata.tiles_mined, - GAME_HEIGHT * GAME_WIDTH - ); + println!(">>> Current Tiles mined : {:?} vs total to be mined : {:?}", game_metadata.tiles_mined, area); let addresses_clone = bot_addresses.clone(); // let c = bot_addresses @@ -758,9 +756,17 @@ impl BlockProductionTask { } fn generate_txns(&self, contract_addresses: Vec) -> BroadcastedInvokeTxn { - let sequencer_address = Felt::from_hex(SEQUENCER_ADDRESS).expect("Unable to extract public key from hex"); - let sequencer_priv_key = Felt::from_hex(SEQUENCER_PRIVATE_KEY).expect("Unable to extract priv key from hex"); - let game_address = Felt::from_hex(GAME_CONTRACT_ADDRESS).expect("Unable to extract public key from hex"); + let x = env::var("MADARA_GAME_SEQUENCER_ADDRESS").unwrap(); + let y = env::var("MADARA_GAME_SEQUENCER_PRIVATE_KEY").unwrap(); + let z = env::var("MADARA_GAME_CONTRACT_ADDRESS").unwrap(); + + println!(">>> SEQUENCER ADDRESS {:?}", x); + println!(">>> SEQUENCER PRIVATE KEY {:?}", y); + println!(">>> GAME ADDRESS {:?}", z); + + let sequencer_address = Felt::from_hex(&x.as_str()).expect("Unable to extract public key from hex"); + let sequencer_priv_key = Felt::from_hex(&y.as_str()).expect("Unable to extract priv key from hex"); + let game_address = Felt::from_hex(&z.as_str()).expect("Unable to extract public key from hex"); let signing_key = SigningKey::from_secret_scalar(sequencer_priv_key); From aa8f061bd9c2941401777b830a6cfc8e915fad21 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Tue, 28 Jan 2025 22:52:06 +0530 Subject: [PATCH 10/11] update: increased event count and added tps env --- crates/madara/client/db/src/game_db.rs | 11 +++++++---- .../resources/versioned_constants_13_2.json | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/madara/client/db/src/game_db.rs b/crates/madara/client/db/src/game_db.rs index b270578ff1..4df1c1b762 100644 --- a/crates/madara/client/db/src/game_db.rs +++ b/crates/madara/client/db/src/game_db.rs @@ -2,6 +2,7 @@ use crate::DatabaseExt; use crate::{Column, MadaraBackend}; use rocksdb::WriteBatch; use serde::{Deserialize, Serialize}; +use std::env; #[derive(Serialize, Deserialize)] pub struct AddressNode { @@ -20,7 +21,6 @@ pub struct ListMetadata { pub tiles_mined: u64, // Number of tiles mined } -const MINES_PER_TRANSACTION: i64 = 500; const METADATA_KEY: &[u8] = b"list_metadata"; impl MadaraBackend { @@ -184,6 +184,9 @@ impl MadaraBackend { } pub fn game_get_bots_list(&self) -> Result, rocksdb::Error> { + let mines_per_transaction = + env::var("MADARA_GAME_TPS").expect("MADARA_GAME_TPS not set").parse::().unwrap(); + let col = self.db.get_column(Column::Game); let meta = self.game_get_metadata()?; @@ -193,7 +196,7 @@ impl MadaraBackend { if meta.length == 0 { return Ok(vec![]); } - let mut return_bots = Vec::with_capacity(MINES_PER_TRANSACTION as usize); + let mut return_bots = Vec::with_capacity(mines_per_transaction as usize); // Start from the given address or head if None let mut current_address = match next_start_address { @@ -201,8 +204,8 @@ impl MadaraBackend { None => meta.head.clone(), }; - // Keep adding bots until we reach MINES_PER_TRANSACTION - while return_bots.len() < MINES_PER_TRANSACTION as usize { + // Keep adding bots until we reach mines_per_transaction + while return_bots.len() < mines_per_transaction as usize { if let Some(addr) = ¤t_address { // Add current address return_bots.push(addr.clone()); diff --git a/crates/madara/primitives/chain_config/resources/versioned_constants_13_2.json b/crates/madara/primitives/chain_config/resources/versioned_constants_13_2.json index 4d3a9ceb9a..f29913cd27 100644 --- a/crates/madara/primitives/chain_config/resources/versioned_constants_13_2.json +++ b/crates/madara/primitives/chain_config/resources/versioned_constants_13_2.json @@ -2,7 +2,7 @@ "tx_event_limits": { "max_data_length": 300, "max_keys_length": 50, - "max_n_emitted_events": 1000 + "max_n_emitted_events": 5000 }, "gateway": { "max_calldata_length": 5000, From f141236658a981d278b24b0ba90cb0a8939fa146 Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Thu, 30 Jan 2025 18:33:19 +0530 Subject: [PATCH 11/11] update build fix --- crates/madara/client/block_production/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/madara/client/block_production/src/lib.rs b/crates/madara/client/block_production/src/lib.rs index 2debdf1efb..afb63c67f0 100644 --- a/crates/madara/client/block_production/src/lib.rs +++ b/crates/madara/client/block_production/src/lib.rs @@ -23,6 +23,7 @@ use blockifier::blockifier::transaction_executor::{ use blockifier::bouncer::BouncerWeights; use blockifier::transaction::errors::TransactionExecutionError; use blockifier::transaction::objects::TransactionExecutionInfo; +use dotenv::dotenv; use finalize_execution_state::StateDiffToStateMapError; use mc_block_import::{BlockImportError, BlockImporter}; use mc_db::db_block_id::DbBlockId; @@ -37,7 +38,7 @@ use mp_class::ConvertedClass; use mp_convert::ToFelt; use mp_receipt::from_blockifier_execution_info; use mp_state_update::{ContractStorageDiffItem, DeclaredClassItem, NonceUpdate, StateDiff, StorageEntry}; -use mp_transactions::TransactionWithHash; +use mp_transactions::{BroadcastedTransactionExt as _, TransactionWithHash}; use mp_utils::service::ServiceContext; use opentelemetry::KeyValue; use rand::{thread_rng, Rng}; @@ -755,7 +756,7 @@ impl BlockProductionTask { // TODO: what is bot is disabled ? let txn = self.generate_txns(addresses_clone); - self.mempool.accept_invoke_tx(txn).expect("Unable to accept invoke tx"); + self.mempool.tx_accept_invoke(txn).expect("Unable to accept invoke tx"); println!(">>> Time taken to run on_pending_tick: {:?}", start.elapsed().as_millis()); // =========================================================================================