Commit 1ca1d81b authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Share providers across different game instances (#10305)

Avoids loading the full state to extract the commitment for each individual game.
parent b23d3f67
......@@ -268,6 +268,13 @@ func registerCannon(
} else {
prestateSource = prestates.NewSinglePrestateSource(cfg.CannonAbsolutePreState)
}
prestateProviderCache := prestates.NewPrestateProviderCache(m, fmt.Sprintf("prestates-%v", gameType), func(prestateHash common.Hash) (faultTypes.PrestateProvider, error) {
prestatePath, err := prestateSource.PrestatePath(prestateHash)
if err != nil {
return nil, fmt.Errorf("required prestate %v not available: %w", prestateHash, err)
}
return cannon.NewPrestateProvider(prestatePath), nil
})
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract := contracts.NewFaultDisputeGameContract(m, game.Proxy, caller)
requiredPrestatehash, err := contract.GetAbsolutePrestateHash(ctx)
......@@ -275,11 +282,11 @@ func registerCannon(
return nil, fmt.Errorf("failed to load prestate hash for game %v: %w", game.Proxy, err)
}
prestatePath, err := prestateSource.PrestatePath(requiredPrestatehash)
cannonPrestateProvider, err := prestateProviderCache.GetOrCreate(requiredPrestatehash)
if err != nil {
return nil, fmt.Errorf("required prestate %v not available for game %v: %w", requiredPrestatehash, game.Proxy, err)
}
cannonPrestateProvider := cannon.NewPrestateProvider(prestatePath)
oracle, err := contract.GetOracle(ctx)
if err != nil {
......
package prestates
import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/sources/caching"
"github.com/ethereum/go-ethereum/common"
)
type PrestateSource interface {
// PrestatePath returns the path to the prestate file to use for the game.
// The provided prestateHash may be used to differentiate between different states but no guarantee is made that
// the returned prestate matches the supplied hash.
PrestatePath(prestateHash common.Hash) (string, error)
}
type PrestateProviderCache struct {
createProvider func(prestateHash common.Hash) (types.PrestateProvider, error)
cache *caching.LRUCache[common.Hash, types.PrestateProvider]
}
func NewPrestateProviderCache(m caching.Metrics, label string, createProvider func(prestateHash common.Hash) (types.PrestateProvider, error)) *PrestateProviderCache {
return &PrestateProviderCache{
createProvider: createProvider,
cache: caching.NewLRUCache[common.Hash, types.PrestateProvider](m, label, 5),
}
}
func (p *PrestateProviderCache) GetOrCreate(prestateHash common.Hash) (types.PrestateProvider, error) {
provider, ok := p.cache.Get(prestateHash)
if ok {
return provider, nil
}
provider, err := p.createProvider(prestateHash)
if err != nil {
return nil, err
}
p.cache.Add(prestateHash, provider)
return provider, nil
}
package prestates
import (
"context"
"errors"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestPrestateProviderCache_CreateAndCache(t *testing.T) {
cache := NewPrestateProviderCache(nil, "", func(prestateHash common.Hash) (types.PrestateProvider, error) {
return &stubPrestateProvider{commitment: prestateHash}, nil
})
hash1 := common.Hash{0xaa}
hash2 := common.Hash{0xbb}
provider1a, err := cache.GetOrCreate(hash1)
require.NoError(t, err)
commitment, err := provider1a.AbsolutePreStateCommitment(context.Background())
require.NoError(t, err)
require.Equal(t, hash1, commitment)
provider1b, err := cache.GetOrCreate(hash1)
require.NoError(t, err)
require.Same(t, provider1a, provider1b)
commitment, err = provider1b.AbsolutePreStateCommitment(context.Background())
require.NoError(t, err)
require.Equal(t, hash1, commitment)
provider2, err := cache.GetOrCreate(hash2)
require.NoError(t, err)
require.NotSame(t, provider1a, provider2)
commitment, err = provider2.AbsolutePreStateCommitment(context.Background())
require.NoError(t, err)
require.Equal(t, hash2, commitment)
}
func TestPrestateProviderCache_CreateFails(t *testing.T) {
hash1 := common.Hash{0xaa}
expectedErr := errors.New("boom")
cache := NewPrestateProviderCache(nil, "", func(prestateHash common.Hash) (types.PrestateProvider, error) {
return nil, expectedErr
})
provider, err := cache.GetOrCreate(hash1)
require.ErrorIs(t, err, expectedErr)
require.Nil(t, provider)
}
type stubPrestateProvider struct {
commitment common.Hash
}
func (s *stubPrestateProvider) AbsolutePreStateCommitment(_ context.Context) (common.Hash, error) {
return s.commitment, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment