Commit d96975f2 authored by refcell.eth's avatar refcell.eth Committed by GitHub

fix(op-challenger): call squeeze after the challenge period elapses (#9226)

parent cba80384
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/game" "github.com/ethereum-optimism/optimism/op-challenger/game"
"github.com/ethereum-optimism/optimism/op-service/cliapp" "github.com/ethereum-optimism/optimism/op-service/cliapp"
"github.com/ethereum-optimism/optimism/op-service/clock"
) )
// Main is the programmatic entry-point for running op-challenger with a given configuration. // Main is the programmatic entry-point for running op-challenger with a given configuration.
...@@ -15,6 +16,6 @@ func Main(ctx context.Context, logger log.Logger, cfg *config.Config) (cliapp.Li ...@@ -15,6 +16,6 @@ func Main(ctx context.Context, logger log.Logger, cfg *config.Config) (cliapp.Li
if err := cfg.Check(); err != nil { if err := cfg.Check(); err != nil {
return nil, err return nil, err
} }
srv, err := game.NewService(ctx, logger, cfg) srv, err := game.NewService(ctx, clock.SystemClock, logger, cfg)
return srv, err return srv, err
} }
...@@ -32,6 +32,7 @@ const ( ...@@ -32,6 +32,7 @@ const (
methodMinProposalSize = "minProposalSize" methodMinProposalSize = "minProposalSize"
methodChallengeFirstLPP = "challengeFirstLPP" methodChallengeFirstLPP = "challengeFirstLPP"
methodChallengeLPP = "challengeLPP" methodChallengeLPP = "challengeLPP"
methodChallengePeriod = "challengePeriod"
) )
var ( var (
...@@ -86,6 +87,24 @@ func (c *PreimageOracleContract) AddLeaves(uuid *big.Int, startingBlockIndex *bi ...@@ -86,6 +87,24 @@ func (c *PreimageOracleContract) AddLeaves(uuid *big.Int, startingBlockIndex *bi
return call.ToTxCandidate() return call.ToTxCandidate()
} }
// MinLargePreimageSize returns the minimum size of a large preimage.
func (c *PreimageOracleContract) MinLargePreimageSize(ctx context.Context) (uint64, error) {
result, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, c.contract.Call(methodMinProposalSize))
if err != nil {
return 0, fmt.Errorf("failed to fetch min lpp size bytes: %w", err)
}
return result.GetBigInt(0).Uint64(), nil
}
// ChallengePeriod returns the challenge period for large preimages.
func (c *PreimageOracleContract) ChallengePeriod(ctx context.Context) (uint64, error) {
result, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, c.contract.Call(methodChallengePeriod))
if err != nil {
return 0, fmt.Errorf("failed to fetch challenge period: %w", err)
}
return result.GetBigInt(0).Uint64(), nil
}
func (c *PreimageOracleContract) CallSqueeze( func (c *PreimageOracleContract) CallSqueeze(
ctx context.Context, ctx context.Context,
claimant common.Address, claimant common.Address,
...@@ -99,7 +118,7 @@ func (c *PreimageOracleContract) CallSqueeze( ...@@ -99,7 +118,7 @@ func (c *PreimageOracleContract) CallSqueeze(
call := c.contract.Call(methodSqueezeLPP, claimant, uuid, abiEncodeStateMatrix(stateMatrix), toPreimageOracleLeaf(preState), preStateProof, toPreimageOracleLeaf(postState), postStateProof) call := c.contract.Call(methodSqueezeLPP, claimant, uuid, abiEncodeStateMatrix(stateMatrix), toPreimageOracleLeaf(preState), preStateProof, toPreimageOracleLeaf(postState), postStateProof)
_, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, call) _, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, call)
if err != nil { if err != nil {
return fmt.Errorf("failed to call resolve claim: %w", err) return fmt.Errorf("failed to call squeeze: %w", err)
} }
return nil return nil
} }
...@@ -140,15 +159,6 @@ func abiEncodePackedState(packedState []byte) bindings.LibKeccakStateMatrix { ...@@ -140,15 +159,6 @@ func abiEncodePackedState(packedState []byte) bindings.LibKeccakStateMatrix {
return bindings.LibKeccakStateMatrix{State: *stateSlice} return bindings.LibKeccakStateMatrix{State: *stateSlice}
} }
// MinLargePreimageSize returns the minimum size of a large preimage.
func (c *PreimageOracleContract) MinLargePreimageSize(ctx context.Context) (uint64, error) {
result, err := c.multiCaller.SingleCall(ctx, batching.BlockLatest, c.contract.Call(methodMinProposalSize))
if err != nil {
return 0, fmt.Errorf("failed to fetch min lpp size bytes: %w", err)
}
return result.GetBigInt(0).Uint64(), nil
}
func (c *PreimageOracleContract) GetActivePreimages(ctx context.Context, blockHash common.Hash) ([]keccakTypes.LargePreimageMetaData, error) { func (c *PreimageOracleContract) GetActivePreimages(ctx context.Context, blockHash common.Hash) ([]keccakTypes.LargePreimageMetaData, error) {
block := batching.BlockByHash(blockHash) block := batching.BlockByHash(blockHash)
results, err := batching.ReadArray(ctx, c.multiCaller, block, c.contract.Call(methodProposalCount), func(i *big.Int) *batching.ContractCall { results, err := batching.ReadArray(ctx, c.multiCaller, block, c.contract.Call(methodProposalCount), func(i *big.Int) *batching.ContractCall {
......
...@@ -37,6 +37,28 @@ func TestPreimageOracleContract_LoadKeccak256(t *testing.T) { ...@@ -37,6 +37,28 @@ func TestPreimageOracleContract_LoadKeccak256(t *testing.T) {
stubRpc.VerifyTxCandidate(tx) stubRpc.VerifyTxCandidate(tx)
} }
func TestPreimageOracleContract_ChallengePeriod(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
stubRpc.SetResponse(oracleAddr, methodChallengePeriod, batching.BlockLatest,
[]interface{}{},
[]interface{}{big.NewInt(123)},
)
challengePeriod, err := oracle.ChallengePeriod(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(123), challengePeriod)
}
func TestPreimageOracleContract_MinLargePreimageSize(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
stubRpc.SetResponse(oracleAddr, methodMinProposalSize, batching.BlockLatest,
[]interface{}{},
[]interface{}{big.NewInt(123)},
)
minProposalSize, err := oracle.MinLargePreimageSize(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(123), minProposalSize)
}
func TestPreimageOracleContract_PreimageDataExists(t *testing.T) { func TestPreimageOracleContract_PreimageDataExists(t *testing.T) {
t.Run("exists", func(t *testing.T) { t.Run("exists", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t) stubRpc, oracle := setupPreimageOracleTest(t)
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -43,6 +44,7 @@ type resourceCreator func(ctx context.Context, logger log.Logger, gameDepth type ...@@ -43,6 +44,7 @@ type resourceCreator func(ctx context.Context, logger log.Logger, gameDepth type
func NewGamePlayer( func NewGamePlayer(
ctx context.Context, ctx context.Context,
cl clock.Clock,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
dir string, dir string,
...@@ -93,7 +95,7 @@ func NewGamePlayer( ...@@ -93,7 +95,7 @@ func NewGamePlayer(
return nil, fmt.Errorf("failed to load min large preimage size: %w", err) return nil, fmt.Errorf("failed to load min large preimage size: %w", err)
} }
direct := preimages.NewDirectPreimageUploader(logger, txSender, loader) direct := preimages.NewDirectPreimageUploader(logger, txSender, loader)
large := preimages.NewLargePreimageUploader(logger, txSender, oracle) large := preimages.NewLargePreimageUploader(logger, cl, txSender, oracle)
uploader := preimages.NewSplitPreimageUploader(direct, large, minLargePreimageSize) uploader := preimages.NewSplitPreimageUploader(direct, large, minLargePreimageSize)
responder, err := responder.NewFaultResponder(logger, txSender, loader, uploader, oracle) responder, err := responder.NewFaultResponder(logger, txSender, loader, uploader, oracle)
if err != nil { if err != nil {
......
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/keccak/matrix" "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/matrix"
keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types" keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
...@@ -21,6 +22,9 @@ import ( ...@@ -21,6 +22,9 @@ import (
var _ PreimageUploader = (*LargePreimageUploader)(nil) var _ PreimageUploader = (*LargePreimageUploader)(nil)
// ErrChallengePeriodNotOver is returned when the challenge period is not over.
var ErrChallengePeriodNotOver = errors.New("challenge period not over")
// MaxBlocksPerChunk is the maximum number of keccak blocks per chunk. // MaxBlocksPerChunk is the maximum number of keccak blocks per chunk.
const MaxBlocksPerChunk = 300 const MaxBlocksPerChunk = 300
...@@ -35,12 +39,13 @@ const MaxChunkSize = MaxBlocksPerChunk * keccakTypes.BlockSize ...@@ -35,12 +39,13 @@ const MaxChunkSize = MaxBlocksPerChunk * keccakTypes.BlockSize
type LargePreimageUploader struct { type LargePreimageUploader struct {
log log.Logger log log.Logger
clock clock.Clock
txSender gameTypes.TxSender txSender gameTypes.TxSender
contract PreimageOracleContract contract PreimageOracleContract
} }
func NewLargePreimageUploader(logger log.Logger, txSender gameTypes.TxSender, contract PreimageOracleContract) *LargePreimageUploader { func NewLargePreimageUploader(logger log.Logger, cl clock.Clock, txSender gameTypes.TxSender, contract PreimageOracleContract) *LargePreimageUploader {
return &LargePreimageUploader{logger, txSender, contract} return &LargePreimageUploader{logger, cl, txSender, contract}
} }
func (p *LargePreimageUploader) UploadPreimage(ctx context.Context, parent uint64, data *types.PreimageOracleData) error { func (p *LargePreimageUploader) UploadPreimage(ctx context.Context, parent uint64, data *types.PreimageOracleData) error {
...@@ -125,11 +130,24 @@ func (p *LargePreimageUploader) Squeeze(ctx context.Context, uuid *big.Int, stat ...@@ -125,11 +130,24 @@ func (p *LargePreimageUploader) Squeeze(ctx context.Context, uuid *big.Int, stat
if err != nil { if err != nil {
return fmt.Errorf("failed to generate poststate proof: %w", err) return fmt.Errorf("failed to generate poststate proof: %w", err)
} }
// TODO(client-pod#474): Return the ErrChallengePeriodNotOver error if the challenge period is not over. challengePeriod, err := p.contract.ChallengePeriod(ctx)
// This allows the responder to retry the squeeze later. if err != nil {
// Other errors should force the responder to stop retrying. return fmt.Errorf("failed to get challenge period: %w", err)
// Nil errors should indicate the squeeze was successful. }
currentTimestamp := p.clock.Now().Unix()
ident := keccakTypes.LargePreimageIdent{Claimant: p.txSender.From(), UUID: uuid}
metadata, err := p.contract.GetProposalMetadata(ctx, batching.BlockLatest, ident)
if err != nil {
return fmt.Errorf("failed to get pre-image oracle metadata: %w", err)
}
if len(metadata) == 0 || metadata[0].ClaimedSize == 0 {
return fmt.Errorf("no metadata found for pre-image oracle with uuid: %s", uuid)
}
if uint64(currentTimestamp) < metadata[0].Timestamp+challengePeriod {
return ErrChallengePeriodNotOver
}
if err := p.contract.CallSqueeze(ctx, p.txSender.From(), uuid, stateMatrix, prestate, prestateProof, poststate, poststateProof); err != nil { if err := p.contract.CallSqueeze(ctx, p.txSender.From(), uuid, stateMatrix, prestate, prestateProof, poststate, poststateProof); err != nil {
p.log.Debug("expected a successful squeeze call", "metadataTimestamp", metadata[0].Timestamp, "currentTimestamp", currentTimestamp, "err", err)
return fmt.Errorf("failed to call squeeze: %w", err) return fmt.Errorf("failed to call squeeze: %w", err)
} }
tx, err := p.contract.Squeeze(p.txSender.From(), uuid, stateMatrix, prestate, prestateProof, poststate, poststateProof) tx, err := p.contract.Squeeze(p.txSender.From(), uuid, stateMatrix, prestate, prestateProof, poststate, poststateProof)
......
...@@ -5,11 +5,13 @@ import ( ...@@ -5,11 +5,13 @@ import (
"errors" "errors"
"math/big" "math/big"
"testing" "testing"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/keccak/matrix" "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/matrix"
"github.com/ethereum-optimism/optimism/op-challenger/game/keccak/merkle" "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/merkle"
keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types" keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
...@@ -19,6 +21,7 @@ import ( ...@@ -19,6 +21,7 @@ import (
) )
var ( var (
mockChallengePeriod = uint64(10000000)
mockAddLeavesError = errors.New("mock add leaves error") mockAddLeavesError = errors.New("mock add leaves error")
mockSqueezeError = errors.New("mock squeeze error") mockSqueezeError = errors.New("mock squeeze error")
mockSqueezeCallError = errors.New("mock squeeze call error") mockSqueezeCallError = errors.New("mock squeeze call error")
...@@ -63,7 +66,7 @@ func TestLargePreimageUploader_NewUUID(t *testing.T) { ...@@ -63,7 +66,7 @@ func TestLargePreimageUploader_NewUUID(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
oracle, _, _ := newTestLargePreimageUploader(t) oracle, _, _, _ := newTestLargePreimageUploader(t)
uuid := oracle.newUUID(test.data) uuid := oracle.newUUID(test.data)
require.Equal(t, test.expectedUUID, uuid) require.Equal(t, test.expectedUUID, uuid)
}) })
...@@ -72,7 +75,7 @@ func TestLargePreimageUploader_NewUUID(t *testing.T) { ...@@ -72,7 +75,7 @@ func TestLargePreimageUploader_NewUUID(t *testing.T) {
func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
t.Run("InitFails", func(t *testing.T) { t.Run("InitFails", func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t) oracle, _, _, contract := newTestLargePreimageUploader(t)
contract.initFails = true contract.initFails = true
data := mockPreimageOracleData() data := mockPreimageOracleData()
err := oracle.UploadPreimage(context.Background(), 0, &data) err := oracle.UploadPreimage(context.Background(), 0, &data)
...@@ -81,7 +84,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -81,7 +84,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
}) })
t.Run("AddLeavesFails", func(t *testing.T) { t.Run("AddLeavesFails", func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t) oracle, _, _, contract := newTestLargePreimageUploader(t)
contract.addFails = true contract.addFails = true
data := mockPreimageOracleData() data := mockPreimageOracleData()
err := oracle.UploadPreimage(context.Background(), 0, &data) err := oracle.UploadPreimage(context.Background(), 0, &data)
...@@ -90,8 +93,9 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -90,8 +93,9 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
}) })
t.Run("NoBytesProcessed", func(t *testing.T) { t.Run("NoBytesProcessed", func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t) oracle, _, _, contract := newTestLargePreimageUploader(t)
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.claimedSize = uint32(len(data.OracleData))
err := oracle.UploadPreimage(context.Background(), 0, &data) err := oracle.UploadPreimage(context.Background(), 0, &data)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, contract.initCalls) require.Equal(t, 1, contract.initCalls)
...@@ -100,7 +104,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -100,7 +104,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
}) })
t.Run("AlreadyInitialized", func(t *testing.T) { t.Run("AlreadyInitialized", func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t) oracle, _, _, contract := newTestLargePreimageUploader(t)
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.initialized = true contract.initialized = true
contract.claimedSize = uint32(len(data.OracleData)) contract.claimedSize = uint32(len(data.OracleData))
...@@ -110,8 +114,24 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -110,8 +114,24 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
require.Equal(t, 6, contract.addCalls) require.Equal(t, 6, contract.addCalls)
}) })
t.Run("ChallengePeriodNotElapsed", func(t *testing.T) {
oracle, cl, _, contract := newTestLargePreimageUploader(t)
data := mockPreimageOracleData()
contract.bytesProcessed = 5*MaxChunkSize + 1
contract.claimedSize = uint32(len(data.OracleData))
contract.timestamp = uint64(cl.Now().Unix())
err := oracle.UploadPreimage(context.Background(), 0, &data)
require.ErrorIs(t, err, ErrChallengePeriodNotOver)
require.Equal(t, 0, contract.squeezeCalls)
// Squeeze should be called once the challenge period has elapsed.
cl.AdvanceTime(time.Duration(mockChallengePeriod) * time.Second)
err = oracle.UploadPreimage(context.Background(), 0, &data)
require.NoError(t, err)
require.Equal(t, 1, contract.squeezeCalls)
})
t.Run("SqueezeCallFails", func(t *testing.T) { t.Run("SqueezeCallFails", func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t) oracle, _, _, contract := newTestLargePreimageUploader(t)
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.bytesProcessed = 5*MaxChunkSize + 1 contract.bytesProcessed = 5*MaxChunkSize + 1
contract.timestamp = 123 contract.timestamp = 123
...@@ -123,7 +143,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -123,7 +143,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
}) })
t.Run("SqueezeFails", func(t *testing.T) { t.Run("SqueezeFails", func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t) oracle, _, _, contract := newTestLargePreimageUploader(t)
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.bytesProcessed = 5*MaxChunkSize + 1 contract.bytesProcessed = 5*MaxChunkSize + 1
contract.timestamp = 123 contract.timestamp = 123
...@@ -135,7 +155,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -135,7 +155,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
}) })
t.Run("AllBytesProcessed", func(t *testing.T) { t.Run("AllBytesProcessed", func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t) oracle, _, _, contract := newTestLargePreimageUploader(t)
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.bytesProcessed = 5*MaxChunkSize + 1 contract.bytesProcessed = 5*MaxChunkSize + 1
contract.timestamp = 123 contract.timestamp = 123
...@@ -244,7 +264,7 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) { ...@@ -244,7 +264,7 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t) oracle, _, _, contract := newTestLargePreimageUploader(t)
data := types.PreimageOracleData{ data := types.PreimageOracleData{
OracleData: test.input, OracleData: test.input,
} }
...@@ -262,13 +282,15 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) { ...@@ -262,13 +282,15 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) {
} }
func newTestLargePreimageUploader(t *testing.T) (*LargePreimageUploader, *mockTxSender, *mockPreimageOracleContract) { func newTestLargePreimageUploader(t *testing.T) (*LargePreimageUploader, *clock.AdvancingClock, *mockTxSender, *mockPreimageOracleContract) {
logger := testlog.Logger(t, log.LvlError) logger := testlog.Logger(t, log.LvlError)
cl := clock.NewAdvancingClock(time.Second)
cl.Start()
txSender := &mockTxSender{} txSender := &mockTxSender{}
contract := &mockPreimageOracleContract{ contract := &mockPreimageOracleContract{
addData: make([]byte, 0), addData: make([]byte, 0),
} }
return NewLargePreimageUploader(logger, txSender, contract), txSender, contract return NewLargePreimageUploader(logger, cl, txSender, contract), cl, txSender, contract
} }
type mockPreimageOracleContract struct { type mockPreimageOracleContract struct {
...@@ -284,6 +306,7 @@ type mockPreimageOracleContract struct { ...@@ -284,6 +306,7 @@ type mockPreimageOracleContract struct {
squeezeCalls int squeezeCalls int
squeezeFails bool squeezeFails bool
squeezeCallFails bool squeezeCallFails bool
squeezeCallClaimSize uint32
squeezePrestate keccakTypes.Leaf squeezePrestate keccakTypes.Leaf
squeezePoststate keccakTypes.Leaf squeezePoststate keccakTypes.Leaf
} }
...@@ -315,7 +338,23 @@ func (s *mockPreimageOracleContract) Squeeze(_ common.Address, _ *big.Int, _ *ma ...@@ -315,7 +338,23 @@ func (s *mockPreimageOracleContract) Squeeze(_ common.Address, _ *big.Int, _ *ma
return txmgr.TxCandidate{}, nil return txmgr.TxCandidate{}, nil
} }
func (s *mockPreimageOracleContract) ChallengePeriod(_ context.Context) (uint64, error) {
return mockChallengePeriod, nil
}
func (s *mockPreimageOracleContract) GetProposalMetadata(_ context.Context, _ batching.Block, idents ...keccakTypes.LargePreimageIdent) ([]keccakTypes.LargePreimageMetaData, error) { func (s *mockPreimageOracleContract) GetProposalMetadata(_ context.Context, _ batching.Block, idents ...keccakTypes.LargePreimageIdent) ([]keccakTypes.LargePreimageMetaData, error) {
if s.squeezeCallClaimSize > 0 {
metadata := make([]keccakTypes.LargePreimageMetaData, 0)
for _, ident := range idents {
metadata = append(metadata, keccakTypes.LargePreimageMetaData{
LargePreimageIdent: ident,
ClaimedSize: s.squeezeCallClaimSize,
BytesProcessed: uint32(s.bytesProcessed),
Timestamp: s.timestamp,
})
}
return metadata, nil
}
if s.initialized || s.bytesProcessed > 0 { if s.initialized || s.bytesProcessed > 0 {
metadata := make([]keccakTypes.LargePreimageMetaData, 0) metadata := make([]keccakTypes.LargePreimageMetaData, 0)
for _, ident := range idents { for _, ident := range idents {
...@@ -328,6 +367,7 @@ func (s *mockPreimageOracleContract) GetProposalMetadata(_ context.Context, _ ba ...@@ -328,6 +367,7 @@ func (s *mockPreimageOracleContract) GetProposalMetadata(_ context.Context, _ ba
} }
return metadata, nil return metadata, nil
} }
s.squeezeCallClaimSize = 1
return []keccakTypes.LargePreimageMetaData{{LargePreimageIdent: idents[0]}}, nil return []keccakTypes.LargePreimageMetaData{{LargePreimageIdent: idents[0]}}, nil
} }
func (s *mockPreimageOracleContract) CallSqueeze(_ context.Context, _ common.Address, _ *big.Int, _ *matrix.StateMatrix, _ keccakTypes.Leaf, _ merkle.Proof, _ keccakTypes.Leaf, _ merkle.Proof) error { func (s *mockPreimageOracleContract) CallSqueeze(_ context.Context, _ common.Address, _ *big.Int, _ *matrix.StateMatrix, _ keccakTypes.Leaf, _ merkle.Proof, _ keccakTypes.Leaf, _ merkle.Proof) error {
......
...@@ -29,4 +29,5 @@ type PreimageOracleContract interface { ...@@ -29,4 +29,5 @@ type PreimageOracleContract interface {
Squeeze(claimant common.Address, uuid *big.Int, stateMatrix *matrix.StateMatrix, preState keccakTypes.Leaf, preStateProof merkle.Proof, postState keccakTypes.Leaf, postStateProof merkle.Proof) (txmgr.TxCandidate, error) Squeeze(claimant common.Address, uuid *big.Int, stateMatrix *matrix.StateMatrix, preState keccakTypes.Leaf, preStateProof merkle.Proof, postState keccakTypes.Leaf, postStateProof merkle.Proof) (txmgr.TxCandidate, error)
CallSqueeze(ctx context.Context, claimant common.Address, uuid *big.Int, stateMatrix *matrix.StateMatrix, preState keccakTypes.Leaf, preStateProof merkle.Proof, postState keccakTypes.Leaf, postStateProof merkle.Proof) error CallSqueeze(ctx context.Context, claimant common.Address, uuid *big.Int, stateMatrix *matrix.StateMatrix, preState keccakTypes.Leaf, preStateProof merkle.Proof, postState keccakTypes.Leaf, postStateProof merkle.Proof) error
GetProposalMetadata(ctx context.Context, block batching.Block, idents ...keccakTypes.LargePreimageIdent) ([]keccakTypes.LargePreimageMetaData, error) GetProposalMetadata(ctx context.Context, block batching.Block, idents ...keccakTypes.LargePreimageIdent) ([]keccakTypes.LargePreimageMetaData, error)
ChallengePeriod(ctx context.Context) (uint64, error)
} }
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/scheduler" "github.com/ethereum-optimism/optimism/op-challenger/game/scheduler"
"github.com/ethereum-optimism/optimism/op-challenger/game/types" "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -32,6 +33,7 @@ type Registry interface { ...@@ -32,6 +33,7 @@ type Registry interface {
func RegisterGameTypes( func RegisterGameTypes(
registry Registry, registry Registry,
ctx context.Context, ctx context.Context,
cl clock.Clock,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
cfg *config.Config, cfg *config.Config,
...@@ -51,12 +53,12 @@ func RegisterGameTypes( ...@@ -51,12 +53,12 @@ func RegisterGameTypes(
closer = l2Client.Close closer = l2Client.Close
} }
if cfg.TraceTypeEnabled(config.TraceTypeCannon) { if cfg.TraceTypeEnabled(config.TraceTypeCannon) {
if err := registerCannon(registry, ctx, logger, m, cfg, rollupClient, txSender, gameFactory, caller, l2Client); err != nil { if err := registerCannon(registry, ctx, cl, logger, m, cfg, rollupClient, txSender, gameFactory, caller, l2Client); err != nil {
return nil, fmt.Errorf("failed to register cannon game type: %w", err) return nil, fmt.Errorf("failed to register cannon game type: %w", err)
} }
} }
if cfg.TraceTypeEnabled(config.TraceTypeAlphabet) { if cfg.TraceTypeEnabled(config.TraceTypeAlphabet) {
if err := registerAlphabet(registry, ctx, logger, m, rollupClient, txSender, gameFactory, caller); err != nil { if err := registerAlphabet(registry, ctx, cl, logger, m, rollupClient, txSender, gameFactory, caller); err != nil {
return nil, fmt.Errorf("failed to register alphabet game type: %w", err) return nil, fmt.Errorf("failed to register alphabet game type: %w", err)
} }
} }
...@@ -66,6 +68,7 @@ func RegisterGameTypes( ...@@ -66,6 +68,7 @@ func RegisterGameTypes(
func registerAlphabet( func registerAlphabet(
registry Registry, registry Registry,
ctx context.Context, ctx context.Context,
cl clock.Clock,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
rollupClient outputs.OutputRollupClient, rollupClient outputs.OutputRollupClient,
...@@ -96,7 +99,7 @@ func registerAlphabet( ...@@ -96,7 +99,7 @@ func registerAlphabet(
} }
prestateValidator := NewPrestateValidator(contract.GetAbsolutePrestateHash, prestateProvider) prestateValidator := NewPrestateValidator(contract.GetAbsolutePrestateHash, prestateProvider)
genesisValidator := NewPrestateValidator(contract.GetGenesisOutputRoot, prestateProvider) genesisValidator := NewPrestateValidator(contract.GetGenesisOutputRoot, prestateProvider)
return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txSender, contract, []Validator{prestateValidator, genesisValidator}, creator) return NewGamePlayer(ctx, cl, logger, m, dir, game.Proxy, txSender, contract, []Validator{prestateValidator, genesisValidator}, creator)
} }
oracle, err := createOracle(ctx, gameFactory, caller, alphabetGameType) oracle, err := createOracle(ctx, gameFactory, caller, alphabetGameType)
if err != nil { if err != nil {
...@@ -125,6 +128,7 @@ func createOracle(ctx context.Context, gameFactory *contracts.DisputeGameFactory ...@@ -125,6 +128,7 @@ func createOracle(ctx context.Context, gameFactory *contracts.DisputeGameFactory
func registerCannon( func registerCannon(
registry Registry, registry Registry,
ctx context.Context, ctx context.Context,
cl clock.Clock,
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
cfg *config.Config, cfg *config.Config,
...@@ -157,7 +161,7 @@ func registerCannon( ...@@ -157,7 +161,7 @@ func registerCannon(
} }
prestateValidator := NewPrestateValidator(contract.GetAbsolutePrestateHash, prestateProvider) prestateValidator := NewPrestateValidator(contract.GetAbsolutePrestateHash, prestateProvider)
genesisValidator := NewPrestateValidator(contract.GetGenesisOutputRoot, prestateProvider) genesisValidator := NewPrestateValidator(contract.GetGenesisOutputRoot, prestateProvider)
return NewGamePlayer(ctx, logger, m, dir, game.Proxy, txSender, contract, []Validator{prestateValidator, genesisValidator}, creator) return NewGamePlayer(ctx, cl, logger, m, dir, game.Proxy, txSender, contract, []Validator{prestateValidator, genesisValidator}, creator)
} }
oracle, err := createOracle(ctx, gameFactory, caller, cannonGameType) oracle, err := createOracle(ctx, gameFactory, caller, cannonGameType)
if err != nil { if err != nil {
......
...@@ -94,7 +94,10 @@ func (r *FaultResponder) PerformAction(ctx context.Context, action types.Action) ...@@ -94,7 +94,10 @@ func (r *FaultResponder) PerformAction(ctx context.Context, action types.Action)
// Always upload local preimages // Always upload local preimages
if !preimageExists { if !preimageExists {
err := r.uploader.UploadPreimage(ctx, uint64(action.ParentIdx), action.OracleData) err := r.uploader.UploadPreimage(ctx, uint64(action.ParentIdx), action.OracleData)
if err != nil { if err == preimages.ErrChallengePeriodNotOver {
r.log.Debug("Large Preimage Squeeze failed, challenge period not over")
return nil
} else if err != nil {
return fmt.Errorf("failed to upload preimage: %w", err) return fmt.Errorf("failed to upload preimage: %w", err)
} }
} }
......
...@@ -42,6 +42,8 @@ type Service struct { ...@@ -42,6 +42,8 @@ type Service struct {
preimages *keccak.LargePreimageScheduler preimages *keccak.LargePreimageScheduler
cl clock.Clock
txMgr *txmgr.SimpleTxManager txMgr *txmgr.SimpleTxManager
txSender *sender.TxSender txSender *sender.TxSender
...@@ -63,8 +65,9 @@ type Service struct { ...@@ -63,8 +65,9 @@ type Service struct {
} }
// NewService creates a new Service. // NewService creates a new Service.
func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*Service, error) { func NewService(ctx context.Context, cl clock.Clock, logger log.Logger, cfg *config.Config) (*Service, error) {
s := &Service{ s := &Service{
cl: cl,
logger: logger, logger: logger,
metrics: metrics.NewMetrics(), metrics: metrics.NewMetrics(),
} }
...@@ -213,7 +216,7 @@ func (s *Service) initRollupClient(ctx context.Context, cfg *config.Config) erro ...@@ -213,7 +216,7 @@ func (s *Service) initRollupClient(ctx context.Context, cfg *config.Config) erro
func (s *Service) registerGameTypes(ctx context.Context, cfg *config.Config) error { func (s *Service) registerGameTypes(ctx context.Context, cfg *config.Config) error {
gameTypeRegistry := registry.NewGameTypeRegistry() gameTypeRegistry := registry.NewGameTypeRegistry()
caller := batching.NewMultiCaller(s.l1Client.Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(s.l1Client.Client(), batching.DefaultBatchSize)
closer, err := fault.RegisterGameTypes(gameTypeRegistry, ctx, s.logger, s.metrics, cfg, s.rollupClient, s.txSender, s.factoryContract, caller) closer, err := fault.RegisterGameTypes(gameTypeRegistry, ctx, s.cl, s.logger, s.metrics, cfg, s.rollupClient, s.txSender, s.factoryContract, caller)
if err != nil { if err != nil {
return err return err
} }
...@@ -236,8 +239,7 @@ func (s *Service) initLargePreimages() error { ...@@ -236,8 +239,7 @@ func (s *Service) initLargePreimages() error {
} }
func (s *Service) initMonitor(cfg *config.Config) { func (s *Service) initMonitor(cfg *config.Config) {
cl := clock.SystemClock s.monitor = newGameMonitor(s.logger, s.cl, s.loader, s.sched, s.preimages, cfg.GameWindow, s.l1Client.BlockNumber, cfg.GameAllowlist, s.pollClient)
s.monitor = newGameMonitor(s.logger, cl, s.loader, s.sched, s.preimages, cfg.GameWindow, s.l1Client.BlockNumber, cfg.GameAllowlist, s.pollClient)
} }
func (s *Service) Start(ctx context.Context) error { func (s *Service) Start(ctx context.Context) error {
......
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