account.rs
Overview
This file defines the WrappedAccount structure, which encapsulates an account identifier (AccountAddress) alongside the account state data (tvm_block::ShardAccount). It provides serialization and deserialization support for WrappedAccount instances by leveraging a helper struct, WrappedAccountData, to convert the account data to and from a byte representation. This enables safe transmission and storage of account data in serialized formats such as JSON or binary.
Structures and Implementations
WrappedAccount
pub struct WrappedAccount {
pub account_id: AccountAddress,
pub account: tvm_block::ShardAccount,
}
Purpose: Combines an account identifier with its corresponding shard account data.
Fields:
account_id: A unique identifier of typeAccountAddressrepresenting the account.account: The actual account data of typetvm_block::ShardAccount.
Traits Implemented
Clone: Enables cloning ofWrappedAccountinstances.PartialEq: Allows comparison between twoWrappedAccountinstances.Debug: Custom implementation that formats the debug output to show the hexadecimal string of theaccount_id.
Debug Implementation
The Debug trait is implemented to display only the hexadecimal string representation of the account_id, providing a concise debug output without exposing the entire account data.
impl Debug for WrappedAccount {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.account_id.to_hex_string())
}
}
Serialization and Deserialization
To facilitate serialization and deserialization, two helper methods are defined:
wrap_serialize(&self) -> WrappedAccountData: Converts theWrappedAccountinto a serializable structureWrappedAccountDataby serializing theShardAccountinto bytes.wrap_deserialize(data: WrappedAccountData) -> Self: Reconstructs aWrappedAccountfromWrappedAccountDataby parsing the byte data back into aShardAccount.
These methods rely on the Serializable and Deserializable traits implemented by tvm_block::ShardAccount for byte-level conversion.
impl WrappedAccount {
fn wrap_serialize(&self) -> WrappedAccountData {
WrappedAccountData {
account_id: self.account_id.clone(),
data: self.account.write_to_bytes().unwrap(),
}
}
fn wrap_deserialize(data: WrappedAccountData) -> Self {
Self {
account_id: data.account_id.clone(),
account: tvm_block::ShardAccount::construct_from_bytes(&data.data).unwrap(),
}
}
}
Serialize Trait Implementation
The Serialize trait is implemented by delegating serialization to the WrappedAccountData structure:
impl Serialize for WrappedAccount {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.wrap_serialize().serialize(serializer)
}
}
Deserialize Trait Implementation
Similarly, the Deserialize trait is implemented by first deserializing into WrappedAccountData and then reconstructing WrappedAccount:
impl<'de> Deserialize<'de> for WrappedAccount {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let data = WrappedAccountData::deserialize(deserializer)?;
let account = WrappedAccount::wrap_deserialize(data);
Ok(account)
}
}
WrappedAccountData
#[derive(Serialize, Deserialize)]
struct WrappedAccountData {
account_id: AccountAddress,
data: Vec<u8>,
}
Purpose: Acts as an intermediate serialized representation of
WrappedAccount.Fields:
account_id: The account identifier.data: Serialized bytes of theShardAccount.
This struct derives Serialize and Deserialize traits automatically, enabling straightforward (de)serialization with Serde.
Important Implementation Details
The serialization strategy separates the
account_id(which is easily serializable) from the account's complex state data (ShardAccount), which requires conversion to bytes.The use of
unwrap()in serialization and deserialization methods assumes that these operations will succeed; any failure will cause a panic. This implies that the input data should always be valid and that error handling for corrupted data is handled upstream or considered unnecessary in this context.The custom
Debugimplementation aids debugging by focusing only on the account's identity instead of its full data, reducing verbosity.
Interactions with Other Components
tvm_block::ShardAccount: The core account state structure whose serialization and deserialization are critical. The file depends on its
write_to_bytesandconstruct_from_bytesmethods for byte conversion.crate::types::AccountAddress: Provides the account identifier type. Its
to_hex_stringmethod is used in debug formatting.Serde Library: Used for serialization and deserialization of both
WrappedAccountDataandWrappedAccount.This file acts as a bridge between the low-level account data (
ShardAccount) and higher-level serialization requirements, enabling seamless persistence or network transmission.
Usage Example
use crate::account::WrappedAccount;
use crate::types::AccountAddress;
use tvm_block::ShardAccount;
// Construct a WrappedAccount
let account_address = AccountAddress::from_hex("abcdef1234567890");
let shard_account = ShardAccount::new(...); // assume some constructor
let wrapped_account = WrappedAccount {
account_id: account_address,
account: shard_account,
};
// Serialize the wrapped account
let serialized = serde_json::to_string(&wrapped_account).unwrap();
// Deserialize back
let deserialized: WrappedAccount = serde_json::from_str(&serialized).unwrap();
// Debug print
println!("{:?}", deserialized);
File Structure Diagram
classDiagram
class WrappedAccount {
+account_id: AccountAddress
+account: ShardAccount
+wrap_serialize()
+wrap_deserialize()
+serialize()
+deserialize()
}
class WrappedAccountData {
+account_id: AccountAddress
+data: Vec<u8>
}
WrappedAccount ..> WrappedAccountData : uses
WrappedAccount --> "ShardAccount" : contains
WrappedAccount --> "AccountAddress" : contains
WrappedAccountData --> "AccountAddress" : contains