Skip to content

Commit

Permalink
Address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
jacek-casper committed May 3, 2024
1 parent f01ba23 commit 155b27f
Show file tree
Hide file tree
Showing 17 changed files with 251 additions and 94 deletions.
171 changes: 171 additions & 0 deletions binary_port/src/key_prefix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#[cfg(any(feature = "testing", test))]
use casper_types::testing::TestRng;
use casper_types::{
account::AccountHash,
bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
contract_messages::TopicNameHash,
system::{auction::BidAddrTag, mint::BalanceHoldAddrTag},
EntityAddr, KeyTag, URefAddr,
};
#[cfg(any(feature = "testing", test))]
use rand::Rng;

/// Key prefixes used for querying the global state.
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
pub enum KeyPrefix {
/// Retrieves all delegator bid addresses for a given validator.
DelegatorBidAddrsByValidator(AccountHash),
/// Retrieves all messages for a given entity.
MessagesByEntity(EntityAddr),
/// Retrieves all messages for a given entity and topic.
MessagesByEntityAndTopic(EntityAddr, TopicNameHash),
/// Retrieves all named keys for a given entity.
NamedKeysByEntity(EntityAddr),
/// Retrieves all gas balance holds for a given purse.
GasBalanceHoldsByPurse(URefAddr),
/// Retrieves all processing balance holds for a given purse.
ProcessingBalanceHoldsByPurse(URefAddr),
}

impl KeyPrefix {
/// Returns a random `KeyPrefix`.
#[cfg(any(feature = "testing", test))]
pub fn random(rng: &mut TestRng) -> Self {
match rng.gen_range(0..6) {
0 => KeyPrefix::DelegatorBidAddrsByValidator(rng.gen()),
1 => KeyPrefix::MessagesByEntity(rng.gen()),
2 => KeyPrefix::MessagesByEntityAndTopic(rng.gen(), rng.gen()),
3 => KeyPrefix::NamedKeysByEntity(rng.gen()),
4 => KeyPrefix::GasBalanceHoldsByPurse(rng.gen()),
5 => KeyPrefix::ProcessingBalanceHoldsByPurse(rng.gen()),
_ => unreachable!(),
}
}
}

impl ToBytes for KeyPrefix {
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
let mut result = bytesrepr::unchecked_allocate_buffer(self);
self.write_bytes(&mut result)?;
Ok(result)
}

fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
match self {
KeyPrefix::DelegatorBidAddrsByValidator(validator) => {
writer.push(KeyTag::BidAddr as u8);
writer.push(BidAddrTag::Delegator as u8);
validator.write_bytes(writer)?;
}
KeyPrefix::MessagesByEntity(entity) => {
writer.push(KeyTag::Message as u8);
entity.write_bytes(writer)?;
}
KeyPrefix::MessagesByEntityAndTopic(entity, topic) => {
writer.push(KeyTag::Message as u8);
entity.write_bytes(writer)?;
topic.write_bytes(writer)?;
}
KeyPrefix::NamedKeysByEntity(entity) => {
writer.push(KeyTag::NamedKey as u8);
entity.write_bytes(writer)?;
}
KeyPrefix::GasBalanceHoldsByPurse(uref) => {
writer.push(KeyTag::BalanceHold as u8);
writer.push(BalanceHoldAddrTag::Gas as u8);
uref.write_bytes(writer)?;
}
KeyPrefix::ProcessingBalanceHoldsByPurse(uref) => {
writer.push(KeyTag::BalanceHold as u8);
writer.push(BalanceHoldAddrTag::Processing as u8);
uref.write_bytes(writer)?;
}
}
Ok(())
}

fn serialized_length(&self) -> usize {
U8_SERIALIZED_LENGTH
+ match self {
KeyPrefix::DelegatorBidAddrsByValidator(validator) => {
U8_SERIALIZED_LENGTH + validator.serialized_length()
}
KeyPrefix::MessagesByEntity(entity) => entity.serialized_length(),
KeyPrefix::MessagesByEntityAndTopic(entity, topic) => {
entity.serialized_length() + topic.serialized_length()
}
KeyPrefix::NamedKeysByEntity(entity) => entity.serialized_length(),
KeyPrefix::GasBalanceHoldsByPurse(uref) => {
U8_SERIALIZED_LENGTH + uref.serialized_length()
}
KeyPrefix::ProcessingBalanceHoldsByPurse(uref) => {
U8_SERIALIZED_LENGTH + uref.serialized_length()
}
}
}
}

impl FromBytes for KeyPrefix {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
let (tag, remainder) = u8::from_bytes(bytes)?;
let result = match tag {
tag if tag == KeyTag::BidAddr as u8 => {
let (bid_addr_tag, remainder) = u8::from_bytes(remainder)?;
match bid_addr_tag {
tag if tag == BidAddrTag::Delegator as u8 => {
let (validator, remainder) = AccountHash::from_bytes(remainder)?;
(
KeyPrefix::DelegatorBidAddrsByValidator(validator),
remainder,
)
}
_ => return Err(bytesrepr::Error::Formatting),
}
}
tag if tag == KeyTag::Message as u8 => {
let (entity, remainder) = EntityAddr::from_bytes(remainder)?;
if remainder.is_empty() {
(KeyPrefix::MessagesByEntity(entity), remainder)
} else {
let (topic, remainder) = TopicNameHash::from_bytes(remainder)?;
(
KeyPrefix::MessagesByEntityAndTopic(entity, topic),
remainder,
)
}
}
tag if tag == KeyTag::NamedKey as u8 => {
let (entity, remainder) = EntityAddr::from_bytes(remainder)?;
(KeyPrefix::NamedKeysByEntity(entity), remainder)
}
tag if tag == KeyTag::BalanceHold as u8 => {
let (balance_hold_addr_tag, remainder) = u8::from_bytes(remainder)?;
let (uref, remainder) = URefAddr::from_bytes(remainder)?;
match balance_hold_addr_tag {
tag if tag == BalanceHoldAddrTag::Gas as u8 => {
(KeyPrefix::GasBalanceHoldsByPurse(uref), remainder)
}
tag if tag == BalanceHoldAddrTag::Processing as u8 => {
(KeyPrefix::ProcessingBalanceHoldsByPurse(uref), remainder)
}
_ => return Err(bytesrepr::Error::Formatting),
}
}
_ => return Err(bytesrepr::Error::Formatting),
};
Ok(result)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn bytesrepr_roundtrip() {
let rng = &mut TestRng::new();

let key_prefix = KeyPrefix::random(rng);
bytesrepr::test_serialization_roundtrip(&key_prefix);
}
}
2 changes: 2 additions & 0 deletions binary_port/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod error_code;
mod get_request;
mod global_state_query_result;
mod information_request;
mod key_prefix;
mod minimal_block_info;
mod node_status;
mod payload_type;
Expand All @@ -33,6 +34,7 @@ pub use error_code::ErrorCode;
pub use get_request::GetRequest;
pub use global_state_query_result::GlobalStateQueryResult;
pub use information_request::{InformationRequest, InformationRequestTag};
pub use key_prefix::KeyPrefix;
pub use minimal_block_info::MinimalBlockInfo;
pub use node_status::NodeStatus;
pub use payload_type::{PayloadEntity, PayloadType};
Expand Down
7 changes: 4 additions & 3 deletions execution_engine/src/runtime/auction_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use casper_types::{
auction::{BidAddr, BidKind, EraInfo, Error, UnbondingPurse},
mint,
},
CLTyped, CLValue, Key, KeyPrefix, KeyTag, PublicKey, RuntimeArgs, StoredValue, URef, U512,
CLTyped, CLValue, Key, KeyTag, PublicKey, RuntimeArgs, StoredValue, URef, U512,
};

use super::Runtime;
Expand Down Expand Up @@ -168,7 +168,7 @@ where
})
}

fn get_keys_by_prefix(&mut self, prefix: &KeyPrefix) -> Result<Vec<Key>, Error> {
fn get_keys_by_prefix(&mut self, prefix: &[u8]) -> Result<Vec<Key>, Error> {
self.context
.get_keys_with_prefix(prefix)
.map_err(|exec_error| {
Expand All @@ -178,9 +178,10 @@ where
}

fn delegator_count(&mut self, bid_addr: &BidAddr) -> Result<usize, Error> {
let prefix = bid_addr.delegators_prefix()?;
let keys = self
.context
.get_keys_with_prefix(&bid_addr.delegators_prefix())
.get_keys_with_prefix(&prefix)
.map_err(|exec_error| {
error!("RuntimeProvider::delegator_count {:?}", exec_error);
<Option<Error>>::from(exec_error).unwrap_or(Error::Storage)
Expand Down
7 changes: 3 additions & 4 deletions execution_engine/src/runtime_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use casper_types::{
system::auction::EraInfo,
AccessRights, AddressableEntity, AddressableEntityHash, BlockTime, CLType, CLValue,
CLValueDictionary, ContextAccessRights, EntityAddr, EntryPointType, Gas, GrantedAccess, Key,
KeyPrefix, KeyTag, Motes, Package, PackageHash, Phase, ProtocolVersion, PublicKey, RuntimeArgs,
KeyTag, Motes, Package, PackageHash, Phase, ProtocolVersion, PublicKey, RuntimeArgs,
StoredValue, StoredValueTypeMismatch, SystemEntityRegistry, TransactionHash, Transfer, URef,
URefAddr, DICTIONARY_ITEM_KEY_MAX_LENGTH, KEY_HASH_LENGTH, U512,
};
Expand Down Expand Up @@ -504,12 +504,11 @@ where
}

/// Returns all key's that start with prefix, if any.
pub fn get_keys_with_prefix(&mut self, prefix: &KeyPrefix) -> Result<Vec<Key>, ExecError> {
let prefix_bytes = prefix.to_bytes()?;
pub fn get_keys_with_prefix(&mut self, prefix: &[u8]) -> Result<Vec<Key>, ExecError> {
self.tracking_copy
.borrow_mut()
.reader()
.keys_with_prefix(&prefix_bytes)
.keys_with_prefix(prefix)
.map_err(Into::into)
}

Expand Down
2 changes: 2 additions & 0 deletions storage/src/data_access_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod flush;
mod genesis;
pub mod handle_fee;
mod handle_refund;
mod key_prefix;
pub mod mint;
mod protocol_upgrade;
pub mod prune;
Expand Down Expand Up @@ -54,6 +55,7 @@ pub use flush::{FlushRequest, FlushResult};
pub use genesis::{GenesisRequest, GenesisResult};
pub use handle_fee::{HandleFeeMode, HandleFeeRequest, HandleFeeResult};
pub use handle_refund::{HandleRefundMode, HandleRefundRequest, HandleRefundResult};
pub use key_prefix::KeyPrefix;
pub use mint::{TransferRequest, TransferResult};
pub use protocol_upgrade::{ProtocolUpgradeRequest, ProtocolUpgradeResult};
pub use prune::{PruneRequest, PruneResult};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#[cfg(any(feature = "testing", test))]
use crate::testing::TestRng;
use crate::{
use casper_types::testing::TestRng;
use casper_types::{
account::AccountHash,
bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
contract_messages::TopicNameHash,
system::{auction::BidAddrTag, mint::BalanceHoldAddrTag},
EntityAddr, KeyTag, URefAddr,
};
use alloc::vec::Vec;
#[cfg(any(feature = "testing", test))]
use rand::Rng;

Expand All @@ -28,30 +27,14 @@ pub enum KeyPrefix {
ProcessingBalanceHoldsByPurse(URefAddr),
}

impl KeyPrefix {
/// Returns a random `KeyPrefix`.
#[cfg(any(feature = "testing", test))]
pub fn random(rng: &mut TestRng) -> Self {
match rng.gen_range(0..6) {
0 => KeyPrefix::DelegatorBidAddrsByValidator(rng.gen()),
1 => KeyPrefix::MessagesByEntity(rng.gen()),
2 => KeyPrefix::MessagesByEntityAndTopic(rng.gen(), rng.gen()),
3 => KeyPrefix::NamedKeysByEntity(rng.gen()),
4 => KeyPrefix::GasBalanceHoldsByPurse(rng.gen()),
5 => KeyPrefix::ProcessingBalanceHoldsByPurse(rng.gen()),
_ => unreachable!(),
}
}
}

impl ToBytes for KeyPrefix {
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
let mut result = bytesrepr::unchecked_allocate_buffer(self);
self.write_bytes(&mut result)?;
Ok(result)
}

fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), crate::bytesrepr::Error> {
fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
match self {
KeyPrefix::DelegatorBidAddrsByValidator(validator) => {
writer.push(KeyTag::BidAddr as u8);
Expand Down Expand Up @@ -160,17 +143,29 @@ impl FromBytes for KeyPrefix {

#[cfg(test)]
mod tests {
use crate::{
use casper_types::{
addressable_entity::NamedKeyAddr,
contract_messages::MessageAddr,
gens::key_prefix_arb,
gens::{account_hash_arb, entity_addr_arb, topic_name_hash_arb, u8_slice_32},
system::{auction::BidAddr, mint::BalanceHoldAddr},
BlockTime, Key,
};

use super::*;
use proptest::prelude::*;

pub fn key_prefix_arb() -> impl Strategy<Value = KeyPrefix> {
prop_oneof![
account_hash_arb().prop_map(KeyPrefix::DelegatorBidAddrsByValidator),
entity_addr_arb().prop_map(KeyPrefix::MessagesByEntity),
(entity_addr_arb(), topic_name_hash_arb())
.prop_map(|(entity, topic)| KeyPrefix::MessagesByEntityAndTopic(entity, topic)),
entity_addr_arb().prop_map(KeyPrefix::NamedKeysByEntity),
u8_slice_32().prop_map(KeyPrefix::GasBalanceHoldsByPurse),
u8_slice_32().prop_map(KeyPrefix::ProcessingBalanceHoldsByPurse),
]
}

proptest! {
#[test]
fn bytesrepr_roundtrip(key_prefix in key_prefix_arb()) {
Expand Down
1 change: 1 addition & 0 deletions storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod system;
pub mod tracking_copy;

pub use address_generator::{AddressGenerator, AddressGeneratorBuilder};
pub use data_access_layer::KeyPrefix;
pub use tracking_copy::TrackingCopy;

pub use block_store::{
Expand Down
2 changes: 1 addition & 1 deletion storage/src/system/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ pub trait Auction:
self.prune_bid(validator_bid_addr);

// Also slash delegator stakes when deactivating validator bid.
let prefix = validator_bid_addr.delegators_prefix();
let prefix = validator_bid_addr.delegators_prefix()?;
let delegator_keys = self.get_keys_by_prefix(&prefix)?;
for delegator_key in delegator_keys {
if let Some(BidKind::Delegator(delegator_bid)) =
Expand Down
18 changes: 8 additions & 10 deletions storage/src/system/auction/auction_native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use casper_types::{
auction::{BidAddr, BidKind, EraInfo, Error, UnbondingPurse},
mint,
},
CLTyped, CLValue, Key, KeyPrefix, KeyTag, PublicKey, StoredValue, URef, U512,
CLTyped, CLValue, Key, KeyTag, PublicKey, StoredValue, URef, U512,
};
use std::collections::BTreeSet;
use tracing::error;
Expand Down Expand Up @@ -53,25 +53,23 @@ where
})
}

fn get_keys_by_prefix(&mut self, prefix: &KeyPrefix) -> Result<Vec<Key>, Error> {
let prefix_bytes = prefix.to_bytes().map_err(|_| Error::Serialization)?;
fn get_keys_by_prefix(&mut self, prefix: &[u8]) -> Result<Vec<Key>, Error> {
self.tracking_copy()
.borrow_mut()
.reader()
.keys_with_prefix(&prefix_bytes)
.keys_with_prefix(prefix)
.map_err(|error| {
error!("RuntimeProvider::get_keys_by_prefix: {:?}", error);
Error::Storage
})
}

fn delegator_count(&mut self, bid_addr: &BidAddr) -> Result<usize, Error> {
let keys = self
.get_keys_by_prefix(&bid_addr.delegators_prefix())
.map_err(|err| {
error!("RuntimeProvider::delegator_count {:?}", err);
Error::Storage
})?;
let prefix = bid_addr.delegators_prefix()?;
let keys = self.get_keys_by_prefix(&prefix).map_err(|err| {
error!("RuntimeProvider::delegator_count {:?}", err);
Error::Storage
})?;
Ok(keys.len())
}

Expand Down
Loading

0 comments on commit 155b27f

Please sign in to comment.