-
Notifications
You must be signed in to change notification settings - Fork 301
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
fix: use simulation to estimate gas used #11211
base: master
Are you sure you want to change the base?
Conversation
a3586fb
to
dc8198a
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.
Looks good! Love to see this API being put to good use. Left a few comments. And yeah, it'd be nice to have a sort-of-unit-test that spins up a reth (instead of an anvil) to test this, as you mentioned today.
const { message } = formatViemError(err, abi); | ||
expect(message).toBe('Test_Error(33)'); |
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.
Love it
} else if (gasConfig.gasLimit) { | ||
gasLimit = this.bumpGasLimit(gasConfig.gasLimit, gasConfig); |
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.
} else if (gasConfig.gasLimit) { | |
gasLimit = this.bumpGasLimit(gasConfig.gasLimit, gasConfig); | |
} else if (gasConfig.gasLimit) { | |
gasLimit = gasConfig.gasLimit; |
I find it confusing that if I set a fixed value, the library then bumps it. I'd expect it to use the exact fixed value I requested. Open to discussion though!
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.
I was on the fence on this, I kept fixedGas
for this purpose but I might just be making it confusing.
The reason was, I wanted to bump the result of simulateGasUsed
in l1-publisher without having a fixed number.
Probably can just extract the gas settings inside l1-publisher though, and multiply it there
} | ||
return receipt; | ||
} | ||
} catch (err) { | ||
if (err instanceof Error && err.message.includes('reverted')) { | ||
throw err; | ||
throw formatViemError(err); |
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.
What happens if we pass something that is not a ViemError
to formatViemError
? I'm worried we may get a non-viem error but still something that contains the string "reverted". But if we're fine sending anything into formatViemError
, no worries then!
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.
yeah probably a good idea to check inside formatViemError
and add a test case for it 👍
yarn-project/ethereum/src/utils.ts
Outdated
if (error instanceof BaseError) { | ||
const revertError = error.walk(err => err instanceof ContractFunctionRevertedError); | ||
if (revertError instanceof ContractFunctionRevertedError) { | ||
const errorName = revertError.data?.errorName ?? ''; |
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.
Can we extract the error selector here if we don't find the errorName
?
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.
huh, I did have a case for that where we extract .signature
, probably lost in the sea of commits 🤦
Good catch, will add back
@@ -983,7 +987,8 @@ export class L1Publisher { | |||
// we will fail estimation in the case where we are simulating for the | |||
// first ethereum block within our slot (as current time is not in the | |||
// slot yet). | |||
const gasGuesstimate = blobEvaluationGas + L1Publisher.PROPOSE_GAS_GUESS; | |||
// const gasGuesstimate = blobEvaluationGas + L1Publisher.PROPOSE_GAS_GUESS; |
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.
Should we delete this and the comment above?
data, | ||
}, | ||
{ | ||
time: timestamp + 1n, |
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.
Let's add a comment why this +1n
// @note we override checkBlob to false since blobs are not part simulate() | ||
stateDiff: [ | ||
{ | ||
slot: toHex(9n, true), |
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'd be nice if we tweaked generate-artifacts.sh
in yarn-project
so we could extract the storage locations from the artifact output. If that ends up being too much, do you think we could add a unit test or something to check that this slot doesn't change?
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.
I think we could probably just use the forge inspect <CONTRACT> storageLayout --json
to populate, then it should be fairly easy to fetch from there. Sounds like a good idea to have.
Its a kinda annoying one though, as ideally the variable itself should not exists 😬.
if (err instanceof MethodNotFoundRpcError || err instanceof MethodNotSupportedRpcError) { | ||
// Node doesn't support simulation, return -1n gas estimate | ||
this.logger?.error('Node does not support simulation API'); | ||
return -1n; |
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.
I'd vote for rethrowing instead of using -1, in case we forget to check for that in the caller and end up propagating an invalid value.
Co-authored-by: Santiago Palladino <[email protected]>
Co-authored-by: Santiago Palladino <[email protected]>
Co-authored-by: Santiago Palladino <[email protected]>
@@ -528,17 +528,19 @@ describe('L1Publisher integration', () => { | |||
await expect(publisher.proposeL2Block(block)).resolves.toEqual(false); | |||
|
|||
// Test for both calls | |||
expect(loggerErrorSpy).toHaveBeenCalledTimes(2); | |||
// NOTE: First error is from the simulate fn, which isn't supported by anvil |
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.
The simulate with time
overrides?
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.
yep
yarn-project/ethereum/src/utils.ts
Outdated
* @param abi - The ABI to use for decoding. | ||
* @returns A FormattedViemError instance. | ||
*/ | ||
export function formatViemError(error: any, abi: Abi = RollupAbi): FormattedViemError { |
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.
I altered the script that we use to generate the artifacts such that the errors should be included inside the other ABIs. So they are in the rollup one or whetever is being used. But maybe it should not be specifically the RollupAbi
that is being checked against here. Mainly if some other contract were used this formatter gets pretty strange.
https://github.com/AztecProtocol/aztec-packages/pull/10697/files
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which | ||
// make time consistency checks break. |
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.
Should not be the case. Also, we should be able to get rid of the validateBlockForSubmission
here if the send can actually simulate it.
// @note we override checkBlob to false since blobs are not part simulate() | ||
stateDiff: [ | ||
{ | ||
slot: toHex(9n, true), |
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.
I think we could probably just use the forge inspect <CONTRACT> storageLayout --json
to populate, then it should be fairly easy to fetch from there. Sounds like a good idea to have.
Its a kinda annoying one though, as ideally the variable itself should not exists 😬.
], | ||
); | ||
|
||
if (simulationResult === -1n) { |
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.
Throwing an error as mentioner earlier would make more sense to me here.
This reverts commit ab9ce34.
Changes to public function bytecode sizes
🧾 Summary (100% most significant diffs)
Full diff report 👇
|
Relevant to #10991 but not 'Fixes' because anvil doesn't support
eth_simulateV1
so we can't yet remove all time-based inputs in L1Fixes #11341
simulate
the 'propose' & 'proposeAndClaim' transactions, using the appropriate timestamp, instead of using hardcoded 12M gas.Follow-up from this: #11390