Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
3bad749a
Commit
3bad749a
authored
Jun 21, 2023
by
Andreas Bigger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Solver implementation, Solver example, Position examples, and
tests.
parent
7ca852ec
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
308 additions
and
35 deletions
+308
-35
alphabet_provider_test.go
op-challenger/fault/alphabet_provider_test.go
+32
-0
position.go
op-challenger/fault/cmd/examples/position.go
+35
-0
solver.go
op-challenger/fault/cmd/examples/solver.go
+83
-0
main.go
op-challenger/fault/cmd/main.go
+4
-35
solver.go
op-challenger/fault/solver.go
+91
-0
solver_test.go
op-challenger/fault/solver_test.go
+63
-0
No files found.
op-challenger/fault/alphabet_provider_test.go
View file @
3bad749a
...
@@ -8,6 +8,38 @@ import (
...
@@ -8,6 +8,38 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
)
)
// TestAlphabetProvider_Get_ClaimsByTraceIndex tests the [fault.AlphabetProvider] Get function.
func
TestAlphabetProvider_Get_ClaimsByTraceIndex
(
t
*
testing
.
T
)
{
// Create a new alphabet provider.
canonicalProvider
:=
NewAlphabetProvider
(
"abcdefgh"
,
uint64
(
3
))
// Build a list of traces.
traces
:=
[]
struct
{
traceIndex
uint64
expectedHash
common
.
Hash
}{
{
7
,
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000768"
),
},
{
3
,
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000364"
),
},
{
5
,
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000566"
),
},
}
// Execute each trace and check the alphabet provider returns the expected hash.
for
_
,
trace
:=
range
traces
{
expectedHash
,
err
:=
canonicalProvider
.
Get
(
trace
.
traceIndex
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
trace
.
expectedHash
,
expectedHash
)
}
}
// FuzzIndexToBytes tests the IndexToBytes function.
// FuzzIndexToBytes tests the IndexToBytes function.
func
FuzzIndexToBytes
(
f
*
testing
.
F
)
{
func
FuzzIndexToBytes
(
f
*
testing
.
F
)
{
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
index
uint64
)
{
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
index
uint64
)
{
...
...
op-challenger/fault/cmd/examples/position.go
0 → 100644
View file @
3bad749a
package
examples
import
(
"github.com/ethereum-optimism/optimism/op-challenger/fault"
)
func
PositionExampleOne
()
{
// Example 1
// abcdefgh
// abcdexyz
// go left to d, then right to f, then left to e
p
:=
fault
.
Position
{}
p
.
Print
(
3
)
p
.
Attack
()
p
.
Print
(
3
)
p
.
Defend
()
p
.
Print
(
3
)
p
.
Attack
()
p
.
Print
(
3
)
}
func
PositionExampleTwo
()
{
// Example 2
// abcdefgh
// abqrstuv
// go left r, then left to b, then right to q
p
:=
fault
.
Position
{}
p
.
Print
(
3
)
p
.
Attack
()
p
.
Print
(
3
)
p
.
Attack
()
p
.
Print
(
3
)
p
.
Defend
()
p
.
Print
(
3
)
}
op-challenger/fault/cmd/examples/solver.go
0 → 100644
View file @
3bad749a
package
examples
import
(
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
)
// SolverExampleOne uses the [fault.Solver] with a [fault.AlphabetProvider]
// to print out fault game traces for the "abcdexyz" counter-state.
func
SolverExampleOne
()
{
fmt
.
Println
()
fmt
.
Println
(
"Solver: Example 1"
)
fmt
.
Println
()
// Construct the fault position.
canonical
:=
"abcdefgh"
disputed
:=
"abcdexyz"
maxDepth
:=
3
parent
:=
fault
.
Claim
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000768"
),
Position
:
fault
.
NewPosition
(
0
,
0
),
}
canonicalProvider
:=
fault
.
NewAlphabetProvider
(
canonical
,
uint64
(
maxDepth
))
disputedProvider
:=
fault
.
NewAlphabetProvider
(
disputed
,
uint64
(
maxDepth
))
// Create a solver with the canonical provider.
solver
:=
fault
.
NewSolver
(
maxDepth
,
canonicalProvider
)
// Print the initial state.
fmt
.
Println
(
"Canonical state: "
,
canonical
)
fmt
.
Println
(
"Disputed state: "
,
disputed
)
fmt
.
Println
()
fmt
.
Println
(
"Proceeding with the following moves:"
)
fmt
.
Println
(
"go left to d, then right to f, then left to e"
)
fmt
.
Println
()
// Get the claim from the disputed provider.
claim
,
err
:=
disputedProvider
.
Get
(
3
)
if
err
!=
nil
{
fmt
.
Printf
(
"error getting claim from disputed provider: %v"
,
err
)
}
firstDisputedClaim
:=
fault
.
Claim
{
Value
:
claim
,
Position
:
fault
.
NewPosition
(
1
,
0
),
}
res
,
err
:=
solver
.
NextMove
(
firstDisputedClaim
,
parent
)
if
err
!=
nil
{
fmt
.
Printf
(
"error getting next move: %v"
,
err
)
}
fmt
.
Printf
(
"Disputed claim: %s
\n
"
,
claim
)
fmt
.
Printf
(
"Expected claim: %s
\n
"
,
parent
.
Value
)
fmt
.
Printf
(
"Response: [Attack: %v, Value: %s]
\n
"
,
res
.
Attack
,
res
.
Value
)
fmt
.
Println
()
// Get the next claim from the disputed provider.
claim
,
err
=
disputedProvider
.
Get
(
5
)
if
err
!=
nil
{
fmt
.
Printf
(
"error getting claim from disputed provider: %v"
,
err
)
}
firstDisputedClaim
=
fault
.
Claim
{
Value
:
claim
,
Position
:
fault
.
NewPosition
(
2
,
2
),
}
res
,
err
=
solver
.
NextMove
(
firstDisputedClaim
,
parent
)
if
err
!=
nil
{
fmt
.
Printf
(
"error getting next move: %v"
,
err
)
}
fmt
.
Printf
(
"Disputed claim: %s
\n
"
,
claim
)
fmt
.
Printf
(
"Expected claim: %s
\n
"
,
parent
.
Value
)
fmt
.
Printf
(
"Response: [Attack: %v, Value: %s]
\n
"
,
res
.
Attack
,
res
.
Value
)
fmt
.
Println
()
// This marks the end of the game!
if
res
.
Attack
{
fmt
.
Println
(
"Game successfully completed!"
)
}
else
{
fmt
.
Println
(
"Game failed!"
)
}
fmt
.
Println
()
}
op-challenger/fault/cmd/main.go
View file @
3bad749a
package
main
package
main
import
(
import
(
"github.com/ethereum-optimism/optimism/op-challenger/fault"
"github.com/ethereum-optimism/optimism/op-challenger/fault
/cmd/examples
"
)
)
func
main
()
{
func
main
()
{
// Example 1
examples
.
SolverExampleOne
()
// abcdefgh
// abcdexyz
// go left to d, then right to f, then left to e
p
:=
fault
.
Position
{}
p
.
Print
(
3
)
p
.
Attack
()
p
.
Print
(
3
)
p
.
Defend
()
p
.
Print
(
3
)
p
.
Attack
()
p
.
Print
(
3
)
// GIN: 1 Trace Position is 0 Trace Depth is: 0 Trace Index is: 8
// examples.PositionExampleOne()
// GIN: 10 Trace Position is 0 Trace Depth is: 1 Trace Index is: 4
// examples.PositionExampleTwo()
// GIN: 110 Trace Position is 10 Trace Depth is: 2 Trace Index is: 6
// GIN: 1100 Trace Position is 100 Trace Depth is: 3 Trace Index is: 5
// Example 2
// abcdefgh
// abqrstuv
// go left r, then left to b, then right to q
p
=
fault
.
Position
{}
p
.
Print
(
3
)
p
.
Attack
()
p
.
Print
(
3
)
p
.
Attack
()
p
.
Print
(
3
)
p
.
Defend
()
p
.
Print
(
3
)
// Trace Position is 0000 Trace Depth is: 0 Trace Index is: 8
// Trace Position is 0000 Trace Depth is: 1 Trace Index is: 4
// Trace Position is 0000 Trace Depth is: 2 Trace Index is: 2
// Trace Position is 0010 Trace Depth is: 3 Trace Index is: 3
}
}
op-challenger/fault/solver.go
0 → 100644
View file @
3bad749a
package
fault
import
(
"errors"
"github.com/ethereum/go-ethereum/common"
)
// Solver uses a [TraceProvider] to determine the moves to make in a dispute game.
type
Solver
struct
{
TraceProvider
gameDepth
int
}
// NewSolver creates a new [Solver] using the provided [TraceProvider].
func
NewSolver
(
gameDepth
int
,
traceProvider
TraceProvider
)
*
Solver
{
return
&
Solver
{
traceProvider
,
gameDepth
,
}
}
// NextMove returns the next move to make given the current state of the game.
func
(
s
*
Solver
)
NextMove
(
claim
Claim
,
parent
Claim
)
(
*
Response
,
error
)
{
parentCorrect
,
err
:=
s
.
agreeWithClaim
(
parent
)
if
err
!=
nil
{
return
nil
,
err
}
claimCorrect
,
err
:=
s
.
agreeWithClaim
(
claim
)
if
err
!=
nil
{
return
nil
,
err
}
if
parentCorrect
&&
claimCorrect
{
// We agree with the parent, but the claim is disagreeing with it.
// Since we agree with the claim, the difference must be to the right of the claim
return
s
.
defend
(
claim
)
}
else
if
parentCorrect
&&
!
claimCorrect
{
// We agree with the parent, but the claim disagrees with it.
// Since we disagree with the claim, the difference must be to the left of the claim
return
s
.
attack
(
claim
)
}
else
if
!
parentCorrect
&&
claimCorrect
{
// Do nothing, we disagree with the parent, but this claim has correctly countered it
return
s
.
doNothing
()
}
else
if
!
parentCorrect
&&
!
claimCorrect
{
// We disagree with the parent so want to counter it (which the claim is doing)
// but we also disagree with the claim so there must be a difference to the left of claim
// Note that we will create the correct counter-claim for parent when it is evaluated, no need to do it here
return
s
.
attack
(
claim
)
}
// This should not be reached
return
nil
,
errors
.
New
(
"no next move"
)
}
func
(
s
*
Solver
)
doNothing
()
(
*
Response
,
error
)
{
return
nil
,
nil
}
// attack returns a response that attacks the claim.
func
(
s
*
Solver
)
attack
(
claim
Claim
)
(
*
Response
,
error
)
{
claim
.
Position
.
Attack
()
value
,
err
:=
s
.
traceAtPosition
(
&
claim
.
Position
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
Response
{
Attack
:
true
,
Value
:
value
},
nil
}
// defend returns a response that defends the claim.
func
(
s
*
Solver
)
defend
(
claim
Claim
)
(
*
Response
,
error
)
{
claim
.
Position
.
Defend
()
value
,
err
:=
s
.
traceAtPosition
(
&
claim
.
Position
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
Response
{
Attack
:
false
,
Value
:
value
},
nil
}
// agreeWithClaim returns true if the [Claim] is correct according to the internal [TraceProvider].
func
(
s
*
Solver
)
agreeWithClaim
(
claim
Claim
)
(
bool
,
error
)
{
ourValue
,
err
:=
s
.
traceAtPosition
(
&
claim
.
Position
)
return
ourValue
==
claim
.
Value
,
err
}
// traceAtPosition returns the [common.Hash] from internal [TraceProvider] at the given [Position].
func
(
s
*
Solver
)
traceAtPosition
(
p
*
Position
)
(
common
.
Hash
,
error
)
{
// todo: update TraceIndex to return a uint64 to keep types consistent
index
:=
p
.
TraceIndex
(
s
.
gameDepth
)
hash
,
err
:=
s
.
Get
(
uint64
(
index
))
return
hash
,
err
}
op-challenger/fault/solver_test.go
0 → 100644
View file @
3bad749a
package
fault
import
(
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
// TestSolver_NextMove_Opponent tests the [Solver] NextMove function
// with an [fault.AlphabetProvider] as the [TraceProvider].
func
TestSolver_NextMove_Opponent
(
t
*
testing
.
T
)
{
// Construct the solver.
maxDepth
:=
3
canonicalProvider
:=
NewAlphabetProvider
(
"abcdefgh"
,
uint64
(
maxDepth
))
solver
:=
NewSolver
(
maxDepth
,
canonicalProvider
)
// The following claims are created using the state: "abcdexyz".
// The responses are the responses we expect from the solver.
indices
:=
[]
struct
{
traceIndex
int
claim
Claim
parent
Claim
response
*
Response
}{
{
3
,
Claim
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000364"
),
Position
:
NewPosition
(
1
,
0
),
},
Claim
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000768"
),
Position
:
NewPosition
(
0
,
0
),
},
&
Response
{
Attack
:
false
,
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000566"
),
},
},
{
5
,
Claim
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000578"
),
Position
:
NewPosition
(
2
,
2
),
},
Claim
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000768"
),
Position
:
NewPosition
(
1
,
1
),
},
&
Response
{
Attack
:
true
,
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000465"
),
},
},
}
for
_
,
test
:=
range
indices
{
res
,
err
:=
solver
.
NextMove
(
test
.
claim
,
test
.
parent
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
test
.
response
,
res
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment