Skip to content

Commit

Permalink
Merge branch 'main' into feat/fetch-price-from-pragma
Browse files Browse the repository at this point in the history
  • Loading branch information
azurwastaken authored Oct 24, 2024
2 parents d83b8f9 + b45bd6a commit 2df3e5a
Show file tree
Hide file tree
Showing 29 changed files with 674 additions and 602 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
## Next release

- feat: fetch eth/strk price and sync strk gas price
- fix: contract 0 state diff fixed
- refactor(rpc): re-worked rpc tower server and added proper websocket support
- fix(network): added the FGW and gateway url to the chain config
- fix(block_hash): block hash mismatch on transaction with an empty signature
- feat: declare v0, l1 handler support added
- feat: strk gas price cli param added
- fix(snos): added special address while closing block for SNOS
Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ serde_json = { version = "1.0", default-features = false, features = ["std"] }
serde_yaml = { version = "0.9.34" }
thiserror = "1.0"
tokio = { version = "1.34", features = ["signal", "rt"] }
url = "2.4"
url = { version = "2.4", features = ["serde"] }
rayon = "1.10"
bincode = "1.3"
prometheus = "0.13.4"
Expand Down
2 changes: 2 additions & 0 deletions configs/presets/devnet.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
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"
latest_protocol_version: "0.13.2"
Expand Down
2 changes: 2 additions & 0 deletions configs/presets/integration.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
chain_name: "Starknet Sepolia"
chain_id: "SN_INTEGRATION_SEPOLIA"
feeder_gateway_url: "https://integration-sepolia.starknet.io/feeder_gateway/"
gateway_url: "https://integration-sepolia.starknet.io/gateway/"
native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d"
parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
latest_protocol_version: "0.13.2"
Expand Down
2 changes: 2 additions & 0 deletions configs/presets/mainnet.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
chain_name: "Starknet Mainnet"
chain_id: "SN_MAIN"
feeder_gateway_url: "https://alpha-mainnet.starknet.io/feeder_gateway/"
gateway_url: "https://alpha-mainnet.starknet.io/gateway/"
native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d"
parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
latest_protocol_version: "0.13.2"
Expand Down
2 changes: 2 additions & 0 deletions configs/presets/sepolia.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
chain_name: "Starknet Sepolia"
chain_id: "SN_SEPOLIA"
feeder_gateway_url: "https://alpha-sepolia.starknet.io/feeder_gateway/"
gateway_url: "https://alpha-sepolia.starknet.io/gateway/"
native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d"
parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
latest_protocol_version: "0.13.2"
Expand Down
6 changes: 3 additions & 3 deletions crates/client/gateway/src/server/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ pub(crate) async fn main_router(
match (path.as_ref(), feeder_gateway_enable, gateway_enable) {
("health", _, _) => Ok(Response::new(Body::from("OK"))),
(path, true, _) if path.starts_with("feeder_gateway/") => feeder_gateway_router(req, path, backend).await,
(path, _, true) if path.starts_with("feeder/") => gateway_router(req, path, add_transaction_provider).await,
(path, _, true) if path.starts_with("gateway/") => gateway_router(req, path, add_transaction_provider).await,
(path, false, _) if path.starts_with("feeder_gateway/") => Ok(service_unavailable_response("Feeder Gateway")),
(path, _, false) if path.starts_with("feeder/") => Ok(service_unavailable_response("Feeder")),
(path, _, false) if path.starts_with("gateway/") => Ok(service_unavailable_response("Feeder")),
_ => {
log::debug!(target: "feeder_gateway", "Main router received invalid request: {path}");
Ok(not_found_response())
Expand Down Expand Up @@ -74,7 +74,7 @@ async fn gateway_router(
add_transaction_provider: Arc<dyn AddTransactionProvider>,
) -> Result<Response<Body>, Infallible> {
match (req.method(), req.uri().path()) {
(&Method::POST, "feeder/add_transaction") => {
(&Method::POST, "gateway/add_transaction") => {
Ok(handle_add_transaction(req, add_transaction_provider).await.unwrap_or_else(Into::into))
}
_ => {
Expand Down
96 changes: 57 additions & 39 deletions crates/client/mempool/src/block_production.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use blockifier::blockifier::transaction_executor::{TransactionExecutor, VisitedSegmentsMapping};
use blockifier::bouncer::{Bouncer, BouncerWeights, BuiltinCount};
use blockifier::state::cached_state::CommitmentStateDiff;
use blockifier::state::cached_state::StateMaps;
use blockifier::state::state_api::StateReader;
use blockifier::transaction::errors::TransactionExecutionError;
use mc_block_import::{BlockImportError, BlockImporter};
Expand All @@ -19,8 +19,11 @@ use mp_state_update::{
};
use mp_transactions::TransactionWithHash;
use mp_utils::graceful_shutdown;
use starknet_api::core::ContractAddress;
use starknet_types_core::felt::Felt;
use std::borrow::Cow;
use std::collections::hash_map;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::mem;
use std::sync::Arc;
Expand Down Expand Up @@ -56,20 +59,56 @@ pub enum Error {
Unexpected(Cow<'static, str>),
}

fn csd_to_state_diff(
fn state_map_to_state_diff(
backend: &MadaraBackend,
on_top_of: &Option<DbBlockId>,
csd: &CommitmentStateDiff,
diff: StateMaps,
) -> Result<StateDiff, Error> {
let CommitmentStateDiff {
address_to_class_hash,
address_to_nonce,
storage_updates,
class_hash_to_compiled_class_hash,
} = csd;

let (mut deployed_contracts, mut replaced_classes) = (Vec::new(), Vec::new());
for (contract_address, new_class_hash) in address_to_class_hash {
let mut backing_map = HashMap::<ContractAddress, usize>::default();
let mut storage_diffs = Vec::<ContractStorageDiffItem>::default();
for ((address, key), value) in diff.storage {
match backing_map.entry(address) {
hash_map::Entry::Vacant(e) => {
e.insert(storage_diffs.len());
storage_diffs.push(ContractStorageDiffItem {
address: address.to_felt(),
storage_entries: vec![StorageEntry { key: key.to_felt(), value }],
});
}
hash_map::Entry::Occupied(e) => {
storage_diffs[*e.get()].storage_entries.push(StorageEntry { key: key.to_felt(), value });
}
}
}

let mut deprecated_declared_classes = Vec::default();
for (class_hash, _) in diff.declared_contracts {
if !diff.compiled_class_hashes.contains_key(&class_hash) {
deprecated_declared_classes.push(class_hash.to_felt());
}
}

let declared_classes = diff
.compiled_class_hashes
.iter()
.map(|(class_hash, compiled_class_hash)| DeclaredClassItem {
class_hash: class_hash.to_felt(),
compiled_class_hash: compiled_class_hash.to_felt(),
})
.collect();

let nonces = diff
.nonces
.into_iter()
.map(|(contract_address, nonce)| NonceUpdate {
contract_address: contract_address.to_felt(),
nonce: nonce.to_felt(),
})
.collect();

let mut deployed_contracts = Vec::new();
let mut replaced_classes = Vec::new();
for (contract_address, new_class_hash) in diff.compiled_class_hashes {
let replaced = if let Some(on_top_of) = on_top_of {
backend.get_contract_class_hash_at(on_top_of, &contract_address.to_felt())?.is_some()
} else {
Expand All @@ -90,31 +129,10 @@ fn csd_to_state_diff(
}

Ok(StateDiff {
storage_diffs: storage_updates
.into_iter()
.map(|(address, storage_entries)| ContractStorageDiffItem {
address: address.to_felt(),
storage_entries: storage_entries
.into_iter()
.map(|(key, value)| StorageEntry { key: key.to_felt(), value: *value })
.collect(),
})
.collect(),
deprecated_declared_classes: vec![],
declared_classes: class_hash_to_compiled_class_hash
.iter()
.map(|(class_hash, compiled_class_hash)| DeclaredClassItem {
class_hash: class_hash.to_felt(),
compiled_class_hash: compiled_class_hash.to_felt(),
})
.collect(),
nonces: address_to_nonce
.into_iter()
.map(|(contract_address, nonce)| NonceUpdate {
contract_address: contract_address.to_felt(),
nonce: nonce.to_felt(),
})
.collect(),
storage_diffs,
deprecated_declared_classes,
declared_classes,
nonces,
deployed_contracts,
replaced_classes,
})
Expand Down Expand Up @@ -150,13 +168,13 @@ fn finalize_execution_state<S: StateReader>(
backend: &MadaraBackend,
on_top_of: &Option<DbBlockId>,
) -> Result<(StateDiff, VisitedSegmentsMapping, BouncerWeights), Error> {
let csd = tx_executor
let state_map = tx_executor
.block_state
.as_mut()
.expect(BLOCK_STATE_ACCESS_ERR)
.to_state_diff()
.map_err(TransactionExecutionError::StateError)?;
let state_update = csd_to_state_diff(backend, on_top_of, &csd.into())?;
let state_update = state_map_to_state_diff(backend, on_top_of, state_map)?;

let visited_segments = get_visited_segments(tx_executor)?;

Expand Down
94 changes: 94 additions & 0 deletions crates/client/rpc/src/RPC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# RPC

_This section consists of a brief overview of RPC handling architecture inside
of Madara, as its structure can be quite confusing at first._

## Properties

Madara RPC has the folliwing properties:

**Each RPC category is independent** and decoupled from the rest, so `trace`
methods exist in isolation from `read` methods for example.

**RPC methods are versioned**. It is therefore possible for a user to call
_different versions_ of the same RPC method. This is mostly present for ease of
development of new RPC versions, but also serves to assure a level of backwards
compatibility. To select a specific version of an rpc method, you will need to
append `/rcp/v{version}` to the rpc url you are connecting to.

**RPC versions are grouped under the `Starknet` struct**. This serves as a
common point of implementation for all RPC methods across all versions, and is
also the point of interaction between RPC methods and the node backend.

> [!NOTE]
> All of this is regrouped as an RPC _service_.
## Implementation details

There are **two** main parts to the implementation of RPC methods in Madara.

### Jsonrpsee implementation

> [!NOTE] > `jsonrpsee` is a library developed by Parity which is used to implement JSON
> RPC APIs through simple macro logic.
Each RPC version is defined under the `version` folder using the
`versioned_starknet_rpc` macro. This just serves to rename the trait it is
defined on and all jsonrpsee `#[method]` definitions to include the version
name. The latter is especially important as it avoids name clashes when merging
multiple `RpcModule`s from different versions together.

#### Renaming

```rust
#[versioned_starknet_rpc("V0_7_1)")]
trait yourTrait {
#[method(name = "foo")]
async fn foo();
}
```

Will become

```rust
#[jsonrpsee::proc_macros::rpc(server, namespace = "starknet")]
trait yourTraitV0_7_1 {
#[method(name = "V0_7_1_foo")]
async fn foo();
}
```

### Implementation as a service

> [!IMPORTANT]
> This is where the RPC server is set up and where RPC calls are actually
> parsed, validated, routed and handled.
`RpcService` is responsible for starting the rpc service, and hence the rpc
server. This is done with tower in the following steps:

- RPC apis are built and combined into a single `RpcModule` using
`versioned_rpc_api`, and all other configurations are loaded.

- Request filtering middleware is set up. This includes host origin filtering
and CORS filtering.

> [!NOTE]
> Rpc middleware will apply to both websocket and http rpc requests, which is
> why we do not apply versioning in the http middleware.
- Request constraints are set, such as the maximum number of connections and
request / response size constraints.

- Additional service layers are added on each rpc call inside `service_fn`.
These are composed into versioning, rate limiting (which is optional) and
metrics layers. Importantly, version filtering with `RpcMiddlewareServiceVersion`
will transforms rpc methods request with header `/rpc/v{version}` and a json rpc
body with a `{method}` field into the correct `starknet_{version}_{method}` rpc
method call, as this is how we version them internally with jsonrpsee.

> [!NOTE]
> The `starknet` prefix comes from the secondary macro expansion of
> `#[rpc(server, namespace = "starknet)]`
- Finally, the RPC service is added to tower as `RpcServiceBuilder`. Note that
22 changes: 16 additions & 6 deletions crates/client/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
mod constants;
mod errors;
mod macros;
pub mod providers;
#[cfg(test)]
pub mod test_utils;
Expand Down Expand Up @@ -99,14 +98,25 @@ pub fn versioned_rpc_api(
write: bool,
trace: bool,
internal: bool,
ws: bool,
) -> anyhow::Result<RpcModule<()>> {
let mut rpc_api = RpcModule::new(());

merge_rpc_versions!(
rpc_api, starknet, read, write, trace, internal,
v0_7_1, // We can add new versions by adding the version module below
// , v0_8_0 (for example)
);
if read {
rpc_api.merge(versions::v0_7_1::StarknetReadRpcApiV0_7_1Server::into_rpc(starknet.clone()))?;
}
if write {
rpc_api.merge(versions::v0_7_1::StarknetWriteRpcApiV0_7_1Server::into_rpc(starknet.clone()))?;
}
if trace {
rpc_api.merge(versions::v0_7_1::StarknetTraceRpcApiV0_7_1Server::into_rpc(starknet.clone()))?;
}
if internal {
rpc_api.merge(versions::v0_7_1::MadaraWriteRpcApiV0_7_1Server::into_rpc(starknet.clone()))?;
}
if ws {
// V0.8.0 ...
}

Ok(rpc_api)
}
21 changes: 0 additions & 21 deletions crates/client/rpc/src/macros.rs

This file was deleted.

1 change: 0 additions & 1 deletion crates/client/rpc/src/versions/v0_7_1/api.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use jsonrpsee::core::RpcResult;
use jsonrpsee::proc_macros::rpc;
use starknet_core::types::{
BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction,
BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, DeclareTransactionResult,
Expand Down
Loading

0 comments on commit 2df3e5a

Please sign in to comment.