Commit 57f9bf9e authored by George Hotz's avatar George Hotz

challenge contract compiles

parent eb1f6050
Two oracles: One oracle:
Implement as three MIPS instructions Implement as a MIPS instruction?
InputOracle -- Preagreed upon inputs InputOracle -- Preagreed upon inputs (TODO: replace with memory reads from given address range)
$a0 = input choice $a0 = input choice
0 -- StateRoot(n) 0 -- StateRoot(n)
1 -- Transactions(n+1) 1 -- Transactions(n+1)
...@@ -40,21 +40,21 @@ C: InitiateChallenge(uint blockNumberN, bytes blockHeaderN, bytes blockHeaderNp1 ...@@ -40,21 +40,21 @@ C: InitiateChallenge(uint blockNumberN, bytes blockHeaderN, bytes blockHeaderNp1
* confirm assertionProof[8] proves the final state of $pc in finalSystemHash is 0xDEADDEAD * confirm assertionProof[8] proves the final state of $pc in finalSystemHash is 0xDEADDEAD
* L = 0, R = stepCount # we agree at L=0, we disagree at R=stepCount * L = 0, R = stepCount # we agree at L=0, we disagree at R=stepCount
* return new challengeId * return new challengeId
* assertedRiscState[0] = GlobalStartSystemHash * assertedState[0] = GlobalStartSystemHash + inputOracleMutations
* defendedRiscState[0] = GlobalStartSystemHash * defendedState[0] = GlobalStartSystemHash + inputOracleMutations
* assertedRiscState[stepCount] = finalSystemHash * assertedState[stepCount] = finalSystemHash
........ ........
if it's one step, we are done. considering it's not, we binary search if it's one step, we are done. considering it's not, we binary search
........ ........
C: ProposeRiscState(uint256 challengeId, uint256 riscState) C: ProposeState(uint256 challengeId, uint256 riscState)
* stepNumber = GetStepNumber(uint256 challengeId) returns floor((L + R) / 2) * stepNumber = GetStepNumber(uint256 challengeId) returns floor((L + R) / 2)
* assert assertedRiscState[stepNumber] == 0 * assert assertedState[stepNumber] == 0
* assertedRiscState[stepNumber] = riscState * assertedState[stepNumber] = riscState
D: RespondRiscState(uint256 challengeId, uint256 riscState) onlyOwner D: RespondState(uint256 challengeId, uint256 riscState) onlyOwner
* off-chain: run to step = stepNumber, get state hash, check if it matches * off-chain: run to step = stepNumber, get state hash, check if it matches
* stepNumber = GetStepNumber(uint256 challengeId) returns floor((L + R) / 2) * stepNumber = GetStepNumber(uint256 challengeId) returns floor((L + R) / 2)
* defendedRiscState[stepNumber] = riscState * defendedState[stepNumber] = riscState
* if assertedRiscState[stepNumber] == defendedRiscState[stepNumber]: * if assertedState[stepNumber] == defendedState[stepNumber]:
L = stepNumber # we agree at stepNumber L = stepNumber # we agree at stepNumber
else: else:
R = stepNumber # we disagree at stepNumber R = stepNumber # we disagree at stepNumber
...@@ -62,14 +62,14 @@ D: RespondRiscState(uint256 challengeId, uint256 riscState) onlyOwner ...@@ -62,14 +62,14 @@ D: RespondRiscState(uint256 challengeId, uint256 riscState) onlyOwner
........ ........
binary search until L+1 == R binary search until L+1 == R
the issue is with the L->R transition the issue is with the L->R transition
aka assertedRiscState[L] -> assertedRiscState[R] aka assertedState[L] -> assertedState[R]
........ ........
# call this at any time (global), adds them to a preimage lookup for PreimageOracle # call this at any time (global), adds them to a preimage lookup for PreimageOracle
# put these on the MIPS contract # put these on the MIPS contract
C: ProposePreimage(bytes anything) C: AddPreimage(bytes anything)
* preimageLookup[keccak256(anything)] = anything * preimageLookup[keccak256(anything)] = anything
C: AddMerkleState(uint256 stateHash, uint32 addr, uint32 value, string proof) C: AddMerkleState(uint256 stateHash, uint32 addr, uint32 value, string proof)
* validate proof in assertedRiscState[stepNumber] * validate proof in assertedState[stepNumber]
* riscMemory[stepNumber][address] = value * riscMemory[stepNumber][address] = value
* Final * Final
...@@ -77,12 +77,12 @@ C: ConfirmStateTransition(uint256 challengeId) ...@@ -77,12 +77,12 @@ C: ConfirmStateTransition(uint256 challengeId)
* assert L+1 == R * assert L+1 == R
* do the state transition * do the state transition
* if any needed pieces of start state are missing in riscMemory, challenge fails (it can try again) * if any needed pieces of start state are missing in riscMemory, challenge fails (it can try again)
* reconstruct the riscState after transition -> newRiscState * reconstruct the riscState after transition -> newState
* assert assertedRiscState[R] == newRiscState * assert assertedState[R] == newState
* pay out bounty * pay out bounty
# optional claim for the defender # optional claim for the defender
# prove the defendedRiscState[L] -> defendedRiscState[R] # prove the defendedState[L] -> defendedState[R]
# NOTE, if it's the last step, defendedRiscState[R] might not exist. # NOTE, if it's the last step, defendedState[R] might not exist.
TODO: ensure the state merklization is canonical. if it doesn't match perfectly you can lose TODO: ensure the state merklization is canonical. if it doesn't match perfectly you can lose
\ No newline at end of file
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.3;
interface IMIPS {
function Step(bytes32 stateHash) external view returns (bytes32);
}
contract Challenge {
address payable immutable owner;
IMIPS immutable mips;
struct Chal {
uint256 L;
uint256 R;
mapping(uint256 => bytes32) assertedState;
mapping(uint256 => bytes32) defendedState;
address payable challenger;
}
Chal[] challenges;
constructor(IMIPS imips) {
owner = msg.sender;
mips = imips;
}
// allow getting money
fallback() external payable {}
receive() external payable {}
function withdraw() external {
require(msg.sender == owner);
owner.transfer(address(this).balance);
}
function InitiateChallenge(uint blockNumberN,
bytes calldata blockHeaderN, bytes calldata blockHeaderNp1,
bytes32 assertionHash, bytes32 finalSystemHash, uint256 stepCount) external {
// is this new?
Chal storage c = challenges[challenges.length];
c.challenger = msg.sender;
// TODO: this is the function with the complexity
}
function getStepNumber(uint256 challengeId) view public returns (uint256) {
Chal storage c = challenges[challengeId];
return (c.L+c.R)/2;
}
function ProposeState(uint256 challengeId, bytes32 riscState) external {
Chal storage c = challenges[challengeId];
require(c.challenger == msg.sender, "must be challenger");
uint256 stepNumber = getStepNumber(challengeId);
require(c.assertedState[stepNumber] == bytes32(0), "state already proposed");
c.assertedState[stepNumber] = riscState;
}
function RespondState(uint256 challengeId, bytes32 riscState) external {
Chal storage c = challenges[challengeId];
require(msg.sender == owner, "must be owner");
uint256 stepNumber = getStepNumber(challengeId);
require(c.defendedState[stepNumber] == bytes32(0), "state already proposed");
// technically, we don't have to save these states
// but if we want to prove us right and not just the attacker wrong, we do
c.defendedState[stepNumber] = riscState;
if (c.assertedState[stepNumber] == c.defendedState[stepNumber]) {
// agree
c.L = stepNumber;
} else {
// disagree
c.R = stepNumber;
}
}
function ConfirmStateTransition(uint256 challengeId) external {
Chal storage c = challenges[challengeId];
require(c.challenger == msg.sender, "must be challenger");
require(c.L + 1 == c.R, "binary search not finished");
bytes32 newState = mips.Step(c.assertedState[c.L]);
require(newState == c.assertedState[c.R], "wrong asserted state");
// pay out bounty!!
msg.sender.transfer(address(this).balance);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.3; pragma solidity ^0.7.3;
// https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_Green_Sheet.pdf // https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_Green_Sheet.pdf
// https://uweb.engr.arizona.edu/~ece369/Resources/spim/MIPSReference.pdf // https://uweb.engr.arizona.edu/~ece369/Resources/spim/MIPSReference.pdf
// This is a separate contract from the challenge contract
// Anyone can use it to validate a MIPS state transition
// First, to prepare, you call AddMerkleState, which adds valid state nodes in the stateHash.
// If you are using the Preimage oracle, you call AddPreimage
// Then, you call Step. Step will revert if state is missing. If all state is present, it will return the next hash
contract MIPS { contract MIPS {
// This state is global // This state is global
mapping(bytes32 => mapping (uint32 => uint64)) public state; mapping(bytes32 => mapping (uint32 => uint64)) public state;
...@@ -33,7 +41,7 @@ contract MIPS { ...@@ -33,7 +41,7 @@ contract MIPS {
// compute the next state // compute the next state
// will revert if any input state is missing // will revert if any input state is missing
function Step(bytes32 stateHash) public view returns (uint64[] memory) { function Step(bytes32 stateHash) public view returns (bytes32) {
// instruction fetch // instruction fetch
uint32 pc = getState(stateHash, REG_PC); uint32 pc = getState(stateHash, REG_PC);
uint32 insn = getState(stateHash, pc); uint32 insn = getState(stateHash, pc);
......
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