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

op-challenger: Implement keccak padding. (#9272)

* op-challenger: Implement keccak padding.

* op-challenger: Add verification to unit test that generated challenge has a StateMatrix preimage that matches the prestate leaf.

* op-challenger: Fix encoding of state matrix.
parent c874ecc9
...@@ -147,16 +147,11 @@ func (c *PreimageOracleContract) Squeeze( ...@@ -147,16 +147,11 @@ func (c *PreimageOracleContract) Squeeze(
// abiEncodeStateMatrix encodes the state matrix for the contract ABI // abiEncodeStateMatrix encodes the state matrix for the contract ABI
func abiEncodeStateMatrix(stateMatrix *matrix.StateMatrix) bindings.LibKeccakStateMatrix { func abiEncodeStateMatrix(stateMatrix *matrix.StateMatrix) bindings.LibKeccakStateMatrix {
return abiEncodePackedState(stateMatrix.PackState()) return abiEncodeSnapshot(stateMatrix.StateSnapshot())
} }
func abiEncodePackedState(packedState []byte) bindings.LibKeccakStateMatrix { func abiEncodeSnapshot(packedState keccakTypes.StateSnapshot) bindings.LibKeccakStateMatrix {
stateSlice := new([25]uint64) return bindings.LibKeccakStateMatrix{State: packedState}
// SAFETY: a maximum of 25 * 8 bytes will be read from packedState and written to stateSlice
for i := 0; i < min(len(packedState), 25*8); i += 8 {
stateSlice[i/8] = new(big.Int).SetBytes(packedState[i : i+8]).Uint64()
}
return bindings.LibKeccakStateMatrix{State: *stateSlice}
} }
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) {
...@@ -271,7 +266,7 @@ func (c *PreimageOracleContract) ChallengeTx(ident keccakTypes.LargePreimageIden ...@@ -271,7 +266,7 @@ func (c *PreimageOracleContract) ChallengeTx(ident keccakTypes.LargePreimageIden
methodChallengeLPP, methodChallengeLPP,
ident.Claimant, ident.Claimant,
ident.UUID, ident.UUID,
abiEncodePackedState(challenge.StateMatrix), abiEncodeSnapshot(challenge.StateMatrix),
toPreimageOracleLeaf(challenge.Prestate), toPreimageOracleLeaf(challenge.Prestate),
challenge.PrestateProof, challenge.PrestateProof,
toPreimageOracleLeaf(challenge.Poststate), toPreimageOracleLeaf(challenge.Poststate),
......
package contracts package contracts
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"math" "math"
...@@ -503,7 +502,7 @@ func TestChallenge_First(t *testing.T) { ...@@ -503,7 +502,7 @@ func TestChallenge_First(t *testing.T) {
UUID: big.NewInt(4829), UUID: big.NewInt(4829),
} }
challenge := keccakTypes.Challenge{ challenge := keccakTypes.Challenge{
StateMatrix: []byte{1, 2, 3, 4, 5}, StateMatrix: keccakTypes.StateSnapshot{1, 2, 3, 4, 5},
Prestate: keccakTypes.Leaf{}, Prestate: keccakTypes.Leaf{},
Poststate: keccakTypes.Leaf{ Poststate: keccakTypes.Leaf{
Input: [136]byte{5, 4, 3, 2, 1}, Input: [136]byte{5, 4, 3, 2, 1},
...@@ -536,7 +535,7 @@ func TestChallenge_NotFirst(t *testing.T) { ...@@ -536,7 +535,7 @@ func TestChallenge_NotFirst(t *testing.T) {
UUID: big.NewInt(4829), UUID: big.NewInt(4829),
} }
challenge := keccakTypes.Challenge{ challenge := keccakTypes.Challenge{
StateMatrix: bytes.Repeat([]byte{1, 2, 3, 4, 5, 6, 7, 8}, 25), StateMatrix: keccakTypes.StateSnapshot{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
Prestate: keccakTypes.Leaf{ Prestate: keccakTypes.Leaf{
Input: [136]byte{9, 8, 7, 6, 5}, Input: [136]byte{9, 8, 7, 6, 5},
Index: 3, Index: 3,
...@@ -553,7 +552,7 @@ func TestChallenge_NotFirst(t *testing.T) { ...@@ -553,7 +552,7 @@ func TestChallenge_NotFirst(t *testing.T) {
stubRpc.SetResponse(oracleAddr, methodChallengeLPP, batching.BlockLatest, stubRpc.SetResponse(oracleAddr, methodChallengeLPP, batching.BlockLatest,
[]interface{}{ []interface{}{
ident.Claimant, ident.UUID, ident.Claimant, ident.UUID,
abiEncodePackedState(challenge.StateMatrix), bindings.LibKeccakStateMatrix{State: challenge.StateMatrix},
bindings.PreimageOracleLeaf{ bindings.PreimageOracleLeaf{
Input: challenge.Prestate.Input[:], Input: challenge.Prestate.Input[:],
Index: new(big.Int).SetUint64(challenge.Prestate.Index), Index: new(big.Int).SetUint64(challenge.Prestate.Index),
......
package preimages package preimages
import ( import (
"bytes"
"context" "context"
"errors" "errors"
"io"
"math/big" "math/big"
"testing" "testing"
"time" "time"
...@@ -204,61 +206,21 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) { ...@@ -204,61 +206,21 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) {
name: "FullLeaf", name: "FullLeaf",
input: fullLeaf[:], input: fullLeaf[:],
addCalls: 1, addCalls: 1,
prestateLeaf: keccakTypes.Leaf{
Input: *fullLeaf,
Index: 0,
StateCommitment: common.HexToHash("9788a3b3bc36c482525b5890767be37130c997917bceca6e91a6c93359a4d1c6"),
},
poststateLeaf: keccakTypes.Leaf{
Input: [keccakTypes.BlockSize]byte{},
Index: 1,
StateCommitment: common.HexToHash("78358b902b7774b314bcffdf0948746f18d6044086e76e3924d585dca3486c7d"),
},
}, },
{ {
name: "MultipleLeaves", name: "MultipleLeaves",
input: append(fullLeaf[:], append(fullLeaf[:], fullLeaf[:]...)...), input: append(fullLeaf[:], append(fullLeaf[:], fullLeaf[:]...)...),
addCalls: 1, addCalls: 1,
prestateLeaf: keccakTypes.Leaf{
Input: *fullLeaf,
Index: 2,
StateCommitment: common.HexToHash("e3deed8ab6f8bbcf3d4fe825d74f703b3f2fc2f5b0afaa2574926fcfd0d4c895"),
},
poststateLeaf: keccakTypes.Leaf{
Input: [keccakTypes.BlockSize]byte{},
Index: 3,
StateCommitment: common.HexToHash("79115eeab1ff2eccf5baf3ea2dda13bc79c548ce906bdd16433a23089c679df2"),
},
}, },
{ {
name: "MultipleLeavesUnaligned", name: "MultipleLeavesUnaligned",
input: append(fullLeaf[:], append(fullLeaf[:], byte(9))...), input: append(fullLeaf[:], append(fullLeaf[:], byte(9))...),
addCalls: 1, addCalls: 1,
prestateLeaf: keccakTypes.Leaf{
Input: *fullLeaf,
Index: 1,
StateCommitment: common.HexToHash("b5ea400e375b2c1ce348f3cc4ad5b6ad28e1b36759ddd2aba155f0b1d476b015"),
},
poststateLeaf: keccakTypes.Leaf{
Input: [keccakTypes.BlockSize]byte{byte(9)},
Index: 2,
StateCommitment: common.HexToHash("fa87e115dc4786e699bf80cc75d13ac1e2db0708c1418fc8cbc9800d17b5811a"),
},
}, },
{ {
name: "MultipleChunks", name: "MultipleChunks",
input: append(chunk, append(fullLeaf[:], fullLeaf[:]...)...), input: append(chunk, append(fullLeaf[:], fullLeaf[:]...)...),
addCalls: 2, addCalls: 2,
prestateLeaf: keccakTypes.Leaf{
Input: *fullLeaf,
Index: 301,
StateCommitment: common.HexToHash("4e9c55542478939feca4ff55ee98fbc632bb65a784a55b94536644bc87298ca4"),
},
poststateLeaf: keccakTypes.Leaf{
Input: [keccakTypes.BlockSize]byte{},
Index: 302,
StateCommitment: common.HexToHash("775020bfcaa93700263d040a4eeec3c8c3cf09e178457d04044594beaaf5e20b"),
},
}, },
} }
...@@ -275,8 +237,16 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) { ...@@ -275,8 +237,16 @@ func TestLargePreimageUploader_UploadPreimage_Succeeds(t *testing.T) {
// for successful large preimage upload calls. // for successful large preimage upload calls.
require.Equal(t, 1, contract.initCalls) require.Equal(t, 1, contract.initCalls)
require.Equal(t, 1, contract.squeezeCalls) require.Equal(t, 1, contract.squeezeCalls)
require.Equal(t, test.prestateLeaf, contract.squeezePrestate)
require.Equal(t, test.poststateLeaf, contract.squeezePoststate) // Use the StateMatrix to determine the expected leaves so it includes padding correctly.
// We rely on the unit tests for StateMatrix to confirm that it does the right thing.
s := matrix.NewStateMatrix()
_, err = s.AbsorbUpTo(bytes.NewReader(test.input), keccakTypes.BlockSize*10000)
require.ErrorIs(t, err, io.EOF)
prestate, _ := s.PrestateWithProof()
poststate, _ := s.PoststateWithProof()
require.Equal(t, prestate, contract.squeezePrestate)
require.Equal(t, poststate, contract.squeezePoststate)
}) })
} }
......
...@@ -60,6 +60,7 @@ func (c *PreimageChallenger) Challenge(ctx context.Context, blockHash common.Has ...@@ -60,6 +60,7 @@ func (c *PreimageChallenger) Challenge(ctx context.Context, blockHash common.Has
logger.Error("Failed to verify large preimage", "err", err) logger.Error("Failed to verify large preimage", "err", err)
return return
} }
logger.Info("Challenging preimage", "block", challenge.Poststate.Index)
tx, err := oracle.ChallengeTx(preimage.LargePreimageIdent, challenge) tx, err := oracle.ChallengeTx(preimage.LargePreimageIdent, challenge)
if err != nil { if err != nil {
logger.Error("Failed to create challenge transaction", "err", err) logger.Error("Failed to create challenge transaction", "err", err)
......
...@@ -43,8 +43,8 @@ func TestChallenge(t *testing.T) { ...@@ -43,8 +43,8 @@ func TestChallenge(t *testing.T) {
t.Run("SendChallenges", func(t *testing.T) { t.Run("SendChallenges", func(t *testing.T) {
verifier, sender, oracle, challenger := setupChallengerTest(logger) verifier, sender, oracle, challenger := setupChallengerTest(logger)
verifier.challenges[preimages[1].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: []byte{0x01}} verifier.challenges[preimages[1].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: keccakTypes.StateSnapshot{0x01}}
verifier.challenges[preimages[2].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: []byte{0x02}} verifier.challenges[preimages[2].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: keccakTypes.StateSnapshot{0x02}}
err := challenger.Challenge(context.Background(), common.Hash{0xaa}, oracle, preimages) err := challenger.Challenge(context.Background(), common.Hash{0xaa}, oracle, preimages)
require.NoError(t, err) require.NoError(t, err)
...@@ -59,7 +59,7 @@ func TestChallenge(t *testing.T) { ...@@ -59,7 +59,7 @@ func TestChallenge(t *testing.T) {
t.Run("ReturnErrorWhenSendingFails", func(t *testing.T) { t.Run("ReturnErrorWhenSendingFails", func(t *testing.T) {
verifier, sender, oracle, challenger := setupChallengerTest(logger) verifier, sender, oracle, challenger := setupChallengerTest(logger)
verifier.challenges[preimages[1].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: []byte{0x01}} verifier.challenges[preimages[1].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: keccakTypes.StateSnapshot{0x01}}
sender.err = errors.New("boom") sender.err = errors.New("boom")
err := challenger.Challenge(context.Background(), common.Hash{0xaa}, oracle, preimages) err := challenger.Challenge(context.Background(), common.Hash{0xaa}, oracle, preimages)
require.ErrorIs(t, err, sender.err) require.ErrorIs(t, err, sender.err)
...@@ -69,7 +69,7 @@ func TestChallenge(t *testing.T) { ...@@ -69,7 +69,7 @@ func TestChallenge(t *testing.T) {
logs := testlog.Capture(logger) logs := testlog.Capture(logger)
verifier, _, oracle, challenger := setupChallengerTest(logger) verifier, _, oracle, challenger := setupChallengerTest(logger)
verifier.challenges[preimages[1].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: []byte{0x01}} verifier.challenges[preimages[1].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: keccakTypes.StateSnapshot{0x01}}
oracle.err = errors.New("boom") oracle.err = errors.New("boom")
err := challenger.Challenge(context.Background(), common.Hash{0xaa}, oracle, preimages) err := challenger.Challenge(context.Background(), common.Hash{0xaa}, oracle, preimages)
require.NoError(t, err) require.NoError(t, err)
...@@ -82,7 +82,7 @@ func TestChallenge(t *testing.T) { ...@@ -82,7 +82,7 @@ func TestChallenge(t *testing.T) {
logs := testlog.Capture(logger) logs := testlog.Capture(logger)
verifier, _, oracle, challenger := setupChallengerTest(logger) verifier, _, oracle, challenger := setupChallengerTest(logger)
verifier.challenges[preimages[1].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: []byte{0x01}} verifier.challenges[preimages[1].LargePreimageIdent] = keccakTypes.Challenge{StateMatrix: keccakTypes.StateSnapshot{0x01}}
verifier.err = errors.New("boom") verifier.err = errors.New("boom")
err := challenger.Challenge(context.Background(), common.Hash{0xaa}, oracle, preimages) err := challenger.Challenge(context.Background(), common.Hash{0xaa}, oracle, preimages)
require.NoError(t, err) require.NoError(t, err)
...@@ -157,6 +157,6 @@ func (s *stubChallengerOracle) ChallengeTx(ident keccakTypes.LargePreimageIdent, ...@@ -157,6 +157,6 @@ func (s *stubChallengerOracle) ChallengeTx(ident keccakTypes.LargePreimageIdent,
} }
return txmgr.TxCandidate{ return txmgr.TxCandidate{
To: &ident.Claimant, To: &ident.Claimant,
TxData: append(ident.UUID.Bytes(), challenge.StateMatrix...), TxData: append(ident.UUID.Bytes(), challenge.StateMatrix.Pack()...),
}, nil }, nil
} }
...@@ -4,12 +4,10 @@ import ( ...@@ -4,12 +4,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math/big"
"github.com/ethereum-optimism/optimism/op-challenger/game/keccak/merkle" "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/merkle"
"github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types" "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
) )
...@@ -30,14 +28,13 @@ var ( ...@@ -30,14 +28,13 @@ var (
ErrInvalidMaxLen = errors.New("invalid max length to absorb") ErrInvalidMaxLen = errors.New("invalid max length to absorb")
ErrIncorrectCommitmentCount = errors.New("incorrect number of commitments for input length") ErrIncorrectCommitmentCount = errors.New("incorrect number of commitments for input length")
ErrValid = errors.New("state commitments are valid") ErrValid = errors.New("state commitments are valid")
uint256Size = 32
) )
// Challenge creates a [types.Challenge] to invalidate the provided preimage data if possible. // Challenge creates a [types.Challenge] to invalidate the provided preimage data if possible.
// [ErrValid] is returned if the provided inputs are valid and no challenge can be created. // [ErrValid] is returned if the provided inputs are valid and no challenge can be created.
func Challenge(data io.Reader, commitments []common.Hash) (types.Challenge, error) { func Challenge(data io.Reader, commitments []common.Hash) (types.Challenge, error) {
s := NewStateMatrix() s := NewStateMatrix()
lastValidState := s.PackState() lastValidState := s.StateSnapshot()
var lastValidLeaf types.Leaf var lastValidLeaf types.Leaf
var firstInvalidLeaf types.Leaf var firstInvalidLeaf types.Leaf
for i := 0; ; i++ { for i := 0; ; i++ {
...@@ -59,7 +56,7 @@ func Challenge(data io.Reader, commitments []common.Hash) (types.Challenge, erro ...@@ -59,7 +56,7 @@ func Challenge(data io.Reader, commitments []common.Hash) (types.Challenge, erro
lastValidLeaf = s.prestateLeaf lastValidLeaf = s.prestateLeaf
firstInvalidLeaf = s.poststateLeaf firstInvalidLeaf = s.poststateLeaf
} else { } else {
lastValidState = s.PackState() lastValidState = s.StateSnapshot()
} }
} }
if isEOF { if isEOF {
...@@ -99,24 +96,23 @@ func NewStateMatrix() *StateMatrix { ...@@ -99,24 +96,23 @@ func NewStateMatrix() *StateMatrix {
// StateCommitment returns the state commitment for the current state matrix. // StateCommitment returns the state commitment for the current state matrix.
// Additional data may be absorbed after calling this method. // Additional data may be absorbed after calling this method.
func (d *StateMatrix) StateCommitment() common.Hash { func (d *StateMatrix) StateCommitment() common.Hash {
buf := d.PackState() return crypto.Keccak256Hash(d.StateSnapshot().Pack())
return crypto.Keccak256Hash(buf)
} }
// PackState packs the state in to the solidity ABI encoding required for the state matrix func (d *StateMatrix) StateSnapshot() types.StateSnapshot {
func (d *StateMatrix) PackState() []byte { var snap types.StateSnapshot
buf := make([]byte, 0, len(d.s.a)*uint256Size) copy(snap[:], d.s.a[:])
for _, v := range d.s.a { return snap
buf = append(buf, math.U256Bytes(new(big.Int).SetUint64(v))...)
}
return buf
} }
// newLeafWithPadding creates a new [Leaf] from inputs, padding the input to the [BlockSize]. // newLeafWithPadding creates a new [Leaf] from inputs, padding the input to the [BlockSize].
func newLeafWithPadding(input []byte, index uint64, commitment common.Hash) types.Leaf { func (d *StateMatrix) newLeafWithPadding(input []byte, index uint64, commitment common.Hash, final bool) types.Leaf {
// TODO(client-pod#480): Add actual keccak padding to ensure the merkle proofs are correct (for readData)
var paddedInput [types.BlockSize]byte var paddedInput [types.BlockSize]byte
copy(paddedInput[:], input) copy(paddedInput[:], input)
if final {
pad(input, &paddedInput, d.s.dsbyte)
}
return types.Leaf{ return types.Leaf{
Input: paddedInput, Input: paddedInput,
Index: index, Index: index,
...@@ -124,6 +120,19 @@ func newLeafWithPadding(input []byte, index uint64, commitment common.Hash) type ...@@ -124,6 +120,19 @@ func newLeafWithPadding(input []byte, index uint64, commitment common.Hash) type
} }
} }
func pad(input []byte, paddedInput *[types.BlockSize]byte, dsbyte byte) {
// Pad with this instance's domain-separator bits. We know that there's
// at least one more byte of space in paddedInput because, if it were full,
// this wouldn't be the last block and the padding would be in the next block.
// dsbyte also contains the first one bit for the padding. See the comment in the state struct.
paddedInput[len(input)] = dsbyte
// The remaining bytes are already zeros since paddedInput is a new array.
// This adds the final one bit for the padding. Because of the way that
// bits are numbered from the LSB upwards, the final bit is the MSB of
// the last byte.
paddedInput[types.BlockSize-1] ^= 0x80
}
func (d *StateMatrix) AbsorbUpTo(in io.Reader, maxLen int) (types.InputData, error) { func (d *StateMatrix) AbsorbUpTo(in io.Reader, maxLen int) (types.InputData, error) {
if maxLen < types.BlockSize || maxLen%types.BlockSize != 0 { if maxLen < types.BlockSize || maxLen%types.BlockSize != 0 {
return types.InputData{}, ErrInvalidMaxLen return types.InputData{}, ErrInvalidMaxLen
...@@ -193,10 +202,10 @@ func (d *StateMatrix) absorbNextLeafInput(in io.Reader, stateCommitment func() c ...@@ -193,10 +202,10 @@ func (d *StateMatrix) absorbNextLeafInput(in io.Reader, stateCommitment func() c
commitment := stateCommitment() commitment := stateCommitment()
if d.poststateLeaf == (types.Leaf{}) { if d.poststateLeaf == (types.Leaf{}) {
d.prestateLeaf = types.Leaf{} d.prestateLeaf = types.Leaf{}
d.poststateLeaf = newLeafWithPadding(input, 0, commitment) d.poststateLeaf = d.newLeafWithPadding(input, 0, commitment, final)
} else { } else {
d.prestateLeaf = d.poststateLeaf d.prestateLeaf = d.poststateLeaf
d.poststateLeaf = newLeafWithPadding(input, d.prestateLeaf.Index+1, commitment) d.poststateLeaf = d.newLeafWithPadding(input, d.prestateLeaf.Index+1, commitment, final)
} }
d.merkleTree.AddLeaf(d.poststateLeaf.Hash()) d.merkleTree.AddLeaf(d.poststateLeaf.Hash())
if final { if final {
......
...@@ -45,7 +45,7 @@ func TestStateCommitment(t *testing.T) { ...@@ -45,7 +45,7 @@ func TestStateCommitment(t *testing.T) {
copy(state.s.a[:], test.matrix) copy(state.s.a[:], test.matrix)
expected := crypto.Keccak256Hash(common.Hex2Bytes(test.expectedPacked)) expected := crypto.Keccak256Hash(common.Hex2Bytes(test.expectedPacked))
actual := state.StateCommitment() actual := state.StateCommitment()
require.Equal(t, test.expectedPacked, common.Bytes2Hex(state.PackState())) require.Equal(t, test.expectedPacked, common.Bytes2Hex(state.StateSnapshot().Pack()))
require.Equal(t, expected, actual) require.Equal(t, expected, actual)
}) })
} }
...@@ -281,7 +281,11 @@ func TestVerifyPreimage(t *testing.T) { ...@@ -281,7 +281,11 @@ func TestVerifyPreimage(t *testing.T) {
} }
leafData := func(idx int) (out [types.BlockSize]byte) { leafData := func(idx int) (out [types.BlockSize]byte) {
end := min((idx+1)*types.BlockSize, len(preimage)) end := min((idx+1)*types.BlockSize, len(preimage))
copy(out[:], preimage[idx*types.BlockSize:end]) input := preimage[idx*types.BlockSize : end]
copy(out[:], input)
if len(input) < types.BlockSize {
pad(input, &out, newLegacyKeccak256().dsbyte)
}
return return
} }
// merkleTree creates the final merkle tree after including all leaves. // merkleTree creates the final merkle tree after including all leaves.
...@@ -308,7 +312,7 @@ func TestVerifyPreimage(t *testing.T) { ...@@ -308,7 +312,7 @@ func TestVerifyPreimage(t *testing.T) {
prestateLeaf := leafData(invalidIdx - 1) prestateLeaf := leafData(invalidIdx - 1)
poststateLeaf := leafData(invalidIdx) poststateLeaf := leafData(invalidIdx)
return types.Challenge{ return types.Challenge{
StateMatrix: s.PackState(), StateMatrix: s.StateSnapshot(),
Prestate: types.Leaf{ Prestate: types.Leaf{
Input: prestateLeaf, Input: prestateLeaf,
Index: uint64(invalidIdx - 1), Index: uint64(invalidIdx - 1),
...@@ -348,7 +352,7 @@ func TestVerifyPreimage(t *testing.T) { ...@@ -348,7 +352,7 @@ func TestVerifyPreimage(t *testing.T) {
return incorrectFirstCommitment return incorrectFirstCommitment
}, },
expected: types.Challenge{ expected: types.Challenge{
StateMatrix: NewStateMatrix().PackState(), StateMatrix: NewStateMatrix().StateSnapshot(),
Prestate: types.Leaf{}, Prestate: types.Leaf{},
Poststate: types.Leaf{ Poststate: types.Leaf{
Input: poststateLeaf, Input: poststateLeaf,
...@@ -380,6 +384,9 @@ func TestVerifyPreimage(t *testing.T) { ...@@ -380,6 +384,9 @@ func TestVerifyPreimage(t *testing.T) {
require.ErrorIs(t, err, test.expectedErr) require.ErrorIs(t, err, test.expectedErr)
require.Equal(t, test.expected.StateMatrix, challenge.StateMatrix, "Correct state matrix") require.Equal(t, test.expected.StateMatrix, challenge.StateMatrix, "Correct state matrix")
require.Equal(t, test.expected.Prestate, challenge.Prestate, "Correct prestate") require.Equal(t, test.expected.Prestate, challenge.Prestate, "Correct prestate")
if test.expected.Prestate != (types.Leaf{}) {
require.Equal(t, test.expected.Prestate.StateCommitment, crypto.Keccak256Hash(challenge.StateMatrix.Pack()), "Prestate matches leaf commitment")
}
require.Equal(t, test.expected.PrestateProof, challenge.PrestateProof, "Correct prestate proof") require.Equal(t, test.expected.PrestateProof, challenge.PrestateProof, "Correct prestate proof")
require.Equal(t, test.expected.Poststate, challenge.Poststate, "Correct poststate") require.Equal(t, test.expected.Poststate, challenge.Poststate, "Correct poststate")
require.Equal(t, test.expected.PoststateProof, challenge.PoststateProof, "Correct poststate proof") require.Equal(t, test.expected.PoststateProof, challenge.PoststateProof, "Correct poststate proof")
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,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/math"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
) )
...@@ -29,7 +30,7 @@ type Leaf struct { ...@@ -29,7 +30,7 @@ type Leaf struct {
func (l Leaf) Hash() common.Hash { func (l Leaf) Hash() common.Hash {
concatted := make([]byte, 0, 136+32+32) concatted := make([]byte, 0, 136+32+32)
concatted = append(concatted, l.Input[:]...) concatted = append(concatted, l.Input[:]...)
concatted = append(concatted, new(big.Int).SetUint64(l.Index).Bytes()...) concatted = append(concatted, math.U256Bytes(new(big.Int).SetUint64(l.Index))...)
concatted = append(concatted, l.StateCommitment.Bytes()...) concatted = append(concatted, l.StateCommitment.Bytes()...)
return crypto.Keccak256Hash(concatted) return crypto.Keccak256Hash(concatted)
} }
...@@ -70,9 +71,20 @@ func (m LargePreimageMetaData) ShouldVerify() bool { ...@@ -70,9 +71,20 @@ func (m LargePreimageMetaData) ShouldVerify() bool {
return m.Timestamp > 0 && !m.Countered return m.Timestamp > 0 && !m.Countered
} }
type StateSnapshot [25]uint64
// Pack packs the state in to the solidity ABI encoding required for the state matrix
func (s StateSnapshot) Pack() []byte {
buf := make([]byte, 0, len(s)*32)
for _, v := range s {
buf = append(buf, math.U256Bytes(new(big.Int).SetUint64(v))...)
}
return buf
}
type Challenge struct { type Challenge struct {
// StateMatrix is the packed state matrix preimage of the StateCommitment in Prestate // StateMatrix is the packed state matrix preimage of the StateCommitment in Prestate
StateMatrix []byte // TODO(client-pod#480): Need a better representation of this StateMatrix StateSnapshot // TODO(client-pod#480): Need a better representation of this
// Prestate is the valid leaf immediately prior to the first invalid leaf // Prestate is the valid leaf immediately prior to the first invalid leaf
Prestate Leaf Prestate Leaf
......
...@@ -3,7 +3,6 @@ package keccak ...@@ -3,7 +3,6 @@ package keccak
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
...@@ -18,8 +17,6 @@ type Fetcher interface { ...@@ -18,8 +17,6 @@ type Fetcher interface {
FetchInputs(ctx context.Context, blockHash common.Hash, oracle fetcher.Oracle, ident keccakTypes.LargePreimageIdent) ([]keccakTypes.InputData, error) FetchInputs(ctx context.Context, blockHash common.Hash, oracle fetcher.Oracle, ident keccakTypes.LargePreimageIdent) ([]keccakTypes.InputData, error)
} }
var ErrNotImplemented = errors.New("verify implementation not complete")
type PreimageVerifier struct { type PreimageVerifier struct {
log log.Logger log log.Logger
fetcher Fetcher fetcher Fetcher
......
...@@ -13,8 +13,6 @@ import ( ...@@ -13,8 +13,6 @@ import (
) )
func TestChallengeLargePreimages_ChallengeFirst(t *testing.T) { func TestChallengeLargePreimages_ChallengeFirst(t *testing.T) {
// TODO(client-pod#480: Fix padding and make this pass
t.Skip("Padding not implemented properly yet")
op_e2e.InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
sys, _ := startFaultDisputeSystem(t) sys, _ := startFaultDisputeSystem(t)
...@@ -34,8 +32,6 @@ func TestChallengeLargePreimages_ChallengeFirst(t *testing.T) { ...@@ -34,8 +32,6 @@ func TestChallengeLargePreimages_ChallengeFirst(t *testing.T) {
} }
func TestChallengeLargePreimages_ChallengeMiddle(t *testing.T) { func TestChallengeLargePreimages_ChallengeMiddle(t *testing.T) {
// TODO(client-pod#480: Fix padding and make this pass
t.Skip("Padding not implemented properly yet")
op_e2e.InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
sys, _ := startFaultDisputeSystem(t) sys, _ := startFaultDisputeSystem(t)
...@@ -52,3 +48,21 @@ func TestChallengeLargePreimages_ChallengeMiddle(t *testing.T) { ...@@ -52,3 +48,21 @@ func TestChallengeLargePreimages_ChallengeMiddle(t *testing.T) {
preimageHelper.WaitForChallenged(ctx, ident) preimageHelper.WaitForChallenged(ctx, ident)
} }
func TestChallengeLargePreimages_ChallengeLast(t *testing.T) {
op_e2e.InitParallel(t)
ctx := context.Background()
sys, _ := startFaultDisputeSystem(t)
t.Cleanup(sys.Close)
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
disputeGameFactory.StartChallenger(ctx, "Challenger",
challenger.WithAlphabet(sys.RollupEndpoint("sequencer")),
challenger.WithPrivKey(sys.Cfg.Secrets.Mallory))
preimageHelper := disputeGameFactory.PreimageHelper(ctx)
ident := preimageHelper.UploadLargePreimage(ctx, preimage.MinPreimageSize,
preimage.WithReplacedCommitment(132, common.Hash{0xaa}))
require.NotEqual(t, ident.Claimant, common.Address{})
preimageHelper.WaitForChallenged(ctx, ident)
}
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