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
460af9e4
Commit
460af9e4
authored
Jul 01, 2023
by
clabby
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Document invariants in `FaultDisputeGame`
parent
d80c145e
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
29 additions
and
21 deletions
+29
-21
FaultDisputeGame.sol
.../contracts-bedrock/contracts/dispute/FaultDisputeGame.sol
+29
-21
No files found.
packages/contracts-bedrock/contracts/dispute/FaultDisputeGame.sol
View file @
460af9e4
...
@@ -87,7 +87,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -87,7 +87,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
bytes calldata _stateData,
bytes calldata _stateData,
bytes calldata _proof
bytes calldata _proof
) external {
) external {
// Steps cannot be made unless the game is currently in progress.
//
INVARIANT:
Steps cannot be made unless the game is currently in progress.
if (status != GameStatus.IN_PROGRESS) {
if (status != GameStatus.IN_PROGRESS) {
revert GameNotInProgress();
revert GameNotInProgress();
}
}
...
@@ -100,7 +100,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -100,7 +100,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// Determine the position of the step.
// Determine the position of the step.
Position stepPos = parentPos.move(_isAttack);
Position stepPos = parentPos.move(_isAttack);
//
Ensure that the step position is 1 deeper than the maximum game depth.
//
INVARIANT: A step cannot be made unless the move position is 1 below the `MAX_GAME_DEPTH`
if (stepPos.depth() != MAX_GAME_DEPTH + 1) {
if (stepPos.depth() != MAX_GAME_DEPTH + 1) {
revert InvalidParent();
revert InvalidParent();
}
}
...
@@ -132,8 +132,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -132,8 +132,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
postStateClaim = claimData[_stateIndex].claim;
postStateClaim = claimData[_stateIndex].claim;
}
}
// Assert that the given prestate commits to the instruction at `gindex - 1` and
// INVARIANT: The prestate is always invalid if its gindex is not one less than that
// that the `_stateData` is the preimage for the prestate claim digest.
// of the post state.
// INVARIANT: The prestate is always invalid if the passed `_stateData` is not the
// preimage of the prestate claim hash.
if (
if (
Position.unwrap(preStatePos.rightIndex(MAX_GAME_DEPTH)) !=
Position.unwrap(preStatePos.rightIndex(MAX_GAME_DEPTH)) !=
Position.unwrap(postStatePos.rightIndex(MAX_GAME_DEPTH)) - 1 ||
Position.unwrap(postStatePos.rightIndex(MAX_GAME_DEPTH)) - 1 ||
...
@@ -143,7 +145,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -143,7 +145,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
}
}
}
}
// Perform the VM step and check to see if it is valid.
// INVARIANT: A VM step can never counter a parent claim unless it produces an unexpected
// poststate. "Unexpected" is defined as "not equal to the claim at
// `_parentIndex` if the step is an attack, or the claim at `_stateIndex` if
// the step is a defense."
if (VM.step(_stateData, _proof) == Claim.unwrap(postStateClaim)) {
if (VM.step(_stateData, _proof) == Claim.unwrap(postStateClaim)) {
revert ValidStep();
revert ValidStep();
}
}
...
@@ -166,14 +171,14 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -166,14 +171,14 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
Claim _pivot,
Claim _pivot,
bool _isAttack
bool _isAttack
) public payable {
) public payable {
// Moves cannot be made unless the game is currently in progress.
//
INVARIANT:
Moves cannot be made unless the game is currently in progress.
if (status != GameStatus.IN_PROGRESS) {
if (status != GameStatus.IN_PROGRESS) {
revert GameNotInProgress();
revert GameNotInProgress();
}
}
//
The only move that can be made against a root claim is an attack. This is because the
//
INVARIANT: A defense can never be made against the root claim. This is because the root
//
root claim commits to the entire state; Therefore, the only valid defense is to d
o
//
claim commits to the entire state. Therefore, the only valid defense is t
o
// nothing if it is agreed with.
//
do
nothing if it is agreed with.
if (_challengeIndex == 0 && !_isAttack) {
if (_challengeIndex == 0 && !_isAttack) {
revert CannotDefendRootClaim();
revert CannotDefendRootClaim();
}
}
...
@@ -189,9 +194,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -189,9 +194,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// or not the move is an attack or defense.
// or not the move is an attack or defense.
Position nextPosition = parent.position.move(_isAttack);
Position nextPosition = parent.position.move(_isAttack);
// At the leaf nodes of the game, the only option is to run a step to prove or disprove
// INVARIANT: A move can never surpass the `MAX_GAME_DEPTH`. The only option to counter a
// the above claim. At this depth, the parent claim commits to the state after a single
// claim at this depth is to perform a single instruction step on-chain via
// instruction step.
// the `step` function to prove that the state transition produces an unexpected
// post-state.
if (nextPosition.depth() > MAX_GAME_DEPTH) {
if (nextPosition.depth() > MAX_GAME_DEPTH) {
revert GameDepthExceeded();
revert GameDepthExceeded();
}
}
...
@@ -217,8 +223,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -217,8 +223,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
)
)
);
);
//
Enforce the clock time rules. If the new clock duration is greater than half of the game
//
INVARIANT: A move can never be made once its clock has exceeded `GAME_DURATION / 2`
//
duration, then the move is invalid and cannot be mad
e.
//
seconds of tim
e.
if (Duration.unwrap(nextDuration) > Duration.unwrap(GAME_DURATION) >> 1) {
if (Duration.unwrap(nextDuration) > Duration.unwrap(GAME_DURATION) >> 1) {
revert ClockTimeExceeded();
revert ClockTimeExceeded();
}
}
...
@@ -226,7 +232,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -226,7 +232,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// Construct the next clock with the new duration and the current block timestamp.
// Construct the next clock with the new duration and the current block timestamp.
Clock nextClock = LibClock.wrap(nextDuration, Timestamp.wrap(uint64(block.timestamp)));
Clock nextClock = LibClock.wrap(nextDuration, Timestamp.wrap(uint64(block.timestamp)));
// Do not allow for a duplicate claim to be made.
// INVARIANT: A claim may only exist at a given position once. Multiple claims may exist
// at the same position, however they must have different values.
ClaimHash claimHash = _pivot.hashClaimPos(nextPosition);
ClaimHash claimHash = _pivot.hashClaimPos(nextPosition);
if (claims[claimHash]) {
if (claims[claimHash]) {
revert ClaimAlreadyExists();
revert ClaimAlreadyExists();
...
@@ -274,7 +281,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -274,7 +281,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
/// @inheritdoc IDisputeGame
/// @inheritdoc IDisputeGame
function resolve() external returns (GameStatus status_) {
function resolve() external returns (GameStatus status_) {
// I
f the game is not in progress, it cannot be resolved
.
// I
NVARIANT: Resolution cannot occur unless the game is currently in progress
.
if (status != GameStatus.IN_PROGRESS) {
if (status != GameStatus.IN_PROGRESS) {
revert GameNotInProgress();
revert GameNotInProgress();
}
}
...
@@ -293,8 +300,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -293,8 +300,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
--i;
--i;
}
}
// I
f the claim is not a dangling node above the bottom of the tree,
// I
NVARIANT: A claim can never be considered as the leftMostIndex or leftMostTraceIndex
//
we can skip over it. These nodes are not relevant to the game resolution
.
//
if it has been countered
.
if (claim.countered) {
if (claim.countered) {
continue;
continue;
}
}
...
@@ -314,9 +321,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
...
@@ -314,9 +321,10 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// Create a reference to the left most uncontested claim and its parent.
// Create a reference to the left most uncontested claim and its parent.
ClaimData storage leftMostUncontested = claimData[leftMostIndex];
ClaimData storage leftMostUncontested = claimData[leftMostIndex];
// If the left most uncontested claim's parent has not expired their clock, the game
// INVARIANT: The game may never be resolved unless the clock of the left-most uncontested
// cannot be resolved. If the left most uncontested claim is the root, no nodes qualified,
// claim's parent has expired. If the left-most uncontested claim is the root
// and we check if 3.5 days has passed since the root claim's creation.
// claim, it is uncountered, and we check if 3.5 days has passed since its
// creation.
uint256 parentIndex = leftMostUncontested.parentIndex;
uint256 parentIndex = leftMostUncontested.parentIndex;
Clock opposingClock = parentIndex == type(uint32).max
Clock opposingClock = parentIndex == type(uint32).max
? leftMostUncontested.clock
? leftMostUncontested.clock
...
...
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