Skip to content
This repository was archived by the owner on Mar 13, 2026. It is now read-only.
Open
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
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ cairo-felt = "0.8.0"
serde_with = "3.0.0"
starknet-core = "0.8.0"
tokio = { version = "1.5.0", features = ["sync", "rt", "macros"] }

rocksdb = "0.19.0"
sled = "0.34.7"
anyhow = "1.0.71"
tracing = "0.1"
5 changes: 4 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use rpc::starknet_backend::StarknetBackend;
use crate::rpc::StarknetRpcApiServer;

mod rpc;
mod store;

const DB_PATH: &str = "store";

#[tokio::main]
async fn main() {
Expand All @@ -24,7 +27,7 @@ pub async fn start_rpc_server(port: u16) -> Result<ServerHandle, jsonrpsee::core
let server = ServerBuilder::default()
.build(format!("0.0.0.0:{}", port))
.await?;
let server_handle = server.start(StarknetBackend::new().into_rpc())?;
let server_handle = server.start(StarknetBackend::new(DB_PATH).into_rpc())?;

Ok(server_handle)
}
5 changes: 3 additions & 2 deletions src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
use cairo_felt::Felt252;
use jsonrpsee::core::RpcResult;
use jsonrpsee::proc_macros::rpc;
use starknet_core::types::{
pub use starknet_core::types::{
BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction,
BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, DeclareTransactionResult,
DeployAccountTransactionResult, EventFilterWithPage, EventsPage, FeeEstimate, FunctionCall,
InvokeTransactionResult, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingTransactionReceipt,
StateUpdate, SyncStatusType, Transaction, TransactionStatus, SimulationFlag, SimulatedTransaction
StateUpdate, SyncStatusType, Transaction, TransactionStatus, SimulationFlag, SimulatedTransaction,
InvokeTransaction, TransactionReceipt, InvokeTransactionV1,
};

// #[serde_as]
Expand Down
10 changes: 10 additions & 0 deletions src/rpc/serializable_types.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use cairo_felt::Felt252;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{serde_as, DeserializeAs, SerializeAs};
use starknet_core::types::FieldElement;

// We need the newtype in order to be able to use it the RPC function signatures since
// jsonrpsee uses serde's deserialize implementations to deserialize params and
Expand All @@ -14,6 +15,15 @@ pub struct FeltHexOption;
pub struct FeltPendingBlockHash;
pub(crate) struct NumAsHex;

pub fn to_felt252(field_element: FieldElement) -> Felt252 {
return Felt252::from_bytes_be(&field_element.to_bytes_be());
}

pub fn to_field_element(felt252: Felt252) -> FieldElement {
return FieldElement::from_bytes_be(&felt252.to_be_bytes()).expect("Could not convert Felt252 to FieldElement");
}


impl SerializeAs<Felt252> for FeltHex {
fn serialize_as<S>(value: &Felt252, serializer: S) -> Result<S::Ok, S::Error>
where
Expand Down
13 changes: 9 additions & 4 deletions src/rpc/starknet_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::rpc::{
MaybePendingBlockWithTxs, MaybePendingTransactionReceipt, StateUpdate,
SyncStatusType, Transaction,
};
use crate::store::{Store, EngineType};
use cairo_felt::Felt252;
use jsonrpsee::
core::{async_trait, RpcResult};
Expand All @@ -15,12 +16,16 @@ use super::StarknetRpcApiServer;

pub struct StarknetBackend {
// mempool_handler: Mempool,
// store: Store,
store: Store,
}

impl StarknetBackend {
pub fn new() -> StarknetBackend {
StarknetBackend {}
pub fn new(store: &str) -> StarknetBackend {

let store_path = format!("db_{}", store);
StarknetBackend {
store: Store::new(&store_path, EngineType::Sled).expect("Failed to create sequencer store"),
}
}
}

Expand Down Expand Up @@ -59,7 +64,7 @@ impl StarknetRpcApiServer for StarknetBackend {
}

fn block_number(&self) -> RpcResult<u64> {
Ok(1024u64)
Ok(self.store.get_height().expect("Heigh not found"))
}

fn block_hash_and_number(&self) -> RpcResult<BlockHashAndNumber> {
Expand Down
113 changes: 113 additions & 0 deletions src/store/in_memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use super::{Key, StoreEngine, Value};
use anyhow::Result;
use cairo_felt::Felt252;
use std::{collections::HashMap, fmt::Debug};
use crate::rpc::{
InvokeTransaction, MaybePendingBlockWithTxs, MaybePendingTransactionReceipt, Transaction,
TransactionReceipt, serializable_types::to_felt252,
};

#[derive(Clone, Default)]
pub struct Store {
transactions: HashMap<Felt252, Transaction>,
blocks_by_hash: HashMap<Felt252, MaybePendingBlockWithTxs>,
blocks_by_height: HashMap<u64, MaybePendingBlockWithTxs>,
transaction_receipts: HashMap<Felt252, MaybePendingTransactionReceipt>,
values: HashMap<Key, Value>,
}

impl Store {
pub fn new() -> Result<Self> {
Ok(Self {
transactions: HashMap::new(),
blocks_by_hash: HashMap::new(),
blocks_by_height: HashMap::new(),
transaction_receipts: HashMap::new(),
values: HashMap::new(),
})
}
}

impl StoreEngine for Store {
fn add_transaction(&mut self, tx: Transaction) -> Result<()> {
match &tx {
Transaction::Invoke(InvokeTransaction::V1(invoke_tx)) => {
let _ = self
.transactions
.insert(to_felt252(invoke_tx.transaction_hash.clone()), tx);
Ok(())
}
// Currently only InvokeTransactionV1 are supported
_ => todo!(),
}
}

fn get_transaction(&self, tx_hash: Felt252) -> Result<Option<Transaction>> {
Ok(self.transactions.get(&tx_hash).cloned())
}

fn add_block(&mut self, block: MaybePendingBlockWithTxs) -> Result<()> {
match &block {
MaybePendingBlockWithTxs::Block(block_with_txs) => {
let _ = self
.blocks_by_hash
.insert(to_felt252(block_with_txs.block_hash.clone()), block.clone());
let _ = self
.blocks_by_height
.insert(block_with_txs.block_number, block);
Ok(())
}
MaybePendingBlockWithTxs::PendingBlock(_) =>
// Currently only MaybePendingBlockWithTxs::Block is supported
{
todo!()
}
}
}

fn get_block_by_hash(&self, block_hash: Felt252) -> Result<Option<MaybePendingBlockWithTxs>> {
Ok(self.blocks_by_hash.get(&block_hash).cloned())
}

fn get_block_by_height(&self, block_height: u64) -> Result<Option<MaybePendingBlockWithTxs>> {
Ok(self.blocks_by_height.get(&block_height).cloned())
}

fn set_value(&mut self, key: Key, value: Value) -> Result<()> {
let _ = self.values.insert(key, value);
Ok(())
}

fn get_value(&self, key: Key) -> Result<Option<Vec<u8>>, anyhow::Error> {
Ok(self.values.get(&key).cloned())
}

fn add_transaction_receipt(
&mut self,
transaction_receipt: MaybePendingTransactionReceipt,
) -> Result<()> {
match &transaction_receipt {
MaybePendingTransactionReceipt::Receipt(TransactionReceipt::Invoke(tx_receipt)) => {
let _ = self
.transaction_receipts
.insert(to_felt252(tx_receipt.transaction_hash.clone()), transaction_receipt);
Ok(())
}
// Currently only InvokeTransactionReceipts are supported
_ => todo!(),
}
}

fn get_transaction_receipt(
&self,
tx_hash: Felt252,
) -> Result<Option<MaybePendingTransactionReceipt>> {
Ok(self.transaction_receipts.get(&tx_hash).cloned())
}
}

impl Debug for Store {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("In Memory Store").finish()
}
}
Loading