Skip to content

Commit

Permalink
[ci skip] remove codeContractAddress from Enforcer, Verifier, basic i…
Browse files Browse the repository at this point in the history
…mpl for EVMCode
  • Loading branch information
peara committed Jun 16, 2019
1 parent 1ff9290 commit cc5c4dd
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 64 deletions.
116 changes: 75 additions & 41 deletions contracts/EVMCode.slb
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,102 @@ pragma experimental ABIEncoderV2;


library EVMCode {

struct Code {
address codeAddress;
bytes codeBytes;
uint length;
uint length; // length is zero-based
mapping (uint => bytes32) fragments;
mapping (uint => bool) known;
}

function fromAddress(address codeAddress) internal view returns (Code memory code) {
code.codeAddress = codeAddress;
uint codeSize;
assembly {
codeSize := extcodesize(codeAddress)
}

code.length = codeSize;
struct RawCode {
uint pos;
bytes32 value;
}

function fromBytes(bytes memory codeBytes) internal pure returns (Code memory code) {
code.codeBytes = codeBytes;
code.length = codeBytes.length;
// TODO no more external address
// function fromAddress(address codeAddress) internal view returns (Code memory code) {
// code.codeAddress = codeAddress;
// uint codeSize;
// assembly {
// codeSize := extcodesize(codeAddress)
// }

// code.length = codeSize;
// }

function fromArray(RawCode[] memory codes, uint length) internal pure return (Code memory code) {
code.length = length;
for (uint i = 0; i < codes.length; i++) {
code.fragments[codes[i].pos] = codes[i].value;
code.known[codes[i].pos] = true;
}
}

/**
* @dev return the opcode at position if known. Otherwise return fe, which is invalid opcode
*
* @params uint pos: position of the required byte, from 0 to 31
*/
function getOpcodeAt(Code memory self, uint pos) internal view returns (uint8 opcode) {
address codeContractAddress = self.codeAddress;
uint fragmentPos = pos >> 5;

if (codeContractAddress == address(0)) {
opcode = uint8(self.codeBytes[pos]);
} else {
assembly {
extcodecopy(codeContractAddress, 31, pos, 1)
opcode := mload(0)
}
if (code.known[pos]) {
// 0x00000000 11111111 22222222 ... (256 bit)
// to get a byte at position x, we need to shift all these byte at position > x + 8
// x = 0 -> shift 248 = (32 - 1) * 8
// x = 1 -> shift 242 = (32 - 2) * 8
// x = 31 -> shift 0 = (32 - 32) * 8
return uint8(code.fragments[fragmentPos] >> ((31 - pos % 32) * 8));
}
return 0xfe;
}

function toBytes(Code memory self) internal view returns (bytes memory bts) {
address codeContractAddress = self.codeAddress;
// TODO no more code address
// address codeContractAddress = self.codeAddress;

if (codeContractAddress == address(0)) {
bts = self.codeBytes;
} else {
uint size = self.length;
assembly {
bts := mload(0x40)
// padding up to word size
mstore(0x40, add(bts, and(add(add(size, 0x20), 0x1f), not(0x1f))))
mstore(bts, size)
extcodecopy(codeContractAddress, add(bts, 0x20), 0, size)
}
}
// if (codeContractAddress == address(0)) {
// bts = self.codeBytes;
// } else {
// uint size = self.length;
// assembly {
// bts := mload(0x40)
// // padding up to word size
// mstore(0x40, add(bts, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// mstore(bts, size)
// extcodecopy(codeContractAddress, add(bts, 0x20), 0, size)
// }
// }
}

function toUint(Code memory self, uint pos, uint numBytes) internal view returns (uint data) {
// if pos + numBytes > self.length, we get zeroes.
// this is the behaviour we want
assert(32 >= numBytes && numBytes > 0);

address codeContractAddress = self.codeAddress;
assembly {
extcodecopy(codeContractAddress, 0, pos, numBytes)
data := mload(0)
// TODO no more code address
// 2 cases:
// - return data fit in a fragment
// - return data span 2 fragments
uint fragmentPos = pos >> 5;
// only need to retrieve 32 bytes
if (fragmentPos == ((pos + numBytes) >> 5)) {
// retrieve the word which contains the required data
// shift left to strip unnecessary data on the left
uint temp = code.fragments[fragmentPos] << ((pos % 32) * 8);
// then shift right to strip unnecessary data on the right
return temp >> ((32 - numBytes) * 8));
}
data = data >> 8 * (32 - numBytes);

// require fetching an additional 32 bytes
// the left part should be the rightmost part of the first word
// to retrieve: shift left to strip, then shift back to correct position in numBytes
uint left = (code.fragments[fragmentsPos] << ((pos % 32) * 8)) >> ((32 - numBytes) * 8);
// the right part should be the leftmost part of the second word
// to retrieve: shift all the way to the right
// 64 - numBytes - (pos % 32) = 32 - (numBytes - (32 - (pos % 32))) = word_length - (required_length - (left_path_length))
// numBytes + (pos % 32) >= 32, if not, then it requires only 1 byte
uint right = (code.fragments[fragmentsPos + 1] >> (64 - numBytes - (pos % 32)) * 8);

return left | right;
}
}
1 change: 1 addition & 0 deletions contracts/EVMRuntime.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,7 @@ contract EVMRuntime is EVMConstants {

state.gas -= gasFee;

// TODO no more all codes available
state.mem.storeBytes(state.code.toBytes(), cAddr, mAddr, len);
}

Expand Down
14 changes: 7 additions & 7 deletions contracts/Enforcer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ contract Enforcer {
_;
}

event Registered(bytes32 indexed executionId, address indexed solver, address codeContractAddress, bytes _callData);
event Registered(bytes32 indexed executionId, address indexed solver, bytes32 codeHashRoot, bytes _callData);
event DisputeInitialised(bytes32 indexed disputeId, bytes32 indexed executionId);
event Slashed(bytes32 indexed executionId, address indexed _address);

Expand All @@ -43,7 +43,7 @@ contract Enforcer {

// register a new execution
function register(
address codeContractAddress,
bytes32 codeHashRoot,
bytes memory _callData,
bytes32 endHash,
uint256 executionDepth,
Expand All @@ -55,7 +55,7 @@ contract Enforcer {
require(msg.value == bondAmount, "Bond is required");
require(executionDepth <= maxExecutionDepth, "Execution too long");

bytes32 executionId = keccak256(abi.encodePacked(codeContractAddress, _callData));
bytes32 executionId = keccak256(abi.encodePacked(codeHashRoot, _callData));

require(executions[executionId].startBlock == 0, "Execution already registered");
executions[executionId] = Execution(
Expand All @@ -67,7 +67,7 @@ contract Enforcer {
);
bonds[msg.sender] += bondAmount;

emit Registered(executionId, msg.sender, codeContractAddress, _callData);
emit Registered(executionId, msg.sender, codeHashRoot, _callData);
}

/**
Expand All @@ -76,10 +76,10 @@ contract Enforcer {
* in case challenger's tree is shallower, he should use node with zero hash to make it deeper
* in case challenger's tree is deeper, he should submit only the left subtree with the same depth with solver's
*/
function dispute(address codeContractAddress, bytes memory _callData, bytes32 endHash)
function dispute(bytes32 codeHashRoot, bytes memory _callData, bytes32 endHash)
public payable
{
bytes32 executionId = keccak256(abi.encodePacked(codeContractAddress, _callData));
bytes32 executionId = keccak256(abi.encodePacked(codeHashRoot, _callData));

Execution storage execution = executions[executionId];

Expand All @@ -101,7 +101,7 @@ contract Enforcer {
execution.customEnvironmentHash,
// challenger
msg.sender,
codeContractAddress,
codeHashRoot,
_callData
);

Expand Down
34 changes: 18 additions & 16 deletions contracts/Verifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ contract Verifier is Ownable, HydratedRuntime {
struct Dispute {
bytes32 executionId;
bytes32 initialStateHash;
address codeContractAddress;
bytes32 codeHashRoot;
address challengerAddr;

bytes32 solverPath;
Expand Down Expand Up @@ -96,7 +96,7 @@ contract Verifier is Ownable, HydratedRuntime {
// optional for implementors
bytes32 customEnvironmentHash,
address challenger,
address codeContractAddress,
bytes32 codeHashRoot,
// TODO: should be the bytes32 root hash later on
bytes memory callData
) public onlyEnforcer() returns (bytes32 disputeId) {
Expand All @@ -119,7 +119,7 @@ contract Verifier is Ownable, HydratedRuntime {
disputes[disputeId] = Dispute(
executionId,
initialStateHash,
codeContractAddress,
codeHashRoot,
challenger,
solverHashRoot,
challengerHashRoot,
Expand Down Expand Up @@ -219,20 +219,21 @@ contract Verifier is Ownable, HydratedRuntime {
}
}

if ((dispute.state & END_OF_EXECUTION) != 0) {
address codeAddress = dispute.codeContractAddress;
uint pos = executionState.pc;
uint8 opcode;
// TODO no more extcodecopy
// if ((dispute.state & END_OF_EXECUTION) != 0) {
// address codeAddress = dispute.codeContractAddress;
// uint pos = executionState.pc;
// uint8 opcode;

assembly {
extcodecopy(codeAddress, 31, pos, 1)
opcode := mload(0)
}
// assembly {
// extcodecopy(codeAddress, 31, pos, 1)
// opcode := mload(0)
// }

if (opcode != OP_REVERT && opcode != OP_RETURN && opcode != OP_STOP) {
return;
}
}
// if (opcode != OP_REVERT && opcode != OP_RETURN && opcode != OP_STOP) {
// return;
// }
// }

EVM memory evm;
HydratedState memory hydratedState = initHydratedState(evm);
Expand All @@ -252,7 +253,8 @@ contract Verifier is Ownable, HydratedRuntime {

evm.data = executionState.data;
evm.gas = executionState.gasRemaining;
evm.code = EVMCode.fromAddress(dispute.codeContractAddress);
// TODO no more fromAddress
// evm.code = EVMCode.fromAddress(dispute.codeContractAddress);
evm.caller = DEFAULT_CALLER;
evm.target = DEFAULT_CONTRACT_ADDRESS;
evm.stack = EVMStack.fromArray(executionState.stack);
Expand Down

0 comments on commit cc5c4dd

Please sign in to comment.