-
Notifications
You must be signed in to change notification settings - Fork 104
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
base: master
Are you sure you want to change the base?
Conversation
0085e4d
to
f1257de
Compare
There was a problem hiding this 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")] |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
saturating?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job! 🥇
discussed |
f1257de
to
4ab1f6e
Compare
4ab1f6e
to
0029069
Compare
pallets/gear/src/builtin.rs
Outdated
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 |
There was a problem hiding this comment.
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 =)
pallets/gear-builtin/src/lib.rs
Outdated
} | ||
} | ||
|
||
/// TODO: |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
.
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 aResult<Payload, BuilintActorError
and not a tuple with actual gas burned; instead, gas usage is captured by theGasCounter
(as a part of mutablecontext
passed as an input tohandle
);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. Thehandle
would only be called if it fits in the current block in the worst possible case based on themax_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:
max_gas()
for every builtin actor with actual values - either through benchmarking or theoretically.