Commit 21825012 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #6392 from ethereum-optimism/aj/challenger-proof-data

op-challenger: Provide proof data when calling step
parents bad663e1 1a35e0d8
...@@ -135,6 +135,7 @@ func (a *Agent) step(ctx context.Context, claim Claim, game Game) error { ...@@ -135,6 +135,7 @@ func (a *Agent) step(ctx context.Context, claim Claim, game Game) error {
ClaimIndex: uint64(step.LeafClaim.ContractIndex), ClaimIndex: uint64(step.LeafClaim.ContractIndex),
IsAttack: step.IsAttack, IsAttack: step.IsAttack,
StateData: step.PreState, StateData: step.PreState,
Proof: step.ProofData,
} }
return a.responder.Step(ctx, callData) return a.responder.Step(ctx, callData)
} }
...@@ -26,21 +26,21 @@ func NewAlphabetProvider(state string, depth uint64) *AlphabetProvider { ...@@ -26,21 +26,21 @@ func NewAlphabetProvider(state string, depth uint64) *AlphabetProvider {
} }
// GetPreimage returns the preimage for the given hash. // GetPreimage returns the preimage for the given hash.
func (ap *AlphabetProvider) GetPreimage(i uint64) ([]byte, error) { func (ap *AlphabetProvider) GetPreimage(i uint64) ([]byte, []byte, error) {
// The index cannot be larger than the maximum index as computed by the depth. // The index cannot be larger than the maximum index as computed by the depth.
if i >= ap.maxLen { if i >= ap.maxLen {
return []byte{}, ErrIndexTooLarge return nil, nil, ErrIndexTooLarge
} }
// We extend the deepest hash to the maximum depth if the trace is not expansive. // We extend the deepest hash to the maximum depth if the trace is not expansive.
if i >= uint64(len(ap.state)) { if i >= uint64(len(ap.state)) {
return ap.GetPreimage(uint64(len(ap.state)) - 1) return ap.GetPreimage(uint64(len(ap.state)) - 1)
} }
return BuildAlphabetPreimage(i, ap.state[i]), nil return BuildAlphabetPreimage(i, ap.state[i]), []byte{}, nil
} }
// Get returns the claim value at the given index in the trace. // Get returns the claim value at the given index in the trace.
func (ap *AlphabetProvider) Get(i uint64) (common.Hash, error) { func (ap *AlphabetProvider) Get(i uint64) (common.Hash, error) {
claimBytes, err := ap.GetPreimage(i) claimBytes, _, err := ap.GetPreimage(i)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
......
...@@ -55,16 +55,17 @@ func FuzzIndexToBytes(f *testing.F) { ...@@ -55,16 +55,17 @@ func FuzzIndexToBytes(f *testing.F) {
func TestGetPreimage_Succeeds(t *testing.T) { func TestGetPreimage_Succeeds(t *testing.T) {
ap := NewAlphabetProvider("abc", 2) ap := NewAlphabetProvider("abc", 2)
expected := BuildAlphabetPreimage(0, "a'") expected := BuildAlphabetPreimage(0, "a'")
retrieved, err := ap.GetPreimage(uint64(0)) retrieved, proof, err := ap.GetPreimage(uint64(0))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expected, retrieved) require.Equal(t, expected, retrieved)
require.Empty(t, proof)
} }
// TestGetPreimage_TooLargeIndex_Fails tests the GetPreimage // TestGetPreimage_TooLargeIndex_Fails tests the GetPreimage
// function errors if the index is too large. // function errors if the index is too large.
func TestGetPreimage_TooLargeIndex_Fails(t *testing.T) { func TestGetPreimage_TooLargeIndex_Fails(t *testing.T) {
ap := NewAlphabetProvider("abc", 2) ap := NewAlphabetProvider("abc", 2)
_, err := ap.GetPreimage(4) _, _, err := ap.GetPreimage(4)
require.ErrorIs(t, err, ErrIndexTooLarge) require.ErrorIs(t, err, ErrIndexTooLarge)
} }
......
...@@ -43,16 +43,20 @@ func (p *CannonTraceProvider) Get(i uint64) (common.Hash, error) { ...@@ -43,16 +43,20 @@ func (p *CannonTraceProvider) Get(i uint64) (common.Hash, error) {
return value, nil return value, nil
} }
func (p *CannonTraceProvider) GetPreimage(i uint64) ([]byte, error) { func (p *CannonTraceProvider) GetPreimage(i uint64) ([]byte, []byte, error) {
proof, err := p.loadProof(i) proof, err := p.loadProof(i)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
value := ([]byte)(proof.StateData) value := ([]byte)(proof.StateData)
if len(value) == 0 { if len(value) == 0 {
return nil, errors.New("proof missing state data") return nil, nil, errors.New("proof missing state data")
} }
return value, nil data := ([]byte)(proof.ProofData)
if len(data) == 0 {
return nil, nil, errors.New("proof missing proof data")
}
return value, data, nil
} }
func (p *CannonTraceProvider) AbsolutePreState() []byte { func (p *CannonTraceProvider) AbsolutePreState() []byte {
......
...@@ -43,27 +43,31 @@ func TestGet(t *testing.T) { ...@@ -43,27 +43,31 @@ func TestGet(t *testing.T) {
func TestGetPreimage(t *testing.T) { func TestGetPreimage(t *testing.T) {
provider := setupWithTestData(t) provider := setupWithTestData(t)
t.Run("ExistingProof", func(t *testing.T) { t.Run("ExistingProof", func(t *testing.T) {
value, err := provider.GetPreimage(0) value, proof, err := provider.GetPreimage(0)
require.NoError(t, err) require.NoError(t, err)
expected := common.Hex2Bytes("b8f068de604c85ea0e2acd437cdb47add074a2d70b81d018390c504b71fe26f400000000000000000000000000000000000000000000000000000000000000000000000000") expected := common.Hex2Bytes("b8f068de604c85ea0e2acd437cdb47add074a2d70b81d018390c504b71fe26f400000000000000000000000000000000000000000000000000000000000000000000000000")
require.Equal(t, expected, value) require.Equal(t, expected, value)
expectedProof := common.Hex2Bytes("08028e3c0000000000000000000000003c01000a24210b7c00200008000000008fa40004")
require.Equal(t, expectedProof, proof)
}) })
t.Run("ProofUnavailable", func(t *testing.T) { t.Run("ProofUnavailable", func(t *testing.T) {
_, err := provider.GetPreimage(7) _, _, err := provider.GetPreimage(7)
require.ErrorIs(t, err, os.ErrNotExist) require.ErrorIs(t, err, os.ErrNotExist)
}) })
t.Run("MissingStateData", func(t *testing.T) { t.Run("MissingStateData", func(t *testing.T) {
_, err := provider.GetPreimage(1) _, _, err := provider.GetPreimage(1)
require.ErrorContains(t, err, "missing state data") require.ErrorContains(t, err, "missing state data")
}) })
t.Run("IgnoreUnknownFields", func(t *testing.T) { t.Run("IgnoreUnknownFields", func(t *testing.T) {
value, err := provider.GetPreimage(2) value, proof, err := provider.GetPreimage(2)
require.NoError(t, err) require.NoError(t, err)
expected := common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc") expected := common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc")
require.Equal(t, expected, value) require.Equal(t, expected, value)
expectedProof := common.Hex2Bytes("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd")
require.Equal(t, expectedProof, proof)
}) })
} }
......
...@@ -67,6 +67,7 @@ type StepData struct { ...@@ -67,6 +67,7 @@ type StepData struct {
LeafClaim Claim LeafClaim Claim
IsAttack bool IsAttack bool
PreState []byte PreState []byte
ProofData []byte
} }
// AttemptStep determines what step should occur for a given leaf claim. // AttemptStep determines what step should occur for a given leaf claim.
...@@ -84,6 +85,7 @@ func (s *Solver) AttemptStep(claim Claim, agreeWithClaimLevel bool) (StepData, e ...@@ -84,6 +85,7 @@ func (s *Solver) AttemptStep(claim Claim, agreeWithClaimLevel bool) (StepData, e
} }
index := claim.TraceIndex(s.gameDepth) index := claim.TraceIndex(s.gameDepth)
var preState []byte var preState []byte
var proofData []byte
// If we are attacking index 0, we provide the absolute pre-state, not an intermediate state // If we are attacking index 0, we provide the absolute pre-state, not an intermediate state
if index == 0 && !claimCorrect { if index == 0 && !claimCorrect {
preState = s.AbsolutePreState() preState = s.AbsolutePreState()
...@@ -92,7 +94,7 @@ func (s *Solver) AttemptStep(claim Claim, agreeWithClaimLevel bool) (StepData, e ...@@ -92,7 +94,7 @@ func (s *Solver) AttemptStep(claim Claim, agreeWithClaimLevel bool) (StepData, e
if !claimCorrect { if !claimCorrect {
index = index - 1 index = index - 1
} }
preState, err = s.GetPreimage(index) preState, proofData, err = s.GetPreimage(index)
if err != nil { if err != nil {
return StepData{}, err return StepData{}, err
} }
...@@ -102,6 +104,7 @@ func (s *Solver) AttemptStep(claim Claim, agreeWithClaimLevel bool) (StepData, e ...@@ -102,6 +104,7 @@ func (s *Solver) AttemptStep(claim Claim, agreeWithClaimLevel bool) (StepData, e
LeafClaim: claim, LeafClaim: claim,
IsAttack: !claimCorrect, IsAttack: !claimCorrect,
PreState: preState, PreState: preState,
ProofData: proofData,
}, nil }, nil
} }
......
...@@ -100,7 +100,7 @@ func TestNoMoveAgainstOwnLevel(t *testing.T) { ...@@ -100,7 +100,7 @@ func TestNoMoveAgainstOwnLevel(t *testing.T) {
func TestAttemptStep(t *testing.T) { func TestAttemptStep(t *testing.T) {
maxDepth := 3 maxDepth := 3
canonicalProvider := NewAlphabetProvider("abcdefgh", uint64(maxDepth)) canonicalProvider := &alphabetWithProofProvider{NewAlphabetProvider("abcdefgh", uint64(maxDepth))}
solver := NewSolver(maxDepth, canonicalProvider) solver := NewSolver(maxDepth, canonicalProvider)
_, _, middle, bottom := createTestClaims() _, _, middle, bottom := createTestClaims()
...@@ -116,6 +116,7 @@ func TestAttemptStep(t *testing.T) { ...@@ -116,6 +116,7 @@ func TestAttemptStep(t *testing.T) {
require.Equal(t, bottom, step.LeafClaim) require.Equal(t, bottom, step.LeafClaim)
require.True(t, step.IsAttack) require.True(t, step.IsAttack)
require.Equal(t, step.PreState, BuildAlphabetPreimage(3, "d")) require.Equal(t, step.PreState, BuildAlphabetPreimage(3, "d"))
require.Equal(t, step.ProofData, []byte{3})
_, err = solver.AttemptStep(middle, false) _, err = solver.AttemptStep(middle, false)
require.Error(t, err) require.Error(t, err)
...@@ -137,3 +138,15 @@ func TestAttempStep_AgreeWithClaimLevel_Fails(t *testing.T) { ...@@ -137,3 +138,15 @@ func TestAttempStep_AgreeWithClaimLevel_Fails(t *testing.T) {
require.Error(t, err) require.Error(t, err)
require.Equal(t, StepData{}, step) require.Equal(t, StepData{}, step)
} }
type alphabetWithProofProvider struct {
*AlphabetProvider
}
func (a *alphabetWithProofProvider) GetPreimage(i uint64) ([]byte, []byte, error) {
preimage, _, err := a.AlphabetProvider.GetPreimage(i)
if err != nil {
return nil, nil, err
}
return preimage, []byte{byte(i)}, nil
}
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
) )
var ( var (
ErrNegativeIndex = errors.New("index cannot be negative")
ErrIndexTooLarge = errors.New("index is larger than the maximum index") ErrIndexTooLarge = errors.New("index is larger than the maximum index")
) )
...@@ -20,13 +19,17 @@ type StepCallData struct { ...@@ -20,13 +19,17 @@ type StepCallData struct {
Proof []byte Proof []byte
} }
// TraceProvider is a generic way to get a claim value at a specific // TraceProvider is a generic way to get a claim value at a specific step in the trace.
// step in the trace.
// Get(i) = Keccak256(GetPreimage(i))
// AbsolutePreState is the value of the trace that transitions to the trace value at index 0
type TraceProvider interface { type TraceProvider interface {
// Get returns the claim value at the requested index.
// Get(i) = Keccak256(GetPreimage(i))
Get(i uint64) (common.Hash, error) Get(i uint64) (common.Hash, error)
GetPreimage(i uint64) ([]byte, error)
// GetPreimage returns the pre-image for a claim at the specified trace index, along
// with any associated proof data to assist in its verification.
GetPreimage(i uint64) (preimage []byte, proofData []byte, err error)
// AbsolutePreState is the pre-image value of the trace that transitions to the trace value at index 0
AbsolutePreState() []byte AbsolutePreState() []byte
} }
......
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