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
13eb939f
Commit
13eb939f
authored
Dec 05, 2023
by
clabby
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bounded trace ancestor
parent
50b613a7
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
46 additions
and
24 deletions
+46
-24
OutputBisectionGame.sol
...ges/contracts-bedrock/src/dispute/OutputBisectionGame.sol
+20
-6
LibPosition.sol
packages/contracts-bedrock/src/dispute/lib/LibPosition.sol
+18
-13
LibPosition.t.sol
...ages/contracts-bedrock/test/dispute/lib/LibPosition.t.sol
+8
-5
No files found.
packages/contracts-bedrock/src/dispute/OutputBisectionGame.sol
View file @
13eb939f
...
@@ -147,16 +147,18 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
...
@@ -147,16 +147,18 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
// prestate.
// prestate.
// If the step is an attack at a trace index > 0, the prestate exists elsewhere in
// If the step is an attack at a trace index > 0, the prestate exists elsewhere in
// the game state.
// the game state.
// WARN: This will not work, except for in the first execution trace bisection game!
// We need to replace `0` with the correct starting index for the given sub-game.
preStateClaim = stepPos.indexAtDepth() == 0
preStateClaim = stepPos.indexAtDepth() == 0
? ABSOLUTE_PRESTATE
? ABSOLUTE_PRESTATE
: findTraceAncestor(Position.wrap(Position.unwrap(parentPos) - 1), parent.parentIndex).claim;
: findTraceAncestor(Position.wrap(Position.unwrap(parentPos) - 1), parent.parentIndex
, false
).claim;
// For all attacks, the poststate is the parent claim.
// For all attacks, the poststate is the parent claim.
postState = parent;
postState = parent;
} else {
} else {
// If the step is a defense, the poststate exists elsewhere in the game state,
// If the step is a defense, the poststate exists elsewhere in the game state,
// and the parent claim is the expected pre-state.
// and the parent claim is the expected pre-state.
preStateClaim = parent.claim;
preStateClaim = parent.claim;
postState = findTraceAncestor(Position.wrap(Position.unwrap(parentPos) + 1), parent.parentIndex);
postState = findTraceAncestor(Position.wrap(Position.unwrap(parentPos) + 1), parent.parentIndex
, false
);
}
}
// INVARIANT: The prestate is always invalid if the passed `_stateData` is not the
// INVARIANT: The prestate is always invalid if the passed `_stateData` is not the
...
@@ -479,10 +481,20 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
...
@@ -479,10 +481,20 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
/// @notice Finds the trace ancestor of a given position within the DAG.
/// @notice Finds the trace ancestor of a given position within the DAG.
/// @param _pos The position to find the trace ancestor claim of.
/// @param _pos The position to find the trace ancestor claim of.
/// @param _start The index to start searching from.
/// @param _start The index to start searching from.
/// @param _global Whether or not to search the entire dag or just within an execution trace subgame. If set to
/// `true`, and `_pos` is at or above the split depth, this function will revert.
/// @return ancestor_ The ancestor claim that commits to the same trace index as `_pos`.
/// @return ancestor_ The ancestor claim that commits to the same trace index as `_pos`.
function findTraceAncestor(Position _pos, uint256 _start) internal view returns (ClaimData storage ancestor_) {
function findTraceAncestor(
Position _pos,
uint256 _start,
bool _global
)
internal
view
returns (ClaimData storage ancestor_)
{
// Grab the trace ancestor's expected position.
// Grab the trace ancestor's expected position.
Position preStateTraceAncestor = _
pos.traceAncestor(
);
Position preStateTraceAncestor = _
global ? _pos.traceAncestor() : _pos.traceAncestorBounded(SPLIT_DEPTH
);
// Walk up the DAG to find a claim that commits to the same trace index as `_pos`. It is
// Walk up the DAG to find a claim that commits to the same trace index as `_pos`. It is
// guaranteed that such a claim exists.
// guaranteed that such a claim exists.
...
@@ -547,14 +559,16 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
...
@@ -547,14 +559,16 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
// starting claim nor position exists in the tree. We leave these as 0, which can be easily
// starting claim nor position exists in the tree. We leave these as 0, which can be easily
// identified due to 0 being an invalid Gindex.
// identified due to 0 being an invalid Gindex.
if (outputPos.indexAtDepth() > 0) {
if (outputPos.indexAtDepth() > 0) {
ClaimData storage starting = findTraceAncestor(Position.wrap(Position.unwrap(outputPos) - 1), claimIdx);
ClaimData storage starting =
findTraceAncestor(Position.wrap(Position.unwrap(outputPos) - 1), claimIdx, true);
(startingClaim_, startingPos_) = (starting.claim, starting.position);
(startingClaim_, startingPos_) = (starting.claim, starting.position);
} else {
} else {
startingClaim_ = Claim.wrap(Hash.unwrap(GENESIS_OUTPUT_ROOT));
startingClaim_ = Claim.wrap(Hash.unwrap(GENESIS_OUTPUT_ROOT));
}
}
(disputedClaim_, disputedPos_) = (claim.claim, claim.position);
(disputedClaim_, disputedPos_) = (claim.claim, claim.position);
} else {
} else {
ClaimData storage disputed = findTraceAncestor(Position.wrap(Position.unwrap(outputPos) + 1), claimIdx);
ClaimData storage disputed =
findTraceAncestor(Position.wrap(Position.unwrap(outputPos) + 1), claimIdx, true);
(startingClaim_, startingPos_) = (claim.claim, claim.position);
(startingClaim_, startingPos_) = (claim.claim, claim.position);
(disputedClaim_, disputedPos_) = (disputed.claim, disputed.position);
(disputedClaim_, disputedPos_) = (disputed.claim, disputed.position);
}
}
...
...
packages/contracts-bedrock/src/dispute/lib/LibPosition.sol
View file @
13eb939f
...
@@ -138,16 +138,21 @@ library LibPosition {
...
@@ -138,16 +138,21 @@ library LibPosition {
}
}
/// @notice Gets the position of the highest ancestor of `_position` that commits to the same
/// @notice Gets the position of the highest ancestor of `_position` that commits to the same
/// trace index.
/// trace index
, while still being below `_upperBoundExclusive`
.
/// @param _position The position to get the highest ancestor of.
/// @param _position The position to get the highest ancestor of.
/// @param _
splitDepth The split depth within the tree, used to inform where to stop in order to not escape an
/// @param _
upperBoundExclusive The exclusive upper depth bound, used to inform where to stop in order
///
execution trace sub-gam
e.
///
to not escape a sub-tre
e.
/// @return ancestor_ The highest ancestor of `position` that commits to the same trace index.
/// @return ancestor_ The highest ancestor of `position` that commits to the same trace index.
function traceAncestorExec(Position _position, uint256 _splitDepth) internal pure returns (Position ancestor_) {
function traceAncestorBounded(
// This function only works for positions that are below the split depth (i.e., commit to state hashes
Position _position,
// of the fault proof program rather than output roots)
uint256 _upperBoundExclusive
uint256 posDepth = _position.depth();
)
if (posDepth <= _splitDepth) revert ClaimAboveSplit();
internal
pure
returns (Position ancestor_)
{
// This function only works for positions that are below the upper bound.
if (_position.depth() <= _upperBoundExclusive) revert ClaimAboveSplit();
// Create a field with only the lowest unset bit of `_position` set.
// Create a field with only the lowest unset bit of `_position` set.
Position lsb;
Position lsb;
...
@@ -162,11 +167,11 @@ library LibPosition {
...
@@ -162,11 +167,11 @@ library LibPosition {
ancestor_ := or(a, iszero(a))
ancestor_ := or(a, iszero(a))
}
}
// If the ancestor is above or at the
split depth, shift it to below the split depth
.
// If the ancestor is above or at the
upper bound, shift it to be below the upper bound
.
// This should be a special case that only covers positions that commit to the final
trace
// This should be a special case that only covers positions that commit to the final
leaf
// in
dex in an execution trace sub
tree.
// in
a sub-
tree.
if (ancestor_.depth() <= _
splitDepth
) {
if (ancestor_.depth() <= _
upperBoundExclusive
) {
ancestor_ = ancestor_.rightIndex(_
splitDepth
+ 1);
ancestor_ = ancestor_.rightIndex(_
upperBoundExclusive
+ 1);
}
}
}
}
...
...
packages/contracts-bedrock/test/dispute/lib/LibPosition.t.sol
View file @
13eb939f
...
@@ -93,18 +93,21 @@ contract LibPosition_Test is Test {
...
@@ -93,18 +93,21 @@ contract LibPosition_Test is Test {
assertEq(Position.unwrap(ancestor), Position.unwrap(loopAncestor));
assertEq(Position.unwrap(ancestor), Position.unwrap(loopAncestor));
}
}
/// @notice Tests that the `traceAncestor` function correctly computes the position of the
/// @notice Tests that the `traceAncestor
Bounded
` function correctly computes the position of the
/// highest ancestor that commits to the same trace index.
/// highest ancestor
(below `SPLIT_DEPTH`)
that commits to the same trace index.
function testFuzz_traceAncestor
Exec
_correctness_succeeds(uint8 _depth, uint64 _indexAtDepth) public {
function testFuzz_traceAncestor
Bounded
_correctness_succeeds(uint8 _depth, uint64 _indexAtDepth) public {
_depth = uint8(bound(_depth, SPLIT_DEPTH + 1, MAX_DEPTH));
_depth = uint8(bound(_depth, SPLIT_DEPTH + 1, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position ancestor = position.traceAncestor
Exec
(SPLIT_DEPTH);
Position ancestor = position.traceAncestor
Bounded
(SPLIT_DEPTH);
Position loopAncestor = position;
Position loopAncestor = position;
// Stop at 1 below the split depth.
// Stop at 1 below the split depth.
while (loopAncestor.parent().traceIndex(MAX_DEPTH) == position.traceIndex(MAX_DEPTH) && loopAncestor.depth() != SPLIT_DEPTH + 1) {
while (
loopAncestor.parent().traceIndex(MAX_DEPTH) == position.traceIndex(MAX_DEPTH)
&& loopAncestor.depth() != SPLIT_DEPTH + 1
) {
loopAncestor = loopAncestor.parent();
loopAncestor = loopAncestor.parent();
}
}
...
...
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