accounts.rs
Overview
This file defines abstractions and utilities for interacting with specific blockchain accounts related to the BlockKeeper system. It provides typed wrappers around raw Account instances, enabling convenient invocation of contract methods through statically initialized TVM contracts. These wrappers facilitate querying critical information such as epoch code hashes, proxy lists, and ownership details from deployed smart contracts.
Key features include:
Typed structures representing different contracts (
Root,Bk,Epoch,ProxyList).Helper functions for decoding and parsing contract method outputs, especially handling
UInt256values and JSON maps.Lazy initialization of contract ABIs and TVC binaries for efficient repeated calls.
A function to collect proxy node details from the blockchain, populating a set of peer nodes with associated network addresses.
This file plays a crucial role in the interaction layer between the application and deployed smart contracts managing block keeper nodes, epochs, and proxy lists.
Detailed Components
Helper Functions
get_u256(v: &Value, name: &str) -> anyhow::Result<UInt256>
Purpose: Extracts a required
UInt256value from a JSONValueobject.Parameters:
v: Reference to aserde_json::Valuerepresenting JSON data.name: The key name within the JSON object to extract.
Returns:
UInt256if present; error if missing or invalid.Usage: Used to extract mandatory 256-bit unsigned integers from contract call outputs.
Implementation Detail: Calls
get_optional_u256and returns an error if the value is not present.
get_optional_u256(v: &Value, name: &str) -> anyhow::Result<Option<UInt256>>
Purpose: Extracts an optional
UInt256value from a JSON object.Parameters: Same as
get_u256.Returns:
Some(UInt256)if present and valid, otherwise None.Usage: Useful for JSON fields that may or may not be set.
Implementation Detail: Parses string representation from JSON, converting to
UInt256.
get_map<K, V: DeserializeOwned>(v: &Value, name: &str) -> anyhow::Result<HashMap<K, V>>
Purpose: Extracts a map from JSON object field, deserializing keys and values.
Parameters:
v: JSON value.name: Key name expected to hold a JSON object.
Generics:
K: Key type, must implementFromStr,Eq,Hash.V: Value type that implements DeserializeOwned.
Returns: A
HashMapwith keys and deserialized values.Usage: Used to parse complex mappings returned by contracts.
Implementation Detail: Converts JSON object keys from strings using
FromStr, deserializes values usingserde_json.
Contract Wrappers
Each contract wrapper holds an Account and provides typed methods to query contract state via run_get.
Static LazyLock TVM Contracts
Contracts are loaded once at runtime using
LazyLockfor efficiency.ABI and TVC binaries are embedded via
include_str!andinclude_bytes!.Contracts included:
ROOT - BlockKeeperContractRoot
BK- AckiNackiBlockKeeperNodeWalletEPOCH - BlockKeeperEpochContract
PROXY_LIST - BlockKeeperEpochProxyList
Root Struct
Purpose: Represents the root BlockKeeper contract.
Field: Holds an
Accountinstance.Method:
get_epoch_code_hash(&self) -> anyhow::Result<UInt256>Invokes "getEpochCodeHash" getter on the root contract.
Returns the epoch code hash as
UInt256.
Bk Struct
Purpose: Represents the BlockKeeper node wallet contract.
Field: Holds an
Account.Method:
get_proxy_list_addr(&self) -> anyhow::Result<UInt256>Calls "getProxyListAddr" getter.
Returns the address of the proxy list contract.
Epoch Struct
Purpose: Represents the BlockKeeper epoch contract.
Field: Holds an
Account.Method:
get_owner_address(&self) -> anyhow::Result<UInt256>Calls "getDetails" getter.
Extracts the
"owner"field asUInt256.
ProxyList Struct
Purpose: Represents the proxy list contract managing node proxies.
Field: Holds an
Account.Method:
get_proxy_list(&self) -> anyhow::Result<(Option<SocketAddr>, HashSet<SocketAddr>)>Calls "getDetails" getter.
Extracts a map of proxies indexed by
u8.The proxy with key 0 is the "node address" (optional).
Remaining proxies parsed into a
HashSetofSocketAddr.Returns a tuple:
(Option<node_addr>, HashSet<proxy_addresses>).
Data Types:
ProxyListEntry: Deserialize struct containingaddrasSocketAddr. Uses a custom deserializerdeserialize_publisher_addrfor address parsing.
Function: collect_bk_set
pub fn collect_bk_set<PeerId>(
accounts: &impl AccountProvider,
bk: &Bk,
nodes: &mut HashMap<PeerId, (Option<SocketAddr>, HashSet<SocketAddr>)>,
) -> anyhow::Result<()>
where
PeerId: Eq + Hash + From<UInt256>,
Purpose: Collects the proxy set associated with a BlockKeeper node wallet and inserts it into a provided map.
Parameters:
accounts: An implementation ofAccountProviderto retrieve accounts by ID.bk: Reference to aBkcontract wrapper.nodes: Mutable map keyed byPeerId, values are tuples of optional node address and proxy address set.
Behavior:
Retrieves the proxy list contract address from
bk.Uses
accountsto get the proxy list account.Converts the
bkaccount ID intoPeerId.Queries the proxy list contract for node and proxy addresses.
Inserts the proxy list into
nodeshashmap under thePeerId.
Errors: Propagates errors related to missing accounts, conversion failures, or empty proxy lists.
Important Implementation Details
The
LazyLockpattern ensures contract ABIs and TVC binaries are loaded only once, improving performance.UInt256values are parsed from string fields in JSON outputs, reflecting the blockchain's 256-bit integer encoding.The use of
serde_json::Valueallows flexible extraction from contract call results.Proxy lists are stored as JSON maps with keys as
u8indices and values as serializedProxyListEntrystrings.The
collect_bk_setfunction bridges contract data with application-level peer management, converting raw blockchain data into structured network node sets.
Interaction with Other Components
Uses types from external crates such as:
tvm_block::Accounttvm_contracts::TvmContracttvm_types::UInt256
Depends on
AccountProvidertrait fromcrate::resolver::blockchainto fetch accounts by blockchain IDs.Utilizes utility functions
parse_publisher_addranddeserialize_publisher_addrfrom the crate for address parsing.Integrates contract ABI and TVC files from the
contracts/bksystemdirectory, linking on-chain logic with off-chain querying.The
collect_bk_setfunction is designed to be called by higher-level network or peer management components to maintain an up-to-date view of proxy nodes.
Visual Diagram: Class Structure and Relationships
classDiagram
class Root {
+Account
+get_epoch_code_hash()
}
class Bk {
+Account
+get_proxy_list_addr()
}
class Epoch {
+Account
+get_owner_address()
}
class ProxyList {
+Account
+get_proxy_list()
}
Root o-- Account
Bk o-- Account
Epoch o-- Account
ProxyList o-- Account
This diagram illustrates the four main contract wrapper structs, each encapsulating an Account and providing specific contract query methods.
Usage Examples
// Assume `account` is an Account instance for the root contract
let root = Root(account);
let epoch_code_hash = root.get_epoch_code_hash()?;
// Assume `bk_account` is an Account instance for a BK contract
let bk = Bk(bk_account);
let proxy_list_addr = bk.get_proxy_list_addr()?;
// For an Epoch contract instance
let epoch = Epoch(epoch_account);
let owner_addr = epoch.get_owner_address()?;
// For a ProxyList contract instance
let proxy_list = ProxyList(proxy_list_account);
let (node_addr, proxies) = proxy_list.get_proxy_list()?;
// Collecting BK proxy sets
let mut nodes_map = HashMap::new();
collect_bk_set(&accounts_provider, &bk, &mut nodes_map)?;
Refer to Account Management and Contract Interaction for broader context on account handling and contract call semantics.