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

feat(runtime): Track block gas allowance in builtins #4345

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

ekovalev
Copy link
Member

@ekovalev ekovalev commented Nov 18, 2024

Addresses #3752.

The initial implementation of builtin actors overlooked the need of keeping track of the block gas allowance. So far only individual message gas limit has been taken in consideration.

To address this, the way how gas usage is tracked in builtin actors has been modified. Specifically:

  • BuiltinActor::handle method signature has been change to return just a Result<Payload, BuilintActorError and not a tuple with actual gas burned; instead, gas usage is captured by the GasCounter (as a part of mutable context passed as an input to handle);
  • BuiltinActor::max_gas() method has been added to the trait to allow builtin actors report the maximum possible amount of gas that can be burned during a message processing. The handle would only be called if it fits in the current block in the worst possible case based on the max_gas output (similarly to how it is decided whether an extrinsic is added to a block based on its weight). It doesn't have to be 100% accurate, I guess - but better be not too far from real values.

The refactoring has rendered the codebase more readable.

TODO:

  • Fill the max_gas() for every builtin actor with actual values - either through benchmarking or theoretically.

@ekovalev ekovalev added A0-pleasereview PR is ready to be reviewed by the team D2-node Gear Node C1-feature Feature request labels Nov 18, 2024
@ekovalev ekovalev force-pushed the ek-gas-allowance-in-builtins branch 2 times, most recently from 0085e4d to f1257de Compare November 26, 2024 11:21
Copy link
Member

@breathx breathx left a comment

Choose a reason for hiding this comment

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

Generally looks good. Regarding "potential todo" mentioned in the description: nobody should under no circumstances be charged for anything in case of gas allowance exceeded case.

@@ -93,6 +95,9 @@ pub enum BuiltinActorError {
/// Actor's inner error encoded as a String.
#[display(fmt = "Builtin execution resulted in error: {_0}")]
Custom(LimitedStr<'static>),
/// Occurs if a builtin actor execution does not fit in the current block.
#[display(fmt = "Block gas allowance exceeded")]
Copy link
Member

Choose a reason for hiding this comment

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

Im wondering If we could abstract it since it more about how system implemented rather than each particular builtin

}

gas_spent += to_spend;
gas_left -= to_spend;
Copy link
Member

Choose a reason for hiding this comment

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

saturating?

Copy link
Member Author

Choose a reason for hiding this comment

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

Safe due to a check above - if gas_left is less than to_spend we abort earlier

Copy link
Member Author

Choose a reason for hiding this comment

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

But for the sake of universality we can use saturated arithmetics - no problem

}

gas_spent += to_spend;
gas_left -= to_spend;
Copy link
Member

Choose a reason for hiding this comment

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

here and in other places

Copy link
Member

@gshep gshep left a comment

Choose a reason for hiding this comment

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

Good job! 🥇

@breathx breathx added A3-gotissues PR occurred to have issues after the review and removed A0-pleasereview PR is ready to be reviewed by the team labels Nov 27, 2024
@breathx
Copy link
Member

breathx commented Nov 27, 2024

discussed

@ekovalev ekovalev force-pushed the ek-gas-allowance-in-builtins branch from f1257de to 4ab1f6e Compare December 10, 2024 10:19
@ekovalev ekovalev requested a review from gshep December 10, 2024 10:46
@ekovalev ekovalev added A0-pleasereview PR is ready to be reviewed by the team C2-refactoring Refactoring proposal and removed A3-gotissues PR occurred to have issues after the review labels Dec 10, 2024
@ekovalev ekovalev requested a review from breathx December 10, 2024 10:49
@ekovalev ekovalev force-pushed the ek-gas-allowance-in-builtins branch from 4ab1f6e to 0029069 Compare December 10, 2024 15:46
pub type HandleFn<C, E> = dyn Fn(&StoredDispatch, &mut C) -> Result<Payload, E>;

/// Builtin actor `max_gas` function signature.
// TODO: let the weight function take a complexity argument similar to extrinsics weight functions
Copy link
Member

Choose a reason for hiding this comment

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

Sounds like a new epic story so definitely needs an issue =)

}
}

/// TODO:
Copy link
Member

Choose a reason for hiding this comment

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

It would be nice to have some description

context: &mut BuiltinContext,
) -> Result<Payload, BuiltinActorError>;

/// Returns the maximum gas that can be spent by the actor.
Copy link
Member

Choose a reason for hiding this comment

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

Does zero value get interpreted in special way?

Copy link
Member Author

@ekovalev ekovalev Dec 12, 2024

Choose a reason for hiding this comment

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

Does zero value get interpreted in special way?

Not really: it'll just always pass the "initial screening" in the BuiltinDispatcher, but checks inside the handle() still remain (every time the gas counter is charged). However, if the max_gas() reports an accurate estimation, the handle would be skipped entirely and message re-queued. In the latter case we are certain no gas is going to be wasted as opposed to the situation if we still have to requeue the message after all, but only know it half way down inside the handle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A0-pleasereview PR is ready to be reviewed by the team C1-feature Feature request C2-refactoring Refactoring proposal D2-node Gear Node
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants