fix(op-challenger): Absolute Prestate Provider Refactor#8453
fix(op-challenger): Absolute Prestate Provider Refactor#8453
Conversation
|
Current dependencies on/for this PR:
This stack of pull requests is managed by Graphite. |
2696744 to
079a695
Compare
df0ea57 to
1928de1
Compare
|
Semgrep found 1
Please create a GitHub ticket for this TODO. Ignore this finding from todos_require_linear. |
providers. fix(op-challenger): genesis output root validation for top of output bisection games genesis output root test
079a695 to
2ac6817
Compare
3331ccf to
bb5a8b9
Compare
ajsutton
left a comment
There was a problem hiding this comment.
I think the basic approach of splitting out a prestate provider is good, but there's some confusion about what the prestate is that we'll need to fix up.
My suggestion would be to do this in a few small steps rather than stacking on the other PR. So the first thing would be to just pull the AbsolutePrestateCommitment function into a PrestateProvider interface and pull the existing functions from each TraceProvider implementation into a separate struct - like you've done with:
type CannonTraceProvider struct {
CannonPrestateProvider
We can merge that as a simple refactoring to separate two concerns.
Then I think I'd look at introducing a ValidatePrestate method to the GamePlayer interface. There's some interesting design challenges to make the right components available there but I think it's where we need to get to so that validation is nicely encapsulated rather than having to be in register.go.
Assuming we can get there, it would then be easy to trigger the validation in coordinator when it creates the player.
| }, nil | ||
| } | ||
|
|
||
| func NewPrestateProviderFromInputs(logger log.Logger, rollupClient OutputRollupClient, prestateBlock uint64) *OutputPrestateProvider { |
There was a problem hiding this comment.
This is unused so can probably be removed. And the logger param is unused if there's a good reason for keeping the method around (maybe it should be used in the test?)
| } | ||
|
|
||
| func (o *OutputPrestateProvider) GenesisOutputRoot(ctx context.Context) (hash common.Hash, err error) { | ||
| return o.outputAtBlock(ctx, 0) |
There was a problem hiding this comment.
I don't think we want to check the genesis block at all. When the contracts say "genesis" they mean the absolute pre-state block which is the bedrock block on OP Mainnet.
| } | ||
|
|
||
| func (o *OutputPrestateProvider) AbsolutePreStateCommitment(ctx context.Context) (hash common.Hash, err error) { | ||
| return o.outputAtBlock(ctx, o.prestateBlock) |
There was a problem hiding this comment.
This should be returning the prestate of the bottom half of the game (the prestate for the cannon or alphabet VM).
| func ValidateGenesisOutputRoot(ctx context.Context, provider types.PrestateProvider, loader HashLoader) error { | ||
| providerGenesisOutputRoot, err := provider.GenesisOutputRoot(ctx) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to get the trace provider's genesis output root: %w", err) | ||
| } | ||
| onchainGenesisOutputRoot, err := loader(ctx) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to get the onchain genesis output root: %w", err) | ||
| } | ||
| if !bytes.Equal(providerGenesisOutputRoot[:], onchainGenesisOutputRoot[:]) { | ||
| return fmt.Errorf("provider's genesis output root does not match onchain genesis output root: Provider: %s | Chain %s", providerGenesisOutputRoot.Hex(), onchainGenesisOutputRoot.Hex()) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // ValidateAbsolutePrestate validates the absolute prestate of the fault game. | ||
| func ValidateAbsolutePrestate(ctx context.Context, provider types.PrestateProvider, loader HashLoader) error { | ||
| providerPrestateHash, err := provider.AbsolutePreStateCommitment(ctx) | ||
| if err != nil { |
There was a problem hiding this comment.
I think these are fundamentally the same function. They're calling a different method on the provider, but that could just be passed in as a function instead of passing the interface but the comparison logic is all the same and would probably be good to deduplicate.
| }, &rollupClient | ||
| } | ||
|
|
||
| func TestAbsolutePreStateCommitment(t *testing.T) { |
There was a problem hiding this comment.
We're missing tests for GenesisOutputRoot.
| type PrestateProvider interface { | ||
| // AbsolutePreStateCommitment is the commitment of the pre-image value of the trace that transitions to the trace value at index 0 | ||
| AbsolutePreStateCommitment(ctx context.Context) (hash common.Hash, err error) | ||
|
|
||
| // GenesisOutputRoot is the output root of the provider at genesis. | ||
| GenesisOutputRoot(ctx context.Context) (hash common.Hash, err error) | ||
| } |
There was a problem hiding this comment.
I think this should just have AbsolutePreStateCommitment as its only method. For the output root bisection the absolute prestate commitment is the prestate block output root (which will be either genesis block or bedrock activation block). For the VM it's the pre-state hash.
So for a split game there are two trace providers (output roots and VM) and each has an absolute prestate that we need to verify.
| ) (*trace.Accessor, error) { | ||
| bottomDepth := gameDepth - splitDepth | ||
| outputProvider, err := NewTraceProvider(ctx, logger, cfg.RollupRpc, splitDepth, prestateBlock, poststateBlock) | ||
| rollupClient, err := dial.DialRollupClientWithTimeout(ctx, dial.DefaultDialTimeout, logger, cfg.RollupRpc) |
There was a problem hiding this comment.
oof, we're not closing this properly and its the same in cannon. We'll need to fix that - logged https://github.com/ethereum-optimism/client-pod/issues/321
We can live with this code as is for now given it's already done that way for output_cannon anyway.
I don't think there is confusion about what the prestate is? For output bisection we need to verify both the absolute prestate commitment hash for the execution trace provider and the genesis output root for the top output provider. Looping in @clabby to verify but this isn't "confusion" :/ |
197aba1 to
74a4849
Compare

Description
Refactors the absolute prestate logic out of the trace provider to hoist its construction to the registry.
Constructing the new
PrestateProviderin the registry creator functions is more lightweight thaninstantiating the trace provider and maintains separation of concerns, leaving the trace provider
construction in the trace package register functions.
This PR also splits genesis output root validation and absolute prestate commitment hash validation
logic in separate functions in a new source file with full test coverage.