From cc5c4dd6d4a15211e1430261255203fc082181e8 Mon Sep 17 00:00:00 2001 From: Vu Ngoc Quang Date: Mon, 17 Jun 2019 00:05:49 +0700 Subject: [PATCH] [ci skip] remove codeContractAddress from Enforcer, Verifier, basic impl for EVMCode --- contracts/EVMCode.slb | 116 +++++++++++++++++++++++++-------------- contracts/EVMRuntime.sol | 1 + contracts/Enforcer.sol | 14 ++--- contracts/Verifier.sol | 34 ++++++------ 4 files changed, 101 insertions(+), 64 deletions(-) diff --git a/contracts/EVMCode.slb b/contracts/EVMCode.slb index 55b519b5..44644cb3 100644 --- a/contracts/EVMCode.slb +++ b/contracts/EVMCode.slb @@ -3,56 +3,71 @@ 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) { @@ -60,11 +75,30 @@ library EVMCode { // 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; } } diff --git a/contracts/EVMRuntime.sol b/contracts/EVMRuntime.sol index 8d4effee..86d810e5 100644 --- a/contracts/EVMRuntime.sol +++ b/contracts/EVMRuntime.sol @@ -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); } diff --git a/contracts/Enforcer.sol b/contracts/Enforcer.sol index ff80d89a..a96d1be3 100644 --- a/contracts/Enforcer.sol +++ b/contracts/Enforcer.sol @@ -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); @@ -43,7 +43,7 @@ contract Enforcer { // register a new execution function register( - address codeContractAddress, + bytes32 codeHashRoot, bytes memory _callData, bytes32 endHash, uint256 executionDepth, @@ -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( @@ -67,7 +67,7 @@ contract Enforcer { ); bonds[msg.sender] += bondAmount; - emit Registered(executionId, msg.sender, codeContractAddress, _callData); + emit Registered(executionId, msg.sender, codeHashRoot, _callData); } /** @@ -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]; @@ -101,7 +101,7 @@ contract Enforcer { execution.customEnvironmentHash, // challenger msg.sender, - codeContractAddress, + codeHashRoot, _callData ); diff --git a/contracts/Verifier.sol b/contracts/Verifier.sol index d5d26e39..7bf2d3e4 100644 --- a/contracts/Verifier.sol +++ b/contracts/Verifier.sol @@ -35,7 +35,7 @@ contract Verifier is Ownable, HydratedRuntime { struct Dispute { bytes32 executionId; bytes32 initialStateHash; - address codeContractAddress; + bytes32 codeHashRoot; address challengerAddr; bytes32 solverPath; @@ -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) { @@ -119,7 +119,7 @@ contract Verifier is Ownable, HydratedRuntime { disputes[disputeId] = Dispute( executionId, initialStateHash, - codeContractAddress, + codeHashRoot, challenger, solverHashRoot, challengerHashRoot, @@ -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); @@ -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);