Commit 989b640d authored by refcell.eth's avatar refcell.eth Committed by GitHub

feat(op-challenger): Large Preimage Uploader InitLPP Call Support (#9033)

* feat(op-challenger): Adds a helper to call the initLPP preimage oracle
contract call.

* fix(op-challenger): call init large preimage from the uploader

* fix(op-challenger): keep large preimage upload unsupported for the interim
parent 7b8b9a80
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
var ( var (
mockUpdateOracleTxError = errors.New("mock update oracle tx error") mockUpdateOracleTxError = errors.New("mock update oracle tx error")
mockTxMgrSendError = errors.New("mock tx mgr send error") mockTxMgrSendError = errors.New("mock tx mgr send error")
mockInitLPPError = errors.New("mock init LPP error")
) )
func TestDirectPreimageUploader_UploadPreimage(t *testing.T) { func TestDirectPreimageUploader_UploadPreimage(t *testing.T) {
...@@ -25,7 +26,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) { ...@@ -25,7 +26,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) {
contract.updateFails = true contract.updateFails = true
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{}) err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{})
require.ErrorIs(t, err, mockUpdateOracleTxError) require.ErrorIs(t, err, mockUpdateOracleTxError)
require.Equal(t, 1, contract.updates) require.Equal(t, 1, contract.updateCalls)
require.Equal(t, 0, txMgr.sends) // verify that the tx was not sent require.Equal(t, 0, txMgr.sends) // verify that the tx was not sent
}) })
...@@ -34,7 +35,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) { ...@@ -34,7 +35,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) {
txMgr.sendFails = true txMgr.sendFails = true
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{}) err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{})
require.ErrorIs(t, err, mockTxMgrSendError) require.ErrorIs(t, err, mockTxMgrSendError)
require.Equal(t, 1, contract.updates) require.Equal(t, 1, contract.updateCalls)
require.Equal(t, 1, txMgr.sends) require.Equal(t, 1, txMgr.sends)
}) })
...@@ -48,7 +49,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) { ...@@ -48,7 +49,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) {
oracle, _, contract := newTestDirectPreimageUploader(t) oracle, _, contract := newTestDirectPreimageUploader(t)
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{}) err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, contract.updates) require.Equal(t, 1, contract.updateCalls)
}) })
} }
...@@ -85,12 +86,12 @@ func newTestDirectPreimageUploader(t *testing.T) (*DirectPreimageUploader, *mock ...@@ -85,12 +86,12 @@ func newTestDirectPreimageUploader(t *testing.T) (*DirectPreimageUploader, *mock
} }
type mockPreimageGameContract struct { type mockPreimageGameContract struct {
updates int updateCalls int
updateFails bool updateFails bool
} }
func (s *mockPreimageGameContract) UpdateOracleTx(_ context.Context, _ uint64, _ *types.PreimageOracleData) (txmgr.TxCandidate, error) { func (s *mockPreimageGameContract) UpdateOracleTx(_ context.Context, _ uint64, _ *types.PreimageOracleData) (txmgr.TxCandidate, error) {
s.updates++ s.updateCalls++
if s.updateFails { if s.updateFails {
return txmgr.TxCandidate{}, mockUpdateOracleTxError return txmgr.TxCandidate{}, mockUpdateOracleTxError
} }
......
...@@ -2,17 +2,21 @@ package preimages ...@@ -2,17 +2,21 @@ package preimages
import ( import (
"context" "context"
"crypto/rand"
"errors" "errors"
"fmt"
"math/big"
"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-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
var _ PreimageUploader = (*LargePreimageUploader)(nil)
var errNotSupported = errors.New("not supported") var errNotSupported = errors.New("not supported")
var _ PreimageUploader = (*LargePreimageUploader)(nil)
// LargePreimageUploader handles uploading large preimages by // LargePreimageUploader handles uploading large preimages by
// streaming the merkleized preimage to the PreimageOracle contract, // streaming the merkleized preimage to the PreimageOracle contract,
// tightly packed across multiple transactions. // tightly packed across multiple transactions.
...@@ -34,7 +38,53 @@ func (p *LargePreimageUploader) UploadPreimage(ctx context.Context, parent uint6 ...@@ -34,7 +38,53 @@ func (p *LargePreimageUploader) UploadPreimage(ctx context.Context, parent uint6
// todo(proofs#467): split up the preimage into chunks and submit the preimages // todo(proofs#467): split up the preimage into chunks and submit the preimages
// and state commitments to the preimage oracle contract using // and state commitments to the preimage oracle contract using
// `PreimageOracle.addLeavesLPP` (`_finalize` = false). // `PreimageOracle.addLeavesLPP` (`_finalize` = false).
// TODO(client-pod#473): The UUID must be deterministic so the challenger can resume uploads.
uuid, err := p.newUUID()
if err != nil {
return fmt.Errorf("failed to generate UUID: %w", err)
}
err = p.initLargePreimage(ctx, uuid, data.OracleOffset, uint32(len(data.OracleData)))
if err != nil {
return fmt.Errorf("failed to initialize large preimage with uuid: %s: %w", uuid, err)
}
// todo(proofs#467): track the challenge period starting once the full preimage is posted. // todo(proofs#467): track the challenge period starting once the full preimage is posted.
// todo(proofs#467): once the challenge period is over, call `squeezeLPP` on the preimage oracle contract. // todo(proofs#467): once the challenge period is over, call `squeezeLPP` on the preimage oracle contract.
return errNotSupported return errNotSupported
} }
func (p *LargePreimageUploader) newUUID() (*big.Int, error) {
max := new(big.Int)
max.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(max, big.NewInt(1))
return rand.Int(rand.Reader, max)
}
// initLargePreimage initializes the large preimage proposal.
// This method *must* be called before adding any leaves.
func (p *LargePreimageUploader) initLargePreimage(ctx context.Context, uuid *big.Int, partOffset uint32, claimedSize uint32) error {
candidate, err := p.contract.InitLargePreimage(uuid, partOffset, claimedSize)
if err != nil {
return fmt.Errorf("failed to create pre-image oracle tx: %w", err)
}
if err := p.sendTxAndWait(ctx, candidate); err != nil {
return fmt.Errorf("failed to populate pre-image oracle: %w", err)
}
return nil
}
// sendTxAndWait sends a transaction through the [txmgr] and waits for a receipt.
// This sets the tx GasLimit to 0, performing gas estimation online through the [txmgr].
func (p *LargePreimageUploader) sendTxAndWait(ctx context.Context, candidate txmgr.TxCandidate) error {
receipt, err := p.txMgr.Send(ctx, candidate)
if err != nil {
return err
}
if receipt.Status == ethtypes.ReceiptStatusFailed {
p.log.Error("LargePreimageUploader tx successfully published but reverted", "tx_hash", receipt.TxHash)
} else {
p.log.Debug("LargePreimageUploader tx successfully published", "tx_hash", receipt.TxHash)
}
return nil
}
...@@ -16,9 +16,18 @@ import ( ...@@ -16,9 +16,18 @@ import (
) )
func TestLargePreimageUploader_UploadPreimage(t *testing.T) { func TestLargePreimageUploader_UploadPreimage(t *testing.T) {
t.Run("InitFails", func(t *testing.T) {
oracle, _, contract := newTestLargePreimageUploader(t)
contract.initFails = true
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{})
require.ErrorIs(t, err, mockInitLPPError)
require.Equal(t, 1, contract.initCalls)
})
t.Run("Success", func(t *testing.T) { t.Run("Success", func(t *testing.T) {
oracle, _, _ := newTestLargePreimageUploader(t) oracle, _, contract := newTestLargePreimageUploader(t)
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{}) err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{})
require.Equal(t, 1, contract.initCalls)
// TODO(proofs#467): fix this to not error. See LargePreimageUploader.UploadPreimage. // TODO(proofs#467): fix this to not error. See LargePreimageUploader.UploadPreimage.
require.ErrorIs(t, err, errNotSupported) require.ErrorIs(t, err, errNotSupported)
}) })
...@@ -31,9 +40,16 @@ func newTestLargePreimageUploader(t *testing.T) (*LargePreimageUploader, *mockTx ...@@ -31,9 +40,16 @@ func newTestLargePreimageUploader(t *testing.T) (*LargePreimageUploader, *mockTx
return NewLargePreimageUploader(logger, txMgr, contract), txMgr, contract return NewLargePreimageUploader(logger, txMgr, contract), txMgr, contract
} }
type mockPreimageOracleContract struct{} type mockPreimageOracleContract struct {
initCalls int
initFails bool
}
func (s *mockPreimageOracleContract) InitLargePreimage(_ *big.Int, _ uint32, _ uint32) (txmgr.TxCandidate, error) { func (s *mockPreimageOracleContract) InitLargePreimage(_ *big.Int, _ uint32, _ uint32) (txmgr.TxCandidate, error) {
s.initCalls++
if s.initFails {
return txmgr.TxCandidate{}, mockInitLPPError
}
return txmgr.TxCandidate{}, nil return txmgr.TxCandidate{}, nil
} }
func (s *mockPreimageOracleContract) AddLeaves(_ *big.Int, _ []contracts.Leaf, _ bool) ([]txmgr.TxCandidate, error) { func (s *mockPreimageOracleContract) AddLeaves(_ *big.Int, _ []contracts.Leaf, _ bool) ([]txmgr.TxCandidate, 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