Commit e9172f60 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Exclude Length Prefix for Large Preimage Uploads (#9318)

* op-challenger: Exclude length prefix when uploading large preimages.

Make OracleData field private to avoid unintentionally using the length-prefixed data.

* fix(op-e2e): upstream merge

---------
Co-authored-by: default avatarrefcell <abigger87@gmail.com>
parent 65751ca9
...@@ -290,12 +290,7 @@ func TestGetGenesisOutputRoot(t *testing.T) { ...@@ -290,12 +290,7 @@ func TestGetGenesisOutputRoot(t *testing.T) {
func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) { func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) {
t.Run("Local", func(t *testing.T) { t.Run("Local", func(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) stubRpc, game := setupFaultDisputeGameTest(t)
data := &faultTypes.PreimageOracleData{ data := faultTypes.NewPreimageOracleData(common.Hash{0x01, 0xbc}.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7}, 16)
IsLocal: true,
OracleKey: common.Hash{0xbc}.Bytes(),
OracleData: []byte{1, 2, 3, 4, 5, 6, 7},
OracleOffset: 16,
}
claimIdx := uint64(6) claimIdx := uint64(6)
stubRpc.SetResponse(fdgAddr, methodAddLocalData, batching.BlockLatest, []interface{}{ stubRpc.SetResponse(fdgAddr, methodAddLocalData, batching.BlockLatest, []interface{}{
data.GetIdent(), data.GetIdent(),
...@@ -309,12 +304,7 @@ func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) { ...@@ -309,12 +304,7 @@ func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) {
t.Run("Global", func(t *testing.T) { t.Run("Global", func(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) stubRpc, game := setupFaultDisputeGameTest(t)
data := &faultTypes.PreimageOracleData{ data := faultTypes.NewPreimageOracleData(common.Hash{0x02, 0xbc}.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}, 16)
IsLocal: false,
OracleKey: common.Hash{0xbc}.Bytes(),
OracleData: []byte{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15},
OracleOffset: 16,
}
claimIdx := uint64(6) claimIdx := uint64(6)
stubRpc.SetResponse(fdgAddr, methodVM, batching.BlockLatest, nil, []interface{}{vmAddr}) stubRpc.SetResponse(fdgAddr, methodVM, batching.BlockLatest, nil, []interface{}{vmAddr})
stubRpc.SetResponse(vmAddr, methodOracle, batching.BlockLatest, nil, []interface{}{oracleAddr}) stubRpc.SetResponse(vmAddr, methodOracle, batching.BlockLatest, nil, []interface{}{oracleAddr})
......
...@@ -20,11 +20,7 @@ import ( ...@@ -20,11 +20,7 @@ import (
func TestPreimageOracleContract_LoadKeccak256(t *testing.T) { func TestPreimageOracleContract_LoadKeccak256(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t) stubRpc, oracle := setupPreimageOracleTest(t)
data := &types.PreimageOracleData{ data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), 545)
OracleKey: common.Hash{0xcc}.Bytes(),
OracleData: make([]byte, 20),
OracleOffset: 545,
}
stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, batching.BlockLatest, []interface{}{ stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, batching.BlockLatest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)), new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPreimageWithoutSize(), data.GetPreimageWithoutSize(),
...@@ -60,11 +56,7 @@ func TestPreimageOracleContract_MinLargePreimageSize(t *testing.T) { ...@@ -60,11 +56,7 @@ func TestPreimageOracleContract_MinLargePreimageSize(t *testing.T) {
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)
data := &types.PreimageOracleData{ data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), 545)
OracleKey: common.Hash{0xcc}.Bytes(),
OracleData: make([]byte, 20),
OracleOffset: 545,
}
stubRpc.SetResponse(oracleAddr, methodPreimagePartOk, batching.BlockLatest, stubRpc.SetResponse(oracleAddr, methodPreimagePartOk, batching.BlockLatest,
[]interface{}{common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset))}, []interface{}{common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset))},
[]interface{}{true}, []interface{}{true},
...@@ -75,11 +67,7 @@ func TestPreimageOracleContract_PreimageDataExists(t *testing.T) { ...@@ -75,11 +67,7 @@ func TestPreimageOracleContract_PreimageDataExists(t *testing.T) {
}) })
t.Run("does not exist", func(t *testing.T) { t.Run("does not exist", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t) stubRpc, oracle := setupPreimageOracleTest(t)
data := &types.PreimageOracleData{ data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), 545)
OracleKey: common.Hash{0xcc}.Bytes(),
OracleData: make([]byte, 20),
OracleOffset: 545,
}
stubRpc.SetResponse(oracleAddr, methodPreimagePartOk, batching.BlockLatest, stubRpc.SetResponse(oracleAddr, methodPreimagePartOk, batching.BlockLatest,
[]interface{}{common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset))}, []interface{}{common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset))},
[]interface{}{false}, []interface{}{false},
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"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/sources/batching" "github.com/ethereum-optimism/optimism/op-service/sources/batching"
batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test" batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -23,9 +24,7 @@ func TestVMContract_Oracle(t *testing.T) { ...@@ -23,9 +24,7 @@ func TestVMContract_Oracle(t *testing.T) {
oracleContract, err := vmContract.Oracle(context.Background()) oracleContract, err := vmContract.Oracle(context.Background())
require.NoError(t, err) require.NoError(t, err)
tx, err := oracleContract.AddGlobalDataTx(&types.PreimageOracleData{ tx, err := oracleContract.AddGlobalDataTx(types.NewPreimageOracleData(common.Hash{}.Bytes(), make([]byte, 20), 0))
OracleData: make([]byte, 20),
})
require.NoError(t, err) require.NoError(t, err)
// This test doesn't care about all the tx details, we just want to confirm the contract binding is using the // This test doesn't care about all the tx details, we just want to confirm the contract binding is using the
// correct address // correct address
......
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
"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/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -49,7 +50,7 @@ func NewLargePreimageUploader(logger log.Logger, cl types.ClockReader, txSender ...@@ -49,7 +50,7 @@ func NewLargePreimageUploader(logger log.Logger, cl types.ClockReader, txSender
} }
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 {
p.log.Debug("Upload large preimage", "key", data.OracleKey) p.log.Debug("Upload large preimage", "key", hexutil.Bytes(data.OracleKey))
stateMatrix, calls, err := p.splitCalls(data) stateMatrix, calls, err := p.splitCalls(data)
if err != nil { if err != nil {
return fmt.Errorf("failed to split preimage into chunks for data with oracle offset %d: %w", data.OracleOffset, err) return fmt.Errorf("failed to split preimage into chunks for data with oracle offset %d: %w", data.OracleOffset, err)
...@@ -66,7 +67,7 @@ func (p *LargePreimageUploader) UploadPreimage(ctx context.Context, parent uint6 ...@@ -66,7 +67,7 @@ func (p *LargePreimageUploader) UploadPreimage(ctx context.Context, parent uint6
// The proposal is not initialized if the queried metadata has a claimed size of 0. // The proposal is not initialized if the queried metadata has a claimed size of 0.
if len(metadata) == 1 && metadata[0].ClaimedSize == 0 { if len(metadata) == 1 && metadata[0].ClaimedSize == 0 {
err = p.initLargePreimage(uuid, data.OracleOffset, uint32(len(data.OracleData))) err = p.initLargePreimage(uuid, data.OracleOffset, uint32(len(data.GetPreimageWithoutSize())))
if err != nil { if err != nil {
return fmt.Errorf("failed to initialize large preimage with uuid: %s: %w", uuid, err) return fmt.Errorf("failed to initialize large preimage with uuid: %s: %w", uuid, err)
} }
...@@ -95,7 +96,7 @@ func (p *LargePreimageUploader) UploadPreimage(ctx context.Context, parent uint6 ...@@ -95,7 +96,7 @@ func (p *LargePreimageUploader) UploadPreimage(ctx context.Context, parent uint6
func NewUUID(sender common.Address, data *types.PreimageOracleData) *big.Int { func NewUUID(sender common.Address, data *types.PreimageOracleData) *big.Int {
offset := make([]byte, 4) offset := make([]byte, 4)
binary.LittleEndian.PutUint32(offset, data.OracleOffset) binary.LittleEndian.PutUint32(offset, data.OracleOffset)
concatenated := append(data.OracleData, offset...) concatenated := append(data.GetPreimageWithoutSize(), offset...)
concatenated = append(concatenated, sender.Bytes()...) concatenated = append(concatenated, sender.Bytes()...)
hash := crypto.Keccak256Hash(concatenated) hash := crypto.Keccak256Hash(concatenated)
return hash.Big() return hash.Big()
...@@ -107,7 +108,7 @@ func (p *LargePreimageUploader) splitCalls(data *types.PreimageOracleData) (*mat ...@@ -107,7 +108,7 @@ func (p *LargePreimageUploader) splitCalls(data *types.PreimageOracleData) (*mat
// Split the preimage data into chunks of size [MaxChunkSize] (except the last chunk). // Split the preimage data into chunks of size [MaxChunkSize] (except the last chunk).
stateMatrix := matrix.NewStateMatrix() stateMatrix := matrix.NewStateMatrix()
var calls []keccakTypes.InputData var calls []keccakTypes.InputData
in := bytes.NewReader(data.OracleData) in := bytes.NewReader(data.GetPreimageWithoutSize())
for { for {
call, err := stateMatrix.AbsorbUpTo(in, MaxChunkSize) call, err := stateMatrix.AbsorbUpTo(in, MaxChunkSize)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
......
...@@ -3,6 +3,7 @@ package preimages ...@@ -3,6 +3,7 @@ package preimages
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/binary"
"errors" "errors"
"io" "io"
"math/big" "math/big"
...@@ -13,11 +14,13 @@ import ( ...@@ -13,11 +14,13 @@ import (
"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"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-service/clock" "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"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -37,31 +40,22 @@ func TestLargePreimageUploader_NewUUID(t *testing.T) { ...@@ -37,31 +40,22 @@ func TestLargePreimageUploader_NewUUID(t *testing.T) {
}{ }{
{ {
name: "EmptyOracleData", name: "EmptyOracleData",
data: &types.PreimageOracleData{}, data: makePreimageData([]byte{}, 0),
expectedUUID: new(big.Int).SetBytes(common.FromHex("827b659bbda2a0bdecce2c91b8b68462545758f3eba2dbefef18e0daf84f5ccd")), expectedUUID: new(big.Int).SetBytes(common.FromHex("827b659bbda2a0bdecce2c91b8b68462545758f3eba2dbefef18e0daf84f5ccd")),
}, },
{ {
name: "OracleDataAndOffset_Control", name: "OracleDataAndOffset_Control",
data: &types.PreimageOracleData{ data: makePreimageData([]byte{1, 2, 3}, 0x010203),
OracleData: []byte{1, 2, 3},
OracleOffset: 0x010203,
},
expectedUUID: new(big.Int).SetBytes(common.FromHex("641e230bcf3ade8c71b7e591d210184cdb190e853f61ba59a1411c3b7aca9890")), expectedUUID: new(big.Int).SetBytes(common.FromHex("641e230bcf3ade8c71b7e591d210184cdb190e853f61ba59a1411c3b7aca9890")),
}, },
{ {
name: "OracleDataAndOffset_DifferentOffset", name: "OracleDataAndOffset_DifferentOffset",
data: &types.PreimageOracleData{ data: makePreimageData([]byte{1, 2, 3}, 0x010204),
OracleData: []byte{1, 2, 3},
OracleOffset: 0x010204,
},
expectedUUID: new(big.Int).SetBytes(common.FromHex("aec56de44401325420e5793f72b777e3e547778de7d8344004b31be086a3136d")), expectedUUID: new(big.Int).SetBytes(common.FromHex("aec56de44401325420e5793f72b777e3e547778de7d8344004b31be086a3136d")),
}, },
{ {
name: "OracleDataAndOffset_DifferentData", name: "OracleDataAndOffset_DifferentData",
data: &types.PreimageOracleData{ data: makePreimageData([]byte{1, 2, 3, 4}, 0x010203),
OracleData: []byte{1, 2, 3, 4},
OracleOffset: 0x010203,
},
expectedUUID: new(big.Int).SetBytes(common.FromHex("ca38aa17d56805cf26376a050c2c7b15b6be4e709bc422a1c679fe21aa6aa8c7")), expectedUUID: new(big.Int).SetBytes(common.FromHex("ca38aa17d56805cf26376a050c2c7b15b6be4e709bc422a1c679fe21aa6aa8c7")),
}, },
} }
...@@ -80,7 +74,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -80,7 +74,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(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)
require.ErrorIs(t, err, mockInitLPPError) require.ErrorIs(t, err, mockInitLPPError)
require.Equal(t, 1, contract.initCalls) require.Equal(t, 1, contract.initCalls)
}) })
...@@ -89,7 +83,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -89,7 +83,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(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)
require.ErrorIs(t, err, mockAddLeavesError) require.ErrorIs(t, err, mockAddLeavesError)
require.Equal(t, 1, contract.addCalls) require.Equal(t, 1, contract.addCalls)
}) })
...@@ -97,20 +91,20 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -97,20 +91,20 @@ 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)) contract.claimedSize = uint32(len(data.GetPreimageWithoutSize()))
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)
require.Equal(t, 6, contract.addCalls) require.Equal(t, 6, contract.addCalls)
require.Equal(t, data.OracleData, contract.addData) require.Equal(t, data.GetPreimageWithoutSize(), contract.addData)
}) })
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.GetPreimageWithoutSize()))
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, 0, contract.initCalls) require.Equal(t, 0, contract.initCalls)
require.Equal(t, 6, contract.addCalls) require.Equal(t, 6, contract.addCalls)
...@@ -120,14 +114,14 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -120,14 +114,14 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
oracle, cl, _, contract := newTestLargePreimageUploader(t) oracle, cl, _, contract := newTestLargePreimageUploader(t)
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.bytesProcessed = 5*MaxChunkSize + 1 contract.bytesProcessed = 5*MaxChunkSize + 1
contract.claimedSize = uint32(len(data.OracleData)) contract.claimedSize = uint32(len(data.GetPreimageWithoutSize()))
contract.timestamp = uint64(cl.Now().Unix()) contract.timestamp = uint64(cl.Now().Unix())
err := oracle.UploadPreimage(context.Background(), 0, &data) err := oracle.UploadPreimage(context.Background(), 0, data)
require.ErrorIs(t, err, ErrChallengePeriodNotOver) require.ErrorIs(t, err, ErrChallengePeriodNotOver)
require.Equal(t, 0, contract.squeezeCalls) require.Equal(t, 0, contract.squeezeCalls)
// Squeeze should be called once the challenge period has elapsed. // Squeeze should be called once the challenge period has elapsed.
cl.AdvanceTime(time.Duration(mockChallengePeriod) * time.Second) cl.AdvanceTime(time.Duration(mockChallengePeriod) * time.Second)
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.squeezeCalls) require.Equal(t, 1, contract.squeezeCalls)
}) })
...@@ -137,9 +131,9 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -137,9 +131,9 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.bytesProcessed = 5*MaxChunkSize + 1 contract.bytesProcessed = 5*MaxChunkSize + 1
contract.timestamp = 123 contract.timestamp = 123
contract.claimedSize = uint32(len(data.OracleData)) contract.claimedSize = uint32(len(data.GetPreimageWithoutSize()))
contract.squeezeCallFails = true contract.squeezeCallFails = true
err := oracle.UploadPreimage(context.Background(), 0, &data) err := oracle.UploadPreimage(context.Background(), 0, data)
require.ErrorIs(t, err, mockSqueezeCallError) require.ErrorIs(t, err, mockSqueezeCallError)
require.Equal(t, 0, contract.squeezeCalls) require.Equal(t, 0, contract.squeezeCalls)
}) })
...@@ -149,9 +143,9 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -149,9 +143,9 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.bytesProcessed = 5*MaxChunkSize + 1 contract.bytesProcessed = 5*MaxChunkSize + 1
contract.timestamp = 123 contract.timestamp = 123
contract.claimedSize = uint32(len(data.OracleData)) contract.claimedSize = uint32(len(data.GetPreimageWithoutSize()))
contract.squeezeFails = true contract.squeezeFails = true
err := oracle.UploadPreimage(context.Background(), 0, &data) err := oracle.UploadPreimage(context.Background(), 0, data)
require.ErrorIs(t, err, mockSqueezeError) require.ErrorIs(t, err, mockSqueezeError)
require.Equal(t, 1, contract.squeezeCalls) require.Equal(t, 1, contract.squeezeCalls)
}) })
...@@ -161,8 +155,8 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -161,8 +155,8 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
data := mockPreimageOracleData() data := mockPreimageOracleData()
contract.bytesProcessed = 5*MaxChunkSize + 1 contract.bytesProcessed = 5*MaxChunkSize + 1
contract.timestamp = 123 contract.timestamp = 123
contract.claimedSize = uint32(len(data.OracleData)) contract.claimedSize = uint32(len(data.GetPreimageWithoutSize()))
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, 0, contract.initCalls) require.Equal(t, 0, contract.initCalls)
require.Equal(t, 0, contract.addCalls) require.Equal(t, 0, contract.addCalls)
...@@ -170,7 +164,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) { ...@@ -170,7 +164,7 @@ func TestLargePreimageUploader_UploadPreimage_EdgeCases(t *testing.T) {
}) })
} }
func mockPreimageOracleData() types.PreimageOracleData { func mockPreimageOracleData() *types.PreimageOracleData {
fullLeaf := make([]byte, keccakTypes.BlockSize) fullLeaf := make([]byte, keccakTypes.BlockSize)
for i := 0; i < keccakTypes.BlockSize; i++ { for i := 0; i < keccakTypes.BlockSize; i++ {
fullLeaf[i] = byte(i) fullLeaf[i] = byte(i)
...@@ -181,9 +175,16 @@ func mockPreimageOracleData() types.PreimageOracleData { ...@@ -181,9 +175,16 @@ func mockPreimageOracleData() types.PreimageOracleData {
} }
// Add a single byte to the end to make sure the last leaf is not processed. // Add a single byte to the end to make sure the last leaf is not processed.
oracleData = append(oracleData, byte(1)) oracleData = append(oracleData, byte(1))
return types.PreimageOracleData{ return makePreimageData(oracleData, 0)
OracleData: oracleData, }
}
func makePreimageData(pre []byte, offset uint32) *types.PreimageOracleData {
key := preimage.Keccak256Key(crypto.Keccak256Hash(pre)).PreimageKey()
// add the length prefix
preimage := make([]byte, 0, 8+len(pre))
preimage = binary.BigEndian.AppendUint64(preimage, uint64(len(pre)))
preimage = append(preimage, pre...)
return types.NewPreimageOracleData(key[:], preimage, offset)
} }
func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) { func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) {
...@@ -227,10 +228,8 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) { ...@@ -227,10 +228,8 @@ 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 := makePreimageData(test.input, 0)
OracleData: test.input, 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, test.addCalls, contract.addCalls) require.Equal(t, test.addCalls, contract.addCalls)
// There must always be at least one init and squeeze call // There must always be at least one init and squeeze call
......
...@@ -25,7 +25,7 @@ func (s *SplitPreimageUploader) UploadPreimage(ctx context.Context, parent uint6 ...@@ -25,7 +25,7 @@ func (s *SplitPreimageUploader) UploadPreimage(ctx context.Context, parent uint6
return ErrNilPreimageData return ErrNilPreimageData
} }
// Always route local preimage uploads to the direct uploader. // Always route local preimage uploads to the direct uploader.
if uint64(len(data.OracleData)) < s.largePreimageSizeThreshold || data.IsLocal { if data.IsLocal || uint64(len(data.GetPreimageWithoutSize())) < s.largePreimageSizeThreshold {
return s.directUploader.UploadPreimage(ctx, parent, data) return s.directUploader.UploadPreimage(ctx, parent, data)
} else { } else {
return s.largeUploader.UploadPreimage(ctx, parent, data) return s.largeUploader.UploadPreimage(ctx, parent, data)
......
...@@ -13,7 +13,7 @@ var mockLargePreimageSizeThreshold = uint64(100) ...@@ -13,7 +13,7 @@ var mockLargePreimageSizeThreshold = uint64(100)
func TestSplitPreimageUploader_UploadPreimage(t *testing.T) { func TestSplitPreimageUploader_UploadPreimage(t *testing.T) {
t.Run("DirectUploadSucceeds", func(t *testing.T) { t.Run("DirectUploadSucceeds", func(t *testing.T) {
oracle, direct, large := newTestSplitPreimageUploader(t, mockLargePreimageSizeThreshold) oracle, direct, large := newTestSplitPreimageUploader(t, mockLargePreimageSizeThreshold)
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{}) err := oracle.UploadPreimage(context.Background(), 0, makePreimageData(nil, 0))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, direct.updates) require.Equal(t, 1, direct.updates)
require.Equal(t, 0, large.updates) require.Equal(t, 0, large.updates)
...@@ -29,7 +29,7 @@ func TestSplitPreimageUploader_UploadPreimage(t *testing.T) { ...@@ -29,7 +29,7 @@ func TestSplitPreimageUploader_UploadPreimage(t *testing.T) {
t.Run("MaxSizeDirectUploadSucceeds", func(t *testing.T) { t.Run("MaxSizeDirectUploadSucceeds", func(t *testing.T) {
oracle, direct, large := newTestSplitPreimageUploader(t, mockLargePreimageSizeThreshold) oracle, direct, large := newTestSplitPreimageUploader(t, mockLargePreimageSizeThreshold)
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{OracleData: make([]byte, mockLargePreimageSizeThreshold-1)}) err := oracle.UploadPreimage(context.Background(), 0, makePreimageData(make([]byte, mockLargePreimageSizeThreshold-1), 0))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, direct.updates) require.Equal(t, 1, direct.updates)
require.Equal(t, 0, large.updates) require.Equal(t, 0, large.updates)
...@@ -37,7 +37,7 @@ func TestSplitPreimageUploader_UploadPreimage(t *testing.T) { ...@@ -37,7 +37,7 @@ func TestSplitPreimageUploader_UploadPreimage(t *testing.T) {
t.Run("LargeUploadSucceeds", func(t *testing.T) { t.Run("LargeUploadSucceeds", func(t *testing.T) {
oracle, direct, large := newTestSplitPreimageUploader(t, mockLargePreimageSizeThreshold) oracle, direct, large := newTestSplitPreimageUploader(t, mockLargePreimageSizeThreshold)
err := oracle.UploadPreimage(context.Background(), 0, &types.PreimageOracleData{OracleData: make([]byte, mockLargePreimageSizeThreshold)}) err := oracle.UploadPreimage(context.Background(), 0, makePreimageData(make([]byte, mockLargePreimageSizeThreshold), 0))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, large.updates) require.Equal(t, 1, large.updates)
require.Equal(t, 0, direct.updates) require.Equal(t, 0, direct.updates)
......
...@@ -176,7 +176,7 @@ func TestAttemptStep(t *testing.T) { ...@@ -176,7 +176,7 @@ func TestAttemptStep(t *testing.T) {
require.Equal(t, tableTest.expectProofData, step.ProofData) require.Equal(t, tableTest.expectProofData, step.ProofData)
require.Equal(t, tableTest.expectedOracleData.IsLocal, step.OracleData.IsLocal) require.Equal(t, tableTest.expectedOracleData.IsLocal, step.OracleData.IsLocal)
require.Equal(t, tableTest.expectedOracleData.OracleKey, step.OracleData.OracleKey) require.Equal(t, tableTest.expectedOracleData.OracleKey, step.OracleData.OracleKey)
require.Equal(t, tableTest.expectedOracleData.OracleData, step.OracleData.OracleData) require.Equal(t, tableTest.expectedOracleData.GetPreimageWithSize(), step.OracleData.GetPreimageWithSize())
require.Equal(t, tableTest.expectedOracleData.OracleOffset, step.OracleData.OracleOffset) require.Equal(t, tableTest.expectedOracleData.OracleOffset, step.OracleData.OracleOffset)
} else { } else {
require.ErrorIs(t, err, tableTest.expectedErr) require.ErrorIs(t, err, tableTest.expectedErr)
......
...@@ -26,7 +26,7 @@ type ClockReader interface { ...@@ -26,7 +26,7 @@ type ClockReader interface {
type PreimageOracleData struct { type PreimageOracleData struct {
IsLocal bool IsLocal bool
OracleKey []byte OracleKey []byte
OracleData []byte oracleData []byte
OracleOffset uint32 OracleOffset uint32
} }
...@@ -37,7 +37,12 @@ func (p *PreimageOracleData) GetIdent() *big.Int { ...@@ -37,7 +37,12 @@ func (p *PreimageOracleData) GetIdent() *big.Int {
// GetPreimageWithoutSize returns the preimage for the preimage oracle data. // GetPreimageWithoutSize returns the preimage for the preimage oracle data.
func (p *PreimageOracleData) GetPreimageWithoutSize() []byte { func (p *PreimageOracleData) GetPreimageWithoutSize() []byte {
return p.OracleData[8:] return p.oracleData[8:]
}
// GetPreimageWithSize returns the preimage with its length prefix.
func (p *PreimageOracleData) GetPreimageWithSize() []byte {
return p.oracleData
} }
// NewPreimageOracleData creates a new [PreimageOracleData] instance. // NewPreimageOracleData creates a new [PreimageOracleData] instance.
...@@ -45,7 +50,7 @@ func NewPreimageOracleData(key []byte, data []byte, offset uint32) *PreimageOrac ...@@ -45,7 +50,7 @@ func NewPreimageOracleData(key []byte, data []byte, offset uint32) *PreimageOrac
return &PreimageOracleData{ return &PreimageOracleData{
IsLocal: len(key) > 0 && key[0] == byte(1), IsLocal: len(key) > 0 && key[0] == byte(1),
OracleKey: key, OracleKey: key,
OracleData: data, oracleData: data,
OracleOffset: offset, OracleOffset: offset,
} }
} }
......
...@@ -12,7 +12,7 @@ func TestNewPreimageOracleData(t *testing.T) { ...@@ -12,7 +12,7 @@ func TestNewPreimageOracleData(t *testing.T) {
data := NewPreimageOracleData([]byte{1, 2, 3}, []byte{4, 5, 6}, 7) data := NewPreimageOracleData([]byte{1, 2, 3}, []byte{4, 5, 6}, 7)
require.True(t, data.IsLocal) require.True(t, data.IsLocal)
require.Equal(t, []byte{1, 2, 3}, data.OracleKey) require.Equal(t, []byte{1, 2, 3}, data.OracleKey)
require.Equal(t, []byte{4, 5, 6}, data.OracleData) require.Equal(t, []byte{4, 5, 6}, data.GetPreimageWithSize())
require.Equal(t, uint32(7), data.OracleOffset) require.Equal(t, uint32(7), data.OracleOffset)
}) })
...@@ -20,7 +20,7 @@ func TestNewPreimageOracleData(t *testing.T) { ...@@ -20,7 +20,7 @@ func TestNewPreimageOracleData(t *testing.T) {
data := NewPreimageOracleData([]byte{0, 2, 3}, []byte{4, 5, 6}, 7) data := NewPreimageOracleData([]byte{0, 2, 3}, []byte{4, 5, 6}, 7)
require.False(t, data.IsLocal) require.False(t, data.IsLocal)
require.Equal(t, []byte{0, 2, 3}, data.OracleKey) require.Equal(t, []byte{0, 2, 3}, data.OracleKey)
require.Equal(t, []byte{4, 5, 6}, data.OracleData) require.Equal(t, []byte{4, 5, 6}, data.GetPreimageWithSize())
require.Equal(t, uint32(7), data.OracleOffset) require.Equal(t, uint32(7), data.OracleOffset)
}) })
} }
......
...@@ -106,7 +106,7 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) * ...@@ -106,7 +106,7 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) *
func (h *FactoryHelper) PreimageHelper(ctx context.Context) *preimage.Helper { func (h *FactoryHelper) PreimageHelper(ctx context.Context) *preimage.Helper {
opts := &bind.CallOpts{Context: ctx} opts := &bind.CallOpts{Context: ctx}
gameAddr, err := h.factory.GameImpls(opts, alphabetGameType) gameAddr, err := h.factory.GameImpls(opts, cannonGameType)
h.require.NoError(err) h.require.NoError(err)
game, err := bindings.NewFaultDisputeGameCaller(gameAddr, h.client) game, err := bindings.NewFaultDisputeGameCaller(gameAddr, h.client)
h.require.NoError(err) h.require.NoError(err)
......
...@@ -538,10 +538,10 @@ func (g *OutputGameHelper) waitForPreimageInOracle(ctx context.Context, data *ty ...@@ -538,10 +538,10 @@ func (g *OutputGameHelper) waitForPreimageInOracle(ctx context.Context, data *ty
defer cancel() defer cancel()
oracle := g.oracle(ctx) oracle := g.oracle(ctx)
err := wait.For(timedCtx, time.Second, func() (bool, error) { err := wait.For(timedCtx, time.Second, func() (bool, error) {
g.t.Logf("Waiting for preimage (%v) to be present in oracle", data.OracleKey) g.t.Logf("Waiting for preimage (%v) to be present in oracle", common.Bytes2Hex(data.OracleKey))
return oracle.GlobalDataExists(ctx, data) return oracle.GlobalDataExists(ctx, data)
}) })
g.require.NoErrorf(err, "Did not find preimage (%v) in oracle", data.OracleKey) g.require.NoErrorf(err, "Did not find preimage (%v) in oracle", common.Bytes2Hex(data.OracleKey))
} }
func (g *OutputGameHelper) uploadPreimage(ctx context.Context, data *types.PreimageOracleData, privateKey *ecdsa.PrivateKey) { func (g *OutputGameHelper) uploadPreimage(ctx context.Context, data *types.PreimageOracleData, privateKey *ecdsa.PrivateKey) {
......
...@@ -212,12 +212,10 @@ func TestOutputCannonDefendStep(t *testing.T) { ...@@ -212,12 +212,10 @@ func TestOutputCannonDefendStep(t *testing.T) {
} }
func TestOutputCannonStepWithLargePreimage(t *testing.T) { func TestOutputCannonStepWithLargePreimage(t *testing.T) {
// TODO(client-pod#525): Fix preimage insertion and enable this test
t.Skip("Preimage not being inserted under correct key")
op_e2e.InitParallel(t, op_e2e.UsesCannon, op_e2e.UseExecutor(0)) op_e2e.InitParallel(t, op_e2e.UsesCannon, op_e2e.UseExecutor(0))
ctx := context.Background() ctx := context.Background()
sys, l1Client := startFaultDisputeSystem(t, withLargeBatches()) sys, _ := startFaultDisputeSystem(t, withLargeBatches())
t.Cleanup(sys.Close) t.Cleanup(sys.Close)
// Send a large l2 transaction and use the receipt block number as the l2 block number for the game // Send a large l2 transaction and use the receipt block number as the l2 block number for the game
...@@ -254,12 +252,8 @@ func TestOutputCannonStepWithLargePreimage(t *testing.T) { ...@@ -254,12 +252,8 @@ func TestOutputCannonStepWithLargePreimage(t *testing.T) {
sender := sys.Cfg.Secrets.Addresses().Alice sender := sys.Cfg.Secrets.Addresses().Alice
preimageLoadCheck := game.CreateStepLargePreimageLoadCheck(ctx, sender) preimageLoadCheck := game.CreateStepLargePreimageLoadCheck(ctx, sender)
game.ChallengeToPreimageLoad(ctx, outputRootClaim, sys.Cfg.Secrets.Alice, cannon.PreimageLargerThan(18_000), preimageLoadCheck, false) game.ChallengeToPreimageLoad(ctx, outputRootClaim, sys.Cfg.Secrets.Alice, cannon.PreimageLargerThan(18_000), preimageLoadCheck, false)
// The above method already verified the image was uploaded and step called successfully
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) // So we don't waste time resolving the game - that's tested elsewhere.
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForInactivity(ctx, 10, true)
game.LogGameData(ctx)
require.EqualValues(t, disputegame.StatusChallengerWins, game.Status(ctx))
} }
func TestOutputCannonStepWithPreimage(t *testing.T) { func TestOutputCannonStepWithPreimage(t *testing.T) {
......
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