diff --git a/binary_port/src/dictionary_item_identifier.rs b/binary_port/src/dictionary_item_identifier.rs index 44277b8ddb..28e5c81150 100644 --- a/binary_port/src/dictionary_item_identifier.rs +++ b/binary_port/src/dictionary_item_identifier.rs @@ -59,7 +59,7 @@ pub enum DictionaryItemIdentifier { impl DictionaryItemIdentifier { #[cfg(test)] pub(crate) fn random(rng: &mut TestRng) -> Self { - match rng.gen_range(0..4) { + match rng.gen_range(0..5) { 0 => DictionaryItemIdentifier::AccountNamedKey { hash: rng.gen(), dictionary_name: rng.random_string(32..64), @@ -70,11 +70,16 @@ impl DictionaryItemIdentifier { dictionary_name: rng.random_string(32..64), dictionary_item_key: rng.random_string(32..64), }, - 2 => DictionaryItemIdentifier::URef { + 2 => DictionaryItemIdentifier::EntityNamedKey { + addr: rng.gen(), + dictionary_name: rng.random_string(32..64), + dictionary_item_key: rng.random_string(32..64), + }, + 3 => DictionaryItemIdentifier::URef { seed_uref: rng.gen(), dictionary_item_key: rng.random_string(32..64), }, - 3 => DictionaryItemIdentifier::DictionaryItem(rng.gen()), + 4 => DictionaryItemIdentifier::DictionaryItem(rng.gen()), _ => unreachable!(), } } diff --git a/binary_port/src/entity_qualifier.rs b/binary_port/src/entity_qualifier.rs new file mode 100644 index 0000000000..93f8bf82bb --- /dev/null +++ b/binary_port/src/entity_qualifier.rs @@ -0,0 +1,193 @@ +use super::dictionary_item_identifier::DictionaryItemIdentifier; +use crate::{KeyPrefix, PurseIdentifier}; +#[cfg(test)] +use casper_types::testing::TestRng; +use casper_types::{ + bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH}, + Key, KeyTag, +}; +#[cfg(test)] +use rand::Rng; + +const ITEM_TAG: u8 = 0; +const ALL_ITEMS_TAG: u8 = 1; +const DICTIONARY_ITEM_TAG: u8 = 2; +const BALANCE_TAG: u8 = 3; +const ITEMS_BY_PREFIX_TAG: u8 = 4; + +/// A request to get data from the global state. +#[derive(Clone, Debug, PartialEq)] +pub enum GlobalStateEntityQualifier { + /// Gets an item from the global state. + Item { + /// Key under which data is stored. + base_key: Key, + /// Path under which the value is stored. + path: Vec, + }, + /// Get all items under the given key tag. + AllItems { + /// Key tag + key_tag: KeyTag, + }, + /// Get a dictionary item by its identifier. + DictionaryItem { + /// Dictionary item identifier. + identifier: DictionaryItemIdentifier, + }, + /// Get balance by state root and purse. + Balance { + /// Purse identifier. + purse_identifier: PurseIdentifier, + }, + ItemsByPrefix { + /// Key prefix to search for. + key_prefix: KeyPrefix, + }, +} + +impl GlobalStateEntityQualifier { + #[cfg(test)] + pub(crate) fn random(rng: &mut TestRng) -> Self { + let gen_range = TestRng::gen_range(rng, 0..5); + random_for_variant(gen_range, rng) + } +} + +#[cfg(test)] +fn random_for_variant(gen_range: u8, rng: &mut TestRng) -> GlobalStateEntityQualifier { + match gen_range { + ITEM_TAG => { + let path_count = rng.gen_range(10..20); + GlobalStateEntityQualifier::Item { + base_key: rng.gen(), + path: std::iter::repeat_with(|| rng.random_string(32..64)) + .take(path_count) + .collect(), + } + } + ALL_ITEMS_TAG => GlobalStateEntityQualifier::AllItems { + key_tag: KeyTag::random(rng), + }, + DICTIONARY_ITEM_TAG => GlobalStateEntityQualifier::DictionaryItem { + identifier: DictionaryItemIdentifier::random(rng), + }, + BALANCE_TAG => GlobalStateEntityQualifier::Balance { + purse_identifier: PurseIdentifier::random(rng), + }, + ITEMS_BY_PREFIX_TAG => GlobalStateEntityQualifier::ItemsByPrefix { + key_prefix: KeyPrefix::random(rng), + }, + _ => unreachable!(), + } +} + +impl ToBytes for GlobalStateEntityQualifier { + fn to_bytes(&self) -> Result, bytesrepr::Error> { + let mut buffer = bytesrepr::allocate_buffer(self)?; + self.write_bytes(&mut buffer)?; + Ok(buffer) + } + + fn write_bytes(&self, writer: &mut Vec) -> Result<(), bytesrepr::Error> { + match self { + GlobalStateEntityQualifier::Item { base_key, path } => { + ITEM_TAG.write_bytes(writer)?; + base_key.write_bytes(writer)?; + path.write_bytes(writer) + } + GlobalStateEntityQualifier::AllItems { key_tag } => { + ALL_ITEMS_TAG.write_bytes(writer)?; + key_tag.write_bytes(writer) + } + GlobalStateEntityQualifier::DictionaryItem { identifier } => { + DICTIONARY_ITEM_TAG.write_bytes(writer)?; + identifier.write_bytes(writer) + } + GlobalStateEntityQualifier::Balance { purse_identifier } => { + BALANCE_TAG.write_bytes(writer)?; + purse_identifier.write_bytes(writer) + } + GlobalStateEntityQualifier::ItemsByPrefix { key_prefix } => { + ITEMS_BY_PREFIX_TAG.write_bytes(writer)?; + key_prefix.write_bytes(writer) + } + } + } + + fn serialized_length(&self) -> usize { + U8_SERIALIZED_LENGTH + + match self { + GlobalStateEntityQualifier::Item { base_key, path } => { + base_key.serialized_length() + path.serialized_length() + } + GlobalStateEntityQualifier::AllItems { key_tag } => key_tag.serialized_length(), + GlobalStateEntityQualifier::DictionaryItem { identifier } => { + identifier.serialized_length() + } + GlobalStateEntityQualifier::Balance { purse_identifier } => { + purse_identifier.serialized_length() + } + GlobalStateEntityQualifier::ItemsByPrefix { key_prefix } => { + key_prefix.serialized_length() + } + } + } +} + +impl FromBytes for GlobalStateEntityQualifier { + fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> { + let (tag, remainder) = u8::from_bytes(bytes)?; + match tag { + ITEM_TAG => { + let (base_key, remainder) = FromBytes::from_bytes(remainder)?; + let (path, remainder) = FromBytes::from_bytes(remainder)?; + Ok(( + GlobalStateEntityQualifier::Item { base_key, path }, + remainder, + )) + } + ALL_ITEMS_TAG => { + let (key_tag, remainder) = FromBytes::from_bytes(remainder)?; + Ok((GlobalStateEntityQualifier::AllItems { key_tag }, remainder)) + } + DICTIONARY_ITEM_TAG => { + let (identifier, remainder) = FromBytes::from_bytes(remainder)?; + Ok(( + GlobalStateEntityQualifier::DictionaryItem { identifier }, + remainder, + )) + } + BALANCE_TAG => { + let (purse_identifier, remainder) = FromBytes::from_bytes(remainder)?; + Ok(( + GlobalStateEntityQualifier::Balance { purse_identifier }, + remainder, + )) + } + ITEMS_BY_PREFIX_TAG => { + let (key_prefix, remainder) = FromBytes::from_bytes(remainder)?; + Ok(( + GlobalStateEntityQualifier::ItemsByPrefix { key_prefix }, + remainder, + )) + } + _ => Err(bytesrepr::Error::Formatting), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use casper_types::testing::TestRng; + + #[test] + fn bytesrepr_roundtrip() { + let rng = &mut TestRng::new(); + for i in 0..5 { + let qualifier = random_for_variant(i, rng); + bytesrepr::test_serialization_roundtrip(&qualifier); + } + } +} diff --git a/binary_port/src/get_request.rs b/binary_port/src/get_request.rs index d0cfcc811b..483a05f9ae 100644 --- a/binary_port/src/get_request.rs +++ b/binary_port/src/get_request.rs @@ -1,4 +1,7 @@ -use casper_types::bytesrepr::{self, Bytes, FromBytes, ToBytes, U8_SERIALIZED_LENGTH}; +use casper_types::{ + bytesrepr::{self, Bytes, FromBytes, ToBytes, U8_SERIALIZED_LENGTH}, + Digest, +}; use crate::state_request::GlobalStateRequest; @@ -10,6 +13,7 @@ use rand::Rng; const RECORD_TAG: u8 = 0; const INFORMATION_TAG: u8 = 1; const STATE_TAG: u8 = 2; +const TRIE_TAG: u8 = 3; /// A request to get data from the node. #[derive(Clone, Debug, PartialEq)] @@ -30,12 +34,17 @@ pub enum GetRequest { }, /// Retrieves data from the global state. State(Box), + /// Get a trie by its Digest. + Trie { + /// A trie key. + trie_key: Digest, + }, } impl GetRequest { #[cfg(test)] pub(crate) fn random(rng: &mut TestRng) -> Self { - match rng.gen_range(0..3) { + match rng.gen_range(0..4) { 0 => GetRequest::Record { record_type_tag: rng.gen(), key: rng.random_vec(16..32), @@ -45,6 +54,9 @@ impl GetRequest { key: rng.random_vec(16..32), }, 2 => GetRequest::State(Box::new(GlobalStateRequest::random(rng))), + 3 => GetRequest::Trie { + trie_key: Digest::random(rng), + }, _ => unreachable!(), } } @@ -76,6 +88,10 @@ impl ToBytes for GetRequest { STATE_TAG.write_bytes(writer)?; req.write_bytes(writer) } + GetRequest::Trie { trie_key } => { + TRIE_TAG.write_bytes(writer)?; + trie_key.write_bytes(writer) + } } } @@ -90,6 +106,7 @@ impl ToBytes for GetRequest { info_type_tag.serialized_length() + key.serialized_length() } GetRequest::State(req) => req.serialized_length(), + GetRequest::Trie { trie_key } => trie_key.serialized_length(), } } } @@ -124,6 +141,10 @@ impl FromBytes for GetRequest { let (req, remainder) = FromBytes::from_bytes(remainder)?; Ok((GetRequest::State(Box::new(req)), remainder)) } + TRIE_TAG => { + let (trie_key, remainder) = FromBytes::from_bytes(remainder)?; + Ok((GetRequest::Trie { trie_key }, remainder)) + } _ => Err(bytesrepr::Error::Formatting), } } diff --git a/binary_port/src/lib.rs b/binary_port/src/lib.rs index ec0a173ccc..292b8740e9 100644 --- a/binary_port/src/lib.rs +++ b/binary_port/src/lib.rs @@ -7,6 +7,7 @@ mod binary_response; mod binary_response_and_request; mod binary_response_header; mod dictionary_item_identifier; +mod entity_qualifier; mod era_identifier; mod error; mod error_code; @@ -31,6 +32,7 @@ pub use binary_response::BinaryResponse; pub use binary_response_and_request::BinaryResponseAndRequest; pub use binary_response_header::BinaryResponseHeader; pub use dictionary_item_identifier::DictionaryItemIdentifier; +pub use entity_qualifier::GlobalStateEntityQualifier; pub use era_identifier::EraIdentifier; pub use error::Error; pub use error_code::ErrorCode; diff --git a/binary_port/src/response_type.rs b/binary_port/src/response_type.rs index 6be59c9b3e..397d29bc05 100644 --- a/binary_port/src/response_type.rs +++ b/binary_port/src/response_type.rs @@ -145,7 +145,7 @@ impl ResponseType { #[cfg(test)] pub(crate) fn random(rng: &mut TestRng) -> Self { - Self::try_from(rng.gen_range(0..45)).unwrap() + Self::try_from(rng.gen_range(0..44)).unwrap() } } diff --git a/binary_port/src/state_request.rs b/binary_port/src/state_request.rs index ca00fc4ecf..267c678e62 100644 --- a/binary_port/src/state_request.rs +++ b/binary_port/src/state_request.rs @@ -1,114 +1,51 @@ +use std::fmt::{Display, Formatter, Result as DisplayResult}; + +use crate::entity_qualifier::GlobalStateEntityQualifier; #[cfg(test)] use casper_types::testing::TestRng; -#[cfg(test)] -use rand::Rng; - use casper_types::{ - bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH}, - Digest, GlobalStateIdentifier, Key, KeyTag, + bytesrepr::{self, FromBytes, ToBytes}, + GlobalStateIdentifier, }; - -use crate::{KeyPrefix, PurseIdentifier}; - -use super::dictionary_item_identifier::DictionaryItemIdentifier; - -const ITEM_TAG: u8 = 0; -const ALL_ITEMS_TAG: u8 = 1; -const TRIE_TAG: u8 = 2; -const DICTIONARY_ITEM_TAG: u8 = 3; -const BALANCE_TAG: u8 = 4; -const ITEMS_BY_PREFIX_TAG: u8 = 5; +#[cfg(test)] +use rand::Rng; /// A request to get data from the global state. #[derive(Clone, Debug, PartialEq)] -pub enum GlobalStateRequest { - /// Gets an item from the global state. - Item { - /// Global state identifier, `None` means "latest block state". - state_identifier: Option, - /// Key under which data is stored. - base_key: Key, - /// Path under which the value is stored. - path: Vec, - }, - /// Get all items under the given key tag. - AllItems { - /// Global state identifier, `None` means "latest block state". - state_identifier: Option, - /// Key tag - key_tag: KeyTag, - }, - /// Get a trie by its Digest. - Trie { - /// A trie key. - trie_key: Digest, - }, - /// Get a dictionary item by its identifier. - DictionaryItem { - /// Global state identifier, `None` means "latest block state". - state_identifier: Option, - /// Dictionary item identifier. - identifier: DictionaryItemIdentifier, - }, - /// Get balance by state root and purse. - Balance { - /// Global state identifier, `None` means "latest block state". - state_identifier: Option, - /// Purse identifier. - purse_identifier: PurseIdentifier, - }, - ItemsByPrefix { - /// Global state identifier, `None` means "latest block state". - state_identifier: Option, - /// Key prefix to search for. - key_prefix: KeyPrefix, - }, +pub struct GlobalStateRequest { + /// Global state identifier, `None` means "latest block state". + state_identifier: Option, + /// qualifier that points to a specific item (or items) in the global state. + qualifier: GlobalStateEntityQualifier, } impl GlobalStateRequest { + pub fn new( + state_identifier: Option, + qualifier: GlobalStateEntityQualifier, + ) -> Self { + GlobalStateRequest { + state_identifier, + qualifier, + } + } + pub fn destructure(self) -> (Option, GlobalStateEntityQualifier) { + (self.state_identifier, self.qualifier) + } + + pub fn state_identifier(self) -> Option { + self.state_identifier + } + #[cfg(test)] pub(crate) fn random(rng: &mut TestRng) -> Self { - match TestRng::gen_range(rng, 0..6) { - ITEM_TAG => { - let path_count = rng.gen_range(10..20); - GlobalStateRequest::Item { - state_identifier: rng - .gen::() - .then(|| GlobalStateIdentifier::random(rng)), - base_key: rng.gen(), - path: std::iter::repeat_with(|| rng.random_string(32..64)) - .take(path_count) - .collect(), - } - } - ALL_ITEMS_TAG => GlobalStateRequest::AllItems { - state_identifier: rng - .gen::() - .then(|| GlobalStateIdentifier::random(rng)), - key_tag: KeyTag::random(rng), - }, - TRIE_TAG => GlobalStateRequest::Trie { - trie_key: Digest::random(rng), - }, - DICTIONARY_ITEM_TAG => GlobalStateRequest::DictionaryItem { - state_identifier: rng - .gen::() - .then(|| GlobalStateIdentifier::random(rng)), - identifier: DictionaryItemIdentifier::random(rng), - }, - BALANCE_TAG => GlobalStateRequest::Balance { - state_identifier: rng - .gen::() - .then(|| GlobalStateIdentifier::random(rng)), - purse_identifier: PurseIdentifier::random(rng), - }, - ITEMS_BY_PREFIX_TAG => GlobalStateRequest::ItemsByPrefix { - state_identifier: rng - .gen::() - .then(|| GlobalStateIdentifier::random(rng)), - key_prefix: KeyPrefix::random(rng), - }, - _ => unreachable!(), + let state_identifier = rng + .gen::() + .then(|| GlobalStateIdentifier::random(rng)); + let qualifier = GlobalStateEntityQualifier::random(rng); + Self { + state_identifier, + qualifier, } } } @@ -121,155 +58,48 @@ impl ToBytes for GlobalStateRequest { } fn write_bytes(&self, writer: &mut Vec) -> Result<(), bytesrepr::Error> { - match self { - GlobalStateRequest::Item { - state_identifier, - base_key, - path, - } => { - ITEM_TAG.write_bytes(writer)?; - state_identifier.write_bytes(writer)?; - base_key.write_bytes(writer)?; - path.write_bytes(writer) - } - GlobalStateRequest::AllItems { - state_identifier, - key_tag, - } => { - ALL_ITEMS_TAG.write_bytes(writer)?; - state_identifier.write_bytes(writer)?; - key_tag.write_bytes(writer) - } - GlobalStateRequest::Trie { trie_key } => { - TRIE_TAG.write_bytes(writer)?; - trie_key.write_bytes(writer) - } - GlobalStateRequest::DictionaryItem { - state_identifier, - identifier, - } => { - DICTIONARY_ITEM_TAG.write_bytes(writer)?; - state_identifier.write_bytes(writer)?; - identifier.write_bytes(writer) - } - GlobalStateRequest::Balance { - state_identifier, - purse_identifier, - } => { - BALANCE_TAG.write_bytes(writer)?; - state_identifier.write_bytes(writer)?; - purse_identifier.write_bytes(writer) - } - GlobalStateRequest::ItemsByPrefix { - state_identifier, - key_prefix, - } => { - ITEMS_BY_PREFIX_TAG.write_bytes(writer)?; - state_identifier.write_bytes(writer)?; - key_prefix.write_bytes(writer) - } - } + self.state_identifier.write_bytes(writer)?; + self.qualifier.write_bytes(writer)?; + Ok(()) } fn serialized_length(&self) -> usize { - U8_SERIALIZED_LENGTH - + match self { - GlobalStateRequest::Item { - state_identifier, - base_key, - path, - } => { - state_identifier.serialized_length() - + base_key.serialized_length() - + path.serialized_length() - } - GlobalStateRequest::AllItems { - state_identifier, - key_tag, - } => state_identifier.serialized_length() + key_tag.serialized_length(), - GlobalStateRequest::Trie { trie_key } => trie_key.serialized_length(), - GlobalStateRequest::DictionaryItem { - state_identifier, - identifier, - } => state_identifier.serialized_length() + identifier.serialized_length(), - GlobalStateRequest::Balance { - state_identifier, - purse_identifier, - } => state_identifier.serialized_length() + purse_identifier.serialized_length(), - GlobalStateRequest::ItemsByPrefix { - state_identifier, - key_prefix, - } => state_identifier.serialized_length() + key_prefix.serialized_length(), - } + self.state_identifier.serialized_length() + self.qualifier.serialized_length() } } impl FromBytes for GlobalStateRequest { fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> { - let (tag, remainder) = u8::from_bytes(bytes)?; - match tag { - ITEM_TAG => { - let (state_identifier, remainder) = FromBytes::from_bytes(remainder)?; - let (base_key, remainder) = FromBytes::from_bytes(remainder)?; - let (path, remainder) = FromBytes::from_bytes(remainder)?; - Ok(( - GlobalStateRequest::Item { - state_identifier, - base_key, - path, - }, - remainder, - )) - } - ALL_ITEMS_TAG => { - let (state_identifier, remainder) = FromBytes::from_bytes(remainder)?; - let (key_tag, remainder) = FromBytes::from_bytes(remainder)?; - Ok(( - GlobalStateRequest::AllItems { - state_identifier, - key_tag, - }, - remainder, - )) + let (state_identifier, remainder) = FromBytes::from_bytes(bytes)?; + let (qualifier, remainder) = FromBytes::from_bytes(remainder)?; + Ok(( + GlobalStateRequest { + state_identifier, + qualifier, + }, + remainder, + )) + } +} + +impl Display for GlobalStateRequest { + fn fmt(&self, f: &mut Formatter<'_>) -> DisplayResult { + match self.qualifier { + GlobalStateEntityQualifier::Item { base_key, .. } => { + write!(f, "get item from global state ({})", base_key) } - TRIE_TAG => { - let (trie_key, remainder) = Digest::from_bytes(remainder)?; - Ok((GlobalStateRequest::Trie { trie_key }, remainder)) + GlobalStateEntityQualifier::AllItems { key_tag, .. } => { + write!(f, "get all items ({})", key_tag) } - DICTIONARY_ITEM_TAG => { - let (state_identifier, remainder) = FromBytes::from_bytes(remainder)?; - let (identifier, remainder) = FromBytes::from_bytes(remainder)?; - Ok(( - GlobalStateRequest::DictionaryItem { - state_identifier, - identifier, - }, - remainder, - )) + GlobalStateEntityQualifier::DictionaryItem { .. } => { + write!(f, "get dictionary item") } - BALANCE_TAG => { - let (state_identifier, remainder) = FromBytes::from_bytes(remainder)?; - let (purse_identifier, remainder) = FromBytes::from_bytes(remainder)?; - Ok(( - GlobalStateRequest::Balance { - state_identifier, - purse_identifier, - }, - remainder, - )) + GlobalStateEntityQualifier::Balance { .. } => { + write!(f, "get balance by state root",) } - ITEMS_BY_PREFIX_TAG => { - let (state_identifier, remainder) = FromBytes::from_bytes(remainder)?; - let (key_prefix, remainder) = FromBytes::from_bytes(remainder)?; - Ok(( - GlobalStateRequest::ItemsByPrefix { - state_identifier, - key_prefix, - }, - remainder, - )) + GlobalStateEntityQualifier::ItemsByPrefix { .. } => { + write!(f, "get items by prefix") } - _ => Err(bytesrepr::Error::Formatting), } } } @@ -282,7 +112,6 @@ mod tests { #[test] fn bytesrepr_roundtrip() { let rng = &mut TestRng::new(); - let val = GlobalStateRequest::random(rng); bytesrepr::test_serialization_roundtrip(&val); } diff --git a/node/src/components/binary_port.rs b/node/src/components/binary_port.rs index c5df30cdf3..e58c3ed67e 100644 --- a/node/src/components/binary_port.rs +++ b/node/src/components/binary_port.rs @@ -14,9 +14,10 @@ use casper_binary_port::{ BinaryMessageCodec, BinaryRequest, BinaryRequestHeader, BinaryRequestTag, BinaryResponse, BinaryResponseAndRequest, ContractInformation, DictionaryItemIdentifier, DictionaryQueryResult, EntityIdentifier, EraIdentifier, ErrorCode, GetRequest, GetTrieFullResult, - GlobalStateQueryResult, GlobalStateRequest, InformationRequest, InformationRequestTag, - KeyPrefix, NodeStatus, PackageIdentifier, PurseIdentifier, ReactorStateName, RecordId, - ResponseType, RewardResponse, TransactionWithExecutionInfo, ValueWithProof, + GlobalStateEntityQualifier, GlobalStateQueryResult, GlobalStateRequest, InformationRequest, + InformationRequestTag, KeyPrefix, NodeStatus, PackageIdentifier, PurseIdentifier, + ReactorStateName, RecordId, ResponseType, RewardResponse, TransactionWithExecutionInfo, + ValueWithProof, }; use casper_storage::{ data_access_layer::{ @@ -305,6 +306,17 @@ where metrics.binary_port_get_state_count.inc(); handle_state_request(effect_builder, *req, protocol_version, config, chainspec).await } + GetRequest::Trie { trie_key } => { + metrics.binary_port_get_trie_count.inc(); + handle_trie_request( + effect_builder, + trie_key, + protocol_version, + config, + chainspec, + ) + .await + } } } @@ -393,12 +405,9 @@ where + From + From, { - match request { - GlobalStateRequest::Item { - state_identifier, - base_key, - path, - } => { + let (state_identifier, qualifier) = request.destructure(); + match qualifier { + GlobalStateEntityQualifier::Item { base_key, path } => { let Some(state_root_hash) = resolve_state_root_hash(effect_builder, state_identifier).await else { @@ -410,10 +419,7 @@ where Err(err) => BinaryResponse::new_error(err, protocol_version), } } - GlobalStateRequest::AllItems { - state_identifier, - key_tag, - } => { + GlobalStateEntityQualifier::AllItems { key_tag } => { if !config.allow_request_get_all_values { debug!(%key_tag, "received a request for items by key tag while the feature is disabled"); BinaryResponse::new_error(ErrorCode::FunctionDisabled, protocol_version) @@ -422,28 +428,7 @@ where .await } } - GlobalStateRequest::Trie { trie_key } => { - if !config.allow_request_get_trie { - debug!(%trie_key, "received a trie request while the feature is disabled"); - BinaryResponse::new_error(ErrorCode::FunctionDisabled, protocol_version) - } else { - let req = TrieRequest::new(trie_key, None); - match effect_builder.get_trie(req).await.into_raw() { - Ok(result) => BinaryResponse::from_value( - GetTrieFullResult::new(result.map(TrieRaw::into_inner)), - protocol_version, - ), - Err(error) => { - debug!(%error, "failed when querying for a trie"); - BinaryResponse::new_error(ErrorCode::InternalError, protocol_version) - } - } - } - } - GlobalStateRequest::DictionaryItem { - state_identifier, - identifier, - } => { + GlobalStateEntityQualifier::DictionaryItem { identifier } => { let Some(state_root_hash) = resolve_state_root_hash(effect_builder, state_identifier).await else { @@ -514,10 +499,7 @@ where Err(err) => BinaryResponse::new_error(err, protocol_version), } } - GlobalStateRequest::Balance { - state_identifier, - purse_identifier, - } => { + GlobalStateEntityQualifier::Balance { purse_identifier } => { let Some(state_root_hash) = resolve_state_root_hash(effect_builder, state_identifier).await else { @@ -531,10 +513,7 @@ where ) .await } - GlobalStateRequest::ItemsByPrefix { - state_identifier, - key_prefix, - } => { + GlobalStateEntityQualifier::ItemsByPrefix { key_prefix } => { handle_get_items_by_prefix( state_identifier, key_prefix, @@ -546,6 +525,37 @@ where } } +async fn handle_trie_request( + effect_builder: EffectBuilder, + trie_key: Digest, + protocol_version: ProtocolVersion, + config: &Config, + _chainspec: &Chainspec, +) -> BinaryResponse +where + REv: From + + From + + From + + From, +{ + if !config.allow_request_get_trie { + debug!(%trie_key, "received a trie request while the feature is disabled"); + BinaryResponse::new_error(ErrorCode::FunctionDisabled, protocol_version) + } else { + let req = TrieRequest::new(trie_key, None); + match effect_builder.get_trie(req).await.into_raw() { + Ok(result) => BinaryResponse::from_value( + GetTrieFullResult::new(result.map(TrieRaw::into_inner)), + protocol_version, + ), + Err(error) => { + debug!(%error, "failed when querying for a trie"); + BinaryResponse::new_error(ErrorCode::InternalError, protocol_version) + } + } + } +} + async fn get_dictionary_item_by_legacy_named_key( effect_builder: EffectBuilder, state_root_hash: Digest, diff --git a/node/src/components/binary_port/event.rs b/node/src/components/binary_port/event.rs index 78b90c574e..0f190682b2 100644 --- a/node/src/components/binary_port/event.rs +++ b/node/src/components/binary_port/event.rs @@ -3,7 +3,7 @@ use std::{ net::SocketAddr, }; -use casper_binary_port::{BinaryRequest, BinaryResponse, GetRequest, GlobalStateRequest}; +use casper_binary_port::{BinaryRequest, BinaryResponse, GetRequest}; use tokio::net::TcpStream; use crate::effect::Responder; @@ -38,26 +38,8 @@ impl Display for Event { GetRequest::Information { info_type_tag, key } => { write!(f, "get info with tag {} ({})", info_type_tag, key.len()) } - GetRequest::State(state_request) => match state_request.as_ref() { - GlobalStateRequest::Item { base_key, .. } => { - write!(f, "get item from global state ({})", base_key) - } - GlobalStateRequest::AllItems { key_tag, .. } => { - write!(f, "get all items ({})", key_tag) - } - GlobalStateRequest::Trie { trie_key } => { - write!(f, "get trie ({})", trie_key) - } - GlobalStateRequest::DictionaryItem { .. } => { - write!(f, "get dictionary item") - } - GlobalStateRequest::Balance { .. } => { - write!(f, "get balance by state root",) - } - GlobalStateRequest::ItemsByPrefix { .. } => { - write!(f, "get items by prefix") - } - }, + GetRequest::State(state_request) => state_request.as_ref().fmt(f), + GetRequest::Trie { trie_key } => write!(f, "get trie ({})", trie_key), }, BinaryRequest::TryAcceptTransaction { transaction, .. } => { write!(f, "try accept transaction ({})", transaction.hash()) diff --git a/node/src/components/binary_port/metrics.rs b/node/src/components/binary_port/metrics.rs index 748afb1077..36de7128fd 100644 --- a/node/src/components/binary_port/metrics.rs +++ b/node/src/components/binary_port/metrics.rs @@ -26,6 +26,9 @@ const BINARY_PORT_CONNECTIONS_COUNT_NAME: &str = "binary_port_connections_count" const BINARY_PORT_CONNECTIONS_COUNT_HELP: &str = "total number of external connections established to binary port"; +const BINARY_PORT_TRIE_COUNT_NAME: &str = "binary_port_get_trie_count"; +const BINARY_PORT_TRIE_COUNT_HELP: &str = "number of Get queries received for the trie state"; + /// Metrics. #[derive(Debug)] pub(super) struct Metrics { @@ -41,6 +44,8 @@ pub(super) struct Metrics { pub(super) binary_port_get_state_count: IntCounter, /// Number of distinct connections to binary port. pub(super) binary_port_connections_count: IntCounter, + /// Number of `Get::Trie` queries received. + pub(super) binary_port_get_trie_count: IntCounter, registry: Registry, } @@ -78,12 +83,18 @@ impl Metrics { BINARY_PORT_CONNECTIONS_COUNT_HELP.to_string(), )?; + let binary_port_get_trie_count = IntCounter::new( + BINARY_PORT_TRIE_COUNT_NAME.to_string(), + BINARY_PORT_TRIE_COUNT_HELP.to_string(), + )?; + registry.register(Box::new(binary_port_try_accept_transaction_count.clone()))?; registry.register(Box::new(binary_port_try_speculative_exec_count.clone()))?; registry.register(Box::new(binary_port_get_record_count.clone()))?; registry.register(Box::new(binary_port_get_info_count.clone()))?; registry.register(Box::new(binary_port_get_state_count.clone()))?; registry.register(Box::new(binary_port_connections_count.clone()))?; + registry.register(Box::new(binary_port_get_trie_count.clone()))?; Ok(Metrics { binary_port_try_accept_transaction_count, @@ -92,6 +103,7 @@ impl Metrics { binary_port_get_info_count, binary_port_get_state_count, binary_port_connections_count, + binary_port_get_trie_count, registry: registry.clone(), }) } diff --git a/node/src/components/binary_port/tests.rs b/node/src/components/binary_port/tests.rs index f55c45d2a1..000254fa68 100644 --- a/node/src/components/binary_port/tests.rs +++ b/node/src/components/binary_port/tests.rs @@ -4,7 +4,9 @@ use derive_more::From; use rand::Rng; use serde::Serialize; -use casper_binary_port::{BinaryRequest, BinaryResponse, GetRequest, GlobalStateRequest}; +use casper_binary_port::{ + BinaryRequest, BinaryResponse, GetRequest, GlobalStateEntityQualifier, GlobalStateRequest, +}; use casper_types::{ BlockHeader, Digest, GlobalStateIdentifier, KeyTag, PublicKey, Timestamp, Transaction, @@ -379,16 +381,18 @@ impl ReactorEvent for Event { fn all_values_request() -> BinaryRequest { let state_identifier = GlobalStateIdentifier::StateRootHash(Digest::hash([1u8; 32])); - BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::AllItems { - state_identifier: Some(state_identifier), - key_tag: KeyTag::Account, - }))) + BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(state_identifier), + GlobalStateEntityQualifier::AllItems { + key_tag: KeyTag::Account, + }, + )))) } fn trie_request() -> BinaryRequest { - BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::Trie { + BinaryRequest::Get(GetRequest::Trie { trie_key: Digest::hash([1u8; 32]), - }))) + }) } fn try_speculative_exec_request(rng: &mut TestRng) -> BinaryRequest { diff --git a/node/src/reactor/main_reactor/tests/binary_port.rs b/node/src/reactor/main_reactor/tests/binary_port.rs index 234ae65753..03f646afbc 100644 --- a/node/src/reactor/main_reactor/tests/binary_port.rs +++ b/node/src/reactor/main_reactor/tests/binary_port.rs @@ -11,10 +11,10 @@ use casper_binary_port::{ BinaryMessageCodec, BinaryRequest, BinaryRequestHeader, BinaryResponse, BinaryResponseAndRequest, ConsensusStatus, ConsensusValidatorChanges, ContractInformation, DictionaryItemIdentifier, DictionaryQueryResult, EntityIdentifier, EraIdentifier, ErrorCode, - GetRequest, GetTrieFullResult, GlobalStateQueryResult, GlobalStateRequest, InformationRequest, - InformationRequestTag, KeyPrefix, LastProgress, NetworkName, NodeStatus, PackageIdentifier, - PurseIdentifier, ReactorStateName, RecordId, ResponseType, RewardResponse, Uptime, - ValueWithProof, + GetRequest, GetTrieFullResult, GlobalStateEntityQualifier, GlobalStateQueryResult, + GlobalStateRequest, InformationRequest, InformationRequestTag, KeyPrefix, LastProgress, + NetworkName, NodeStatus, PackageIdentifier, PurseIdentifier, ReactorStateName, RecordId, + ResponseType, RewardResponse, Uptime, ValueWithProof, }; use casper_storage::global_state::state::CommitProvider; use casper_types::{ @@ -837,11 +837,13 @@ fn get_block_transfers(expected: BlockHeader) -> TestCase { fn get_era_summary(state_root_hash: Digest) -> TestCase { TestCase { name: "get_era_summary", - request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::Item { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), - base_key: Key::EraSummary, - path: vec![], - }))), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::Item { + base_key: Key::EraSummary, + path: vec![], + }, + )))), asserter: Box::new(|response| { assert_response::( response, @@ -858,10 +860,12 @@ fn get_era_summary(state_root_hash: Digest) -> TestCase { fn get_all_bids(state_root_hash: Digest) -> TestCase { TestCase { name: "get_all_bids", - request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::AllItems { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), - key_tag: KeyTag::Bid, - }))), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::AllItems { + key_tag: KeyTag::Bid, + }, + )))), asserter: Box::new(|response| { assert_response::, _>( response, @@ -875,9 +879,7 @@ fn get_all_bids(state_root_hash: Digest) -> TestCase { fn get_trie(digest: Digest) -> TestCase { TestCase { name: "get_trie", - request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::Trie { - trie_key: digest, - }))), + request: BinaryRequest::Get(GetRequest::Trie { trie_key: digest }), asserter: Box::new(|response| { assert_response::( response, @@ -891,12 +893,12 @@ fn get_trie(digest: Digest) -> TestCase { fn get_dictionary_item_by_addr(state_root_hash: Digest, addr: DictionaryAddr) -> TestCase { TestCase { name: "get_dictionary_item_by_addr", - request: BinaryRequest::Get(GetRequest::State(Box::new( - GlobalStateRequest::DictionaryItem { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::DictionaryItem { identifier: DictionaryItemIdentifier::DictionaryItem(addr), }, - ))), + )))), asserter: Box::new(move |response| { assert_response::( response, @@ -919,15 +921,15 @@ fn get_dictionary_item_by_seed_uref( ) -> TestCase { TestCase { name: "get_dictionary_item_by_seed_uref", - request: BinaryRequest::Get(GetRequest::State(Box::new( - GlobalStateRequest::DictionaryItem { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::DictionaryItem { identifier: DictionaryItemIdentifier::URef { seed_uref, dictionary_item_key: dictionary_item_key.clone(), }, }, - ))), + )))), asserter: Box::new(move |response| { assert_response::( response, @@ -952,16 +954,16 @@ fn get_dictionary_item_by_legacy_named_key( ) -> TestCase { TestCase { name: "get_dictionary_item_by_legacy_named_key", - request: BinaryRequest::Get(GetRequest::State(Box::new( - GlobalStateRequest::DictionaryItem { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::DictionaryItem { identifier: DictionaryItemIdentifier::AccountNamedKey { hash, dictionary_name, dictionary_item_key, }, }, - ))), + )))), asserter: Box::new(|response| { assert_response::( response, @@ -980,16 +982,16 @@ fn get_dictionary_item_by_named_key( ) -> TestCase { TestCase { name: "get_dictionary_item_by_named_key", - request: BinaryRequest::Get(GetRequest::State(Box::new( - GlobalStateRequest::DictionaryItem { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::DictionaryItem { identifier: DictionaryItemIdentifier::EntityNamedKey { addr, dictionary_name, dictionary_item_key, }, }, - ))), + )))), asserter: Box::new(|response| { assert_response::( response, @@ -1003,10 +1005,12 @@ fn get_dictionary_item_by_named_key( fn get_balance(state_root_hash: Digest, account_hash: AccountHash) -> TestCase { TestCase { name: "get_balance", - request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::Balance { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), - purse_identifier: PurseIdentifier::Account(account_hash), - }))), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::Balance { + purse_identifier: PurseIdentifier::Account(account_hash), + }, + )))), asserter: Box::new(|response| { assert_response::( response, @@ -1020,10 +1024,12 @@ fn get_balance(state_root_hash: Digest, account_hash: AccountHash) -> TestCase { fn get_balance_account_not_found(state_root_hash: Digest) -> TestCase { TestCase { name: "get_balance_account_not_found", - request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::Balance { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), - purse_identifier: PurseIdentifier::Account(AccountHash([9; 32])), - }))), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::Balance { + purse_identifier: PurseIdentifier::Account(AccountHash([9; 32])), + }, + )))), asserter: Box::new(|response| response.error_code() == ErrorCode::PurseNotFound as u16), } } @@ -1031,10 +1037,12 @@ fn get_balance_account_not_found(state_root_hash: Digest) -> TestCase { fn get_balance_purse_uref_not_found(state_root_hash: Digest) -> TestCase { TestCase { name: "get_balance_purse_uref_not_found", - request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::Balance { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), - purse_identifier: PurseIdentifier::Purse(URef::new([9; 32], Default::default())), - }))), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::Balance { + purse_identifier: PurseIdentifier::Purse(URef::new([9; 32], Default::default())), + }, + )))), asserter: Box::new(|response| response.error_code() == ErrorCode::PurseNotFound as u16), } } @@ -1042,12 +1050,12 @@ fn get_balance_purse_uref_not_found(state_root_hash: Digest) -> TestCase { fn get_named_keys_by_prefix(state_root_hash: Digest, entity_addr: EntityAddr) -> TestCase { TestCase { name: "get_named_keys_by_prefix", - request: BinaryRequest::Get(GetRequest::State(Box::new( - GlobalStateRequest::ItemsByPrefix { - state_identifier: Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + request: BinaryRequest::Get(GetRequest::State(Box::new(GlobalStateRequest::new( + Some(GlobalStateIdentifier::StateRootHash(state_root_hash)), + GlobalStateEntityQualifier::ItemsByPrefix { key_prefix: KeyPrefix::NamedKeysByEntity(entity_addr), }, - ))), + )))), asserter: Box::new(|response| { assert_response::, _>( response,