Commit 3f1c9761 authored by George Hotz's avatar George Hotz

write challenge contract

parent 57f9bf9e
...@@ -24,7 +24,7 @@ PreimageOracle -- key value store ...@@ -24,7 +24,7 @@ PreimageOracle -- key value store
returns returns
$v0 = preimage[$t7...$t0] >> ($a0 * 32) $v0 = preimage[$t7...$t0] >> ($a0 * 32)
Program returns a hash in [$t7...$t0] and exits(jump to 0xDEADDEAD) with the hash in the state Program returns a hash in [$t7...$t0] and exits(jump to 0xDEAD0000) with the hash in the state
Challenge Flow: Challenge Flow:
C is challenger, D is defender C is challenger, D is defender
...@@ -35,9 +35,8 @@ C: InitiateChallenge(uint blockNumberN, bytes blockHeaderN, bytes blockHeaderNp1 ...@@ -35,9 +35,8 @@ C: InitiateChallenge(uint blockNumberN, bytes blockHeaderN, bytes blockHeaderNp1
* checks hashes of the block headers * checks hashes of the block headers
* saves inputs for input oracle * saves inputs for input oracle
* confirms assertionHash != blockHeaderNp1.Hash * confirms assertionHash != blockHeaderNp1.Hash
* expectCorrect = (assertionHash == blockHeaderNp1.Hash)
* confirm assertionProof[0..7] proves the final state of [$t7...$t0] in finalSystemHash is assertionHash * confirm assertionProof[0..7] proves the final state of [$t7...$t0] in finalSystemHash is assertionHash
* 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 0xDEAD0000
* 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
* assertedState[0] = GlobalStartSystemHash + inputOracleMutations * assertedState[0] = GlobalStartSystemHash + inputOracleMutations
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.7.3; pragma solidity ^0.7.3;
import "./lib/Lib_RLPReader.sol";
interface IMIPS { interface IMIPS {
function Step(bytes32 stateHash) external view returns (bytes32); function Step(bytes32 stateHash) external view returns (bytes32);
function ReadMemory(bytes32 stateHash, uint32 addr) external view returns (uint32);
function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) external pure returns (bytes32);
} }
contract Challenge { contract Challenge {
address payable immutable owner; address payable immutable owner;
IMIPS immutable mips; IMIPS immutable mips;
bytes32 immutable GlobalStartState;
struct Chal { struct Chal {
uint256 L; uint256 L;
...@@ -16,12 +21,12 @@ contract Challenge { ...@@ -16,12 +21,12 @@ contract Challenge {
mapping(uint256 => bytes32) defendedState; mapping(uint256 => bytes32) defendedState;
address payable challenger; address payable challenger;
} }
mapping(uint256 => Chal) challenges;
Chal[] challenges; constructor(IMIPS imips, bytes32 globalStartState) {
constructor(IMIPS imips) {
owner = msg.sender; owner = msg.sender;
mips = imips; mips = imips;
GlobalStartState = globalStartState;
} }
// allow getting money // allow getting money
...@@ -32,17 +37,86 @@ contract Challenge { ...@@ -32,17 +37,86 @@ contract Challenge {
owner.transfer(address(this).balance); owner.transfer(address(this).balance);
} }
function InitiateChallenge(uint blockNumberN, // memory helpers
bytes calldata blockHeaderN, bytes calldata blockHeaderNp1,
bytes32 assertionHash, bytes32 finalSystemHash, uint256 stepCount) external { function writeBytes32(bytes32 stateHash, uint32 addr, bytes32 val) internal view returns (bytes32) {
// is this new? for (uint32 i = 0; i < 32; i += 4) {
Chal storage c = challenges[challenges.length]; uint256 tv = uint256(val>>(224-(i*8)));
stateHash = mips.WriteMemory(stateHash, addr+i, uint32(tv));
}
return stateHash;
}
function readBytes32(bytes32 stateHash, uint32 addr) internal view returns (bytes32) {
uint256 ret = 0;
for (uint32 i = 0; i < 32; i += 4) {
ret <<= 32;
ret |= uint256(mips.ReadMemory(stateHash, addr+i));
}
return bytes32(ret);
}
// create challenge
uint256 lastChallengeId = 0;
function newChallengeTrusted(bytes32 startState, bytes32 finalSystemState, uint256 stepCount) internal returns (uint256) {
uint256 challengeId = lastChallengeId;
Chal storage c = challenges[challengeId];
lastChallengeId += 1;
// the challenger arrives
c.challenger = msg.sender; c.challenger = msg.sender;
// the state is set
c.assertedState[0] = startState;
c.defendedState[0] = startState;
c.assertedState[stepCount] = finalSystemState;
// init the binary search
c.L = 0;
c.R = stepCount;
// find me later
return challengeId;
}
// TODO: this is the function with the complexity function InitiateChallenge(uint blockNumberN,
bytes calldata blockHeaderN, bytes calldata blockHeaderNp1,
bytes32 assertionRoot, bytes32 finalSystemState, uint256 stepCount) external returns (uint256) {
require(blockhash(blockNumberN) == keccak256(blockHeaderN), "start block hash wrong");
require(blockhash(blockNumberN+1) == keccak256(blockHeaderNp1), "end block hash wrong");
// decode the blocks
Lib_RLPReader.RLPItem[] memory blockN = Lib_RLPReader.readList(blockHeaderN);
Lib_RLPReader.RLPItem[] memory blockNp1 = Lib_RLPReader.readList(blockHeaderNp1);
bytes32 newroot = Lib_RLPReader.readBytes32(blockNp1[3]);
require(assertionRoot != newroot, "asserting that the real state is correct is not a challenge");
// input oracle info
bytes32 root = Lib_RLPReader.readBytes32(blockN[3]);
bytes32 txhash = Lib_RLPReader.readBytes32(blockNp1[4]);
address coinbase = Lib_RLPReader.readAddress(blockNp1[2]);
bytes32 uncles = Lib_RLPReader.readBytes32(blockNp1[1]);
// load starting info into the input oracle
// we both agree at the beginning
bytes32 startState = GlobalStartState;
startState = writeBytes32(startState, 0xD0000000, root);
startState = writeBytes32(startState, 0xD0000020, txhash);
startState = writeBytes32(startState, 0xD0000040, bytes32(uint256(coinbase)));
startState = writeBytes32(startState, 0xD0000060, uncles);
// confirm the finalSystemHash asserts the state you claim (in $t0-$t7) and the machine is stopped
// we disagree at the end
require(readBytes32(finalSystemState, 0xC0000020) == assertionRoot, "you are claiming a different state in machine");
require(mips.ReadMemory(finalSystemState, 0xC0000080) == 0xDEAD0000, "machine is not stopped in final state (PC == 0xDEAD0000)");
return newChallengeTrusted(startState, finalSystemState, stepCount);
} }
// binary search
function getStepNumber(uint256 challengeId) view public returns (uint256) { function getStepNumber(uint256 challengeId) view public returns (uint256) {
Chal storage c = challenges[challengeId]; Chal storage c = challenges[challengeId];
return (c.L+c.R)/2; return (c.L+c.R)/2;
...@@ -62,6 +136,7 @@ contract Challenge { ...@@ -62,6 +136,7 @@ contract Challenge {
require(msg.sender == owner, "must be owner"); require(msg.sender == owner, "must be owner");
uint256 stepNumber = getStepNumber(challengeId); uint256 stepNumber = getStepNumber(challengeId);
require(c.assertedState[stepNumber] != bytes32(0), "challenger state not proposed");
require(c.defendedState[stepNumber] == bytes32(0), "state already proposed"); require(c.defendedState[stepNumber] == bytes32(0), "state already proposed");
// technically, we don't have to save these states // 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 // but if we want to prove us right and not just the attacker wrong, we do
...@@ -75,6 +150,8 @@ contract Challenge { ...@@ -75,6 +150,8 @@ contract Challenge {
} }
} }
// final payout
function ConfirmStateTransition(uint256 challengeId) external { function ConfirmStateTransition(uint256 challengeId) external {
Chal storage c = challenges[challengeId]; Chal storage c = challenges[challengeId];
require(c.challenger == msg.sender, "must be challenger"); require(c.challenger == msg.sender, "must be challenger");
......
...@@ -24,10 +24,15 @@ contract MIPS { ...@@ -24,10 +24,15 @@ contract MIPS {
state[stateHash][addr] = (1 << 32) | value; state[stateHash][addr] = (1 << 32) | value;
} }
uint32 constant REG_OFFSET = 0xc0000000; uint32 constant public REG_OFFSET = 0xc0000000;
uint32 constant REG_PC = REG_OFFSET + 21*4; uint32 constant public REG_PC = REG_OFFSET + 0x20*4;
function getState(bytes32 stateHash, uint32 addr) public view returns (uint32) { function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) public pure returns (bytes32) {
// TODO: does the stateHash mutation
}
function ReadMemory(bytes32 stateHash, uint32 addr) public view returns (uint32) {
if (addr == REG_OFFSET) { if (addr == REG_OFFSET) {
// zero register is always 0 // zero register is always 0
return 0; return 0;
...@@ -38,13 +43,12 @@ contract MIPS { ...@@ -38,13 +43,12 @@ contract MIPS {
return uint32(ret); return uint32(ret);
} }
// 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 (bytes32) { function Step(bytes32 stateHash) public view returns (bytes32) {
// instruction fetch // instruction fetch
uint32 pc = getState(stateHash, REG_PC); uint32 pc = ReadMemory(stateHash, REG_PC);
uint32 insn = getState(stateHash, pc); uint32 insn = ReadMemory(stateHash, pc);
uint32 opcode = insn >> 26; // 6-bits uint32 opcode = insn >> 26; // 6-bits
// decode // decode
...@@ -54,10 +58,10 @@ contract MIPS { ...@@ -54,10 +58,10 @@ contract MIPS {
uint32 rt; uint32 rt;
if (opcode != 2 && opcode != 3) { // j and jal have no register fetch if (opcode != 2 && opcode != 3) { // j and jal have no register fetch
// R-type or I-type (stores rt) // R-type or I-type (stores rt)
rs = getState(stateHash, REG_OFFSET + ((insn >> 19) & 0x7C)); rs = ReadMemory(stateHash, REG_OFFSET + ((insn >> 19) & 0x7C));
if (opcode == 0) { if (opcode == 0) {
// R-type (stores rd) // R-type (stores rd)
rt = getState(stateHash, REG_OFFSET + ((insn >> 14) & 0x7C)); rt = ReadMemory(stateHash, REG_OFFSET + ((insn >> 14) & 0x7C));
} }
} }
...@@ -67,7 +71,7 @@ contract MIPS { ...@@ -67,7 +71,7 @@ contract MIPS {
if (opcode >= 0x20) { if (opcode >= 0x20) {
// M[R[rs]+SignExtImm] // M[R[rs]+SignExtImm]
uint32 SignExtImm = insn&0xFFFF | (insn&0x8000 != 0 ? 0xFFFF0000 : 0); uint32 SignExtImm = insn&0xFFFF | (insn&0x8000 != 0 ? 0xFFFF0000 : 0);
mem = getState(stateHash, (rs + SignExtImm) & 0xFFFFFFFC); mem = ReadMemory(stateHash, (rs + SignExtImm) & 0xFFFFFFFC);
} }
// execute // execute
......
This diff is collapsed.
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