Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(high-level): Don't require &mut Block to improve the API for developers #93

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

khorolets
Copy link
Member

Recently, I've received feedback about the usage of high-level updates.

It is impossible to use the framework like this:

for action in block.actions() {
        if action.receiver_id() == ctx.contract_id {
            let receipt = block.receipt_by_id(&action.receipt_id()).unwrap();
...

The reason is that we require the block to be &mut Block. I did it because I attempted to keep the Block size lower. I intended to empty some fields (receipts, transactions, state_changes, etc.) and set the value to them on demand. For example, a developer does block.transactions(). We extract the transactions from the underlying block if the value is empty.streamer_message: StreamerMessage.
While I still believe that idea makes some sense, this adds inconveniences to other places. It does not make sense to attempt to save a small amount of bytes and ruin the DevEx.

In this PR, I made the Block structure to have all the data at the time of the conversion from the StreamerMessage. This allows me to eliminate the requirement to deal with &mut Block and makes the code above possible to use without redundant clone().

Feedback is welcome, meanwhile, I need to revisit the doc side for the leftover referrals to the &mut Block and correct them.

@khorolets
Copy link
Member Author

I talked to @frol, and we agreed that parsing events and storing them in the Block is the heaviest operation that most developers might not need.

Instead of parsing all the logs for the events, we will do it on demand when Block.events() is called. Developers might build the cache layer for the events on top if needed, the framework is not going to handle it.

@khorolets khorolets marked this pull request as ready for review December 8, 2023 11:52
.map(Into::into)
.collect();
}
pub fn receipts(&self) -> impl Iterator<Item = &receipts::Receipt> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a strong need to return an iterator? I would just return a slice whenever possible:

Suggested change
pub fn receipts(&self) -> impl Iterator<Item = &receipts::Receipt> {
pub fn receipts(&self) -> &[receipts::Receipt] {
&self.executed_receipts

&self,
account_id: &crate::near_indexer_primitives::types::AccountId,
) -> Vec<events::Event> {
let account_id_clone = account_id.clone(); // Clone the account_id
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to clone it at all, just use the account_id below

Comment on lines +104 to +105
/// Returns a Vec of [Events](crate::events::Event) emitted in the [Block]
pub fn events(&self) -> HashMap<super::ReceiptId, Vec<events::Event>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc and the return value are out of sync. I would keep the original return value (iterator)

}
if let Some(events) = self.events.get(receipt_id) {
pub fn events_by_receipt_id(&self, receipt_id: &super::ReceiptId) -> Vec<events::Event> {
if let Some(events) = self.events().get(receipt_id) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is faster to execute and easier to maintain:

self.receipt_by_id(receipt_id)
    .map(|receipt| receipt.events())
    .unwrap_or_default()

Comment on lines +144 to +147
.values()
.flatten()
.filter(|event| event.is_emitted_by_contract(&account_id_clone))
.map(Clone::clone)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to point out that you turned .events() to return HashMap only to turn it into an iterator of values and flatten them... Revert the changes here, the old implementation was good (except the unnecessary cloning of account_id

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants