diff --git a/lib/preprocessor.js b/lib/preprocessor.js
index 9624f3ca..6ab90ae6 100644
--- a/lib/preprocessor.js
+++ b/lib/preprocessor.js
@@ -2,14 +2,17 @@ const SolExplore = require('sol-explore');
const SolidityParser = require('solidity-parser-antlr');
const crRegex = /[\r\n ]+$/g;
+const OPEN = '{';
+const CLOSE = '}';
+
/**
* Splices enclosing brackets into `contract` around `expression`;
* @param {String} contract solidity source
* @param {Object} node AST node to bracket
* @return {String} contract
*/
-function blockWrap(contract, expression) {
- return contract.slice(0, expression.range[0]) + '{' + contract.slice(expression.range[0], expression.range[1] + 1) + '}' + contract.slice(expression.range[1] + 1);
+function insertBrace(contract, item, offset) {
+ return contract.slice(0,item.pos + offset) + item.type + contract.slice(item.pos + offset)
}
/** Remove 'pure' and 'view' from the function declaration.
@@ -47,24 +50,28 @@ module.exports.run = function r(contract) {
try {
const ast = SolidityParser.parse(contract, { range: true });
- blocksToWrap = [];
+ insertions = [];
viewPureToRemove = [];
SolidityParser.visit(ast, {
IfStatement: function(node) {
if (node.trueBody.type !== 'Block') {
- blocksToWrap.push(node.trueBody);
- } else if (node.falseBody && node.falseBody.type !== 'Block'){
- blocksToWrap.push(node.falseBody);
+ insertions.push({type: OPEN, pos: node.trueBody.range[0]});
+ insertions.push({type: CLOSE, pos: node.trueBody.range[1] + 1});
+ } else if ( node.falseBody && node.falseBody.type !== 'Block' ) {
+ insertions.push({type: OPEN, pos: node.falseBody.range[0]});
+ insertions.push({type: CLOSE, pos: node.falseBody.range[1] + 1});
}
},
ForStatement: function(node){
if (node.body.type !== 'Block'){
- blocksToWrap.push(node.body);
+ insertions.push({type: OPEN, pos: node.body.range[0]});
+ insertions.push({type: CLOSE, pos: node.body.range[1] + 1});
}
},
WhileStatement: function(node){
if (node.body.type !== 'Block'){
- blocksToWrap.push(node.body);
+ insertions.push({type: OPEN, pos: node.body.range[0]});
+ insertions.push({type: CLOSE, pos: node.body.range[1] + 1});
}
},
FunctionDefinition: function(node){
@@ -73,12 +80,13 @@ module.exports.run = function r(contract) {
}
}
})
- // Firstly, remove pures and views. Note that we replace 'pure' and 'view' with spaces, so
+ // Firstly, remove pures and views. Note that we replace 'pure' and 'view' with spaces, so
// character counts remain the same, so we can do this in any order
viewPureToRemove.forEach(node => contract = removePureView(contract, node));
- // We apply the blocks we found in reverse order to avoid extra characters messing things up.
- blocksToWrap.sort((a,b) => a.range[0] < b.range[0]);
- blocksToWrap.forEach(block => contract = blockWrap(contract, block))
+ // Sort the insertion points.
+ insertions.sort((a,b) => a.pos - b.pos);
+ insertions.forEach((item, idx) => contract = insertBrace(contract, item, idx));
+
} catch (err) {
contract = err;
keepRunning = false;
diff --git a/test/app.js b/test/app.js
index 8b56a42b..0dc3cf17 100644
--- a/test/app.js
+++ b/test/app.js
@@ -28,7 +28,7 @@ describe('app', () => {
};
before(done => {
- const command = `./node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port ${port}`;
+ const command = `./node_modules/.bin/testrpc-sc --allowUnlimitedContractSize --gasLimit 0xfffffffffff --port ${port}`;
testrpcProcess = childprocess.exec(command);
testrpcProcess.stdout.on('data', data => {
@@ -194,6 +194,36 @@ describe('app', () => {
}
});
+ it('large contract w/ many unbracketed statements (Oraclize)', () => {
+ const trufflejs =
+ `module.exports = {
+ networks: {
+ coverage: {
+ host: "localhost",
+ network_id: "*",
+ port: 8555,
+ gas: 0xfffffffffff,
+ gasPrice: 0x01
+ },
+ },
+ compilers: {
+ solc: {
+ version: "0.4.24",
+ }
+ }
+ };`;
+
+ // Directory should be clean
+ assert(pathExists('./coverage') === false, 'should start without: coverage');
+ assert(pathExists('./coverage.json') === false, 'should start without: coverage.json');
+
+ // Run script (exits 0);
+ mock.install('Oraclize.sol', 'oraclize.js', config, trufflejs, null, true);
+ shell.exec(script);
+ assert(shell.error() === null, 'script should not error');
+
+ });
+
it('simple contract: should generate coverage, cleanup & exit(0)', () => {
// Directory should be clean
assert(pathExists('./coverage') === false, 'should start without: coverage');
diff --git a/test/cli/oraclize.js b/test/cli/oraclize.js
new file mode 100644
index 00000000..994d5e9c
--- /dev/null
+++ b/test/cli/oraclize.js
@@ -0,0 +1,10 @@
+/* eslint-env node, mocha */
+/* global artifacts, contract, assert */
+const usingOraclize = artifacts.require('usingOraclize');
+
+contract('Nothing', () => {
+ it('nothing', async () => {
+ const ora = await usingOraclize.new();
+ await ora.test();
+ });
+});
\ No newline at end of file
diff --git a/test/if.js b/test/if.js
index 60cb49b1..cd989d6a 100644
--- a/test/if.js
+++ b/test/if.js
@@ -186,6 +186,30 @@ describe('if, else, and else if statements', () => {
}).catch(done);
});
+ it('should cover an else if statement with an unbracketed alternate', done => {
+ const contract = util.getCode('if/else-if-without-brackets.sol');
+ const info = getInstrumentedVersion(contract, filePath);
+ const coverage = new CoverageMap();
+ coverage.addContract(info, filePath);
+
+ vm.execute(info.contract, 'a', [2]).then(events => {
+ const mapping = coverage.generate(events, pathPrefix);
+ assert.deepEqual(mapping[filePath].l, {
+ 5: 1, 6: 0, 8: 0,
+ });
+ assert.deepEqual(mapping[filePath].b, {
+ 1: [0, 1], 2: [0, 1]
+ });
+ assert.deepEqual(mapping[filePath].s, {
+ 1: 1, 2: 0, 3: 1, 4: 0
+ });
+ assert.deepEqual(mapping[filePath].f, {
+ 1: 1,
+ });
+ done();
+ }).catch(done);
+ });
+
it('should cover nested if statements with missing else statements', done => {
const contract = util.getCode('if/nested-if-missing-else.sol');
const info = getInstrumentedVersion(contract, filePath);
diff --git a/test/sources/cli/Oraclize.sol b/test/sources/cli/Oraclize.sol
new file mode 100644
index 00000000..de77e3ff
--- /dev/null
+++ b/test/sources/cli/Oraclize.sol
@@ -0,0 +1,1097 @@
+//
+/*
+Copyright (c) 2015-2016 Oraclize SRL
+Copyright (c) 2016 Oraclize LTD
+
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+// This api is currently targeted at 0.4.18, please import oraclizeAPI_pre0.4.sol or oraclizeAPI_0.4 where necessary
+pragma solidity ^0.4.24;
+
+contract OraclizeI {
+ address public cbAddress;
+ function query(uint _timestamp, string _datasource, string _arg) external payable returns (bytes32 _id);
+ function query_withGasLimit(uint _timestamp, string _datasource, string _arg, uint _gaslimit) external payable returns (bytes32 _id);
+ function query2(uint _timestamp, string _datasource, string _arg1, string _arg2) public payable returns (bytes32 _id);
+ function query2_withGasLimit(uint _timestamp, string _datasource, string _arg1, string _arg2, uint _gaslimit) external payable returns (bytes32 _id);
+ function queryN(uint _timestamp, string _datasource, bytes _argN) public payable returns (bytes32 _id);
+ function queryN_withGasLimit(uint _timestamp, string _datasource, bytes _argN, uint _gaslimit) external payable returns (bytes32 _id);
+ function getPrice(string _datasource) public returns (uint _dsprice);
+ function getPrice(string _datasource, uint gaslimit) public returns (uint _dsprice);
+ function setProofType(byte _proofType) external;
+ function setCustomGasPrice(uint _gasPrice) external;
+ function randomDS_getSessionPubKeyHash() external view returns(bytes32);
+}
+contract OraclizeAddrResolverI {
+ function getAddress() public returns (address _addr);
+}
+contract usingOraclize {
+ uint constant day = 60*60*24;
+ uint constant week = 60*60*24*7;
+ uint constant month = 60*60*24*30;
+ byte constant proofType_NONE = 0x00;
+ byte constant proofType_TLSNotary = 0x10;
+ byte constant proofType_Android = 0x20;
+ byte constant proofType_Ledger = 0x30;
+ byte constant proofType_Native = 0xF0;
+ byte constant proofStorage_IPFS = 0x01;
+ uint8 constant networkID_auto = 0;
+ uint8 constant networkID_mainnet = 1;
+ uint8 constant networkID_testnet = 2;
+ uint8 constant networkID_morden = 2;
+ uint8 constant networkID_consensys = 161;
+
+ OraclizeAddrResolverI OAR;
+
+ OraclizeI oraclize;
+ modifier oraclizeAPI {
+ if((address(OAR)==0)||(getCodeSize(address(OAR))==0))
+ oraclize_setNetwork(networkID_auto);
+
+ if(address(oraclize) != OAR.getAddress())
+ oraclize = OraclizeI(OAR.getAddress());
+
+ _;
+ }
+ modifier coupon(string code){
+ oraclize = OraclizeI(OAR.getAddress());
+ _;
+ }
+
+ function oraclize_setNetwork(uint8 networkID) internal returns(bool){
+ return oraclize_setNetwork();
+ networkID; // silence the warning and remain backwards compatible
+ }
+ function oraclize_setNetwork() internal returns(bool){
+ if (getCodeSize(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed)>0){ //mainnet
+ OAR = OraclizeAddrResolverI(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed);
+ oraclize_setNetworkName("eth_mainnet");
+ return true;
+ }
+ if (getCodeSize(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1)>0){ //ropsten testnet
+ OAR = OraclizeAddrResolverI(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1);
+ oraclize_setNetworkName("eth_ropsten3");
+ return true;
+ }
+ if (getCodeSize(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e)>0){ //kovan testnet
+ OAR = OraclizeAddrResolverI(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e);
+ oraclize_setNetworkName("eth_kovan");
+ return true;
+ }
+ if (getCodeSize(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48)>0){ //rinkeby testnet
+ OAR = OraclizeAddrResolverI(0x146500cfd35B22E4A392Fe0aDc06De1a1368Ed48);
+ oraclize_setNetworkName("eth_rinkeby");
+ return true;
+ }
+ if (getCodeSize(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475)>0){ //ethereum-bridge
+ OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475);
+ return true;
+ }
+ if (getCodeSize(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF)>0){ //ether.camp ide
+ OAR = OraclizeAddrResolverI(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF);
+ return true;
+ }
+ if (getCodeSize(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA)>0){ //browser-solidity
+ OAR = OraclizeAddrResolverI(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA);
+ return true;
+ }
+ return false;
+ }
+
+ function __callback(bytes32 myid, string result) public {
+ __callback(myid, result, new bytes(0));
+ }
+ function __callback(bytes32 myid, string result, bytes proof) public {
+ return;
+ myid; result; proof; // Silence compiler warnings
+ }
+
+ function oraclize_getPrice(string datasource) oraclizeAPI internal returns (uint){
+ return oraclize.getPrice(datasource);
+ }
+
+ function oraclize_getPrice(string datasource, uint gaslimit) oraclizeAPI internal returns (uint){
+ return oraclize.getPrice(datasource, gaslimit);
+ }
+
+ function oraclize_query(string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource);
+ if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
+ return oraclize.query.value(price)(0, datasource, arg);
+ }
+ function oraclize_query(uint timestamp, string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource);
+ if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
+ return oraclize.query.value(price)(timestamp, datasource, arg);
+ }
+ function oraclize_query(uint timestamp, string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource, gaslimit);
+ if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
+ return oraclize.query_withGasLimit.value(price)(timestamp, datasource, arg, gaslimit);
+ }
+ function oraclize_query(string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource, gaslimit);
+ if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
+ return oraclize.query_withGasLimit.value(price)(0, datasource, arg, gaslimit);
+ }
+ function oraclize_query(string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource);
+ if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
+ return oraclize.query2.value(price)(0, datasource, arg1, arg2);
+ }
+ function oraclize_query(uint timestamp, string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource);
+ if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
+ return oraclize.query2.value(price)(timestamp, datasource, arg1, arg2);
+ }
+ function oraclize_query(uint timestamp, string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource, gaslimit);
+ if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
+ return oraclize.query2_withGasLimit.value(price)(timestamp, datasource, arg1, arg2, gaslimit);
+ }
+ function oraclize_query(string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource, gaslimit);
+ if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
+ return oraclize.query2_withGasLimit.value(price)(0, datasource, arg1, arg2, gaslimit);
+ }
+ function oraclize_query(string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource);
+ if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
+ bytes memory args = stra2cbor(argN);
+ return oraclize.queryN.value(price)(0, datasource, args);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource);
+ if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
+ bytes memory args = stra2cbor(argN);
+ return oraclize.queryN.value(price)(timestamp, datasource, args);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource, gaslimit);
+ if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
+ bytes memory args = stra2cbor(argN);
+ return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
+ }
+ function oraclize_query(string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource, gaslimit);
+ if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
+ bytes memory args = stra2cbor(argN);
+ return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
+ }
+ function oraclize_query(string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](1);
+ dynargs[0] = args[0];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](1);
+ dynargs[0] = args[0];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](1);
+ dynargs[0] = args[0];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](1);
+ dynargs[0] = args[0];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+
+ function oraclize_query(string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](2);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](2);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](2);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](2);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](3);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](3);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](3);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](3);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+
+ function oraclize_query(string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](4);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](4);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](4);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](4);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](5);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ dynargs[4] = args[4];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](5);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ dynargs[4] = args[4];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](5);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ dynargs[4] = args[4];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ string[] memory dynargs = new string[](5);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ dynargs[4] = args[4];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[] argN) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource);
+ if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
+ bytes memory args = ba2cbor(argN);
+ return oraclize.queryN.value(price)(0, datasource, args);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[] argN) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource);
+ if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
+ bytes memory args = ba2cbor(argN);
+ return oraclize.queryN.value(price)(timestamp, datasource, args);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource, gaslimit);
+ if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
+ bytes memory args = ba2cbor(argN);
+ return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
+ uint price = oraclize.getPrice(datasource, gaslimit);
+ if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
+ bytes memory args = ba2cbor(argN);
+ return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[1] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](1);
+ dynargs[0] = args[0];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[1] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](1);
+ dynargs[0] = args[0];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](1);
+ dynargs[0] = args[0];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](1);
+ dynargs[0] = args[0];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+
+ function oraclize_query(string datasource, bytes[2] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](2);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[2] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](2);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](2);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](2);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[3] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](3);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[3] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](3);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](3);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](3);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+
+ function oraclize_query(string datasource, bytes[4] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](4);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[4] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](4);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](4);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](4);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[5] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](5);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ dynargs[4] = args[4];
+ return oraclize_query(datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[5] args) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](5);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ dynargs[4] = args[4];
+ return oraclize_query(timestamp, datasource, dynargs);
+ }
+ function oraclize_query(uint timestamp, string datasource, bytes[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](5);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ dynargs[4] = args[4];
+ return oraclize_query(timestamp, datasource, dynargs, gaslimit);
+ }
+ function oraclize_query(string datasource, bytes[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
+ bytes[] memory dynargs = new bytes[](5);
+ dynargs[0] = args[0];
+ dynargs[1] = args[1];
+ dynargs[2] = args[2];
+ dynargs[3] = args[3];
+ dynargs[4] = args[4];
+ return oraclize_query(datasource, dynargs, gaslimit);
+ }
+
+ function oraclize_cbAddress() oraclizeAPI internal returns (address){
+ return oraclize.cbAddress();
+ }
+ function oraclize_setProof(byte proofP) oraclizeAPI internal {
+ return oraclize.setProofType(proofP);
+ }
+ function oraclize_setCustomGasPrice(uint gasPrice) oraclizeAPI internal {
+ return oraclize.setCustomGasPrice(gasPrice);
+ }
+
+ function oraclize_randomDS_getSessionPubKeyHash() oraclizeAPI internal returns (bytes32){
+ return oraclize.randomDS_getSessionPubKeyHash();
+ }
+
+ function getCodeSize(address _addr) view internal returns(uint _size) {
+ assembly {
+ _size := extcodesize(_addr)
+ }
+ }
+
+ function parseAddr(string _a) internal pure returns (address){
+ bytes memory tmp = bytes(_a);
+ uint160 iaddr = 0;
+ uint160 b1;
+ uint160 b2;
+ for (uint i=2; i<2+2*20; i+=2){
+ iaddr *= 256;
+ b1 = uint160(tmp[i]);
+ b2 = uint160(tmp[i+1]);
+ if ((b1 >= 97)&&(b1 <= 102)) b1 -= 87;
+ else if ((b1 >= 65)&&(b1 <= 70)) b1 -= 55;
+ else if ((b1 >= 48)&&(b1 <= 57)) b1 -= 48;
+ if ((b2 >= 97)&&(b2 <= 102)) b2 -= 87;
+ else if ((b2 >= 65)&&(b2 <= 70)) b2 -= 55;
+ else if ((b2 >= 48)&&(b2 <= 57)) b2 -= 48;
+ iaddr += (b1*16+b2);
+ }
+ return address(iaddr);
+ }
+
+ /*function strCompare(string _a, string _b) internal pure returns (int) {
+ bytes memory a = bytes(_a);
+ bytes memory b = bytes(_b);
+ uint minLength = a.length;
+ if (b.length < minLength) minLength = b.length;
+ for (uint i = 0; i < minLength; i ++)
+ if (a[i] < b[i])
+ return -1;
+ else if (a[i] > b[i])
+ return 1;
+ if (a.length < b.length)
+ return -1;
+ else if (a.length > b.length)
+ return 1;
+ else
+ return 0;
+ }*/
+
+ function indexOf(string _haystack, string _needle) internal pure returns (int) {
+ bytes memory h = bytes(_haystack);
+ bytes memory n = bytes(_needle);
+ if(h.length < 1 || n.length < 1 || (n.length > h.length))
+ return -1;
+ else if(h.length > (2**128 -1))
+ return -1;
+ else
+ {
+ uint subindex = 0;
+ for (uint i = 0; i < h.length; i ++)
+ {
+ if (h[i] == n[0])
+ {
+ subindex = 1;
+ while(subindex < n.length && (i + subindex) < h.length && h[i + subindex] == n[subindex])
+ {
+ subindex++;
+ }
+ if(subindex == n.length)
+ return int(i);
+ }
+ }
+ return -1;
+ }
+ }
+
+ function strConcat(string _a, string _b, string _c, string _d, string _e) internal pure returns (string) {
+ bytes memory _ba = bytes(_a);
+ bytes memory _bb = bytes(_b);
+ bytes memory _bc = bytes(_c);
+ bytes memory _bd = bytes(_d);
+ bytes memory _be = bytes(_e);
+ string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
+ bytes memory babcde = bytes(abcde);
+ uint k = 0;
+ for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
+ for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
+ for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
+ for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
+ for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
+ return string(babcde);
+ }
+
+ function strConcat(string _a, string _b, string _c, string _d) internal pure returns (string) {
+ return strConcat(_a, _b, _c, _d, "");
+ }
+
+ function strConcat(string _a, string _b, string _c) internal pure returns (string) {
+ return strConcat(_a, _b, _c, "", "");
+ }
+
+ function strConcat(string _a, string _b) internal pure returns (string) {
+ return strConcat(_a, _b, "", "", "");
+ }
+
+ // parseInt
+ function parseInt(string _a) internal pure returns (uint) {
+ return parseInt(_a, 0);
+ }
+
+ // parseInt(parseFloat*10^_b)
+ function parseInt(string _a, uint _b) internal pure returns (uint) {
+ bytes memory bresult = bytes(_a);
+ uint mint = 0;
+ bool decimals = false;
+ for (uint i=0; i= 48)&&(bresult[i] <= 57)){
+ if (decimals){
+ if (_b == 0) {
+ break;
+ } else _b--;
+ }
+ mint *= 10;
+ mint += uint(bresult[i]) - 48;
+ } else if (bresult[i] == 46) decimals = true;
+ }
+ if (_b > 0) mint *= 10**_b;
+ return mint;
+ }
+
+ function uint2str(uint i) internal pure returns (string){
+ if (i == 0) return "0";
+ uint j = i;
+ uint len;
+ while (j != 0){
+ len++;
+ j /= 10;
+ }
+ bytes memory bstr = new bytes(len);
+ uint k = len - 1;
+ while (i != 0){
+ bstr[k--] = byte(48 + i % 10);
+ i /= 10;
+ }
+ return string(bstr);
+ }
+
+ function stra2cbor(string[] arr) internal pure returns (bytes) {
+ uint arrlen = arr.length;
+
+ // get correct cbor output length
+ uint outputlen = 0;
+ bytes[] memory elemArray = new bytes[](arrlen);
+ for (uint i = 0; i < arrlen; i++) {
+ elemArray[i] = (bytes(arr[i]));
+ outputlen += elemArray[i].length + (elemArray[i].length - 1)/23 + 3; //+3 accounts for paired identifier types
+ }
+ uint ctr = 0;
+ uint cborlen = arrlen + 0x80;
+ outputlen += byte(cborlen).length;
+ bytes memory res = new bytes(outputlen);
+
+ while (byte(cborlen).length > ctr) {
+ res[ctr] = byte(cborlen)[ctr];
+ ctr++;
+ }
+ for (i = 0; i < arrlen; i++) {
+ res[ctr] = 0x5F;
+ ctr++;
+ for (uint x = 0; x < elemArray[i].length; x++) {
+ // if there's a bug with larger strings, this may be the culprit
+ if (x % 23 == 0) {
+ uint elemcborlen = elemArray[i].length - x >= 24 ? 23 : elemArray[i].length - x;
+ elemcborlen += 0x40;
+ uint lctr = ctr;
+ while (byte(elemcborlen).length > ctr - lctr) {
+ res[ctr] = byte(elemcborlen)[ctr - lctr];
+ ctr++;
+ }
+ }
+ res[ctr] = elemArray[i][x];
+ ctr++;
+ }
+ res[ctr] = 0xFF;
+ ctr++;
+ }
+ return res;
+ }
+
+ function ba2cbor(bytes[] arr) internal pure returns (bytes) {
+ uint arrlen = arr.length;
+
+ // get correct cbor output length
+ uint outputlen = 0;
+ bytes[] memory elemArray = new bytes[](arrlen);
+ for (uint i = 0; i < arrlen; i++) {
+ elemArray[i] = (bytes(arr[i]));
+ outputlen += elemArray[i].length + (elemArray[i].length - 1)/23 + 3; //+3 accounts for paired identifier types
+ }
+ uint ctr = 0;
+ uint cborlen = arrlen + 0x80;
+ outputlen += byte(cborlen).length;
+ bytes memory res = new bytes(outputlen);
+
+ while (byte(cborlen).length > ctr) {
+ res[ctr] = byte(cborlen)[ctr];
+ ctr++;
+ }
+ for (i = 0; i < arrlen; i++) {
+ res[ctr] = 0x5F;
+ ctr++;
+ for (uint x = 0; x < elemArray[i].length; x++) {
+ // if there's a bug with larger strings, this may be the culprit
+ if (x % 23 == 0) {
+ uint elemcborlen = elemArray[i].length - x >= 24 ? 23 : elemArray[i].length - x;
+ elemcborlen += 0x40;
+ uint lctr = ctr;
+ while (byte(elemcborlen).length > ctr - lctr) {
+ res[ctr] = byte(elemcborlen)[ctr - lctr];
+ ctr++;
+ }
+ }
+ res[ctr] = elemArray[i][x];
+ ctr++;
+ }
+ res[ctr] = 0xFF;
+ ctr++;
+ }
+ return res;
+ }
+
+
+ string oraclize_network_name;
+ function oraclize_setNetworkName(string _network_name) internal {
+ oraclize_network_name = _network_name;
+ }
+
+ function oraclize_getNetworkName() internal view returns (string) {
+ return oraclize_network_name;
+ }
+
+ function oraclize_newRandomDSQuery(uint _delay, uint _nbytes, uint _customGasLimit) internal returns (bytes32){
+ require((_nbytes > 0) && (_nbytes <= 32));
+ // Convert from seconds to ledger timer ticks
+ _delay *= 10;
+ bytes memory nbytes = new bytes(1);
+ nbytes[0] = byte(_nbytes);
+ bytes memory unonce = new bytes(32);
+ bytes memory sessionKeyHash = new bytes(32);
+ bytes32 sessionKeyHash_bytes32 = oraclize_randomDS_getSessionPubKeyHash();
+ assembly {
+ mstore(unonce, 0x20)
+ mstore(add(unonce, 0x20), xor(blockhash(sub(number, 1)), xor(coinbase, timestamp)))
+ mstore(sessionKeyHash, 0x20)
+ mstore(add(sessionKeyHash, 0x20), sessionKeyHash_bytes32)
+ }
+ bytes memory delay = new bytes(32);
+ assembly {
+ mstore(add(delay, 0x20), _delay)
+ }
+
+ bytes memory delay_bytes8 = new bytes(8);
+ copyBytes(delay, 24, 8, delay_bytes8, 0);
+
+ bytes[4] memory args = [unonce, nbytes, sessionKeyHash, delay];
+ bytes32 queryId = oraclize_query("random", args, _customGasLimit);
+
+ bytes memory delay_bytes8_left = new bytes(8);
+
+ assembly {
+ let x := mload(add(delay_bytes8, 0x20))
+ mstore8(add(delay_bytes8_left, 0x27), div(x, 0x100000000000000000000000000000000000000000000000000000000000000))
+ mstore8(add(delay_bytes8_left, 0x26), div(x, 0x1000000000000000000000000000000000000000000000000000000000000))
+ mstore8(add(delay_bytes8_left, 0x25), div(x, 0x10000000000000000000000000000000000000000000000000000000000))
+ mstore8(add(delay_bytes8_left, 0x24), div(x, 0x100000000000000000000000000000000000000000000000000000000))
+ mstore8(add(delay_bytes8_left, 0x23), div(x, 0x1000000000000000000000000000000000000000000000000000000))
+ mstore8(add(delay_bytes8_left, 0x22), div(x, 0x10000000000000000000000000000000000000000000000000000))
+ mstore8(add(delay_bytes8_left, 0x21), div(x, 0x100000000000000000000000000000000000000000000000000))
+ mstore8(add(delay_bytes8_left, 0x20), div(x, 0x1000000000000000000000000000000000000000000000000))
+
+ }
+
+ oraclize_randomDS_setCommitment(queryId, keccak256(delay_bytes8_left, args[1], sha256(args[0]), args[2]));
+ return queryId;
+ }
+
+ function oraclize_randomDS_setCommitment(bytes32 queryId, bytes32 commitment) internal {
+ oraclize_randomDS_args[queryId] = commitment;
+ }
+
+ mapping(bytes32=>bytes32) oraclize_randomDS_args;
+ mapping(bytes32=>bool) oraclize_randomDS_sessionKeysHashVerified;
+
+ function verifySig(bytes32 tosignh, bytes dersig, bytes pubkey) internal returns (bool){
+ bool sigok;
+ address signer;
+
+ bytes32 sigr;
+ bytes32 sigs;
+
+ bytes memory sigr_ = new bytes(32);
+ uint offset = 4+(uint(dersig[3]) - 0x20);
+ sigr_ = copyBytes(dersig, offset, 32, sigr_, 0);
+ bytes memory sigs_ = new bytes(32);
+ offset += 32 + 2;
+ sigs_ = copyBytes(dersig, offset+(uint(dersig[offset-1]) - 0x20), 32, sigs_, 0);
+
+ assembly {
+ sigr := mload(add(sigr_, 32))
+ sigs := mload(add(sigs_, 32))
+ }
+
+
+ (sigok, signer) = safer_ecrecover(tosignh, 27, sigr, sigs);
+ if (address(keccak256(pubkey)) == signer) return true;
+ else {
+ (sigok, signer) = safer_ecrecover(tosignh, 28, sigr, sigs);
+ return (address(keccak256(pubkey)) == signer);
+ }
+ }
+
+ function oraclize_randomDS_proofVerify__sessionKeyValidity(bytes proof, uint sig2offset) internal returns (bool) {
+ bool sigok;
+
+ // Step 6: verify the attestation signature, APPKEY1 must sign the sessionKey from the correct ledger app (CODEHASH)
+ bytes memory sig2 = new bytes(uint(proof[sig2offset+1])+2);
+ copyBytes(proof, sig2offset, sig2.length, sig2, 0);
+
+ bytes memory appkey1_pubkey = new bytes(64);
+ copyBytes(proof, 3+1, 64, appkey1_pubkey, 0);
+
+ bytes memory tosign2 = new bytes(1+65+32);
+ tosign2[0] = byte(1); //role
+ copyBytes(proof, sig2offset-65, 65, tosign2, 1);
+ bytes memory CODEHASH = hex"fd94fa71bc0ba10d39d464d0d8f465efeef0a2764e3887fcc9df41ded20f505c";
+ copyBytes(CODEHASH, 0, 32, tosign2, 1+65);
+ sigok = verifySig(sha256(tosign2), sig2, appkey1_pubkey);
+
+ if (sigok == false) return false;
+
+
+ // Step 7: verify the APPKEY1 provenance (must be signed by Ledger)
+ bytes memory LEDGERKEY = hex"7fb956469c5c9b89840d55b43537e66a98dd4811ea0a27224272c2e5622911e8537a2f8e86a46baec82864e98dd01e9ccc2f8bc5dfc9cbe5a91a290498dd96e4";
+
+ bytes memory tosign3 = new bytes(1+65);
+ tosign3[0] = 0xFE;
+ copyBytes(proof, 3, 65, tosign3, 1);
+
+ bytes memory sig3 = new bytes(uint(proof[3+65+1])+2);
+ copyBytes(proof, 3+65, sig3.length, sig3, 0);
+
+ sigok = verifySig(sha256(tosign3), sig3, LEDGERKEY);
+
+ return sigok;
+ }
+
+ modifier oraclize_randomDS_proofVerify(bytes32 _queryId, string _result, bytes _proof) {
+ // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1)
+ require((_proof[0] == "L") && (_proof[1] == "P") && (_proof[2] == 1));
+
+ bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName());
+ require(proofVerified);
+
+ _;
+ }
+
+ function oraclize_randomDS_proofVerify__returnCode(bytes32 _queryId, string _result, bytes _proof) internal returns (uint8){
+ // Step 1: the prefix has to match 'LP\x01' (Ledger Proof version 1)
+ if ((_proof[0] != "L")||(_proof[1] != "P")||(_proof[2] != 1)) return 1;
+
+ bool proofVerified = oraclize_randomDS_proofVerify__main(_proof, _queryId, bytes(_result), oraclize_getNetworkName());
+ if (proofVerified == false) return 2;
+
+ return 0;
+ }
+
+ function matchBytes32Prefix(bytes32 content, bytes prefix, uint n_random_bytes) internal pure returns (bool){
+ bool match_ = true;
+
+ require(prefix.length == n_random_bytes);
+
+ for (uint256 i=0; i< n_random_bytes; i++) {
+ if (content[i] != prefix[i]) match_ = false;
+ }
+
+ return match_;
+ }
+
+ function oraclize_randomDS_proofVerify__main(bytes proof, bytes32 queryId, bytes result, string context_name) internal returns (bool){
+
+ // Step 2: the unique keyhash has to match with the sha256 of (context name + queryId)
+ uint ledgerProofLength = 3+65+(uint(proof[3+65+1])+2)+32;
+ bytes memory keyhash = new bytes(32);
+ copyBytes(proof, ledgerProofLength, 32, keyhash, 0);
+ if (!(keccak256(keyhash) == keccak256(sha256(context_name, queryId)))) return false;
+
+ bytes memory sig1 = new bytes(uint(proof[ledgerProofLength+(32+8+1+32)+1])+2);
+ copyBytes(proof, ledgerProofLength+(32+8+1+32), sig1.length, sig1, 0);
+
+ // Step 3: we assume sig1 is valid (it will be verified during step 5) and we verify if 'result' is the prefix of sha256(sig1)
+ if (!matchBytes32Prefix(sha256(sig1), result, uint(proof[ledgerProofLength+32+8]))) return false;
+
+ // Step 4: commitment match verification, keccak256(delay, nbytes, unonce, sessionKeyHash) == commitment in storage.
+ // This is to verify that the computed args match with the ones specified in the query.
+ bytes memory commitmentSlice1 = new bytes(8+1+32);
+ copyBytes(proof, ledgerProofLength+32, 8+1+32, commitmentSlice1, 0);
+
+ bytes memory sessionPubkey = new bytes(64);
+ uint sig2offset = ledgerProofLength+32+(8+1+32)+sig1.length+65;
+ copyBytes(proof, sig2offset-64, 64, sessionPubkey, 0);
+
+ bytes32 sessionPubkeyHash = sha256(sessionPubkey);
+ if (oraclize_randomDS_args[queryId] == keccak256(commitmentSlice1, sessionPubkeyHash)){ //unonce, nbytes and sessionKeyHash match
+ delete oraclize_randomDS_args[queryId];
+ } else return false;
+
+
+ // Step 5: validity verification for sig1 (keyhash and args signed with the sessionKey)
+ bytes memory tosign1 = new bytes(32+8+1+32);
+ copyBytes(proof, ledgerProofLength, 32+8+1+32, tosign1, 0);
+ if (!verifySig(sha256(tosign1), sig1, sessionPubkey)) return false;
+
+ // verify if sessionPubkeyHash was verified already, if not.. let's do it!
+ if (oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash] == false){
+ oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash] = oraclize_randomDS_proofVerify__sessionKeyValidity(proof, sig2offset);
+ }
+
+ return oraclize_randomDS_sessionKeysHashVerified[sessionPubkeyHash];
+ }
+
+ // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
+ function copyBytes(bytes from, uint fromOffset, uint length, bytes to, uint toOffset) internal pure returns (bytes) {
+ uint minLength = length + toOffset;
+
+ // Buffer too small
+ require(to.length >= minLength); // Should be a better way?
+
+ // NOTE: the offset 32 is added to skip the `size` field of both bytes variables
+ uint i = 32 + fromOffset;
+ uint j = 32 + toOffset;
+
+ while (i < (32 + fromOffset + length)) {
+ assembly {
+ let tmp := mload(add(from, i))
+ mstore(add(to, j), tmp)
+ }
+ i += 32;
+ j += 32;
+ }
+
+ return to;
+ }
+
+ // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
+ // Duplicate Solidity's ecrecover, but catching the CALL return value
+ function safer_ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal returns (bool, address) {
+ // We do our own memory management here. Solidity uses memory offset
+ // 0x40 to store the current end of memory. We write past it (as
+ // writes are memory extensions), but don't update the offset so
+ // Solidity will reuse it. The memory used here is only needed for
+ // this context.
+
+ // FIXME: inline assembly can't access return values
+ bool ret;
+ address addr;
+
+ assembly {
+ let size := mload(0x40)
+ mstore(size, hash)
+ mstore(add(size, 32), v)
+ mstore(add(size, 64), r)
+ mstore(add(size, 96), s)
+
+ // NOTE: we can reuse the request memory because we deal with
+ // the return code
+ ret := call(3000, 1, 0, size, 128, size, 32)
+ addr := mload(size)
+ }
+
+ return (ret, addr);
+ }
+
+ // the following function has been written by Alex Beregszaszi (@axic), use it under the terms of the MIT license
+ function ecrecovery(bytes32 hash, bytes sig) internal returns (bool, address) {
+ bytes32 r;
+ bytes32 s;
+ uint8 v;
+
+ if (sig.length != 65)
+ return (false, 0);
+
+ // The signature format is a compact form of:
+ // {bytes32 r}{bytes32 s}{uint8 v}
+ // Compact means, uint8 is not padded to 32 bytes.
+ assembly {
+ r := mload(add(sig, 32))
+ s := mload(add(sig, 64))
+
+ // Here we are loading the last 32 bytes. We exploit the fact that
+ // 'mload' will pad with zeroes if we overread.
+ // There is no 'mload8' to do this, but that would be nicer.
+ v := byte(0, mload(add(sig, 96)))
+
+ // Alternative solution:
+ // 'byte' is not working due to the Solidity parser, so lets
+ // use the second best option, 'and'
+ // v := and(mload(add(sig, 65)), 255)
+ }
+
+ // albeit non-transactional signatures are not specified by the YP, one would expect it
+ // to match the YP range of [27, 28]
+ //
+ // geth uses [0, 1] and some clients have followed. This might change, see:
+ // https://github.com/ethereum/go-ethereum/issues/2053
+ if (v < 27)
+ v += 27;
+
+ if (v != 27 && v != 28)
+ return (false, 0);
+
+ return safer_ecrecover(hash, v, r, s);
+ }
+
+ function nestingTest(string _a, string _b, string _c, string _d, string _e) {
+ uint i;
+ uint k;
+
+ uint[] _ba;
+ uint[] _bb;
+ uint[] _bc;
+ uint[] _bd;
+ uint[] _be;
+ uint[] babcde;
+
+ for (i = 0; i < _bb.length; i++)
+ for (i = 0; i < _bb.length; i++)
+ if (i == 0)
+ babcde[k++] = _bb[i];
+ for (i = 0; i < _bb.length; i++)
+ for (i = 0; i < _bb.length; i++)
+ if (i == 0)
+ while (true)
+ babcde[k++] = _bb[i];
+ for (i = 0; i < _bb.length; i++)
+ for (i = 0; i < _bb.length; i++)
+ if (i == 0)
+ babcde[k++] = _bb[i];
+ for (i = 0; i < _bb.length; i++)
+ for (i = 0; i < _bb.length; i++)
+ if (i == 0)
+ babcde[k++] = _bb[i];
+ for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
+ for (i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
+ for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
+ for (i = 0; i < _bb.length; i++)
+ for (i = 0; i < _bb.length; i++)
+ if (i == 0)
+ babcde[k++] = _bb[i];
+ for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
+ for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
+ for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
+ if (_be[0] < _bd[0])
+ return;
+ else if (babcde[0] > _bd[0])
+ if (_bd[0] < _bc[0])
+ return;
+ if (_bd[0] == _bc[0])
+ return;
+ }
+
+ function test() public {
+ uint tls = 5;
+ }
+
+}
+//
diff --git a/test/sources/if/else-if-without-brackets.sol b/test/sources/if/else-if-without-brackets.sol
new file mode 100644
index 00000000..d5f08b92
--- /dev/null
+++ b/test/sources/if/else-if-without-brackets.sol
@@ -0,0 +1,10 @@
+pragma solidity ^0.5.0;
+
+contract Test {
+ function a(uint x) public {
+ if (x == 1) {
+ revert();
+ } else if (x == 50)
+ x = 5;
+ }
+}
\ No newline at end of file
diff --git a/test/statements.js b/test/statements.js
index 0e02e766..876c4cc1 100644
--- a/test/statements.js
+++ b/test/statements.js
@@ -59,8 +59,6 @@ describe('generic statements', () => {
util.report(output.errors);
});
-
-
it('should NOT pass tests if the contract has a compilation error', () => {
const contract = util.getCode('statements/compilation-error.sol');
const info = getInstrumentedVersion(contract, filePath);
diff --git a/test/util/mockTruffle.js b/test/util/mockTruffle.js
index dded2261..f8fd55e4 100644
--- a/test/util/mockTruffle.js
+++ b/test/util/mockTruffle.js
@@ -27,7 +27,14 @@ const defaultTruffleJs = `module.exports = {
* @param {String} contract located in /test/sources/cli/
* @param {[type]} test located in /test/cli/
*/
-module.exports.install = function install(contract, test, config, _trufflejs, _trufflejsName) {
+module.exports.install = function install(
+ contract,
+ test,
+ config,
+ _trufflejs,
+ _trufflejsName,
+ noMigrations
+) {
const configjs = `module.exports = ${JSON.stringify(config)}`;
const contractLocation = `./${contract}`;
const trufflejsName = _trufflejsName || 'truffle.js';
@@ -68,9 +75,12 @@ module.exports.install = function install(contract, test, config, _trufflejs, _t
shell.cp(`./test/sources/cli/${contract}`, `./mock/contracts/${contract}`);
}
- shell.cp('./test/sources/cli/Migrations.sol', './mock/contracts/Migrations.sol');
- fs.writeFileSync('./mock/migrations/1_initial_migration.js', initialMigration);
- fs.writeFileSync('./mock/migrations/2_deploy_contracts.js', deployContracts);
+ if (!noMigrations){
+ shell.cp('./test/sources/cli/Migrations.sol', './mock/contracts/Migrations.sol');
+ fs.writeFileSync('./mock/migrations/1_initial_migration.js', initialMigration);
+ fs.writeFileSync('./mock/migrations/2_deploy_contracts.js', deployContracts);
+ }
+
fs.writeFileSync(`./mock/${trufflejsName}`, trufflejs);
fs.writeFileSync('./mock/assets/asset.js', asset);
fs.writeFileSync('./.solcover.js', configjs);