Skip to content

fix(op-challenger): Absolute Prestate Provider Refactor#8453

Closed
refcell wants to merge 3 commits intodevelopfrom
refcell/prestate-provider
Closed

fix(op-challenger): Absolute Prestate Provider Refactor#8453
refcell wants to merge 3 commits intodevelopfrom
refcell/prestate-provider

Conversation

@refcell
Copy link
Contributor

@refcell refcell commented Dec 5, 2023

Description

Refactors the absolute prestate logic out of the trace provider to hoist its construction to the registry.

Constructing the new PrestateProvider in the registry creator functions is more lightweight than
instantiating 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.

@refcell refcell self-assigned this Dec 5, 2023
@refcell
Copy link
Contributor Author

refcell commented Dec 5, 2023

@semgrep-app
Copy link
Contributor

semgrep-app bot commented Dec 6, 2023

Semgrep found 1 todos_require_linear finding:

  • op-node/rollup/derive/calldata_source.go: L53

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
@refcell refcell force-pushed the refcell/absolute-prestate-validation branch from 079a695 to 2ac6817 Compare December 6, 2023 17:10
@refcell refcell requested a review from ajsutton December 6, 2023 17:11
@refcell refcell force-pushed the refcell/prestate-provider branch from 3331ccf to bb5a8b9 Compare December 6, 2023 17:12
@refcell refcell marked this pull request as ready for review December 6, 2023 17:12
@refcell refcell requested a review from a team as a code owner December 6, 2023 17:12
@refcell refcell requested review from Inphi and clabby December 6, 2023 17:15
Copy link
Contributor

@ajsutton ajsutton left a comment

Choose a reason for hiding this comment

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

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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

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)
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cc @clabby

}

func (o *OutputPrestateProvider) AbsolutePreStateCommitment(ctx context.Context) (hash common.Hash, err error) {
return o.outputAtBlock(ctx, o.prestateBlock)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be returning the prestate of the bottom half of the game (the prestate for the cannon or alphabet VM).

Comment on lines +15 to +33
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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

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) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We're missing tests for GenesisOutputRoot.

Comment on lines +71 to +77
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)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

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)
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

@refcell
Copy link
Contributor Author

refcell commented Dec 6, 2023

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.

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" :/

@refcell refcell force-pushed the refcell/absolute-prestate-validation branch 2 times, most recently from 197aba1 to 74a4849 Compare December 7, 2023 03:04
Base automatically changed from refcell/absolute-prestate-validation to develop December 7, 2023 03:40
@refcell refcell closed this Dec 7, 2023
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