Skip to content

Commit

Permalink
[Test] Verify received genesis block hash during bootstrap
Browse files Browse the repository at this point in the history
  • Loading branch information
mrzenioszeniou committed Oct 21, 2021
1 parent 0f9688a commit f67e080
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 33 deletions.
@@ -1,2 +1,2 @@
pub mod mempool;
pub mod start_node;
mod mempool;
mod start_node;
48 changes: 48 additions & 0 deletions testing/jormungandr-integration-tests/src/jormungandr/block.rs
@@ -0,0 +1,48 @@
use assert_fs::TempDir;
use chain_impl_mockchain::chaintypes::ConsensusType;
use jormungandr_lib::interfaces::SlotDuration;
use jormungandr_testing_utils::testing::{
adversary::process::AdversaryNodeBuilder,
jormungandr::{ConfigurationBuilder, Starter},
network::LeadershipMode,
Block0ConfigurationBuilder,
};

#[test]
fn bft_block0_with_incorrect_hash() {
block0_with_incorrect_hash(ConsensusType::Bft);
}

#[test]
fn genesis_praos_block0_with_incorrect_hash() {
block0_with_incorrect_hash(ConsensusType::GenesisPraos)
}

/// Ensures that the genesis block fetched during bootstrapping is the requested one.
fn block0_with_incorrect_hash(consensus: ConsensusType) {
let block0 = Block0ConfigurationBuilder::new()
.with_slot_duration(SlotDuration::new(10).unwrap())
.with_block0_consensus(consensus)
.build()
.to_block();

let adversary = AdversaryNodeBuilder::new(block0)
.with_protocol_version(consensus.into())
.with_invalid_block0_hash()
.with_server_enabled()
.build();

let passive_temp_dir = TempDir::new().unwrap();

let passive_params = ConfigurationBuilder::default()
.with_block0_consensus(consensus)
.with_trusted_peers(vec![adversary.to_trusted_peer()])
.with_block_hash(format!("{}", adversary.genesis_block_hash()))
.build(&passive_temp_dir);

Starter::default()
.config(passive_params)
.leadership_mode(LeadershipMode::Passive)
.start_with_fail_in_logs("failed to download block")
.unwrap();
}
Expand Up @@ -11,7 +11,7 @@ pub fn wrong_protocol() {

let block0 = setup.server.block0_configuration().to_block();

let mock_controller = MockBuilder::new()
let mock_controller = MockBuilder::default()
.with_port(setup.mock_port)
.with_genesis_block(block0)
.with_protocol_version(ProtocolVersion::Bft)
Expand Down Expand Up @@ -42,7 +42,7 @@ pub fn wrong_genesis_hash() {

let block0 = setup.server.block0_configuration().to_block();

let mut mock_controller = MockBuilder::new()
let mut mock_controller = MockBuilder::default()
.with_port(setup.mock_port)
.with_protocol_version(ProtocolVersion::GenesisPraos)
.build();
Expand Down Expand Up @@ -77,7 +77,7 @@ pub fn handshake_ok() {

let block0 = setup.server.block0_configuration().to_block();

let mock_controller = MockBuilder::new()
let mock_controller = MockBuilder::default()
.with_port(setup.mock_port)
.with_genesis_block(block0)
.with_protocol_version(ProtocolVersion::GenesisPraos)
Expand Down
@@ -1,4 +1,5 @@
pub mod bft;
pub mod block;
pub mod cors;
pub mod explorer;
pub mod fragments;
Expand Down
Expand Up @@ -10,7 +10,7 @@ fn main() {
let args: Vec<String> = env::args().collect();
let port: u16 = args[1].parse().unwrap();

let mut mock_controller = MockBuilder::new().with_port(port).build();
let mut mock_controller = MockBuilder::default().with_port(port).build();

std::thread::sleep(std::time::Duration::from_secs(60));

Expand Down
Expand Up @@ -153,6 +153,7 @@ pub struct AdversaryNodeBuilder {
server_enabled: bool,
protocol_version: ProtocolVersion,
genesis_block: Block,
invalid_block0_hash: bool,
}

impl AdversaryNodeBuilder {
Expand All @@ -165,6 +166,7 @@ impl AdversaryNodeBuilder {
server_enabled: false,
protocol_version: ProtocolVersion::Bft,
genesis_block,
invalid_block0_hash: false,
}
}

Expand Down Expand Up @@ -193,8 +195,16 @@ impl AdversaryNodeBuilder {
}
}

pub fn with_invalid_block0_hash(self) -> Self {
Self {
invalid_block0_hash: true,
..self
}
}

pub fn build(self) -> AdversaryNode {
let data = MockBuilder::new()
let data = MockBuilder::default()
.with_invalid_block0_hash(self.invalid_block0_hash)
.with_protocol_version(self.protocol_version)
.with_genesis_block(self.genesis_block)
.build_data();
Expand Down
Expand Up @@ -11,31 +11,30 @@ use std::sync::RwLock;
use tokio::sync::oneshot;
use tonic::transport::Server;

use crate::testing::configuration::get_available_port;
use crate::testing::node::grpc::server::NodeServer;

pub struct MockBuilder {
mock_port: u16,
mock_port: Option<u16>,
genesis_block: Option<Block>,
protocol_version: ProtocolVersion,
invalid_block0_hash: bool,
}

impl Default for MockBuilder {
fn default() -> Self {
Self::new()
}
}

impl MockBuilder {
pub fn new() -> Self {
Self {
mock_port: 9999,
mock_port: None,
genesis_block: None,
protocol_version: ProtocolVersion::GenesisPraos,
invalid_block0_hash: false,
}
}
}

impl MockBuilder {
pub fn with_port(&mut self, mock_port: u16) -> &mut Self {
self.mock_port = mock_port;
self.mock_port = Some(mock_port);
self
}

Expand All @@ -49,6 +48,11 @@ impl MockBuilder {
self
}

pub fn with_invalid_block0_hash(&mut self, invalid_block0_hash: bool) -> &mut Self {
self.invalid_block0_hash = invalid_block0_hash;
self
}

pub fn build_data(&self) -> Arc<RwLock<MockServerData>> {
let storage = BlockStore::memory(Hash::zero_hash().as_bytes().to_owned()).unwrap();
let block0 = if let Some(block) = self.genesis_block.clone().take() {
Expand All @@ -62,10 +66,14 @@ impl MockBuilder {
let data = MockServerData::new(
block0.header().hash(),
self.protocol_version.clone(),
format!("127.0.0.1:{}", self.mock_port)
.parse::<SocketAddr>()
.unwrap(),
format!(
"127.0.0.1:{}",
self.mock_port.unwrap_or_else(get_available_port)
)
.parse::<SocketAddr>()
.unwrap(),
storage,
self.invalid_block0_hash,
);

data.put_block(&block0).unwrap();
Expand Down
Expand Up @@ -14,7 +14,7 @@ use std::{
pub struct MockController {
verifier: MockVerifier,
stop_signal: tokio::sync::oneshot::Sender<()>,
pub data: Arc<RwLock<MockServerData>>,
data: Arc<RwLock<MockServerData>>,
port: u16,
}

Expand Down
Expand Up @@ -22,6 +22,7 @@ pub struct MockServerData {
profile: poldercast::Profile,
auth_nonce: [u8; AUTH_NONCE_LEN],
storage: BlockStore,
invalid_block0_hash: bool,
}

#[derive(thiserror::Error, Debug)]
Expand All @@ -41,6 +42,7 @@ impl MockServerData {
protocol: ProtocolVersion,
addr: SocketAddr,
storage: BlockStore,
invalid_get_blocks_hash: bool,
) -> Self {
let keypair = KeyPair::generate(&mut rand::thread_rng());
let topology_key = keynesis::key::ed25519::SecretKey::new(&mut rand::thread_rng());
Expand All @@ -52,6 +54,7 @@ impl MockServerData {
profile,
auth_nonce: [0; AUTH_NONCE_LEN],
storage,
invalid_block0_hash: invalid_get_blocks_hash,
}
}

Expand Down Expand Up @@ -146,6 +149,10 @@ impl MockServerData {
pub fn protocol_mut(&mut self) -> &mut ProtocolVersion {
&mut self.protocol
}

pub fn invalid_block0_hash(&self) -> bool {
self.invalid_block0_hash
}
}

pub fn block0() -> Block {
Expand Down
@@ -1,20 +1,26 @@
pub use super::proto::{
node_server::{Node, NodeServer},
{
Block, BlockEvent, BlockIds, ClientAuthRequest, ClientAuthResponse, Fragment, FragmentIds,
Gossip, HandshakeRequest, HandshakeResponse, Header, PeersRequest, PeersResponse,
PullBlocksRequest, PullBlocksToTipRequest, PullHeadersRequest, PushHeadersResponse,
TipRequest, TipResponse, UploadBlocksResponse,
use crate::testing::{
node::grpc::proto::{
node_server::{Node, NodeServer},
{
Block, BlockEvent, BlockIds, ClientAuthRequest, ClientAuthResponse, Fragment,
FragmentIds, Gossip, HandshakeRequest, HandshakeResponse, Header, PeersRequest,
PeersResponse, PullBlocksRequest, PullBlocksToTipRequest, PullHeadersRequest,
PushHeadersResponse, TipRequest, TipResponse, UploadBlocksResponse,
},
},
Block0ConfigurationBuilder,
};

use chain_core::{
mempack::{ReadBuf, Readable},
property::{Header as BlockHeader, Serialize},
};
use chain_impl_mockchain::{block::BlockVersion, chaintypes::ConsensusVersion, key::Hash};
use std::fmt;
use std::sync::Arc;
use std::sync::RwLock;
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;
use tonic::{Request, Response, Status};

use std::fmt;
use std::sync::Arc;
use tracing::info;

mod builder;
Expand All @@ -41,6 +47,15 @@ pub enum ProtocolVersion {
GenesisPraos = 1,
}

impl From<ConsensusVersion> for ProtocolVersion {
fn from(from: ConsensusVersion) -> Self {
match from {
ConsensusVersion::Bft => Self::Bft,
ConsensusVersion::GenesisPraos => Self::GenesisPraos,
}
}
}

impl fmt::Display for ProtocolVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
Expand Down Expand Up @@ -150,13 +165,51 @@ impl Node for JormungandrServerImpl {
}
async fn get_blocks(
&self,
_request: tonic::Request<BlockIds>,
request: tonic::Request<BlockIds>,
) -> Result<tonic::Response<Self::GetBlocksStream>, tonic::Status> {
info!(
method = %MethodType::GetBlocks,
"Get blocks request received"
);
let (_tx, rx) = mpsc::channel(1);

let block_ids = request.into_inner();

let mut blocks = vec![];

for block_id in block_ids.ids.iter() {
let block_hash = Hash::read(&mut ReadBuf::from(block_id.as_ref())).unwrap();

let mut block = self
.data
.read()
.unwrap()
.get_block(block_hash)
.map_err(|_| tonic::Status::not_found(format!("{} not available", block_hash)));

if self.data.read().unwrap().invalid_block0_hash()
&& block
.as_ref()
.map(|b| b.header().version() == BlockVersion::Genesis)
.unwrap_or(false)
{
block = Ok(Block0ConfigurationBuilder::new().build().to_block());
}

blocks.push(block);
}

let (tx, rx) = mpsc::channel(blocks.len());

for block in blocks {
tx.send(block.map(|b| {
let mut bytes = vec![];
b.serialize(&mut bytes).unwrap();
Block { content: bytes }
}))
.await
.unwrap();
}

Ok(Response::new(ReceiverStream::new(rx)))
}
async fn get_headers(
Expand Down

0 comments on commit f67e080

Please sign in to comment.