diff --git a/lake-primitives/src/lib.rs b/lake-primitives/src/lib.rs index 8127a82..ecc96fa 100644 --- a/lake-primitives/src/lib.rs +++ b/lake-primitives/src/lib.rs @@ -2,6 +2,15 @@ pub use near_indexer_primitives::{ self, near_primitives, types::AccountId, CryptoHash, IndexerShard, StreamerMessage, }; -pub use types::{actions, block, events, receipts, state_changes, transactions}; +pub use types::{ + actions::{self, Action}, + block::{self, Block, BlockHeader}, + delegate_actions::{self, DelegateAction}, + events::{self, Event, EventsTrait, RawEvent}, + receipts::{self, Receipt, ReceiptKind}, + state_changes::{self, StateChange, StateChangeCause, StateChangeValue}, + transactions::{self, Transaction}, + ReceiptId, +}; mod types; diff --git a/lake-primitives/src/types/actions.rs b/lake-primitives/src/types/actions.rs index 5b35876..426d9f6 100644 --- a/lake-primitives/src/types/actions.rs +++ b/lake-primitives/src/types/actions.rs @@ -5,8 +5,14 @@ use near_indexer_primitives::{ }; use crate::types::delegate_actions; -pub use delegate_actions::DelegateAction; +pub use delegate_actions::{ + DelegateAction, DelegateAddKey, DelegateCreateAccount, DelegateDeleteAccount, + DelegateDeleteKey, DelegateDeployContract, DelegateFunctionCall, DelegateStake, + DelegateTransfer, +}; +/// Represents the metadata of the action. +/// This is the information that is common to all actions. #[derive(Debug, Clone)] pub struct ActionMetadata { pub(crate) receipt_id: CryptoHash, @@ -17,22 +23,27 @@ pub struct ActionMetadata { } impl ActionMetadata { + /// Returns the [CryptoHash] id of the corresponding Receipt. pub fn receipt_id(&self) -> CryptoHash { self.receipt_id } + /// Returns the [AccountId] of the predecessor of the action. pub fn predecessor_id(&self) -> AccountId { self.predecessor_id.clone() } + /// Returns the [AccountId] of the receiver of the action. pub fn receiver_id(&self) -> AccountId { self.receiver_id.clone() } + /// Returns the [AccountId] of the signer of the action. pub fn signer_id(&self) -> AccountId { self.signer_id.clone() } + /// Returns the [PublicKey] of the signer of the action. pub fn signer_public_key(&self) -> PublicKey { self.signer_public_key.clone() } @@ -58,6 +69,17 @@ pub trait ActionMetaDataExt { } } +/// High-level representation of the `Action`. +/// +/// Action is "registered" in the [Transaction](super::transactions::Transaction) to be performed on the blockchain. +/// There is a predefined set of actions that can be performed on the blockchain. +/// +/// #### Important notes on Action enum +/// +/// Please, note that each enum variant is a wrapper around the corresponding action struct. Also, we have special methods +/// for each action type that attempts to convert the action to the corresponding struct. For example, if you have an action +/// of type `Action::Transfer`, you can call `action.as_transfer()` to get the `Transfer` struct. If the action is not of +/// the corresponding type, the method will return `None`. This is done to simplify the usage of the `Action` enum. #[derive(Debug, Clone)] pub enum Action { CreateAccount(CreateAccount), @@ -133,11 +155,15 @@ impl_action_metadata_ext!(DeleteKey); impl_action_metadata_ext!(DeleteAccount); impl_action_metadata_ext!(Delegate); +/// Structure representing the `CreateAccount` action. +/// This is a special action that is used to create a new account on the blockchain. It doesn't contain any +/// additional data. The `receiver_id` from the metadata is the name of the account that is created by this action. #[derive(Debug, Clone)] pub struct CreateAccount { pub(crate) metadata: ActionMetadata, } +/// Structure representing the `DeployContract` action. #[derive(Debug, Clone)] pub struct DeployContract { pub(crate) metadata: ActionMetadata, @@ -145,11 +171,13 @@ pub struct DeployContract { } impl DeployContract { + /// Returns the contract code bytes. pub fn code(&self) -> &[u8] { &self.code } } +/// Structure representing the `FunctionCall` action. #[derive(Debug, Clone)] pub struct FunctionCall { pub(crate) metadata: ActionMetadata, @@ -160,23 +188,28 @@ pub struct FunctionCall { } impl FunctionCall { + /// Returns the method name this FunctionCall calls. pub fn method_name(&self) -> &str { &self.method_name } + /// Returns the arguments bytes. pub fn args(&self) -> &[u8] { &self.args } + /// Returns the gas attached to this FunctionCall. pub fn gas(&self) -> Gas { self.gas } + /// Returns the deposit attached to this FunctionCall. pub fn deposit(&self) -> Balance { self.deposit } } +/// Structure representing the `Transfer` action. #[derive(Debug, Clone)] pub struct Transfer { pub(crate) metadata: ActionMetadata, @@ -184,11 +217,13 @@ pub struct Transfer { } impl Transfer { + /// Returns the deposit attached to this Transfer. pub fn deposit(&self) -> Balance { self.deposit } } +/// Structure representing the `Stake` action. #[derive(Debug, Clone)] pub struct Stake { pub(crate) metadata: ActionMetadata, @@ -197,15 +232,18 @@ pub struct Stake { } impl Stake { + /// Returns the stake attached to this Stake. pub fn stake(&self) -> Balance { self.stake } + /// Returns the public key attached to this Stake. pub fn public_key(&self) -> &PublicKey { &self.public_key } } +/// Structure representing the `AddKey` action. #[derive(Debug, Clone)] pub struct AddKey { pub(crate) metadata: ActionMetadata, @@ -214,15 +252,18 @@ pub struct AddKey { } impl AddKey { + /// Returns the [PublicKey] added with this AddKey. pub fn public_key(&self) -> &PublicKey { &self.public_key } + /// Returns the [AccessKey](views::AccessKeyView) to the PublicKey being added with this AddKey. pub fn access_key(&self) -> &views::AccessKeyView { &self.access_key } } +/// Structure representing the `DeleteKey` action. #[derive(Debug, Clone)] pub struct DeleteKey { pub(crate) metadata: ActionMetadata, @@ -230,11 +271,13 @@ pub struct DeleteKey { } impl DeleteKey { + /// Returns the [PublicKey] deleted with this DeleteKey. pub fn public_key(&self) -> &PublicKey { &self.public_key } } +/// Structure representing the `DeleteAccount` action. #[derive(Debug, Clone)] pub struct DeleteAccount { pub(crate) metadata: ActionMetadata, @@ -242,11 +285,22 @@ pub struct DeleteAccount { } impl DeleteAccount { + /// Returns the beneficiary account ID of this DeleteAccount. pub fn beneficiary_id(&self) -> &AccountId { &self.beneficiary_id } } +/// Structure representing the `Delegate` action. +/// This is related to the Meta-Transactions [NEP-366](https://github.com/near/NEPs/blob/master/neps/nep-0366.md). +/// +/// This action is used to delegate the right to sign transactions on behalf of the signer to another account. +/// The signer is the account that is signing the transaction that contains this action. +/// The receiver is the account that will be able to sign transactions on behalf of the signer. +/// The `delegate_action` is the action that the receiver will be able to sign on behalf of the signer. +/// The `signature` is the signature of the signer on the hash of the `delegate_action`. +/// +/// The `delegate_action` can be any action, except for another `Delegate` action. Thus not allowing the nesting of `Delegate` actions. #[derive(Debug, Clone)] pub struct Delegate { pub(crate) metadata: ActionMetadata, @@ -255,10 +309,12 @@ pub struct Delegate { } impl Delegate { + /// Returns the delegate action that the receiver will be able to sign on behalf of the signer. pub fn delegate_action(&self) -> &[delegate_actions::DelegateAction] { &self.delegate_action } + /// Returns the signature of the signer on the hash of the `delegate_action`. pub fn signature(&self) -> &Signature { &self.signature } diff --git a/lake-primitives/src/types/block.rs b/lake-primitives/src/types/block.rs index b807aff..0fede21 100644 --- a/lake-primitives/src/types/block.rs +++ b/lake-primitives/src/types/block.rs @@ -7,6 +7,22 @@ use super::state_changes; use super::transactions; use crate::near_indexer_primitives::{types::AccountId, views, CryptoHash, StreamerMessage}; +/// A structure that represents an entire block in the NEAR blockchain. +/// It is a high-level structure that is built on top of the low-level [StreamerMessage] structure. +/// +/// The access to all the data is provided through the getters. Thus we can refactor the structure yet keep the API stable and backward compatible. +/// +/// With a high-level update we are trying to replace the usage of the low-level [StreamerMessage] with this one. +/// +/// #### Important notes on the Block +/// - All the entities located on different shards were merged into one single list without differentiation. +/// The statement from **NEAR** is that **sharding is going to be dynamic and seamless for the users**, that’s why we’ve decided indexer +/// developers don’t want to care about shards either. +/// - Original [near_indexer_primitives::StreamerMessage] represents the blockchain data in *a most fair manner**. Although, it used to be +/// a pain in the neck for indexer developers, we’ve decided to act as a painkiller here. +/// - [Block] is not the fairest name for this structure either. **NEAR Protocol** is a sharded blockchain, so its block is actually an +/// ephemeral structure that represents a collection of *real blocks* called Chunks in **NEAR Protocol**. We’ve been simplifying things here though, +/// so here is a result of the simplification. #[derive(Debug)] pub struct Block { streamer_message: StreamerMessage, @@ -19,26 +35,46 @@ pub struct Block { } impl Block { + /// Return a reference to the original StreamerMessage of the block. This is the low-level structure. + /// + /// While introducing the high-level structures, methods, and helpers, we do want to keep the low-level “door” open + /// for advanced developers or edge cases which we haven’t accidentally covered, or just don’t have the capacity to cover. + /// + /// That’s why every instance of the Block will hold the original StreamerMessage for developers. + /// Think of it as backward compatibility if you prefer. pub fn streamer_message(&self) -> &StreamerMessage { &self.streamer_message } + /// Returns the block hash. It is a shortcut to get the data from the block header. pub fn block_hash(&self) -> CryptoHash { self.header().hash() } + /// Returns the previous block hash. It is a shortcut to get the data from the block header. pub fn prev_block_hash(&self) -> CryptoHash { self.header().prev_hash() } + /// Returns the block height. It is a shortcut to get the data from the block header. pub fn block_height(&self) -> u64 { self.header().height() } + /// Returns a [BlockHeader] structure of the block + /// + ///See [BlockHeader] structure sections for details. pub fn header(&self) -> BlockHeader { (&self.streamer_message).into() } + /// Returns an iterator over the [Receipt](crate::receipts::Receipt)s executed in this [Block]. + /// + /// This field is a representation of `StreamerMessage.shard[N].receipt_execution_outcomes` + /// + /// A reminder that `receipt_execution_outcomes` has a type [near_indexer_primitives::IndexerExecutionOutcomeWithReceipt] which is an + /// ephemeral structure from `near-indexer-primitives` that hold a [near_primitives::views::ExecutionOutcomeView] + /// along with the corresponding [near_primitives::views::ReceiptView]. pub fn receipts(&mut self) -> impl Iterator { if self.executed_receipts.is_empty() { self.executed_receipts = self @@ -52,6 +88,10 @@ impl Block { self.executed_receipts.iter() } + /// Returns an iterator of [Receipt](crate::receipts::Receipt) included yet not executed in the [Block]. + /// + /// [Receipts](crate::receipts::Receipt) included on the chain but not executed yet are called "postponed", + /// they are represented by the same structure [Receipt](crate::receipts::Receipt). pub fn postponed_receipts(&mut self) -> impl Iterator { if self.postponed_receipts.is_empty() { let executed_receipts_ids: Vec<_> = self @@ -72,6 +112,12 @@ impl Block { self.postponed_receipts.iter() } + /// Returns an iterator of the [Transactions](crate::transactions::Transaction) included in the [Block]. + /// + /// **Heads up!** Some indexer developers care about [Transaction](crate::transactions::Transaction)s for the knowledge where + /// the action chain has begun. Other indexer developers care about it because of the habits + /// from other blockchains like Ethereum where a transaction is a main asset. In case of NEAR + /// [Receipts](crate::receipts::Receipt) are more important. pub fn transactions(&mut self) -> impl Iterator { if self.transactions.is_empty() { self.transactions = self @@ -87,6 +133,7 @@ impl Block { self.transactions.iter() } + /// Internal method to build the cache of actions on demand fn actions_from_streamer_message(&self) -> Vec { self.streamer_message() .shards @@ -99,6 +146,7 @@ impl Block { .collect() } + /// Returns an iterator of the [Actions](crate::actions::Action) executed in the [Block] pub fn actions(&mut self) -> impl Iterator { if self.actions.is_empty() { self.build_actions_cache(); @@ -106,6 +154,7 @@ impl Block { self.actions.iter() } + /// Returns an iterator of the [Events](crate::events::Event) emitted in the [Block] pub fn events(&mut self) -> impl Iterator { if self.events.is_empty() { self.build_events_hashmap(); @@ -113,6 +162,7 @@ impl Block { self.events.values().flatten() } + /// Returns an iterator of the [StateChanges](crate::state_changes::StateChange) happened in the [Block] pub fn state_changes(&mut self) -> impl Iterator { if self.state_changes.is_empty() { self.state_changes = self @@ -126,6 +176,9 @@ impl Block { self.state_changes.iter() } + /// Helper to get all the [Actions](crate::actions::Action) by the single [Receipt](crate::receipts::Receipt) + /// + /// **Heads up!** This methods searches for the actions in the current [Block] only. pub fn actions_by_receipt_id<'a>( &'a mut self, receipt_id: &'a super::ReceiptId, @@ -134,6 +187,7 @@ impl Block { .filter(move |action| &action.receipt_id() == receipt_id) } + /// Helper to get all the [Events](crate::events::Event) emitted by the specific [Receipt](crate::receipts::Receipt) pub fn events_by_receipt_id(&mut self, receipt_id: &super::ReceiptId) -> Vec { if self.events.is_empty() { self.build_events_hashmap(); @@ -145,6 +199,7 @@ impl Block { } } + /// Helper to get all the [Events](crate::events::Event) emitted by the specific contract ([AccountId](crate::near_indexer_primitives::types::AccountId)) pub fn events_by_contract_id<'a>( &'a mut self, account_id: &'a crate::near_indexer_primitives::types::AccountId, @@ -153,6 +208,7 @@ impl Block { .filter(move |event| event.is_emitted_by_contract(&account_id.clone())) } + /// Helper to get a specific [Receipt](crate::receipts::Receipt) by the [ReceiptId](crate::types::ReceiptId) pub fn receipt_by_id(&mut self, receipt_id: &super::ReceiptId) -> Option<&receipts::Receipt> { self.receipts() .find(|receipt| &receipt.receipt_id() == receipt_id) @@ -160,10 +216,12 @@ impl Block { } impl Block { + // Internal method to build the cache of actions on demand fn build_actions_cache(&mut self) { self.actions = self.actions_from_streamer_message().to_vec(); } + // Internal method to build the cache of events on demand fn build_events_hashmap(&mut self) { self.events = self .receipts() @@ -186,6 +244,11 @@ impl From for Block { } } +/// Replacement for [`BlockHeaderView`](near_primitives::views::BlockHeaderView) from `near-primitives`. Shrank and simplified. +/// We were trying to leave only the fields indexer developers might be interested in. +/// +/// Friendly reminder, the original [`BlockHeaderView`](near_primitives::views::BlockHeaderView) is still accessible +/// via [`.streamer_message()`](Block::streamer_message()) method. #[derive(Debug, Clone)] pub struct BlockHeader { height: u64, @@ -204,54 +267,70 @@ pub struct BlockHeader { } impl BlockHeader { + /// The height of the [Block] pub fn height(&self) -> u64 { self.height } + /// The hash of the [Block] pub fn hash(&self) -> CryptoHash { self.hash } + /// The hash of the previous [Block] pub fn prev_hash(&self) -> CryptoHash { self.prev_hash } + /// The [AccountId](crate::near_indexer_primitives::types::AccountId) of the author of the [Block] pub fn author(&self) -> AccountId { self.author.clone() } + /// The timestamp of the [Block] in nanoseconds pub fn timestamp_nanosec(&self) -> u64 { self.timestamp_nanosec } + /// The [CryptoHash] of the epoch the [Block] belongs to pub fn epoch_id(&self) -> CryptoHash { self.epoch_id } + /// The [CryptoHash] of the next epoch pub fn next_epoch_id(&self) -> CryptoHash { self.next_epoch_id } + /// The gas price of the [Block] pub fn gas_price(&self) -> u128 { self.gas_price } + /// The total supply of the [Block] pub fn total_supply(&self) -> u128 { self.total_supply } + /// The latest protocol version of the [Block] pub fn latest_protocol_version(&self) -> u32 { self.latest_protocol_version } + /// The random value of the [Block] pub fn random_value(&self) -> CryptoHash { self.random_value } + /// The number of chunks included in the [Block] pub fn chunks_included(&self) -> u64 { self.chunks_included } + /// The validator proposals of the [Block] + /// + /// **Heads up!** This methods returns types defined in the `near-primitives` crate as is. + /// It is a subject of change in the future (once we define the corresponding Lake Primitives types) pub fn validator_proposals(&self) -> Vec { self.validator_proposals.clone() } diff --git a/lake-primitives/src/types/delegate_actions.rs b/lake-primitives/src/types/delegate_actions.rs index 931293c..7097790 100644 --- a/lake-primitives/src/types/delegate_actions.rs +++ b/lake-primitives/src/types/delegate_actions.rs @@ -4,6 +4,12 @@ use near_indexer_primitives::{ views::{self, AccessKeyView}, }; +/// Similarly to the [Action](super::actions::Action) enum, this enum represents the different types of actions that can be +/// delegated to a contract. +/// +/// `DelegateAction` enum has a corresponding `Action` variant for every possible `Action` except the `DelegateAction` itself. +/// Thus forbidding the nesting of `DelegateActions` and making the `Action` enum exhaustive. +/// Another difference is that `DelegateAction` itself and it's variants do not hold metadata and don't implement `ActionMetaDataExt`. #[derive(Debug, Clone)] pub enum DelegateAction { DelegateCreateAccount(DelegateCreateAccount), @@ -17,6 +23,7 @@ pub enum DelegateAction { } impl DelegateAction { + /// Attempts to return the [DelegateFunctionCall](struct@DelegateFunctionCall) struct if the variant is [DelegateAction::DelegateFunctionCall]. Otherwise returns `None`. pub fn as_delegate_function_call(&self) -> Option<&DelegateFunctionCall> { match self { DelegateAction::DelegateFunctionCall(action) => Some(action), @@ -24,6 +31,7 @@ impl DelegateAction { } } + /// Attempts to return the [DelegateCreateAccount] struct if the variant is [DelegateAction::DelegateCreateAccount]. Otherwise returns `None`. pub fn as_delegate_create_account(&self) -> Option<&DelegateCreateAccount> { match self { DelegateAction::DelegateCreateAccount(action) => Some(action), @@ -31,6 +39,7 @@ impl DelegateAction { } } + /// Attempts to return the [DelegateDeployContract] struct if the variant is [DelegateAction::DelegateDeployContract]. Otherwise returns `None`. pub fn as_delegate_deploy_contract(&self) -> Option<&DelegateDeployContract> { match self { DelegateAction::DelegateDeployContract(action) => Some(action), @@ -38,6 +47,7 @@ impl DelegateAction { } } + /// Attempts to return the [DelegateTransfer] struct if the variant is [DelegateAction::DelegateTransfer]. Otherwise returns `None`. pub fn as_delegate_transfer(&self) -> Option<&DelegateTransfer> { match self { DelegateAction::DelegateTransfer(action) => Some(action), @@ -45,6 +55,7 @@ impl DelegateAction { } } + /// Attempts to return the [DelegateStake] struct if the variant is [DelegateAction::DelegateStake]. Otherwise returns `None`. pub fn as_delegate_stake(&self) -> Option<&DelegateStake> { match self { DelegateAction::DelegateStake(action) => Some(action), @@ -52,6 +63,7 @@ impl DelegateAction { } } + /// Attempts to return the [DelegateAddKey] struct if the variant is [DelegateAction::DelegateAddKey]. Otherwise returns `None`. pub fn as_delegate_add_key(&self) -> Option<&DelegateAddKey> { match self { DelegateAction::DelegateAddKey(action) => Some(action), @@ -59,6 +71,7 @@ impl DelegateAction { } } + /// Attempts to return the [DelegateDeleteKey] struct if the variant is [DelegateAction::DelegateDeleteKey]. Otherwise returns `None`. pub fn as_delegate_delete_key(&self) -> Option<&DelegateDeleteKey> { match self { DelegateAction::DelegateDeleteKey(action) => Some(action), @@ -66,6 +79,7 @@ impl DelegateAction { } } + /// Attempts to return the [DelegateDeleteAccount] struct if the variant is [DelegateAction::DelegateDeleteAccount]. Otherwise returns `None`. pub fn as_delegate_delete_account(&self) -> Option<&DelegateDeleteAccount> { match self { DelegateAction::DelegateDeleteAccount(action) => Some(action), @@ -74,20 +88,24 @@ impl DelegateAction { } } +/// Similarly to [CreateAccount](super::actions::CreateAccount), this struct represents the `CreateAccount` action that is delegated. #[derive(Debug, Clone)] pub struct DelegateCreateAccount; +/// Similarly to [DeployContract](super::actions::DeployContract), this struct represents the `DeployContract` action that is delegated. #[derive(Debug, Clone)] pub struct DelegateDeployContract { pub(crate) code: Vec, } impl DelegateDeployContract { + /// Returns the bytes of the contract code that is being deployed. pub fn code(&self) -> &[u8] { &self.code } } +/// Similarly to [FunctionCall](super::actions::FunctionCall), this struct represents the `FunctionCall` action that is delegated. #[derive(Debug, Clone)] pub struct DelegateFunctionCall { pub(crate) method_name: String, @@ -97,34 +115,41 @@ pub struct DelegateFunctionCall { } impl DelegateFunctionCall { + /// Returns the name of the method that is being called. pub fn method_name(&self) -> &str { &self.method_name } + /// Returns the bytes of the arguments that are being passed to the method. pub fn args(&self) -> &[u8] { &self.args } + /// Returns the amount of gas that is being used for the method call. pub fn gas(&self) -> Gas { self.gas } + /// Returns the amount of tokens that are being deposited to the contract. pub fn deposit(&self) -> Balance { self.deposit } } +/// Similarly to [Transfer](super::actions::Transfer), this struct represents the `Transfer` action that is delegated. #[derive(Debug, Clone)] pub struct DelegateTransfer { pub(crate) deposit: Balance, } impl DelegateTransfer { + /// Returns the amount of tokens that are being transferred. pub fn deposit(&self) -> Balance { self.deposit } } +/// Similarly to [Stake](super::actions::Stake), this struct represents the `Stake` action that is delegated. #[derive(Debug, Clone)] pub struct DelegateStake { pub(crate) stake: Balance, @@ -132,15 +157,18 @@ pub struct DelegateStake { } impl DelegateStake { + /// Returns the amount of tokens that are being staked. pub fn stake(&self) -> Balance { self.stake } + /// Returns the public key of the staking pool. pub fn public_key(&self) -> &PublicKey { &self.public_key } } +/// Similarly to [AddKey](super::actions::AddKey), this struct represents the `AddKey` action that is delegated. #[derive(Debug, Clone)] pub struct DelegateAddKey { pub(crate) public_key: PublicKey, @@ -148,39 +176,45 @@ pub struct DelegateAddKey { } impl DelegateAddKey { + /// Returns the public key that is being added. pub fn public_key(&self) -> &PublicKey { &self.public_key } + /// Returns the access key that is being added. pub fn access_key(&self) -> &AccessKeyView { &self.access_key } } +/// Similarly to [DeleteKey](super::actions::DeleteKey), this struct represents the `DeleteKey` action that is delegated. #[derive(Debug, Clone)] pub struct DelegateDeleteKey { pub(crate) public_key: PublicKey, } impl DelegateDeleteKey { + /// Returns the public key that is being deleted. pub fn public_key(&self) -> &PublicKey { &self.public_key } } +/// Similarly to [DeleteAccount](super::actions::DeleteAccount), this struct represents the `DeleteAccount` action that is delegated. #[derive(Debug, Clone)] pub struct DelegateDeleteAccount { pub(crate) beneficiary_id: AccountId, } impl DelegateDeleteAccount { + /// Returns the account ID of the beneficiary. pub fn beneficiary_id(&self) -> &AccountId { &self.beneficiary_id } } impl DelegateAction { - // Tries to convert a near_primitives::delegate_action::DelegateAction into a Vec. + // Tries to convert a `near_primitives::delegate_action::DelegateAction` into a [Vec]. pub fn try_from_delegate_action( delegate_action: &near_primitives::delegate_action::DelegateAction, ) -> Result, &'static str> { diff --git a/lake-primitives/src/types/events.rs b/lake-primitives/src/types/events.rs index 94b6a06..59de0e3 100644 --- a/lake-primitives/src/types/events.rs +++ b/lake-primitives/src/types/events.rs @@ -2,6 +2,8 @@ use crate::AccountId; use super::receipts::Receipt; +/// Hight-level representation of the Event according to the [Events Format](https://nomicon.io/Standards/EventsFormat.html). +/// In addition to the event this structure holds the data about the related [Receipt]: `receipt_id`, `receiver_id` and `predecessor_id`. All these fields are accessible via the corresponding getters. #[derive(Clone, Debug)] pub struct Event { pub(crate) related_receipt_id: crate::CryptoHash, @@ -11,30 +13,40 @@ pub struct Event { } impl Event { + /// Returns the `event` value from the [RawEvent]. pub fn event(&self) -> &str { &self.raw_event.event } + /// Returns the `standard` value from the [RawEvent]. pub fn standard(&self) -> &str { &self.raw_event.standard } + /// Returns the `version` value from the [RawEvent]. pub fn version(&self) -> &str { &self.raw_event.version } + /// Returns the `data` value from the [RawEvent] if present, otherwise returns `None`. pub fn data(&self) -> Option<&serde_json::Value> { self.raw_event.data.as_ref() } + /// Returns the [CryptoHash](crate::CryptoHash) id of the related [Receipt]. + /// + /// **Please note** that events are emitted through the `ExecutionOutcome` logs. In turn, the `ExecutionOutcome` + /// is a result of the execution of the [Receipt]. pub fn related_receipt_id(&self) -> crate::CryptoHash { self.related_receipt_id } + /// Returns the [AccountId] of the receiver of the related [Receipt]. pub fn related_receipt_receiver_id(&self) -> &AccountId { &self.receiver_id } + /// Returns the [AccountId] of the predecessor of the related [Receipt]. pub fn related_receipt_predecessor_id(&self) -> &AccountId { &self.predecessor_id } @@ -45,6 +57,8 @@ impl Event { } } +/// This structure is an honest representation of the Events Format standard described here +/// #[derive(Clone, Debug, serde::Deserialize)] pub struct RawEvent { pub event: String, @@ -54,6 +68,7 @@ pub struct RawEvent { } impl RawEvent { + /// Parses the log message (originated from `ExecutionOutcome` but not limited) and returns the RawEvent. pub fn from_log(log: &str) -> anyhow::Result { let prefix = "EVENT_JSON:"; if !log.starts_with(prefix) { @@ -71,6 +86,7 @@ pub trait EventsTrait { } impl EventsTrait for Receipt { + /// Reads the logs from the [Receipt] and extracts all the [Events](Event) from it into a Vec. fn events(&self) -> Vec { self.logs() .iter() diff --git a/lake-primitives/src/types/impl_actions.rs b/lake-primitives/src/types/impl_actions.rs index 4968a2b..3186aa5 100644 --- a/lake-primitives/src/types/impl_actions.rs +++ b/lake-primitives/src/types/impl_actions.rs @@ -3,7 +3,7 @@ use near_indexer_primitives::{views, IndexerTransactionWithOutcome}; use crate::actions::{Action, ActionMetadata, DelegateAction}; impl Action { - // Tries to convert a &ReceiptView into a vector of Action. + // Tries to convert a [&ReceiptView](views::ReceiptView) into a vector of [Action]. pub fn try_vec_from_receipt_view( receipt_view: &views::ReceiptView, ) -> Result, &'static str> { @@ -104,7 +104,7 @@ impl Action { } } - // Tries to convert a IndexerTransactionWithOutcome to a Vec + // Tries to convert a [IndexerTransactionWithOutcome] to a [Vec] pub fn try_vec_from_transaction_outcome( transaction_with_outcome: &IndexerTransactionWithOutcome, ) -> Result, &'static str> { diff --git a/lake-primitives/src/types/mod.rs b/lake-primitives/src/types/mod.rs index 4d836a8..2b3f554 100644 --- a/lake-primitives/src/types/mod.rs +++ b/lake-primitives/src/types/mod.rs @@ -7,4 +7,6 @@ pub mod receipts; pub mod state_changes; pub mod transactions; +/// Since both [transactions::Transaction] hash and [receipts::Receipt] id are the [crate::CryptoHash] type, +/// we use this type alias to make the code more readable. pub type ReceiptId = near_indexer_primitives::CryptoHash; diff --git a/lake-primitives/src/types/receipts.rs b/lake-primitives/src/types/receipts.rs index c3bf9e6..7250a2a 100644 --- a/lake-primitives/src/types/receipts.rs +++ b/lake-primitives/src/types/receipts.rs @@ -2,6 +2,18 @@ use crate::near_indexer_primitives::{ types::AccountId, views, CryptoHash, IndexerExecutionOutcomeWithReceipt, }; +/// Simplified representation of the `Receipt`. +/// +/// This is a simplification from the [near_primitives::views::ReceiptView] and [near_primitives::views::ReceiptEnumView] into a more flat structure. +/// The [ReceiptKind] is used to distinguish between the different types of receipts: Action and Data. +/// +/// #### Important notes on the Receipt +/// +/// The original low-level Receipt is represented by the enum that differentiates between the Action and Data receipts. In turn this enum is a field +/// `receipt` in the parent `ReceiptView` struct. +/// Parent structure has a set of fields that are common for both Action and Data receipts. +/// During the simplification we have put the common fields into the [Receipt] struct itself and extracted the `actions` from Action Receipt into a separate struct. +/// Since the high-level NEAR Lake Framework update we encourage developers to create more actions-and-events oriented indexers instead. #[derive(Debug, Clone)] pub struct Receipt { receipt_kind: ReceiptKind, @@ -14,30 +26,46 @@ pub struct Receipt { } impl Receipt { + /// Returns the [ReceiptKind](ReceiptKind) of the receipt. + /// + /// This is a simplification from the [near_primitives::views::ReceiptEnumView::Action] into a more flat structure + /// that has a type. pub fn receipt_kind(&self) -> ReceiptKind { self.receipt_kind.clone() } + /// Returns the [CryptoHash] id of the receipt. pub fn receipt_id(&self) -> CryptoHash { self.receipt_id } + /// Returns the [AccountId] of the receiver of the receipt. pub fn receiver_id(&self) -> AccountId { self.receiver_id.clone() } + /// Returns the [AccountId] of the predecessor of the receipt. pub fn predecessor_id(&self) -> AccountId { self.predecessor_id.clone() } + /// Returns the [ExecutionStatus] of the corresponding ExecutionOutcome. + /// + /// Note that the status will be `Postponed` for the receipts that are included in the block but not executed yet. pub fn status(&self) -> ExecutionStatus { self.status.clone() } + /// Returns the [CryptoHash] id of the corresponding ExecutionOutcome if it exists. + /// + /// Note that this is an optional field because the ExecutionOutcome might not be available + /// if the [Receipt] is "postponed" (included in the block but not executed yet) pub fn execution_outcome_id(&self) -> Option { self.execution_outcome_id } + /// Returns the logs of the corresponding ExecutionOutcome. + /// Might be an empty Vec if the ExecutionOutcome is not available. pub fn logs(&self) -> Vec { self.logs.clone() } @@ -77,9 +105,12 @@ impl From<&views::ReceiptView> for Receipt { } } +/// Represents the Receipt kind: Action or Data. #[derive(Debug, Clone)] pub enum ReceiptKind { + /// For the Action Receipt Action, + /// For the Data Receipt Data, } @@ -92,12 +123,21 @@ impl From<&views::ReceiptEnumView> for ReceiptKind { } } +/// Representation of the execution status for the [Receipt]. #[derive(Debug, Clone)] pub enum ExecutionStatus { + /// Execution succeeded with a value, value is represented by [`Vec`] and literally can be anything. SuccessValue(Vec), + /// Execution succeeded and a result of the execution is a new [Receipt] with the id represented by [CryptoHash] SuccessReceiptId(CryptoHash), // TODO: handle the Failure and all the nested errors it has + /// Execution failed with an error represented by a [String] + /// **WARNINNG!** Here must be our representation of the `TxExecutionError from `near-primitives` instead of the [String]. + /// It requires some additional work on our version of the error, meanwhile we’ve left the [String] here, **this is subject to change + /// in the nearest updates**. Failure(String), + /// Execution hasn’t started yet, it is postponed (delayed) and will be later. + /// The Receipt with such status is considered as postponed too (included, yet not executed) Postponed, } diff --git a/lake-primitives/src/types/state_changes.rs b/lake-primitives/src/types/state_changes.rs index bdb1b99..6e17231 100644 --- a/lake-primitives/src/types/state_changes.rs +++ b/lake-primitives/src/types/state_changes.rs @@ -9,6 +9,7 @@ use crate::near_indexer_primitives::{ CryptoHash, }; +/// Represents the changes to the state of the account. #[derive(Debug, Clone)] pub struct StateChange { affected_account_id: AccountId, @@ -17,14 +18,17 @@ pub struct StateChange { } impl StateChange { + /// Returns the [AccountId] of the account that was affected by the state change. pub fn affected_account_id(&self) -> AccountId { self.affected_account_id.clone() } + /// Returns the [StateChangeCause] of the state change. pub fn cause(&self) -> StateChangeCause { self.cause.clone() } + /// Returns the [StateChangeValue] of the state change. pub fn value(&self) -> StateChangeValue { self.value.clone() } diff --git a/lake-primitives/src/types/transactions.rs b/lake-primitives/src/types/transactions.rs index 40ed03d..c453da1 100644 --- a/lake-primitives/src/types/transactions.rs +++ b/lake-primitives/src/types/transactions.rs @@ -3,6 +3,17 @@ use near_crypto::{PublicKey, Signature}; use super::receipts::ExecutionStatus; use crate::near_indexer_primitives::{types::AccountId, CryptoHash, IndexerTransactionWithOutcome}; +/// High-level representation of the `Transaction`. +/// +/// The structure basically combines the `Transaction` itself and the corresponding `ExecutionOutcome`. +/// **Reminder**: the result of the transaction execution is always a [Receipt](super::receipts::Receipt) +/// that looks pretty much like the `Transaction` itself. +/// +/// #### Important notes on the Transaction +/// +/// Transaction's `actions` are represented by the [Action](super::actions::Action) enum. Actions are +/// included for the informational purpose to help developers to know what exactly should happen after the +/// `Transaction` is executed. #[derive(Debug, Clone)] pub struct Transaction { transaction_hash: CryptoHash, @@ -16,34 +27,42 @@ pub struct Transaction { } impl Transaction { + /// Returns the [CryptoHash] hash of the transaction. pub fn transaction_hash(&self) -> CryptoHash { self.transaction_hash } + /// Returns the [AccountId] of the signer of the transaction. pub fn signer_id(&self) -> &AccountId { &self.signer_id } + /// Returns the [PublicKey] of the signer of the transaction. pub fn signer_public_key(&self) -> &PublicKey { &self.signer_public_key } + /// Returns the [Signature] of the transaction. pub fn signature(&self) -> &Signature { &self.signature } + /// Returns the [AccountId] of the receiver of the transaction. pub fn receiver_id(&self) -> &AccountId { &self.receiver_id } + /// Returns the [ExecutionStatus] of the corresponding ExecutionOutcome. pub fn status(&self) -> &ExecutionStatus { &self.status } + /// Returns the [CryptoHash] id of the corresponding ExecutionOutcome. pub fn execution_outcome_id(&self) -> CryptoHash { self.execution_outcome_id } + /// Returns the [Action](super::actions::Action) of the transaction. pub fn actions_included(&self) -> impl Iterator { self.actions.iter() }