From 66945dfe879f4845c59841569b4e8118a9c6b52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Chabowski?= Date: Tue, 16 Jan 2024 11:27:27 +0100 Subject: [PATCH 1/5] binary_port: Remove stray comment --- types/src/binary_port/payload_type.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/types/src/binary_port/payload_type.rs b/types/src/binary_port/payload_type.rs index 87da7f4ce8..4fdab4c23f 100644 --- a/types/src/binary_port/payload_type.rs +++ b/types/src/binary_port/payload_type.rs @@ -142,7 +142,6 @@ impl PayloadType { impl TryFrom for PayloadType { type Error = (); - // TODO: replace with macro or find better option fn try_from(v: u8) -> Result { match v { x if x == PayloadType::BlockHeaderV1 as u8 => Ok(PayloadType::BlockHeaderV1), From 9d67819aec1096dd73a9d398a9e9e4323ee25ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Chabowski?= Date: Tue, 16 Jan 2024 11:57:58 +0100 Subject: [PATCH 2/5] binary_port: Handle serialization error in `BinaryResponse::from_value()` --- types/src/binary_port/binary_response.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/types/src/binary_port/binary_response.rs b/types/src/binary_port/binary_response.rs index a56207f8f4..41667c74bd 100644 --- a/types/src/binary_port/binary_response.rs +++ b/types/src/binary_port/binary_response.rs @@ -66,10 +66,13 @@ impl BinaryResponse { where V: ToBytes + PayloadEntity, { - BinaryResponse { - payload: ToBytes::to_bytes(&val).unwrap(), - header: BinaryResponseHeader::new(Some(V::PAYLOAD_TYPE)), - } + ToBytes::to_bytes(&val).map_or( + BinaryResponse::new_error(ErrorCode::InternalError), + |payload| BinaryResponse { + payload, + header: BinaryResponseHeader::new(Some(V::PAYLOAD_TYPE)), + }, + ) } /// Creates a new binary response from an optional value. From d72f3d58c0200d94da588f9becc6d1158e710405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Chabowski?= Date: Tue, 16 Jan 2024 12:02:00 +0100 Subject: [PATCH 3/5] binary_port: Remove `get_bids()` metric --- node/src/components/contract_runtime/metrics.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/node/src/components/contract_runtime/metrics.rs b/node/src/components/contract_runtime/metrics.rs index 891b29be1a..e778906583 100644 --- a/node/src/components/contract_runtime/metrics.rs +++ b/node/src/components/contract_runtime/metrics.rs @@ -43,9 +43,6 @@ const GET_ERA_VALIDATORS_NAME: &str = "contract_runtime_get_era_validators"; const GET_ERA_VALIDATORS_HELP: &str = "time in seconds to get validators for a given era from global state"; -const GET_BIDS_NAME: &str = "contract_runtime_get_bids"; -const GET_BIDS_HELP: &str = "time in seconds to get bids from global state"; - const GET_ALL_VALUES_NAME: &str = "contract_runtime_get_all_values"; const GET_ALL_VALUES_NAME_HELP: &str = "time in seconds to get all values under a give key from global state"; @@ -78,7 +75,6 @@ pub struct Metrics { pub(super) get_total_supply: Histogram, pub(super) get_round_seigniorage_rate: Histogram, pub(super) get_era_validators: Histogram, - pub(super) get_bids: Histogram, // TODO[RC]: Remove as `GetBids` request has been removed. pub(super) get_all_values: Histogram, pub(super) put_trie: Histogram, pub(super) get_trie: Histogram, @@ -164,12 +160,6 @@ impl Metrics { GET_ERA_VALIDATORS_HELP, common_buckets.clone(), )?, - get_bids: utils::register_histogram_metric( - registry, - GET_BIDS_NAME, - GET_BIDS_HELP, - common_buckets.clone(), - )?, get_all_values: utils::register_histogram_metric( registry, GET_ALL_VALUES_NAME, @@ -210,7 +200,6 @@ impl Drop for Metrics { unregister_metric!(self.registry, self.commit_step); unregister_metric!(self.registry, self.get_balance); unregister_metric!(self.registry, self.get_era_validators); - unregister_metric!(self.registry, self.get_bids); unregister_metric!(self.registry, self.put_trie); unregister_metric!(self.registry, self.get_trie); unregister_metric!(self.registry, self.exec_block); From 304c9641a8a482ff4dbd45fc05064be7bcd9f9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Chabowski?= Date: Tue, 16 Jan 2024 12:18:11 +0100 Subject: [PATCH 4/5] binary_ports: Minor updates to protocol description --- node/BINARY_PORT_PROTOCOL.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/node/BINARY_PORT_PROTOCOL.md b/node/BINARY_PORT_PROTOCOL.md index 19020aed70..59ba97f94e 100644 --- a/node/BINARY_PORT_PROTOCOL.md +++ b/node/BINARY_PORT_PROTOCOL.md @@ -11,17 +11,21 @@ This is a binary protocol which follows a simple request-response model built on | 1 | RequestTag | Tag identifying the request | | ... | RequestPayload | Payload to be interpreted according to `RequestTag` | +Request bytes can be constructed from bytesrepr-serialized `BinaryRequestHeader` followed by bytesrepr-serialized `BinaryRequest` + ### Response format | Size in bytes | Field | Description | |-----------------|-----------------|-------------------------------------------------------------------------| -| 4 | LengthOfRequest | Length of the request being responded to | +| 4 | LengthOfRequest | Length of the request being responded to | | LengthOfRequest | RequestBytes | The request being responded to encoded as bytes | | 12 | ProtocolVersion | Protocol version as a u32 triplet (major, minor, patch) | | 1 | ErrorCode | Error code, where 0 indicates success | | 1-2 | PayloadTag | Optional payload type tag (first byte being 1 indicates that it exists) | -| ... | Payload | Payload to be interpreted according to `PayloadTypeTag` | +| ... | Payload | Payload to be interpreted according to `PayloadTag` | + +`BinaryResponseAndRequest` object can be bytesrepr-deserialized from these bytes. -**Note:** `...` means that the payload size is variable in size and depends on the tag. +**Notes:** `...` means that the payload size is variable in size and depends on the tag. ## Versioning Every version of the protocol follows a standard SemVer MAJOR.MINOR.PATCH scheme. @@ -32,11 +36,11 @@ The protocol supports **backwards-compatible** changes to some parts of the requ - addition of new [`DbId`](#request-model-details) - addition of new [`ErrorCode`](#response-format) -Implementations of the protocol can handle requests/responses with a different **MINOR** version than their own. It is possible that they receive a payload they don't support if their version is lower. In that case they should respond with an error code indicating the lack of support for the given payload. +Implementations of the protocol can handle requests/responses with a different **MINOR** version than their own. It is possible that they receive a payload they don't support if their version is lower. In that case they should respond with an error code indicating the lack of support for the given payload (`ErrorCode::UnsupportedRequest`). -Other changes to the protocol such as changes to the format of existing requests/responses or removal of existing requests/responses are only allowed between **MAJOR** versions. Implementations of the protocol should not handle requests/responses with a different **MAJOR** version than their own and immediately respond with an error code indicating the lack of support for the given version. +Other changes to the protocol such as changes to the format of existing requests/responses or removal of existing requests/responses are only allowed between **MAJOR** versions. Implementations of the protocol should not handle requests/responses with a different **MAJOR** version than their own and immediately respond with an error code indicating the lack of support for the given version (`ErrorCode::UnsupportedRequest`). -Changes to the envelopes (the request/response headers) are not allowed. +Changes to the envelopes (the request/response headers) are not allowed. ## Request model details There are currently 3 supported types of requests, but the request model can be extended with new variants according to the [versioning](#versioning) rules. The request types are: From 1dcd362283713ea6b351bc54a868e5cce32ba6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Chabowski?= Date: Tue, 16 Jan 2024 16:03:07 +0100 Subject: [PATCH 5/5] binary_port: Clean up tests for enabled/disabled binary port functions --- node/src/components/binary_port/tests.rs | 333 +----------------- .../binary_port/tests/functions_disabled.rs | 125 +++++++ .../binary_port/tests/functions_enabled.rs | 222 ++++++++++++ 3 files changed, 356 insertions(+), 324 deletions(-) create mode 100644 node/src/components/binary_port/tests/functions_disabled.rs create mode 100644 node/src/components/binary_port/tests/functions_enabled.rs diff --git a/node/src/components/binary_port/tests.rs b/node/src/components/binary_port/tests.rs index 61e1c3cd96..0b1e5f5ec9 100644 --- a/node/src/components/binary_port/tests.rs +++ b/node/src/components/binary_port/tests.rs @@ -1,27 +1,18 @@ -use std::{ - fmt::{self, Display, Formatter}, - sync::Arc, - time::Duration, -}; +mod functions_disabled; +mod functions_enabled; + +use std::fmt::{self, Display, Formatter}; use derive_more::From; -use futures::channel::oneshot; -use prometheus::Registry; use serde::Serialize; -use thiserror::Error as ThisError; use casper_types::{ - binary_port::{binary_request::BinaryRequest, get::GetRequest, ErrorCode}, - testing::TestRng, - Chainspec, ChainspecRawBytes, Digest, KeyTag, + binary_port::{binary_request::BinaryRequest, get::GetRequest}, + Digest, KeyTag, }; use crate::{ - components::{ - binary_port::{config::Config as BinaryPortConfig, event::Event as BinaryPortEvent}, - network::Identity as NetworkIdentity, - Component, InitializedComponent, - }, + components::binary_port::event::Event as BinaryPortEvent, effect::{ announcements::ControlAnnouncement, requests::{ @@ -29,17 +20,13 @@ use crate::{ ConsensusRequest, ContractRuntimeRequest, NetworkInfoRequest, ReactorInfoRequest, StorageRequest, UpgradeWatcherRequest, }, - EffectBuilder, EffectExt, Effects, Responder, }, - reactor::{self, EventQueueHandle, QueueKind, Reactor, ReactorEvent, Runner, Scheduler}, - testing::{network::NetworkedReactor, ConditionCheckReactor}, - types::NodeRng, - utils::{self, Loadable}, + reactor::ReactorEvent, }; use super::BinaryPort; -/// Top-level event for the reactor. +/// Top-level event for the test reactors. #[derive(Debug, From, Serialize)] #[must_use] enum Event { @@ -125,308 +112,6 @@ impl ReactorEvent for Event { } } -/// Error type returned by the test reactor. -#[derive(Debug, ThisError)] -enum ReactorError { - #[error("prometheus (metrics) error: {0}")] - Metrics(#[from] prometheus::Error), -} - -struct MockReactor { - binary_port: BinaryPort, - scheduler: &'static Scheduler, -} - -impl MockReactor { - fn new(config: BinaryPortConfig) -> Self { - let registry = Registry::new(); - let mut binary_port = BinaryPort::new(config, ®istry).unwrap(); - >::start_initialization(&mut binary_port); - Self { - binary_port, - scheduler: utils::leak(Scheduler::new(QueueKind::weights(), None)), - } - } -} - -#[tokio::test] -async fn should_respect_function_disabled_flag_for_get_all_values() { - let mut rng = TestRng::new(); - - const ENABLED: bool = true; - const DISABLED: bool = false; - const EXPECTED_ERROR_CODE: ErrorCode = ErrorCode::FunctionDisabled; - - let config = BinaryPortConfig { - enable_server: true, - allow_request_get_all_values: DISABLED, - allow_request_get_trie: ENABLED, - max_request_size_bytes: 1024, - max_response_size_bytes: 1024, - client_request_limit: 2, - client_request_buffer_size: 16, - max_connections: 2, - ..Default::default() - }; - - let (sender, receiver) = oneshot::channel(); - let event = super::Event::HandleRequest { - request: all_values_request(), - responder: Responder::without_shutdown(sender), - }; - - let mut reactor = MockReactor::new(config.clone()); - let effect_builder = EffectBuilder::new(EventQueueHandle::without_shutdown(reactor.scheduler)); - - let initialize_event = super::Event::Initialize; - let effects = reactor - .binary_port - .handle_event(effect_builder, &mut rng, initialize_event); - assert_eq!(0, effects.len()); - - let mut effects = reactor - .binary_port - .handle_event(effect_builder, &mut rng, event); - assert_eq!(1, effects.len()); - tokio::spawn(effects.remove(0)); - let result = receiver.await.unwrap(); - assert_eq!(result.error_code(), EXPECTED_ERROR_CODE as u8); -} - -#[tokio::test] -async fn should_respect_function_disabled_flag_for_get_trie() { - let mut rng = TestRng::new(); - - const ENABLED: bool = true; - const DISABLED: bool = false; - const EXPECTED_ERROR_CODE: ErrorCode = ErrorCode::FunctionDisabled; - - let config = BinaryPortConfig { - enable_server: true, - allow_request_get_all_values: ENABLED, - allow_request_get_trie: DISABLED, - max_request_size_bytes: 1024, - max_response_size_bytes: 1024, - client_request_limit: 2, - client_request_buffer_size: 16, - max_connections: 2, - ..Default::default() - }; - - let (sender, receiver) = oneshot::channel(); - let event = super::Event::HandleRequest { - request: trie_request(), - responder: Responder::without_shutdown(sender), - }; - - let mut reactor = MockReactor::new(config.clone()); - let effect_builder = EffectBuilder::new(EventQueueHandle::without_shutdown(reactor.scheduler)); - - let initialize_event = super::Event::Initialize; - let effects = reactor - .binary_port - .handle_event(effect_builder, &mut rng, initialize_event); - assert_eq!(0, effects.len()); - - let mut effects = reactor - .binary_port - .handle_event(effect_builder, &mut rng, event); - assert_eq!(1, effects.len()); - tokio::spawn(effects.remove(0)); - let result = receiver.await.unwrap(); - assert_eq!(result.error_code(), EXPECTED_ERROR_CODE as u8); -} - -struct MockReactor1 { - binary_port: BinaryPort, - //scheduler: &'static Scheduler, -} - -impl NetworkedReactor for MockReactor1 {} - -impl Reactor for MockReactor1 { - type Event = Event; - type Config = BinaryPortConfig; - type Error = ReactorError; - - fn new( - config: Self::Config, - _chainspec: Arc, - _chainspec_raw_bytes: Arc, - _network_identity: NetworkIdentity, - registry: &Registry, - _event_queue: EventQueueHandle, - _rng: &mut NodeRng, - ) -> Result<(Self, Effects), Self::Error> { - let mut binary_port = BinaryPort::new(config, registry).unwrap(); - >::start_initialization(&mut binary_port); - - let reactor = MockReactor1 { binary_port }; - - let effects = Effects::new(); - - Ok((reactor, effects)) - } - - fn dispatch_event( - &mut self, - effect_builder: EffectBuilder, - rng: &mut NodeRng, - event: Event, - ) -> Effects { - match event { - Event::BinaryPort(event) => reactor::wrap_effects( - Event::BinaryPort, - self.binary_port.handle_event(effect_builder, rng, event), - ), - Event::ControlAnnouncement(_) => panic!("unexpected control announcement"), - Event::ContractRuntimeRequest(_) => { - // We're only interested if the binary port actually created a request to Contract - // Runtime component, but we're not interested in the result. - Effects::new() - } - } - } -} - -fn got_contract_runtime_request(event: &Event) -> bool { - match event { - Event::BinaryPort(_) => false, - Event::ControlAnnouncement(_) => false, - Event::ContractRuntimeRequest(_) => true, - } -} - -#[tokio::test] -async fn should_respect_function_enabled_flag_for_get_all_values() { - let mut rng = TestRng::new(); - - const ENABLED: bool = true; - const DISABLED: bool = false; - const EXPECTED_ERROR_CODE: ErrorCode = ErrorCode::FunctionDisabled; - - let config = BinaryPortConfig { - enable_server: true, - allow_request_get_all_values: ENABLED, - allow_request_get_trie: DISABLED, - max_request_size_bytes: 1024, - max_response_size_bytes: 1024, - client_request_limit: 2, - client_request_buffer_size: 16, - max_connections: 2, - ..Default::default() - }; - - let (chainspec, chainspec_raw_bytes) = - <(Chainspec, ChainspecRawBytes)>::from_resources("local"); - let mut runner: Runner> = Runner::new( - config.clone(), - Arc::new(chainspec), - Arc::new(chainspec_raw_bytes), - &mut rng, - ) - .await - .unwrap(); - - // Initialize component. - runner - .process_injected_effects(|effect_builder| { - effect_builder - .into_inner() - .schedule(super::Event::Initialize, QueueKind::Api) - .ignore() - }) - .await; - - let (sender, _receiver) = oneshot::channel(); - let event = super::Event::HandleRequest { - request: all_values_request(), - responder: Responder::without_shutdown(sender), - }; - - runner - .process_injected_effects(|effect_builder| { - effect_builder - .into_inner() - .schedule(event, QueueKind::Api) - .ignore() - }) - .await; - - runner - .crank_until( - &mut rng, - got_contract_runtime_request, - Duration::from_secs(10), - ) - .await; -} - -#[tokio::test] -async fn should_respect_function_enabled_flag_for_get_trie() { - let mut rng = TestRng::new(); - - const ENABLED: bool = true; - const DISABLED: bool = false; - const EXPECTED_ERROR_CODE: ErrorCode = ErrorCode::FunctionDisabled; - - let config = BinaryPortConfig { - enable_server: true, - allow_request_get_all_values: DISABLED, - allow_request_get_trie: ENABLED, - max_request_size_bytes: 1024, - max_response_size_bytes: 1024, - client_request_limit: 2, - client_request_buffer_size: 16, - max_connections: 2, - ..Default::default() - }; - - let (chainspec, chainspec_raw_bytes) = - <(Chainspec, ChainspecRawBytes)>::from_resources("local"); - let mut runner: Runner> = Runner::new( - config.clone(), - Arc::new(chainspec), - Arc::new(chainspec_raw_bytes), - &mut rng, - ) - .await - .unwrap(); - - // Initialize component. - runner - .process_injected_effects(|effect_builder| { - effect_builder - .into_inner() - .schedule(super::Event::Initialize, QueueKind::Api) - .ignore() - }) - .await; - - let (sender, _receiver) = oneshot::channel(); - let event = super::Event::HandleRequest { - request: trie_request(), - responder: Responder::without_shutdown(sender), - }; - - runner - .process_injected_effects(|effect_builder| { - effect_builder - .into_inner() - .schedule(event, QueueKind::Api) - .ignore() - }) - .await; - - runner - .crank_until( - &mut rng, - got_contract_runtime_request, - Duration::from_secs(10), - ) - .await; -} - fn all_values_request() -> BinaryRequest { BinaryRequest::Get(GetRequest::AllValues { state_root_hash: Digest::hash([1u8; 32]), diff --git a/node/src/components/binary_port/tests/functions_disabled.rs b/node/src/components/binary_port/tests/functions_disabled.rs new file mode 100644 index 0000000000..299fe8a6d6 --- /dev/null +++ b/node/src/components/binary_port/tests/functions_disabled.rs @@ -0,0 +1,125 @@ +use futures::channel::oneshot; +use prometheus::Registry; + +use casper_types::{binary_port::ErrorCode, testing::TestRng}; + +use crate::{ + components::{ + binary_port::{ + config::Config as BinaryPortConfig, + event::Event as BinaryPortEvent, + tests::{all_values_request, trie_request}, + }, + Component, InitializedComponent, + }, + effect::{EffectBuilder, Responder}, + reactor::{EventQueueHandle, QueueKind, Scheduler}, + utils, +}; + +use super::{BinaryPort, Event}; + +#[tokio::test] +async fn should_respect_function_disabled_flag_for_get_all_values() { + let mut rng = TestRng::new(); + + const ENABLED: bool = true; + const DISABLED: bool = false; + const EXPECTED_ERROR_CODE: ErrorCode = ErrorCode::FunctionDisabled; + + let config = BinaryPortConfig { + enable_server: true, + allow_request_get_all_values: DISABLED, + allow_request_get_trie: ENABLED, + max_request_size_bytes: 1024, + max_response_size_bytes: 1024, + client_request_limit: 2, + client_request_buffer_size: 16, + max_connections: 2, + ..Default::default() + }; + + let (sender, receiver) = oneshot::channel(); + let event = BinaryPortEvent::HandleRequest { + request: all_values_request(), + responder: Responder::without_shutdown(sender), + }; + + let mut reactor = MockReactor::new(config.clone()); + let effect_builder = EffectBuilder::new(EventQueueHandle::without_shutdown(reactor.scheduler)); + + let initialize_event = BinaryPortEvent::Initialize; + let effects = reactor + .binary_port + .handle_event(effect_builder, &mut rng, initialize_event); + assert_eq!(0, effects.len()); + + let mut effects = reactor + .binary_port + .handle_event(effect_builder, &mut rng, event); + assert_eq!(1, effects.len()); + tokio::spawn(effects.remove(0)); + let result = receiver.await.unwrap(); + assert_eq!(result.error_code(), EXPECTED_ERROR_CODE as u8); +} + +#[tokio::test] +async fn should_respect_function_disabled_flag_for_get_trie() { + let mut rng = TestRng::new(); + + const ENABLED: bool = true; + const DISABLED: bool = false; + const EXPECTED_ERROR_CODE: ErrorCode = ErrorCode::FunctionDisabled; + + let config = BinaryPortConfig { + enable_server: true, + allow_request_get_all_values: ENABLED, + allow_request_get_trie: DISABLED, + max_request_size_bytes: 1024, + max_response_size_bytes: 1024, + client_request_limit: 2, + client_request_buffer_size: 16, + max_connections: 2, + ..Default::default() + }; + + let (sender, receiver) = oneshot::channel(); + let event = BinaryPortEvent::HandleRequest { + request: trie_request(), + responder: Responder::without_shutdown(sender), + }; + + let mut reactor = MockReactor::new(config.clone()); + let effect_builder = EffectBuilder::new(EventQueueHandle::without_shutdown(reactor.scheduler)); + + let initialize_event = BinaryPortEvent::Initialize; + let effects = reactor + .binary_port + .handle_event(effect_builder, &mut rng, initialize_event); + assert_eq!(0, effects.len()); + + let mut effects = reactor + .binary_port + .handle_event(effect_builder, &mut rng, event); + assert_eq!(1, effects.len()); + tokio::spawn(effects.remove(0)); + let result = receiver.await.unwrap(); + assert_eq!(result.error_code(), EXPECTED_ERROR_CODE as u8); +} + +struct MockReactor { + binary_port: BinaryPort, + scheduler: &'static Scheduler, +} + +impl MockReactor { + fn new(config: BinaryPortConfig) -> Self { + let registry = Registry::new(); + let mut binary_port = BinaryPort::new(config, ®istry).unwrap(); + >::start_initialization(&mut binary_port); + Self { + binary_port, + scheduler: utils::leak(Scheduler::new(QueueKind::weights(), None)), + } + } +} diff --git a/node/src/components/binary_port/tests/functions_enabled.rs b/node/src/components/binary_port/tests/functions_enabled.rs new file mode 100644 index 0000000000..52c1ce167b --- /dev/null +++ b/node/src/components/binary_port/tests/functions_enabled.rs @@ -0,0 +1,222 @@ +use std::{sync::Arc, time::Duration}; + +use futures::channel::oneshot; +use prometheus::Registry; +use thiserror::Error as ThisError; + +use casper_types::{binary_port::ErrorCode, testing::TestRng, Chainspec, ChainspecRawBytes}; + +use crate::{ + components::{ + binary_port::{ + config::Config as BinaryPortConfig, + event::Event as BinaryPortEvent, + tests::{all_values_request, trie_request}, + }, + network::Identity as NetworkIdentity, + Component, InitializedComponent, + }, + effect::{EffectBuilder, EffectExt, Effects, Responder}, + reactor::{self, EventQueueHandle, QueueKind, Reactor, Runner}, + testing::{network::NetworkedReactor, ConditionCheckReactor}, + types::NodeRng, + utils::Loadable, +}; + +use super::{BinaryPort, Event}; + +#[tokio::test] +async fn should_respect_function_enabled_flag_for_get_all_values() { + let mut rng = TestRng::new(); + + const ENABLED: bool = true; + const DISABLED: bool = false; + const EXPECTED_ERROR_CODE: ErrorCode = ErrorCode::FunctionDisabled; + + let config = BinaryPortConfig { + enable_server: true, + allow_request_get_all_values: ENABLED, + allow_request_get_trie: DISABLED, + max_request_size_bytes: 1024, + max_response_size_bytes: 1024, + client_request_limit: 2, + client_request_buffer_size: 16, + max_connections: 2, + ..Default::default() + }; + + let (chainspec, chainspec_raw_bytes) = + <(Chainspec, ChainspecRawBytes)>::from_resources("local"); + let mut runner: Runner> = Runner::new( + config.clone(), + Arc::new(chainspec), + Arc::new(chainspec_raw_bytes), + &mut rng, + ) + .await + .unwrap(); + + // Initialize component. + runner + .process_injected_effects(|effect_builder| { + effect_builder + .into_inner() + .schedule(BinaryPortEvent::Initialize, QueueKind::Api) + .ignore() + }) + .await; + + let (sender, _receiver) = oneshot::channel(); + let event = BinaryPortEvent::HandleRequest { + request: all_values_request(), + responder: Responder::without_shutdown(sender), + }; + + runner + .process_injected_effects(|effect_builder| { + effect_builder + .into_inner() + .schedule(event, QueueKind::Api) + .ignore() + }) + .await; + + runner + .crank_until( + &mut rng, + got_contract_runtime_request, + Duration::from_secs(10), + ) + .await; +} + +#[tokio::test] +async fn should_respect_function_enabled_flag_for_get_trie() { + let mut rng = TestRng::new(); + + const ENABLED: bool = true; + const DISABLED: bool = false; + const EXPECTED_ERROR_CODE: ErrorCode = ErrorCode::FunctionDisabled; + + let config = BinaryPortConfig { + enable_server: true, + allow_request_get_all_values: DISABLED, + allow_request_get_trie: ENABLED, + max_request_size_bytes: 1024, + max_response_size_bytes: 1024, + client_request_limit: 2, + client_request_buffer_size: 16, + max_connections: 2, + ..Default::default() + }; + + let (chainspec, chainspec_raw_bytes) = + <(Chainspec, ChainspecRawBytes)>::from_resources("local"); + let mut runner: Runner> = Runner::new( + config.clone(), + Arc::new(chainspec), + Arc::new(chainspec_raw_bytes), + &mut rng, + ) + .await + .unwrap(); + + // Initialize component. + runner + .process_injected_effects(|effect_builder| { + effect_builder + .into_inner() + .schedule(BinaryPortEvent::Initialize, QueueKind::Api) + .ignore() + }) + .await; + + let (sender, _receiver) = oneshot::channel(); + let event = BinaryPortEvent::HandleRequest { + request: trie_request(), + responder: Responder::without_shutdown(sender), + }; + + runner + .process_injected_effects(|effect_builder| { + effect_builder + .into_inner() + .schedule(event, QueueKind::Api) + .ignore() + }) + .await; + + runner + .crank_until( + &mut rng, + got_contract_runtime_request, + Duration::from_secs(10), + ) + .await; +} + +struct MockReactor { + binary_port: BinaryPort, +} + +impl NetworkedReactor for MockReactor {} + +impl Reactor for MockReactor { + type Event = Event; + type Config = BinaryPortConfig; + type Error = ReactorError; + + fn new( + config: Self::Config, + _chainspec: Arc, + _chainspec_raw_bytes: Arc, + _network_identity: NetworkIdentity, + registry: &Registry, + _event_queue: EventQueueHandle, + _rng: &mut NodeRng, + ) -> Result<(Self, Effects), Self::Error> { + let mut binary_port = BinaryPort::new(config, registry).unwrap(); + >::start_initialization(&mut binary_port); + + let reactor = MockReactor { binary_port }; + + let effects = Effects::new(); + + Ok((reactor, effects)) + } + + fn dispatch_event( + &mut self, + effect_builder: EffectBuilder, + rng: &mut NodeRng, + event: Event, + ) -> Effects { + match event { + Event::BinaryPort(event) => reactor::wrap_effects( + Event::BinaryPort, + self.binary_port.handle_event(effect_builder, rng, event), + ), + Event::ControlAnnouncement(_) => panic!("unexpected control announcement"), + Event::ContractRuntimeRequest(_) => { + // We're only interested if the binary port actually created a request to Contract + // Runtime component, but we're not interested in the result. + Effects::new() + } + } + } +} + +fn got_contract_runtime_request(event: &Event) -> bool { + match event { + Event::BinaryPort(_) => false, + Event::ControlAnnouncement(_) => false, + Event::ContractRuntimeRequest(_) => true, + } +} + +/// Error type returned by the test reactor. +#[derive(Debug, ThisError)] +enum ReactorError { + #[error("prometheus (metrics) error: {0}")] + Metrics(#[from] prometheus::Error), +}