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,30 +282,33 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) { ...@@ -262,30 +282,33 @@ 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 {
initCalls int initCalls int
initFails bool initFails bool
initialized bool initialized bool
claimedSize uint32 claimedSize uint32
bytesProcessed int bytesProcessed int
timestamp uint64 timestamp uint64
addCalls int addCalls int
addFails bool addFails bool
addData []byte addData []byte
squeezeCalls int squeezeCalls int
squeezeFails bool squeezeFails bool
squeezeCallFails bool squeezeCallFails bool
squeezePrestate keccakTypes.Leaf squeezeCallClaimSize uint32
squeezePoststate keccakTypes.Leaf squeezePrestate keccakTypes.Leaf
squeezePoststate keccakTypes.Leaf
} }
func (s *mockPreimageOracleContract) InitLargePreimage(_ *big.Int, _ uint32, _ uint32) (txmgr.TxCandidate, error) { func (s *mockPreimageOracleContract) InitLargePreimage(_ *big.Int, _ uint32, _ uint32) (txmgr.TxCandidate, error) {
...@@ -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