Commit c2e009b5 authored by clabby's avatar clabby

Focus PR on bisection

parent 9a8f2814
......@@ -77,6 +77,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
*/
ClaimData[] public claimData;
/**
* @notice An internal mapping to allow for constant-time lookups of existing claims.
*/
mapping(ClaimHash => bool) internal claims;
////////////////////////////////////////////////////////////////
// External Logic //
////////////////////////////////////////////////////////////////
......@@ -99,37 +104,12 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
* @inheritdoc IFaultDisputeGame
*/
function step(
uint256 prestateIndex,
uint256 parentIndex,
bytes32 stateHash,
bytes calldata stateData,
bytes calldata
) public {
) external {
// 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 {
revert ParentDoesNotExist();
}
// Bump the parent's reference counter.
claimData[challengeIndex].rc += 1;
// Set the parent claim as countered.
claimData[challengeIndex].countered = true;
......@@ -217,8 +195,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
Clock nextClock = LibClock.wrap(nextDuration, Timestamp.wrap(uint64(block.timestamp)));
// Do not allow for a duplicate claim to be made.
// TODO.
// Maybe map the claimHash? There's no efficient way to check for this with the flat DAG.
ClaimHash claimHash = LibHashing.hashClaimPos(pivot, nextPosition);
if (claims[claimHash]) {
revert ClaimAlreadyExists();
}
claims[claimHash] = true;
// Create the new claim.
claimData.push(
......@@ -227,7 +208,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
claim: pivot,
position: nextPosition,
clock: nextClock,
rc: 0,
countered: false
})
);
......@@ -276,45 +256,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// the search.
Position leftMost;
// Run an exhaustive search (`O(n)`) over the DAG to find the left most, deepest
// 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;
}
}
}
// TODO - Resolution
// 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.
......@@ -379,7 +321,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
claim: rootClaim(),
position: ROOT_POSITION,
clock: LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))),
rc: 0,
countered: false
})
);
......
......@@ -17,7 +17,6 @@ interface IFaultDisputeGame is IDisputeGame {
*/
struct ClaimData {
uint32 parentIndex;
uint32 rc;
bool countered;
Claim claim;
Position position;
......@@ -62,15 +61,14 @@ interface IFaultDisputeGame is IDisputeGame {
* 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
* fault proof VMs (MIPS, RiscV5, etc.)
* @param parentIndex The index of the parent claim in `claimData`. Contains the state hash
* of the post-state.
* @param stateHash The initial merklized prestate.
* @param stateData The input for the state transition.
* @param proof The proof that the state transition is valid.
* @param prestateIndex The index of the prestate of the step within `claimData`.
* @param parentIndex The index of the parent claim within `claimData`.
* @param stateData The stateData of the step is the preimage of the claim @ `prestateIndex`
* @param proof ...
*/
function step(
uint256 prestateIndex,
uint256 parentIndex,
bytes32 stateHash,
bytes calldata stateData,
bytes calldata proof
) external;
......
......@@ -114,7 +114,6 @@ contract FaultDisputeGame_Test is Test {
function test_initialRootClaimData_succeeds() public {
(
uint32 parentIndex,
uint32 rc,
bool countered,
Claim claim,
Position position,
......@@ -122,7 +121,6 @@ contract FaultDisputeGame_Test is Test {
) = gameProxy.claimData(0);
assertEq(parentIndex, type(uint32).max);
assertEq(rc, 0);
assertEq(countered, false);
assertEq(Claim.unwrap(claim), Claim.unwrap(ROOT_CLAIM));
assertEq(Position.unwrap(position), 0);
......@@ -145,7 +143,6 @@ contract FaultDisputeGame_Test is Test {
// Grab the claim data of the attack.
(
uint32 parentIndex,
uint32 rc,
bool countered,
Claim claim,
Position position,
......@@ -154,7 +151,6 @@ contract FaultDisputeGame_Test is Test {
// Assert correctness of the attack claim's data.
assertEq(parentIndex, 0);
assertEq(rc, 0);
assertEq(countered, false);
assertEq(Claim.unwrap(claim), Claim.unwrap(Claim.wrap(bytes32(uint256(5)))));
assertEq(Position.unwrap(position), Position.unwrap(LibPosition.attack(Position.wrap(0))));
......@@ -164,11 +160,10 @@ contract FaultDisputeGame_Test is Test {
);
// 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.
assertEq(parentIndex, type(uint32).max);
assertEq(rc, 1);
assertEq(countered, true);
assertEq(Claim.unwrap(claim), Claim.unwrap(ROOT_CLAIM));
assertEq(Position.unwrap(position), 0);
......@@ -178,9 +173,6 @@ contract FaultDisputeGame_Test is Test {
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