Commit c2e009b5 authored by clabby's avatar clabby

Focus PR on bisection

parent 9a8f2814
...@@ -77,6 +77,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -77,6 +77,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
*/ */
ClaimData[] public claimData; ClaimData[] public claimData;
/**
* @notice An internal mapping to allow for constant-time lookups of existing claims.
*/
mapping(ClaimHash => bool) internal claims;
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// External Logic // // External Logic //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
...@@ -99,37 +104,12 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -99,37 +104,12 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
* @inheritdoc IFaultDisputeGame * @inheritdoc IFaultDisputeGame
*/ */
function step( function step(
uint256 prestateIndex,
uint256 parentIndex, uint256 parentIndex,
bytes32 stateHash,
bytes calldata stateData, bytes calldata stateData,
bytes calldata bytes calldata
) public { ) external {
// TODO - Call the VM to perform the execution step. // TODO - Call the VM to perform the execution step.
// Mock a state transition
// NOTE: This mock lacks several necessary checks. For testing only.
uint256 inp = abi.decode(stateData, (uint256));
bytes32 nextStateHash = bytes32(uint256(stateHash) + inp);
ClaimData memory parent = claimData[parentIndex];
if (nextStateHash != Claim.unwrap(parent.claim)) {
revert("Invalid state transition");
}
// If the state transition was successful, append a new claim to the game at the
// `MAX_GAME_DEPTH`
Position nextPosition = LibPosition.attack(parent.position);
claimData.push(
ClaimData({
parentIndex: uint32(parentIndex),
claim: Claim.wrap(nextStateHash),
position: nextPosition,
clock: Clock.wrap(0),
rc: 0,
countered: false
})
);
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
...@@ -167,8 +147,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -167,8 +147,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
revert ParentDoesNotExist(); revert ParentDoesNotExist();
} }
// Bump the parent's reference counter.
claimData[challengeIndex].rc += 1;
// Set the parent claim as countered. // Set the parent claim as countered.
claimData[challengeIndex].countered = true; claimData[challengeIndex].countered = true;
...@@ -217,8 +195,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -217,8 +195,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
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. // Do not allow for a duplicate claim to be made.
// TODO. ClaimHash claimHash = LibHashing.hashClaimPos(pivot, nextPosition);
// Maybe map the claimHash? There's no efficient way to check for this with the flat DAG. if (claims[claimHash]) {
revert ClaimAlreadyExists();
}
claims[claimHash] = true;
// Create the new claim. // Create the new claim.
claimData.push( claimData.push(
...@@ -227,7 +208,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -227,7 +208,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
claim: pivot, claim: pivot,
position: nextPosition, position: nextPosition,
clock: nextClock, clock: nextClock,
rc: 0,
countered: false countered: false
}) })
); );
...@@ -276,45 +256,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -276,45 +256,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// the search. // the search.
Position leftMost; Position leftMost;
// Run an exhaustive search (`O(n)`) over the DAG to find the left most, deepest // TODO - Resolution
// uncontested claim.
for (; i > 0; --i) {
ClaimData memory claim = claimData[i];
// If the claim has no refereces, we can virtually prune it.
if (claim.rc == 0) {
Position position = claim.position;
uint128 depth = LibPosition.depth(position);
// 1. Do not count nodes at the max game depth. These can be truthy, but they do not
// give us any intuition about the final outcome of the game.
// 2. Any node that has been countered is not a dangling claim, which is all that
// we're concerned about.
// All claims that pass this check qualify for pruning.
if (depth != MAX_GAME_DEPTH && !claim.countered) {
uint128 leftMostDepth = LibPosition.depth(leftMost);
// If the claim here is deeper than the current left most, deepest claim,
// update `leftMost`.
// If the claim here is at the same depth, but further left, update `leftMost`.
if (
depth > leftMostDepth ||
(depth == leftMostDepth &&
LibPosition.indexAtDepth(position) <=
LibPosition.indexAtDepth(leftMost))
) {
leftMost = position;
}
}
// If the claim has a parent, decrement the reference count of the parent. This
// effectively "prunes" the claim from the DAG without spending extra gas on
// deleting it from storage.
if (claim.parentIndex != type(uint32).max) {
--claimData[claim.parentIndex].rc;
}
}
}
// If the depth of the left most, deepest dangling claim is odd, the root was attacked // If the depth of the left most, deepest dangling claim is odd, the root was attacked
// successfully and the defender wins. Otherwise, the challenger wins. // successfully and the defender wins. Otherwise, the challenger wins.
...@@ -379,7 +321,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -379,7 +321,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
claim: rootClaim(), claim: rootClaim(),
position: ROOT_POSITION, position: ROOT_POSITION,
clock: LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))), clock: LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))),
rc: 0,
countered: false countered: false
}) })
); );
......
...@@ -17,7 +17,6 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -17,7 +17,6 @@ interface IFaultDisputeGame is IDisputeGame {
*/ */
struct ClaimData { struct ClaimData {
uint32 parentIndex; uint32 parentIndex;
uint32 rc;
bool countered; bool countered;
Claim claim; Claim claim;
Position position; Position position;
...@@ -62,15 +61,14 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -62,15 +61,14 @@ interface IFaultDisputeGame is IDisputeGame {
* a step in the fault proof program on-chain. The interface of the fault proof * a step in the fault proof program on-chain. The interface of the fault proof
* processor contract should be generic enough such that we can use different * processor contract should be generic enough such that we can use different
* fault proof VMs (MIPS, RiscV5, etc.) * fault proof VMs (MIPS, RiscV5, etc.)
* @param parentIndex The index of the parent claim in `claimData`. Contains the state hash * @param prestateIndex The index of the prestate of the step within `claimData`.
* of the post-state. * @param parentIndex The index of the parent claim within `claimData`.
* @param stateHash The initial merklized prestate. * @param stateData The stateData of the step is the preimage of the claim @ `prestateIndex`
* @param stateData The input for the state transition. * @param proof ...
* @param proof The proof that the state transition is valid.
*/ */
function step( function step(
uint256 prestateIndex,
uint256 parentIndex, uint256 parentIndex,
bytes32 stateHash,
bytes calldata stateData, bytes calldata stateData,
bytes calldata proof bytes calldata proof
) external; ) external;
......
...@@ -114,7 +114,6 @@ contract FaultDisputeGame_Test is Test { ...@@ -114,7 +114,6 @@ contract FaultDisputeGame_Test is Test {
function test_initialRootClaimData_succeeds() public { function test_initialRootClaimData_succeeds() public {
( (
uint32 parentIndex, uint32 parentIndex,
uint32 rc,
bool countered, bool countered,
Claim claim, Claim claim,
Position position, Position position,
...@@ -122,7 +121,6 @@ contract FaultDisputeGame_Test is Test { ...@@ -122,7 +121,6 @@ contract FaultDisputeGame_Test is Test {
) = gameProxy.claimData(0); ) = gameProxy.claimData(0);
assertEq(parentIndex, type(uint32).max); assertEq(parentIndex, type(uint32).max);
assertEq(rc, 0);
assertEq(countered, false); assertEq(countered, false);
assertEq(Claim.unwrap(claim), Claim.unwrap(ROOT_CLAIM)); assertEq(Claim.unwrap(claim), Claim.unwrap(ROOT_CLAIM));
assertEq(Position.unwrap(position), 0); assertEq(Position.unwrap(position), 0);
...@@ -145,7 +143,6 @@ contract FaultDisputeGame_Test is Test { ...@@ -145,7 +143,6 @@ contract FaultDisputeGame_Test is Test {
// Grab the claim data of the attack. // Grab the claim data of the attack.
( (
uint32 parentIndex, uint32 parentIndex,
uint32 rc,
bool countered, bool countered,
Claim claim, Claim claim,
Position position, Position position,
...@@ -154,7 +151,6 @@ contract FaultDisputeGame_Test is Test { ...@@ -154,7 +151,6 @@ contract FaultDisputeGame_Test is Test {
// Assert correctness of the attack claim's data. // Assert correctness of the attack claim's data.
assertEq(parentIndex, 0); assertEq(parentIndex, 0);
assertEq(rc, 0);
assertEq(countered, false); assertEq(countered, false);
assertEq(Claim.unwrap(claim), Claim.unwrap(Claim.wrap(bytes32(uint256(5))))); assertEq(Claim.unwrap(claim), Claim.unwrap(Claim.wrap(bytes32(uint256(5)))));
assertEq(Position.unwrap(position), Position.unwrap(LibPosition.attack(Position.wrap(0)))); assertEq(Position.unwrap(position), Position.unwrap(LibPosition.attack(Position.wrap(0))));
...@@ -164,11 +160,10 @@ contract FaultDisputeGame_Test is Test { ...@@ -164,11 +160,10 @@ contract FaultDisputeGame_Test is Test {
); );
// Grab the claim data of the parent. // Grab the claim data of the parent.
(parentIndex, rc, countered, claim, position, clock) = gameProxy.claimData(0); (parentIndex, countered, claim, position, clock) = gameProxy.claimData(0);
// Assert correctness of the parent claim's data. // Assert correctness of the parent claim's data.
assertEq(parentIndex, type(uint32).max); assertEq(parentIndex, type(uint32).max);
assertEq(rc, 1);
assertEq(countered, true); assertEq(countered, true);
assertEq(Claim.unwrap(claim), Claim.unwrap(ROOT_CLAIM)); assertEq(Claim.unwrap(claim), Claim.unwrap(ROOT_CLAIM));
assertEq(Position.unwrap(position), 0); assertEq(Position.unwrap(position), 0);
...@@ -178,9 +173,6 @@ contract FaultDisputeGame_Test is Test { ...@@ -178,9 +173,6 @@ contract FaultDisputeGame_Test is Test {
LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp - 5))) LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp - 5)))
) )
); );
// Resolve the game.
assertEq(uint256(gameProxy.resolve()), uint256(GameStatus.CHALLENGER_WINS));
} }
} }
......
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