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 (
var (
mockUpdateOracleTxError = errors.New("mock update oracle tx error")
mockTxMgrSendError = errors.New("mock tx mgr send error")
mockInitLPPError = errors.New("mock init LPP error")
)
func TestDirectPreimageUploader_UploadPreimage(t *testing.T) {
......@@ -25,7 +26,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) {
contract.updateFails = true
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{})
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
})
......@@ -34,7 +35,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) {
txMgr.sendFails = true
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{})
require.ErrorIs(t, err, mockTxMgrSendError)
require.Equal(t, 1, contract.updates)
require.Equal(t, 1, contract.updateCalls)
require.Equal(t, 1, txMgr.sends)
})
......@@ -48,7 +49,7 @@ func TestDirectPreimageUploader_UploadPreimage(t *testing.T) {
oracle, _, contract := newTestDirectPreimageUploader(t)
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{})
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
}
type mockPreimageGameContract struct {
updates int
updateCalls int
updateFails bool
}
func (s *mockPreimageGameContract) UpdateOracleTx(_ context.Context, _ uint64, _ *types.PreimageOracleData) (txmgr.TxCandidate, error) {
s.updates++
s.updateCalls++
if s.updateFails {
return txmgr.TxCandidate{}, mockUpdateOracleTxError
}
......
......@@ -2,17 +2,21 @@ package preimages
import (
"context"
"crypto/rand"
"errors"
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
var _ PreimageUploader = (*LargePreimageUploader)(nil)
var errNotSupported = errors.New("not supported")
var _ PreimageUploader = (*LargePreimageUploader)(nil)
// LargePreimageUploader handles uploading large preimages by
// streaming the merkleized preimage to the PreimageOracle contract,
// tightly packed across multiple transactions.
......@@ -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
// and state commitments to the preimage oracle contract using
// `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): once the challenge period is over, call `squeezeLPP` on the preimage oracle contract.
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 (
)
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) {
oracle, _, _ := newTestLargePreimageUploader(t)
oracle, _, contract := newTestLargePreimageUploader(t)
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.
require.ErrorIs(t, err, errNotSupported)
})
......@@ -31,9 +40,16 @@ func newTestLargePreimageUploader(t *testing.T) (*LargePreimageUploader, *mockTx
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) {
s.initCalls++
if s.initFails {
return txmgr.TxCandidate{}, mockInitLPPError
}
return txmgr.TxCandidate{}, nil
}
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