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
00ed269e
Unverified
Commit
00ed269e
authored
Jun 30, 2023
by
mergify[bot]
Committed by
GitHub
Jun 30, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into clabby/ctb/fault-game-clock-tests
parents
d7bdc74a
40af4dcf
Changes
17
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
995 additions
and
224 deletions
+995
-224
breezy-spoons-hope.md
.changeset/breezy-spoons-hope.md
+5
-0
cuddly-panthers-trade.md
.changeset/cuddly-panthers-trade.md
+5
-0
publish-canary.yml
.github/workflows/publish-canary.yml
+1
-1
game.go
op-challenger/fault/game.go
+106
-80
game_test.go
op-challenger/fault/game_test.go
+141
-32
loader.go
op-challenger/fault/loader.go
+101
-0
loader_test.go
op-challenger/fault/loader_test.go
+188
-0
orchestrator.go
op-challenger/fault/orchestrator.go
+1
-1
responder.go
op-challenger/fault/responder.go
+100
-0
responder_test.go
op-challenger/fault/responder_test.go
+156
-0
types.go
op-challenger/fault/types.go
+7
-0
package.json
package.json
+1
-1
package.json
packages/fault-detector/package.json
+1
-1
helpers.spec.ts
packages/fault-detector/test/helpers.spec.ts
+9
-2
cross-chain-messenger.ts
packages/sdk/src/cross-chain-messenger.ts
+164
-70
cross-chain-messenger.spec.ts
packages/sdk/test/cross-chain-messenger.spec.ts
+7
-5
pnpm-lock.yaml
pnpm-lock.yaml
+2
-31
No files found.
.changeset/breezy-spoons-hope.md
0 → 100644
View file @
00ed269e
---
'
@eth-optimism/fault-detector'
:
patch
---
Bump contracts-bedrock version
.changeset/cuddly-panthers-trade.md
0 → 100644
View file @
00ed269e
---
'
@eth-optimism/sdk'
:
minor
---
Add support for claiming multicall3 withdrawals
.github/workflows/publish-canary.yml
View file @
00ed269e
...
@@ -51,7 +51,7 @@ jobs:
...
@@ -51,7 +51,7 @@ jobs:
version
:
nightly
version
:
nightly
-
name
:
Build
-
name
:
Build
run
:
pnpm build
run
:
npx nx run-many --target=build --skip-nx-cache
-
name
:
Setup Canary Snapshot
-
name
:
Setup Canary Snapshot
run
:
pnpm changeset version --snapshot
run
:
pnpm changeset version --snapshot
...
...
op-challenger/fault/game.go
View file @
00ed269e
...
@@ -17,127 +17,153 @@ type Game interface {
...
@@ -17,127 +17,153 @@ type Game interface {
// Put adds a claim into the game state.
// Put adds a claim into the game state.
Put
(
claim
Claim
)
error
Put
(
claim
Claim
)
error
// PutAll adds a list of claims into the game state.
PutAll
(
claims
[]
Claim
)
error
// Claims returns all of the claims in the game.
// Claims returns all of the claims in the game.
Claims
()
[]
Claim
Claims
()
[]
Claim
// IsDuplicate returns true if the provided [Claim] already exists in the game state.
IsDuplicate
(
claim
Claim
)
bool
IsDuplicate
(
claim
Claim
)
bool
// PreStateClaim gets the claim which commits to the pre-state of this specific claim.
// This will return an error if it is called with a non-leaf claim.
PreStateClaim
(
claim
Claim
)
(
Claim
,
error
)
// PostStateClaim gets the claim which commits to the post-state of this specific claim.
// This will return an error if it is called with a non-leaf claim.
PostStateClaim
(
claim
Claim
)
(
Claim
,
error
)
}
}
// Node is a node in the game state tree.
type
extendedClaim
struct
{
type
Node
struct
{
self
Claim
self
Claim
contractIndex
int
children
[]
*
Node
children
[]
ClaimData
}
}
// gameState is a struct that represents the state of a dispute game.
// gameState is a struct that represents the state of a dispute game.
// The game state implements the [Game] interface.
// The game state implements the [Game] interface.
type
gameState
struct
{
type
gameState
struct
{
root
Node
root
ClaimData
claims
map
[
ClaimData
]
Claim
claims
map
[
ClaimData
]
*
extendedClaim
depth
uint64
}
}
// NewGameState returns a new game state.
// NewGameState returns a new game state.
// The provided [Claim] is used as the root node.
// The provided [Claim] is used as the root node.
func
NewGameState
(
root
Claim
)
*
gameState
{
func
NewGameState
(
root
Claim
,
depth
uint64
)
*
gameState
{
claims
:=
make
(
map
[
ClaimData
]
Claim
)
claims
:=
make
(
map
[
ClaimData
]
*
extendedClaim
)
claims
[
root
.
ClaimData
]
=
root
claims
[
root
.
ClaimData
]
=
&
extendedClaim
{
self
:
root
,
contractIndex
:
0
,
children
:
make
([]
ClaimData
,
0
),
}
return
&
gameState
{
return
&
gameState
{
root
:
Node
{
root
:
root
.
ClaimData
,
self
:
root
,
children
:
make
([]
*
Node
,
0
),
},
claims
:
claims
,
claims
:
claims
,
depth
:
depth
,
}
}
}
}
// getParent returns the parent of the provided [Claim].
// PutAll adds a list of claims into the [Game] state.
func
(
g
*
gameState
)
getParent
(
claim
Claim
)
(
Claim
,
error
)
{
// If any of the claims already exist in the game state, an error is returned.
// If the claim is the root node, return an error.
func
(
g
*
gameState
)
PutAll
(
claims
[]
Claim
)
error
{
if
claim
.
IsRoot
()
{
for
_
,
claim
:=
range
claims
{
return
Claim
{},
ErrClaimNotFound
if
err
:=
g
.
Put
(
claim
);
err
!=
nil
{
return
err
}
}
}
return
nil
}
// Walk down the tree from the root node to find the parent
.
// Put adds a claim into the game state
.
found
,
err
:=
g
.
recurseTree
(
&
g
.
root
,
claim
.
Parent
)
func
(
g
*
gameState
)
Put
(
claim
Claim
)
error
{
if
err
!=
nil
{
if
claim
.
IsRoot
()
||
g
.
IsDuplicate
(
claim
)
{
return
Claim
{},
err
return
ErrClaimExists
}
}
if
parent
,
ok
:=
g
.
claims
[
claim
.
Parent
];
!
ok
{
// Return the parent of the found node.
return
errors
.
New
(
"no parent claim"
)
return
found
.
self
,
nil
}
else
{
parent
.
children
=
append
(
parent
.
children
,
claim
.
ClaimData
)
}
g
.
claims
[
claim
.
ClaimData
]
=
&
extendedClaim
{
self
:
claim
,
contractIndex
:
claim
.
ContractIndex
,
children
:
make
([]
ClaimData
,
0
),
}
return
nil
}
}
// recurseTree recursively walks down the tree from the root node to find the
func
(
g
*
gameState
)
IsDuplicate
(
claim
Claim
)
bool
{
// node with the provided [Claim].
_
,
ok
:=
g
.
claims
[
claim
.
ClaimData
]
func
(
g
*
gameState
)
recurseTree
(
treeNode
*
Node
,
claim
ClaimData
)
(
*
Node
,
error
)
{
return
ok
// Check if the current node is the claim.
}
if
treeNode
.
self
.
ClaimData
==
claim
{
return
treeNode
,
nil
}
// Check all children of the current node.
func
(
g
*
gameState
)
Claims
()
[]
Claim
{
for
_
,
child
:=
range
treeNode
.
children
{
queue
:=
[]
ClaimData
{
g
.
root
}
// Recurse and drop errors.
var
out
[]
Claim
n
,
_
:=
g
.
recurseTree
(
child
,
claim
)
for
len
(
queue
)
>
0
{
if
n
!=
nil
{
item
:=
queue
[
0
]
return
n
,
nil
queue
=
queue
[
1
:
]
}
queue
=
append
(
queue
,
g
.
getChildren
(
item
)
...
)
out
=
append
(
out
,
g
.
claims
[
item
]
.
self
)
}
}
return
out
}
// If we reach this point, the claim was not found.
func
(
g
*
gameState
)
getChildren
(
c
ClaimData
)
[]
ClaimData
{
return
nil
,
ErrClaimNotFound
return
g
.
claims
[
c
]
.
children
}
}
// Put adds a claim into the game state.
func
(
g
*
gameState
)
getParent
(
claim
Claim
)
(
Claim
,
error
)
{
func
(
g
*
gameState
)
Put
(
claim
Claim
)
error
{
// The game is always initialized with a root claim. Cannot add a second.
if
claim
.
IsRoot
()
{
if
claim
.
IsRoot
()
{
return
ErrClaimExists
return
Claim
{},
ErrClaimNotFound
}
}
if
parent
,
ok
:=
g
.
claims
[
claim
.
Parent
];
!
ok
{
// Grab the claim's parent.
return
Claim
{},
ErrClaimNotFound
parent
:=
claim
.
Parent
}
else
{
return
parent
.
self
,
nil
// Walk down the tree from the root node to find the parent.
found
,
err
:=
g
.
recurseTree
(
&
g
.
root
,
parent
)
if
err
!=
nil
{
return
err
}
}
}
// Check that the node is not already in the tree.
func
(
g
*
gameState
)
PreStateClaim
(
claim
Claim
)
(
Claim
,
error
)
{
for
_
,
child
:=
range
found
.
children
{
// Do checks in PreStateClaim because these do not hold while walking the tree
if
child
.
self
==
claim
{
if
claim
.
Depth
()
!=
int
(
g
.
depth
)
{
return
ErrClaimExists
return
Claim
{},
errors
.
New
(
"Only leaf claims have pre or post state"
)
}
}
}
// If the claim is the far left most claim, the pre-state is pulled from the contracts & we can supply at contract index.
// Create a new node.
if
claim
.
IndexAtDepth
()
==
0
{
node
:=
Node
{
return
Claim
{
self
:
claim
,
ContractIndex
:
-
1
,
children
:
make
([]
*
Node
,
0
),
},
nil
}
}
return
g
.
preStateClaim
(
claim
)
// Add the node to the tree.
found
.
children
=
append
(
found
.
children
,
&
node
)
g
.
claims
[
claim
.
ClaimData
]
=
claim
return
nil
}
}
func
(
g
*
gameState
)
IsDuplicate
(
claim
Claim
)
bool
{
// preStateClaim is the internal tree walker which does not do error handling
_
,
ok
:=
g
.
claims
[
claim
.
ClaimData
]
func
(
g
*
gameState
)
preStateClaim
(
claim
Claim
)
(
Claim
,
error
)
{
return
ok
parent
,
_
:=
g
.
getParent
(
claim
)
if
claim
.
DefendsParent
()
{
return
parent
,
nil
}
else
{
return
g
.
preStateClaim
(
parent
)
}
}
}
func
(
g
*
gameState
)
Claims
()
[]
Claim
{
func
(
g
*
gameState
)
PostStateClaim
(
claim
Claim
)
(
Claim
,
error
)
{
return
g
.
root
.
claims
()
// Do checks in PostStateClaim because these do not hold while walking the tree
if
claim
.
Depth
()
!=
int
(
g
.
depth
)
{
return
Claim
{},
errors
.
New
(
"Only leaf claims have pre or post state"
)
}
return
g
.
postStateClaim
(
claim
)
}
}
func
(
n
*
Node
)
claims
()
[]
Claim
{
// postStateClaim is the internal tree walker which does not do error handling
var
out
[]
Claim
func
(
g
*
gameState
)
postStateClaim
(
claim
Claim
)
(
Claim
,
error
)
{
out
=
append
(
out
,
n
.
self
)
parent
,
_
:=
g
.
getParent
(
claim
)
for
_
,
c
:=
range
n
.
children
{
if
claim
.
DefendsParent
()
{
out
=
append
(
out
,
c
.
claims
()
...
)
return
g
.
postStateClaim
(
parent
)
}
else
{
return
parent
,
nil
}
}
return
out
}
}
op-challenger/fault/game_test.go
View file @
00ed269e
...
@@ -7,19 +7,29 @@ import (
...
@@ -7,19 +7,29 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
)
)
func
createTestClaims
()
(
Claim
,
Claim
,
Claim
)
{
const
testMaxDepth
=
3
top
:=
Claim
{
func
createTestClaims
()
(
Claim
,
Claim
,
Claim
,
Claim
)
{
// root & middle are from the trace "abcdexyz"
// top & bottom are from the trace "abcdefgh"
root
:=
Claim
{
ClaimData
:
ClaimData
{
ClaimData
:
ClaimData
{
Value
:
common
.
HexToHash
(
"0x00000000000000000000000000000000000000000000000000000000000007
68
"
),
Value
:
common
.
HexToHash
(
"0x00000000000000000000000000000000000000000000000000000000000007
7a
"
),
Position
:
NewPosition
(
0
,
0
),
Position
:
NewPosition
(
0
,
0
),
},
},
Parent
:
ClaimData
{},
// Root claim has no parent
}
}
top
:=
Claim
{
middle
:=
Claim
{
ClaimData
:
ClaimData
{
ClaimData
:
ClaimData
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000364"
),
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000364"
),
Position
:
NewPosition
(
1
,
1
),
Position
:
NewPosition
(
1
,
0
),
},
Parent
:
root
.
ClaimData
,
}
middle
:=
Claim
{
ClaimData
:
ClaimData
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000578"
),
Position
:
NewPosition
(
2
,
2
),
},
},
Parent
:
top
.
ClaimData
,
Parent
:
top
.
ClaimData
,
}
}
...
@@ -27,26 +37,26 @@ func createTestClaims() (Claim, Claim, Claim) {
...
@@ -27,26 +37,26 @@ func createTestClaims() (Claim, Claim, Claim) {
bottom
:=
Claim
{
bottom
:=
Claim
{
ClaimData
:
ClaimData
{
ClaimData
:
ClaimData
{
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000465"
),
Value
:
common
.
HexToHash
(
"0x0000000000000000000000000000000000000000000000000000000000000465"
),
Position
:
NewPosition
(
2
,
2
),
Position
:
NewPosition
(
3
,
4
),
},
},
Parent
:
middle
.
ClaimData
,
Parent
:
middle
.
ClaimData
,
}
}
return
top
,
middle
,
bottom
return
root
,
top
,
middle
,
bottom
}
}
func
TestIsDuplicate
(
t
*
testing
.
T
)
{
func
TestIsDuplicate
(
t
*
testing
.
T
)
{
// Setup the game state.
// Setup the game state.
top
,
middle
,
bottom
:=
createTestClaims
()
root
,
top
,
middle
,
bottom
:=
createTestClaims
()
g
:=
NewGameState
(
top
)
g
:=
NewGameState
(
root
,
testMaxDepth
)
err
:=
g
.
Put
(
middle
)
require
.
NoError
(
t
,
g
.
Put
(
top
))
require
.
NoError
(
t
,
err
)
// Top + Middle should be duplicates
// Root + Top should be duplicates
require
.
True
(
t
,
g
.
IsDuplicate
(
root
))
require
.
True
(
t
,
g
.
IsDuplicate
(
top
))
require
.
True
(
t
,
g
.
IsDuplicate
(
top
))
require
.
True
(
t
,
g
.
IsDuplicate
(
middle
))
// Bottom should not be a duplicate
// Middle + Bottom should not be a duplicate
require
.
False
(
t
,
g
.
IsDuplicate
(
middle
))
require
.
False
(
t
,
g
.
IsDuplicate
(
bottom
))
require
.
False
(
t
,
g
.
IsDuplicate
(
bottom
))
}
}
...
@@ -54,20 +64,70 @@ func TestIsDuplicate(t *testing.T) {
...
@@ -54,20 +64,70 @@ func TestIsDuplicate(t *testing.T) {
// instance errors when the root claim already exists in state.
// instance errors when the root claim already exists in state.
func
TestGame_Put_RootAlreadyExists
(
t
*
testing
.
T
)
{
func
TestGame_Put_RootAlreadyExists
(
t
*
testing
.
T
)
{
// Setup the game state.
// Setup the game state.
top
,
_
,
_
:=
createTestClaims
()
top
,
_
,
_
,
_
:=
createTestClaims
()
g
:=
NewGameState
(
top
)
g
:=
NewGameState
(
top
,
testMaxDepth
)
// Try to put the root claim into the game state again.
// Try to put the root claim into the game state again.
err
:=
g
.
Put
(
top
)
err
:=
g
.
Put
(
top
)
require
.
ErrorIs
(
t
,
err
,
ErrClaimExists
)
require
.
ErrorIs
(
t
,
err
,
ErrClaimExists
)
}
}
// TestGame_PutAll_RootAlreadyExists tests the [Game.PutAll] method using a [gameState]
// instance errors when the root claim already exists in state.
func
TestGame_PutAll_RootAlreadyExists
(
t
*
testing
.
T
)
{
// Setup the game state.
root
,
_
,
_
,
_
:=
createTestClaims
()
g
:=
NewGameState
(
root
,
testMaxDepth
)
// Try to put the root claim into the game state again.
err
:=
g
.
PutAll
([]
Claim
{
root
})
require
.
ErrorIs
(
t
,
err
,
ErrClaimExists
)
}
// TestGame_PutAll_AlreadyExists tests the [Game.PutAll] method using a [gameState]
// instance errors when the given claim already exists in state.
func
TestGame_PutAll_AlreadyExists
(
t
*
testing
.
T
)
{
root
,
top
,
middle
,
bottom
:=
createTestClaims
()
g
:=
NewGameState
(
root
,
testMaxDepth
)
err
:=
g
.
PutAll
([]
Claim
{
top
,
middle
})
require
.
NoError
(
t
,
err
)
err
=
g
.
PutAll
([]
Claim
{
middle
,
bottom
})
require
.
ErrorIs
(
t
,
err
,
ErrClaimExists
)
}
// TestGame_PutAll_ParentsAndChildren tests the [Game.PutAll] method using a [gameState] instance.
func
TestGame_PutAll_ParentsAndChildren
(
t
*
testing
.
T
)
{
// Setup the game state.
root
,
top
,
middle
,
bottom
:=
createTestClaims
()
g
:=
NewGameState
(
root
,
testMaxDepth
)
// We should not be able to get the parent of the root claim.
parent
,
err
:=
g
.
getParent
(
root
)
require
.
ErrorIs
(
t
,
err
,
ErrClaimNotFound
)
require
.
Equal
(
t
,
parent
,
Claim
{})
// Put the rest of the claims in the state.
err
=
g
.
PutAll
([]
Claim
{
top
,
middle
,
bottom
})
require
.
NoError
(
t
,
err
)
parent
,
err
=
g
.
getParent
(
top
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
parent
,
root
)
parent
,
err
=
g
.
getParent
(
middle
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
parent
,
top
)
parent
,
err
=
g
.
getParent
(
bottom
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
parent
,
middle
)
}
// TestGame_Put_AlreadyExists tests the [Game.Put] method using a [gameState]
// TestGame_Put_AlreadyExists tests the [Game.Put] method using a [gameState]
// instance errors when the given claim already exists in state.
// instance errors when the given claim already exists in state.
func
TestGame_Put_AlreadyExists
(
t
*
testing
.
T
)
{
func
TestGame_Put_AlreadyExists
(
t
*
testing
.
T
)
{
// Setup the game state.
// Setup the game state.
top
,
middle
,
_
:=
createTestClaims
()
top
,
middle
,
_
,
_
:=
createTestClaims
()
g
:=
NewGameState
(
top
)
g
:=
NewGameState
(
top
,
testMaxDepth
)
// Put the next claim into state.
// Put the next claim into state.
err
:=
g
.
Put
(
middle
)
err
:=
g
.
Put
(
middle
)
...
@@ -81,24 +141,29 @@ func TestGame_Put_AlreadyExists(t *testing.T) {
...
@@ -81,24 +141,29 @@ func TestGame_Put_AlreadyExists(t *testing.T) {
// TestGame_Put_ParentsAndChildren tests the [Game.Put] method using a [gameState] instance.
// TestGame_Put_ParentsAndChildren tests the [Game.Put] method using a [gameState] instance.
func
TestGame_Put_ParentsAndChildren
(
t
*
testing
.
T
)
{
func
TestGame_Put_ParentsAndChildren
(
t
*
testing
.
T
)
{
// Setup the game state.
// Setup the game state.
top
,
middle
,
bottom
:=
createTestClaims
()
root
,
top
,
middle
,
bottom
:=
createTestClaims
()
g
:=
NewGameState
(
top
)
g
:=
NewGameState
(
root
,
testMaxDepth
)
// We should not be able to get the parent of the root claim.
// We should not be able to get the parent of the root claim.
parent
,
err
:=
g
.
getParent
(
top
)
parent
,
err
:=
g
.
getParent
(
root
)
require
.
ErrorIs
(
t
,
err
,
ErrClaimNotFound
)
require
.
ErrorIs
(
t
,
err
,
ErrClaimNotFound
)
require
.
Equal
(
t
,
parent
,
Claim
{})
require
.
Equal
(
t
,
parent
,
Claim
{})
// Put the middle claim into the game state.
// Put + Check Top
// We should expect no parent to exist, yet.
err
=
g
.
Put
(
top
)
require
.
NoError
(
t
,
err
)
parent
,
err
=
g
.
getParent
(
top
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
parent
,
root
)
// Put + Check Top Middle
err
=
g
.
Put
(
middle
)
err
=
g
.
Put
(
middle
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
parent
,
err
=
g
.
getParent
(
middle
)
parent
,
err
=
g
.
getParent
(
middle
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
parent
,
top
)
require
.
Equal
(
t
,
parent
,
top
)
// Put the bottom claim into the game state.
// Put + Check Top Bottom
// We should expect the parent to be the claim we just added.
err
=
g
.
Put
(
bottom
)
err
=
g
.
Put
(
bottom
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
parent
,
err
=
g
.
getParent
(
bottom
)
parent
,
err
=
g
.
getParent
(
bottom
)
...
@@ -109,11 +174,15 @@ func TestGame_Put_ParentsAndChildren(t *testing.T) {
...
@@ -109,11 +174,15 @@ func TestGame_Put_ParentsAndChildren(t *testing.T) {
// TestGame_ClaimPairs tests the [Game.ClaimPairs] method using a [gameState] instance.
// TestGame_ClaimPairs tests the [Game.ClaimPairs] method using a [gameState] instance.
func
TestGame_ClaimPairs
(
t
*
testing
.
T
)
{
func
TestGame_ClaimPairs
(
t
*
testing
.
T
)
{
// Setup the game state.
// Setup the game state.
top
,
middle
,
bottom
:=
createTestClaims
()
root
,
top
,
middle
,
bottom
:=
createTestClaims
()
g
:=
NewGameState
(
top
)
g
:=
NewGameState
(
root
,
testMaxDepth
)
// Add middle claim to the game state.
// Add top claim to the game state.
err
:=
g
.
Put
(
middle
)
err
:=
g
.
Put
(
top
)
require
.
NoError
(
t
,
err
)
// Add the middle claim to the game state.
err
=
g
.
Put
(
middle
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
// Add the bottom claim to the game state.
// Add the bottom claim to the game state.
...
@@ -121,7 +190,47 @@ func TestGame_ClaimPairs(t *testing.T) {
...
@@ -121,7 +190,47 @@ func TestGame_ClaimPairs(t *testing.T) {
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
// Validate claim pairs.
// Validate claim pairs.
expected
:=
[]
Claim
{
top
,
middle
,
bottom
}
expected
:=
[]
Claim
{
root
,
top
,
middle
,
bottom
}
claims
:=
g
.
Claims
()
claims
:=
g
.
Claims
()
require
.
ElementsMatch
(
t
,
expected
,
claims
)
require
.
ElementsMatch
(
t
,
expected
,
claims
)
}
}
// TestPrePostStateOnlyOnLeafClaim tests that if PreStateClaim or PostStateClaim is called with an non-leaf claim
// those functions return an error.
func
TestPrePostStateOnlyOnLeafClaim
(
t
*
testing
.
T
)
{
root
,
top
,
middle
,
bottom
:=
createTestClaims
()
g
:=
NewGameState
(
root
,
testMaxDepth
)
require
.
NoError
(
t
,
g
.
PutAll
([]
Claim
{
top
,
middle
,
bottom
}))
_
,
err
:=
g
.
PreStateClaim
(
middle
)
require
.
Error
(
t
,
err
)
_
,
err
=
g
.
PostStateClaim
(
middle
)
require
.
Error
(
t
,
err
)
}
func
TestPreStateClaim
(
t
*
testing
.
T
)
{
root
,
top
,
middle
,
bottom
:=
createTestClaims
()
g
:=
NewGameState
(
root
,
testMaxDepth
)
require
.
NoError
(
t
,
g
.
Put
(
top
))
require
.
NoError
(
t
,
g
.
Put
(
middle
))
require
.
NoError
(
t
,
g
.
Put
(
bottom
))
// Bottom trace index is 4. Pre trace index is then 3
pre
,
err
:=
g
.
PreStateClaim
(
bottom
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
top
,
pre
)
}
func
TestPostStateClaim
(
t
*
testing
.
T
)
{
root
,
top
,
middle
,
bottom
:=
createTestClaims
()
g
:=
NewGameState
(
root
,
testMaxDepth
)
require
.
NoError
(
t
,
g
.
Put
(
top
))
require
.
NoError
(
t
,
g
.
Put
(
middle
))
require
.
NoError
(
t
,
g
.
Put
(
bottom
))
// Bottom trace index is 4. Post trace index is then 5
post
,
err
:=
g
.
PostStateClaim
(
bottom
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
middle
,
post
)
}
op-challenger/fault/loader.go
0 → 100644
View file @
00ed269e
package
fault
import
(
"context"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/log"
)
// ClaimFetcher is a minimal interface around [bindings.FaultDisputeGameCaller].
// This needs to be updated if the [bindings.FaultDisputeGameCaller] interface changes.
type
ClaimFetcher
interface
{
ClaimData
(
opts
*
bind
.
CallOpts
,
arg0
*
big
.
Int
)
(
struct
{
ParentIndex
uint32
Countered
bool
Claim
[
32
]
byte
Position
*
big
.
Int
Clock
*
big
.
Int
},
error
)
ClaimDataLen
(
opts
*
bind
.
CallOpts
)
(
*
big
.
Int
,
error
)
}
// Loader is a minimal interface for loading onchain [Claim] data.
type
Loader
interface
{
FetchClaims
(
ctx
context
.
Context
)
([]
Claim
,
error
)
}
// loader pulls in fault dispute game claim data periodically and over subscriptions.
type
loader
struct
{
log
log
.
Logger
state
Game
claimFetcher
ClaimFetcher
}
// NewLoader creates a new [loader].
func
NewLoader
(
log
log
.
Logger
,
state
Game
,
claimFetcher
ClaimFetcher
)
*
loader
{
return
&
loader
{
log
:
log
,
state
:
state
,
claimFetcher
:
claimFetcher
,
}
}
// fetchClaim fetches a single [Claim] with a hydrated parent.
func
(
l
*
loader
)
fetchClaim
(
ctx
context
.
Context
,
arrIndex
uint64
)
(
Claim
,
error
)
{
callOpts
:=
bind
.
CallOpts
{
Context
:
ctx
,
}
fetchedClaim
,
err
:=
l
.
claimFetcher
.
ClaimData
(
&
callOpts
,
new
(
big
.
Int
)
.
SetUint64
(
arrIndex
))
if
err
!=
nil
{
return
Claim
{},
err
}
claim
:=
Claim
{
ClaimData
:
ClaimData
{
Value
:
fetchedClaim
.
Claim
,
Position
:
NewPositionFromGIndex
(
fetchedClaim
.
Position
.
Uint64
()),
},
}
if
!
claim
.
IsRootPosition
()
{
parentIndex
:=
uint64
(
fetchedClaim
.
ParentIndex
)
parentClaim
,
err
:=
l
.
claimFetcher
.
ClaimData
(
&
callOpts
,
new
(
big
.
Int
)
.
SetUint64
(
parentIndex
))
if
err
!=
nil
{
return
Claim
{},
err
}
claim
.
Parent
=
ClaimData
{
Value
:
parentClaim
.
Claim
,
Position
:
NewPositionFromGIndex
(
parentClaim
.
Position
.
Uint64
()),
}
}
return
claim
,
nil
}
// FetchClaims fetches all claims from the fault dispute game.
func
(
l
*
loader
)
FetchClaims
(
ctx
context
.
Context
)
([]
Claim
,
error
)
{
// Get the current claim count.
claimCount
,
err
:=
l
.
claimFetcher
.
ClaimDataLen
(
&
bind
.
CallOpts
{
Context
:
ctx
,
})
if
err
!=
nil
{
return
nil
,
err
}
// Fetch each claim and build a list.
claimList
:=
make
([]
Claim
,
claimCount
.
Uint64
())
for
i
:=
uint64
(
0
);
i
<
claimCount
.
Uint64
();
i
++
{
claim
,
err
:=
l
.
fetchClaim
(
ctx
,
i
)
if
err
!=
nil
{
return
nil
,
err
}
claimList
[
i
]
=
claim
}
return
claimList
,
nil
}
op-challenger/fault/loader_test.go
0 → 100644
View file @
00ed269e
package
fault
import
(
"context"
"fmt"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
var
(
mockClaimDataError
=
fmt
.
Errorf
(
"claim data errored"
)
mockClaimLenError
=
fmt
.
Errorf
(
"claim len errored"
)
mockPutError
=
fmt
.
Errorf
(
"put errored"
)
)
type
mockGameState
struct
{
putCalled
int
putErrors
bool
}
func
(
m
*
mockGameState
)
Put
(
claim
Claim
)
error
{
m
.
putCalled
++
if
m
.
putErrors
{
return
mockPutError
}
return
nil
}
func
(
m
*
mockGameState
)
PutAll
(
claims
[]
Claim
)
error
{
m
.
putCalled
+=
len
(
claims
)
if
m
.
putErrors
{
return
mockPutError
}
return
nil
}
func
(
m
*
mockGameState
)
Claims
()
[]
Claim
{
return
[]
Claim
{}
}
func
(
m
*
mockGameState
)
IsDuplicate
(
claim
Claim
)
bool
{
return
false
}
func
(
m
*
mockGameState
)
PreStateClaim
(
claim
Claim
)
(
Claim
,
error
)
{
panic
(
"unimplemented"
)
}
func
(
m
*
mockGameState
)
PostStateClaim
(
claim
Claim
)
(
Claim
,
error
)
{
panic
(
"unimplemented"
)
}
type
mockClaimFetcher
struct
{
claimDataError
bool
claimLenError
bool
currentIndex
uint64
returnClaims
[]
struct
{
ParentIndex
uint32
Countered
bool
Claim
[
32
]
byte
Position
*
big
.
Int
Clock
*
big
.
Int
}
}
func
newMockClaimFetcher
()
*
mockClaimFetcher
{
return
&
mockClaimFetcher
{
returnClaims
:
[]
struct
{
ParentIndex
uint32
Countered
bool
Claim
[
32
]
byte
Position
*
big
.
Int
Clock
*
big
.
Int
}{
{
Claim
:
[
32
]
byte
{
0x00
},
Position
:
big
.
NewInt
(
0
),
},
{
Claim
:
[
32
]
byte
{
0x01
},
Position
:
big
.
NewInt
(
0
),
},
{
Claim
:
[
32
]
byte
{
0x02
},
Position
:
big
.
NewInt
(
0
),
},
},
}
}
func
(
m
*
mockClaimFetcher
)
ClaimData
(
opts
*
bind
.
CallOpts
,
arg0
*
big
.
Int
)
(
struct
{
ParentIndex
uint32
Countered
bool
Claim
[
32
]
byte
Position
*
big
.
Int
Clock
*
big
.
Int
},
error
)
{
if
m
.
claimDataError
{
return
struct
{
ParentIndex
uint32
Countered
bool
Claim
[
32
]
byte
Position
*
big
.
Int
Clock
*
big
.
Int
}{},
mockClaimDataError
}
returnClaim
:=
m
.
returnClaims
[
m
.
currentIndex
]
m
.
currentIndex
++
return
returnClaim
,
nil
}
func
(
m
*
mockClaimFetcher
)
ClaimDataLen
(
opts
*
bind
.
CallOpts
)
(
*
big
.
Int
,
error
)
{
if
m
.
claimLenError
{
return
big
.
NewInt
(
0
),
mockClaimLenError
}
return
big
.
NewInt
(
int64
(
len
(
m
.
returnClaims
))),
nil
}
// TestLoader_FetchClaims_Succeeds tests [loader.FetchClaims].
func
TestLoader_FetchClaims_Succeeds
(
t
*
testing
.
T
)
{
log
:=
testlog
.
Logger
(
t
,
log
.
LvlError
)
mockClaimFetcher
:=
newMockClaimFetcher
()
expectedClaims
:=
mockClaimFetcher
.
returnClaims
loader
:=
NewLoader
(
log
,
&
mockGameState
{},
mockClaimFetcher
)
claims
,
err
:=
loader
.
FetchClaims
(
context
.
Background
())
require
.
NoError
(
t
,
err
)
require
.
ElementsMatch
(
t
,
[]
Claim
{
{
ClaimData
:
ClaimData
{
Value
:
expectedClaims
[
0
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
0
]
.
Position
.
Uint64
()),
},
Parent
:
ClaimData
{
Value
:
expectedClaims
[
0
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
0
]
.
Position
.
Uint64
()),
},
},
{
ClaimData
:
ClaimData
{
Value
:
expectedClaims
[
1
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
1
]
.
Position
.
Uint64
()),
},
Parent
:
ClaimData
{
Value
:
expectedClaims
[
0
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
1
]
.
Position
.
Uint64
()),
},
},
{
ClaimData
:
ClaimData
{
Value
:
expectedClaims
[
2
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
2
]
.
Position
.
Uint64
()),
},
Parent
:
ClaimData
{
Value
:
expectedClaims
[
0
]
.
Claim
,
Position
:
NewPositionFromGIndex
(
expectedClaims
[
2
]
.
Position
.
Uint64
()),
},
},
},
claims
)
}
// TestLoader_FetchClaims_ClaimDataErrors tests [loader.FetchClaims]
// when the claim fetcher [ClaimData] function call errors.
func
TestLoader_FetchClaims_ClaimDataErrors
(
t
*
testing
.
T
)
{
log
:=
testlog
.
Logger
(
t
,
log
.
LvlError
)
mockClaimFetcher
:=
newMockClaimFetcher
()
mockClaimFetcher
.
claimDataError
=
true
loader
:=
NewLoader
(
log
,
&
mockGameState
{},
mockClaimFetcher
)
claims
,
err
:=
loader
.
FetchClaims
(
context
.
Background
())
require
.
ErrorIs
(
t
,
err
,
mockClaimDataError
)
require
.
Empty
(
t
,
claims
)
}
// TestLoader_FetchClaims_ClaimLenErrors tests [loader.FetchClaims]
// when the claim fetcher [ClaimDataLen] function call errors.
func
TestLoader_FetchClaims_ClaimLenErrors
(
t
*
testing
.
T
)
{
log
:=
testlog
.
Logger
(
t
,
log
.
LvlError
)
mockClaimFetcher
:=
newMockClaimFetcher
()
mockClaimFetcher
.
claimLenError
=
true
loader
:=
NewLoader
(
log
,
&
mockGameState
{},
mockClaimFetcher
)
claims
,
err
:=
loader
.
FetchClaims
(
context
.
Background
())
require
.
ErrorIs
(
t
,
err
,
mockClaimLenError
)
require
.
Empty
(
t
,
claims
)
}
op-challenger/fault/orchestrator.go
View file @
00ed269e
...
@@ -22,7 +22,7 @@ func NewOrchestrator(maxDepth uint64, traces []TraceProvider, names []string, ro
...
@@ -22,7 +22,7 @@ func NewOrchestrator(maxDepth uint64, traces []TraceProvider, names []string, ro
}
}
log
.
Info
(
"Starting game"
,
"root_letter"
,
string
(
root
.
Value
[
31
:
]))
log
.
Info
(
"Starting game"
,
"root_letter"
,
string
(
root
.
Value
[
31
:
]))
for
i
,
trace
:=
range
traces
{
for
i
,
trace
:=
range
traces
{
game
:=
NewGameState
(
root
)
game
:=
NewGameState
(
root
,
maxDepth
)
o
.
agents
[
i
]
=
NewAgent
(
game
,
int
(
maxDepth
),
trace
,
&
o
,
log
.
New
(
"role"
,
names
[
i
]))
o
.
agents
[
i
]
=
NewAgent
(
game
,
int
(
maxDepth
),
trace
,
&
o
,
log
.
New
(
"role"
,
names
[
i
]))
o
.
outputChs
[
i
]
=
make
(
chan
Claim
)
o
.
outputChs
[
i
]
=
make
(
chan
Claim
)
}
}
...
...
op-challenger/fault/responder.go
0 → 100644
View file @
00ed269e
package
fault
import
(
"context"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
// faultResponder implements the [Responder] interface to send onchain transactions.
type
faultResponder
struct
{
log
log
.
Logger
txMgr
txmgr
.
TxManager
fdgAddr
common
.
Address
fdgAbi
*
abi
.
ABI
}
// NewFaultResponder returns a new [faultResponder].
func
NewFaultResponder
(
logger
log
.
Logger
,
txManagr
txmgr
.
TxManager
,
fdgAddr
common
.
Address
)
(
*
faultResponder
,
error
)
{
fdgAbi
,
err
:=
bindings
.
FaultDisputeGameMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
return
&
faultResponder
{
log
:
logger
,
txMgr
:
txManagr
,
fdgAddr
:
fdgAddr
,
fdgAbi
:
fdgAbi
,
},
nil
}
// buildFaultDefendData creates the transaction data for the Defend function.
func
(
r
*
faultResponder
)
buildFaultDefendData
(
parentContractIndex
int
,
pivot
[
32
]
byte
)
([]
byte
,
error
)
{
return
r
.
fdgAbi
.
Pack
(
"defend"
,
big
.
NewInt
(
int64
(
parentContractIndex
)),
pivot
,
)
}
// buildFaultAttackData creates the transaction data for the Attack function.
func
(
r
*
faultResponder
)
buildFaultAttackData
(
parentContractIndex
int
,
pivot
[
32
]
byte
)
([]
byte
,
error
)
{
return
r
.
fdgAbi
.
Pack
(
"attack"
,
big
.
NewInt
(
int64
(
parentContractIndex
)),
pivot
,
)
}
// BuildTx builds the transaction for the [faultResponder].
func
(
r
*
faultResponder
)
BuildTx
(
ctx
context
.
Context
,
response
Claim
)
([]
byte
,
error
)
{
if
response
.
DefendsParent
()
{
txData
,
err
:=
r
.
buildFaultDefendData
(
response
.
ParentContractIndex
,
response
.
ValueBytes
())
if
err
!=
nil
{
return
nil
,
err
}
return
txData
,
nil
}
else
{
txData
,
err
:=
r
.
buildFaultAttackData
(
response
.
ParentContractIndex
,
response
.
ValueBytes
())
if
err
!=
nil
{
return
nil
,
err
}
return
txData
,
nil
}
}
// Respond takes a [Claim] and executes the response action.
func
(
r
*
faultResponder
)
Respond
(
ctx
context
.
Context
,
response
Claim
)
error
{
// Build the transaction data.
txData
,
err
:=
r
.
BuildTx
(
ctx
,
response
)
if
err
!=
nil
{
return
err
}
// Send the transaction through the [txmgr].
receipt
,
err
:=
r
.
txMgr
.
Send
(
ctx
,
txmgr
.
TxCandidate
{
To
:
&
r
.
fdgAddr
,
TxData
:
txData
,
// Setting GasLimit to 0 performs gas estimation online through the [txmgr].
GasLimit
:
0
,
})
if
err
!=
nil
{
return
err
}
if
receipt
.
Status
==
types
.
ReceiptStatusFailed
{
r
.
log
.
Error
(
"responder tx successfully published but reverted"
,
"tx_hash"
,
receipt
.
TxHash
)
}
else
{
r
.
log
.
Info
(
"responder tx successfully published"
,
"tx_hash"
,
receipt
.
TxHash
)
}
return
nil
}
op-challenger/fault/responder_test.go
0 → 100644
View file @
00ed269e
package
fault
import
(
"context"
"errors"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
var
(
mockFdgAddress
=
common
.
HexToAddress
(
"0x1234"
)
mockSendError
=
errors
.
New
(
"mock send error"
)
)
type
mockTxManager
struct
{
from
common
.
Address
sends
int
sendFails
bool
}
func
(
m
*
mockTxManager
)
Send
(
ctx
context
.
Context
,
candidate
txmgr
.
TxCandidate
)
(
*
types
.
Receipt
,
error
)
{
if
m
.
sendFails
{
return
nil
,
mockSendError
}
m
.
sends
++
return
types
.
NewReceipt
(
[]
byte
{},
false
,
0
,
),
nil
}
func
(
m
*
mockTxManager
)
From
()
common
.
Address
{
return
m
.
from
}
func
newTestFaultResponder
(
t
*
testing
.
T
,
sendFails
bool
)
(
*
faultResponder
,
*
mockTxManager
)
{
log
:=
testlog
.
Logger
(
t
,
log
.
LvlError
)
mockTxMgr
:=
&
mockTxManager
{}
mockTxMgr
.
sendFails
=
sendFails
responder
,
err
:=
NewFaultResponder
(
log
,
mockTxMgr
,
mockFdgAddress
)
require
.
NoError
(
t
,
err
)
return
responder
,
mockTxMgr
}
// TestResponder_Respond_SendFails tests the [Responder.Respond] method
// bubbles up the error returned by the [txmgr.Send] method.
func
TestResponder_Respond_SendFails
(
t
*
testing
.
T
)
{
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
,
true
)
err
:=
responder
.
Respond
(
context
.
Background
(),
Claim
{
ClaimData
:
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
NewPositionFromGIndex
(
2
),
},
Parent
:
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
NewPositionFromGIndex
(
1
),
},
ContractIndex
:
0
,
ParentContractIndex
:
0
,
})
require
.
ErrorIs
(
t
,
err
,
mockSendError
)
require
.
Equal
(
t
,
0
,
mockTxMgr
.
sends
)
}
// TestResponder_Respond_Success tests the [Responder.Respond] method
// succeeds when the tx candidate is successfully sent through the txmgr.
func
TestResponder_Respond_Success
(
t
*
testing
.
T
)
{
responder
,
mockTxMgr
:=
newTestFaultResponder
(
t
,
false
)
err
:=
responder
.
Respond
(
context
.
Background
(),
Claim
{
ClaimData
:
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
NewPositionFromGIndex
(
2
),
},
Parent
:
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
NewPositionFromGIndex
(
1
),
},
ContractIndex
:
0
,
ParentContractIndex
:
0
,
})
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
1
,
mockTxMgr
.
sends
)
}
// TestResponder_BuildTx_Attack tests the [Responder.BuildTx] method
// returns a tx candidate with the correct data for an attack tx.
func
TestResponder_BuildTx_Attack
(
t
*
testing
.
T
)
{
responder
,
_
:=
newTestFaultResponder
(
t
,
false
)
responseClaim
:=
Claim
{
ClaimData
:
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
NewPositionFromGIndex
(
2
),
},
Parent
:
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
NewPositionFromGIndex
(
1
),
},
ContractIndex
:
0
,
ParentContractIndex
:
7
,
}
tx
,
err
:=
responder
.
BuildTx
(
context
.
Background
(),
responseClaim
)
require
.
NoError
(
t
,
err
)
// Pack the tx data manually.
fdgAbi
,
err
:=
bindings
.
FaultDisputeGameMetaData
.
GetAbi
()
require
.
NoError
(
t
,
err
)
expected
,
err
:=
fdgAbi
.
Pack
(
"attack"
,
big
.
NewInt
(
int64
(
7
)),
responseClaim
.
ValueBytes
(),
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expected
,
tx
)
}
// TestResponder_BuildTx_Defend tests the [Responder.BuildTx] method
// returns a tx candidate with the correct data for a defend tx.
func
TestResponder_BuildTx_Defend
(
t
*
testing
.
T
)
{
responder
,
_
:=
newTestFaultResponder
(
t
,
false
)
responseClaim
:=
Claim
{
ClaimData
:
ClaimData
{
Value
:
common
.
Hash
{
0x01
},
Position
:
NewPositionFromGIndex
(
3
),
},
Parent
:
ClaimData
{
Value
:
common
.
Hash
{
0x02
},
Position
:
NewPositionFromGIndex
(
6
),
},
ContractIndex
:
0
,
ParentContractIndex
:
7
,
}
tx
,
err
:=
responder
.
BuildTx
(
context
.
Background
(),
responseClaim
)
require
.
NoError
(
t
,
err
)
// Pack the tx data manually.
fdgAbi
,
err
:=
bindings
.
FaultDisputeGameMetaData
.
GetAbi
()
require
.
NoError
(
t
,
err
)
expected
,
err
:=
fdgAbi
.
Pack
(
"defend"
,
big
.
NewInt
(
int64
(
7
)),
responseClaim
.
ValueBytes
(),
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expected
,
tx
)
}
op-challenger/fault/types.go
View file @
00ed269e
...
@@ -25,6 +25,13 @@ type ClaimData struct {
...
@@ -25,6 +25,13 @@ type ClaimData struct {
Position
Position
}
}
func
(
c
*
ClaimData
)
ValueBytes
()
[
32
]
byte
{
responseBytes
:=
c
.
Value
.
Bytes
()
var
responseArr
[
32
]
byte
copy
(
responseArr
[
:
],
responseBytes
[
:
32
])
return
responseArr
}
// Claim extends ClaimData with information about the relationship between two claims.
// Claim extends ClaimData with information about the relationship between two claims.
// It uses ClaimData to break cyclicity without using pointers.
// It uses ClaimData to break cyclicity without using pointers.
// If the position of the game is Depth 0, IndexAtDepth 0 it is the root claim
// If the position of the game is Depth 0, IndexAtDepth 0 it is the root claim
...
...
package.json
View file @
00ed269e
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
"postinstall"
:
"patch-package && (test -d docs/op-stack && cd docs/op-stack && npx yarn@1 install && cd ../.. || exit 0)"
,
"postinstall"
:
"patch-package && (test -d docs/op-stack && cd docs/op-stack && npx yarn@1 install && cd ../.. || exit 0)"
,
"ready"
:
"pnpm lint && pnpm test"
,
"ready"
:
"pnpm lint && pnpm test"
,
"prepare"
:
"husky install"
,
"prepare"
:
"husky install"
,
"release"
:
"
pnpm build
&& pnpm changeset publish"
,
"release"
:
"
npx nx run-many --target=build --skip-nx-cache
&& pnpm changeset publish"
,
"install:foundry"
:
"curl -L https://foundry.paradigm.xyz | bash && pnpm update:foundry"
,
"install:foundry"
:
"curl -L https://foundry.paradigm.xyz | bash && pnpm update:foundry"
,
"update:foundry"
:
"foundryup -C $(cat .foundryrc)"
"update:foundry"
:
"foundryup -C $(cat .foundryrc)"
},
},
...
...
packages/fault-detector/package.json
View file @
00ed269e
...
@@ -51,7 +51,7 @@
...
@@ -51,7 +51,7 @@
},
},
"dependencies"
:
{
"dependencies"
:
{
"@eth-optimism/common-ts"
:
"^0.8.2"
,
"@eth-optimism/common-ts"
:
"^0.8.2"
,
"@eth-optimism/contracts-bedrock"
:
"
^0.14
.0"
,
"@eth-optimism/contracts-bedrock"
:
"
0.15
.0"
,
"@eth-optimism/core-utils"
:
"^0.12.1"
,
"@eth-optimism/core-utils"
:
"^0.12.1"
,
"@eth-optimism/sdk"
:
"^3.0.0"
,
"@eth-optimism/sdk"
:
"^3.0.0"
,
"@ethersproject/abstract-provider"
:
"^5.7.0"
"@ethersproject/abstract-provider"
:
"^5.7.0"
...
...
packages/fault-detector/test/helpers.spec.ts
View file @
00ed269e
import
hre
from
'
hardhat
'
import
hre
from
'
hardhat
'
import
'
@nomiclabs/hardhat-ethers
'
import
{
Contract
,
utils
}
from
'
ethers
'
import
{
Contract
,
utils
}
from
'
ethers
'
import
{
toRpcHexString
}
from
'
@eth-optimism/core-utils
'
import
{
toRpcHexString
}
from
'
@eth-optimism/core-utils
'
import
{
getContractFactory
}
from
'
@eth-optimism/contracts-bedrock
'
import
Artifact__L2OutputOracle
from
'
@eth-optimism/contracts-bedrock/forge-artifacts/L2OutputOracle.sol/L2OutputOracle.json
'
import
{
SignerWithAddress
}
from
'
@nomiclabs/hardhat-ethers/signers
'
import
{
SignerWithAddress
}
from
'
@nomiclabs/hardhat-ethers/signers
'
import
{
expect
}
from
'
./setup
'
import
{
expect
}
from
'
./setup
'
...
@@ -26,7 +27,13 @@ describe('helpers', () => {
...
@@ -26,7 +27,13 @@ describe('helpers', () => {
let
L2OutputOracle
:
Contract
let
L2OutputOracle
:
Contract
beforeEach
(
async
()
=>
{
beforeEach
(
async
()
=>
{
L2OutputOracle
=
await
getContractFactory
(
'
L2OutputOracle
'
,
signer
).
deploy
(
const
Factory__L2OutputOracle
=
new
hre
.
ethers
.
ContractFactory
(
Artifact__L2OutputOracle
.
abi
,
Artifact__L2OutputOracle
.
bytecode
.
object
,
signer
)
L2OutputOracle
=
await
Factory__L2OutputOracle
.
deploy
(
deployConfig
.
l2OutputOracleSubmissionInterval
,
deployConfig
.
l2OutputOracleSubmissionInterval
,
deployConfig
.
l2BlockTime
,
deployConfig
.
l2BlockTime
,
deployConfig
.
l2OutputOracleStartingBlockNumber
,
deployConfig
.
l2OutputOracleStartingBlockNumber
,
...
...
packages/sdk/src/cross-chain-messenger.ts
View file @
00ed269e
This diff is collapsed.
Click to expand it.
packages/sdk/test/cross-chain-messenger.spec.ts
View file @
00ed269e
...
@@ -565,23 +565,25 @@ describe('CrossChainMessenger', () => {
...
@@ -565,23 +565,25 @@ describe('CrossChainMessenger', () => {
})
})
describe
(
'
when the transaction sent more than one message
'
,
()
=>
{
describe
(
'
when the transaction sent more than one message
'
,
()
=>
{
it
(
'
should
throw an error
'
,
async
()
=>
{
it
(
'
should
be able to get second message by passing in an idex
'
,
async
()
=>
{
const
messages
=
[...
Array
(
2
)].
map
(()
=>
{
const
messages
=
[...
Array
(
2
)].
map
(()
=>
{
return
DUMMY_MESSAGE
return
DUMMY_MESSAGE
})
})
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
(
messages
)
await
expect
(
messenger
.
toCrossChainMessage
(
tx
)).
to
.
be
.
rejectedWith
(
const
foundCrossChainMessages
=
'
expected 1 message, got 2
'
await
messenger
.
getMessagesByTransaction
(
tx
)
expect
(
await
messenger
.
toCrossChainMessage
(
tx
,
1
)).
to
.
deep
.
eq
(
foundCrossChainMessages
[
1
]
)
)
})
})
})
})
describe
(
'
when the transaction sent no messages
'
,
()
=>
{
describe
(
'
when the transaction sent no messages
'
,
()
=>
{
it
(
'
should throw an error
'
,
async
()
=>
{
it
(
'
should throw an
out of bounds
error
'
,
async
()
=>
{
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
([])
const
tx
=
await
l1Messenger
.
triggerSentMessageEvents
([])
await
expect
(
messenger
.
toCrossChainMessage
(
tx
)).
to
.
be
.
rejectedWith
(
await
expect
(
messenger
.
toCrossChainMessage
(
tx
)).
to
.
be
.
rejectedWith
(
'
expected 1 message, got 0
'
`withdrawal index 0 out of bounds. There are 0 withdrawals`
)
)
})
})
})
})
...
...
pnpm-lock.yaml
View file @
00ed269e
...
@@ -457,8 +457,8 @@ importers:
...
@@ -457,8 +457,8 @@ importers:
specifier
:
^0.8.2
specifier
:
^0.8.2
version
:
link:../common-ts
version
:
link:../common-ts
'
@eth-optimism/contracts-bedrock'
:
'
@eth-optimism/contracts-bedrock'
:
specifier
:
^0.14
.0
specifier
:
0.15
.0
version
:
0.14.0
version
:
link:../contracts-bedrock
'
@eth-optimism/core-utils'
:
'
@eth-optimism/core-utils'
:
specifier
:
^0.12.1
specifier
:
^0.12.1
version
:
link:../core-utils
version
:
link:../core-utils
...
@@ -1482,18 +1482,6 @@ packages:
...
@@ -1482,18 +1482,6 @@ packages:
engines
:
{
node
:
^12.22.0 || ^14.17.0 || >=16.0.0
}
engines
:
{
node
:
^12.22.0 || ^14.17.0 || >=16.0.0
}
dev
:
true
dev
:
true
/@eth-optimism/contracts-bedrock@0.14.0
:
resolution
:
{
integrity
:
sha512-mvbSE2q2cyHUwg1jtHwR4JOQJcwdCVRAkmBdXCKUP0XsP48NT1J92bYileRdiUM5nLIESgNNmPA8L2J87mr62g==
}
dependencies
:
'
@eth-optimism/core-utils'
:
0.12.1
'
@openzeppelin/contracts'
:
4.7.3
'
@openzeppelin/contracts-upgradeable'
:
4.7.3
ethers
:
5.7.1
transitivePeerDependencies
:
-
bufferutil
-
utf-8-validate
dev
:
false
/@eth-optimism/contracts@0.6.0(ethers@5.7.1)
:
/@eth-optimism/contracts@0.6.0(ethers@5.7.1)
:
resolution
:
{
integrity
:
sha512-vQ04wfG9kMf1Fwy3FEMqH2QZbgS0gldKhcBeBUPfO8zu68L61VI97UDXmsMQXzTsEAxK8HnokW3/gosl4/NW3w==
}
resolution
:
{
integrity
:
sha512-vQ04wfG9kMf1Fwy3FEMqH2QZbgS0gldKhcBeBUPfO8zu68L61VI97UDXmsMQXzTsEAxK8HnokW3/gosl4/NW3w==
}
peerDependencies
:
peerDependencies
:
...
@@ -1532,23 +1520,6 @@ packages:
...
@@ -1532,23 +1520,6 @@ packages:
-
utf-8-validate
-
utf-8-validate
dev
:
false
dev
:
false
/@eth-optimism/core-utils@0.12.1
:
resolution
:
{
integrity
:
sha512-H2NnH9HTVDJmr9Yzb5R7GrAaYimcyIY4bF5Oud0xM1/DP4pSoNMtWm1kG3ZBpdqHFFYWH9GiSZZC5/cjFdKBEA==
}
dependencies
:
'
@ethersproject/abi'
:
5.7.0
'
@ethersproject/abstract-provider'
:
5.7.0
'
@ethersproject/address'
:
5.7.0
'
@ethersproject/bignumber'
:
5.7.0
'
@ethersproject/bytes'
:
5.7.0
'
@ethersproject/constants'
:
5.7.0
'
@ethersproject/contracts'
:
5.7.0
'
@ethersproject/keccak256'
:
5.7.0
'
@ethersproject/properties'
:
5.7.0
'
@ethersproject/rlp'
:
5.7.0
'
@ethersproject/web'
:
5.7.1
chai
:
4.3.7
dev
:
false
/@ethereum-waffle/chai@3.4.4
:
/@ethereum-waffle/chai@3.4.4
:
resolution
:
{
integrity
:
sha512-/K8czydBtXXkcM9X6q29EqEkc5dN3oYenyH2a9hF7rGAApAJUpH8QBtojxOY/xQ2up5W332jqgxwp0yPiYug1g==
}
resolution
:
{
integrity
:
sha512-/K8czydBtXXkcM9X6q29EqEkc5dN3oYenyH2a9hF7rGAApAJUpH8QBtojxOY/xQ2up5W332jqgxwp0yPiYug1g==
}
engines
:
{
node
:
'
>=10.0'
}
engines
:
{
node
:
'
>=10.0'
}
...
...
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