Skip to content

Commit

Permalink
invalid justification test
Browse files Browse the repository at this point in the history
  • Loading branch information
pompon0 committed Oct 1, 2024
1 parent 3b06032 commit cee8d59
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 9 deletions.
2 changes: 2 additions & 0 deletions node/actors/network/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ pub struct Config {
pub tcp_accept_rate: limiter::Rate,
/// Rate limiting config for RPCs.
pub rpc: RpcConfig,
/// Enables syncing blocks before genesis.
pub enable_pre_genesis_support: bool,
/// Maximum number of not-yet-persisted blocks fetched from the network.
/// If reached, network actor will wait for more blocks to get persisted
/// before fetching the next ones. It is useful for limiting memory consumption
Expand Down
26 changes: 19 additions & 7 deletions node/actors/network/src/gossip/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,11 @@ impl rpc::Handler<rpc::push_block_store_state::Rpc> for &PushServer<'_> {
async fn handle(
&self,
_ctx: &ctx::Ctx,
req: rpc::push_block_store_state::Req,
mut req: rpc::push_block_store_state::Req,
) -> anyhow::Result<()> {
if !self.net.cfg.enable_pre_genesis_support {
req.clear_pre_genesis_info();
}
let state = req.state();
state.verify(self.net.genesis())?;
self.blocks.send_replace(state);
Expand All @@ -109,7 +112,11 @@ impl rpc::Handler<rpc::get_block::Rpc> for &BlockStore {
ctx: &ctx::Ctx,
req: rpc::get_block::Req,
) -> anyhow::Result<rpc::get_block::Resp> {
Ok(rpc::get_block::Resp(self.block(ctx, req.0).await?))
let mut resp = rpc::get_block::Resp(self.block(ctx, req.0).await?;
if !self.cfg.enable_pre_genesis_support {
resp.clear_pre_genesis_info();
}
Ok(resp)
}
}

Expand Down Expand Up @@ -205,7 +212,10 @@ impl Network {
s.spawn::<()>(async {
let mut state = self.block_store.queued();
loop {
let req = rpc::push_block_store_state::Req::new(state.clone(), self.genesis());
let mut req = rpc::push_block_store_state::Req::new(state.clone(), self.genesis());
if !self.cfg.enable_pre_genesis_support {
req.clear_pre_genesis_info();
}
push_block_store_state_client.call(ctx, &req, kB).await?;
state = self.block_store.wait_for_queued_change(ctx, &state).await?;
}
Expand Down Expand Up @@ -251,11 +261,13 @@ impl Network {
let ctx_with_timeout =
self.cfg.rpc.get_block_timeout.map(|t| ctx.with_timeout(t));
let ctx = ctx_with_timeout.as_ref().unwrap_or(ctx);
let block = call
let mut resp = call
.call(ctx, &req, self.cfg.max_block_size.saturating_add(kB))
.await?
.0
.context("empty response")?;
.await?;
if self.cfg.enable_pre_genesis_support {
resp.0.clear_pre_genesis_info();
}
let block = resp.0.context("empty response")?;
anyhow::ensure!(block.number() == req.0, "received wrong block");
// Storing the block will fail in case block is invalid.
self.block_store
Expand Down
6 changes: 6 additions & 0 deletions node/actors/network/src/rpc/push_block_store_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ impl Req {
},
}
}

/// Clears pre-genesis info from the request.
/// Use to simulate node behavior before pre-genesis support.
pub(crate) fn clear_pre_genesis_info(&mut self) {
self.state = None;
}
}

impl ProtoRepr for proto::Last {
Expand Down
5 changes: 4 additions & 1 deletion node/libs/storage/src/testonly/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ impl PersistentBlockStore for BlockStore {
Ok(blocks.get(idx as usize).context("not found")?.clone())
}

async fn queue_next_block(&self, _ctx: &ctx::Ctx, block: validator::Block) -> ctx::Result<()> {
async fn queue_next_block(&self, ctx: &ctx::Ctx, block: validator::Block) -> ctx::Result<()> {
if let validator::Block::PreGenesis(b) = &block {
self.verify_pre_genesis_block(ctx, b).await?;
}
let mut blocks = self.0.blocks.lock().unwrap();
let want = self.0.persisted.borrow().next();
if block.number() < want {
Expand Down
27 changes: 26 additions & 1 deletion node/libs/storage/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::*;
use crate::{testonly::TestMemoryStorage, ReplicaState};
use zksync_concurrency::{ctx, scope, sync, testonly::abort_on_panic};
use zksync_consensus_roles::validator::testonly::Setup;
use zksync_consensus_roles::{validator,validator::testonly::{SetupSpec,Setup}};
use rand::Rng as _;

#[tokio::test]
async fn test_inmemory_block_store() {
Expand All @@ -27,6 +28,30 @@ async fn test_inmemory_block_store() {
}
}

// Test checking that store doesn't accept pre-genesis blocks with invalid justification.
#[tokio::test]
async fn test_invalid_justification() {
abort_on_panic();
let ctx = &ctx::test_root(&ctx::RealClock);
let rng = &mut ctx.rng();
let mut spec = SetupSpec::new(rng, 1);
spec.first_block = spec.first_pregenesis_block+2;
let setup = Setup::from_spec(rng, spec);
scope::run!(ctx, |ctx,s| async {
let store = TestMemoryStorage::new(ctx, &setup).await;
s.spawn_bg(store.runner.run(ctx));
let store = store.blocks;
// Insert a correct block first.
store.queue_block(ctx, setup.blocks[0].clone()).await.unwrap();
// Insert an incorrect second block.
let validator::Block::PreGenesis(mut b) = setup.blocks[1].clone() else { panic!() };
b.justification = rng.gen();
store.queue_block(ctx, b.into()).await.unwrap_err();
Ok(())
}).await.unwrap();
}


#[test]
fn test_schema_encode_decode() {
let ctx = ctx::test_root(&ctx::RealClock);
Expand Down

0 comments on commit cee8d59

Please sign in to comment.