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

feat(warp): added warp update to madara and other changes #393

Merged
merged 86 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
135a3c0
feat(rate-limit): removed rpc rate limiting in Madara
Trantorian1 Nov 18, 2024
5e4f779
feat(endpoint): added a separate `admin` endpoint
Trantorian1 Nov 18, 2024
5e8ee41
feat(changelog): updated `CHANGELOG.md`
Trantorian1 Nov 18, 2024
75e3d91
fix(lint)
Trantorian1 Nov 18, 2024
c4a0055
feat(endpoint): seperated user and admin rpc method versions
Trantorian1 Nov 18, 2024
b0c456d
fix(tests): invalid version import in tests
Trantorian1 Nov 18, 2024
f8ab3e4
fix(test)
Trantorian1 Nov 18, 2024
f774276
Merge branch 'main' into feat/engine_endpoint
Trantorian1 Nov 19, 2024
b29f886
feat(enpoint): updated `rpc-methods` cli arg to work better with new …
Trantorian1 Nov 19, 2024
fbd89b6
docs(endpoint): renamed `rpc-methods` cli argument to `rpc-enpoints`
Trantorian1 Nov 19, 2024
a72deba
Merge branch 'main' into feat/engine_endpoint
Trantorian1 Nov 19, 2024
d2afdf2
build(profiling): added profiling build target
Trantorian1 Nov 19, 2024
3fbe996
fix(fgw): include `l1_to_l2_consumed_message` in L1 handler receipt
jbcaron Nov 13, 2024
7263c8d
fix comment: MAX_H160
jbcaron Nov 18, 2024
6ac5b72
update dependencies starknet-rs, starknet-types, blockifier, cairo
jbcaron Nov 13, 2024
3141d73
add FIXME for FeePayment conversion
jbcaron Nov 18, 2024
7d10c97
rename FeederClient to GatewayProvider
jbcaron Nov 14, 2024
555c2d8
add `add_transaction` gateway client
jbcaron Nov 14, 2024
3acaa86
fix mock fgw
jbcaron Nov 15, 2024
8f969bd
fix comment, remove crate error
jbcaron Nov 18, 2024
14c8209
refactor: replace starknet-rs BlockId with types-rs BlockId, remove r…
jbcaron Nov 15, 2024
912e0c9
remove type `FetchBlockId`
jbcaron Nov 18, 2024
c841913
revert get_storage_at
jbcaron Nov 18, 2024
31baf41
Merge branch 'fix/fgw-l1l2msg' into feat/engine_endpoint
Trantorian1 Nov 19, 2024
d564466
Merge branch 'feat/fgw-add-tx' into feat/engine_endpoint
Trantorian1 Nov 19, 2024
340171d
Merge branch 'refactor/rpc-types' into feat/engine_endpoint
Trantorian1 Nov 19, 2024
7c7031b
Merge branch 'main' into feat/engine_endpoint
Trantorian1 Nov 19, 2024
0813c0e
Merge branch 'main' into feat/engine_endpoint
Trantorian1 Nov 19, 2024
bc7fe96
fix(comments)
Trantorian1 Nov 19, 2024
6f52fce
fix(comments)
Trantorian1 Nov 19, 2024
0e0a120
fix(comments)
Trantorian1 Nov 19, 2024
1135eb6
fix(tests)
Trantorian1 Nov 19, 2024
71278b2
Merge branch 'main' into feat/engine_endpoint
Trantorian1 Nov 19, 2024
2646179
feat(cancellation): added service cancellation boilerplate
Trantorian1 Nov 20, 2024
69c287c
build(symbols): updated symbols build element to work with cargo work…
Trantorian1 Nov 20, 2024
804a235
feat(sync): added `stop-on-sync` cli flag
Trantorian1 Nov 20, 2024
e50bf22
Merge branch 'main' into debug
Trantorian1 Nov 20, 2024
817f97d
feat(changelog)
Trantorian1 Nov 20, 2024
6b81330
fix(lint)
Trantorian1 Nov 20, 2024
76a82ba
fix(tests)
Trantorian1 Nov 20, 2024
4c05802
Merge branch 'main' into debug
Trantorian1 Nov 20, 2024
b55d686
fix(changelog)
Trantorian1 Nov 20, 2024
6bbfee7
fix(comments)
Trantorian1 Nov 20, 2024
e9256d2
Merge branch 'main' into feat/engine_endpoint
jbcaron Nov 20, 2024
8e08cbe
fix(comments)
Trantorian1 Nov 20, 2024
7482581
fix(rebase)
Trantorian1 Nov 20, 2024
0d75dc6
feat(rpc): moved rpc server config creation to service start
Trantorian1 Nov 20, 2024
a9c1574
feat(rpc): added `node_stop` rpc method
Trantorian1 Nov 20, 2024
74023d3
Merge branch 'main' into feat/stop_node
Trantorian1 Nov 20, 2024
23ad801
Merge branch 'main' into feat/stop_node
Trantorian1 Nov 20, 2024
14a5501
tmp
Trantorian1 Nov 21, 2024
6c3b211
refactor(sync): cleared up various sync function signatures
Trantorian1 Nov 21, 2024
5233339
refactor(db): `maybe_flush` is now `flush` and will flush each time i…
Trantorian1 Nov 21, 2024
9b01100
docs(warp): added docs on warp update
Trantorian1 Nov 21, 2024
0fded70
docs(review): got feature ready for review
Trantorian1 Nov 21, 2024
373e55d
Merge branch 'main' into feat/warp_update
Trantorian1 Nov 22, 2024
be08e4c
fix(ci)
Trantorian1 Nov 22, 2024
675f214
fix(ci)
Trantorian1 Nov 22, 2024
a614117
feat(rpc): added `pulse` admin rpc method
Trantorian1 Nov 22, 2024
b3b781d
feat(service): strarted work on `ServiceContext`
Trantorian1 Nov 22, 2024
5a3e244
feat(service): added `ServiceContext` to `Service`
Trantorian1 Nov 22, 2024
998017f
fix(tests): updated tests to use `ServiceContext`
Trantorian1 Nov 25, 2024
93455d9
feat(service): inter-process service communication
Trantorian1 Nov 25, 2024
2d88efa
feat(service): impled cross-service shitdown for rpc and sync
Trantorian1 Nov 25, 2024
46fa8cf
feat(warp): warp update clip args
Trantorian1 Nov 26, 2024
be2f41c
Merge branch 'main' into feat/warp_update
Trantorian1 Nov 26, 2024
ab5759a
docs(readme): updated readme
Trantorian1 Nov 26, 2024
fa020c1
Merge branch 'main' into feat/warp_update
antiyro Nov 27, 2024
ada9a64
feat(admin): reset admin rpc versions to v0.1.0
Trantorian1 Nov 27, 2024
556d640
fix(log): fixed log level
Trantorian1 Nov 27, 2024
dc83e43
fix(e2e): tests now use `ServiceContext` with services activated by d…
Trantorian1 Nov 27, 2024
5e9ff44
fix(l2): channel close error in `fetch/mod.rs`
Trantorian1 Nov 27, 2024
1e23f46
feat(l2): `sync_parallelism` in warp update now set based on number o…
Trantorian1 Nov 27, 2024
529561c
fix(tests)
Trantorian1 Nov 27, 2024
64743aa
Merge branch 'main' into feat/warp_update
jbcaron Nov 28, 2024
0d71ca1
docs(admin): updated admin rpc methods docs
Trantorian1 Nov 29, 2024
602d705
refactor(service): replaced `ServiceContext::branch` with clone, adde…
Trantorian1 Nov 29, 2024
7448c4b
refactor(serive): renamed capabilities to services
Trantorian1 Nov 29, 2024
f5754d6
fix(comments)
Trantorian1 Nov 29, 2024
3950c1a
fix(comments)
Trantorian1 Nov 29, 2024
3769030
fix(comments)
Trantorian1 Nov 29, 2024
75dc17d
docs(fetch): added doccumentation to l2 fetch methods
Trantorian1 Nov 29, 2024
4c0b1f8
docs(args): added docs to `ArgsPresetParams`
Trantorian1 Nov 29, 2024
17eb84d
feat(db): added `--flush-every-n-seconds` cli flag
Trantorian1 Nov 29, 2024
b91914a
Merge branch 'main' into feat/warp_update
Trantorian1 Nov 29, 2024
470890b
fix(comments)
Trantorian1 Nov 29, 2024
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 @@

## Next release

- feat(warp): added warp update to madara
- docs(readme): updated README.md docs and added Docker Compose support
- fix(log): define RUST_LOG=info by default
- fix(tracing): RUST_LOG filtering support
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

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

49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Madara is a powerful Starknet client written in Rust.
- [Starknet Compliant](#starknet-compliant)
- [Feeder-Gateway State Synchronization](#feeder-gateway-state-synchronization)
- [State Commitment Computation](#state-commitment-computation)
- [Database Migration](#database-migration)
- 💬 [Get in touch](#-get-in-touch)
- [Contributing](#contributing)
- [Partnerships](#partnerships)
Expand Down Expand Up @@ -573,6 +574,54 @@ Besu Bonsai Merkle Tries. See the [bonsai lib](https://github.com/madara-allianc
You can read more about Starknet Block structure and how it affects state
commitment [here](https://docs.starknet.io/architecture-and-concepts/network-architecture/block-structure/).

### Database Migration

When migration to a newer version of Madara you might need to update your
database. Instead of re-synchronizing the entirety of your chain's state from
genesis, you can use Madara's **warp update** feature.

> [!NOTE]
> Warp update requires an already synchronized _local_ node with a working
> database.

To begin the database migration, you will need to start an existing node with
[admin methods](#madara-specific-json-rpc-methods) and
[feeder gateway](#feeder-gateway-state-synchronization) enabled. This will be
the _source_ of the migration. You can do this with the `--warp-update-sender`
[preset](#4.-presets):

```bash
cargo run --releasae -- \
--name Sender \
--full \ # This also works with other types of nodes
--network mainnet \
--warp-update-sender
```

You will then need to start a second node to synchronize the state of your
database:

```bash
cargo run --releasae -- \
--name Receiver \
--base-path /tmp/madara_new \ # Where you want the new database to be stored
--full \
--network mainnet \
--l1-endpoint https://*** \
--warp-update-receiver
```

This will start generating a new up-to-date database under `/tmp/madara_new`.
Once this process is over, the warp update sender node will automatically
shutdown while the warp update receiver will take its place.

> [!WARNING]
> As of now, the warp update receiver has its rpc disabled, even after the
> migration process has completed. This will be fixed in the future, so that
> services that would otherwise conflict with the sender node will automatically
> start after the migration has finished, allowing for migrations with 0
> downtime.

## 💬 Get in touch

[⬅️ back to top](#-madara-starknet-client)
Expand Down
13 changes: 1 addition & 12 deletions crates/client/block_import/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,11 @@ pub struct BlockImporter {
backend: Arc<MadaraBackend>,
verify_apply: VerifyApply,
metrics: BlockMetrics,
always_force_flush: bool,
}

impl BlockImporter {
/// The starting block is used for metrics. Setting it to None means it will look at the database latest block number.
pub fn new(
backend: Arc<MadaraBackend>,
starting_block: Option<u64>,
always_force_flush: bool,
) -> anyhow::Result<Self> {
pub fn new(backend: Arc<MadaraBackend>, starting_block: Option<u64>) -> anyhow::Result<Self> {
let pool = Arc::new(RayonPool::new());
let starting_block = if let Some(n) = starting_block {
n
Expand All @@ -145,7 +140,6 @@ impl BlockImporter {
pool,
metrics: BlockMetrics::register(starting_block).context("Registering metrics for block import")?,
backend,
always_force_flush,
})
}

Expand Down Expand Up @@ -176,11 +170,6 @@ impl BlockImporter {
validation: BlockValidationContext,
) -> Result<BlockImportResult, BlockImportError> {
let result = self.verify_apply.verify_apply(block, validation).await?;
// Flush step.
let force = self.always_force_flush;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aaah!! no, we really need to flush every block, always, in block_production mode

Copy link
Collaborator Author

@Trantorian1 Trantorian1 Nov 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has no importance anymore as maybe_flush has been removed and will always flush anyways, so always_force_flush is no longer needed. This is after I noticed the only part of the code we were performing this check was in the block import, so instead we just do the check there while other parts of the code just call flush directly.

self.backend
.maybe_flush(force)
.map_err(|err| BlockImportError::Internal(format!("DB flushing error: {err:#}").into()))?;
self.metrics.update(&result.header, &self.backend);
Ok(result)
}
Expand Down
57 changes: 24 additions & 33 deletions crates/client/db/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
//! Madara database

use anyhow::{Context, Result};
use anyhow::Context;
use bonsai_db::{BonsaiDb, DatabaseKeyMapping};
use bonsai_trie::id::BasicId;
use bonsai_trie::{BonsaiStorage, BonsaiStorageConfig};
use db_metrics::DbMetrics;
use mp_chain_config::ChainConfig;
use mp_utils::service::Service;
use mp_utils::service::{MadaraService, Service};
use rocksdb::backup::{BackupEngine, BackupEngineOptions};
use rocksdb::{BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, Env, FlushOptions, MultiThreaded};
use rocksdb_options::rocksdb_global_options;
use starknet_types_core::hash::{Pedersen, Poseidon, StarkHash};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use std::sync::Arc;
use std::{fmt, fs};
use tokio::sync::{mpsc, oneshot};

Expand All @@ -37,7 +36,7 @@ pub type WriteBatchWithTransaction = rocksdb::WriteBatchWithTransaction<false>;

const DB_UPDATES_BATCH_SIZE: usize = 1024;

pub fn open_rocksdb(path: &Path) -> Result<Arc<DB>> {
pub fn open_rocksdb(path: &Path) -> anyhow::Result<Arc<DB>> {
let opts = rocksdb_global_options()?;
tracing::debug!("opening db at {:?}", path.display());
let db = DB::open_cf_descriptors(
Expand All @@ -49,14 +48,14 @@ pub fn open_rocksdb(path: &Path) -> Result<Arc<DB>> {
Ok(Arc::new(db))
}

/// This runs in anothr thread as the backup engine is not thread safe
/// This runs in another thread as the backup engine is not thread safe
fn spawn_backup_db_task(
backup_dir: &Path,
restore_from_latest_backup: bool,
db_path: &Path,
db_restored_cb: oneshot::Sender<()>,
mut recv: mpsc::Receiver<BackupRequest>,
) -> Result<()> {
) -> anyhow::Result<()> {
let mut backup_opts = BackupEngineOptions::new(backup_dir).context("Creating backup options")?;
let cores = std::thread::available_parallelism().map(|e| e.get() as i32).unwrap_or(1);
backup_opts.set_max_background_operations(cores);
Expand Down Expand Up @@ -254,7 +253,6 @@ impl DatabaseExt for DB {
pub struct MadaraBackend {
backup_handle: Option<mpsc::Sender<BackupRequest>>,
db: Arc<DB>,
last_flush_time: Mutex<Option<Instant>>,
chain_config: Arc<ChainConfig>,
db_metrics: DbMetrics,
sender_block_info: tokio::sync::broadcast::Sender<mp_block::MadaraBlockInfo>,
Expand Down Expand Up @@ -305,7 +303,11 @@ impl DatabaseService {
}
}

impl Service for DatabaseService {}
impl Service for DatabaseService {
fn id(&self) -> MadaraService {
MadaraService::Database
}
}

struct BackupRequest {
callback: oneshot::Sender<()>,
Expand All @@ -315,7 +317,7 @@ struct BackupRequest {
impl Drop for MadaraBackend {
fn drop(&mut self) {
tracing::info!("⏳ Gracefully closing the database...");
self.maybe_flush(true).expect("Error when flushing the database"); // flush :)
self.flush().expect("Error when flushing the database"); // flush :)
}
}

Expand All @@ -330,7 +332,6 @@ impl MadaraBackend {
Arc::new(Self {
backup_handle: None,
db: open_rocksdb(temp_dir.as_ref()).unwrap(),
last_flush_time: Default::default(),
chain_config,
db_metrics: DbMetrics::register().unwrap(),
sender_block_info: tokio::sync::broadcast::channel(100).0,
Expand All @@ -344,7 +345,7 @@ impl MadaraBackend {
backup_dir: Option<PathBuf>,
restore_from_latest_backup: bool,
chain_config: Arc<ChainConfig>,
) -> Result<Arc<MadaraBackend>> {
) -> anyhow::Result<Arc<MadaraBackend>> {
let db_path = db_config_dir.join("db");

// when backups are enabled, a thread is spawned that owns the rocksdb BackupEngine (it is not thread safe) and it receives backup requests using a mpsc channel
Expand Down Expand Up @@ -374,7 +375,6 @@ impl MadaraBackend {
db_metrics: DbMetrics::register().context("Registering db metrics")?,
backup_handle,
db,
last_flush_time: Default::default(),
chain_config: Arc::clone(&chain_config),
sender_block_info: tokio::sync::broadcast::channel(100).0,
#[cfg(feature = "testing")]
Expand All @@ -384,30 +384,21 @@ impl MadaraBackend {
Ok(backend)
}

pub fn maybe_flush(&self, force: bool) -> Result<bool> {
let mut inst = self.last_flush_time.lock().expect("poisoned mutex");
let will_flush = force
|| match *inst {
Some(inst) => inst.elapsed() >= Duration::from_secs(5),
None => true,
};
if will_flush {
tracing::debug!("doing a db flush");
let mut opts = FlushOptions::default();
opts.set_wait(true);
// we have to collect twice here :/
let columns = Column::ALL.iter().map(|e| self.db.get_column(*e)).collect::<Vec<_>>();
let columns = columns.iter().collect::<Vec<_>>();
self.db.flush_cfs_opt(&columns, &opts).context("Flushing database")?;

*inst = Some(Instant::now());
}
pub fn flush(&self) -> anyhow::Result<()> {
tracing::debug!("doing a db flush");
let mut opts = FlushOptions::default();
opts.set_wait(true);
// we have to collect twice here :/
let columns = Column::ALL.iter().map(|e| self.db.get_column(*e)).collect::<Vec<_>>();
let columns = columns.iter().collect::<Vec<_>>();

Ok(will_flush)
self.db.flush_cfs_opt(&columns, &opts).context("Flushing database")?;

Ok(())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not mandatory now but we should add metrics to follow the flush frequency and behavior

}

#[tracing::instrument(skip(self))]
pub async fn backup(&self) -> Result<()> {
pub async fn backup(&self) -> anyhow::Result<()> {
let (callback_sender, callback_recv) = oneshot::channel();
let _res = self
.backup_handle
Expand Down
2 changes: 1 addition & 1 deletion crates/client/devnet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ mod tests {
let chain_config = Arc::new(ChainConfig::madara_devnet());
let block = g.build(&chain_config).unwrap();
let backend = MadaraBackend::open_for_testing(Arc::clone(&chain_config));
let importer = Arc::new(BlockImporter::new(Arc::clone(&backend), None, true).unwrap());
let importer = Arc::new(BlockImporter::new(Arc::clone(&backend), None).unwrap());

println!("{:?}", block.state_diff);
tokio::runtime::Runtime::new()
Expand Down
1 change: 1 addition & 0 deletions crates/client/eth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,4 @@ httpmock = { workspace = true }
tracing-test = "0.2.5"
serial_test = { workspace = true }
lazy_static = { workspace = true }
mp-utils = { workspace = true, features = ["testing"] }
10 changes: 5 additions & 5 deletions crates/client/eth/src/l1_gas_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use anyhow::Context;
use mc_mempool::{GasPriceProvider, L1DataProvider};
use std::time::{Duration, UNIX_EPOCH};

use mp_utils::wait_or_graceful_shutdown;
use mp_utils::{service::ServiceContext, wait_or_graceful_shutdown};
use std::time::SystemTime;

pub async fn gas_price_worker_once(
Expand Down Expand Up @@ -36,12 +36,12 @@ pub async fn gas_price_worker(
eth_client: &EthereumClient,
l1_gas_provider: GasPriceProvider,
gas_price_poll_ms: Duration,
cancellation_token: tokio_util::sync::CancellationToken,
ctx: ServiceContext,
antiyro marked this conversation as resolved.
Show resolved Hide resolved
) -> anyhow::Result<()> {
l1_gas_provider.update_last_update_timestamp();
let mut interval = tokio::time::interval(gas_price_poll_ms);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
while wait_or_graceful_shutdown(interval.tick(), &cancellation_token).await.is_some() {
while wait_or_graceful_shutdown(interval.tick(), &ctx).await.is_some() {
gas_price_worker_once(eth_client, l1_gas_provider.clone(), gas_price_poll_ms).await?;
}
Ok(())
Expand Down Expand Up @@ -135,7 +135,7 @@ mod eth_client_gas_price_worker_test {
&eth_client,
l1_gas_provider,
Duration::from_millis(200),
tokio_util::sync::CancellationToken::new(),
ServiceContext::new_for_testing(),
)
.await
}
Expand Down Expand Up @@ -280,7 +280,7 @@ mod eth_client_gas_price_worker_test {
&eth_client,
l1_gas_provider.clone(),
Duration::from_millis(200),
tokio_util::sync::CancellationToken::new(),
ServiceContext::new_for_testing(),
),
)
.await;
Expand Down
Loading
Loading