Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testnet #7

Merged
merged 4 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ git # Deoxys Changelog

## Next release

- feat: Removal of the hardcoded mainnet configuration
- refactor: pass new CI
- fix(workflows): Fix deoxys CI
- feat(rpc): add_invoke_tx, add_deploy_account_tx, add_declare_tx
Expand Down
26 changes: 20 additions & 6 deletions crates/client/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use mc_genesis_data_provider::GenesisProvider;
pub use mc_rpc_core::utils::*;
pub use mc_rpc_core::{Felt, StarknetReadRpcApiServer, StarknetTraceRpcApiServer, StarknetWriteRpcApiServer};
use mc_storage::OverrideHandle;
use mc_sync::l2::get_config;
use mc_sync::utility::get_highest_block_hash_and_number;
use mc_sync::l2::get_highest_block_hash_and_number;
use mc_sync::utility::get_config;
use mp_block::BlockStatus;
use mp_contract::class::ContractClassWrapper;
use mp_felt::{Felt252Wrapper, Felt252WrapperError};
Expand Down Expand Up @@ -291,7 +291,10 @@ where
&self,
declare_transaction: BroadcastedDeclareTransaction,
) -> RpcResult<DeclareTransactionResult> {
let config = get_config();
let config = get_config().map_err(|e| {
error!("Failed to get config: {e}");
StarknetRpcApiError::InternalServerError
})?;
let sequencer = SequencerGatewayProvider::new(config.feeder_gateway, config.gateway, config.chain_id);

let sequencer_response = match sequencer.add_declare_transaction(declare_transaction).await {
Expand Down Expand Up @@ -321,7 +324,10 @@ where
&self,
invoke_transaction: BroadcastedInvokeTransaction,
) -> RpcResult<InvokeTransactionResult> {
let config = get_config();
let config = get_config().map_err(|e| {
error!("Failed to get config: {e}");
StarknetRpcApiError::InternalServerError
})?;
let sequencer = SequencerGatewayProvider::new(config.feeder_gateway, config.gateway, config.chain_id);

let sequencer_response = match sequencer.add_invoke_transaction(invoke_transaction).await {
Expand Down Expand Up @@ -352,7 +358,10 @@ where
&self,
deploy_account_transaction: BroadcastedDeployAccountTransaction,
) -> RpcResult<DeployAccountTransactionResult> {
let config = get_config();
let config = get_config().map_err(|e| {
error!("Failed to get config: {e}");
StarknetRpcApiError::InternalServerError
})?;
let sequencer = SequencerGatewayProvider::new(config.feeder_gateway, config.gateway, config.chain_id);

let sequencer_response = match sequencer.add_deploy_account_transaction(deploy_account_transaction).await {
Expand Down Expand Up @@ -959,7 +968,12 @@ where
/// defined by the Starknet protocol, indicating the particular network.
fn chain_id(&self) -> RpcResult<Felt> {
let best_block_hash = self.client.info().best_hash;
let chain_id = get_config().chain_id;
let chain_id = get_config()
.map_err(|e| {
error!("Failed to get config: {e}");
StarknetRpcApiError::InternalServerError
})?
.chain_id;

Ok(Felt(chain_id))
}
Expand Down
4 changes: 2 additions & 2 deletions crates/client/sync/src/commitments/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ pub fn event_commitment<B: BlockT>(events: &[Event], bonsai_db: &Arc<BonsaiDb<B>
}

let id = id_builder.new_id();
bonsai_storage.commit(id).map_err(|_| format!("Failed to commit to bonsai storage"))?;
bonsai_storage.commit(id).map_err(|_| "Failed to commit to bonsai storage")?;

// restores the Bonsai Trie to it's previous state
let root_hash = bonsai_storage.root_hash().map_err(|_| format!("Failed to get root hash"))?;
let root_hash = bonsai_storage.root_hash().map_err(|_| "Failed to get root hash")?;
bonsai_storage.revert_to(zero).unwrap();

Ok(Felt252Wrapper::from(root_hash))
Expand Down
16 changes: 7 additions & 9 deletions crates/client/sync/src/l1.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Contains the necessaries to perform an L1 verification of the state

use std::str::FromStr;
use std::sync::{Arc, Mutex};

use anyhow::Result;
Expand All @@ -19,8 +18,8 @@ use serde_json::Value;
use starknet_api::hash::StarkHash;

use crate::l2::STARKNET_STATE_UPDATE;
use crate::utility::{event_to_l1_state_update, get_state_update_at};
use crate::utils::constant::{starknet_core_address, LOG_STATE_UPDTATE_TOPIC};
use crate::utility::{event_to_l1_state_update, get_config, get_state_update_at};
use crate::utils::constant::LOG_STATE_UPDTATE_TOPIC;

lazy_static! {
/// Shared latest L2 state update verified on L1
Expand Down Expand Up @@ -83,8 +82,7 @@ impl EthereumClient {
/// Get the block number of the last occurrence of a given event.
pub async fn get_last_event_block_number(&self) -> Result<u64, Box<dyn std::error::Error>> {
let topic = H256::from_slice(&hex::decode(&LOG_STATE_UPDTATE_TOPIC[2..])?);
let address =
Address::from_str(starknet_core_address::MAINNET).map_err(|e| format!("Failed to parse address: {}", e))?;
let address = get_config()?.l1_core_address;
let latest_block = self.get_latest_block_number().await.expect("Failed to retrieve latest block number");

// Assuming an avg Block time of 15sec we check for a LogStateUpdate occurence in the last ~24h
Expand All @@ -107,7 +105,7 @@ impl EthereumClient {
/// Get the last Starknet block number verified on L1
pub async fn get_last_block_number(&self) -> Result<u64> {
let data = decode("35befa5d")?;
let to: Address = starknet_core_address::MAINNET.parse()?;
let to: Address = get_config().expect("Failed to get config").l1_core_address;
let tx_request = TransactionRequest::new().to(to).data(data);
let tx = TypedTransaction::Legacy(tx_request);
let result = self.provider.call(&tx, None).await.expect("Failed to get last block number");
Expand All @@ -121,7 +119,7 @@ impl EthereumClient {
/// Get the last Starknet state root verified on L1
pub async fn get_last_state_root(&self) -> Result<StarkHash> {
let data = decode("9588eca2")?;
let to: Address = starknet_core_address::MAINNET.parse()?;
let to: Address = get_config().expect("Failed to get config").l1_core_address;
let tx_request = TransactionRequest::new().to(to).data(data);
let tx = TypedTransaction::Legacy(tx_request);
let result = self.provider.call(&tx, None).await.expect("Failed to get last state root");
Expand All @@ -131,7 +129,7 @@ impl EthereumClient {
/// Get the last Starknet block hash verified on L1
pub async fn get_last_block_hash(&self) -> Result<StarkHash> {
let data = decode("0x382d83e3")?;
let to: Address = starknet_core_address::MAINNET.parse()?;
let to: Address = get_config().expect("Failed to get config").l1_core_address;
let tx_request = TransactionRequest::new().to(to).data(data);
let tx = TypedTransaction::Legacy(tx_request);
let result = self.provider.call(&tx, None).await.expect("Failed to get last block hash");
Expand All @@ -157,7 +155,7 @@ impl EthereumClient {
/// verified state
pub async fn listen_and_update_state(&self, start_block: u64) -> Result<(), Box<dyn std::error::Error>> {
let client = self.provider.clone();
let address: Address = starknet_core_address::MAINNET.parse().expect("Failed to parse Starknet core address");
let address: Address = get_config().expect("Failed to get config").l1_core_address;
abigen!(
StarknetCore,
"crates/client/sync/src/utils/abis/starknet_core.json",
Expand Down
62 changes: 25 additions & 37 deletions crates/client/sync/src/l2.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! Contains the code required to fetch data from the feeder efficiently.
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, RwLock};
use std::time::Duration;

use itertools::Itertools;
use lazy_static::lazy_static;
use mc_db::BonsaiDbs;
use mc_storage::OverrideHandle;
use mp_block::state_update::StateUpdateWrapper;
Expand All @@ -12,7 +13,7 @@ use mp_felt::Felt252Wrapper;
use mp_storage::StarknetStorageSchemaVersion;
use reqwest::Url;
use serde::Deserialize;
use sp_core::H256;
use sp_core::{H160, H256};
use sp_runtime::generic::{Block, Header};
use sp_runtime::traits::{BlakeTwo256, Block as BlockT};
use sp_runtime::OpaqueExtrinsic;
Expand All @@ -27,7 +28,7 @@ use tokio::sync::mpsc::Sender;
use tokio::task::JoinSet;

use crate::commitments::lib::{build_commitment_state_diff, update_state_root};
use crate::utility::{get_block_hash_by_number, update_highest_block_hash_and_number};
use crate::utility::get_block_hash_by_number;
use crate::CommandSink;

/// Contains the Starknet verified state on L2
Expand All @@ -47,17 +48,9 @@ lazy_static! {
});
}

use lazy_static::lazy_static;

// TODO: find a better place to store this
lazy_static! {
/// Store the configuration globally
static ref CONFIG: Arc<Mutex<FetchConfig>> = Arc::new(Mutex::new(FetchConfig::default()));
}

lazy_static! {
/// Shared latest block number and hash of chain
pub static ref STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER: Arc<Mutex<(FieldElement, u64)>> = Arc::new(Mutex::new((FieldElement::default(), 0)));
/// Shared latest block number and hash of chain, using a RwLock to allow for concurrent reads and exclusive writes
static ref STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER: RwLock<(FieldElement, u64)> = RwLock::new((FieldElement::default(), 0));
}

/// The configuration of the worker responsible for fetching new blocks and state updates from the
Expand All @@ -74,19 +67,8 @@ pub struct FetchConfig {
pub workers: u32,
/// Whether to play a sound when a new block is fetched.
pub sound: bool,
}

impl Default for FetchConfig {
fn default() -> Self {
FetchConfig {
// Provide default values for each field of FetchConfig
gateway: Url::parse("http://default-gateway-url.com").unwrap(),
feeder_gateway: Url::parse("http://default-feeder-gateway-url.com").unwrap(),
chain_id: starknet_ff::FieldElement::default(), // Adjust as necessary
workers: 4,
sound: false,
}
}
/// The L1 contract core address
pub l1_core_address: H160,
}

/// The configuration of the senders responsible for sending blocks and state
Expand Down Expand Up @@ -141,7 +123,6 @@ pub async fn sync<B: BlockT>(
rpc_port: u16,
backend: Arc<mc_db::Backend<B>>,
) {
update_config(&config);
let SenderConfig { block_sender, state_update_sender, class_sender, command_sink, overrides } = &mut sender_config;
let client = SequencerGatewayProvider::new(config.gateway.clone(), config.feeder_gateway.clone(), config.chain_id);
let bonsai_dbs = BonsaiDbs {
Expand Down Expand Up @@ -436,7 +417,8 @@ async fn create_block(cmds: &mut CommandSink, parent_hash: &mut Option<H256>) ->
/// Update the L2 state with the latest data
pub fn update_l2(state_update: L2StateUpdate) {
{
let mut last_state_update = STARKNET_STATE_UPDATE.lock().expect("failed to lock STARKNET_STATE_UPDATE");
let mut last_state_update =
STARKNET_STATE_UPDATE.lock().expect("Failed to acquire lock on STARKNET_STATE_UPDATE");
*last_state_update = state_update.clone();
}
}
Expand Down Expand Up @@ -466,16 +448,22 @@ pub async fn verify_l2<B: BlockT>(
Ok(())
}

pub fn get_highest_block_hash_and_number() -> (FieldElement, u64) {
*STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER.lock().expect("failed to lock STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER")
}
async fn update_highest_block_hash_and_number(client: &SequencerGatewayProvider) -> Result<(), String> {
let block = client.get_block(BlockId::Latest).await.map_err(|e| format!("failed to get block: {e}"))?;

fn update_config(config: &FetchConfig) {
let last_config = CONFIG.clone();
let mut new_config = last_config.lock().unwrap();
*new_config = config.clone();
let hash = block.block_hash.ok_or("block hash not found")?;
let number = block.block_number.ok_or("block number not found")?;

let mut highest_block_hash_and_number = STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER
.write()
.expect("Failed to acquire write lock on STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER");
*highest_block_hash_and_number = (hash, number);

Ok(())
}

pub fn get_config() -> FetchConfig {
CONFIG.lock().unwrap().clone()
pub fn get_highest_block_hash_and_number() -> (FieldElement, u64) {
*STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER
.read()
.expect("Failed to acquire read lock on STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER")
}
9 changes: 8 additions & 1 deletion crates/client/sync/src/utils/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use starknet_ff::FieldElement;
use starknet_providers::sequencer::models as p;

use crate::commitments::lib::calculate_commitments;
use crate::utility::get_config;

pub async fn block(block: p::Block) -> mp_block::Block {
// converts starknet_provider transactions and events to mp_transactions and starknet_api events
Expand Down Expand Up @@ -207,7 +208,13 @@ async fn commitments(
}

fn chain_id() -> mp_felt::Felt252Wrapper {
starknet_ff::FieldElement::from_byte_slice_be(b"SN_MAIN").unwrap().into()
match get_config() {
Ok(config) => config.chain_id.into(),
Err(e) => {
log::error!("Failed to get chain id: {}", e);
FieldElement::from_byte_slice_be(b"").unwrap().into()
}
}
}

fn felt(field_element: starknet_ff::FieldElement) -> starknet_api::hash::StarkFelt {
Expand Down
44 changes: 23 additions & 21 deletions crates/client/sync/src/utils/utility.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
//! Utility functions for Deoxys.

use std::error::Error;
use std::sync::RwLock;
use std::thread::sleep;
use std::time::Duration;

use ethers::types::I256;
use lazy_static::lazy_static;
use rand::seq::SliceRandom;
use rand::thread_rng;
use reqwest::header;
use serde_json::{json, Value};
use starknet_api::hash::StarkFelt;
use starknet_ff::FieldElement;
use starknet_providers::sequencer::models::BlockId;
use starknet_providers::SequencerGatewayProvider;

use crate::l1::{L1StateUpdate, LogStateUpdate};
use crate::l2::{L2StateUpdate, STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER};
use crate::l2::{FetchConfig, L2StateUpdate};

// TODO: find a better place to store this
lazy_static! {
/// Store the configuration globally, using a RwLock to allow for concurrent reads and exclusive writes
static ref CONFIG: RwLock<Option<FetchConfig>> = RwLock::new(None);
}

/// this function needs to be called only once at the start of the program
pub fn update_config(config: &FetchConfig) {
let mut new_config = CONFIG.write().expect("Failed to acquire write lock on CONFIG");
*new_config = Some(config.clone());
}

pub fn get_config() -> Result<FetchConfig, &'static str> {
let config_guard = CONFIG.read().expect("Failed to acquire read lock on CONFIG");
match &*config_guard {
Some(config) => Ok(config.clone()),
None => Err("Configuration not set yet"),
}
}

// TODO: secure the auto calls here

Expand Down Expand Up @@ -132,23 +151,6 @@ pub async fn get_state_update_at(rpc_port: u16, block_number: u64) -> Result<L2S
Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "Maximum retries exceeded")))
}

pub async fn update_highest_block_hash_and_number(client: &SequencerGatewayProvider) -> Result<(), String> {
let block = client.get_block(BlockId::Latest).await.map_err(|e| format!("failed to get block: {e}"))?;

let hash = block.block_hash.ok_or("block hash not found")?;
let number = block.block_number.ok_or("block number not found")?;

let last_highest_block_hash_and_number = STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER.clone();
let mut new_highest_block_hash_and_number = last_highest_block_hash_and_number.lock().unwrap();
*new_highest_block_hash_and_number = (hash, number);

Ok(())
}

pub fn get_highest_block_hash_and_number() -> (FieldElement, u64) {
*STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER.lock().expect("failed to lock STARKNET_HIGHEST_BLOCK_HASH_AND_NUMBER")
}

/// Returns a random Pokémon name.
pub async fn get_random_pokemon_name() -> Result<String, Box<dyn std::error::Error>> {
let res = reqwest::get("https://pokeapi.co/api/v2/pokemon/?limit=1000").await?;
Expand Down
Loading
Loading