From 10ae2a44615faa0a8e93cfc629245c4f92aa8d51 Mon Sep 17 00:00:00 2001 From: Ed Hastings Date: Sat, 10 Feb 2024 15:35:26 -0800 Subject: [PATCH] adding AddressableEntity to data_provider --- .../test_support/src/wasm_test_builder.rs | 2 +- .../components/block_synchronizer/tests.rs | 6 +- node/src/components/contract_runtime.rs | 36 ++-- .../components/contract_runtime/metrics.rs | 10 ++ .../components/contract_runtime/operations.rs | 169 +----------------- node/src/components/transaction_acceptor.rs | 32 ++-- .../components/transaction_acceptor/event.rs | 2 +- .../components/transaction_acceptor/tests.rs | 16 +- node/src/effect.rs | 11 +- node/src/effect/requests.rs | 13 +- node/src/reactor/main_reactor/tests.rs | 2 +- storage/src/data_access_layer.rs | 2 + .../data_access_layer/addressable_entity.rs | 52 ++++++ .../execution_results_checksum.rs | 9 - storage/src/data_access_layer/get_bids.rs | 2 +- storage/src/global_state/state/mod.rs | 113 +++++++++++- 16 files changed, 242 insertions(+), 235 deletions(-) create mode 100644 storage/src/data_access_layer/addressable_entity.rs diff --git a/execution_engine_testing/test_support/src/wasm_test_builder.rs b/execution_engine_testing/test_support/src/wasm_test_builder.rs index 9f78fca2c0..df45c4cc5b 100644 --- a/execution_engine_testing/test_support/src/wasm_test_builder.rs +++ b/execution_engine_testing/test_support/src/wasm_test_builder.rs @@ -1344,7 +1344,7 @@ where let get_bids_result = self.engine_state.get_bids(get_bids_request); - get_bids_result.into_success().unwrap() + get_bids_result.into_option().unwrap() } /// Returns named keys for an account entity by its account hash. diff --git a/node/src/components/block_synchronizer/tests.rs b/node/src/components/block_synchronizer/tests.rs index d90d05d3ba..11d304a96d 100644 --- a/node/src/components/block_synchronizer/tests.rs +++ b/node/src/components/block_synchronizer/tests.rs @@ -13,8 +13,10 @@ use derive_more::From; use num_rational::Ratio; use rand::{seq::IteratorRandom, Rng}; -use casper_storage::data_access_layer::ExecutionResultsChecksumResult; -use casper_storage::global_state::trie::merkle_proof::TrieMerkleProof; +use casper_storage::{ + data_access_layer::ExecutionResultsChecksumResult, + global_state::trie::merkle_proof::TrieMerkleProof, +}; use casper_types::{ testing::TestRng, AccessRights, BlockV2, CLValue, Chainspec, Deploy, EraId, Key, LegacyRequiredFinality, ProtocolVersion, PublicKey, SecretKey, StoredValue, TestBlockBuilder, diff --git a/node/src/components/contract_runtime.rs b/node/src/components/contract_runtime.rs index b600649096..449ee8a37c 100644 --- a/node/src/components/contract_runtime.rs +++ b/node/src/components/contract_runtime.rs @@ -39,7 +39,8 @@ use casper_storage::data_access_layer::{BidsRequest, BidsResult}; use casper_storage::{ data_access_layer::{ - BlockStore, DataAccessLayer, ExecutionResultsChecksumRequest, QueryRequest, QueryResult, + AddressableEntityRequest, BlockStore, DataAccessLayer, ExecutionResultsChecksumRequest, + QueryRequest, QueryResult, }, global_state::{ state::{lmdb::LmdbGlobalState, StateProvider}, @@ -899,6 +900,26 @@ impl ContractRuntime { } .ignore() } + ContractRuntimeRequest::GetAddressableEntity { + state_root_hash, + key, + responder, + } => { + trace!(?state_root_hash, "get addressable entity"); + let metrics = Arc::clone(&self.metrics); + let data_access_layer = Arc::clone(&self.data_access_layer); + async move { + let start = Instant::now(); + let request = AddressableEntityRequest::new(state_root_hash, key); + let result = data_access_layer.addressable_entity(request); + metrics + .addressable_entity + .observe(start.elapsed().as_secs_f64()); + trace!(?result, "get addressable entity"); + responder.respond(result).await + } + .ignore() + } ContractRuntimeRequest::GetTrie { trie_or_chunk_id, responder, @@ -1028,19 +1049,6 @@ impl ContractRuntime { .set(self.exec_queue.len().try_into().unwrap_or(i64::MIN)); effects } - ContractRuntimeRequest::GetAddressableEntity { - state_root_hash, - key, - responder, - } => { - let engine_state = Arc::clone(&self.engine_state); - async move { - let result = - operations::get_addressable_entity(&engine_state, state_root_hash, key); - responder.respond(result).await - } - .ignore() - } ContractRuntimeRequest::SpeculativelyExecute { execution_prestate, transaction, diff --git a/node/src/components/contract_runtime/metrics.rs b/node/src/components/contract_runtime/metrics.rs index 73c2fc848e..71a07c5516 100644 --- a/node/src/components/contract_runtime/metrics.rs +++ b/node/src/components/contract_runtime/metrics.rs @@ -49,6 +49,9 @@ const GET_BIDS_HELP: &str = "time in seconds to get bids from global state"; const EXECUTION_RESULTS_CHECKSUM_NAME: &str = "contract_runtime_execution_results_checksum"; const EXECUTION_RESULTS_CHECKSUM_HELP: &str = "contract_runtime_execution_results_checksum"; +const ADDRESSABLE_ENTITY_NAME: &str = "contract_runtime_addressable_entity"; +const ADDRESSABLE_ENTITY_HELP: &str = "contract_runtime_addressable_entity"; + const PUT_TRIE_NAME: &str = "contract_runtime_put_trie"; const PUT_TRIE_HELP: &str = "time in seconds to put a trie"; @@ -79,6 +82,7 @@ pub struct Metrics { pub(super) get_era_validators: Histogram, pub(super) get_bids: Histogram, pub(super) execution_results_checksum: Histogram, + pub(super) addressable_entity: Histogram, pub(super) put_trie: Histogram, pub(super) get_trie: Histogram, pub(super) exec_block: Histogram, @@ -175,6 +179,12 @@ impl Metrics { EXECUTION_RESULTS_CHECKSUM_HELP, common_buckets.clone(), )?, + addressable_entity: utils::register_histogram_metric( + registry, + ADDRESSABLE_ENTITY_NAME, + ADDRESSABLE_ENTITY_HELP, + common_buckets.clone(), + )?, get_trie: utils::register_histogram_metric( registry, GET_TRIE_NAME, diff --git a/node/src/components/contract_runtime/operations.rs b/node/src/components/contract_runtime/operations.rs index b1ee4225f4..4d8f7a275b 100644 --- a/node/src/components/contract_runtime/operations.rs +++ b/node/src/components/contract_runtime/operations.rs @@ -11,18 +11,15 @@ use casper_execution_engine::engine_state::{ PruneResult, StepError, StepRequest, StepSuccess, }; use casper_storage::{ - data_access_layer::{ - DataAccessLayer, EraValidatorsRequest, EraValidatorsResult, QueryRequest, QueryResult, - }, + data_access_layer::{DataAccessLayer, EraValidatorsRequest, EraValidatorsResult}, global_state::state::{lmdb::LmdbGlobalState, CommitProvider, StateProvider}, }; use casper_types::{ - account::AccountHash, bytesrepr::{self, ToBytes, U32_SERIALIZED_LENGTH}, contract_messages::Messages, execution::{Effects, ExecutionResult, ExecutionResultV2, Transform, TransformKind}, - AddressableEntity, BlockV2, CLValue, ChecksumRegistry, DeployHash, Digest, EntityAddr, - EraEndV2, EraId, HashAddr, Key, ProtocolVersion, PublicKey, StoredValue, Transaction, U512, + BlockV2, CLValue, ChecksumRegistry, DeployHash, Digest, EraEndV2, EraId, Key, ProtocolVersion, + PublicKey, Transaction, U512, }; use crate::{ @@ -620,166 +617,6 @@ pub(crate) fn compute_execution_results_checksum<'a>( }) } -pub(super) fn get_addressable_entity( - engine_state: &EngineState, - state_root_hash: Digest, - key: Key, -) -> Option -where - S: StateProvider + CommitProvider, -{ - match key { - Key::AddressableEntity(entity_addr) => { - get_addressable_entity_under_entity_hash(engine_state, state_root_hash, entity_addr) - } - Key::Account(account_hash) => { - get_addressable_entity_under_account_hash(engine_state, state_root_hash, account_hash) - } - Key::Hash(contract_hash) => { - get_addressable_entity_under_contract_hash(engine_state, state_root_hash, contract_hash) - } - _ => { - warn!(%key, "expected a Key::AddressableEntity, Key::Account, Key::Hash"); - None - } - } -} - -fn get_addressable_entity_under_entity_hash( - engine_state: &EngineState, - state_root_hash: Digest, - entity_addr: EntityAddr, -) -> Option -where - S: StateProvider + CommitProvider, -{ - let key = Key::AddressableEntity(entity_addr); - let query_request = QueryRequest::new(state_root_hash, key, vec![]); - let value = match engine_state.run_query(query_request) { - QueryResult::RootNotFound => { - error!(%state_root_hash, "state root not found"); - return None; - } - QueryResult::ValueNotFound(msg) => { - debug!(%key, "expected to find addressable entity: {}", msg); - return None; - } - QueryResult::Failure(tce) => { - warn!(%tce, %key, "failed querying for addressable entity"); - return None; - } - QueryResult::Success { value, .. } => *value, - }; - match value { - StoredValue::AddressableEntity(addressable_entity) => Some(addressable_entity), - _ => { - debug!(type_name = %value.type_name(), %key, "expected an AddressableEntity"); - None - } - } -} - -fn get_addressable_entity_under_account_hash( - engine_state: &EngineState, - state_root_hash: Digest, - account_hash: AccountHash, -) -> Option -where - S: StateProvider + CommitProvider, -{ - let account_key = Key::Account(account_hash); - let query_request = QueryRequest::new(state_root_hash, account_key, vec![]); - let value = match engine_state.run_query(query_request) { - QueryResult::RootNotFound => { - error!(%state_root_hash, "state root not found"); - return None; - } - QueryResult::ValueNotFound(msg) => { - debug!(%account_key, "expected to find account: {}", msg); - return None; - } - QueryResult::Failure(tce) => { - warn!(%tce, %account_key, "failed querying for account"); - return None; - } - QueryResult::Success { value, .. } => *value, - }; - match value { - StoredValue::CLValue(cl_value) => match cl_value.into_t::() { - Ok(Key::AddressableEntity(entity_addr)) => { - get_addressable_entity_under_entity_hash(engine_state, state_root_hash, entity_addr) - } - Ok(invalid_key) => { - warn!( - %account_key, - %invalid_key, - "expected a Key::AddressableEntity to be stored under account hash" - ); - None - } - Err(error) => { - warn!(%account_key, %error, "expected a Key to be stored under account hash"); - None - } - }, - StoredValue::Account(account) => Some(AddressableEntity::from(account)), - _ => { - warn!( - type_name = %value.type_name(), - %account_key, - "expected a CLValue or Account to be stored under account hash" - ); - None - } - } -} - -fn get_addressable_entity_under_contract_hash( - engine_state: &EngineState, - state_root_hash: Digest, - contract_hash: HashAddr, -) -> Option -where - S: StateProvider + CommitProvider, -{ - // First try with an `AddressableEntityHash` derived from the contract hash. - get_addressable_entity_under_entity_hash( - engine_state, - state_root_hash, - EntityAddr::SmartContract(contract_hash), - ) - .or_else(|| { - // Didn't work; the contract was either not migrated yet or the `AddressableEntity` - // record was not available at this state root hash. Try to query with a - // contract key next. - let contract_key = Key::Hash(contract_hash); - let query_request = QueryRequest::new(state_root_hash, contract_key, vec![]); - let value = match engine_state.run_query(query_request) { - QueryResult::RootNotFound => { - error!(%state_root_hash, "state root not found"); - return None; - } - QueryResult::ValueNotFound(msg) => { - debug!(%contract_key, "expected to find contract: {}", msg); - return None; - } - QueryResult::Failure(tce) => { - warn!(%tce, %contract_key, "failed querying for contract"); - return None; - } - QueryResult::Success { value, .. } => *value, - }; - - match value { - StoredValue::Contract(contract) => Some(contract.into()), - _ => { - debug!(type_name = %value.type_name(), ?contract_hash, "expected a Contract"); - None - } - } - }) -} - #[cfg(test)] mod tests { use super::*; diff --git a/node/src/components/transaction_acceptor.rs b/node/src/components/transaction_acceptor.rs index 27057f0088..a7282a1eec 100644 --- a/node/src/components/transaction_acceptor.rs +++ b/node/src/components/transaction_acceptor.rs @@ -167,9 +167,9 @@ impl TransactionAcceptor { let block_header = block_header.clone(); return effect_builder .get_addressable_entity(*block_header.state_root_hash(), account_key) - .event(move |maybe_entity| Event::GetAddressableEntityResult { + .event(move |result| Event::GetAddressableEntityResult { event_metadata, - maybe_entity, + maybe_entity: result.into_option(), block_header, }); } @@ -208,10 +208,10 @@ impl TransactionAcceptor { }; effect_builder .get_addressable_entity(*block_header.state_root_hash(), account_key) - .event(move |maybe_entity| Event::GetAddressableEntityResult { + .event(move |result| Event::GetAddressableEntityResult { event_metadata, + maybe_entity: result.into_option(), block_header, - maybe_entity, }) } else { self.verify_payment(effect_builder, event_metadata, block_header) @@ -331,12 +331,12 @@ impl TransactionAcceptor { let query_key = Key::from(ContractHash::new(contract_hash.value())); effect_builder .get_addressable_entity(*block_header.state_root_hash(), query_key) - .event(move |maybe_contract| Event::GetContractResult { + .event(move |result| Event::GetContractResult { event_metadata, block_header, is_payment: true, contract_hash, - maybe_contract, + maybe_entity: result.into_option(), }) } ExecutableDeployItemIdentifier::Package( @@ -438,12 +438,12 @@ impl TransactionAcceptor { let key = Key::from(ContractHash::new(entity_hash.value())); effect_builder .get_addressable_entity(*block_header.state_root_hash(), key) - .event(move |maybe_contract| Event::GetContractResult { + .event(move |result| Event::GetContractResult { event_metadata, block_header, is_payment: false, contract_hash: entity_hash, - maybe_contract, + maybe_entity: result.into_option(), }) } ExecutableDeployItemIdentifier::Package( @@ -515,12 +515,12 @@ impl TransactionAcceptor { let key = Key::Hash(entity_addr.value()); effect_builder .get_addressable_entity(*block_header.state_root_hash(), key) - .event(move |maybe_contract| Event::GetContractResult { + .event(move |result| Event::GetContractResult { event_metadata, block_header, is_payment: false, contract_hash: AddressableEntityHash::new(entity_addr.value()), - maybe_contract, + maybe_entity: result.into_option(), }) } NextStep::GetPackage(package_addr, maybe_package_version) => { @@ -551,7 +551,7 @@ impl TransactionAcceptor { contract_hash: AddressableEntityHash, maybe_contract: Option, ) -> Effects { - let contract = match maybe_contract { + let entity = match maybe_contract { Some(contract) => contract, None => { let error = Error::parameter_failure( @@ -581,7 +581,7 @@ impl TransactionAcceptor { }; if let Some(entry_point_name) = maybe_entry_point_name { - if !contract.entry_points().has_entry_point(entry_point_name) { + if !entity.entry_points().has_entry_point(entry_point_name) { let error = Error::parameter_failure( &block_header, ParameterFailure::NoSuchEntryPoint { @@ -639,12 +639,12 @@ impl TransactionAcceptor { let key = Key::from(ContractHash::new(contract_hash.value())); effect_builder .get_addressable_entity(*block_header.state_root_hash(), key) - .event(move |maybe_contract| Event::GetContractResult { + .event(move |result| Event::GetContractResult { event_metadata, block_header, is_payment, contract_hash, - maybe_contract, + maybe_entity: result.into_option(), }) } None => { @@ -845,14 +845,14 @@ impl Component for TransactionAcceptor { block_header, is_payment, contract_hash, - maybe_contract, + maybe_entity, } => self.handle_get_contract_result( effect_builder, event_metadata, block_header, is_payment, contract_hash, - maybe_contract, + maybe_entity, ), Event::GetPackageResult { event_metadata, diff --git a/node/src/components/transaction_acceptor/event.rs b/node/src/components/transaction_acceptor/event.rs index 3805c33091..a9102325ac 100644 --- a/node/src/components/transaction_acceptor/event.rs +++ b/node/src/components/transaction_acceptor/event.rs @@ -80,7 +80,7 @@ pub(crate) enum Event { block_header: Box, is_payment: bool, contract_hash: AddressableEntityHash, - maybe_contract: Option, + maybe_entity: Option, }, /// The result of querying global state for a `Package` to verify the executable logic. GetPackageResult { diff --git a/node/src/components/transaction_acceptor/tests.rs b/node/src/components/transaction_acceptor/tests.rs index 20070ec9c1..1e25e869c3 100644 --- a/node/src/components/transaction_acceptor/tests.rs +++ b/node/src/components/transaction_acceptor/tests.rs @@ -22,7 +22,7 @@ use tokio::time; use casper_execution_engine::engine_state::MAX_PAYMENT_AMOUNT; use casper_storage::{ - data_access_layer::{BalanceResult, QueryResult}, + data_access_layer::{AddressableEntityResult, BalanceResult, QueryResult}, global_state::trie::merkle_proof::TrieMerkleProof, }; use casper_types::{ @@ -808,10 +808,12 @@ impl reactor::Reactor for Reactor { self.test_scenario, TestScenario::FromPeerMissingAccount(_) ) { - None + AddressableEntityResult::ValueNotFound("missing account".to_string()) } else if let Key::Account(account_hash) = key { let account = create_account(account_hash, self.test_scenario); - Some(AddressableEntity::from(account)) + AddressableEntityResult::Success { + entity: AddressableEntity::from(account), + } } else if let Key::Hash(..) = key { match self.test_scenario { TestScenario::FromPeerCustomPaymentContract( @@ -827,7 +829,9 @@ impl reactor::Reactor for Reactor { | TestScenario::FromClientSessionContract( _, ContractScenario::MissingContractAtHash, - ) => None, + ) => AddressableEntityResult::ValueNotFound( + "missing contract".to_string(), + ), TestScenario::FromPeerCustomPaymentContract( ContractScenario::MissingEntryPoint, ) @@ -843,7 +847,9 @@ impl reactor::Reactor for Reactor { ContractScenario::MissingEntryPoint, ) => { let contract = Contract::default(); - Some(AddressableEntity::from(contract)) + AddressableEntityResult::Success { + entity: AddressableEntity::from(contract), + } } _ => panic!("unexpected GetAddressableEntity: {:?}", key), } diff --git a/node/src/effect.rs b/node/src/effect.rs index 7715693326..966ebc2e31 100644 --- a/node/src/effect.rs +++ b/node/src/effect.rs @@ -124,16 +124,17 @@ use casper_storage::{ }; use casper_storage::data_access_layer::{ - EraValidatorsRequest, EraValidatorsResult, ExecutionResultsChecksumResult, + AddressableEntityResult, EraValidatorsRequest, EraValidatorsResult, + ExecutionResultsChecksumResult, }; use casper_types::{ bytesrepr::Bytes, contract_messages::Messages, execution::{Effects as ExecutionEffects, ExecutionResult, ExecutionResultV2}, package::Package, - AddressableEntity, Block, BlockHash, BlockHeader, BlockSignatures, BlockV2, ChainspecRawBytes, - DeployHash, Digest, EraId, FinalitySignature, FinalitySignatureId, Key, PublicKey, TimeDiff, - Timestamp, Transaction, TransactionHash, TransactionHeader, TransactionId, Transfer, U512, + Block, BlockHash, BlockHeader, BlockSignatures, BlockV2, ChainspecRawBytes, DeployHash, Digest, + EraId, FinalitySignature, FinalitySignatureId, Key, PublicKey, TimeDiff, Timestamp, + Transaction, TransactionHash, TransactionHeader, TransactionId, Transfer, U512, }; use crate::{ @@ -1968,7 +1969,7 @@ impl EffectBuilder { self, state_root_hash: Digest, key: Key, - ) -> Option + ) -> AddressableEntityResult where REv: From, { diff --git a/node/src/effect/requests.rs b/node/src/effect/requests.rs index 7919569fa6..85eacc0e2a 100644 --- a/node/src/effect/requests.rs +++ b/node/src/effect/requests.rs @@ -20,13 +20,12 @@ use casper_execution_engine::engine_state::{self}; use casper_storage::{ data_access_layer::{ get_bids::{BidsRequest, BidsResult}, - BalanceRequest, BalanceResult, EraValidatorsRequest, EraValidatorsResult, - ExecutionResultsChecksumResult, QueryRequest, QueryResult, + AddressableEntityResult, BalanceRequest, BalanceResult, EraValidatorsRequest, + EraValidatorsResult, ExecutionResultsChecksumResult, QueryRequest, QueryResult, }, global_state::trie::TrieRaw, }; use casper_types::{ - addressable_entity::AddressableEntity, bytesrepr::Bytes, contract_messages::Messages, execution::{ExecutionResult, ExecutionResultV2}, @@ -935,12 +934,14 @@ pub(crate) enum ContractRuntimeRequest { state_root_hash: Digest, responder: Responder, }, - /// Returns an `AddressableEntity` if found under the given key. If a legacy `Account` exists - /// under the given key, it will be converted to an `AddressableEntity` and returned. + /// Returns an `AddressableEntity` if found under the given key. If a legacy `Account` + /// or contract exists under the given key, it will be migrated to an `AddressableEntity` + /// and returned. However, global state is not altered and the migrated record does not + /// actually exist. GetAddressableEntity { state_root_hash: Digest, key: Key, - responder: Responder>, + responder: Responder, }, /// Get a trie or chunk by its ID. GetTrie { diff --git a/node/src/reactor/main_reactor/tests.rs b/node/src/reactor/main_reactor/tests.rs index 10a17d5545..59fe424f59 100644 --- a/node/src/reactor/main_reactor/tests.rs +++ b/node/src/reactor/main_reactor/tests.rs @@ -966,7 +966,7 @@ async fn run_equivocator_network() { let era_count = 4; - let timeout = ONE_MIN * era_count as u32; + let timeout = ONE_MIN * (era_count + 1) as u32; info!("Waiting for {} eras to end.", era_count); fixture .run_until_stored_switch_block_header(EraId::new(era_count - 1), timeout) diff --git a/storage/src/data_access_layer.rs b/storage/src/data_access_layer.rs index c3ab083ac0..743e1d549e 100644 --- a/storage/src/data_access_layer.rs +++ b/storage/src/data_access_layer.rs @@ -9,12 +9,14 @@ use crate::global_state::{ use crate::tracking_copy::TrackingCopy; +mod addressable_entity; pub mod balance; pub mod era_validators; mod execution_results_checksum; pub mod get_bids; pub mod query; +pub use addressable_entity::{AddressableEntityRequest, AddressableEntityResult}; pub use balance::{BalanceRequest, BalanceResult}; pub use era_validators::{EraValidatorsRequest, EraValidatorsResult}; pub use execution_results_checksum::{ diff --git a/storage/src/data_access_layer/addressable_entity.rs b/storage/src/data_access_layer/addressable_entity.rs new file mode 100644 index 0000000000..24147882f0 --- /dev/null +++ b/storage/src/data_access_layer/addressable_entity.rs @@ -0,0 +1,52 @@ +use crate::tracking_copy::TrackingCopyError; +use casper_types::{AddressableEntity, Digest, Key}; + +/// Represents a request to obtain an addressable entity. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AddressableEntityRequest { + state_hash: Digest, + key: Key, +} + +impl AddressableEntityRequest { + /// Creates new request. + pub fn new(state_hash: Digest, key: Key) -> Self { + AddressableEntityRequest { state_hash, key } + } + + /// Returns state root hash. + pub fn state_hash(&self) -> Digest { + self.state_hash + } + + /// Returns key. + pub fn key(&self) -> Key { + self.key + } +} + +/// Represents a result of a `addressable_entity` request. +#[derive(Debug)] +pub enum AddressableEntityResult { + /// Invalid state root hash. + RootNotFound, + /// Value not found. + ValueNotFound(String), + /// Contains an addressable entity from global state. + Success { + /// An addressable entity. + entity: AddressableEntity, + }, + Failure(TrackingCopyError), +} + +impl AddressableEntityResult { + /// Returns wrapped addressable entity if this represents a successful query result. + pub fn into_option(self) -> Option { + if let Self::Success { entity } = self { + Some(entity) + } else { + None + } + } +} diff --git a/storage/src/data_access_layer/execution_results_checksum.rs b/storage/src/data_access_layer/execution_results_checksum.rs index 4d7f756bb8..a206dd6099 100644 --- a/storage/src/data_access_layer/execution_results_checksum.rs +++ b/storage/src/data_access_layer/execution_results_checksum.rs @@ -40,15 +40,6 @@ pub enum ExecutionResultsChecksumResult { } impl ExecutionResultsChecksumResult { - /// Returns checksum if this represents a successful query result. - pub fn into_success(self) -> Option { - if let Self::Success { checksum } = self { - Some(checksum) - } else { - None - } - } - /// Returns a Result matching the original api for this functionality. pub fn as_legacy(&self) -> Result, TrackingCopyError> { match self { diff --git a/storage/src/data_access_layer/get_bids.rs b/storage/src/data_access_layer/get_bids.rs index b9d72f239b..befeebd4ae 100644 --- a/storage/src/data_access_layer/get_bids.rs +++ b/storage/src/data_access_layer/get_bids.rs @@ -36,7 +36,7 @@ pub enum BidsResult { impl BidsResult { /// Returns wrapped [`Vec`] if this represents a successful query result. - pub fn into_success(self) -> Option> { + pub fn into_option(self) -> Option> { if let Self::Success { bids } = self { Some(bids) } else { diff --git a/storage/src/global_state/state/mod.rs b/storage/src/global_state/state/mod.rs index bce323058e..40323f4ad6 100644 --- a/storage/src/global_state/state/mod.rs +++ b/storage/src/global_state/state/mod.rs @@ -15,7 +15,7 @@ use casper_types::{ bytesrepr, execution::{Effects, Transform, TransformError, TransformInstruction, TransformKind}, system::{auction::SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY, AUCTION}, - Digest, Key, KeyTag, StoredValue, + AddressableEntity, Digest, EntityAddr, Key, KeyTag, StoredValue, }; #[cfg(test)] @@ -23,9 +23,10 @@ pub use self::lmdb::make_temporary_global_state; use crate::{ data_access_layer::{ - era_validators::EraValidatorsResult, BalanceRequest, BalanceResult, BidsRequest, - BidsResult, EraValidatorsRequest, ExecutionResultsChecksumRequest, - ExecutionResultsChecksumResult, QueryRequest, QueryResult, EXECUTION_RESULTS_CHECKSUM_NAME, + era_validators::EraValidatorsResult, AddressableEntityRequest, AddressableEntityResult, + BalanceRequest, BalanceResult, BidsRequest, BidsResult, EraValidatorsRequest, + ExecutionResultsChecksumRequest, ExecutionResultsChecksumResult, QueryRequest, QueryResult, + EXECUTION_RESULTS_CHECKSUM_NAME, }, global_state::{ error::Error as GlobalStateError, @@ -96,8 +97,8 @@ pub trait StateProvider { /// Associated reader type for `StateProvider`. type Reader: StateReader; - /// Checkouts to the post state of a specific block. - fn checkout(&self, state_hash: Digest) -> Result, GlobalStateError>; + /// Returns an empty root hash. + fn empty_root(&self) -> Digest; /// Get a tracking copy. fn tracking_copy( @@ -105,6 +106,9 @@ pub trait StateProvider { state_hash: Digest, ) -> Result>, GlobalStateError>; + /// Checkouts a slice of initial state using root state hash. + fn checkout(&self, state_hash: Digest) -> Result, GlobalStateError>; + /// Query state. fn query(&self, request: QueryRequest) -> QueryResult { match self.tracking_copy(request.state_hash()) { @@ -255,8 +259,101 @@ pub trait StateProvider { } } - /// Returns an empty root hash. - fn empty_root(&self) -> Digest; + fn addressable_entity(&self, request: AddressableEntityRequest) -> AddressableEntityResult { + let key = request.key(); + let query_key = match key { + Key::Account(_) => { + let query_request = QueryRequest::new(request.state_hash(), key, vec![]); + match self.query(query_request) { + QueryResult::RootNotFound => return AddressableEntityResult::RootNotFound, + QueryResult::ValueNotFound(msg) => { + return AddressableEntityResult::ValueNotFound(msg) + } + QueryResult::Failure(err) => return AddressableEntityResult::Failure(err), + QueryResult::Success { value, .. } => { + if let StoredValue::Account(account) = *value { + // legacy account that has not been migrated + let entity = AddressableEntity::from(account); + return AddressableEntityResult::Success { entity }; + } + if let StoredValue::CLValue(cl_value) = &*value { + // the corresponding entity key should be under the account's key + match cl_value.clone().into_t::() { + Ok(entity_key @ Key::AddressableEntity(_)) => entity_key, + Ok(invalid_key) => { + warn!( + %key, + %invalid_key, + type_name = %value.type_name(), + "expected a Key::AddressableEntity to be stored under account hash" + ); + return AddressableEntityResult::Failure( + TrackingCopyError::UnexpectedStoredValueVariant, + ); + } + Err(error) => { + error!(%key, %error, "expected a CLValue::Key to be stored under account hash"); + return AddressableEntityResult::Failure( + TrackingCopyError::CLValue(error), + ); + } + }; + }; + warn!( + %key, + type_name = %value.type_name(), + "expected a CLValue::Key or Account to be stored under account hash" + ); + return AddressableEntityResult::Failure( + TrackingCopyError::UnexpectedStoredValueVariant, + ); + } + } + } + Key::Hash(contract_hash) => { + let query_request = QueryRequest::new(request.state_hash(), key, vec![]); + match self.query(query_request) { + QueryResult::RootNotFound => return AddressableEntityResult::RootNotFound, + QueryResult::ValueNotFound(msg) => { + return AddressableEntityResult::ValueNotFound(msg) + } + QueryResult::Failure(err) => return AddressableEntityResult::Failure(err), + QueryResult::Success { value, .. } => { + if let StoredValue::Contract(contract) = *value { + // legacy contract that has not been migrated + let entity = AddressableEntity::from(contract); + return AddressableEntityResult::Success { entity }; + } + Key::AddressableEntity(EntityAddr::SmartContract(contract_hash)) + } + } + } + Key::AddressableEntity(_) => key, + _ => { + return AddressableEntityResult::Failure(TrackingCopyError::UnexpectedKeyVariant( + key, + )) + } + }; + + let query_request = QueryRequest::new(request.state_hash(), query_key, vec![]); + match self.query(query_request) { + QueryResult::RootNotFound => AddressableEntityResult::RootNotFound, + QueryResult::ValueNotFound(msg) => AddressableEntityResult::ValueNotFound(msg), + QueryResult::Success { value, .. } => { + let entity = match value.as_addressable_entity() { + Some(entity) => entity.clone(), + None => { + return AddressableEntityResult::Failure( + TrackingCopyError::UnexpectedStoredValueVariant, + ) + } + }; + AddressableEntityResult::Success { entity } + } + QueryResult::Failure(err) => AddressableEntityResult::Failure(err), + } + } /// Reads a full `Trie` (never chunked) from the state if it is present fn get_trie_full(&self, trie_key: &Digest) -> Result, GlobalStateError>;