From 60313959de74d8f4786858ee6e5425b7964478e9 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 10 Apr 2015 08:50:24 +0200 Subject: [PATCH 001/108] Squashed 'libjsqrc/ethereumjs/' changes from 73b9ed2..4def095 4def095 updated README.md 15b4dbd updated bower && package.json files 0ccc05a web3 in global namespace ccc59d1 version 0.2.6 9c2c946 Merge branch 'web3' into develop 6763f34 tests for creating new contract with nondefault constructor, added missing files 2ef5efc fixed #70, creating contract with nondefault constructor dbe4015 Merge branch 'master' into develop 48b351a add gasPrice test and fixed failing uncle tests 7f75f3e fixed gasPrice output ddec629 fixed getUncle parameter count 1e89ef0 changed to eth_protocolVersion 6add9bd Merge pull request #151 from ethereum/develop git-subtree-dir: libjsqrc/ethereumjs git-subtree-split: 4def0958d35cb5b8d92d277423af4d435dd89f16 --- README.md | 12 +- bower.json | 12 +- dist/web3-light.js | 240 +++++++++++++++++---------- dist/web3-light.js.map | 18 ++- dist/web3-light.min.js | 2 +- dist/web3.js | 242 ++++++++++++++++++---------- dist/web3.js.map | 18 ++- dist/web3.min.js | 4 +- index.js | 13 +- lib/solidity/abi.js | 23 ++- lib/solidity/utils.js | 68 ++++++++ lib/utils/utils.js | 46 ++---- lib/version.json | 2 +- lib/web3.js | 2 +- lib/web3/contract.js | 28 +++- lib/web3/eth.js | 6 +- package.js | 2 +- package.json | 8 +- test/abi.formatConstructorParams.js | 106 ++++++++++++ test/abi.inputParser.js | 11 +- test/utils.filters.js | 2 +- test/utils.isAddress.js | 2 +- test/utils.isStrictAddress.js | 23 +++ test/web3.eth.contract.js | 49 +++++- test/web3.eth.gasPrice.js | 39 +++++ test/web3.eth.getUncle.js | 6 +- 26 files changed, 713 insertions(+), 271 deletions(-) create mode 100644 lib/solidity/utils.js create mode 100644 test/abi.formatConstructorParams.js create mode 100644 test/utils.isStrictAddress.js create mode 100644 test/web3.eth.gasPrice.js diff --git a/README.md b/README.md index e9eca4113..99afaf54e 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ You need to run a local ethrereum node to use this library. ### Node.js - $ npm install ethereum.js + $ npm install web3 ### Meteor.js @@ -26,20 +26,24 @@ You need to run a local ethrereum node to use this library. ### As Browser module Bower - $ bower install ethereum.js + $ bower install web3 Component - $ component install ethereum/ethereum.js + $ component install ethereum/web3.js * Include `ethereum.min.js` in your html file. (not required for the meteor package) * Include [bignumber.js](https://github.com/MikeMcl/bignumber.js/) (not required for the meteor package) ## Usage -Require the library (not required for the meteor package): +You can require the library (not required for the meteor package): var web3 = require('ethereum.js'); +Or use it directly from global namespace: + + console.log(web3); // {eth: .., shh: ...} // it's here! + Set a provider (QtSyncProvider, HttpProvider) web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545')); diff --git a/bower.json b/bower.json index cdb588b4f..d4e2b1886 100644 --- a/bower.json +++ b/bower.json @@ -1,22 +1,22 @@ { "name": "web3", "namespace": "ethereum", - "version": "0.2.5", + "version": "0.2.6", "description": "Ethereum Compatible JavaScript API", "main": [ - "./dist/ethereum.js", - "./dist/ethereum.min.js" + "./dist/web3.js", + "./dist/web3.min.js" ], "dependencies": { "bignumber.js": ">=2.0.0" }, "repository": { "type": "git", - "url": "https://github.com/ethereum/ethereum.js.git" + "url": "https://github.com/ethereum/web3.js.git" }, - "homepage": "https://github.com/ethereum/ethereum.js", + "homepage": "https://github.com/ethereum/web3.js", "bugs": { - "url": "https://github.com/ethereum/ethereum.js/issues" + "url": "https://github.com/ethereum/web3.js/issues" }, "keywords": [ "ethereum", diff --git a/dist/web3-light.js b/dist/web3-light.js index 95c059774..8face24cd 100644 --- a/dist/web3-light.js +++ b/dist/web3-light.js @@ -15,10 +15,10 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file abi.js - * @authors: - * Marek Kotewicz - * Gav Wood +/** + * @file abi.js + * @author Marek Kotewicz + * @author Gav Wood * @date 2014 */ @@ -26,6 +26,7 @@ var utils = require('../utils/utils'); var c = require('../utils/config'); var types = require('./types'); var f = require('./formatters'); +var solUtils = require('./utils'); /** * throw incorrect type error @@ -238,14 +239,26 @@ var outputParser = function (json) { return parser; }; +var formatConstructorParams = function (abi, params) { + var constructor = solUtils.getConstructor(abi, params.length); + if (!constructor) { + if (params.length > 0) { + console.warn("didn't found matching constructor, using default one"); + } + return ''; + } + return formatInput(constructor.inputs, params); +}; + module.exports = { inputParser: inputParser, outputParser: outputParser, formatInput: formatInput, - formatOutput: formatOutput + formatOutput: formatOutput, + formatConstructorParams: formatConstructorParams }; -},{"../utils/config":5,"../utils/utils":6,"./formatters":2,"./types":3}],2:[function(require,module,exports){ +},{"../utils/config":6,"../utils/utils":7,"./formatters":2,"./types":3,"./utils":4}],2:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -445,7 +458,7 @@ module.exports = { }; -},{"../utils/config":5,"../utils/utils":6,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){ +},{"../utils/config":6,"../utils/utils":7,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -525,6 +538,76 @@ module.exports = { },{"./formatters":2}],4:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file utils.js + * @author Marek Kotewicz + * @date 2015 + */ + +/** + * Returns the contstructor with matching number of arguments + * + * @method getConstructor + * @param {Array} abi + * @param {Number} numberOfArgs + * @returns {Object} constructor function abi + */ +var getConstructor = function (abi, numberOfArgs) { + return abi.filter(function (f) { + return f.type === 'constructor' && f.inputs.length === numberOfArgs; + })[0]; +}; + +/** + * Filters all functions from input abi + * + * @method filterFunctions + * @param {Array} abi + * @returns {Array} abi array with filtered objects of type 'function' + */ +var filterFunctions = function (json) { + return json.filter(function (current) { + return current.type === 'function'; + }); +}; + +/** + * Filters all events from input abi + * + * @method filterEvents + * @param {Array} abi + * @returns {Array} abi array with filtered objects of type 'event' + */ +var filterEvents = function (json) { + return json.filter(function (current) { + return current.type === 'event'; + }); +}; + +module.exports = { + getConstructor: getConstructor, + filterFunctions: filterFunctions, + filterEvents: filterEvents +}; + + +},{}],5:[function(require,module,exports){ 'use strict'; // go env doesn't have and need XMLHttpRequest @@ -535,7 +618,7 @@ if (typeof XMLHttpRequest === 'undefined') { } -},{}],5:[function(require,module,exports){ +},{}],6:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -606,7 +689,7 @@ module.exports = { }; -},{"bignumber.js":"bignumber.js"}],6:[function(require,module,exports){ +},{"bignumber.js":"bignumber.js"}],7:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -770,32 +853,6 @@ var extractTypeName = function (name) { return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : ""; }; -/** - * Filters all functions from input abi - * - * @method filterFunctions - * @param {Array} abi - * @returns {Array} abi array with filtered objects of type 'function' - */ -var filterFunctions = function (json) { - return json.filter(function (current) { - return current.type === 'function'; - }); -}; - -/** - * Filters all events from input abi - * - * @method filterEvents - * @param {Array} abi - * @returns {Array} abi array with filtered objects of type 'event' - */ -var filterEvents = function (json) { - return json.filter(function (current) { - return current.type === 'event'; - }); -}; - /** * Converts value to it's decimal representation in string * @@ -958,14 +1015,25 @@ var toTwosComplement = function (number) { }; /** - * Checks if the given string has proper length + * Checks if the given string is strictly an address + * + * @method isStrictAddress + * @param {String} address the given HEX adress + * @return {Boolean} +*/ +var isStrictAddress = function (address) { + return /^0x[0-9a-f]{40}$/.test(address); +}; + +/** + * Checks if the given string is an address * * @method isAddress * @param {String} address the given HEX adress * @return {Boolean} */ var isAddress = function (address) { - return /^0x[0-9a-f]{40}$/.test(address); + return /^(0x)?[0-9a-f]{40}$/.test(address); }; /** @@ -976,7 +1044,7 @@ var isAddress = function (address) { * @return {String} formatted address */ var toAddress = function (address) { - if (isAddress(address)) { + if (isStrictAddress(address)) { return address; } @@ -1080,14 +1148,13 @@ module.exports = { fromAscii: fromAscii, extractDisplayName: extractDisplayName, extractTypeName: extractTypeName, - filterFunctions: filterFunctions, - filterEvents: filterEvents, toWei: toWei, fromWei: fromWei, toBigNumber: toBigNumber, toTwosComplement: toTwosComplement, toAddress: toAddress, isBigNumber: isBigNumber, + isStrictAddress: isStrictAddress, isAddress: isAddress, isFunction: isFunction, isString: isString, @@ -1098,12 +1165,12 @@ module.exports = { }; -},{"bignumber.js":"bignumber.js"}],7:[function(require,module,exports){ +},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){ module.exports={ - "version": "0.2.5" + "version": "0.2.6" } -},{}],8:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1164,7 +1231,7 @@ var web3Properties = [ }), new Property({ name: 'version.ethereum', - getter: 'eth_version', + getter: 'eth_protocolVersion', inputFormatter: utils.toDecimal }), new Property({ @@ -1259,7 +1326,7 @@ setupMethods(web3.shh, shh.methods); module.exports = web3; -},{"./utils/config":5,"./utils/utils":6,"./version.json":7,"./web3/db":10,"./web3/eth":12,"./web3/filter":14,"./web3/formatters":15,"./web3/method":18,"./web3/net":19,"./web3/property":20,"./web3/requestmanager":22,"./web3/shh":23,"./web3/watches":25}],9:[function(require,module,exports){ +},{"./utils/config":6,"./utils/utils":7,"./version.json":8,"./web3/db":11,"./web3/eth":13,"./web3/filter":15,"./web3/formatters":16,"./web3/method":19,"./web3/net":20,"./web3/property":21,"./web3/requestmanager":23,"./web3/shh":24,"./web3/watches":26}],10:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1283,8 +1350,9 @@ module.exports = web3; */ var web3 = require('../web3'); -var abi = require('../solidity/abi'); +var solAbi = require('../solidity/abi'); var utils = require('../utils/utils'); +var solUtils = require('../solidity/utils'); var eventImpl = require('./event'); var signature = require('./signature'); @@ -1304,11 +1372,11 @@ var addFunctionRelatedPropertiesToContract = function (contract) { }; var addFunctionsToContract = function (contract, desc, address) { - var inputParser = abi.inputParser(desc); - var outputParser = abi.outputParser(desc); + var inputParser = solAbi.inputParser(desc); + var outputParser = solAbi.outputParser(desc); // create contract functions - utils.filterFunctions(desc).forEach(function (method) { + solUtils.filterFunctions(desc).forEach(function (method) { var displayName = utils.extractDisplayName(method.name); var typeName = utils.extractTypeName(method.name); @@ -1360,14 +1428,14 @@ var addFunctionsToContract = function (contract, desc, address) { var addEventRelatedPropertiesToContract = function (contract, desc, address) { contract.address = address; contract._onWatchEventResult = function (data) { - var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc)); + var matchingEvent = event.getMatchingEvent(solUtils.filterEvents(desc)); var parser = eventImpl.outputParser(matchingEvent); return parser(data); }; Object.defineProperty(contract, 'topics', { get: function() { - return utils.filterEvents(desc).map(function (e) { + return solUtils.filterEvents(desc).map(function (e) { return signature.eventSignatureFromAscii(e.name); }); } @@ -1377,7 +1445,7 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) { var addEventsToContract = function (contract, desc, address) { // create contract events - utils.filterEvents(desc).forEach(function (e) { + solUtils.filterEvents(desc).forEach(function (e) { var impl = function () { var params = Array.prototype.slice.call(arguments); @@ -1435,7 +1503,7 @@ var contract = function (abi) { return Contract.bind(null, abi); }; -function Contract(abi, address) { +function Contract(abi, options) { // workaround for invalid assumption that method.name is the full anonymous prototype of the method. // it's not. it's just the name. the rest of the code assumes it's actually the anonymous @@ -1449,6 +1517,17 @@ function Contract(abi, address) { } }); + var address = ''; + if (utils.isAddress(options)) { + address = options; + } else { // is a source code! + // TODO, parse the rest of the args + var code = options; + var args = Array.prototype.slice.call(arguments, 2); + var bytes = solAbi.formatConstructorParams(abi, args); + address = web3.eth.sendTransaction({data: code + bytes}); + } + var result = {}; addFunctionRelatedPropertiesToContract(result); addFunctionsToContract(result, abi, address); @@ -1461,7 +1540,7 @@ function Contract(abi, address) { module.exports = contract; -},{"../solidity/abi":1,"../utils/utils":6,"../web3":8,"./event":13,"./signature":24}],10:[function(require,module,exports){ +},{"../solidity/abi":1,"../solidity/utils":4,"../utils/utils":7,"../web3":9,"./event":14,"./signature":25}],11:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1519,7 +1598,7 @@ module.exports = { methods: methods }; -},{"./method":18}],11:[function(require,module,exports){ +},{"./method":19}],12:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1559,7 +1638,7 @@ module.exports = { }; -},{"../utils/utils":6}],12:[function(require,module,exports){ +},{"../utils/utils":7}],13:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1671,8 +1750,8 @@ var getBlock = new Method({ var getUncle = new Method({ name: 'getUncle', call: uncleCall, - params: 3, - inputFormatter: [utils.toHex, utils.toHex, function (val) { return !!val; }], + params: 2, + inputFormatter: [utils.toHex, utils.toHex], outputFormatter: formatters.outputBlockFormatter, }); @@ -1796,7 +1875,7 @@ var properties = [ new Property({ name: 'gasPrice', getter: 'eth_gasPrice', - outputFormatter: formatters.inputNumberFormatter + outputFormatter: formatters.outputBigNumberFormatter }), new Property({ name: 'accounts', @@ -1815,7 +1894,7 @@ module.exports = { }; -},{"../utils/utils":6,"./formatters":15,"./method":18,"./property":20}],13:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":16,"./method":19,"./property":21}],14:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1955,7 +2034,7 @@ module.exports = { }; -},{"../solidity/abi":1,"../utils/utils":6,"./signature":24}],14:[function(require,module,exports){ +},{"../solidity/abi":1,"../utils/utils":7,"./signature":25}],15:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2067,7 +2146,7 @@ Filter.prototype.get = function () { module.exports = Filter; -},{"../utils/utils":6,"./formatters":15,"./requestmanager":22}],15:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":16,"./requestmanager":23}],16:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2280,7 +2359,7 @@ module.exports = { }; -},{"../utils/config":5,"../utils/utils":6}],16:[function(require,module,exports){ +},{"../utils/config":6,"../utils/utils":7}],17:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2343,7 +2422,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { module.exports = HttpProvider; -},{"xmlhttprequest":4}],17:[function(require,module,exports){ +},{"xmlhttprequest":5}],18:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2436,7 +2515,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) { module.exports = Jsonrpc; -},{}],18:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2597,7 +2676,7 @@ Method.prototype.send = function () { module.exports = Method; -},{"../utils/utils":6,"./errors":11,"./requestmanager":22}],19:[function(require,module,exports){ +},{"../utils/utils":7,"./errors":12,"./requestmanager":23}],20:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2647,7 +2726,7 @@ module.exports = { }; -},{"../utils/utils":6,"./property":20}],20:[function(require,module,exports){ +},{"../utils/utils":7,"./property":21}],21:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2753,7 +2832,7 @@ Property.prototype.set = function (value) { module.exports = Property; -},{"./requestmanager":22}],21:[function(require,module,exports){ +},{"./requestmanager":23}],22:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2788,7 +2867,7 @@ QtSyncProvider.prototype.send = function (payload) { module.exports = QtSyncProvider; -},{}],22:[function(require,module,exports){ +},{}],23:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3009,7 +3088,7 @@ RequestManager.prototype.poll = function () { module.exports = RequestManager; -},{"../utils/config":5,"../utils/utils":6,"./errors":11,"./jsonrpc":17}],23:[function(require,module,exports){ +},{"../utils/config":6,"../utils/utils":7,"./errors":12,"./jsonrpc":18}],24:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3079,7 +3158,7 @@ module.exports = { }; -},{"./formatters":15,"./method":18}],24:[function(require,module,exports){ +},{"./formatters":16,"./method":19}],25:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3123,7 +3202,7 @@ module.exports = { }; -},{"../utils/config":5,"../web3":8}],25:[function(require,module,exports){ +},{"../utils/config":6,"../web3":9}],26:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3226,7 +3305,7 @@ module.exports = { }; -},{"./method":18}],26:[function(require,module,exports){ +},{"./method":19}],27:[function(require,module,exports){ },{}],"bignumber.js":[function(require,module,exports){ 'use strict'; @@ -3235,22 +3314,21 @@ module.exports = BigNumber; // jshint ignore:line },{}],"web3":[function(require,module,exports){ -// dont override global variable -if (typeof web3 !== 'undefined') { - var web3; -} - -web3 = require('./lib/web3'); +var web3 = require('./lib/web3'); web3.providers.HttpProvider = require('./lib/web3/httpprovider'); web3.providers.QtSyncProvider = require('./lib/web3/qtsync'); web3.eth.contract = require('./lib/web3/contract'); web3.abi = require('./lib/solidity/abi'); - +// dont override global variable +if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { + window.web3 = web3; +} module.exports = web3; -},{"./lib/solidity/abi":1,"./lib/web3":8,"./lib/web3/contract":9,"./lib/web3/httpprovider":16,"./lib/web3/qtsync":21}]},{},["web3"]) + +},{"./lib/solidity/abi":1,"./lib/web3":9,"./lib/web3/contract":10,"./lib/web3/httpprovider":17,"./lib/web3/qtsync":22}]},{},["web3"]) //# sourceMappingURL=web3-light.js.map \ No newline at end of file diff --git a/dist/web3-light.js.map b/dist/web3-light.js.map index 182c2f2aa..f8df84067 100644 --- a/dist/web3-light.js.map +++ b/dist/web3-light.js.map @@ -5,6 +5,7 @@ "lib/solidity/abi.js", "lib/solidity/formatters.js", "lib/solidity/types.js", + "lib/solidity/utils.js", "lib/utils/browser-xhr.js", "lib/utils/config.js", "lib/utils/utils.js", @@ -32,23 +33,24 @@ "index.js" ], "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1eA;AACA;AACA;AACA;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;;ACAA;AACA;AACA;AACA;AACA;;ACJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1dA;AACA;AACA;AACA;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;;ACAA;AACA;AACA;AACA;AACA;;ACJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "generated.js", "sourceRoot": "", "sourcesContent": [ "(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o.\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar types = require('./types');\nvar f = require('./formatters');\n\n/**\n * throw incorrect type error\n *\n * @method throwTypeError\n * @param {String} type\n * @throws incorrect type error\n */\nvar throwTypeError = function (type) {\n throw new Error('parser does not support type: ' + type);\n};\n\n/** This method should be called if we want to check if givent type is an array type\n *\n * @method isArrayType\n * @param {String} type name\n * @returns {Boolean} true if it is, otherwise false\n */\nvar isArrayType = function (type) {\n return type.slice(-2) === '[]';\n};\n\n/**\n * This method should be called to return dynamic type length in hex\n *\n * @method dynamicTypeBytes\n * @param {String} type\n * @param {String|Array} dynamic type\n * @return {String} length of dynamic type in hex or empty string if type is not dynamic\n */\nvar dynamicTypeBytes = function (type, value) {\n // TODO: decide what to do with array of strings\n if (isArrayType(type) || type === 'bytes')\n return f.formatInputInt(value.length);\n return \"\";\n};\n\nvar inputTypes = types.inputTypes();\n\n/**\n * Formats input params to bytes\n *\n * @method formatInput\n * @param {Array} abi inputs of method\n * @param {Array} params that will be formatted to bytes\n * @returns bytes representation of input params\n */\nvar formatInput = function (inputs, params) {\n var bytes = \"\";\n var toAppendConstant = \"\";\n var toAppendArrayContent = \"\";\n\n /// first we iterate in search for dynamic\n inputs.forEach(function (input, index) {\n bytes += dynamicTypeBytes(input.type, params[index]);\n });\n\n inputs.forEach(function (input, i) {\n /*jshint maxcomplexity:5 */\n var typeMatch = false;\n for (var j = 0; j < inputTypes.length && !typeMatch; j++) {\n typeMatch = inputTypes[j].type(inputs[i].type, params[i]);\n }\n if (!typeMatch) {\n throwTypeError(inputs[i].type);\n }\n\n var formatter = inputTypes[j - 1].format;\n\n if (isArrayType(inputs[i].type))\n toAppendArrayContent += params[i].reduce(function (acc, curr) {\n return acc + formatter(curr);\n }, \"\");\n else if (inputs[i].type === 'bytes')\n toAppendArrayContent += formatter(params[i]);\n else\n toAppendConstant += formatter(params[i]);\n });\n\n bytes += toAppendConstant + toAppendArrayContent;\n\n return bytes;\n};\n\n/**\n * This method should be called to predict the length of dynamic type\n *\n * @method dynamicBytesLength\n * @param {String} type\n * @returns {Number} length of dynamic type, 0 or multiplication of ETH_PADDING (32)\n */\nvar dynamicBytesLength = function (type) {\n if (isArrayType(type) || type === 'bytes')\n return c.ETH_PADDING * 2;\n return 0;\n};\n\nvar outputTypes = types.outputTypes();\n\n/** \n * Formats output bytes back to param list\n *\n * @method formatOutput\n * @param {Array} abi outputs of method\n * @param {String} bytes represention of output\n * @returns {Array} output params\n */\nvar formatOutput = function (outs, output) {\n\n output = output.slice(2);\n var result = [];\n var padding = c.ETH_PADDING * 2;\n\n var dynamicPartLength = outs.reduce(function (acc, curr) {\n return acc + dynamicBytesLength(curr.type);\n }, 0);\n\n var dynamicPart = output.slice(0, dynamicPartLength);\n output = output.slice(dynamicPartLength);\n\n outs.forEach(function (out, i) {\n /*jshint maxcomplexity:6 */\n var typeMatch = false;\n for (var j = 0; j < outputTypes.length && !typeMatch; j++) {\n typeMatch = outputTypes[j].type(outs[i].type);\n }\n\n if (!typeMatch) {\n throwTypeError(outs[i].type);\n }\n\n var formatter = outputTypes[j - 1].format;\n if (isArrayType(outs[i].type)) {\n var size = f.formatOutputUInt(dynamicPart.slice(0, padding));\n dynamicPart = dynamicPart.slice(padding);\n var array = [];\n for (var k = 0; k < size; k++) {\n array.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n result.push(array);\n }\n else if (types.prefixedType('bytes')(outs[i].type)) {\n dynamicPart = dynamicPart.slice(padding);\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n } else {\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n });\n\n return result;\n};\n\n/**\n * Should be called to create input parser for contract with given abi\n *\n * @method inputParser\n * @param {Array} contract abi\n * @returns {Object} input parser object for given json abi\n * TODO: refactor creating the parser, do not double logic from contract\n */\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n return formatInput(method.inputs, params);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\n/**\n * Should be called to create output parser for contract with given abi\n *\n * @method outputParser\n * @param {Array} contract abi\n * @returns {Object} output parser for given json abi\n */\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function (output) {\n return formatOutput(method.outputs, output);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n formatInput: formatInput,\n formatOutput: formatOutput\n};\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file abi.js\n * @author Marek Kotewicz \n * @author Gav Wood \n * @date 2014\n */\n\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar types = require('./types');\nvar f = require('./formatters');\nvar solUtils = require('./utils');\n\n/**\n * throw incorrect type error\n *\n * @method throwTypeError\n * @param {String} type\n * @throws incorrect type error\n */\nvar throwTypeError = function (type) {\n throw new Error('parser does not support type: ' + type);\n};\n\n/** This method should be called if we want to check if givent type is an array type\n *\n * @method isArrayType\n * @param {String} type name\n * @returns {Boolean} true if it is, otherwise false\n */\nvar isArrayType = function (type) {\n return type.slice(-2) === '[]';\n};\n\n/**\n * This method should be called to return dynamic type length in hex\n *\n * @method dynamicTypeBytes\n * @param {String} type\n * @param {String|Array} dynamic type\n * @return {String} length of dynamic type in hex or empty string if type is not dynamic\n */\nvar dynamicTypeBytes = function (type, value) {\n // TODO: decide what to do with array of strings\n if (isArrayType(type) || type === 'bytes')\n return f.formatInputInt(value.length);\n return \"\";\n};\n\nvar inputTypes = types.inputTypes();\n\n/**\n * Formats input params to bytes\n *\n * @method formatInput\n * @param {Array} abi inputs of method\n * @param {Array} params that will be formatted to bytes\n * @returns bytes representation of input params\n */\nvar formatInput = function (inputs, params) {\n var bytes = \"\";\n var toAppendConstant = \"\";\n var toAppendArrayContent = \"\";\n\n /// first we iterate in search for dynamic\n inputs.forEach(function (input, index) {\n bytes += dynamicTypeBytes(input.type, params[index]);\n });\n\n inputs.forEach(function (input, i) {\n /*jshint maxcomplexity:5 */\n var typeMatch = false;\n for (var j = 0; j < inputTypes.length && !typeMatch; j++) {\n typeMatch = inputTypes[j].type(inputs[i].type, params[i]);\n }\n if (!typeMatch) {\n throwTypeError(inputs[i].type);\n }\n\n var formatter = inputTypes[j - 1].format;\n\n if (isArrayType(inputs[i].type))\n toAppendArrayContent += params[i].reduce(function (acc, curr) {\n return acc + formatter(curr);\n }, \"\");\n else if (inputs[i].type === 'bytes')\n toAppendArrayContent += formatter(params[i]);\n else\n toAppendConstant += formatter(params[i]);\n });\n\n bytes += toAppendConstant + toAppendArrayContent;\n\n return bytes;\n};\n\n/**\n * This method should be called to predict the length of dynamic type\n *\n * @method dynamicBytesLength\n * @param {String} type\n * @returns {Number} length of dynamic type, 0 or multiplication of ETH_PADDING (32)\n */\nvar dynamicBytesLength = function (type) {\n if (isArrayType(type) || type === 'bytes')\n return c.ETH_PADDING * 2;\n return 0;\n};\n\nvar outputTypes = types.outputTypes();\n\n/** \n * Formats output bytes back to param list\n *\n * @method formatOutput\n * @param {Array} abi outputs of method\n * @param {String} bytes represention of output\n * @returns {Array} output params\n */\nvar formatOutput = function (outs, output) {\n\n output = output.slice(2);\n var result = [];\n var padding = c.ETH_PADDING * 2;\n\n var dynamicPartLength = outs.reduce(function (acc, curr) {\n return acc + dynamicBytesLength(curr.type);\n }, 0);\n\n var dynamicPart = output.slice(0, dynamicPartLength);\n output = output.slice(dynamicPartLength);\n\n outs.forEach(function (out, i) {\n /*jshint maxcomplexity:6 */\n var typeMatch = false;\n for (var j = 0; j < outputTypes.length && !typeMatch; j++) {\n typeMatch = outputTypes[j].type(outs[i].type);\n }\n\n if (!typeMatch) {\n throwTypeError(outs[i].type);\n }\n\n var formatter = outputTypes[j - 1].format;\n if (isArrayType(outs[i].type)) {\n var size = f.formatOutputUInt(dynamicPart.slice(0, padding));\n dynamicPart = dynamicPart.slice(padding);\n var array = [];\n for (var k = 0; k < size; k++) {\n array.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n result.push(array);\n }\n else if (types.prefixedType('bytes')(outs[i].type)) {\n dynamicPart = dynamicPart.slice(padding);\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n } else {\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n });\n\n return result;\n};\n\n/**\n * Should be called to create input parser for contract with given abi\n *\n * @method inputParser\n * @param {Array} contract abi\n * @returns {Object} input parser object for given json abi\n * TODO: refactor creating the parser, do not double logic from contract\n */\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n return formatInput(method.inputs, params);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\n/**\n * Should be called to create output parser for contract with given abi\n *\n * @method outputParser\n * @param {Array} contract abi\n * @returns {Object} output parser for given json abi\n */\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function (output) {\n return formatOutput(method.outputs, output);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\nvar formatConstructorParams = function (abi, params) {\n var constructor = solUtils.getConstructor(abi, params.length);\n if (!constructor) {\n if (params.length > 0) {\n console.warn(\"didn't found matching constructor, using default one\");\n }\n return '';\n }\n return formatInput(constructor.inputs, params);\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n formatInput: formatInput,\n formatOutput: formatOutput,\n formatConstructorParams: formatConstructorParams\n};\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file formatters.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar BigNumber = require('bignumber.js');\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\n\n/**\n * Formats input value to byte representation of int\n * If value is negative, return it's two's complement\n * If the value is floating point, round it down\n *\n * @method formatInputInt\n * @param {String|Number|BigNumber} value that needs to be formatted\n * @returns {String} right-aligned byte representation of int\n */\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n return utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);\n};\n\n/**\n * Formats input value to byte representation of string\n *\n * @method formatInputString\n * @param {String}\n * @returns {String} left-algined byte representation of string\n */\nvar formatInputString = function (value) {\n return utils.fromAscii(value, c.ETH_PADDING).substr(2);\n};\n\n/**\n * Formats input value to byte representation of bool\n *\n * @method formatInputBool\n * @param {Boolean}\n * @returns {String} right-aligned byte representation bool\n */\nvar formatInputBool = function (value) {\n return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n};\n\n/**\n * Formats input value to byte representation of real\n * Values are multiplied by 2^m and encoded as integers\n *\n * @method formatInputReal\n * @param {String|Number|BigNumber}\n * @returns {String} byte representation of real\n */\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); \n};\n\n/**\n * Check if input value is negative\n *\n * @method signedIsNegative\n * @param {String} value is hex format\n * @returns {Boolean} true if it is negative, otherwise false\n */\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/**\n * Formats right-aligned output bytes to int\n *\n * @method formatOutputInt\n * @param {String} bytes\n * @returns {BigNumber} right-aligned output bytes formatted to big number\n */\nvar formatOutputInt = function (value) {\n\n value = value || \"0\";\n\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/**\n * Formats right-aligned output bytes to uint\n *\n * @method formatOutputUInt\n * @param {String} bytes\n * @returns {BigNumeber} right-aligned output bytes formatted to uint\n */\nvar formatOutputUInt = function (value) {\n value = value || \"0\";\n return new BigNumber(value, 16);\n};\n\n/**\n * Formats right-aligned output bytes to real\n *\n * @method formatOutputReal\n * @param {String}\n * @returns {BigNumber} input bytes formatted to real\n */\nvar formatOutputReal = function (value) {\n return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/**\n * Formats right-aligned output bytes to ureal\n *\n * @method formatOutputUReal\n * @param {String}\n * @returns {BigNumber} input bytes formatted to ureal\n */\nvar formatOutputUReal = function (value) {\n return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/**\n * Should be used to format output hash\n *\n * @method formatOutputHash\n * @param {String}\n * @returns {String} right-aligned output bytes formatted to hex\n */\nvar formatOutputHash = function (value) {\n return \"0x\" + value;\n};\n\n/**\n * Should be used to format output bool\n *\n * @method formatOutputBool\n * @param {String}\n * @returns {Boolean} right-aligned input bytes formatted to bool\n */\nvar formatOutputBool = function (value) {\n return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/**\n * Should be used to format output string\n *\n * @method formatOutputString\n * @param {Sttring} left-aligned hex representation of string\n * @returns {String} ascii string\n */\nvar formatOutputString = function (value) {\n return utils.toAscii(value);\n};\n\n/**\n * Should be used to format output address\n *\n * @method formatOutputAddress\n * @param {String} right-aligned input bytes\n * @returns {String} address\n */\nvar formatOutputAddress = function (value) {\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputString: formatInputString,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputHash: formatOutputHash,\n formatOutputBool: formatOutputBool,\n formatOutputString: formatOutputString,\n formatOutputAddress: formatOutputAddress\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file types.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar f = require('./formatters');\n\n/// @param expected type prefix (string)\n/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false\nvar prefixedType = function (prefix) {\n return function (type) {\n return type.indexOf(prefix) === 0;\n };\n};\n\n/// @param expected type name (string)\n/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false\nvar namedType = function (name) {\n return function (type) {\n return name === type;\n };\n};\n\n/// Setups input formatters for solidity types\n/// @returns an array of input formatters \nvar inputTypes = function () {\n \n return [\n { type: prefixedType('uint'), format: f.formatInputInt },\n { type: prefixedType('int'), format: f.formatInputInt },\n { type: prefixedType('bytes'), format: f.formatInputString }, \n { type: prefixedType('real'), format: f.formatInputReal },\n { type: prefixedType('ureal'), format: f.formatInputReal },\n { type: namedType('address'), format: f.formatInputInt },\n { type: namedType('bool'), format: f.formatInputBool }\n ];\n};\n\n/// Setups output formaters for solidity types\n/// @returns an array of output formatters\nvar outputTypes = function () {\n\n return [\n { type: prefixedType('uint'), format: f.formatOutputUInt },\n { type: prefixedType('int'), format: f.formatOutputInt },\n { type: prefixedType('bytes'), format: f.formatOutputString },\n { type: prefixedType('real'), format: f.formatOutputReal },\n { type: prefixedType('ureal'), format: f.formatOutputUReal },\n { type: namedType('address'), format: f.formatOutputAddress },\n { type: namedType('bool'), format: f.formatOutputBool }\n ];\n};\n\nmodule.exports = {\n prefixedType: prefixedType,\n namedType: namedType,\n inputTypes: inputTypes,\n outputTypes: outputTypes\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file utils.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Returns the contstructor with matching number of arguments\n *\n * @method getConstructor\n * @param {Array} abi\n * @param {Number} numberOfArgs\n * @returns {Object} constructor function abi\n */\nvar getConstructor = function (abi, numberOfArgs) {\n return abi.filter(function (f) {\n return f.type === 'constructor' && f.inputs.length === numberOfArgs;\n })[0];\n};\n\n/**\n * Filters all functions from input abi\n *\n * @method filterFunctions\n * @param {Array} abi\n * @returns {Array} abi array with filtered objects of type 'function'\n */\nvar filterFunctions = function (json) {\n return json.filter(function (current) {\n return current.type === 'function'; \n }); \n};\n\n/**\n * Filters all events from input abi\n *\n * @method filterEvents\n * @param {Array} abi\n * @returns {Array} abi array with filtered objects of type 'event'\n */\nvar filterEvents = function (json) {\n return json.filter(function (current) {\n return current.type === 'event';\n });\n};\n\nmodule.exports = {\n getConstructor: getConstructor,\n filterFunctions: filterFunctions,\n filterEvents: filterEvents\n};\n\n", "'use strict';\n\n// go env doesn't have and need XMLHttpRequest\nif (typeof XMLHttpRequest === 'undefined') {\n exports.XMLHttpRequest = {};\n} else {\n exports.XMLHttpRequest = XMLHttpRequest; // jshint ignore:line\n}\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file config.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] config\n * @constructor\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nvar BigNumber = require('bignumber.js');\n\nvar ETH_UNITS = [ \n 'wei', \n 'Kwei', \n 'Mwei', \n 'Gwei', \n 'szabo', \n 'finney', \n 'ether', \n 'grand', \n 'Mether', \n 'Gether', \n 'Tether', \n 'Pether', \n 'Eether', \n 'Zether', \n 'Yether', \n 'Nether', \n 'Dether', \n 'Vether', \n 'Uether' \n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },\n ETH_POLLING_TIMEOUT: 1000,\n ETH_DEFAULTBLOCK: 'latest'\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file utils.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] utils\n * @constructor\n */\n\nvar BigNumber = require('bignumber.js');\n\nvar unitMap = {\n 'wei': '1',\n 'kwei': '1000',\n 'ada': '1000',\n 'mwei': '1000000',\n 'babbage': '1000000',\n 'gwei': '1000000000',\n 'shannon': '1000000000',\n 'szabo': '1000000000000',\n 'finney': '1000000000000000',\n 'ether': '1000000000000000000',\n 'kether': '1000000000000000000000',\n 'grand': '1000000000000000000000',\n 'einstein': '1000000000000000000000',\n 'mether': '1000000000000000000000000',\n 'gether': '1000000000000000000000000000',\n 'tether': '1000000000000000000000000000000'\n};\n\n/**\n * Should be called to pad string to expected length\n *\n * @method padLeft\n * @param {String} string to be padded\n * @param {Number} characters that result string should have\n * @param {String} sign, by default 0\n * @returns {String} right aligned string\n */\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/** Finds first index of array element matching pattern\n *\n * @method findIndex\n * @param {Array}\n * @param {Function} pattern\n * @returns {Number} index of element\n */\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\n/** \n * Should be called to get sting from it's hex representation\n *\n * @method toAscii\n * @param {String} string in hex\n * @returns {String} ascii string representation of hex value\n */\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n if (code === 0) {\n break;\n }\n\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @returns {String} hex representation of input string\n */\nvar toHexNative = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @param {Number} optional padding\n * @returns {String} hex representation of input string\n */\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHexNative(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/**\n * Should be called to get display name of contract function\n * \n * @method extractDisplayName\n * @param {String} name of function/event\n * @returns {String} display name for function/event eg. multiply(uint256) -> multiply\n */\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/**\n * Filters all functions from input abi\n *\n * @method filterFunctions\n * @param {Array} abi\n * @returns {Array} abi array with filtered objects of type 'function'\n */\nvar filterFunctions = function (json) {\n return json.filter(function (current) {\n return current.type === 'function'; \n }); \n};\n\n/**\n * Filters all events from input abi\n *\n * @method filterEvents\n * @param {Array} abi\n * @returns {Array} abi array with filtered objects of type 'event'\n */\nvar filterEvents = function (json) {\n return json.filter(function (current) {\n return current.type === 'event';\n });\n};\n\n/**\n * Converts value to it's decimal representation in string\n *\n * @method toDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar toDecimal = function (value) {\n return toBigNumber(value).toNumber();\n};\n\n/**\n * Converts value to it's hex representation\n *\n * @method fromDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar fromDecimal = function (value) {\n var number = toBigNumber(value);\n var result = number.toString(16);\n\n return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result;\n};\n\n/**\n * Auto converts any given value into it's hex representation.\n *\n * And even stringifys objects before.\n *\n * @method toHex\n * @param {String|Number|BigNumber|Object}\n * @return {String}\n */\nvar toHex = function (val) {\n /*jshint maxcomplexity:7 */\n\n if (isBoolean(val))\n return fromDecimal(+val);\n\n if (isBigNumber(val))\n return fromDecimal(val);\n\n if (isObject(val))\n return fromAscii(JSON.stringify(val));\n\n // if its a negative number, pass it through fromDecimal\n if (isString(val)) {\n if (val.indexOf('-0x') === 0)\n return fromDecimal(val);\n else if (!isFinite(val))\n return fromAscii(val);\n }\n\n return fromDecimal(val);\n};\n\n/**\n * Returns value of unit in Wei\n *\n * @method getValueOfUnit\n * @param {String} unit the unit to convert to, default ether\n * @returns {BigNumber} value of the unit (in Wei)\n * @throws error if the unit is not correct:w\n */\nvar getValueOfUnit = function (unit) {\n unit = unit ? unit.toLowerCase() : 'ether';\n var unitValue = unitMap[unit];\n if (unitValue === undefined) {\n throw new Error('This unit doesn\\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2));\n }\n return new BigNumber(unitValue, 10);\n};\n\n/**\n * Takes a number of wei and converts it to any other ether unit.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method fromWei\n * @param {Number|String} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert to, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar fromWei = function(number, unit) {\n var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes a number of a unit and converts it to wei.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method toWei\n * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert from, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar toWei = function(number, unit) {\n var returnValue = toBigNumber(number).times(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes an input and transforms it into an bignumber\n *\n * @method toBigNumber\n * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber\n * @return {BigNumber} BigNumber\n*/\nvar toBigNumber = function(number) {\n /*jshint maxcomplexity:5 */\n number = number || 0;\n if (isBigNumber(number))\n return number;\n\n if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {\n return new BigNumber(number.replace('0x',''), 16);\n }\n \n return new BigNumber(number.toString(10), 10);\n};\n\n/**\n * Takes and input transforms it into bignumber and if it is negative value, into two's complement\n *\n * @method toTwosComplement\n * @param {Number|String|BigNumber}\n * @return {BigNumber}\n */\nvar toTwosComplement = function (number) {\n var bigNumber = toBigNumber(number);\n if (bigNumber.lessThan(0)) {\n return new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(bigNumber).plus(1);\n }\n return bigNumber;\n};\n\n/**\n * Checks if the given string has proper length\n *\n * @method isAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isAddress = function (address) {\n return /^0x[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Transforms given string to valid 20 bytes-length addres with 0x prefix\n *\n * @method toAddress\n * @param {String} address\n * @return {String} formatted address\n */\nvar toAddress = function (address) {\n if (isAddress(address)) {\n return address;\n }\n \n if (/^[0-9a-f]{40}$/.test(address)) {\n return '0x' + address;\n }\n\n return '0x' + padLeft(toHex(address).substr(2), 40);\n};\n\n/**\n * Returns true if object is BigNumber, otherwise false\n *\n * @method isBigNumber\n * @param {Object}\n * @return {Boolean} \n */\nvar isBigNumber = function (object) {\n return object instanceof BigNumber ||\n (object && object.constructor && object.constructor.name === 'BigNumber');\n};\n\n/**\n * Returns true if object is string, otherwise false\n * \n * @method isString\n * @param {Object}\n * @return {Boolean}\n */\nvar isString = function (object) {\n return typeof object === 'string' ||\n (object && object.constructor && object.constructor.name === 'String');\n};\n\n/**\n * Returns true if object is function, otherwise false\n *\n * @method isFunction\n * @param {Object}\n * @return {Boolean}\n */\nvar isFunction = function (object) {\n return typeof object === 'function';\n};\n\n/**\n * Returns true if object is Objet, otherwise false\n *\n * @method isObject\n * @param {Object}\n * @return {Boolean}\n */\nvar isObject = function (object) {\n return typeof object === 'object';\n};\n\n/**\n * Returns true if object is boolean, otherwise false\n *\n * @method isBoolean\n * @param {Object}\n * @return {Boolean}\n */\nvar isBoolean = function (object) {\n return typeof object === 'boolean';\n};\n\n/**\n * Returns true if object is array, otherwise false\n *\n * @method isArray\n * @param {Object}\n * @return {Boolean}\n */\nvar isArray = function (object) {\n return object instanceof Array; \n};\n\n/**\n * Returns true if given string is valid json object\n * \n * @method isJson\n * @param {String}\n * @return {Boolean}\n */\nvar isJson = function (str) {\n try {\n return !!JSON.parse(str);\n } catch (e) {\n return false;\n }\n};\n\nmodule.exports = {\n padLeft: padLeft,\n findIndex: findIndex,\n toHex: toHex,\n toDecimal: toDecimal,\n fromDecimal: fromDecimal,\n toAscii: toAscii,\n fromAscii: fromAscii,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n filterFunctions: filterFunctions,\n filterEvents: filterEvents,\n toWei: toWei,\n fromWei: fromWei,\n toBigNumber: toBigNumber,\n toTwosComplement: toTwosComplement,\n toAddress: toAddress,\n isBigNumber: isBigNumber,\n isAddress: isAddress,\n isFunction: isFunction,\n isString: isString,\n isObject: isObject,\n isBoolean: isBoolean,\n isArray: isArray,\n isJson: isJson\n};\n\n", - "module.exports={\n \"version\": \"0.2.5\"\n}\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar version = require('./version.json');\nvar net = require('./web3/net');\nvar eth = require('./web3/eth');\nvar db = require('./web3/db');\nvar shh = require('./web3/shh');\nvar watches = require('./web3/watches');\nvar Filter = require('./web3/filter');\nvar utils = require('./utils/utils');\nvar formatters = require('./web3/formatters');\nvar RequestManager = require('./web3/requestmanager');\nvar c = require('./utils/config');\nvar Method = require('./web3/method');\nvar Property = require('./web3/property');\n\nvar web3Methods = [\n new Method({\n name: 'sha3',\n call: 'web3_sha3',\n params: 1\n })\n];\n\nvar web3Properties = [\n new Property({\n name: 'version.client',\n getter: 'web3_clientVersion'\n }),\n new Property({\n name: 'version.network',\n getter: 'net_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.ethereum',\n getter: 'eth_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.whisper',\n getter: 'shh_version',\n inputFormatter: utils.toDecimal\n })\n];\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n method.attachToObject(obj);\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n property.attachToObject(obj);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {};\nweb3.providers = {};\nweb3.version = {};\nweb3.version.api = version.version;\nweb3.eth = {};\n\n/*jshint maxparams:4 */\nweb3.eth.filter = function (fil, eventParams, options, formatter) {\n\n // if its event, treat it differently\n // TODO: simplify and remove\n if (fil._isEvent) {\n return fil(eventParams, options);\n }\n\n // what outputLogFormatter? that's wrong\n //return new Filter(fil, watches.eth(), formatters.outputLogFormatter);\n return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);\n};\n/*jshint maxparams:3 */\n\nweb3.shh = {};\nweb3.shh.filter = function (fil) {\n return new Filter(fil, watches.shh(), formatters.outputPostFormatter);\n};\nweb3.net = {};\nweb3.db = {};\nweb3.setProvider = function (provider) {\n RequestManager.getInstance().setProvider(provider);\n};\nweb3.reset = function () {\n RequestManager.getInstance().reset();\n};\nweb3.toHex = utils.toHex;\nweb3.toAscii = utils.toAscii;\nweb3.fromAscii = utils.fromAscii;\nweb3.toDecimal = utils.toDecimal;\nweb3.fromDecimal = utils.fromDecimal;\nweb3.toBigNumber = utils.toBigNumber;\nweb3.toWei = utils.toWei;\nweb3.fromWei = utils.fromWei;\nweb3.isAddress = utils.isAddress;\n\n// ADD defaultblock\nObject.defineProperty(web3.eth, 'defaultBlock', {\n get: function () {\n return c.ETH_DEFAULTBLOCK;\n },\n set: function (val) {\n c.ETH_DEFAULTBLOCK = val;\n return c.ETH_DEFAULTBLOCK;\n }\n});\n\n\n/// setups all api methods\nsetupMethods(web3, web3Methods);\nsetupProperties(web3, web3Properties);\nsetupMethods(web3.net, net.methods);\nsetupProperties(web3.net, net.properties);\nsetupMethods(web3.eth, eth.methods);\nsetupProperties(web3.eth, eth.properties);\nsetupMethods(web3.db, db.methods);\nsetupMethods(web3.shh, shh.methods);\n\nmodule.exports = web3;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('../web3'); \nvar abi = require('../solidity/abi');\nvar utils = require('../utils/utils');\nvar eventImpl = require('./event');\nvar signature = require('./signature');\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransaction = false;\n contract._options = options;\n return contract;\n };\n\n contract.sendTransaction = function (options) {\n contract._isTransaction = true;\n contract._options = options;\n return contract;\n };\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n // create contract functions\n utils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n /*jshint maxcomplexity:7 */\n var params = Array.prototype.slice.call(arguments);\n var sign = signature.functionSignatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = sign + parsed;\n \n var isTransaction = contract._isTransaction === true || (contract._isTransaction !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransaction = null;\n\n if (isTransaction) {\n \n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.sendTransaction(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topics', {\n get: function() {\n return utils.filterEvents(desc).map(function (e) {\n return signature.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n utils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var sign = signature.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, sign, e);\n var o = event.apply(null, params);\n var outputFormatter = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.filter(o, undefined, undefined, outputFormatter);\n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var MyContract = web3.eth.contract(abi); // creation of contract prototype\n *\n * var contractInstance = new MyContract('0x0123123121');\n *\n * contractInstance.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * contractInstance.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * contractInstance.sendTransaction().myMethod('this is test string param for transact'); // myMethod sendTransaction\n *\n * @param abi - abi json description of the contract, which is being created\n * @returns contract object\n */\nvar contract = function (abi) {\n\n // return prototype\n return Contract.bind(null, abi);\n};\n\nfunction Contract(abi, address) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n abi.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, abi, address);\n addEventRelatedPropertiesToContract(result, abi, address);\n addEventsToContract(result, abi, address);\n\n return result;\n}\n\nmodule.exports = contract;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file utils.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] utils\n * @constructor\n */\n\nvar BigNumber = require('bignumber.js');\n\nvar unitMap = {\n 'wei': '1',\n 'kwei': '1000',\n 'ada': '1000',\n 'mwei': '1000000',\n 'babbage': '1000000',\n 'gwei': '1000000000',\n 'shannon': '1000000000',\n 'szabo': '1000000000000',\n 'finney': '1000000000000000',\n 'ether': '1000000000000000000',\n 'kether': '1000000000000000000000',\n 'grand': '1000000000000000000000',\n 'einstein': '1000000000000000000000',\n 'mether': '1000000000000000000000000',\n 'gether': '1000000000000000000000000000',\n 'tether': '1000000000000000000000000000000'\n};\n\n/**\n * Should be called to pad string to expected length\n *\n * @method padLeft\n * @param {String} string to be padded\n * @param {Number} characters that result string should have\n * @param {String} sign, by default 0\n * @returns {String} right aligned string\n */\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/** Finds first index of array element matching pattern\n *\n * @method findIndex\n * @param {Array}\n * @param {Function} pattern\n * @returns {Number} index of element\n */\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\n/** \n * Should be called to get sting from it's hex representation\n *\n * @method toAscii\n * @param {String} string in hex\n * @returns {String} ascii string representation of hex value\n */\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n if (code === 0) {\n break;\n }\n\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @returns {String} hex representation of input string\n */\nvar toHexNative = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @param {Number} optional padding\n * @returns {String} hex representation of input string\n */\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHexNative(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/**\n * Should be called to get display name of contract function\n * \n * @method extractDisplayName\n * @param {String} name of function/event\n * @returns {String} display name for function/event eg. multiply(uint256) -> multiply\n */\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/**\n * Converts value to it's decimal representation in string\n *\n * @method toDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar toDecimal = function (value) {\n return toBigNumber(value).toNumber();\n};\n\n/**\n * Converts value to it's hex representation\n *\n * @method fromDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar fromDecimal = function (value) {\n var number = toBigNumber(value);\n var result = number.toString(16);\n\n return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result;\n};\n\n/**\n * Auto converts any given value into it's hex representation.\n *\n * And even stringifys objects before.\n *\n * @method toHex\n * @param {String|Number|BigNumber|Object}\n * @return {String}\n */\nvar toHex = function (val) {\n /*jshint maxcomplexity:7 */\n\n if (isBoolean(val))\n return fromDecimal(+val);\n\n if (isBigNumber(val))\n return fromDecimal(val);\n\n if (isObject(val))\n return fromAscii(JSON.stringify(val));\n\n // if its a negative number, pass it through fromDecimal\n if (isString(val)) {\n if (val.indexOf('-0x') === 0)\n return fromDecimal(val);\n else if (!isFinite(val))\n return fromAscii(val);\n }\n\n return fromDecimal(val);\n};\n\n/**\n * Returns value of unit in Wei\n *\n * @method getValueOfUnit\n * @param {String} unit the unit to convert to, default ether\n * @returns {BigNumber} value of the unit (in Wei)\n * @throws error if the unit is not correct:w\n */\nvar getValueOfUnit = function (unit) {\n unit = unit ? unit.toLowerCase() : 'ether';\n var unitValue = unitMap[unit];\n if (unitValue === undefined) {\n throw new Error('This unit doesn\\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2));\n }\n return new BigNumber(unitValue, 10);\n};\n\n/**\n * Takes a number of wei and converts it to any other ether unit.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method fromWei\n * @param {Number|String} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert to, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar fromWei = function(number, unit) {\n var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes a number of a unit and converts it to wei.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method toWei\n * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert from, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar toWei = function(number, unit) {\n var returnValue = toBigNumber(number).times(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes an input and transforms it into an bignumber\n *\n * @method toBigNumber\n * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber\n * @return {BigNumber} BigNumber\n*/\nvar toBigNumber = function(number) {\n /*jshint maxcomplexity:5 */\n number = number || 0;\n if (isBigNumber(number))\n return number;\n\n if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {\n return new BigNumber(number.replace('0x',''), 16);\n }\n \n return new BigNumber(number.toString(10), 10);\n};\n\n/**\n * Takes and input transforms it into bignumber and if it is negative value, into two's complement\n *\n * @method toTwosComplement\n * @param {Number|String|BigNumber}\n * @return {BigNumber}\n */\nvar toTwosComplement = function (number) {\n var bigNumber = toBigNumber(number);\n if (bigNumber.lessThan(0)) {\n return new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(bigNumber).plus(1);\n }\n return bigNumber;\n};\n\n/**\n * Checks if the given string is strictly an address\n *\n * @method isStrictAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isStrictAddress = function (address) {\n return /^0x[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Checks if the given string is an address\n *\n * @method isAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isAddress = function (address) {\n return /^(0x)?[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Transforms given string to valid 20 bytes-length addres with 0x prefix\n *\n * @method toAddress\n * @param {String} address\n * @return {String} formatted address\n */\nvar toAddress = function (address) {\n if (isStrictAddress(address)) {\n return address;\n }\n \n if (/^[0-9a-f]{40}$/.test(address)) {\n return '0x' + address;\n }\n\n return '0x' + padLeft(toHex(address).substr(2), 40);\n};\n\n/**\n * Returns true if object is BigNumber, otherwise false\n *\n * @method isBigNumber\n * @param {Object}\n * @return {Boolean} \n */\nvar isBigNumber = function (object) {\n return object instanceof BigNumber ||\n (object && object.constructor && object.constructor.name === 'BigNumber');\n};\n\n/**\n * Returns true if object is string, otherwise false\n * \n * @method isString\n * @param {Object}\n * @return {Boolean}\n */\nvar isString = function (object) {\n return typeof object === 'string' ||\n (object && object.constructor && object.constructor.name === 'String');\n};\n\n/**\n * Returns true if object is function, otherwise false\n *\n * @method isFunction\n * @param {Object}\n * @return {Boolean}\n */\nvar isFunction = function (object) {\n return typeof object === 'function';\n};\n\n/**\n * Returns true if object is Objet, otherwise false\n *\n * @method isObject\n * @param {Object}\n * @return {Boolean}\n */\nvar isObject = function (object) {\n return typeof object === 'object';\n};\n\n/**\n * Returns true if object is boolean, otherwise false\n *\n * @method isBoolean\n * @param {Object}\n * @return {Boolean}\n */\nvar isBoolean = function (object) {\n return typeof object === 'boolean';\n};\n\n/**\n * Returns true if object is array, otherwise false\n *\n * @method isArray\n * @param {Object}\n * @return {Boolean}\n */\nvar isArray = function (object) {\n return object instanceof Array; \n};\n\n/**\n * Returns true if given string is valid json object\n * \n * @method isJson\n * @param {String}\n * @return {Boolean}\n */\nvar isJson = function (str) {\n try {\n return !!JSON.parse(str);\n } catch (e) {\n return false;\n }\n};\n\nmodule.exports = {\n padLeft: padLeft,\n findIndex: findIndex,\n toHex: toHex,\n toDecimal: toDecimal,\n fromDecimal: fromDecimal,\n toAscii: toAscii,\n fromAscii: fromAscii,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n toWei: toWei,\n fromWei: fromWei,\n toBigNumber: toBigNumber,\n toTwosComplement: toTwosComplement,\n toAddress: toAddress,\n isBigNumber: isBigNumber,\n isStrictAddress: isStrictAddress,\n isAddress: isAddress,\n isFunction: isFunction,\n isString: isString,\n isObject: isObject,\n isBoolean: isBoolean,\n isArray: isArray,\n isJson: isJson\n};\n\n", + "module.exports={\n \"version\": \"0.2.6\"\n}\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar version = require('./version.json');\nvar net = require('./web3/net');\nvar eth = require('./web3/eth');\nvar db = require('./web3/db');\nvar shh = require('./web3/shh');\nvar watches = require('./web3/watches');\nvar Filter = require('./web3/filter');\nvar utils = require('./utils/utils');\nvar formatters = require('./web3/formatters');\nvar RequestManager = require('./web3/requestmanager');\nvar c = require('./utils/config');\nvar Method = require('./web3/method');\nvar Property = require('./web3/property');\n\nvar web3Methods = [\n new Method({\n name: 'sha3',\n call: 'web3_sha3',\n params: 1\n })\n];\n\nvar web3Properties = [\n new Property({\n name: 'version.client',\n getter: 'web3_clientVersion'\n }),\n new Property({\n name: 'version.network',\n getter: 'net_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.ethereum',\n getter: 'eth_protocolVersion',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.whisper',\n getter: 'shh_version',\n inputFormatter: utils.toDecimal\n })\n];\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n method.attachToObject(obj);\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n property.attachToObject(obj);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {};\nweb3.providers = {};\nweb3.version = {};\nweb3.version.api = version.version;\nweb3.eth = {};\n\n/*jshint maxparams:4 */\nweb3.eth.filter = function (fil, eventParams, options, formatter) {\n\n // if its event, treat it differently\n // TODO: simplify and remove\n if (fil._isEvent) {\n return fil(eventParams, options);\n }\n\n // what outputLogFormatter? that's wrong\n //return new Filter(fil, watches.eth(), formatters.outputLogFormatter);\n return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);\n};\n/*jshint maxparams:3 */\n\nweb3.shh = {};\nweb3.shh.filter = function (fil) {\n return new Filter(fil, watches.shh(), formatters.outputPostFormatter);\n};\nweb3.net = {};\nweb3.db = {};\nweb3.setProvider = function (provider) {\n RequestManager.getInstance().setProvider(provider);\n};\nweb3.reset = function () {\n RequestManager.getInstance().reset();\n};\nweb3.toHex = utils.toHex;\nweb3.toAscii = utils.toAscii;\nweb3.fromAscii = utils.fromAscii;\nweb3.toDecimal = utils.toDecimal;\nweb3.fromDecimal = utils.fromDecimal;\nweb3.toBigNumber = utils.toBigNumber;\nweb3.toWei = utils.toWei;\nweb3.fromWei = utils.fromWei;\nweb3.isAddress = utils.isAddress;\n\n// ADD defaultblock\nObject.defineProperty(web3.eth, 'defaultBlock', {\n get: function () {\n return c.ETH_DEFAULTBLOCK;\n },\n set: function (val) {\n c.ETH_DEFAULTBLOCK = val;\n return c.ETH_DEFAULTBLOCK;\n }\n});\n\n\n/// setups all api methods\nsetupMethods(web3, web3Methods);\nsetupProperties(web3, web3Properties);\nsetupMethods(web3.net, net.methods);\nsetupProperties(web3.net, net.properties);\nsetupMethods(web3.eth, eth.methods);\nsetupProperties(web3.eth, eth.properties);\nsetupMethods(web3.db, db.methods);\nsetupMethods(web3.shh, shh.methods);\n\nmodule.exports = web3;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('../web3'); \nvar solAbi = require('../solidity/abi');\nvar utils = require('../utils/utils');\nvar solUtils = require('../solidity/utils');\nvar eventImpl = require('./event');\nvar signature = require('./signature');\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransaction = false;\n contract._options = options;\n return contract;\n };\n\n contract.sendTransaction = function (options) {\n contract._isTransaction = true;\n contract._options = options;\n return contract;\n };\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = solAbi.inputParser(desc);\n var outputParser = solAbi.outputParser(desc);\n\n // create contract functions\n solUtils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n /*jshint maxcomplexity:7 */\n var params = Array.prototype.slice.call(arguments);\n var sign = signature.functionSignatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = sign + parsed;\n \n var isTransaction = contract._isTransaction === true || (contract._isTransaction !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransaction = null;\n\n if (isTransaction) {\n \n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.sendTransaction(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(solUtils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topics', {\n get: function() {\n return solUtils.filterEvents(desc).map(function (e) {\n return signature.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n solUtils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var sign = signature.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, sign, e);\n var o = event.apply(null, params);\n var outputFormatter = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.filter(o, undefined, undefined, outputFormatter);\n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var MyContract = web3.eth.contract(abi); // creation of contract prototype\n *\n * var contractInstance = new MyContract('0x0123123121');\n *\n * contractInstance.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * contractInstance.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * contractInstance.sendTransaction().myMethod('this is test string param for transact'); // myMethod sendTransaction\n *\n * @param abi - abi json description of the contract, which is being created\n * @returns contract object\n */\nvar contract = function (abi) {\n\n // return prototype\n return Contract.bind(null, abi);\n};\n\nfunction Contract(abi, options) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n abi.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var address = '';\n if (utils.isAddress(options)) {\n address = options;\n } else { // is a source code!\n // TODO, parse the rest of the args\n var code = options;\n var args = Array.prototype.slice.call(arguments, 2);\n var bytes = solAbi.formatConstructorParams(abi, args);\n address = web3.eth.sendTransaction({data: code + bytes});\n }\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, abi, address);\n addEventRelatedPropertiesToContract(result, abi, address);\n addEventsToContract(result, abi, address);\n\n return result;\n}\n\nmodule.exports = contract;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file db.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\nvar putString = new Method({\n name: 'putString',\n call: 'db_putString',\n params: 3\n});\n\n\nvar getString = new Method({\n name: 'getString',\n call: 'db_getString',\n params: 2\n});\n\nvar putHex = new Method({\n name: 'putHex',\n call: 'db_putHex',\n params: 3\n});\n\nvar getHex = new Method({\n name: 'getHex',\n call: 'db_getHex',\n params: 2\n});\n\nvar methods = [\n putString, getString, putHex, getHex\n];\n\nmodule.exports = {\n methods: methods\n};\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file errors.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\n\nmodule.exports = {\n InvalidNumberOfParams: new Error('Invalid number of input parameters'),\n InvalidProvider: new Error('Providor not set or invalid'),\n InvalidResponse: function(result){\n var message = 'Invalid JSON RPC response';\n\n if(utils.isObject(result) && result.error && result.error.message) {\n message = result.error.message;\n }\n\n return new Error(message);\n }\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file eth.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\n/**\n * Web3\n * \n * @module web3\n */\n\n/**\n * Eth methods and properties\n *\n * An example method object can look as follows:\n *\n * {\n * name: 'getBlock',\n * call: blockCall,\n * params: 2,\n * outputFormatter: formatters.outputBlockFormatter,\n * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter\n * utils.toHex, // formats paramter 1\n * function(param){ return !!param; } // formats paramter 2\n * ]\n * },\n *\n * @class [web3] eth\n * @constructor\n */\n\n\"use strict\";\n\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Method = require('./method');\nvar Property = require('./property');\n\nvar blockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? \"eth_getBlockByHash\" : \"eth_getBlockByNumber\";\n};\n\nvar transactionFromBlockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';\n};\n\nvar uncleCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';\n};\n\nvar getBlockTransactionCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';\n};\n\nvar uncleCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';\n};\n\n/// @returns an array of objects describing web3.eth api methods\n\nvar getBalance = new Method({\n name: 'getBalance', \n call: 'eth_getBalance', \n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: formatters.outputBigNumberFormatter\n});\n\nvar getStorageAt = new Method({\n name: 'getStorageAt', \n call: 'eth_getStorageAt', \n params: 3,\n inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getCode = new Method({\n name: 'getCode',\n call: 'eth_getCode',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getBlock = new Method({\n name: 'getBlock', \n call: blockCall,\n params: 2,\n inputFormatter: [utils.toHex, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter\n});\n\nvar getUncle = new Method({\n name: 'getUncle',\n call: uncleCall,\n params: 3,\n inputFormatter: [utils.toHex, utils.toHex, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter,\n\n});\n\nvar getCompilers = new Method({\n name: 'getCompilers',\n call: 'eth_getCompilers',\n params: 0\n});\n\nvar getBlockTransactionCount = new Method({\n name: 'getBlockTransactionCount',\n call: getBlockTransactionCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getBlockUncleCount = new Method({\n name: 'getBlockUncleCount',\n call: uncleCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getTransaction = new Method({\n name: 'getTransaction',\n call: 'eth_getTransactionByHash',\n params: 1,\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionFromBlock = new Method({\n name: 'getTransactionFromBlock',\n call: transactionFromBlockCall,\n params: 2,\n inputFormatter: [utils.toHex, utils.toHex],\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionCount = new Method({\n name: 'getTransactionCount',\n call: 'eth_getTransactionCount',\n params: 2,\n inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar sendTransaction = new Method({\n name: 'sendTransaction',\n call: 'eth_sendTransaction',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter]\n});\n\nvar call = new Method({\n name: 'call',\n call: 'eth_call',\n params: 2,\n inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar compileSolidity = new Method({\n name: 'compile.solidity',\n call: 'eth_compileSolidity',\n params: 1\n});\n\nvar compileLLL = new Method({\n name: 'compile.lll',\n call: 'eth_compileLLL',\n params: 1\n});\n\nvar compileSerpent = new Method({\n name: 'compile.serpent',\n call: 'eth_compileSerpent',\n params: 1\n});\n\nvar flush = new Method({\n name: 'flush',\n call: 'eth_flush',\n params: 0\n});\n\nvar methods = [\n getBalance,\n getStorageAt,\n getCode,\n getBlock,\n getUncle,\n getCompilers,\n getBlockTransactionCount,\n getBlockUncleCount,\n getTransaction,\n getTransactionFromBlock,\n getTransactionCount,\n call,\n sendTransaction,\n compileSolidity,\n compileLLL,\n compileSerpent,\n flush\n];\n\n/// @returns an array of objects describing web3.eth api properties\n\n\n\nvar properties = [\n new Property({\n name: 'coinbase',\n getter: 'eth_coinbase'\n }),\n new Property({\n name: 'mining',\n getter: 'eth_mining'\n }),\n new Property({\n name: 'gasPrice',\n getter: 'eth_gasPrice',\n outputFormatter: formatters.inputNumberFormatter\n }),\n new Property({\n name: 'accounts',\n getter: 'eth_accounts'\n }),\n new Property({\n name: 'blockNumber',\n getter: 'eth_blockNumber',\n outputFormatter: utils.toDecimal\n })\n];\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file eth.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\n/**\n * Web3\n * \n * @module web3\n */\n\n/**\n * Eth methods and properties\n *\n * An example method object can look as follows:\n *\n * {\n * name: 'getBlock',\n * call: blockCall,\n * params: 2,\n * outputFormatter: formatters.outputBlockFormatter,\n * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter\n * utils.toHex, // formats paramter 1\n * function(param){ return !!param; } // formats paramter 2\n * ]\n * },\n *\n * @class [web3] eth\n * @constructor\n */\n\n\"use strict\";\n\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Method = require('./method');\nvar Property = require('./property');\n\nvar blockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? \"eth_getBlockByHash\" : \"eth_getBlockByNumber\";\n};\n\nvar transactionFromBlockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';\n};\n\nvar uncleCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';\n};\n\nvar getBlockTransactionCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';\n};\n\nvar uncleCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';\n};\n\n/// @returns an array of objects describing web3.eth api methods\n\nvar getBalance = new Method({\n name: 'getBalance', \n call: 'eth_getBalance', \n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: formatters.outputBigNumberFormatter\n});\n\nvar getStorageAt = new Method({\n name: 'getStorageAt', \n call: 'eth_getStorageAt', \n params: 3,\n inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getCode = new Method({\n name: 'getCode',\n call: 'eth_getCode',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getBlock = new Method({\n name: 'getBlock', \n call: blockCall,\n params: 2,\n inputFormatter: [utils.toHex, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter\n});\n\nvar getUncle = new Method({\n name: 'getUncle',\n call: uncleCall,\n params: 2,\n inputFormatter: [utils.toHex, utils.toHex],\n outputFormatter: formatters.outputBlockFormatter,\n\n});\n\nvar getCompilers = new Method({\n name: 'getCompilers',\n call: 'eth_getCompilers',\n params: 0\n});\n\nvar getBlockTransactionCount = new Method({\n name: 'getBlockTransactionCount',\n call: getBlockTransactionCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getBlockUncleCount = new Method({\n name: 'getBlockUncleCount',\n call: uncleCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getTransaction = new Method({\n name: 'getTransaction',\n call: 'eth_getTransactionByHash',\n params: 1,\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionFromBlock = new Method({\n name: 'getTransactionFromBlock',\n call: transactionFromBlockCall,\n params: 2,\n inputFormatter: [utils.toHex, utils.toHex],\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionCount = new Method({\n name: 'getTransactionCount',\n call: 'eth_getTransactionCount',\n params: 2,\n inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar sendTransaction = new Method({\n name: 'sendTransaction',\n call: 'eth_sendTransaction',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter]\n});\n\nvar call = new Method({\n name: 'call',\n call: 'eth_call',\n params: 2,\n inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar compileSolidity = new Method({\n name: 'compile.solidity',\n call: 'eth_compileSolidity',\n params: 1\n});\n\nvar compileLLL = new Method({\n name: 'compile.lll',\n call: 'eth_compileLLL',\n params: 1\n});\n\nvar compileSerpent = new Method({\n name: 'compile.serpent',\n call: 'eth_compileSerpent',\n params: 1\n});\n\nvar flush = new Method({\n name: 'flush',\n call: 'eth_flush',\n params: 0\n});\n\nvar methods = [\n getBalance,\n getStorageAt,\n getCode,\n getBlock,\n getUncle,\n getCompilers,\n getBlockTransactionCount,\n getBlockUncleCount,\n getTransaction,\n getTransactionFromBlock,\n getTransactionCount,\n call,\n sendTransaction,\n compileSolidity,\n compileLLL,\n compileSerpent,\n flush\n];\n\n/// @returns an array of objects describing web3.eth api properties\n\n\n\nvar properties = [\n new Property({\n name: 'coinbase',\n getter: 'eth_coinbase'\n }),\n new Property({\n name: 'mining',\n getter: 'eth_mining'\n }),\n new Property({\n name: 'gasPrice',\n getter: 'eth_gasPrice',\n outputFormatter: formatters.outputBigNumberFormatter\n }),\n new Property({\n name: 'accounts',\n getter: 'eth_accounts'\n }),\n new Property({\n name: 'blockNumber',\n getter: 'eth_blockNumber',\n outputFormatter: utils.toDecimal\n })\n];\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('../solidity/abi');\nvar utils = require('../utils/utils');\nvar signature = require('./signature');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return '0x' + abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, sign, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.filter'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topics = [];\n o.topics.push(sign);\n if (indexed) {\n o.topics = o.topics.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexedCopy.splice(0, 1)[0];\n else\n value = notIndexedCopy.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n hash: output.hash,\n args: {}\n };\n\n if (!output.topics) {\n return result;\n }\n output.data = output.data || '';\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topics.slice(1, output.topics.length).map(function (topics) { return topics.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var sign = signature.eventSignatureFromAscii(events[i].name); \n if (sign === payload.topics[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar RequestManager = require('./requestmanager');\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n\n if (utils.isString(options)) {\n return options;\n } \n\n options = options || {};\n\n // make sure topics, get converted to hex\n options.topics = options.topics || [];\n options.topics = options.topics.map(function(topic){\n return utils.toHex(topic);\n });\n\n // lazy load\n return {\n topics: options.topics,\n to: options.to,\n address: options.address,\n fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),\n toBlock: formatters.inputBlockNumberFormatter(options.toBlock) \n }; \n};\n\nvar Filter = function (options, methods, formatter) {\n var implementation = {};\n methods.forEach(function (method) {\n method.attachToObject(implementation);\n });\n this.options = getOptions(options);\n this.implementation = implementation;\n this.callbacks = [];\n this.formatter = formatter;\n this.filterId = this.implementation.newFilter(this.options);\n};\n\nFilter.prototype.watch = function (callback) {\n this.callbacks.push(callback);\n var self = this;\n\n var onMessage = function (error, messages) {\n if (error) {\n return self.callbacks.forEach(function (callback) {\n callback(error);\n });\n }\n\n messages.forEach(function (message) {\n message = self.formatter ? self.formatter(message) : message;\n self.callbacks.forEach(function (callback) {\n callback(null, message);\n });\n });\n };\n\n RequestManager.getInstance().startPolling({\n method: this.implementation.poll.call,\n params: [this.filterId],\n }, this.filterId, onMessage, this.stopWatching.bind(this));\n};\n\nFilter.prototype.stopWatching = function () {\n RequestManager.getInstance().stopPolling(this.filterId);\n this.implementation.uninstallFilter(this.filterId);\n this.callbacks = [];\n};\n\nFilter.prototype.get = function () {\n var logs = this.implementation.getLogs(this.filterId);\n var self = this;\n return logs.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n });\n};\n\nmodule.exports = Filter;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file formatters.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar config = require('../utils/config');\n\n/**\n * Should the format output to a big number\n *\n * @method outputBigNumberFormatter\n * @param {String|Number|BigNumber}\n * @returns {BigNumber} object\n */\nvar outputBigNumberFormatter = function (number) {\n return utils.toBigNumber(number);\n};\n\nvar isPredefinedBlockNumber = function (blockNumber) {\n return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest';\n};\n\nvar inputDefaultBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return config.ETH_DEFAULTBLOCK;\n }\n return inputBlockNumberFormatter(blockNumber);\n};\n\nvar inputBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return undefined;\n } else if (isPredefinedBlockNumber(blockNumber)) {\n return blockNumber;\n }\n return utils.toHex(blockNumber);\n};\n\n/**\n * Formats the input of a transaction and converts all values to HEX\n *\n * @method inputTransactionFormatter\n * @param {Object} transaction options\n * @returns object\n*/\nvar inputTransactionFormatter = function (options){\n\n // make code -> data\n if (options.code) {\n options.data = options.code;\n delete options.code;\n }\n\n ['gasPrice', 'gas', 'value'].filter(function (key) {\n return options[key] !== undefined;\n }).forEach(function(key){\n options[key] = utils.fromDecimal(options[key]);\n });\n\n return options; \n};\n\n/**\n * Formats the output of a transaction to its proper values\n * \n * @method outputTransactionFormatter\n * @param {Object} transaction\n * @returns {Object} transaction\n*/\nvar outputTransactionFormatter = function (tx){\n tx.blockNumber = utils.toDecimal(tx.blockNumber);\n tx.transactionIndex = utils.toDecimal(tx.transactionIndex);\n tx.gas = utils.toDecimal(tx.gas);\n tx.gasPrice = utils.toBigNumber(tx.gasPrice);\n tx.value = utils.toBigNumber(tx.value);\n return tx;\n};\n\n/**\n * Formats the output of a block to its proper values\n *\n * @method outputBlockFormatter\n * @param {Object} block object \n * @returns {Object} block object\n*/\nvar outputBlockFormatter = function(block) {\n\n // transform to number\n block.gasLimit = utils.toDecimal(block.gasLimit);\n block.gasUsed = utils.toDecimal(block.gasUsed);\n block.size = utils.toDecimal(block.size);\n block.timestamp = utils.toDecimal(block.timestamp);\n block.number = utils.toDecimal(block.number);\n\n block.minGasPrice = utils.toBigNumber(block.minGasPrice);\n block.difficulty = utils.toBigNumber(block.difficulty);\n block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);\n\n if (utils.isArray(block.transactions)) {\n block.transactions.forEach(function(item){\n if(!utils.isString(item))\n return outputTransactionFormatter(item);\n });\n }\n\n return block;\n};\n\n/**\n * Formats the output of a log\n * \n * @method outputLogFormatter\n * @param {Object} log object\n * @returns {Object} log\n*/\nvar outputLogFormatter = function(log) {\n if (log === null) { // 'pending' && 'latest' filters are nulls\n return null;\n }\n\n log.blockNumber = utils.toDecimal(log.blockNumber);\n log.transactionIndex = utils.toDecimal(log.transactionIndex);\n log.logIndex = utils.toDecimal(log.logIndex);\n\n return log;\n};\n\n/**\n * Formats the input of a whisper post and converts all values to HEX\n *\n * @method inputPostFormatter\n * @param {Object} transaction object\n * @returns {Object}\n*/\nvar inputPostFormatter = function(post) {\n\n post.payload = utils.toHex(post.payload);\n post.ttl = utils.fromDecimal(post.ttl);\n post.priority = utils.fromDecimal(post.priority);\n\n if(!utils.isArray(post.topics)) {\n post.topics = [post.topics];\n }\n\n // format the following options\n post.topics = post.topics.map(function(topic){\n return utils.fromAscii(topic);\n });\n\n return post; \n};\n\n/**\n * Formats the output of a received post message\n *\n * @method outputPostFormatter\n * @param {Object}\n * @returns {Object}\n */\nvar outputPostFormatter = function(post){\n\n post.expiry = utils.toDecimal(post.expiry);\n post.sent = utils.toDecimal(post.sent);\n post.ttl = utils.toDecimal(post.ttl);\n post.workProved = utils.toDecimal(post.workProved);\n post.payloadRaw = post.payload;\n post.payload = utils.toAscii(post.payload);\n\n if (utils.isJson(post.payload)) {\n post.payload = JSON.parse(post.payload);\n }\n\n // format the following options\n post.topics = post.topics.map(function(topic){\n return utils.toAscii(topic);\n });\n\n return post;\n};\n\nmodule.exports = {\n inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,\n inputBlockNumberFormatter: inputBlockNumberFormatter,\n inputTransactionFormatter: inputTransactionFormatter,\n inputPostFormatter: inputPostFormatter,\n outputBigNumberFormatter: outputBigNumberFormatter,\n outputTransactionFormatter: outputTransactionFormatter,\n outputBlockFormatter: outputBlockFormatter,\n outputLogFormatter: outputLogFormatter,\n outputPostFormatter: outputPostFormatter\n};\n\n", @@ -64,6 +66,6 @@ "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file watches.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\n/// @returns an array of objects describing web3.eth.filter api methods\nvar eth = function () {\n var newFilterCall = function (args) {\n return typeof args[0] === 'string' ? 'eth_newBlockFilter' : 'eth_newFilter';\n };\n\n var newFilter = new Method({\n name: 'newFilter',\n call: newFilterCall,\n params: 1\n });\n\n var uninstallFilter = new Method({\n name: 'uninstallFilter',\n call: 'eth_uninstallFilter',\n params: 1\n });\n\n var getLogs = new Method({\n name: 'getLogs',\n call: 'eth_getFilterLogs',\n params: 1\n });\n\n var poll = new Method({\n name: 'poll',\n call: 'eth_getFilterChanges',\n params: 1\n });\n\n return [\n newFilter,\n uninstallFilter,\n getLogs,\n poll\n ];\n};\n\n/// @returns an array of objects describing web3.shh.watch api methods\nvar shh = function () {\n var newFilter = new Method({\n name: 'newFilter',\n call: 'shh_newFilter',\n params: 1\n });\n\n var uninstallFilter = new Method({\n name: 'uninstallFilter',\n call: 'shh_uninstallFilter',\n params: 1\n });\n\n var getLogs = new Method({\n name: 'getLogs',\n call: 'shh_getMessages',\n params: 1\n });\n\n var poll = new Method({\n name: 'poll',\n call: 'shh_getFilterChanges',\n params: 1\n });\n\n return [\n newFilter,\n uninstallFilter,\n getLogs,\n poll\n ];\n};\n\nmodule.exports = {\n eth: eth,\n shh: shh\n};\n\n", null, "'use strict';\n\nmodule.exports = BigNumber; // jshint ignore:line\n\n", - "// dont override global variable\nif (typeof web3 !== 'undefined') {\n var web3;\n}\n\nweb3 = require('./lib/web3');\nweb3.providers.HttpProvider = require('./lib/web3/httpprovider');\nweb3.providers.QtSyncProvider = require('./lib/web3/qtsync');\nweb3.eth.contract = require('./lib/web3/contract');\nweb3.abi = require('./lib/solidity/abi');\n\n\n\nmodule.exports = web3;\n" + "var web3 = require('./lib/web3');\nweb3.providers.HttpProvider = require('./lib/web3/httpprovider');\nweb3.providers.QtSyncProvider = require('./lib/web3/qtsync');\nweb3.eth.contract = require('./lib/web3/contract');\nweb3.abi = require('./lib/solidity/abi');\n\n// dont override global variable\nif (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {\n window.web3 = web3;\n}\n\nmodule.exports = web3;\n\n" ] } \ No newline at end of file diff --git a/dist/web3-light.min.js b/dist/web3-light.min.js index 6a651c205..6c35d47f7 100644 --- a/dist/web3-light.min.js +++ b/dist/web3-light.min.js @@ -1 +1 @@ -require=function t(e,n,r){function o(a,u){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;av;v++)g.push(h(e.slice(0,s))),e=e.slice(s);n.push(g)}else o.prefixedType("bytes")(t[c].type)?(l=l.slice(s),n.push(h(e.slice(0,s))),e=e.slice(s)):(n.push(h(e.slice(0,s))),e=e.slice(s))}),n},h=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),o=n.extractTypeName(t.name),i=function(){var e=Array.prototype.slice.call(arguments);return l(t.inputs,e)};void 0===e[r]&&(e[r]=i),e[r][o]=i}),e},d=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),o=n.extractTypeName(t.name),i=function(e){return m(t.outputs,e)};void 0===e[r]&&(e[r]=i),e[r][o]=i}),e};e.exports={inputParser:h,outputParser:d,formatInput:l,formatOutput:m}},{"../utils/config":5,"../utils/utils":6,"./formatters":2,"./types":3}],2:[function(t,e){var n=t("bignumber.js"),r=t("../utils/utils"),o=t("../utils/config"),i=function(t){var e=2*o.ETH_PADDING;return n.config(o.ETH_BIGNUMBER_ROUNDING_MODE),r.padLeft(r.toTwosComplement(t).round().toString(16),e)},a=function(t){return r.fromAscii(t,o.ETH_PADDING).substr(2)},u=function(t){return"000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0")},s=function(t){return i(new n(t).times(new n(2).pow(128)))},c=function(t){return"1"===new n(t.substr(0,1),16).toString(2).substr(0,1)},l=function(t){return t=t||"0",c(t)?new n(t,16).minus(new n("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new n(t,16)},f=function(t){return t=t||"0",new n(t,16)},p=function(t){return l(t).dividedBy(new n(2).pow(128))},m=function(t){return f(t).dividedBy(new n(2).pow(128))},h=function(t){return"0x"+t},d=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t?!0:!1},g=function(t){return r.toAscii(t)},v=function(t){return"0x"+t.slice(t.length-40,t.length)};e.exports={formatInputInt:i,formatInputString:a,formatInputBool:u,formatInputReal:s,formatOutputInt:l,formatOutputUInt:f,formatOutputReal:p,formatOutputUReal:m,formatOutputHash:h,formatOutputBool:d,formatOutputString:g,formatOutputAddress:v}},{"../utils/config":5,"../utils/utils":6,"bignumber.js":"bignumber.js"}],3:[function(t,e){var n=t("./formatters"),r=function(t){return function(e){return 0===e.indexOf(t)}},o=function(t){return function(e){return t===e}},i=function(){return[{type:r("uint"),format:n.formatInputInt},{type:r("int"),format:n.formatInputInt},{type:r("bytes"),format:n.formatInputString},{type:r("real"),format:n.formatInputReal},{type:r("ureal"),format:n.formatInputReal},{type:o("address"),format:n.formatInputInt},{type:o("bool"),format:n.formatInputBool}]},a=function(){return[{type:r("uint"),format:n.formatOutputUInt},{type:r("int"),format:n.formatOutputInt},{type:r("bytes"),format:n.formatOutputString},{type:r("real"),format:n.formatOutputReal},{type:r("ureal"),format:n.formatOutputUReal},{type:o("address"),format:n.formatOutputAddress},{type:o("bool"),format:n.formatOutputBool}]};e.exports={prefixedType:r,namedType:o,inputTypes:i,outputTypes:a}},{"./formatters":2}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e){var n=t("bignumber.js"),r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:r,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:n.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3,ETH_DEFAULTBLOCK:"latest"}},{"bignumber.js":"bignumber.js"}],6:[function(t,e){var n=t("bignumber.js"),r={wei:"1",kwei:"1000",ada:"1000",mwei:"1000000",babbage:"1000000",gwei:"1000000000",shannon:"1000000000",szabo:"1000000000000",finney:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},o=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},i=function(t,e){for(var n=!1,r=0;rn;n+=2){var o=parseInt(t.substr(n,2),16);if(0===o)break;e+=String.fromCharCode(o)}return e},u=function(t){for(var e="",n=0;n1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},i.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},i.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return n.getInstance().sendAsync(t,function(n,r){t.callback(null,e.formatOutput(r))})}return this.formatOutput(n.getInstance().send(t))},e.exports=i},{"../utils/utils":6,"./errors":11,"./requestmanager":22}],19:[function(t,e){var n=t("../utils/utils"),r=t("./property"),o=[],i=[new r({name:"listening",getter:"net_listening"}),new r({name:"peerCount",getter:"net_peerCount",outputFormatter:n.toDecimal})];e.exports={methods:o,properties:i}},{"../utils/utils":6,"./property":20}],20:[function(t,e){var n=t("./requestmanager"),r=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};r.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},r.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},r.prototype.attachToObject=function(t){var e={get:this.get.bind(this),set:this.set.bind(this)},n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},Object.defineProperty(t[n[0]],n[1],e)):Object.defineProperty(t,n[0],e)},r.prototype.get=function(){return this.formatOutput(n.getInstance().send({method:this.getter}))},r.prototype.set=function(t){return n.getInstance().send({method:this.setter,params:[this.formatInput(t)]})},e.exports=r},{"./requestmanager":22}],21:[function(t,e){var n=function(){};n.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=n},{}],22:[function(t,e){var n=t("./jsonrpc"),r=t("../utils/utils"),o=t("../utils/config"),i=t("./errors"),a=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls=[],this.timeout=null,void this.poll())};a.getInstance=function(){var t=new a;return t},a.prototype.send=function(t){if(!this.provider)return console.error(i.InvalidProvider),null;var e=n.getInstance().toPayload(t.method,t.params),r=this.provider.send(e);if(!n.getInstance().isValidResponse(r))throw i.InvalidResponse(r);return r.result},a.prototype.sendAsync=function(t,e){if(!this.provider)return e(i.InvalidProvider);var r=n.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(r,function(t,r){return t?e(t):n.getInstance().isValidResponse(r)?void e(null,r.result):e(i.InvalidResponse(r))})},a.prototype.setProvider=function(t){this.provider=t},a.prototype.startPolling=function(t,e,n,r){this.polls.push({data:t,id:e,callback:n,uninstall:r})},a.prototype.stopPolling=function(t){for(var e=this.polls.length;e--;){var n=this.polls[e];n.id===t&&this.polls.splice(e,1)}},a.prototype.reset=function(){this.polls.forEach(function(t){t.uninstall(t.id)}),this.polls=[],this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},a.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),o.ETH_POLLING_TIMEOUT),this.polls.length){if(!this.provider)return void console.error(i.InvalidProvider);var t=n.getInstance().toBatchPayload(this.polls.map(function(t){return t.data})),e=this;this.provider.sendAsync(t,function(t,o){if(!t){if(!r.isArray(o))throw i.InvalidResponse(o);o.map(function(t,n){return t.callback=e.polls[n].callback,t}).filter(function(t){var e=n.getInstance().isValidResponse(t);return e||t.callback(i.InvalidResponse(t)),e}).filter(function(t){return r.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}},e.exports=a},{"../utils/config":5,"../utils/utils":6,"./errors":11,"./jsonrpc":17}],23:[function(t,e){var n=t("./method"),r=t("./formatters"),o=new n({name:"post",call:"shh_post",params:1,inputFormatter:r.inputPostFormatter}),i=new n({name:"newIdentity",call:"shh_newIdentity",params:0}),a=new n({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new n({name:"newGroup",call:"shh_newGroup",params:0}),s=new n({name:"addToGroup",call:"shh_addToGroup",params:0}),c=[o,i,a,u,s];e.exports={methods:c}},{"./formatters":15,"./method":18}],24:[function(t,e){var n=t("../web3"),r=t("../utils/config"),o=function(t){return n.sha3(n.fromAscii(t)).slice(0,2+2*r.ETH_SIGNATURE_LENGTH)},i=function(t){return n.sha3(n.fromAscii(t))};e.exports={functionSignatureFromAscii:o,eventSignatureFromAscii:i}},{"../utils/config":5,"../web3":8}],25:[function(t,e){var n=t("./method"),r=function(){var t=function(t){return"string"==typeof t[0]?"eth_newBlockFilter":"eth_newFilter"},e=new n({name:"newFilter",call:t,params:1}),r=new n({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),o=new n({name:"getLogs",call:"eth_getFilterLogs",params:1}),i=new n({name:"poll",call:"eth_getFilterChanges",params:1});return[e,r,o,i]},o=function(){var t=new n({name:"newFilter",call:"shh_newFilter",params:1}),e=new n({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),r=new n({name:"getLogs",call:"shh_getMessages",params:1}),o=new n({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,r,o]};e.exports={eth:r,shh:o}},{"./method":18}],26:[function(){},{}],"bignumber.js":[function(t,e){"use strict";e.exports=BigNumber},{}],web3:[function(t,e){if("undefined"!=typeof n)var n;n=t("./lib/web3"),n.providers.HttpProvider=t("./lib/web3/httpprovider"),n.providers.QtSyncProvider=t("./lib/web3/qtsync"),n.eth.contract=t("./lib/web3/contract"),n.abi=t("./lib/solidity/abi"),e.exports=n},{"./lib/solidity/abi":1,"./lib/web3":8,"./lib/web3/contract":9,"./lib/web3/httpprovider":16,"./lib/web3/qtsync":21}]},{},["web3"]); \ No newline at end of file +require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;av;v++)g.push(h(e.slice(0,a))),e=e.slice(a);n.push(g)}else o.prefixedType("bytes")(t[c].type)?(l=l.slice(a),n.push(h(e.slice(0,a))),e=e.slice(a)):(n.push(h(e.slice(0,a))),e=e.slice(a))}),n},d=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),o=n.extractTypeName(t.name),i=function(){var e=Array.prototype.slice.call(arguments);return f(t.inputs,e)};void 0===e[r]&&(e[r]=i),e[r][o]=i}),e},g=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),o=n.extractTypeName(t.name),i=function(e){return h(t.outputs,e)};void 0===e[r]&&(e[r]=i),e[r][o]=i}),e},v=function(t,e){var n=a.getConstructor(t,e.length);return n?f(n.inputs,e):(e.length>0&&console.warn("didn't found matching constructor, using default one"),"")};e.exports={inputParser:d,outputParser:g,formatInput:f,formatOutput:h,formatConstructorParams:v}},{"../utils/config":6,"../utils/utils":7,"./formatters":2,"./types":3,"./utils":4}],2:[function(t,e){var n=t("bignumber.js"),r=t("../utils/utils"),o=t("../utils/config"),i=function(t){var e=2*o.ETH_PADDING;return n.config(o.ETH_BIGNUMBER_ROUNDING_MODE),r.padLeft(r.toTwosComplement(t).round().toString(16),e)},a=function(t){return r.fromAscii(t,o.ETH_PADDING).substr(2)},s=function(t){return"000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0")},u=function(t){return i(new n(t).times(new n(2).pow(128)))},c=function(t){return"1"===new n(t.substr(0,1),16).toString(2).substr(0,1)},l=function(t){return t=t||"0",c(t)?new n(t,16).minus(new n("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new n(t,16)},f=function(t){return t=t||"0",new n(t,16)},p=function(t){return l(t).dividedBy(new n(2).pow(128))},m=function(t){return f(t).dividedBy(new n(2).pow(128))},h=function(t){return"0x"+t},d=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t?!0:!1},g=function(t){return r.toAscii(t)},v=function(t){return"0x"+t.slice(t.length-40,t.length)};e.exports={formatInputInt:i,formatInputString:a,formatInputBool:s,formatInputReal:u,formatOutputInt:l,formatOutputUInt:f,formatOutputReal:p,formatOutputUReal:m,formatOutputHash:h,formatOutputBool:d,formatOutputString:g,formatOutputAddress:v}},{"../utils/config":6,"../utils/utils":7,"bignumber.js":"bignumber.js"}],3:[function(t,e){var n=t("./formatters"),r=function(t){return function(e){return 0===e.indexOf(t)}},o=function(t){return function(e){return t===e}},i=function(){return[{type:r("uint"),format:n.formatInputInt},{type:r("int"),format:n.formatInputInt},{type:r("bytes"),format:n.formatInputString},{type:r("real"),format:n.formatInputReal},{type:r("ureal"),format:n.formatInputReal},{type:o("address"),format:n.formatInputInt},{type:o("bool"),format:n.formatInputBool}]},a=function(){return[{type:r("uint"),format:n.formatOutputUInt},{type:r("int"),format:n.formatOutputInt},{type:r("bytes"),format:n.formatOutputString},{type:r("real"),format:n.formatOutputReal},{type:r("ureal"),format:n.formatOutputUReal},{type:o("address"),format:n.formatOutputAddress},{type:o("bool"),format:n.formatOutputBool}]};e.exports={prefixedType:r,namedType:o,inputTypes:i,outputTypes:a}},{"./formatters":2}],4:[function(t,e){var n=function(t,e){return t.filter(function(t){return"constructor"===t.type&&t.inputs.length===e})[0]},r=function(t){return t.filter(function(t){return"function"===t.type})},o=function(t){return t.filter(function(t){return"event"===t.type})};e.exports={getConstructor:n,filterFunctions:r,filterEvents:o}},{}],5:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],6:[function(t,e){var n=t("bignumber.js"),r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:r,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:n.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3,ETH_DEFAULTBLOCK:"latest"}},{"bignumber.js":"bignumber.js"}],7:[function(t,e){var n=t("bignumber.js"),r={wei:"1",kwei:"1000",ada:"1000",mwei:"1000000",babbage:"1000000",gwei:"1000000000",shannon:"1000000000",szabo:"1000000000000",finney:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},o=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},i=function(t,e){for(var n=!1,r=0;rn;n+=2){var o=parseInt(t.substr(n,2),16);if(0===o)break;e+=String.fromCharCode(o)}return e},s=function(t){for(var e="",n=0;n1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},i.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},i.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return n.getInstance().sendAsync(t,function(n,r){t.callback(null,e.formatOutput(r))})}return this.formatOutput(n.getInstance().send(t))},e.exports=i},{"../utils/utils":7,"./errors":12,"./requestmanager":23}],20:[function(t,e){var n=t("../utils/utils"),r=t("./property"),o=[],i=[new r({name:"listening",getter:"net_listening"}),new r({name:"peerCount",getter:"net_peerCount",outputFormatter:n.toDecimal})];e.exports={methods:o,properties:i}},{"../utils/utils":7,"./property":21}],21:[function(t,e){var n=t("./requestmanager"),r=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};r.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},r.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},r.prototype.attachToObject=function(t){var e={get:this.get.bind(this),set:this.set.bind(this)},n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},Object.defineProperty(t[n[0]],n[1],e)):Object.defineProperty(t,n[0],e)},r.prototype.get=function(){return this.formatOutput(n.getInstance().send({method:this.getter}))},r.prototype.set=function(t){return n.getInstance().send({method:this.setter,params:[this.formatInput(t)]})},e.exports=r},{"./requestmanager":23}],22:[function(t,e){var n=function(){};n.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=n},{}],23:[function(t,e){var n=t("./jsonrpc"),r=t("../utils/utils"),o=t("../utils/config"),i=t("./errors"),a=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls=[],this.timeout=null,void this.poll())};a.getInstance=function(){var t=new a;return t},a.prototype.send=function(t){if(!this.provider)return console.error(i.InvalidProvider),null;var e=n.getInstance().toPayload(t.method,t.params),r=this.provider.send(e);if(!n.getInstance().isValidResponse(r))throw i.InvalidResponse(r);return r.result},a.prototype.sendAsync=function(t,e){if(!this.provider)return e(i.InvalidProvider);var r=n.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(r,function(t,r){return t?e(t):n.getInstance().isValidResponse(r)?void e(null,r.result):e(i.InvalidResponse(r))})},a.prototype.setProvider=function(t){this.provider=t},a.prototype.startPolling=function(t,e,n,r){this.polls.push({data:t,id:e,callback:n,uninstall:r})},a.prototype.stopPolling=function(t){for(var e=this.polls.length;e--;){var n=this.polls[e];n.id===t&&this.polls.splice(e,1)}},a.prototype.reset=function(){this.polls.forEach(function(t){t.uninstall(t.id)}),this.polls=[],this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},a.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),o.ETH_POLLING_TIMEOUT),this.polls.length){if(!this.provider)return void console.error(i.InvalidProvider);var t=n.getInstance().toBatchPayload(this.polls.map(function(t){return t.data})),e=this;this.provider.sendAsync(t,function(t,o){if(!t){if(!r.isArray(o))throw i.InvalidResponse(o);o.map(function(t,n){return t.callback=e.polls[n].callback,t}).filter(function(t){var e=n.getInstance().isValidResponse(t);return e||t.callback(i.InvalidResponse(t)),e}).filter(function(t){return r.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}},e.exports=a},{"../utils/config":6,"../utils/utils":7,"./errors":12,"./jsonrpc":18}],24:[function(t,e){var n=t("./method"),r=t("./formatters"),o=new n({name:"post",call:"shh_post",params:1,inputFormatter:r.inputPostFormatter}),i=new n({name:"newIdentity",call:"shh_newIdentity",params:0}),a=new n({name:"hasIdentity",call:"shh_hasIdentity",params:1}),s=new n({name:"newGroup",call:"shh_newGroup",params:0}),u=new n({name:"addToGroup",call:"shh_addToGroup",params:0}),c=[o,i,a,s,u];e.exports={methods:c}},{"./formatters":16,"./method":19}],25:[function(t,e){var n=t("../web3"),r=t("../utils/config"),o=function(t){return n.sha3(n.fromAscii(t)).slice(0,2+2*r.ETH_SIGNATURE_LENGTH)},i=function(t){return n.sha3(n.fromAscii(t))};e.exports={functionSignatureFromAscii:o,eventSignatureFromAscii:i}},{"../utils/config":6,"../web3":9}],26:[function(t,e){var n=t("./method"),r=function(){var t=function(t){return"string"==typeof t[0]?"eth_newBlockFilter":"eth_newFilter"},e=new n({name:"newFilter",call:t,params:1}),r=new n({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),o=new n({name:"getLogs",call:"eth_getFilterLogs",params:1}),i=new n({name:"poll",call:"eth_getFilterChanges",params:1});return[e,r,o,i]},o=function(){var t=new n({name:"newFilter",call:"shh_newFilter",params:1}),e=new n({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),r=new n({name:"getLogs",call:"shh_getMessages",params:1}),o=new n({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,r,o]};e.exports={eth:r,shh:o}},{"./method":19}],27:[function(){},{}],"bignumber.js":[function(t,e){"use strict";e.exports=BigNumber},{}],web3:[function(t,e){var n=t("./lib/web3");n.providers.HttpProvider=t("./lib/web3/httpprovider"),n.providers.QtSyncProvider=t("./lib/web3/qtsync"),n.eth.contract=t("./lib/web3/contract"),n.abi=t("./lib/solidity/abi"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=n),e.exports=n},{"./lib/solidity/abi":1,"./lib/web3":9,"./lib/web3/contract":10,"./lib/web3/httpprovider":17,"./lib/web3/qtsync":22}]},{},["web3"]); \ No newline at end of file diff --git a/dist/web3.js b/dist/web3.js index a491bf4e0..a4b38d06b 100644 --- a/dist/web3.js +++ b/dist/web3.js @@ -15,10 +15,10 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file abi.js - * @authors: - * Marek Kotewicz - * Gav Wood +/** + * @file abi.js + * @author Marek Kotewicz + * @author Gav Wood * @date 2014 */ @@ -26,6 +26,7 @@ var utils = require('../utils/utils'); var c = require('../utils/config'); var types = require('./types'); var f = require('./formatters'); +var solUtils = require('./utils'); /** * throw incorrect type error @@ -238,14 +239,26 @@ var outputParser = function (json) { return parser; }; +var formatConstructorParams = function (abi, params) { + var constructor = solUtils.getConstructor(abi, params.length); + if (!constructor) { + if (params.length > 0) { + console.warn("didn't found matching constructor, using default one"); + } + return ''; + } + return formatInput(constructor.inputs, params); +}; + module.exports = { inputParser: inputParser, outputParser: outputParser, formatInput: formatInput, - formatOutput: formatOutput + formatOutput: formatOutput, + formatConstructorParams: formatConstructorParams }; -},{"../utils/config":5,"../utils/utils":6,"./formatters":2,"./types":3}],2:[function(require,module,exports){ +},{"../utils/config":6,"../utils/utils":7,"./formatters":2,"./types":3,"./utils":4}],2:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -445,7 +458,7 @@ module.exports = { }; -},{"../utils/config":5,"../utils/utils":6,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){ +},{"../utils/config":6,"../utils/utils":7,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -525,6 +538,76 @@ module.exports = { },{"./formatters":2}],4:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file utils.js + * @author Marek Kotewicz + * @date 2015 + */ + +/** + * Returns the contstructor with matching number of arguments + * + * @method getConstructor + * @param {Array} abi + * @param {Number} numberOfArgs + * @returns {Object} constructor function abi + */ +var getConstructor = function (abi, numberOfArgs) { + return abi.filter(function (f) { + return f.type === 'constructor' && f.inputs.length === numberOfArgs; + })[0]; +}; + +/** + * Filters all functions from input abi + * + * @method filterFunctions + * @param {Array} abi + * @returns {Array} abi array with filtered objects of type 'function' + */ +var filterFunctions = function (json) { + return json.filter(function (current) { + return current.type === 'function'; + }); +}; + +/** + * Filters all events from input abi + * + * @method filterEvents + * @param {Array} abi + * @returns {Array} abi array with filtered objects of type 'event' + */ +var filterEvents = function (json) { + return json.filter(function (current) { + return current.type === 'event'; + }); +}; + +module.exports = { + getConstructor: getConstructor, + filterFunctions: filterFunctions, + filterEvents: filterEvents +}; + + +},{}],5:[function(require,module,exports){ 'use strict'; // go env doesn't have and need XMLHttpRequest @@ -535,7 +618,7 @@ if (typeof XMLHttpRequest === 'undefined') { } -},{}],5:[function(require,module,exports){ +},{}],6:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -606,7 +689,7 @@ module.exports = { }; -},{"bignumber.js":"bignumber.js"}],6:[function(require,module,exports){ +},{"bignumber.js":"bignumber.js"}],7:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -770,32 +853,6 @@ var extractTypeName = function (name) { return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : ""; }; -/** - * Filters all functions from input abi - * - * @method filterFunctions - * @param {Array} abi - * @returns {Array} abi array with filtered objects of type 'function' - */ -var filterFunctions = function (json) { - return json.filter(function (current) { - return current.type === 'function'; - }); -}; - -/** - * Filters all events from input abi - * - * @method filterEvents - * @param {Array} abi - * @returns {Array} abi array with filtered objects of type 'event' - */ -var filterEvents = function (json) { - return json.filter(function (current) { - return current.type === 'event'; - }); -}; - /** * Converts value to it's decimal representation in string * @@ -958,14 +1015,25 @@ var toTwosComplement = function (number) { }; /** - * Checks if the given string has proper length + * Checks if the given string is strictly an address + * + * @method isStrictAddress + * @param {String} address the given HEX adress + * @return {Boolean} +*/ +var isStrictAddress = function (address) { + return /^0x[0-9a-f]{40}$/.test(address); +}; + +/** + * Checks if the given string is an address * * @method isAddress * @param {String} address the given HEX adress * @return {Boolean} */ var isAddress = function (address) { - return /^0x[0-9a-f]{40}$/.test(address); + return /^(0x)?[0-9a-f]{40}$/.test(address); }; /** @@ -976,7 +1044,7 @@ var isAddress = function (address) { * @return {String} formatted address */ var toAddress = function (address) { - if (isAddress(address)) { + if (isStrictAddress(address)) { return address; } @@ -1080,14 +1148,13 @@ module.exports = { fromAscii: fromAscii, extractDisplayName: extractDisplayName, extractTypeName: extractTypeName, - filterFunctions: filterFunctions, - filterEvents: filterEvents, toWei: toWei, fromWei: fromWei, toBigNumber: toBigNumber, toTwosComplement: toTwosComplement, toAddress: toAddress, isBigNumber: isBigNumber, + isStrictAddress: isStrictAddress, isAddress: isAddress, isFunction: isFunction, isString: isString, @@ -1098,12 +1165,12 @@ module.exports = { }; -},{"bignumber.js":"bignumber.js"}],7:[function(require,module,exports){ +},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){ module.exports={ - "version": "0.2.5" + "version": "0.2.6" } -},{}],8:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1164,7 +1231,7 @@ var web3Properties = [ }), new Property({ name: 'version.ethereum', - getter: 'eth_version', + getter: 'eth_protocolVersion', inputFormatter: utils.toDecimal }), new Property({ @@ -1259,7 +1326,7 @@ setupMethods(web3.shh, shh.methods); module.exports = web3; -},{"./utils/config":5,"./utils/utils":6,"./version.json":7,"./web3/db":10,"./web3/eth":12,"./web3/filter":14,"./web3/formatters":15,"./web3/method":18,"./web3/net":19,"./web3/property":20,"./web3/requestmanager":22,"./web3/shh":23,"./web3/watches":25}],9:[function(require,module,exports){ +},{"./utils/config":6,"./utils/utils":7,"./version.json":8,"./web3/db":11,"./web3/eth":13,"./web3/filter":15,"./web3/formatters":16,"./web3/method":19,"./web3/net":20,"./web3/property":21,"./web3/requestmanager":23,"./web3/shh":24,"./web3/watches":26}],10:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1283,8 +1350,9 @@ module.exports = web3; */ var web3 = require('../web3'); -var abi = require('../solidity/abi'); +var solAbi = require('../solidity/abi'); var utils = require('../utils/utils'); +var solUtils = require('../solidity/utils'); var eventImpl = require('./event'); var signature = require('./signature'); @@ -1304,11 +1372,11 @@ var addFunctionRelatedPropertiesToContract = function (contract) { }; var addFunctionsToContract = function (contract, desc, address) { - var inputParser = abi.inputParser(desc); - var outputParser = abi.outputParser(desc); + var inputParser = solAbi.inputParser(desc); + var outputParser = solAbi.outputParser(desc); // create contract functions - utils.filterFunctions(desc).forEach(function (method) { + solUtils.filterFunctions(desc).forEach(function (method) { var displayName = utils.extractDisplayName(method.name); var typeName = utils.extractTypeName(method.name); @@ -1360,14 +1428,14 @@ var addFunctionsToContract = function (contract, desc, address) { var addEventRelatedPropertiesToContract = function (contract, desc, address) { contract.address = address; contract._onWatchEventResult = function (data) { - var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc)); + var matchingEvent = event.getMatchingEvent(solUtils.filterEvents(desc)); var parser = eventImpl.outputParser(matchingEvent); return parser(data); }; Object.defineProperty(contract, 'topics', { get: function() { - return utils.filterEvents(desc).map(function (e) { + return solUtils.filterEvents(desc).map(function (e) { return signature.eventSignatureFromAscii(e.name); }); } @@ -1377,7 +1445,7 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) { var addEventsToContract = function (contract, desc, address) { // create contract events - utils.filterEvents(desc).forEach(function (e) { + solUtils.filterEvents(desc).forEach(function (e) { var impl = function () { var params = Array.prototype.slice.call(arguments); @@ -1435,7 +1503,7 @@ var contract = function (abi) { return Contract.bind(null, abi); }; -function Contract(abi, address) { +function Contract(abi, options) { // workaround for invalid assumption that method.name is the full anonymous prototype of the method. // it's not. it's just the name. the rest of the code assumes it's actually the anonymous @@ -1449,6 +1517,17 @@ function Contract(abi, address) { } }); + var address = ''; + if (utils.isAddress(options)) { + address = options; + } else { // is a source code! + // TODO, parse the rest of the args + var code = options; + var args = Array.prototype.slice.call(arguments, 2); + var bytes = solAbi.formatConstructorParams(abi, args); + address = web3.eth.sendTransaction({data: code + bytes}); + } + var result = {}; addFunctionRelatedPropertiesToContract(result); addFunctionsToContract(result, abi, address); @@ -1461,7 +1540,7 @@ function Contract(abi, address) { module.exports = contract; -},{"../solidity/abi":1,"../utils/utils":6,"../web3":8,"./event":13,"./signature":24}],10:[function(require,module,exports){ +},{"../solidity/abi":1,"../solidity/utils":4,"../utils/utils":7,"../web3":9,"./event":14,"./signature":25}],11:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1519,7 +1598,7 @@ module.exports = { methods: methods }; -},{"./method":18}],11:[function(require,module,exports){ +},{"./method":19}],12:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1559,7 +1638,7 @@ module.exports = { }; -},{"../utils/utils":6}],12:[function(require,module,exports){ +},{"../utils/utils":7}],13:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1671,8 +1750,8 @@ var getBlock = new Method({ var getUncle = new Method({ name: 'getUncle', call: uncleCall, - params: 3, - inputFormatter: [utils.toHex, utils.toHex, function (val) { return !!val; }], + params: 2, + inputFormatter: [utils.toHex, utils.toHex], outputFormatter: formatters.outputBlockFormatter, }); @@ -1796,7 +1875,7 @@ var properties = [ new Property({ name: 'gasPrice', getter: 'eth_gasPrice', - outputFormatter: formatters.inputNumberFormatter + outputFormatter: formatters.outputBigNumberFormatter }), new Property({ name: 'accounts', @@ -1815,7 +1894,7 @@ module.exports = { }; -},{"../utils/utils":6,"./formatters":15,"./method":18,"./property":20}],13:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":16,"./method":19,"./property":21}],14:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1955,7 +2034,7 @@ module.exports = { }; -},{"../solidity/abi":1,"../utils/utils":6,"./signature":24}],14:[function(require,module,exports){ +},{"../solidity/abi":1,"../utils/utils":7,"./signature":25}],15:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2067,7 +2146,7 @@ Filter.prototype.get = function () { module.exports = Filter; -},{"../utils/utils":6,"./formatters":15,"./requestmanager":22}],15:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":16,"./requestmanager":23}],16:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2280,7 +2359,7 @@ module.exports = { }; -},{"../utils/config":5,"../utils/utils":6}],16:[function(require,module,exports){ +},{"../utils/config":6,"../utils/utils":7}],17:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2343,7 +2422,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { module.exports = HttpProvider; -},{"xmlhttprequest":4}],17:[function(require,module,exports){ +},{"xmlhttprequest":5}],18:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2436,7 +2515,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) { module.exports = Jsonrpc; -},{}],18:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2597,7 +2676,7 @@ Method.prototype.send = function () { module.exports = Method; -},{"../utils/utils":6,"./errors":11,"./requestmanager":22}],19:[function(require,module,exports){ +},{"../utils/utils":7,"./errors":12,"./requestmanager":23}],20:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2647,7 +2726,7 @@ module.exports = { }; -},{"../utils/utils":6,"./property":20}],20:[function(require,module,exports){ +},{"../utils/utils":7,"./property":21}],21:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2753,7 +2832,7 @@ Property.prototype.set = function (value) { module.exports = Property; -},{"./requestmanager":22}],21:[function(require,module,exports){ +},{"./requestmanager":23}],22:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2788,7 +2867,7 @@ QtSyncProvider.prototype.send = function (payload) { module.exports = QtSyncProvider; -},{}],22:[function(require,module,exports){ +},{}],23:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3009,7 +3088,7 @@ RequestManager.prototype.poll = function () { module.exports = RequestManager; -},{"../utils/config":5,"../utils/utils":6,"./errors":11,"./jsonrpc":17}],23:[function(require,module,exports){ +},{"../utils/config":6,"../utils/utils":7,"./errors":12,"./jsonrpc":18}],24:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3079,7 +3158,7 @@ module.exports = { }; -},{"./formatters":15,"./method":18}],24:[function(require,module,exports){ +},{"./formatters":16,"./method":19}],25:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3123,7 +3202,7 @@ module.exports = { }; -},{"../utils/config":5,"../web3":8}],25:[function(require,module,exports){ +},{"../utils/config":6,"../web3":9}],26:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3226,7 +3305,7 @@ module.exports = { }; -},{"./method":18}],26:[function(require,module,exports){ +},{"./method":19}],27:[function(require,module,exports){ },{}],"bignumber.js":[function(require,module,exports){ /*! bignumber.js v2.0.3 https://github.com/MikeMcl/bignumber.js/LICENCE */ @@ -5899,23 +5978,22 @@ module.exports = { } })(this); -},{"crypto":26}],"web3":[function(require,module,exports){ -// dont override global variable -if (typeof web3 !== 'undefined') { - var web3; -} - -web3 = require('./lib/web3'); +},{"crypto":27}],"web3":[function(require,module,exports){ +var web3 = require('./lib/web3'); web3.providers.HttpProvider = require('./lib/web3/httpprovider'); web3.providers.QtSyncProvider = require('./lib/web3/qtsync'); web3.eth.contract = require('./lib/web3/contract'); web3.abi = require('./lib/solidity/abi'); - +// dont override global variable +if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { + window.web3 = web3; +} module.exports = web3; -},{"./lib/solidity/abi":1,"./lib/web3":8,"./lib/web3/contract":9,"./lib/web3/httpprovider":16,"./lib/web3/qtsync":21}]},{},["web3"]) + +},{"./lib/solidity/abi":1,"./lib/web3":9,"./lib/web3/contract":10,"./lib/web3/httpprovider":17,"./lib/web3/qtsync":22}]},{},["web3"]) //# sourceMappingURL=web3.js.map \ No newline at end of file diff --git a/dist/web3.js.map b/dist/web3.js.map index 1f1713b0e..6e9d116c9 100644 --- a/dist/web3.js.map +++ b/dist/web3.js.map @@ -5,6 +5,7 @@ "lib/solidity/abi.js", "lib/solidity/formatters.js", "lib/solidity/types.js", + "lib/solidity/utils.js", "lib/utils/browser-xhr.js", "lib/utils/config.js", "lib/utils/utils.js", @@ -32,23 +33,24 @@ "index.js" ], "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1eA;AACA;AACA;AACA;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7mFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1dA;AACA;AACA;AACA;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7mFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "generated.js", "sourceRoot": "", "sourcesContent": [ "(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o.\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar types = require('./types');\nvar f = require('./formatters');\n\n/**\n * throw incorrect type error\n *\n * @method throwTypeError\n * @param {String} type\n * @throws incorrect type error\n */\nvar throwTypeError = function (type) {\n throw new Error('parser does not support type: ' + type);\n};\n\n/** This method should be called if we want to check if givent type is an array type\n *\n * @method isArrayType\n * @param {String} type name\n * @returns {Boolean} true if it is, otherwise false\n */\nvar isArrayType = function (type) {\n return type.slice(-2) === '[]';\n};\n\n/**\n * This method should be called to return dynamic type length in hex\n *\n * @method dynamicTypeBytes\n * @param {String} type\n * @param {String|Array} dynamic type\n * @return {String} length of dynamic type in hex or empty string if type is not dynamic\n */\nvar dynamicTypeBytes = function (type, value) {\n // TODO: decide what to do with array of strings\n if (isArrayType(type) || type === 'bytes')\n return f.formatInputInt(value.length);\n return \"\";\n};\n\nvar inputTypes = types.inputTypes();\n\n/**\n * Formats input params to bytes\n *\n * @method formatInput\n * @param {Array} abi inputs of method\n * @param {Array} params that will be formatted to bytes\n * @returns bytes representation of input params\n */\nvar formatInput = function (inputs, params) {\n var bytes = \"\";\n var toAppendConstant = \"\";\n var toAppendArrayContent = \"\";\n\n /// first we iterate in search for dynamic\n inputs.forEach(function (input, index) {\n bytes += dynamicTypeBytes(input.type, params[index]);\n });\n\n inputs.forEach(function (input, i) {\n /*jshint maxcomplexity:5 */\n var typeMatch = false;\n for (var j = 0; j < inputTypes.length && !typeMatch; j++) {\n typeMatch = inputTypes[j].type(inputs[i].type, params[i]);\n }\n if (!typeMatch) {\n throwTypeError(inputs[i].type);\n }\n\n var formatter = inputTypes[j - 1].format;\n\n if (isArrayType(inputs[i].type))\n toAppendArrayContent += params[i].reduce(function (acc, curr) {\n return acc + formatter(curr);\n }, \"\");\n else if (inputs[i].type === 'bytes')\n toAppendArrayContent += formatter(params[i]);\n else\n toAppendConstant += formatter(params[i]);\n });\n\n bytes += toAppendConstant + toAppendArrayContent;\n\n return bytes;\n};\n\n/**\n * This method should be called to predict the length of dynamic type\n *\n * @method dynamicBytesLength\n * @param {String} type\n * @returns {Number} length of dynamic type, 0 or multiplication of ETH_PADDING (32)\n */\nvar dynamicBytesLength = function (type) {\n if (isArrayType(type) || type === 'bytes')\n return c.ETH_PADDING * 2;\n return 0;\n};\n\nvar outputTypes = types.outputTypes();\n\n/** \n * Formats output bytes back to param list\n *\n * @method formatOutput\n * @param {Array} abi outputs of method\n * @param {String} bytes represention of output\n * @returns {Array} output params\n */\nvar formatOutput = function (outs, output) {\n\n output = output.slice(2);\n var result = [];\n var padding = c.ETH_PADDING * 2;\n\n var dynamicPartLength = outs.reduce(function (acc, curr) {\n return acc + dynamicBytesLength(curr.type);\n }, 0);\n\n var dynamicPart = output.slice(0, dynamicPartLength);\n output = output.slice(dynamicPartLength);\n\n outs.forEach(function (out, i) {\n /*jshint maxcomplexity:6 */\n var typeMatch = false;\n for (var j = 0; j < outputTypes.length && !typeMatch; j++) {\n typeMatch = outputTypes[j].type(outs[i].type);\n }\n\n if (!typeMatch) {\n throwTypeError(outs[i].type);\n }\n\n var formatter = outputTypes[j - 1].format;\n if (isArrayType(outs[i].type)) {\n var size = f.formatOutputUInt(dynamicPart.slice(0, padding));\n dynamicPart = dynamicPart.slice(padding);\n var array = [];\n for (var k = 0; k < size; k++) {\n array.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n result.push(array);\n }\n else if (types.prefixedType('bytes')(outs[i].type)) {\n dynamicPart = dynamicPart.slice(padding);\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n } else {\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n });\n\n return result;\n};\n\n/**\n * Should be called to create input parser for contract with given abi\n *\n * @method inputParser\n * @param {Array} contract abi\n * @returns {Object} input parser object for given json abi\n * TODO: refactor creating the parser, do not double logic from contract\n */\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n return formatInput(method.inputs, params);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\n/**\n * Should be called to create output parser for contract with given abi\n *\n * @method outputParser\n * @param {Array} contract abi\n * @returns {Object} output parser for given json abi\n */\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function (output) {\n return formatOutput(method.outputs, output);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n formatInput: formatInput,\n formatOutput: formatOutput\n};\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file abi.js\n * @author Marek Kotewicz \n * @author Gav Wood \n * @date 2014\n */\n\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar types = require('./types');\nvar f = require('./formatters');\nvar solUtils = require('./utils');\n\n/**\n * throw incorrect type error\n *\n * @method throwTypeError\n * @param {String} type\n * @throws incorrect type error\n */\nvar throwTypeError = function (type) {\n throw new Error('parser does not support type: ' + type);\n};\n\n/** This method should be called if we want to check if givent type is an array type\n *\n * @method isArrayType\n * @param {String} type name\n * @returns {Boolean} true if it is, otherwise false\n */\nvar isArrayType = function (type) {\n return type.slice(-2) === '[]';\n};\n\n/**\n * This method should be called to return dynamic type length in hex\n *\n * @method dynamicTypeBytes\n * @param {String} type\n * @param {String|Array} dynamic type\n * @return {String} length of dynamic type in hex or empty string if type is not dynamic\n */\nvar dynamicTypeBytes = function (type, value) {\n // TODO: decide what to do with array of strings\n if (isArrayType(type) || type === 'bytes')\n return f.formatInputInt(value.length);\n return \"\";\n};\n\nvar inputTypes = types.inputTypes();\n\n/**\n * Formats input params to bytes\n *\n * @method formatInput\n * @param {Array} abi inputs of method\n * @param {Array} params that will be formatted to bytes\n * @returns bytes representation of input params\n */\nvar formatInput = function (inputs, params) {\n var bytes = \"\";\n var toAppendConstant = \"\";\n var toAppendArrayContent = \"\";\n\n /// first we iterate in search for dynamic\n inputs.forEach(function (input, index) {\n bytes += dynamicTypeBytes(input.type, params[index]);\n });\n\n inputs.forEach(function (input, i) {\n /*jshint maxcomplexity:5 */\n var typeMatch = false;\n for (var j = 0; j < inputTypes.length && !typeMatch; j++) {\n typeMatch = inputTypes[j].type(inputs[i].type, params[i]);\n }\n if (!typeMatch) {\n throwTypeError(inputs[i].type);\n }\n\n var formatter = inputTypes[j - 1].format;\n\n if (isArrayType(inputs[i].type))\n toAppendArrayContent += params[i].reduce(function (acc, curr) {\n return acc + formatter(curr);\n }, \"\");\n else if (inputs[i].type === 'bytes')\n toAppendArrayContent += formatter(params[i]);\n else\n toAppendConstant += formatter(params[i]);\n });\n\n bytes += toAppendConstant + toAppendArrayContent;\n\n return bytes;\n};\n\n/**\n * This method should be called to predict the length of dynamic type\n *\n * @method dynamicBytesLength\n * @param {String} type\n * @returns {Number} length of dynamic type, 0 or multiplication of ETH_PADDING (32)\n */\nvar dynamicBytesLength = function (type) {\n if (isArrayType(type) || type === 'bytes')\n return c.ETH_PADDING * 2;\n return 0;\n};\n\nvar outputTypes = types.outputTypes();\n\n/** \n * Formats output bytes back to param list\n *\n * @method formatOutput\n * @param {Array} abi outputs of method\n * @param {String} bytes represention of output\n * @returns {Array} output params\n */\nvar formatOutput = function (outs, output) {\n\n output = output.slice(2);\n var result = [];\n var padding = c.ETH_PADDING * 2;\n\n var dynamicPartLength = outs.reduce(function (acc, curr) {\n return acc + dynamicBytesLength(curr.type);\n }, 0);\n\n var dynamicPart = output.slice(0, dynamicPartLength);\n output = output.slice(dynamicPartLength);\n\n outs.forEach(function (out, i) {\n /*jshint maxcomplexity:6 */\n var typeMatch = false;\n for (var j = 0; j < outputTypes.length && !typeMatch; j++) {\n typeMatch = outputTypes[j].type(outs[i].type);\n }\n\n if (!typeMatch) {\n throwTypeError(outs[i].type);\n }\n\n var formatter = outputTypes[j - 1].format;\n if (isArrayType(outs[i].type)) {\n var size = f.formatOutputUInt(dynamicPart.slice(0, padding));\n dynamicPart = dynamicPart.slice(padding);\n var array = [];\n for (var k = 0; k < size; k++) {\n array.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n result.push(array);\n }\n else if (types.prefixedType('bytes')(outs[i].type)) {\n dynamicPart = dynamicPart.slice(padding);\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n } else {\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n });\n\n return result;\n};\n\n/**\n * Should be called to create input parser for contract with given abi\n *\n * @method inputParser\n * @param {Array} contract abi\n * @returns {Object} input parser object for given json abi\n * TODO: refactor creating the parser, do not double logic from contract\n */\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n return formatInput(method.inputs, params);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\n/**\n * Should be called to create output parser for contract with given abi\n *\n * @method outputParser\n * @param {Array} contract abi\n * @returns {Object} output parser for given json abi\n */\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function (output) {\n return formatOutput(method.outputs, output);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\nvar formatConstructorParams = function (abi, params) {\n var constructor = solUtils.getConstructor(abi, params.length);\n if (!constructor) {\n if (params.length > 0) {\n console.warn(\"didn't found matching constructor, using default one\");\n }\n return '';\n }\n return formatInput(constructor.inputs, params);\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n formatInput: formatInput,\n formatOutput: formatOutput,\n formatConstructorParams: formatConstructorParams\n};\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file formatters.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar BigNumber = require('bignumber.js');\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\n\n/**\n * Formats input value to byte representation of int\n * If value is negative, return it's two's complement\n * If the value is floating point, round it down\n *\n * @method formatInputInt\n * @param {String|Number|BigNumber} value that needs to be formatted\n * @returns {String} right-aligned byte representation of int\n */\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n return utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);\n};\n\n/**\n * Formats input value to byte representation of string\n *\n * @method formatInputString\n * @param {String}\n * @returns {String} left-algined byte representation of string\n */\nvar formatInputString = function (value) {\n return utils.fromAscii(value, c.ETH_PADDING).substr(2);\n};\n\n/**\n * Formats input value to byte representation of bool\n *\n * @method formatInputBool\n * @param {Boolean}\n * @returns {String} right-aligned byte representation bool\n */\nvar formatInputBool = function (value) {\n return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n};\n\n/**\n * Formats input value to byte representation of real\n * Values are multiplied by 2^m and encoded as integers\n *\n * @method formatInputReal\n * @param {String|Number|BigNumber}\n * @returns {String} byte representation of real\n */\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); \n};\n\n/**\n * Check if input value is negative\n *\n * @method signedIsNegative\n * @param {String} value is hex format\n * @returns {Boolean} true if it is negative, otherwise false\n */\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/**\n * Formats right-aligned output bytes to int\n *\n * @method formatOutputInt\n * @param {String} bytes\n * @returns {BigNumber} right-aligned output bytes formatted to big number\n */\nvar formatOutputInt = function (value) {\n\n value = value || \"0\";\n\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/**\n * Formats right-aligned output bytes to uint\n *\n * @method formatOutputUInt\n * @param {String} bytes\n * @returns {BigNumeber} right-aligned output bytes formatted to uint\n */\nvar formatOutputUInt = function (value) {\n value = value || \"0\";\n return new BigNumber(value, 16);\n};\n\n/**\n * Formats right-aligned output bytes to real\n *\n * @method formatOutputReal\n * @param {String}\n * @returns {BigNumber} input bytes formatted to real\n */\nvar formatOutputReal = function (value) {\n return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/**\n * Formats right-aligned output bytes to ureal\n *\n * @method formatOutputUReal\n * @param {String}\n * @returns {BigNumber} input bytes formatted to ureal\n */\nvar formatOutputUReal = function (value) {\n return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/**\n * Should be used to format output hash\n *\n * @method formatOutputHash\n * @param {String}\n * @returns {String} right-aligned output bytes formatted to hex\n */\nvar formatOutputHash = function (value) {\n return \"0x\" + value;\n};\n\n/**\n * Should be used to format output bool\n *\n * @method formatOutputBool\n * @param {String}\n * @returns {Boolean} right-aligned input bytes formatted to bool\n */\nvar formatOutputBool = function (value) {\n return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/**\n * Should be used to format output string\n *\n * @method formatOutputString\n * @param {Sttring} left-aligned hex representation of string\n * @returns {String} ascii string\n */\nvar formatOutputString = function (value) {\n return utils.toAscii(value);\n};\n\n/**\n * Should be used to format output address\n *\n * @method formatOutputAddress\n * @param {String} right-aligned input bytes\n * @returns {String} address\n */\nvar formatOutputAddress = function (value) {\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputString: formatInputString,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputHash: formatOutputHash,\n formatOutputBool: formatOutputBool,\n formatOutputString: formatOutputString,\n formatOutputAddress: formatOutputAddress\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file types.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar f = require('./formatters');\n\n/// @param expected type prefix (string)\n/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false\nvar prefixedType = function (prefix) {\n return function (type) {\n return type.indexOf(prefix) === 0;\n };\n};\n\n/// @param expected type name (string)\n/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false\nvar namedType = function (name) {\n return function (type) {\n return name === type;\n };\n};\n\n/// Setups input formatters for solidity types\n/// @returns an array of input formatters \nvar inputTypes = function () {\n \n return [\n { type: prefixedType('uint'), format: f.formatInputInt },\n { type: prefixedType('int'), format: f.formatInputInt },\n { type: prefixedType('bytes'), format: f.formatInputString }, \n { type: prefixedType('real'), format: f.formatInputReal },\n { type: prefixedType('ureal'), format: f.formatInputReal },\n { type: namedType('address'), format: f.formatInputInt },\n { type: namedType('bool'), format: f.formatInputBool }\n ];\n};\n\n/// Setups output formaters for solidity types\n/// @returns an array of output formatters\nvar outputTypes = function () {\n\n return [\n { type: prefixedType('uint'), format: f.formatOutputUInt },\n { type: prefixedType('int'), format: f.formatOutputInt },\n { type: prefixedType('bytes'), format: f.formatOutputString },\n { type: prefixedType('real'), format: f.formatOutputReal },\n { type: prefixedType('ureal'), format: f.formatOutputUReal },\n { type: namedType('address'), format: f.formatOutputAddress },\n { type: namedType('bool'), format: f.formatOutputBool }\n ];\n};\n\nmodule.exports = {\n prefixedType: prefixedType,\n namedType: namedType,\n inputTypes: inputTypes,\n outputTypes: outputTypes\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file utils.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Returns the contstructor with matching number of arguments\n *\n * @method getConstructor\n * @param {Array} abi\n * @param {Number} numberOfArgs\n * @returns {Object} constructor function abi\n */\nvar getConstructor = function (abi, numberOfArgs) {\n return abi.filter(function (f) {\n return f.type === 'constructor' && f.inputs.length === numberOfArgs;\n })[0];\n};\n\n/**\n * Filters all functions from input abi\n *\n * @method filterFunctions\n * @param {Array} abi\n * @returns {Array} abi array with filtered objects of type 'function'\n */\nvar filterFunctions = function (json) {\n return json.filter(function (current) {\n return current.type === 'function'; \n }); \n};\n\n/**\n * Filters all events from input abi\n *\n * @method filterEvents\n * @param {Array} abi\n * @returns {Array} abi array with filtered objects of type 'event'\n */\nvar filterEvents = function (json) {\n return json.filter(function (current) {\n return current.type === 'event';\n });\n};\n\nmodule.exports = {\n getConstructor: getConstructor,\n filterFunctions: filterFunctions,\n filterEvents: filterEvents\n};\n\n", "'use strict';\n\n// go env doesn't have and need XMLHttpRequest\nif (typeof XMLHttpRequest === 'undefined') {\n exports.XMLHttpRequest = {};\n} else {\n exports.XMLHttpRequest = XMLHttpRequest; // jshint ignore:line\n}\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file config.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] config\n * @constructor\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nvar BigNumber = require('bignumber.js');\n\nvar ETH_UNITS = [ \n 'wei', \n 'Kwei', \n 'Mwei', \n 'Gwei', \n 'szabo', \n 'finney', \n 'ether', \n 'grand', \n 'Mether', \n 'Gether', \n 'Tether', \n 'Pether', \n 'Eether', \n 'Zether', \n 'Yether', \n 'Nether', \n 'Dether', \n 'Vether', \n 'Uether' \n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },\n ETH_POLLING_TIMEOUT: 1000,\n ETH_DEFAULTBLOCK: 'latest'\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file utils.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] utils\n * @constructor\n */\n\nvar BigNumber = require('bignumber.js');\n\nvar unitMap = {\n 'wei': '1',\n 'kwei': '1000',\n 'ada': '1000',\n 'mwei': '1000000',\n 'babbage': '1000000',\n 'gwei': '1000000000',\n 'shannon': '1000000000',\n 'szabo': '1000000000000',\n 'finney': '1000000000000000',\n 'ether': '1000000000000000000',\n 'kether': '1000000000000000000000',\n 'grand': '1000000000000000000000',\n 'einstein': '1000000000000000000000',\n 'mether': '1000000000000000000000000',\n 'gether': '1000000000000000000000000000',\n 'tether': '1000000000000000000000000000000'\n};\n\n/**\n * Should be called to pad string to expected length\n *\n * @method padLeft\n * @param {String} string to be padded\n * @param {Number} characters that result string should have\n * @param {String} sign, by default 0\n * @returns {String} right aligned string\n */\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/** Finds first index of array element matching pattern\n *\n * @method findIndex\n * @param {Array}\n * @param {Function} pattern\n * @returns {Number} index of element\n */\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\n/** \n * Should be called to get sting from it's hex representation\n *\n * @method toAscii\n * @param {String} string in hex\n * @returns {String} ascii string representation of hex value\n */\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n if (code === 0) {\n break;\n }\n\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @returns {String} hex representation of input string\n */\nvar toHexNative = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @param {Number} optional padding\n * @returns {String} hex representation of input string\n */\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHexNative(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/**\n * Should be called to get display name of contract function\n * \n * @method extractDisplayName\n * @param {String} name of function/event\n * @returns {String} display name for function/event eg. multiply(uint256) -> multiply\n */\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/**\n * Filters all functions from input abi\n *\n * @method filterFunctions\n * @param {Array} abi\n * @returns {Array} abi array with filtered objects of type 'function'\n */\nvar filterFunctions = function (json) {\n return json.filter(function (current) {\n return current.type === 'function'; \n }); \n};\n\n/**\n * Filters all events from input abi\n *\n * @method filterEvents\n * @param {Array} abi\n * @returns {Array} abi array with filtered objects of type 'event'\n */\nvar filterEvents = function (json) {\n return json.filter(function (current) {\n return current.type === 'event';\n });\n};\n\n/**\n * Converts value to it's decimal representation in string\n *\n * @method toDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar toDecimal = function (value) {\n return toBigNumber(value).toNumber();\n};\n\n/**\n * Converts value to it's hex representation\n *\n * @method fromDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar fromDecimal = function (value) {\n var number = toBigNumber(value);\n var result = number.toString(16);\n\n return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result;\n};\n\n/**\n * Auto converts any given value into it's hex representation.\n *\n * And even stringifys objects before.\n *\n * @method toHex\n * @param {String|Number|BigNumber|Object}\n * @return {String}\n */\nvar toHex = function (val) {\n /*jshint maxcomplexity:7 */\n\n if (isBoolean(val))\n return fromDecimal(+val);\n\n if (isBigNumber(val))\n return fromDecimal(val);\n\n if (isObject(val))\n return fromAscii(JSON.stringify(val));\n\n // if its a negative number, pass it through fromDecimal\n if (isString(val)) {\n if (val.indexOf('-0x') === 0)\n return fromDecimal(val);\n else if (!isFinite(val))\n return fromAscii(val);\n }\n\n return fromDecimal(val);\n};\n\n/**\n * Returns value of unit in Wei\n *\n * @method getValueOfUnit\n * @param {String} unit the unit to convert to, default ether\n * @returns {BigNumber} value of the unit (in Wei)\n * @throws error if the unit is not correct:w\n */\nvar getValueOfUnit = function (unit) {\n unit = unit ? unit.toLowerCase() : 'ether';\n var unitValue = unitMap[unit];\n if (unitValue === undefined) {\n throw new Error('This unit doesn\\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2));\n }\n return new BigNumber(unitValue, 10);\n};\n\n/**\n * Takes a number of wei and converts it to any other ether unit.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method fromWei\n * @param {Number|String} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert to, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar fromWei = function(number, unit) {\n var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes a number of a unit and converts it to wei.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method toWei\n * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert from, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar toWei = function(number, unit) {\n var returnValue = toBigNumber(number).times(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes an input and transforms it into an bignumber\n *\n * @method toBigNumber\n * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber\n * @return {BigNumber} BigNumber\n*/\nvar toBigNumber = function(number) {\n /*jshint maxcomplexity:5 */\n number = number || 0;\n if (isBigNumber(number))\n return number;\n\n if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {\n return new BigNumber(number.replace('0x',''), 16);\n }\n \n return new BigNumber(number.toString(10), 10);\n};\n\n/**\n * Takes and input transforms it into bignumber and if it is negative value, into two's complement\n *\n * @method toTwosComplement\n * @param {Number|String|BigNumber}\n * @return {BigNumber}\n */\nvar toTwosComplement = function (number) {\n var bigNumber = toBigNumber(number);\n if (bigNumber.lessThan(0)) {\n return new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(bigNumber).plus(1);\n }\n return bigNumber;\n};\n\n/**\n * Checks if the given string has proper length\n *\n * @method isAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isAddress = function (address) {\n return /^0x[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Transforms given string to valid 20 bytes-length addres with 0x prefix\n *\n * @method toAddress\n * @param {String} address\n * @return {String} formatted address\n */\nvar toAddress = function (address) {\n if (isAddress(address)) {\n return address;\n }\n \n if (/^[0-9a-f]{40}$/.test(address)) {\n return '0x' + address;\n }\n\n return '0x' + padLeft(toHex(address).substr(2), 40);\n};\n\n/**\n * Returns true if object is BigNumber, otherwise false\n *\n * @method isBigNumber\n * @param {Object}\n * @return {Boolean} \n */\nvar isBigNumber = function (object) {\n return object instanceof BigNumber ||\n (object && object.constructor && object.constructor.name === 'BigNumber');\n};\n\n/**\n * Returns true if object is string, otherwise false\n * \n * @method isString\n * @param {Object}\n * @return {Boolean}\n */\nvar isString = function (object) {\n return typeof object === 'string' ||\n (object && object.constructor && object.constructor.name === 'String');\n};\n\n/**\n * Returns true if object is function, otherwise false\n *\n * @method isFunction\n * @param {Object}\n * @return {Boolean}\n */\nvar isFunction = function (object) {\n return typeof object === 'function';\n};\n\n/**\n * Returns true if object is Objet, otherwise false\n *\n * @method isObject\n * @param {Object}\n * @return {Boolean}\n */\nvar isObject = function (object) {\n return typeof object === 'object';\n};\n\n/**\n * Returns true if object is boolean, otherwise false\n *\n * @method isBoolean\n * @param {Object}\n * @return {Boolean}\n */\nvar isBoolean = function (object) {\n return typeof object === 'boolean';\n};\n\n/**\n * Returns true if object is array, otherwise false\n *\n * @method isArray\n * @param {Object}\n * @return {Boolean}\n */\nvar isArray = function (object) {\n return object instanceof Array; \n};\n\n/**\n * Returns true if given string is valid json object\n * \n * @method isJson\n * @param {String}\n * @return {Boolean}\n */\nvar isJson = function (str) {\n try {\n return !!JSON.parse(str);\n } catch (e) {\n return false;\n }\n};\n\nmodule.exports = {\n padLeft: padLeft,\n findIndex: findIndex,\n toHex: toHex,\n toDecimal: toDecimal,\n fromDecimal: fromDecimal,\n toAscii: toAscii,\n fromAscii: fromAscii,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n filterFunctions: filterFunctions,\n filterEvents: filterEvents,\n toWei: toWei,\n fromWei: fromWei,\n toBigNumber: toBigNumber,\n toTwosComplement: toTwosComplement,\n toAddress: toAddress,\n isBigNumber: isBigNumber,\n isAddress: isAddress,\n isFunction: isFunction,\n isString: isString,\n isObject: isObject,\n isBoolean: isBoolean,\n isArray: isArray,\n isJson: isJson\n};\n\n", - "module.exports={\n \"version\": \"0.2.5\"\n}\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar version = require('./version.json');\nvar net = require('./web3/net');\nvar eth = require('./web3/eth');\nvar db = require('./web3/db');\nvar shh = require('./web3/shh');\nvar watches = require('./web3/watches');\nvar Filter = require('./web3/filter');\nvar utils = require('./utils/utils');\nvar formatters = require('./web3/formatters');\nvar RequestManager = require('./web3/requestmanager');\nvar c = require('./utils/config');\nvar Method = require('./web3/method');\nvar Property = require('./web3/property');\n\nvar web3Methods = [\n new Method({\n name: 'sha3',\n call: 'web3_sha3',\n params: 1\n })\n];\n\nvar web3Properties = [\n new Property({\n name: 'version.client',\n getter: 'web3_clientVersion'\n }),\n new Property({\n name: 'version.network',\n getter: 'net_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.ethereum',\n getter: 'eth_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.whisper',\n getter: 'shh_version',\n inputFormatter: utils.toDecimal\n })\n];\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n method.attachToObject(obj);\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n property.attachToObject(obj);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {};\nweb3.providers = {};\nweb3.version = {};\nweb3.version.api = version.version;\nweb3.eth = {};\n\n/*jshint maxparams:4 */\nweb3.eth.filter = function (fil, eventParams, options, formatter) {\n\n // if its event, treat it differently\n // TODO: simplify and remove\n if (fil._isEvent) {\n return fil(eventParams, options);\n }\n\n // what outputLogFormatter? that's wrong\n //return new Filter(fil, watches.eth(), formatters.outputLogFormatter);\n return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);\n};\n/*jshint maxparams:3 */\n\nweb3.shh = {};\nweb3.shh.filter = function (fil) {\n return new Filter(fil, watches.shh(), formatters.outputPostFormatter);\n};\nweb3.net = {};\nweb3.db = {};\nweb3.setProvider = function (provider) {\n RequestManager.getInstance().setProvider(provider);\n};\nweb3.reset = function () {\n RequestManager.getInstance().reset();\n};\nweb3.toHex = utils.toHex;\nweb3.toAscii = utils.toAscii;\nweb3.fromAscii = utils.fromAscii;\nweb3.toDecimal = utils.toDecimal;\nweb3.fromDecimal = utils.fromDecimal;\nweb3.toBigNumber = utils.toBigNumber;\nweb3.toWei = utils.toWei;\nweb3.fromWei = utils.fromWei;\nweb3.isAddress = utils.isAddress;\n\n// ADD defaultblock\nObject.defineProperty(web3.eth, 'defaultBlock', {\n get: function () {\n return c.ETH_DEFAULTBLOCK;\n },\n set: function (val) {\n c.ETH_DEFAULTBLOCK = val;\n return c.ETH_DEFAULTBLOCK;\n }\n});\n\n\n/// setups all api methods\nsetupMethods(web3, web3Methods);\nsetupProperties(web3, web3Properties);\nsetupMethods(web3.net, net.methods);\nsetupProperties(web3.net, net.properties);\nsetupMethods(web3.eth, eth.methods);\nsetupProperties(web3.eth, eth.properties);\nsetupMethods(web3.db, db.methods);\nsetupMethods(web3.shh, shh.methods);\n\nmodule.exports = web3;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('../web3'); \nvar abi = require('../solidity/abi');\nvar utils = require('../utils/utils');\nvar eventImpl = require('./event');\nvar signature = require('./signature');\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransaction = false;\n contract._options = options;\n return contract;\n };\n\n contract.sendTransaction = function (options) {\n contract._isTransaction = true;\n contract._options = options;\n return contract;\n };\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n // create contract functions\n utils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n /*jshint maxcomplexity:7 */\n var params = Array.prototype.slice.call(arguments);\n var sign = signature.functionSignatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = sign + parsed;\n \n var isTransaction = contract._isTransaction === true || (contract._isTransaction !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransaction = null;\n\n if (isTransaction) {\n \n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.sendTransaction(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topics', {\n get: function() {\n return utils.filterEvents(desc).map(function (e) {\n return signature.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n utils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var sign = signature.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, sign, e);\n var o = event.apply(null, params);\n var outputFormatter = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.filter(o, undefined, undefined, outputFormatter);\n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var MyContract = web3.eth.contract(abi); // creation of contract prototype\n *\n * var contractInstance = new MyContract('0x0123123121');\n *\n * contractInstance.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * contractInstance.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * contractInstance.sendTransaction().myMethod('this is test string param for transact'); // myMethod sendTransaction\n *\n * @param abi - abi json description of the contract, which is being created\n * @returns contract object\n */\nvar contract = function (abi) {\n\n // return prototype\n return Contract.bind(null, abi);\n};\n\nfunction Contract(abi, address) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n abi.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, abi, address);\n addEventRelatedPropertiesToContract(result, abi, address);\n addEventsToContract(result, abi, address);\n\n return result;\n}\n\nmodule.exports = contract;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file utils.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] utils\n * @constructor\n */\n\nvar BigNumber = require('bignumber.js');\n\nvar unitMap = {\n 'wei': '1',\n 'kwei': '1000',\n 'ada': '1000',\n 'mwei': '1000000',\n 'babbage': '1000000',\n 'gwei': '1000000000',\n 'shannon': '1000000000',\n 'szabo': '1000000000000',\n 'finney': '1000000000000000',\n 'ether': '1000000000000000000',\n 'kether': '1000000000000000000000',\n 'grand': '1000000000000000000000',\n 'einstein': '1000000000000000000000',\n 'mether': '1000000000000000000000000',\n 'gether': '1000000000000000000000000000',\n 'tether': '1000000000000000000000000000000'\n};\n\n/**\n * Should be called to pad string to expected length\n *\n * @method padLeft\n * @param {String} string to be padded\n * @param {Number} characters that result string should have\n * @param {String} sign, by default 0\n * @returns {String} right aligned string\n */\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/** Finds first index of array element matching pattern\n *\n * @method findIndex\n * @param {Array}\n * @param {Function} pattern\n * @returns {Number} index of element\n */\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\n/** \n * Should be called to get sting from it's hex representation\n *\n * @method toAscii\n * @param {String} string in hex\n * @returns {String} ascii string representation of hex value\n */\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n if (code === 0) {\n break;\n }\n\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @returns {String} hex representation of input string\n */\nvar toHexNative = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @param {Number} optional padding\n * @returns {String} hex representation of input string\n */\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHexNative(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/**\n * Should be called to get display name of contract function\n * \n * @method extractDisplayName\n * @param {String} name of function/event\n * @returns {String} display name for function/event eg. multiply(uint256) -> multiply\n */\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/**\n * Converts value to it's decimal representation in string\n *\n * @method toDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar toDecimal = function (value) {\n return toBigNumber(value).toNumber();\n};\n\n/**\n * Converts value to it's hex representation\n *\n * @method fromDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar fromDecimal = function (value) {\n var number = toBigNumber(value);\n var result = number.toString(16);\n\n return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result;\n};\n\n/**\n * Auto converts any given value into it's hex representation.\n *\n * And even stringifys objects before.\n *\n * @method toHex\n * @param {String|Number|BigNumber|Object}\n * @return {String}\n */\nvar toHex = function (val) {\n /*jshint maxcomplexity:7 */\n\n if (isBoolean(val))\n return fromDecimal(+val);\n\n if (isBigNumber(val))\n return fromDecimal(val);\n\n if (isObject(val))\n return fromAscii(JSON.stringify(val));\n\n // if its a negative number, pass it through fromDecimal\n if (isString(val)) {\n if (val.indexOf('-0x') === 0)\n return fromDecimal(val);\n else if (!isFinite(val))\n return fromAscii(val);\n }\n\n return fromDecimal(val);\n};\n\n/**\n * Returns value of unit in Wei\n *\n * @method getValueOfUnit\n * @param {String} unit the unit to convert to, default ether\n * @returns {BigNumber} value of the unit (in Wei)\n * @throws error if the unit is not correct:w\n */\nvar getValueOfUnit = function (unit) {\n unit = unit ? unit.toLowerCase() : 'ether';\n var unitValue = unitMap[unit];\n if (unitValue === undefined) {\n throw new Error('This unit doesn\\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2));\n }\n return new BigNumber(unitValue, 10);\n};\n\n/**\n * Takes a number of wei and converts it to any other ether unit.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method fromWei\n * @param {Number|String} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert to, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar fromWei = function(number, unit) {\n var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes a number of a unit and converts it to wei.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method toWei\n * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert from, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar toWei = function(number, unit) {\n var returnValue = toBigNumber(number).times(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes an input and transforms it into an bignumber\n *\n * @method toBigNumber\n * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber\n * @return {BigNumber} BigNumber\n*/\nvar toBigNumber = function(number) {\n /*jshint maxcomplexity:5 */\n number = number || 0;\n if (isBigNumber(number))\n return number;\n\n if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {\n return new BigNumber(number.replace('0x',''), 16);\n }\n \n return new BigNumber(number.toString(10), 10);\n};\n\n/**\n * Takes and input transforms it into bignumber and if it is negative value, into two's complement\n *\n * @method toTwosComplement\n * @param {Number|String|BigNumber}\n * @return {BigNumber}\n */\nvar toTwosComplement = function (number) {\n var bigNumber = toBigNumber(number);\n if (bigNumber.lessThan(0)) {\n return new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(bigNumber).plus(1);\n }\n return bigNumber;\n};\n\n/**\n * Checks if the given string is strictly an address\n *\n * @method isStrictAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isStrictAddress = function (address) {\n return /^0x[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Checks if the given string is an address\n *\n * @method isAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isAddress = function (address) {\n return /^(0x)?[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Transforms given string to valid 20 bytes-length addres with 0x prefix\n *\n * @method toAddress\n * @param {String} address\n * @return {String} formatted address\n */\nvar toAddress = function (address) {\n if (isStrictAddress(address)) {\n return address;\n }\n \n if (/^[0-9a-f]{40}$/.test(address)) {\n return '0x' + address;\n }\n\n return '0x' + padLeft(toHex(address).substr(2), 40);\n};\n\n/**\n * Returns true if object is BigNumber, otherwise false\n *\n * @method isBigNumber\n * @param {Object}\n * @return {Boolean} \n */\nvar isBigNumber = function (object) {\n return object instanceof BigNumber ||\n (object && object.constructor && object.constructor.name === 'BigNumber');\n};\n\n/**\n * Returns true if object is string, otherwise false\n * \n * @method isString\n * @param {Object}\n * @return {Boolean}\n */\nvar isString = function (object) {\n return typeof object === 'string' ||\n (object && object.constructor && object.constructor.name === 'String');\n};\n\n/**\n * Returns true if object is function, otherwise false\n *\n * @method isFunction\n * @param {Object}\n * @return {Boolean}\n */\nvar isFunction = function (object) {\n return typeof object === 'function';\n};\n\n/**\n * Returns true if object is Objet, otherwise false\n *\n * @method isObject\n * @param {Object}\n * @return {Boolean}\n */\nvar isObject = function (object) {\n return typeof object === 'object';\n};\n\n/**\n * Returns true if object is boolean, otherwise false\n *\n * @method isBoolean\n * @param {Object}\n * @return {Boolean}\n */\nvar isBoolean = function (object) {\n return typeof object === 'boolean';\n};\n\n/**\n * Returns true if object is array, otherwise false\n *\n * @method isArray\n * @param {Object}\n * @return {Boolean}\n */\nvar isArray = function (object) {\n return object instanceof Array; \n};\n\n/**\n * Returns true if given string is valid json object\n * \n * @method isJson\n * @param {String}\n * @return {Boolean}\n */\nvar isJson = function (str) {\n try {\n return !!JSON.parse(str);\n } catch (e) {\n return false;\n }\n};\n\nmodule.exports = {\n padLeft: padLeft,\n findIndex: findIndex,\n toHex: toHex,\n toDecimal: toDecimal,\n fromDecimal: fromDecimal,\n toAscii: toAscii,\n fromAscii: fromAscii,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n toWei: toWei,\n fromWei: fromWei,\n toBigNumber: toBigNumber,\n toTwosComplement: toTwosComplement,\n toAddress: toAddress,\n isBigNumber: isBigNumber,\n isStrictAddress: isStrictAddress,\n isAddress: isAddress,\n isFunction: isFunction,\n isString: isString,\n isObject: isObject,\n isBoolean: isBoolean,\n isArray: isArray,\n isJson: isJson\n};\n\n", + "module.exports={\n \"version\": \"0.2.6\"\n}\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar version = require('./version.json');\nvar net = require('./web3/net');\nvar eth = require('./web3/eth');\nvar db = require('./web3/db');\nvar shh = require('./web3/shh');\nvar watches = require('./web3/watches');\nvar Filter = require('./web3/filter');\nvar utils = require('./utils/utils');\nvar formatters = require('./web3/formatters');\nvar RequestManager = require('./web3/requestmanager');\nvar c = require('./utils/config');\nvar Method = require('./web3/method');\nvar Property = require('./web3/property');\n\nvar web3Methods = [\n new Method({\n name: 'sha3',\n call: 'web3_sha3',\n params: 1\n })\n];\n\nvar web3Properties = [\n new Property({\n name: 'version.client',\n getter: 'web3_clientVersion'\n }),\n new Property({\n name: 'version.network',\n getter: 'net_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.ethereum',\n getter: 'eth_protocolVersion',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.whisper',\n getter: 'shh_version',\n inputFormatter: utils.toDecimal\n })\n];\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n method.attachToObject(obj);\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n property.attachToObject(obj);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {};\nweb3.providers = {};\nweb3.version = {};\nweb3.version.api = version.version;\nweb3.eth = {};\n\n/*jshint maxparams:4 */\nweb3.eth.filter = function (fil, eventParams, options, formatter) {\n\n // if its event, treat it differently\n // TODO: simplify and remove\n if (fil._isEvent) {\n return fil(eventParams, options);\n }\n\n // what outputLogFormatter? that's wrong\n //return new Filter(fil, watches.eth(), formatters.outputLogFormatter);\n return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);\n};\n/*jshint maxparams:3 */\n\nweb3.shh = {};\nweb3.shh.filter = function (fil) {\n return new Filter(fil, watches.shh(), formatters.outputPostFormatter);\n};\nweb3.net = {};\nweb3.db = {};\nweb3.setProvider = function (provider) {\n RequestManager.getInstance().setProvider(provider);\n};\nweb3.reset = function () {\n RequestManager.getInstance().reset();\n};\nweb3.toHex = utils.toHex;\nweb3.toAscii = utils.toAscii;\nweb3.fromAscii = utils.fromAscii;\nweb3.toDecimal = utils.toDecimal;\nweb3.fromDecimal = utils.fromDecimal;\nweb3.toBigNumber = utils.toBigNumber;\nweb3.toWei = utils.toWei;\nweb3.fromWei = utils.fromWei;\nweb3.isAddress = utils.isAddress;\n\n// ADD defaultblock\nObject.defineProperty(web3.eth, 'defaultBlock', {\n get: function () {\n return c.ETH_DEFAULTBLOCK;\n },\n set: function (val) {\n c.ETH_DEFAULTBLOCK = val;\n return c.ETH_DEFAULTBLOCK;\n }\n});\n\n\n/// setups all api methods\nsetupMethods(web3, web3Methods);\nsetupProperties(web3, web3Properties);\nsetupMethods(web3.net, net.methods);\nsetupProperties(web3.net, net.properties);\nsetupMethods(web3.eth, eth.methods);\nsetupProperties(web3.eth, eth.properties);\nsetupMethods(web3.db, db.methods);\nsetupMethods(web3.shh, shh.methods);\n\nmodule.exports = web3;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('../web3'); \nvar solAbi = require('../solidity/abi');\nvar utils = require('../utils/utils');\nvar solUtils = require('../solidity/utils');\nvar eventImpl = require('./event');\nvar signature = require('./signature');\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransaction = false;\n contract._options = options;\n return contract;\n };\n\n contract.sendTransaction = function (options) {\n contract._isTransaction = true;\n contract._options = options;\n return contract;\n };\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = solAbi.inputParser(desc);\n var outputParser = solAbi.outputParser(desc);\n\n // create contract functions\n solUtils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n /*jshint maxcomplexity:7 */\n var params = Array.prototype.slice.call(arguments);\n var sign = signature.functionSignatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = sign + parsed;\n \n var isTransaction = contract._isTransaction === true || (contract._isTransaction !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransaction = null;\n\n if (isTransaction) {\n \n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.sendTransaction(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(solUtils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topics', {\n get: function() {\n return solUtils.filterEvents(desc).map(function (e) {\n return signature.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n solUtils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var sign = signature.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, sign, e);\n var o = event.apply(null, params);\n var outputFormatter = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.filter(o, undefined, undefined, outputFormatter);\n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var MyContract = web3.eth.contract(abi); // creation of contract prototype\n *\n * var contractInstance = new MyContract('0x0123123121');\n *\n * contractInstance.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * contractInstance.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * contractInstance.sendTransaction().myMethod('this is test string param for transact'); // myMethod sendTransaction\n *\n * @param abi - abi json description of the contract, which is being created\n * @returns contract object\n */\nvar contract = function (abi) {\n\n // return prototype\n return Contract.bind(null, abi);\n};\n\nfunction Contract(abi, options) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n abi.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var address = '';\n if (utils.isAddress(options)) {\n address = options;\n } else { // is a source code!\n // TODO, parse the rest of the args\n var code = options;\n var args = Array.prototype.slice.call(arguments, 2);\n var bytes = solAbi.formatConstructorParams(abi, args);\n address = web3.eth.sendTransaction({data: code + bytes});\n }\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, abi, address);\n addEventRelatedPropertiesToContract(result, abi, address);\n addEventsToContract(result, abi, address);\n\n return result;\n}\n\nmodule.exports = contract;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file db.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\nvar putString = new Method({\n name: 'putString',\n call: 'db_putString',\n params: 3\n});\n\n\nvar getString = new Method({\n name: 'getString',\n call: 'db_getString',\n params: 2\n});\n\nvar putHex = new Method({\n name: 'putHex',\n call: 'db_putHex',\n params: 3\n});\n\nvar getHex = new Method({\n name: 'getHex',\n call: 'db_getHex',\n params: 2\n});\n\nvar methods = [\n putString, getString, putHex, getHex\n];\n\nmodule.exports = {\n methods: methods\n};\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file errors.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\n\nmodule.exports = {\n InvalidNumberOfParams: new Error('Invalid number of input parameters'),\n InvalidProvider: new Error('Providor not set or invalid'),\n InvalidResponse: function(result){\n var message = 'Invalid JSON RPC response';\n\n if(utils.isObject(result) && result.error && result.error.message) {\n message = result.error.message;\n }\n\n return new Error(message);\n }\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file eth.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\n/**\n * Web3\n * \n * @module web3\n */\n\n/**\n * Eth methods and properties\n *\n * An example method object can look as follows:\n *\n * {\n * name: 'getBlock',\n * call: blockCall,\n * params: 2,\n * outputFormatter: formatters.outputBlockFormatter,\n * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter\n * utils.toHex, // formats paramter 1\n * function(param){ return !!param; } // formats paramter 2\n * ]\n * },\n *\n * @class [web3] eth\n * @constructor\n */\n\n\"use strict\";\n\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Method = require('./method');\nvar Property = require('./property');\n\nvar blockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? \"eth_getBlockByHash\" : \"eth_getBlockByNumber\";\n};\n\nvar transactionFromBlockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';\n};\n\nvar uncleCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';\n};\n\nvar getBlockTransactionCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';\n};\n\nvar uncleCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';\n};\n\n/// @returns an array of objects describing web3.eth api methods\n\nvar getBalance = new Method({\n name: 'getBalance', \n call: 'eth_getBalance', \n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: formatters.outputBigNumberFormatter\n});\n\nvar getStorageAt = new Method({\n name: 'getStorageAt', \n call: 'eth_getStorageAt', \n params: 3,\n inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getCode = new Method({\n name: 'getCode',\n call: 'eth_getCode',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getBlock = new Method({\n name: 'getBlock', \n call: blockCall,\n params: 2,\n inputFormatter: [utils.toHex, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter\n});\n\nvar getUncle = new Method({\n name: 'getUncle',\n call: uncleCall,\n params: 3,\n inputFormatter: [utils.toHex, utils.toHex, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter,\n\n});\n\nvar getCompilers = new Method({\n name: 'getCompilers',\n call: 'eth_getCompilers',\n params: 0\n});\n\nvar getBlockTransactionCount = new Method({\n name: 'getBlockTransactionCount',\n call: getBlockTransactionCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getBlockUncleCount = new Method({\n name: 'getBlockUncleCount',\n call: uncleCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getTransaction = new Method({\n name: 'getTransaction',\n call: 'eth_getTransactionByHash',\n params: 1,\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionFromBlock = new Method({\n name: 'getTransactionFromBlock',\n call: transactionFromBlockCall,\n params: 2,\n inputFormatter: [utils.toHex, utils.toHex],\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionCount = new Method({\n name: 'getTransactionCount',\n call: 'eth_getTransactionCount',\n params: 2,\n inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar sendTransaction = new Method({\n name: 'sendTransaction',\n call: 'eth_sendTransaction',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter]\n});\n\nvar call = new Method({\n name: 'call',\n call: 'eth_call',\n params: 2,\n inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar compileSolidity = new Method({\n name: 'compile.solidity',\n call: 'eth_compileSolidity',\n params: 1\n});\n\nvar compileLLL = new Method({\n name: 'compile.lll',\n call: 'eth_compileLLL',\n params: 1\n});\n\nvar compileSerpent = new Method({\n name: 'compile.serpent',\n call: 'eth_compileSerpent',\n params: 1\n});\n\nvar flush = new Method({\n name: 'flush',\n call: 'eth_flush',\n params: 0\n});\n\nvar methods = [\n getBalance,\n getStorageAt,\n getCode,\n getBlock,\n getUncle,\n getCompilers,\n getBlockTransactionCount,\n getBlockUncleCount,\n getTransaction,\n getTransactionFromBlock,\n getTransactionCount,\n call,\n sendTransaction,\n compileSolidity,\n compileLLL,\n compileSerpent,\n flush\n];\n\n/// @returns an array of objects describing web3.eth api properties\n\n\n\nvar properties = [\n new Property({\n name: 'coinbase',\n getter: 'eth_coinbase'\n }),\n new Property({\n name: 'mining',\n getter: 'eth_mining'\n }),\n new Property({\n name: 'gasPrice',\n getter: 'eth_gasPrice',\n outputFormatter: formatters.inputNumberFormatter\n }),\n new Property({\n name: 'accounts',\n getter: 'eth_accounts'\n }),\n new Property({\n name: 'blockNumber',\n getter: 'eth_blockNumber',\n outputFormatter: utils.toDecimal\n })\n];\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file eth.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\n/**\n * Web3\n * \n * @module web3\n */\n\n/**\n * Eth methods and properties\n *\n * An example method object can look as follows:\n *\n * {\n * name: 'getBlock',\n * call: blockCall,\n * params: 2,\n * outputFormatter: formatters.outputBlockFormatter,\n * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter\n * utils.toHex, // formats paramter 1\n * function(param){ return !!param; } // formats paramter 2\n * ]\n * },\n *\n * @class [web3] eth\n * @constructor\n */\n\n\"use strict\";\n\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Method = require('./method');\nvar Property = require('./property');\n\nvar blockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? \"eth_getBlockByHash\" : \"eth_getBlockByNumber\";\n};\n\nvar transactionFromBlockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';\n};\n\nvar uncleCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';\n};\n\nvar getBlockTransactionCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';\n};\n\nvar uncleCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';\n};\n\n/// @returns an array of objects describing web3.eth api methods\n\nvar getBalance = new Method({\n name: 'getBalance', \n call: 'eth_getBalance', \n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: formatters.outputBigNumberFormatter\n});\n\nvar getStorageAt = new Method({\n name: 'getStorageAt', \n call: 'eth_getStorageAt', \n params: 3,\n inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getCode = new Method({\n name: 'getCode',\n call: 'eth_getCode',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getBlock = new Method({\n name: 'getBlock', \n call: blockCall,\n params: 2,\n inputFormatter: [utils.toHex, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter\n});\n\nvar getUncle = new Method({\n name: 'getUncle',\n call: uncleCall,\n params: 2,\n inputFormatter: [utils.toHex, utils.toHex],\n outputFormatter: formatters.outputBlockFormatter,\n\n});\n\nvar getCompilers = new Method({\n name: 'getCompilers',\n call: 'eth_getCompilers',\n params: 0\n});\n\nvar getBlockTransactionCount = new Method({\n name: 'getBlockTransactionCount',\n call: getBlockTransactionCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getBlockUncleCount = new Method({\n name: 'getBlockUncleCount',\n call: uncleCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getTransaction = new Method({\n name: 'getTransaction',\n call: 'eth_getTransactionByHash',\n params: 1,\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionFromBlock = new Method({\n name: 'getTransactionFromBlock',\n call: transactionFromBlockCall,\n params: 2,\n inputFormatter: [utils.toHex, utils.toHex],\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionCount = new Method({\n name: 'getTransactionCount',\n call: 'eth_getTransactionCount',\n params: 2,\n inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar sendTransaction = new Method({\n name: 'sendTransaction',\n call: 'eth_sendTransaction',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter]\n});\n\nvar call = new Method({\n name: 'call',\n call: 'eth_call',\n params: 2,\n inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar compileSolidity = new Method({\n name: 'compile.solidity',\n call: 'eth_compileSolidity',\n params: 1\n});\n\nvar compileLLL = new Method({\n name: 'compile.lll',\n call: 'eth_compileLLL',\n params: 1\n});\n\nvar compileSerpent = new Method({\n name: 'compile.serpent',\n call: 'eth_compileSerpent',\n params: 1\n});\n\nvar flush = new Method({\n name: 'flush',\n call: 'eth_flush',\n params: 0\n});\n\nvar methods = [\n getBalance,\n getStorageAt,\n getCode,\n getBlock,\n getUncle,\n getCompilers,\n getBlockTransactionCount,\n getBlockUncleCount,\n getTransaction,\n getTransactionFromBlock,\n getTransactionCount,\n call,\n sendTransaction,\n compileSolidity,\n compileLLL,\n compileSerpent,\n flush\n];\n\n/// @returns an array of objects describing web3.eth api properties\n\n\n\nvar properties = [\n new Property({\n name: 'coinbase',\n getter: 'eth_coinbase'\n }),\n new Property({\n name: 'mining',\n getter: 'eth_mining'\n }),\n new Property({\n name: 'gasPrice',\n getter: 'eth_gasPrice',\n outputFormatter: formatters.outputBigNumberFormatter\n }),\n new Property({\n name: 'accounts',\n getter: 'eth_accounts'\n }),\n new Property({\n name: 'blockNumber',\n getter: 'eth_blockNumber',\n outputFormatter: utils.toDecimal\n })\n];\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('../solidity/abi');\nvar utils = require('../utils/utils');\nvar signature = require('./signature');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return '0x' + abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, sign, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.filter'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topics = [];\n o.topics.push(sign);\n if (indexed) {\n o.topics = o.topics.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexedCopy.splice(0, 1)[0];\n else\n value = notIndexedCopy.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n hash: output.hash,\n args: {}\n };\n\n if (!output.topics) {\n return result;\n }\n output.data = output.data || '';\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topics.slice(1, output.topics.length).map(function (topics) { return topics.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var sign = signature.eventSignatureFromAscii(events[i].name); \n if (sign === payload.topics[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar RequestManager = require('./requestmanager');\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n\n if (utils.isString(options)) {\n return options;\n } \n\n options = options || {};\n\n // make sure topics, get converted to hex\n options.topics = options.topics || [];\n options.topics = options.topics.map(function(topic){\n return utils.toHex(topic);\n });\n\n // lazy load\n return {\n topics: options.topics,\n to: options.to,\n address: options.address,\n fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),\n toBlock: formatters.inputBlockNumberFormatter(options.toBlock) \n }; \n};\n\nvar Filter = function (options, methods, formatter) {\n var implementation = {};\n methods.forEach(function (method) {\n method.attachToObject(implementation);\n });\n this.options = getOptions(options);\n this.implementation = implementation;\n this.callbacks = [];\n this.formatter = formatter;\n this.filterId = this.implementation.newFilter(this.options);\n};\n\nFilter.prototype.watch = function (callback) {\n this.callbacks.push(callback);\n var self = this;\n\n var onMessage = function (error, messages) {\n if (error) {\n return self.callbacks.forEach(function (callback) {\n callback(error);\n });\n }\n\n messages.forEach(function (message) {\n message = self.formatter ? self.formatter(message) : message;\n self.callbacks.forEach(function (callback) {\n callback(null, message);\n });\n });\n };\n\n RequestManager.getInstance().startPolling({\n method: this.implementation.poll.call,\n params: [this.filterId],\n }, this.filterId, onMessage, this.stopWatching.bind(this));\n};\n\nFilter.prototype.stopWatching = function () {\n RequestManager.getInstance().stopPolling(this.filterId);\n this.implementation.uninstallFilter(this.filterId);\n this.callbacks = [];\n};\n\nFilter.prototype.get = function () {\n var logs = this.implementation.getLogs(this.filterId);\n var self = this;\n return logs.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n });\n};\n\nmodule.exports = Filter;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file formatters.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar config = require('../utils/config');\n\n/**\n * Should the format output to a big number\n *\n * @method outputBigNumberFormatter\n * @param {String|Number|BigNumber}\n * @returns {BigNumber} object\n */\nvar outputBigNumberFormatter = function (number) {\n return utils.toBigNumber(number);\n};\n\nvar isPredefinedBlockNumber = function (blockNumber) {\n return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest';\n};\n\nvar inputDefaultBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return config.ETH_DEFAULTBLOCK;\n }\n return inputBlockNumberFormatter(blockNumber);\n};\n\nvar inputBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return undefined;\n } else if (isPredefinedBlockNumber(blockNumber)) {\n return blockNumber;\n }\n return utils.toHex(blockNumber);\n};\n\n/**\n * Formats the input of a transaction and converts all values to HEX\n *\n * @method inputTransactionFormatter\n * @param {Object} transaction options\n * @returns object\n*/\nvar inputTransactionFormatter = function (options){\n\n // make code -> data\n if (options.code) {\n options.data = options.code;\n delete options.code;\n }\n\n ['gasPrice', 'gas', 'value'].filter(function (key) {\n return options[key] !== undefined;\n }).forEach(function(key){\n options[key] = utils.fromDecimal(options[key]);\n });\n\n return options; \n};\n\n/**\n * Formats the output of a transaction to its proper values\n * \n * @method outputTransactionFormatter\n * @param {Object} transaction\n * @returns {Object} transaction\n*/\nvar outputTransactionFormatter = function (tx){\n tx.blockNumber = utils.toDecimal(tx.blockNumber);\n tx.transactionIndex = utils.toDecimal(tx.transactionIndex);\n tx.gas = utils.toDecimal(tx.gas);\n tx.gasPrice = utils.toBigNumber(tx.gasPrice);\n tx.value = utils.toBigNumber(tx.value);\n return tx;\n};\n\n/**\n * Formats the output of a block to its proper values\n *\n * @method outputBlockFormatter\n * @param {Object} block object \n * @returns {Object} block object\n*/\nvar outputBlockFormatter = function(block) {\n\n // transform to number\n block.gasLimit = utils.toDecimal(block.gasLimit);\n block.gasUsed = utils.toDecimal(block.gasUsed);\n block.size = utils.toDecimal(block.size);\n block.timestamp = utils.toDecimal(block.timestamp);\n block.number = utils.toDecimal(block.number);\n\n block.minGasPrice = utils.toBigNumber(block.minGasPrice);\n block.difficulty = utils.toBigNumber(block.difficulty);\n block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);\n\n if (utils.isArray(block.transactions)) {\n block.transactions.forEach(function(item){\n if(!utils.isString(item))\n return outputTransactionFormatter(item);\n });\n }\n\n return block;\n};\n\n/**\n * Formats the output of a log\n * \n * @method outputLogFormatter\n * @param {Object} log object\n * @returns {Object} log\n*/\nvar outputLogFormatter = function(log) {\n if (log === null) { // 'pending' && 'latest' filters are nulls\n return null;\n }\n\n log.blockNumber = utils.toDecimal(log.blockNumber);\n log.transactionIndex = utils.toDecimal(log.transactionIndex);\n log.logIndex = utils.toDecimal(log.logIndex);\n\n return log;\n};\n\n/**\n * Formats the input of a whisper post and converts all values to HEX\n *\n * @method inputPostFormatter\n * @param {Object} transaction object\n * @returns {Object}\n*/\nvar inputPostFormatter = function(post) {\n\n post.payload = utils.toHex(post.payload);\n post.ttl = utils.fromDecimal(post.ttl);\n post.priority = utils.fromDecimal(post.priority);\n\n if(!utils.isArray(post.topics)) {\n post.topics = [post.topics];\n }\n\n // format the following options\n post.topics = post.topics.map(function(topic){\n return utils.fromAscii(topic);\n });\n\n return post; \n};\n\n/**\n * Formats the output of a received post message\n *\n * @method outputPostFormatter\n * @param {Object}\n * @returns {Object}\n */\nvar outputPostFormatter = function(post){\n\n post.expiry = utils.toDecimal(post.expiry);\n post.sent = utils.toDecimal(post.sent);\n post.ttl = utils.toDecimal(post.ttl);\n post.workProved = utils.toDecimal(post.workProved);\n post.payloadRaw = post.payload;\n post.payload = utils.toAscii(post.payload);\n\n if (utils.isJson(post.payload)) {\n post.payload = JSON.parse(post.payload);\n }\n\n // format the following options\n post.topics = post.topics.map(function(topic){\n return utils.toAscii(topic);\n });\n\n return post;\n};\n\nmodule.exports = {\n inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,\n inputBlockNumberFormatter: inputBlockNumberFormatter,\n inputTransactionFormatter: inputTransactionFormatter,\n inputPostFormatter: inputPostFormatter,\n outputBigNumberFormatter: outputBigNumberFormatter,\n outputTransactionFormatter: outputTransactionFormatter,\n outputBlockFormatter: outputBlockFormatter,\n outputLogFormatter: outputLogFormatter,\n outputPostFormatter: outputPostFormatter\n};\n\n", @@ -64,6 +66,6 @@ "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file watches.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\n/// @returns an array of objects describing web3.eth.filter api methods\nvar eth = function () {\n var newFilterCall = function (args) {\n return typeof args[0] === 'string' ? 'eth_newBlockFilter' : 'eth_newFilter';\n };\n\n var newFilter = new Method({\n name: 'newFilter',\n call: newFilterCall,\n params: 1\n });\n\n var uninstallFilter = new Method({\n name: 'uninstallFilter',\n call: 'eth_uninstallFilter',\n params: 1\n });\n\n var getLogs = new Method({\n name: 'getLogs',\n call: 'eth_getFilterLogs',\n params: 1\n });\n\n var poll = new Method({\n name: 'poll',\n call: 'eth_getFilterChanges',\n params: 1\n });\n\n return [\n newFilter,\n uninstallFilter,\n getLogs,\n poll\n ];\n};\n\n/// @returns an array of objects describing web3.shh.watch api methods\nvar shh = function () {\n var newFilter = new Method({\n name: 'newFilter',\n call: 'shh_newFilter',\n params: 1\n });\n\n var uninstallFilter = new Method({\n name: 'uninstallFilter',\n call: 'shh_uninstallFilter',\n params: 1\n });\n\n var getLogs = new Method({\n name: 'getLogs',\n call: 'shh_getMessages',\n params: 1\n });\n\n var poll = new Method({\n name: 'poll',\n call: 'shh_getFilterChanges',\n params: 1\n });\n\n return [\n newFilter,\n uninstallFilter,\n getLogs,\n poll\n ];\n};\n\nmodule.exports = {\n eth: eth,\n shh: shh\n};\n\n", null, "/*! bignumber.js v2.0.3 https://github.com/MikeMcl/bignumber.js/LICENCE */\r\n\r\n;(function (global) {\r\n 'use strict';\r\n\r\n /*\r\n bignumber.js v2.0.3\r\n A JavaScript library for arbitrary-precision arithmetic.\r\n https://github.com/MikeMcl/bignumber.js\r\n Copyright (c) 2015 Michael Mclaughlin \r\n MIT Expat Licence\r\n */\r\n\r\n\r\n var BigNumber, crypto, parseNumeric,\r\n isNumeric = /^-?(\\d+(\\.\\d*)?|\\.\\d+)(e[+-]?\\d+)?$/i,\r\n mathceil = Math.ceil,\r\n mathfloor = Math.floor,\r\n notBool = ' not a boolean or binary digit',\r\n roundingMode = 'rounding mode',\r\n tooManyDigits = 'number type has more than 15 significant digits',\r\n ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_',\r\n BASE = 1e14,\r\n LOG_BASE = 14,\r\n MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1\r\n // MAX_INT32 = 0x7fffffff, // 2^31 - 1\r\n POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13],\r\n SQRT_BASE = 1e7,\r\n\r\n /*\r\n * The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and\r\n * the arguments to toExponential, toFixed, toFormat, and toPrecision, beyond which an\r\n * exception is thrown (if ERRORS is true).\r\n */\r\n MAX = 1E9; // 0 to MAX_INT32\r\n\r\n\r\n /*\r\n * Create and return a BigNumber constructor.\r\n */\r\n function another(configObj) {\r\n var div,\r\n\r\n // id tracks the caller function, so its name can be included in error messages.\r\n id = 0,\r\n P = BigNumber.prototype,\r\n ONE = new BigNumber(1),\r\n\r\n\r\n /********************************* EDITABLE DEFAULTS **********************************/\r\n\r\n\r\n /*\r\n * The default values below must be integers within the inclusive ranges stated.\r\n * The values can also be changed at run-time using BigNumber.config.\r\n */\r\n\r\n // The maximum number of decimal places for operations involving division.\r\n DECIMAL_PLACES = 20, // 0 to MAX\r\n\r\n /*\r\n * The rounding mode used when rounding to the above decimal places, and when using\r\n * toExponential, toFixed, toFormat and toPrecision, and round (default value).\r\n * UP 0 Away from zero.\r\n * DOWN 1 Towards zero.\r\n * CEIL 2 Towards +Infinity.\r\n * FLOOR 3 Towards -Infinity.\r\n * HALF_UP 4 Towards nearest neighbour. If equidistant, up.\r\n * HALF_DOWN 5 Towards nearest neighbour. If equidistant, down.\r\n * HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour.\r\n * HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity.\r\n * HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity.\r\n */\r\n ROUNDING_MODE = 4, // 0 to 8\r\n\r\n // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS]\r\n\r\n // The exponent value at and beneath which toString returns exponential notation.\r\n // Number type: -7\r\n TO_EXP_NEG = -7, // 0 to -MAX\r\n\r\n // The exponent value at and above which toString returns exponential notation.\r\n // Number type: 21\r\n TO_EXP_POS = 21, // 0 to MAX\r\n\r\n // RANGE : [MIN_EXP, MAX_EXP]\r\n\r\n // The minimum exponent value, beneath which underflow to zero occurs.\r\n // Number type: -324 (5e-324)\r\n MIN_EXP = -1e7, // -1 to -MAX\r\n\r\n // The maximum exponent value, above which overflow to Infinity occurs.\r\n // Number type: 308 (1.7976931348623157e+308)\r\n // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow.\r\n MAX_EXP = 1e7, // 1 to MAX\r\n\r\n // Whether BigNumber Errors are ever thrown.\r\n ERRORS = true, // true or false\r\n\r\n // Change to intValidatorNoErrors if ERRORS is false.\r\n isValidInt = intValidatorWithErrors, // intValidatorWithErrors/intValidatorNoErrors\r\n\r\n // Whether to use cryptographically-secure random number generation, if available.\r\n CRYPTO = false, // true or false\r\n\r\n /*\r\n * The modulo mode used when calculating the modulus: a mod n.\r\n * The quotient (q = a / n) is calculated according to the corresponding rounding mode.\r\n * The remainder (r) is calculated as: r = a - n * q.\r\n *\r\n * UP 0 The remainder is positive if the dividend is negative, else is negative.\r\n * DOWN 1 The remainder has the same sign as the dividend.\r\n * This modulo mode is commonly known as 'truncated division' and is\r\n * equivalent to (a % n) in JavaScript.\r\n * FLOOR 3 The remainder has the same sign as the divisor (Python %).\r\n * HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function.\r\n * EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)).\r\n * The remainder is always positive.\r\n *\r\n * The truncated division, floored division, Euclidian division and IEEE 754 remainder\r\n * modes are commonly used for the modulus operation.\r\n * Although the other rounding modes can also be used, they may not give useful results.\r\n */\r\n MODULO_MODE = 1, // 0 to 9\r\n\r\n // The maximum number of significant digits of the result of the toPower operation.\r\n // If POW_PRECISION is 0, there will be unlimited significant digits.\r\n POW_PRECISION = 100, // 0 to MAX\r\n\r\n // The format specification used by the BigNumber.prototype.toFormat method.\r\n FORMAT = {\r\n decimalSeparator: '.',\r\n groupSeparator: ',',\r\n groupSize: 3,\r\n secondaryGroupSize: 0,\r\n fractionGroupSeparator: '\\xA0', // non-breaking space\r\n fractionGroupSize: 0\r\n };\r\n\r\n\r\n /******************************************************************************************/\r\n\r\n\r\n // CONSTRUCTOR\r\n\r\n\r\n /*\r\n * The BigNumber constructor and exported function.\r\n * Create and return a new instance of a BigNumber object.\r\n *\r\n * n {number|string|BigNumber} A numeric value.\r\n * [b] {number} The base of n. Integer, 2 to 64 inclusive.\r\n */\r\n function BigNumber( n, b ) {\r\n var c, e, i, num, len, str,\r\n x = this;\r\n\r\n // Enable constructor usage without new.\r\n if ( !( x instanceof BigNumber ) ) {\r\n\r\n // 'BigNumber() constructor call without new: {n}'\r\n if (ERRORS) raise( 26, 'constructor call without new', n );\r\n return new BigNumber( n, b );\r\n }\r\n\r\n // 'new BigNumber() base not an integer: {b}'\r\n // 'new BigNumber() base out of range: {b}'\r\n if ( b == null || !isValidInt( b, 2, 64, id, 'base' ) ) {\r\n\r\n // Duplicate.\r\n if ( n instanceof BigNumber ) {\r\n x.s = n.s;\r\n x.e = n.e;\r\n x.c = ( n = n.c ) ? n.slice() : n;\r\n id = 0;\r\n return;\r\n }\r\n\r\n if ( ( num = typeof n == 'number' ) && n * 0 == 0 ) {\r\n x.s = 1 / n < 0 ? ( n = -n, -1 ) : 1;\r\n\r\n // Fast path for integers.\r\n if ( n === ~~n ) {\r\n for ( e = 0, i = n; i >= 10; i /= 10, e++ );\r\n x.e = e;\r\n x.c = [n];\r\n id = 0;\r\n return;\r\n }\r\n\r\n str = n + '';\r\n } else {\r\n if ( !isNumeric.test( str = n + '' ) ) return parseNumeric( x, str, num );\r\n x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1;\r\n }\r\n } else {\r\n b = b | 0;\r\n str = n + '';\r\n\r\n // Ensure return value is rounded to DECIMAL_PLACES as with other bases.\r\n // Allow exponential notation to be used with base 10 argument.\r\n if ( b == 10 ) {\r\n x = new BigNumber( n instanceof BigNumber ? n : str );\r\n return round( x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE );\r\n }\r\n\r\n // Avoid potential interpretation of Infinity and NaN as base 44+ values.\r\n // Any number in exponential form will fail due to the [Ee][+-].\r\n if ( ( num = typeof n == 'number' ) && n * 0 != 0 ||\r\n !( new RegExp( '^-?' + ( c = '[' + ALPHABET.slice( 0, b ) + ']+' ) +\r\n '(?:\\\\.' + c + ')?$',b < 37 ? 'i' : '' ) ).test(str) ) {\r\n return parseNumeric( x, str, num, b );\r\n }\r\n\r\n if (num) {\r\n x.s = 1 / n < 0 ? ( str = str.slice(1), -1 ) : 1;\r\n\r\n if ( ERRORS && str.replace( /^0\\.0*|\\./, '' ).length > 15 ) {\r\n\r\n // 'new BigNumber() number type has more than 15 significant digits: {n}'\r\n raise( id, tooManyDigits, n );\r\n }\r\n\r\n // Prevent later check for length on converted number.\r\n num = false;\r\n } else {\r\n x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1;\r\n }\r\n\r\n str = convertBase( str, 10, b, x.s );\r\n }\r\n\r\n // Decimal point?\r\n if ( ( e = str.indexOf('.') ) > -1 ) str = str.replace( '.', '' );\r\n\r\n // Exponential form?\r\n if ( ( i = str.search( /e/i ) ) > 0 ) {\r\n\r\n // Determine exponent.\r\n if ( e < 0 ) e = i;\r\n e += +str.slice( i + 1 );\r\n str = str.substring( 0, i );\r\n } else if ( e < 0 ) {\r\n\r\n // Integer.\r\n e = str.length;\r\n }\r\n\r\n // Determine leading zeros.\r\n for ( i = 0; str.charCodeAt(i) === 48; i++ );\r\n\r\n // Determine trailing zeros.\r\n for ( len = str.length; str.charCodeAt(--len) === 48; );\r\n str = str.slice( i, len + 1 );\r\n\r\n if (str) {\r\n len = str.length;\r\n\r\n // Disallow numbers with over 15 significant digits if number type.\r\n // 'new BigNumber() number type has more than 15 significant digits: {n}'\r\n if ( num && ERRORS && len > 15 ) raise( id, tooManyDigits, x.s * n );\r\n\r\n e = e - i - 1;\r\n\r\n // Overflow?\r\n if ( e > MAX_EXP ) {\r\n\r\n // Infinity.\r\n x.c = x.e = null;\r\n\r\n // Underflow?\r\n } else if ( e < MIN_EXP ) {\r\n\r\n // Zero.\r\n x.c = [ x.e = 0 ];\r\n } else {\r\n x.e = e;\r\n x.c = [];\r\n\r\n // Transform base\r\n\r\n // e is the base 10 exponent.\r\n // i is where to slice str to get the first element of the coefficient array.\r\n i = ( e + 1 ) % LOG_BASE;\r\n if ( e < 0 ) i += LOG_BASE;\r\n\r\n if ( i < len ) {\r\n if (i) x.c.push( +str.slice( 0, i ) );\r\n\r\n for ( len -= LOG_BASE; i < len; ) {\r\n x.c.push( +str.slice( i, i += LOG_BASE ) );\r\n }\r\n\r\n str = str.slice(i);\r\n i = LOG_BASE - str.length;\r\n } else {\r\n i -= len;\r\n }\r\n\r\n for ( ; i--; str += '0' );\r\n x.c.push( +str );\r\n }\r\n } else {\r\n\r\n // Zero.\r\n x.c = [ x.e = 0 ];\r\n }\r\n\r\n id = 0;\r\n }\r\n\r\n\r\n // CONSTRUCTOR PROPERTIES\r\n\r\n\r\n BigNumber.another = another;\r\n\r\n BigNumber.ROUND_UP = 0;\r\n BigNumber.ROUND_DOWN = 1;\r\n BigNumber.ROUND_CEIL = 2;\r\n BigNumber.ROUND_FLOOR = 3;\r\n BigNumber.ROUND_HALF_UP = 4;\r\n BigNumber.ROUND_HALF_DOWN = 5;\r\n BigNumber.ROUND_HALF_EVEN = 6;\r\n BigNumber.ROUND_HALF_CEIL = 7;\r\n BigNumber.ROUND_HALF_FLOOR = 8;\r\n BigNumber.EUCLID = 9;\r\n\r\n\r\n /*\r\n * Configure infrequently-changing library-wide settings.\r\n *\r\n * Accept an object or an argument list, with one or many of the following properties or\r\n * parameters respectively:\r\n *\r\n * DECIMAL_PLACES {number} Integer, 0 to MAX inclusive\r\n * ROUNDING_MODE {number} Integer, 0 to 8 inclusive\r\n * EXPONENTIAL_AT {number|number[]} Integer, -MAX to MAX inclusive or\r\n * [integer -MAX to 0 incl., 0 to MAX incl.]\r\n * RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or\r\n * [integer -MAX to -1 incl., integer 1 to MAX incl.]\r\n * ERRORS {boolean|number} true, false, 1 or 0\r\n * CRYPTO {boolean|number} true, false, 1 or 0\r\n * MODULO_MODE {number} 0 to 9 inclusive\r\n * POW_PRECISION {number} 0 to MAX inclusive\r\n * FORMAT {object} See BigNumber.prototype.toFormat\r\n * decimalSeparator {string}\r\n * groupSeparator {string}\r\n * groupSize {number}\r\n * secondaryGroupSize {number}\r\n * fractionGroupSeparator {string}\r\n * fractionGroupSize {number}\r\n *\r\n * (The values assigned to the above FORMAT object properties are not checked for validity.)\r\n *\r\n * E.g.\r\n * BigNumber.config(20, 4) is equivalent to\r\n * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 })\r\n *\r\n * Ignore properties/parameters set to null or undefined.\r\n * Return an object with the properties current values.\r\n */\r\n BigNumber.config = function () {\r\n var v, p,\r\n i = 0,\r\n r = {},\r\n a = arguments,\r\n o = a[0],\r\n has = o && typeof o == 'object'\r\n ? function () { if ( o.hasOwnProperty(p) ) return ( v = o[p] ) != null; }\r\n : function () { if ( a.length > i ) return ( v = a[i++] ) != null; };\r\n\r\n // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive.\r\n // 'config() DECIMAL_PLACES not an integer: {v}'\r\n // 'config() DECIMAL_PLACES out of range: {v}'\r\n if ( has( p = 'DECIMAL_PLACES' ) && isValidInt( v, 0, MAX, 2, p ) ) {\r\n DECIMAL_PLACES = v | 0;\r\n }\r\n r[p] = DECIMAL_PLACES;\r\n\r\n // ROUNDING_MODE {number} Integer, 0 to 8 inclusive.\r\n // 'config() ROUNDING_MODE not an integer: {v}'\r\n // 'config() ROUNDING_MODE out of range: {v}'\r\n if ( has( p = 'ROUNDING_MODE' ) && isValidInt( v, 0, 8, 2, p ) ) {\r\n ROUNDING_MODE = v | 0;\r\n }\r\n r[p] = ROUNDING_MODE;\r\n\r\n // EXPONENTIAL_AT {number|number[]}\r\n // Integer, -MAX to MAX inclusive or [integer -MAX to 0 inclusive, 0 to MAX inclusive].\r\n // 'config() EXPONENTIAL_AT not an integer: {v}'\r\n // 'config() EXPONENTIAL_AT out of range: {v}'\r\n if ( has( p = 'EXPONENTIAL_AT' ) ) {\r\n\r\n if ( isArray(v) ) {\r\n if ( isValidInt( v[0], -MAX, 0, 2, p ) && isValidInt( v[1], 0, MAX, 2, p ) ) {\r\n TO_EXP_NEG = v[0] | 0;\r\n TO_EXP_POS = v[1] | 0;\r\n }\r\n } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) {\r\n TO_EXP_NEG = -( TO_EXP_POS = ( v < 0 ? -v : v ) | 0 );\r\n }\r\n }\r\n r[p] = [ TO_EXP_NEG, TO_EXP_POS ];\r\n\r\n // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or\r\n // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive].\r\n // 'config() RANGE not an integer: {v}'\r\n // 'config() RANGE cannot be zero: {v}'\r\n // 'config() RANGE out of range: {v}'\r\n if ( has( p = 'RANGE' ) ) {\r\n\r\n if ( isArray(v) ) {\r\n if ( isValidInt( v[0], -MAX, -1, 2, p ) && isValidInt( v[1], 1, MAX, 2, p ) ) {\r\n MIN_EXP = v[0] | 0;\r\n MAX_EXP = v[1] | 0;\r\n }\r\n } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) {\r\n if ( v | 0 ) MIN_EXP = -( MAX_EXP = ( v < 0 ? -v : v ) | 0 );\r\n else if (ERRORS) raise( 2, p + ' cannot be zero', v );\r\n }\r\n }\r\n r[p] = [ MIN_EXP, MAX_EXP ];\r\n\r\n // ERRORS {boolean|number} true, false, 1 or 0.\r\n // 'config() ERRORS not a boolean or binary digit: {v}'\r\n if ( has( p = 'ERRORS' ) ) {\r\n\r\n if ( v === !!v || v === 1 || v === 0 ) {\r\n id = 0;\r\n isValidInt = ( ERRORS = !!v ) ? intValidatorWithErrors : intValidatorNoErrors;\r\n } else if (ERRORS) {\r\n raise( 2, p + notBool, v );\r\n }\r\n }\r\n r[p] = ERRORS;\r\n\r\n // CRYPTO {boolean|number} true, false, 1 or 0.\r\n // 'config() CRYPTO not a boolean or binary digit: {v}'\r\n // 'config() crypto unavailable: {crypto}'\r\n if ( has( p = 'CRYPTO' ) ) {\r\n\r\n if ( v === !!v || v === 1 || v === 0 ) {\r\n CRYPTO = !!( v && crypto && typeof crypto == 'object' );\r\n if ( v && !CRYPTO && ERRORS ) raise( 2, 'crypto unavailable', crypto );\r\n } else if (ERRORS) {\r\n raise( 2, p + notBool, v );\r\n }\r\n }\r\n r[p] = CRYPTO;\r\n\r\n // MODULO_MODE {number} Integer, 0 to 9 inclusive.\r\n // 'config() MODULO_MODE not an integer: {v}'\r\n // 'config() MODULO_MODE out of range: {v}'\r\n if ( has( p = 'MODULO_MODE' ) && isValidInt( v, 0, 9, 2, p ) ) {\r\n MODULO_MODE = v | 0;\r\n }\r\n r[p] = MODULO_MODE;\r\n\r\n // POW_PRECISION {number} Integer, 0 to MAX inclusive.\r\n // 'config() POW_PRECISION not an integer: {v}'\r\n // 'config() POW_PRECISION out of range: {v}'\r\n if ( has( p = 'POW_PRECISION' ) && isValidInt( v, 0, MAX, 2, p ) ) {\r\n POW_PRECISION = v | 0;\r\n }\r\n r[p] = POW_PRECISION;\r\n\r\n // FORMAT {object}\r\n // 'config() FORMAT not an object: {v}'\r\n if ( has( p = 'FORMAT' ) ) {\r\n\r\n if ( typeof v == 'object' ) {\r\n FORMAT = v;\r\n } else if (ERRORS) {\r\n raise( 2, p + ' not an object', v );\r\n }\r\n }\r\n r[p] = FORMAT;\r\n\r\n return r;\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the maximum of the arguments.\r\n *\r\n * arguments {number|string|BigNumber}\r\n */\r\n BigNumber.max = function () { return maxOrMin( arguments, P.lt ); };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the minimum of the arguments.\r\n *\r\n * arguments {number|string|BigNumber}\r\n */\r\n BigNumber.min = function () { return maxOrMin( arguments, P.gt ); };\r\n\r\n\r\n /*\r\n * Return a new BigNumber with a random value equal to or greater than 0 and less than 1,\r\n * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing\r\n * zeros are produced).\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\r\n *\r\n * 'random() decimal places not an integer: {dp}'\r\n * 'random() decimal places out of range: {dp}'\r\n * 'random() crypto unavailable: {crypto}'\r\n */\r\n BigNumber.random = (function () {\r\n var pow2_53 = 0x20000000000000;\r\n\r\n // Return a 53 bit integer n, where 0 <= n < 9007199254740992.\r\n // Check if Math.random() produces more than 32 bits of randomness.\r\n // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits.\r\n // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1.\r\n var random53bitInt = (Math.random() * pow2_53) & 0x1fffff\r\n ? function () { return mathfloor( Math.random() * pow2_53 ); }\r\n : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) +\r\n (Math.random() * 0x800000 | 0); };\r\n\r\n return function (dp) {\r\n var a, b, e, k, v,\r\n i = 0,\r\n c = [],\r\n rand = new BigNumber(ONE);\r\n\r\n dp = dp == null || !isValidInt( dp, 0, MAX, 14 ) ? DECIMAL_PLACES : dp | 0;\r\n k = mathceil( dp / LOG_BASE );\r\n\r\n if (CRYPTO) {\r\n\r\n // Browsers supporting crypto.getRandomValues.\r\n if ( crypto && crypto.getRandomValues ) {\r\n\r\n a = crypto.getRandomValues( new Uint32Array( k *= 2 ) );\r\n\r\n for ( ; i < k; ) {\r\n\r\n // 53 bits:\r\n // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2)\r\n // 11111 11111111 11111111 11111111 11100000 00000000 00000000\r\n // ((Math.pow(2, 32) - 1) >>> 11).toString(2)\r\n // 11111 11111111 11111111\r\n // 0x20000 is 2^21.\r\n v = a[i] * 0x20000 + (a[i + 1] >>> 11);\r\n\r\n // Rejection sampling:\r\n // 0 <= v < 9007199254740992\r\n // Probability that v >= 9e15, is\r\n // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251\r\n if ( v >= 9e15 ) {\r\n b = crypto.getRandomValues( new Uint32Array(2) );\r\n a[i] = b[0];\r\n a[i + 1] = b[1];\r\n } else {\r\n\r\n // 0 <= v <= 8999999999999999\r\n // 0 <= (v % 1e14) <= 99999999999999\r\n c.push( v % 1e14 );\r\n i += 2;\r\n }\r\n }\r\n i = k / 2;\r\n\r\n // Node.js supporting crypto.randomBytes.\r\n } else if ( crypto && crypto.randomBytes ) {\r\n\r\n // buffer\r\n a = crypto.randomBytes( k *= 7 );\r\n\r\n for ( ; i < k; ) {\r\n\r\n // 0x1000000000000 is 2^48, 0x10000000000 is 2^40\r\n // 0x100000000 is 2^32, 0x1000000 is 2^24\r\n // 11111 11111111 11111111 11111111 11111111 11111111 11111111\r\n // 0 <= v < 9007199254740992\r\n v = ( ( a[i] & 31 ) * 0x1000000000000 ) + ( a[i + 1] * 0x10000000000 ) +\r\n ( a[i + 2] * 0x100000000 ) + ( a[i + 3] * 0x1000000 ) +\r\n ( a[i + 4] << 16 ) + ( a[i + 5] << 8 ) + a[i + 6];\r\n\r\n if ( v >= 9e15 ) {\r\n crypto.randomBytes(7).copy( a, i );\r\n } else {\r\n\r\n // 0 <= (v % 1e14) <= 99999999999999\r\n c.push( v % 1e14 );\r\n i += 7;\r\n }\r\n }\r\n i = k / 7;\r\n } else if (ERRORS) {\r\n raise( 14, 'crypto unavailable', crypto );\r\n }\r\n }\r\n\r\n // Use Math.random: CRYPTO is false or crypto is unavailable and ERRORS is false.\r\n if (!i) {\r\n\r\n for ( ; i < k; ) {\r\n v = random53bitInt();\r\n if ( v < 9e15 ) c[i++] = v % 1e14;\r\n }\r\n }\r\n\r\n k = c[--i];\r\n dp %= LOG_BASE;\r\n\r\n // Convert trailing digits to zeros according to dp.\r\n if ( k && dp ) {\r\n v = POWS_TEN[LOG_BASE - dp];\r\n c[i] = mathfloor( k / v ) * v;\r\n }\r\n\r\n // Remove trailing elements which are zero.\r\n for ( ; c[i] === 0; c.pop(), i-- );\r\n\r\n // Zero?\r\n if ( i < 0 ) {\r\n c = [ e = 0 ];\r\n } else {\r\n\r\n // Remove leading elements which are zero and adjust exponent accordingly.\r\n for ( e = -1 ; c[0] === 0; c.shift(), e -= LOG_BASE);\r\n\r\n // Count the digits of the first element of c to determine leading zeros, and...\r\n for ( i = 1, v = c[0]; v >= 10; v /= 10, i++);\r\n\r\n // adjust the exponent accordingly.\r\n if ( i < LOG_BASE ) e -= LOG_BASE - i;\r\n }\r\n\r\n rand.e = e;\r\n rand.c = c;\r\n return rand;\r\n };\r\n })();\r\n\r\n\r\n // PRIVATE FUNCTIONS\r\n\r\n\r\n // Convert a numeric string of baseIn to a numeric string of baseOut.\r\n function convertBase( str, baseOut, baseIn, sign ) {\r\n var d, e, k, r, x, xc, y,\r\n i = str.indexOf( '.' ),\r\n dp = DECIMAL_PLACES,\r\n rm = ROUNDING_MODE;\r\n\r\n if ( baseIn < 37 ) str = str.toLowerCase();\r\n\r\n // Non-integer.\r\n if ( i >= 0 ) {\r\n k = POW_PRECISION;\r\n\r\n // Unlimited precision.\r\n POW_PRECISION = 0;\r\n str = str.replace( '.', '' );\r\n y = new BigNumber(baseIn);\r\n x = y.pow( str.length - i );\r\n POW_PRECISION = k;\r\n\r\n // Convert str as if an integer, then restore the fraction part by dividing the\r\n // result by its base raised to a power.\r\n y.c = toBaseOut( toFixedPoint( coeffToString( x.c ), x.e ), 10, baseOut );\r\n y.e = y.c.length;\r\n }\r\n\r\n // Convert the number as integer.\r\n xc = toBaseOut( str, baseIn, baseOut );\r\n e = k = xc.length;\r\n\r\n // Remove trailing zeros.\r\n for ( ; xc[--k] == 0; xc.pop() );\r\n if ( !xc[0] ) return '0';\r\n\r\n if ( i < 0 ) {\r\n --e;\r\n } else {\r\n x.c = xc;\r\n x.e = e;\r\n\r\n // sign is needed for correct rounding.\r\n x.s = sign;\r\n x = div( x, y, dp, rm, baseOut );\r\n xc = x.c;\r\n r = x.r;\r\n e = x.e;\r\n }\r\n\r\n d = e + dp + 1;\r\n\r\n // The rounding digit, i.e. the digit to the right of the digit that may be rounded up.\r\n i = xc[d];\r\n k = baseOut / 2;\r\n r = r || d < 0 || xc[d + 1] != null;\r\n\r\n r = rm < 4 ? ( i != null || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) )\r\n : i > k || i == k &&( rm == 4 || r || rm == 6 && xc[d - 1] & 1 ||\r\n rm == ( x.s < 0 ? 8 : 7 ) );\r\n\r\n if ( d < 1 || !xc[0] ) {\r\n\r\n // 1^-dp or 0.\r\n str = r ? toFixedPoint( '1', -dp ) : '0';\r\n } else {\r\n xc.length = d;\r\n\r\n if (r) {\r\n\r\n // Rounding up may mean the previous digit has to be rounded up and so on.\r\n for ( --baseOut; ++xc[--d] > baseOut; ) {\r\n xc[d] = 0;\r\n\r\n if ( !d ) {\r\n ++e;\r\n xc.unshift(1);\r\n }\r\n }\r\n }\r\n\r\n // Determine trailing zeros.\r\n for ( k = xc.length; !xc[--k]; );\r\n\r\n // E.g. [4, 11, 15] becomes 4bf.\r\n for ( i = 0, str = ''; i <= k; str += ALPHABET.charAt( xc[i++] ) );\r\n str = toFixedPoint( str, e );\r\n }\r\n\r\n // The caller will add the sign.\r\n return str;\r\n }\r\n\r\n\r\n // Perform division in the specified base. Called by div and convertBase.\r\n div = (function () {\r\n\r\n // Assume non-zero x and k.\r\n function multiply( x, k, base ) {\r\n var m, temp, xlo, xhi,\r\n carry = 0,\r\n i = x.length,\r\n klo = k % SQRT_BASE,\r\n khi = k / SQRT_BASE | 0;\r\n\r\n for ( x = x.slice(); i--; ) {\r\n xlo = x[i] % SQRT_BASE;\r\n xhi = x[i] / SQRT_BASE | 0;\r\n m = khi * xlo + xhi * klo;\r\n temp = klo * xlo + ( ( m % SQRT_BASE ) * SQRT_BASE ) + carry;\r\n carry = ( temp / base | 0 ) + ( m / SQRT_BASE | 0 ) + khi * xhi;\r\n x[i] = temp % base;\r\n }\r\n\r\n if (carry) x.unshift(carry);\r\n\r\n return x;\r\n }\r\n\r\n function compare( a, b, aL, bL ) {\r\n var i, cmp;\r\n\r\n if ( aL != bL ) {\r\n cmp = aL > bL ? 1 : -1;\r\n } else {\r\n\r\n for ( i = cmp = 0; i < aL; i++ ) {\r\n\r\n if ( a[i] != b[i] ) {\r\n cmp = a[i] > b[i] ? 1 : -1;\r\n break;\r\n }\r\n }\r\n }\r\n return cmp;\r\n }\r\n\r\n function subtract( a, b, aL, base ) {\r\n var i = 0;\r\n\r\n // Subtract b from a.\r\n for ( ; aL--; ) {\r\n a[aL] -= i;\r\n i = a[aL] < b[aL] ? 1 : 0;\r\n a[aL] = i * base + a[aL] - b[aL];\r\n }\r\n\r\n // Remove leading zeros.\r\n for ( ; !a[0] && a.length > 1; a.shift() );\r\n }\r\n\r\n // x: dividend, y: divisor.\r\n return function ( x, y, dp, rm, base ) {\r\n var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0,\r\n yL, yz,\r\n s = x.s == y.s ? 1 : -1,\r\n xc = x.c,\r\n yc = y.c;\r\n\r\n // Either NaN, Infinity or 0?\r\n if ( !xc || !xc[0] || !yc || !yc[0] ) {\r\n\r\n return new BigNumber(\r\n\r\n // Return NaN if either NaN, or both Infinity or 0.\r\n !x.s || !y.s || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN :\r\n\r\n // Return ยฑ0 if x is ยฑ0 or y is ยฑInfinity, or return ยฑInfinity as y is ยฑ0.\r\n xc && xc[0] == 0 || !yc ? s * 0 : s / 0\r\n );\r\n }\r\n\r\n q = new BigNumber(s);\r\n qc = q.c = [];\r\n e = x.e - y.e;\r\n s = dp + e + 1;\r\n\r\n if ( !base ) {\r\n base = BASE;\r\n e = bitFloor( x.e / LOG_BASE ) - bitFloor( y.e / LOG_BASE );\r\n s = s / LOG_BASE | 0;\r\n }\r\n\r\n // Result exponent may be one less then the current value of e.\r\n // The coefficients of the BigNumbers from convertBase may have trailing zeros.\r\n for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ );\r\n if ( yc[i] > ( xc[i] || 0 ) ) e--;\r\n\r\n if ( s < 0 ) {\r\n qc.push(1);\r\n more = true;\r\n } else {\r\n xL = xc.length;\r\n yL = yc.length;\r\n i = 0;\r\n s += 2;\r\n\r\n // Normalise xc and yc so highest order digit of yc is >= base/2\r\n\r\n n = mathfloor( base / ( yc[0] + 1 ) );\r\n\r\n if ( n > 1 ) {\r\n yc = multiply( yc, n, base );\r\n xc = multiply( xc, n, base );\r\n yL = yc.length;\r\n xL = xc.length;\r\n }\r\n\r\n xi = yL;\r\n rem = xc.slice( 0, yL );\r\n remL = rem.length;\r\n\r\n // Add zeros to make remainder as long as divisor.\r\n for ( ; remL < yL; rem[remL++] = 0 );\r\n yz = yc.slice();\r\n yz.unshift(0);\r\n yc0 = yc[0];\r\n if ( yc[1] >= base / 2 ) yc0++;\r\n\r\n do {\r\n n = 0;\r\n\r\n // Compare divisor and remainder.\r\n cmp = compare( yc, rem, yL, remL );\r\n\r\n // If divisor < remainder.\r\n if ( cmp < 0 ) {\r\n\r\n // Calculate trial digit, n.\r\n\r\n rem0 = rem[0];\r\n if ( yL != remL ) rem0 = rem0 * base + ( rem[1] || 0 );\r\n\r\n // n is how many times the divisor goes into the current remainder.\r\n n = mathfloor( rem0 / yc0 );\r\n\r\n // Algorithm:\r\n // 1. product = divisor * trial digit (n)\r\n // 2. if product > remainder: product -= divisor, n--\r\n // 3. remainder -= product\r\n // 4. if product was < remainder at 2:\r\n // 5. compare new remainder and divisor\r\n // 6. If remainder > divisor: remainder -= divisor, n++\r\n\r\n if ( n > 1 ) {\r\n if ( n >= base ) n = base - 1;\r\n\r\n // product = divisor * trial digit.\r\n prod = multiply( yc, n, base );\r\n prodL = prod.length;\r\n remL = rem.length;\r\n\r\n // Compare product and remainder.\r\n cmp = compare( prod, rem, prodL, remL );\r\n\r\n // product > remainder.\r\n if ( cmp == 1 ) {\r\n n--;\r\n\r\n // Subtract divisor from product.\r\n subtract( prod, yL < prodL ? yz : yc, prodL, base );\r\n }\r\n } else {\r\n\r\n // cmp is -1.\r\n // If n is 0, there is no need to compare yc and rem again\r\n // below, so change cmp to 1 to avoid it.\r\n // If n is 1, compare yc and rem again below.\r\n if ( n == 0 ) cmp = n = 1;\r\n prod = yc.slice();\r\n }\r\n\r\n prodL = prod.length;\r\n if ( prodL < remL ) prod.unshift(0);\r\n\r\n // Subtract product from remainder.\r\n subtract( rem, prod, remL, base );\r\n\r\n // If product was < previous remainder.\r\n if ( cmp == -1 ) {\r\n remL = rem.length;\r\n\r\n // Compare divisor and new remainder.\r\n cmp = compare( yc, rem, yL, remL );\r\n\r\n // If divisor < new remainder, subtract divisor from remainder.\r\n if ( cmp < 1 ) {\r\n n++;\r\n\r\n // Subtract divisor from remainder.\r\n subtract( rem, yL < remL ? yz : yc, remL, base );\r\n }\r\n }\r\n remL = rem.length;\r\n } else if ( cmp === 0 ) {\r\n n++;\r\n rem = [0];\r\n }\r\n // if cmp === 1, n will be 0\r\n\r\n // Add the next digit, n, to the result array.\r\n qc[i++] = n;\r\n\r\n // Update the remainder.\r\n if ( cmp && rem[0] ) {\r\n rem[remL++] = xc[xi] || 0;\r\n } else {\r\n rem = [ xc[xi] ];\r\n remL = 1;\r\n }\r\n } while ( ( xi++ < xL || rem[0] != null ) && s-- );\r\n\r\n more = rem[0] != null;\r\n\r\n // Leading zero?\r\n if ( !qc[0] ) qc.shift();\r\n }\r\n\r\n if ( base == BASE ) {\r\n\r\n // To calculate q.e, first get the number of digits of qc[0].\r\n for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ );\r\n round( q, dp + ( q.e = i + e * LOG_BASE - 1 ) + 1, rm, more );\r\n\r\n // Caller is convertBase.\r\n } else {\r\n q.e = e;\r\n q.r = +more;\r\n }\r\n\r\n return q;\r\n };\r\n })();\r\n\r\n\r\n /*\r\n * Return a string representing the value of BigNumber n in fixed-point or exponential\r\n * notation rounded to the specified decimal places or significant digits.\r\n *\r\n * n is a BigNumber.\r\n * i is the index of the last digit required (i.e. the digit that may be rounded up).\r\n * rm is the rounding mode.\r\n * caller is caller id: toExponential 19, toFixed 20, toFormat 21, toPrecision 24.\r\n */\r\n function format( n, i, rm, caller ) {\r\n var c0, e, ne, len, str;\r\n\r\n rm = rm != null && isValidInt( rm, 0, 8, caller, roundingMode )\r\n ? rm | 0 : ROUNDING_MODE;\r\n\r\n if ( !n.c ) return n.toString();\r\n c0 = n.c[0];\r\n ne = n.e;\r\n\r\n if ( i == null ) {\r\n str = coeffToString( n.c );\r\n str = caller == 19 || caller == 24 && ne <= TO_EXP_NEG\r\n ? toExponential( str, ne )\r\n : toFixedPoint( str, ne );\r\n } else {\r\n n = round( new BigNumber(n), i, rm );\r\n\r\n // n.e may have changed if the value was rounded up.\r\n e = n.e;\r\n\r\n str = coeffToString( n.c );\r\n len = str.length;\r\n\r\n // toPrecision returns exponential notation if the number of significant digits\r\n // specified is less than the number of digits necessary to represent the integer\r\n // part of the value in fixed-point notation.\r\n\r\n // Exponential notation.\r\n if ( caller == 19 || caller == 24 && ( i <= e || e <= TO_EXP_NEG ) ) {\r\n\r\n // Append zeros?\r\n for ( ; len < i; str += '0', len++ );\r\n str = toExponential( str, e );\r\n\r\n // Fixed-point notation.\r\n } else {\r\n i -= ne;\r\n str = toFixedPoint( str, e );\r\n\r\n // Append zeros?\r\n if ( e + 1 > len ) {\r\n if ( --i > 0 ) for ( str += '.'; i--; str += '0' );\r\n } else {\r\n i += e - len;\r\n if ( i > 0 ) {\r\n if ( e + 1 == len ) str += '.';\r\n for ( ; i--; str += '0' );\r\n }\r\n }\r\n }\r\n }\r\n\r\n return n.s < 0 && c0 ? '-' + str : str;\r\n }\r\n\r\n\r\n // Handle BigNumber.max and BigNumber.min.\r\n function maxOrMin( args, method ) {\r\n var m, n,\r\n i = 0;\r\n\r\n if ( isArray( args[0] ) ) args = args[0];\r\n m = new BigNumber( args[0] );\r\n\r\n for ( ; ++i < args.length; ) {\r\n n = new BigNumber( args[i] );\r\n\r\n // If any number is NaN, return NaN.\r\n if ( !n.s ) {\r\n m = n;\r\n break;\r\n } else if ( method.call( m, n ) ) {\r\n m = n;\r\n }\r\n }\r\n\r\n return m;\r\n }\r\n\r\n\r\n /*\r\n * Return true if n is an integer in range, otherwise throw.\r\n * Use for argument validation when ERRORS is true.\r\n */\r\n function intValidatorWithErrors( n, min, max, caller, name ) {\r\n if ( n < min || n > max || n != truncate(n) ) {\r\n raise( caller, ( name || 'decimal places' ) +\r\n ( n < min || n > max ? ' out of range' : ' not an integer' ), n );\r\n }\r\n\r\n return true;\r\n }\r\n\r\n\r\n /*\r\n * Strip trailing zeros, calculate base 10 exponent and check against MIN_EXP and MAX_EXP.\r\n * Called by minus, plus and times.\r\n */\r\n function normalise( n, c, e ) {\r\n var i = 1,\r\n j = c.length;\r\n\r\n // Remove trailing zeros.\r\n for ( ; !c[--j]; c.pop() );\r\n\r\n // Calculate the base 10 exponent. First get the number of digits of c[0].\r\n for ( j = c[0]; j >= 10; j /= 10, i++ );\r\n\r\n // Overflow?\r\n if ( ( e = i + e * LOG_BASE - 1 ) > MAX_EXP ) {\r\n\r\n // Infinity.\r\n n.c = n.e = null;\r\n\r\n // Underflow?\r\n } else if ( e < MIN_EXP ) {\r\n\r\n // Zero.\r\n n.c = [ n.e = 0 ];\r\n } else {\r\n n.e = e;\r\n n.c = c;\r\n }\r\n\r\n return n;\r\n }\r\n\r\n\r\n // Handle values that fail the validity test in BigNumber.\r\n parseNumeric = (function () {\r\n var basePrefix = /^(-?)0([xbo])(?=\\w[\\w.]*$)/i,\r\n dotAfter = /^([^.]+)\\.$/,\r\n dotBefore = /^\\.([^.]+)$/,\r\n isInfinityOrNaN = /^-?(Infinity|NaN)$/,\r\n whitespaceOrPlus = /^\\s*\\+(?=[\\w.])|^\\s+|\\s+$/g;\r\n\r\n return function ( x, str, num, b ) {\r\n var base,\r\n s = num ? str : str.replace( whitespaceOrPlus, '' );\r\n\r\n // No exception on ยฑInfinity or NaN.\r\n if ( isInfinityOrNaN.test(s) ) {\r\n x.s = isNaN(s) ? null : s < 0 ? -1 : 1;\r\n } else {\r\n if ( !num ) {\r\n\r\n // basePrefix = /^(-?)0([xbo])(?=\\w[\\w.]*$)/i\r\n s = s.replace( basePrefix, function ( m, p1, p2 ) {\r\n base = ( p2 = p2.toLowerCase() ) == 'x' ? 16 : p2 == 'b' ? 2 : 8;\r\n return !b || b == base ? p1 : m;\r\n });\r\n\r\n if (b) {\r\n base = b;\r\n\r\n // E.g. '1.' to '1', '.1' to '0.1'\r\n s = s.replace( dotAfter, '$1' ).replace( dotBefore, '0.$1' );\r\n }\r\n\r\n if ( str != s ) return new BigNumber( s, base );\r\n }\r\n\r\n // 'new BigNumber() not a number: {n}'\r\n // 'new BigNumber() not a base {b} number: {n}'\r\n if (ERRORS) raise( id, 'not a' + ( b ? ' base ' + b : '' ) + ' number', str );\r\n x.s = null;\r\n }\r\n\r\n x.c = x.e = null;\r\n id = 0;\r\n }\r\n })();\r\n\r\n\r\n // Throw a BigNumber Error.\r\n function raise( caller, msg, val ) {\r\n var error = new Error( [\r\n 'new BigNumber', // 0\r\n 'cmp', // 1\r\n 'config', // 2\r\n 'div', // 3\r\n 'divToInt', // 4\r\n 'eq', // 5\r\n 'gt', // 6\r\n 'gte', // 7\r\n 'lt', // 8\r\n 'lte', // 9\r\n 'minus', // 10\r\n 'mod', // 11\r\n 'plus', // 12\r\n 'precision', // 13\r\n 'random', // 14\r\n 'round', // 15\r\n 'shift', // 16\r\n 'times', // 17\r\n 'toDigits', // 18\r\n 'toExponential', // 19\r\n 'toFixed', // 20\r\n 'toFormat', // 21\r\n 'toFraction', // 22\r\n 'pow', // 23\r\n 'toPrecision', // 24\r\n 'toString', // 25\r\n 'BigNumber' // 26\r\n ][caller] + '() ' + msg + ': ' + val );\r\n\r\n error.name = 'BigNumber Error';\r\n id = 0;\r\n throw error;\r\n }\r\n\r\n\r\n /*\r\n * Round x to sd significant digits using rounding mode rm. Check for over/under-flow.\r\n * If r is truthy, it is known that there are more digits after the rounding digit.\r\n */\r\n function round( x, sd, rm, r ) {\r\n var d, i, j, k, n, ni, rd,\r\n xc = x.c,\r\n pows10 = POWS_TEN;\r\n\r\n // if x is not Infinity or NaN...\r\n if (xc) {\r\n\r\n // rd is the rounding digit, i.e. the digit after the digit that may be rounded up.\r\n // n is a base 1e14 number, the value of the element of array x.c containing rd.\r\n // ni is the index of n within x.c.\r\n // d is the number of digits of n.\r\n // i is the index of rd within n including leading zeros.\r\n // j is the actual index of rd within n (if < 0, rd is a leading zero).\r\n out: {\r\n\r\n // Get the number of digits of the first element of xc.\r\n for ( d = 1, k = xc[0]; k >= 10; k /= 10, d++ );\r\n i = sd - d;\r\n\r\n // If the rounding digit is in the first element of xc...\r\n if ( i < 0 ) {\r\n i += LOG_BASE;\r\n j = sd;\r\n n = xc[ ni = 0 ];\r\n\r\n // Get the rounding digit at index j of n.\r\n rd = n / pows10[ d - j - 1 ] % 10 | 0;\r\n } else {\r\n ni = mathceil( ( i + 1 ) / LOG_BASE );\r\n\r\n if ( ni >= xc.length ) {\r\n\r\n if (r) {\r\n\r\n // Needed by sqrt.\r\n for ( ; xc.length <= ni; xc.push(0) );\r\n n = rd = 0;\r\n d = 1;\r\n i %= LOG_BASE;\r\n j = i - LOG_BASE + 1;\r\n } else {\r\n break out;\r\n }\r\n } else {\r\n n = k = xc[ni];\r\n\r\n // Get the number of digits of n.\r\n for ( d = 1; k >= 10; k /= 10, d++ );\r\n\r\n // Get the index of rd within n.\r\n i %= LOG_BASE;\r\n\r\n // Get the index of rd within n, adjusted for leading zeros.\r\n // The number of leading zeros of n is given by LOG_BASE - d.\r\n j = i - LOG_BASE + d;\r\n\r\n // Get the rounding digit at index j of n.\r\n rd = j < 0 ? 0 : n / pows10[ d - j - 1 ] % 10 | 0;\r\n }\r\n }\r\n\r\n r = r || sd < 0 ||\r\n\r\n // Are there any non-zero digits after the rounding digit?\r\n // The expression n % pows10[ d - j - 1 ] returns all digits of n to the right\r\n // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714.\r\n xc[ni + 1] != null || ( j < 0 ? n : n % pows10[ d - j - 1 ] );\r\n\r\n r = rm < 4\r\n ? ( rd || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) )\r\n : rd > 5 || rd == 5 && ( rm == 4 || r || rm == 6 &&\r\n\r\n // Check whether the digit to the left of the rounding digit is odd.\r\n ( ( i > 0 ? j > 0 ? n / pows10[ d - j ] : 0 : xc[ni - 1] ) % 10 ) & 1 ||\r\n rm == ( x.s < 0 ? 8 : 7 ) );\r\n\r\n if ( sd < 1 || !xc[0] ) {\r\n xc.length = 0;\r\n\r\n if (r) {\r\n\r\n // Convert sd to decimal places.\r\n sd -= x.e + 1;\r\n\r\n // 1, 0.1, 0.01, 0.001, 0.0001 etc.\r\n xc[0] = pows10[ sd % LOG_BASE ];\r\n x.e = -sd || 0;\r\n } else {\r\n\r\n // Zero.\r\n xc[0] = x.e = 0;\r\n }\r\n\r\n return x;\r\n }\r\n\r\n // Remove excess digits.\r\n if ( i == 0 ) {\r\n xc.length = ni;\r\n k = 1;\r\n ni--;\r\n } else {\r\n xc.length = ni + 1;\r\n k = pows10[ LOG_BASE - i ];\r\n\r\n // E.g. 56700 becomes 56000 if 7 is the rounding digit.\r\n // j > 0 means i > number of leading zeros of n.\r\n xc[ni] = j > 0 ? mathfloor( n / pows10[ d - j ] % pows10[j] ) * k : 0;\r\n }\r\n\r\n // Round up?\r\n if (r) {\r\n\r\n for ( ; ; ) {\r\n\r\n // If the digit to be rounded up is in the first element of xc...\r\n if ( ni == 0 ) {\r\n\r\n // i will be the length of xc[0] before k is added.\r\n for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ );\r\n j = xc[0] += k;\r\n for ( k = 1; j >= 10; j /= 10, k++ );\r\n\r\n // if i != k the length has increased.\r\n if ( i != k ) {\r\n x.e++;\r\n if ( xc[0] == BASE ) xc[0] = 1;\r\n }\r\n\r\n break;\r\n } else {\r\n xc[ni] += k;\r\n if ( xc[ni] != BASE ) break;\r\n xc[ni--] = 0;\r\n k = 1;\r\n }\r\n }\r\n }\r\n\r\n // Remove trailing zeros.\r\n for ( i = xc.length; xc[--i] === 0; xc.pop() );\r\n }\r\n\r\n // Overflow? Infinity.\r\n if ( x.e > MAX_EXP ) {\r\n x.c = x.e = null;\r\n\r\n // Underflow? Zero.\r\n } else if ( x.e < MIN_EXP ) {\r\n x.c = [ x.e = 0 ];\r\n }\r\n }\r\n\r\n return x;\r\n }\r\n\r\n\r\n // PROTOTYPE/INSTANCE METHODS\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the absolute value of this BigNumber.\r\n */\r\n P.absoluteValue = P.abs = function () {\r\n var x = new BigNumber(this);\r\n if ( x.s < 0 ) x.s = 1;\r\n return x;\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole\r\n * number in the direction of Infinity.\r\n */\r\n P.ceil = function () {\r\n return round( new BigNumber(this), this.e + 1, 2 );\r\n };\r\n\r\n\r\n /*\r\n * Return\r\n * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b),\r\n * -1 if the value of this BigNumber is less than the value of BigNumber(y, b),\r\n * 0 if they have the same value,\r\n * or null if the value of either is NaN.\r\n */\r\n P.comparedTo = P.cmp = function ( y, b ) {\r\n id = 1;\r\n return compare( this, new BigNumber( y, b ) );\r\n };\r\n\r\n\r\n /*\r\n * Return the number of decimal places of the value of this BigNumber, or null if the value\r\n * of this BigNumber is ยฑInfinity or NaN.\r\n */\r\n P.decimalPlaces = P.dp = function () {\r\n var n, v,\r\n c = this.c;\r\n\r\n if ( !c ) return null;\r\n n = ( ( v = c.length - 1 ) - bitFloor( this.e / LOG_BASE ) ) * LOG_BASE;\r\n\r\n // Subtract the number of trailing zeros of the last number.\r\n if ( v = c[v] ) for ( ; v % 10 == 0; v /= 10, n-- );\r\n if ( n < 0 ) n = 0;\r\n\r\n return n;\r\n };\r\n\r\n\r\n /*\r\n * n / 0 = I\r\n * n / N = N\r\n * n / I = 0\r\n * 0 / n = 0\r\n * 0 / 0 = N\r\n * 0 / N = N\r\n * 0 / I = 0\r\n * N / n = N\r\n * N / 0 = N\r\n * N / N = N\r\n * N / I = N\r\n * I / n = I\r\n * I / 0 = I\r\n * I / N = N\r\n * I / I = N\r\n *\r\n * Return a new BigNumber whose value is the value of this BigNumber divided by the value of\r\n * BigNumber(y, b), rounded according to DECIMAL_PLACES and ROUNDING_MODE.\r\n */\r\n P.dividedBy = P.div = function ( y, b ) {\r\n id = 3;\r\n return div( this, new BigNumber( y, b ), DECIMAL_PLACES, ROUNDING_MODE );\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the integer part of dividing the value of this\r\n * BigNumber by the value of BigNumber(y, b).\r\n */\r\n P.dividedToIntegerBy = P.divToInt = function ( y, b ) {\r\n id = 4;\r\n return div( this, new BigNumber( y, b ), 0, 1 );\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is equal to the value of BigNumber(y, b),\r\n * otherwise returns false.\r\n */\r\n P.equals = P.eq = function ( y, b ) {\r\n id = 5;\r\n return compare( this, new BigNumber( y, b ) ) === 0;\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole\r\n * number in the direction of -Infinity.\r\n */\r\n P.floor = function () {\r\n return round( new BigNumber(this), this.e + 1, 3 );\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is greater than the value of BigNumber(y, b),\r\n * otherwise returns false.\r\n */\r\n P.greaterThan = P.gt = function ( y, b ) {\r\n id = 6;\r\n return compare( this, new BigNumber( y, b ) ) > 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is greater than or equal to the value of\r\n * BigNumber(y, b), otherwise returns false.\r\n */\r\n P.greaterThanOrEqualTo = P.gte = function ( y, b ) {\r\n id = 7;\r\n return ( b = compare( this, new BigNumber( y, b ) ) ) === 1 || b === 0;\r\n\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is a finite number, otherwise returns false.\r\n */\r\n P.isFinite = function () {\r\n return !!this.c;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is an integer, otherwise return false.\r\n */\r\n P.isInteger = P.isInt = function () {\r\n return !!this.c && bitFloor( this.e / LOG_BASE ) > this.c.length - 2;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is NaN, otherwise returns false.\r\n */\r\n P.isNaN = function () {\r\n return !this.s;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is negative, otherwise returns false.\r\n */\r\n P.isNegative = P.isNeg = function () {\r\n return this.s < 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is 0 or -0, otherwise returns false.\r\n */\r\n P.isZero = function () {\r\n return !!this.c && this.c[0] == 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is less than the value of BigNumber(y, b),\r\n * otherwise returns false.\r\n */\r\n P.lessThan = P.lt = function ( y, b ) {\r\n id = 8;\r\n return compare( this, new BigNumber( y, b ) ) < 0;\r\n };\r\n\r\n\r\n /*\r\n * Return true if the value of this BigNumber is less than or equal to the value of\r\n * BigNumber(y, b), otherwise returns false.\r\n */\r\n P.lessThanOrEqualTo = P.lte = function ( y, b ) {\r\n id = 9;\r\n return ( b = compare( this, new BigNumber( y, b ) ) ) === -1 || b === 0;\r\n };\r\n\r\n\r\n /*\r\n * n - 0 = n\r\n * n - N = N\r\n * n - I = -I\r\n * 0 - n = -n\r\n * 0 - 0 = 0\r\n * 0 - N = N\r\n * 0 - I = -I\r\n * N - n = N\r\n * N - 0 = N\r\n * N - N = N\r\n * N - I = N\r\n * I - n = I\r\n * I - 0 = I\r\n * I - N = N\r\n * I - I = N\r\n *\r\n * Return a new BigNumber whose value is the value of this BigNumber minus the value of\r\n * BigNumber(y, b).\r\n */\r\n P.minus = P.sub = function ( y, b ) {\r\n var i, j, t, xLTy,\r\n x = this,\r\n a = x.s;\r\n\r\n id = 10;\r\n y = new BigNumber( y, b );\r\n b = y.s;\r\n\r\n // Either NaN?\r\n if ( !a || !b ) return new BigNumber(NaN);\r\n\r\n // Signs differ?\r\n if ( a != b ) {\r\n y.s = -b;\r\n return x.plus(y);\r\n }\r\n\r\n var xe = x.e / LOG_BASE,\r\n ye = y.e / LOG_BASE,\r\n xc = x.c,\r\n yc = y.c;\r\n\r\n if ( !xe || !ye ) {\r\n\r\n // Either Infinity?\r\n if ( !xc || !yc ) return xc ? ( y.s = -b, y ) : new BigNumber( yc ? x : NaN );\r\n\r\n // Either zero?\r\n if ( !xc[0] || !yc[0] ) {\r\n\r\n // Return y if y is non-zero, x if x is non-zero, or zero if both are zero.\r\n return yc[0] ? ( y.s = -b, y ) : new BigNumber( xc[0] ? x :\r\n\r\n // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity\r\n ROUNDING_MODE == 3 ? -0 : 0 );\r\n }\r\n }\r\n\r\n xe = bitFloor(xe);\r\n ye = bitFloor(ye);\r\n xc = xc.slice();\r\n\r\n // Determine which is the bigger number.\r\n if ( a = xe - ye ) {\r\n\r\n if ( xLTy = a < 0 ) {\r\n a = -a;\r\n t = xc;\r\n } else {\r\n ye = xe;\r\n t = yc;\r\n }\r\n\r\n t.reverse();\r\n\r\n // Prepend zeros to equalise exponents.\r\n for ( b = a; b--; t.push(0) );\r\n t.reverse();\r\n } else {\r\n\r\n // Exponents equal. Check digit by digit.\r\n j = ( xLTy = ( a = xc.length ) < ( b = yc.length ) ) ? a : b;\r\n\r\n for ( a = b = 0; b < j; b++ ) {\r\n\r\n if ( xc[b] != yc[b] ) {\r\n xLTy = xc[b] < yc[b];\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // x < y? Point xc to the array of the bigger number.\r\n if (xLTy) t = xc, xc = yc, yc = t, y.s = -y.s;\r\n\r\n b = ( j = yc.length ) - ( i = xc.length );\r\n\r\n // Append zeros to xc if shorter.\r\n // No need to add zeros to yc if shorter as subtract only needs to start at yc.length.\r\n if ( b > 0 ) for ( ; b--; xc[i++] = 0 );\r\n b = BASE - 1;\r\n\r\n // Subtract yc from xc.\r\n for ( ; j > a; ) {\r\n\r\n if ( xc[--j] < yc[j] ) {\r\n for ( i = j; i && !xc[--i]; xc[i] = b );\r\n --xc[i];\r\n xc[j] += BASE;\r\n }\r\n\r\n xc[j] -= yc[j];\r\n }\r\n\r\n // Remove leading zeros and adjust exponent accordingly.\r\n for ( ; xc[0] == 0; xc.shift(), --ye );\r\n\r\n // Zero?\r\n if ( !xc[0] ) {\r\n\r\n // Following IEEE 754 (2008) 6.3,\r\n // n - n = +0 but n - n = -0 when rounding towards -Infinity.\r\n y.s = ROUNDING_MODE == 3 ? -1 : 1;\r\n y.c = [ y.e = 0 ];\r\n return y;\r\n }\r\n\r\n // No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity\r\n // for finite x and y.\r\n return normalise( y, xc, ye );\r\n };\r\n\r\n\r\n /*\r\n * n % 0 = N\r\n * n % N = N\r\n * n % I = n\r\n * 0 % n = 0\r\n * -0 % n = -0\r\n * 0 % 0 = N\r\n * 0 % N = N\r\n * 0 % I = 0\r\n * N % n = N\r\n * N % 0 = N\r\n * N % N = N\r\n * N % I = N\r\n * I % n = N\r\n * I % 0 = N\r\n * I % N = N\r\n * I % I = N\r\n *\r\n * Return a new BigNumber whose value is the value of this BigNumber modulo the value of\r\n * BigNumber(y, b). The result depends on the value of MODULO_MODE.\r\n */\r\n P.modulo = P.mod = function ( y, b ) {\r\n var q, s,\r\n x = this;\r\n\r\n id = 11;\r\n y = new BigNumber( y, b );\r\n\r\n // Return NaN if x is Infinity or NaN, or y is NaN or zero.\r\n if ( !x.c || !y.s || y.c && !y.c[0] ) {\r\n return new BigNumber(NaN);\r\n\r\n // Return x if y is Infinity or x is zero.\r\n } else if ( !y.c || x.c && !x.c[0] ) {\r\n return new BigNumber(x);\r\n }\r\n\r\n if ( MODULO_MODE == 9 ) {\r\n\r\n // Euclidian division: q = sign(y) * floor(x / abs(y))\r\n // r = x - qy where 0 <= r < abs(y)\r\n s = y.s;\r\n y.s = 1;\r\n q = div( x, y, 0, 3 );\r\n y.s = s;\r\n q.s *= s;\r\n } else {\r\n q = div( x, y, 0, MODULO_MODE );\r\n }\r\n\r\n return x.minus( q.times(y) );\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the value of this BigNumber negated,\r\n * i.e. multiplied by -1.\r\n */\r\n P.negated = P.neg = function () {\r\n var x = new BigNumber(this);\r\n x.s = -x.s || null;\r\n return x;\r\n };\r\n\r\n\r\n /*\r\n * n + 0 = n\r\n * n + N = N\r\n * n + I = I\r\n * 0 + n = n\r\n * 0 + 0 = 0\r\n * 0 + N = N\r\n * 0 + I = I\r\n * N + n = N\r\n * N + 0 = N\r\n * N + N = N\r\n * N + I = N\r\n * I + n = I\r\n * I + 0 = I\r\n * I + N = N\r\n * I + I = I\r\n *\r\n * Return a new BigNumber whose value is the value of this BigNumber plus the value of\r\n * BigNumber(y, b).\r\n */\r\n P.plus = P.add = function ( y, b ) {\r\n var t,\r\n x = this,\r\n a = x.s;\r\n\r\n id = 12;\r\n y = new BigNumber( y, b );\r\n b = y.s;\r\n\r\n // Either NaN?\r\n if ( !a || !b ) return new BigNumber(NaN);\r\n\r\n // Signs differ?\r\n if ( a != b ) {\r\n y.s = -b;\r\n return x.minus(y);\r\n }\r\n\r\n var xe = x.e / LOG_BASE,\r\n ye = y.e / LOG_BASE,\r\n xc = x.c,\r\n yc = y.c;\r\n\r\n if ( !xe || !ye ) {\r\n\r\n // Return ยฑInfinity if either ยฑInfinity.\r\n if ( !xc || !yc ) return new BigNumber( a / 0 );\r\n\r\n // Either zero?\r\n // Return y if y is non-zero, x if x is non-zero, or zero if both are zero.\r\n if ( !xc[0] || !yc[0] ) return yc[0] ? y : new BigNumber( xc[0] ? x : a * 0 );\r\n }\r\n\r\n xe = bitFloor(xe);\r\n ye = bitFloor(ye);\r\n xc = xc.slice();\r\n\r\n // Prepend zeros to equalise exponents. Faster to use reverse then do unshifts.\r\n if ( a = xe - ye ) {\r\n if ( a > 0 ) {\r\n ye = xe;\r\n t = yc;\r\n } else {\r\n a = -a;\r\n t = xc;\r\n }\r\n\r\n t.reverse();\r\n for ( ; a--; t.push(0) );\r\n t.reverse();\r\n }\r\n\r\n a = xc.length;\r\n b = yc.length;\r\n\r\n // Point xc to the longer array, and b to the shorter length.\r\n if ( a - b < 0 ) t = yc, yc = xc, xc = t, b = a;\r\n\r\n // Only start adding at yc.length - 1 as the further digits of xc can be ignored.\r\n for ( a = 0; b; ) {\r\n a = ( xc[--b] = xc[b] + yc[b] + a ) / BASE | 0;\r\n xc[b] %= BASE;\r\n }\r\n\r\n if (a) {\r\n xc.unshift(a);\r\n ++ye;\r\n }\r\n\r\n // No need to check for zero, as +x + +y != 0 && -x + -y != 0\r\n // ye = MAX_EXP + 1 possible\r\n return normalise( y, xc, ye );\r\n };\r\n\r\n\r\n /*\r\n * Return the number of significant digits of the value of this BigNumber.\r\n *\r\n * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0.\r\n */\r\n P.precision = P.sd = function (z) {\r\n var n, v,\r\n x = this,\r\n c = x.c;\r\n\r\n // 'precision() argument not a boolean or binary digit: {z}'\r\n if ( z != null && z !== !!z && z !== 1 && z !== 0 ) {\r\n if (ERRORS) raise( 13, 'argument' + notBool, z );\r\n if ( z != !!z ) z = null;\r\n }\r\n\r\n if ( !c ) return null;\r\n v = c.length - 1;\r\n n = v * LOG_BASE + 1;\r\n\r\n if ( v = c[v] ) {\r\n\r\n // Subtract the number of trailing zeros of the last element.\r\n for ( ; v % 10 == 0; v /= 10, n-- );\r\n\r\n // Add the number of digits of the first element.\r\n for ( v = c[0]; v >= 10; v /= 10, n++ );\r\n }\r\n\r\n if ( z && x.e + 1 > n ) n = x.e + 1;\r\n\r\n return n;\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of\r\n * dp decimal places using rounding mode rm, or to 0 and ROUNDING_MODE respectively if\r\n * omitted.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * 'round() decimal places out of range: {dp}'\r\n * 'round() decimal places not an integer: {dp}'\r\n * 'round() rounding mode not an integer: {rm}'\r\n * 'round() rounding mode out of range: {rm}'\r\n */\r\n P.round = function ( dp, rm ) {\r\n var n = new BigNumber(this);\r\n\r\n if ( dp == null || isValidInt( dp, 0, MAX, 15 ) ) {\r\n round( n, ~~dp + this.e + 1, rm == null ||\r\n !isValidInt( rm, 0, 8, 15, roundingMode ) ? ROUNDING_MODE : rm | 0 );\r\n }\r\n\r\n return n;\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the value of this BigNumber shifted by k places\r\n * (powers of 10). Shift to the right if n > 0, and to the left if n < 0.\r\n *\r\n * k {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive.\r\n *\r\n * If k is out of range and ERRORS is false, the result will be ยฑ0 if k < 0, or ยฑInfinity\r\n * otherwise.\r\n *\r\n * 'shift() argument not an integer: {k}'\r\n * 'shift() argument out of range: {k}'\r\n */\r\n P.shift = function (k) {\r\n var n = this;\r\n return isValidInt( k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 16, 'argument' )\r\n\r\n // k < 1e+21, or truncate(k) will produce exponential notation.\r\n ? n.times( '1e' + truncate(k) )\r\n : new BigNumber( n.c && n.c[0] && ( k < -MAX_SAFE_INTEGER || k > MAX_SAFE_INTEGER )\r\n ? n.s * ( k < 0 ? 0 : 1 / 0 )\r\n : n );\r\n };\r\n\r\n\r\n /*\r\n * sqrt(-n) = N\r\n * sqrt( N) = N\r\n * sqrt(-I) = N\r\n * sqrt( I) = I\r\n * sqrt( 0) = 0\r\n * sqrt(-0) = -0\r\n *\r\n * Return a new BigNumber whose value is the square root of the value of this BigNumber,\r\n * rounded according to DECIMAL_PLACES and ROUNDING_MODE.\r\n */\r\n P.squareRoot = P.sqrt = function () {\r\n var m, n, r, rep, t,\r\n x = this,\r\n c = x.c,\r\n s = x.s,\r\n e = x.e,\r\n dp = DECIMAL_PLACES + 4,\r\n half = new BigNumber('0.5');\r\n\r\n // Negative/NaN/Infinity/zero?\r\n if ( s !== 1 || !c || !c[0] ) {\r\n return new BigNumber( !s || s < 0 && ( !c || c[0] ) ? NaN : c ? x : 1 / 0 );\r\n }\r\n\r\n // Initial estimate.\r\n s = Math.sqrt( +x );\r\n\r\n // Math.sqrt underflow/overflow?\r\n // Pass x to Math.sqrt as integer, then adjust the exponent of the result.\r\n if ( s == 0 || s == 1 / 0 ) {\r\n n = coeffToString(c);\r\n if ( ( n.length + e ) % 2 == 0 ) n += '0';\r\n s = Math.sqrt(n);\r\n e = bitFloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 );\r\n\r\n if ( s == 1 / 0 ) {\r\n n = '1e' + e;\r\n } else {\r\n n = s.toExponential();\r\n n = n.slice( 0, n.indexOf('e') + 1 ) + e;\r\n }\r\n\r\n r = new BigNumber(n);\r\n } else {\r\n r = new BigNumber( s + '' );\r\n }\r\n\r\n // Check for zero.\r\n // r could be zero if MIN_EXP is changed after the this value was created.\r\n // This would cause a division by zero (x/t) and hence Infinity below, which would cause\r\n // coeffToString to throw.\r\n if ( r.c[0] ) {\r\n e = r.e;\r\n s = e + dp;\r\n if ( s < 3 ) s = 0;\r\n\r\n // Newton-Raphson iteration.\r\n for ( ; ; ) {\r\n t = r;\r\n r = half.times( t.plus( div( x, t, dp, 1 ) ) );\r\n\r\n if ( coeffToString( t.c ).slice( 0, s ) === ( n =\r\n coeffToString( r.c ) ).slice( 0, s ) ) {\r\n\r\n // The exponent of r may here be one less than the final result exponent,\r\n // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits\r\n // are indexed correctly.\r\n if ( r.e < e ) --s;\r\n n = n.slice( s - 3, s + 1 );\r\n\r\n // The 4th rounding digit may be in error by -1 so if the 4 rounding digits\r\n // are 9999 or 4999 (i.e. approaching a rounding boundary) continue the\r\n // iteration.\r\n if ( n == '9999' || !rep && n == '4999' ) {\r\n\r\n // On the first iteration only, check to see if rounding up gives the\r\n // exact result as the nines may infinitely repeat.\r\n if ( !rep ) {\r\n round( t, t.e + DECIMAL_PLACES + 2, 0 );\r\n\r\n if ( t.times(t).eq(x) ) {\r\n r = t;\r\n break;\r\n }\r\n }\r\n\r\n dp += 4;\r\n s += 4;\r\n rep = 1;\r\n } else {\r\n\r\n // If rounding digits are null, 0{0,4} or 50{0,3}, check for exact\r\n // result. If not, then there are further digits and m will be truthy.\r\n if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) {\r\n\r\n // Truncate to the first rounding digit.\r\n round( r, r.e + DECIMAL_PLACES + 2, 1 );\r\n m = !r.times(r).eq(x);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return round( r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m );\r\n };\r\n\r\n\r\n /*\r\n * n * 0 = 0\r\n * n * N = N\r\n * n * I = I\r\n * 0 * n = 0\r\n * 0 * 0 = 0\r\n * 0 * N = N\r\n * 0 * I = N\r\n * N * n = N\r\n * N * 0 = N\r\n * N * N = N\r\n * N * I = N\r\n * I * n = I\r\n * I * 0 = N\r\n * I * N = N\r\n * I * I = I\r\n *\r\n * Return a new BigNumber whose value is the value of this BigNumber times the value of\r\n * BigNumber(y, b).\r\n */\r\n P.times = P.mul = function ( y, b ) {\r\n var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc,\r\n base, sqrtBase,\r\n x = this,\r\n xc = x.c,\r\n yc = ( id = 17, y = new BigNumber( y, b ) ).c;\r\n\r\n // Either NaN, ยฑInfinity or ยฑ0?\r\n if ( !xc || !yc || !xc[0] || !yc[0] ) {\r\n\r\n // Return NaN if either is NaN, or one is 0 and the other is Infinity.\r\n if ( !x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc ) {\r\n y.c = y.e = y.s = null;\r\n } else {\r\n y.s *= x.s;\r\n\r\n // Return ยฑInfinity if either is ยฑInfinity.\r\n if ( !xc || !yc ) {\r\n y.c = y.e = null;\r\n\r\n // Return ยฑ0 if either is ยฑ0.\r\n } else {\r\n y.c = [0];\r\n y.e = 0;\r\n }\r\n }\r\n\r\n return y;\r\n }\r\n\r\n e = bitFloor( x.e / LOG_BASE ) + bitFloor( y.e / LOG_BASE );\r\n y.s *= x.s;\r\n xcL = xc.length;\r\n ycL = yc.length;\r\n\r\n // Ensure xc points to longer array and xcL to its length.\r\n if ( xcL < ycL ) zc = xc, xc = yc, yc = zc, i = xcL, xcL = ycL, ycL = i;\r\n\r\n // Initialise the result array with zeros.\r\n for ( i = xcL + ycL, zc = []; i--; zc.push(0) );\r\n\r\n base = BASE;\r\n sqrtBase = SQRT_BASE;\r\n\r\n for ( i = ycL; --i >= 0; ) {\r\n c = 0;\r\n ylo = yc[i] % sqrtBase;\r\n yhi = yc[i] / sqrtBase | 0;\r\n\r\n for ( k = xcL, j = i + k; j > i; ) {\r\n xlo = xc[--k] % sqrtBase;\r\n xhi = xc[k] / sqrtBase | 0;\r\n m = yhi * xlo + xhi * ylo;\r\n xlo = ylo * xlo + ( ( m % sqrtBase ) * sqrtBase ) + zc[j] + c;\r\n c = ( xlo / base | 0 ) + ( m / sqrtBase | 0 ) + yhi * xhi;\r\n zc[j--] = xlo % base;\r\n }\r\n\r\n zc[j] = c;\r\n }\r\n\r\n if (c) {\r\n ++e;\r\n } else {\r\n zc.shift();\r\n }\r\n\r\n return normalise( y, zc, e );\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of\r\n * sd significant digits using rounding mode rm, or ROUNDING_MODE if rm is omitted.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * 'toDigits() precision out of range: {sd}'\r\n * 'toDigits() precision not an integer: {sd}'\r\n * 'toDigits() rounding mode not an integer: {rm}'\r\n * 'toDigits() rounding mode out of range: {rm}'\r\n */\r\n P.toDigits = function ( sd, rm ) {\r\n var n = new BigNumber(this);\r\n sd = sd == null || !isValidInt( sd, 1, MAX, 18, 'precision' ) ? null : sd | 0;\r\n rm = rm == null || !isValidInt( rm, 0, 8, 18, roundingMode ) ? ROUNDING_MODE : rm | 0;\r\n return sd ? round( n, sd, rm ) : n;\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this BigNumber in exponential notation and\r\n * rounded using ROUNDING_MODE to dp fixed decimal places.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * 'toExponential() decimal places not an integer: {dp}'\r\n * 'toExponential() decimal places out of range: {dp}'\r\n * 'toExponential() rounding mode not an integer: {rm}'\r\n * 'toExponential() rounding mode out of range: {rm}'\r\n */\r\n P.toExponential = function ( dp, rm ) {\r\n return format( this,\r\n dp != null && isValidInt( dp, 0, MAX, 19 ) ? ~~dp + 1 : null, rm, 19 );\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this BigNumber in fixed-point notation rounding\r\n * to dp fixed decimal places using rounding mode rm, or ROUNDING_MODE if rm is omitted.\r\n *\r\n * Note: as with JavaScript's number type, (-0).toFixed(0) is '0',\r\n * but e.g. (-0.00001).toFixed(0) is '-0'.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * 'toFixed() decimal places not an integer: {dp}'\r\n * 'toFixed() decimal places out of range: {dp}'\r\n * 'toFixed() rounding mode not an integer: {rm}'\r\n * 'toFixed() rounding mode out of range: {rm}'\r\n */\r\n P.toFixed = function ( dp, rm ) {\r\n return format( this, dp != null && isValidInt( dp, 0, MAX, 20 )\r\n ? ~~dp + this.e + 1 : null, rm, 20 );\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this BigNumber in fixed-point notation rounded\r\n * using rm or ROUNDING_MODE to dp decimal places, and formatted according to the properties\r\n * of the FORMAT object (see BigNumber.config).\r\n *\r\n * FORMAT = {\r\n * decimalSeparator : '.',\r\n * groupSeparator : ',',\r\n * groupSize : 3,\r\n * secondaryGroupSize : 0,\r\n * fractionGroupSeparator : '\\xA0', // non-breaking space\r\n * fractionGroupSize : 0\r\n * };\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * 'toFormat() decimal places not an integer: {dp}'\r\n * 'toFormat() decimal places out of range: {dp}'\r\n * 'toFormat() rounding mode not an integer: {rm}'\r\n * 'toFormat() rounding mode out of range: {rm}'\r\n */\r\n P.toFormat = function ( dp, rm ) {\r\n var str = format( this, dp != null && isValidInt( dp, 0, MAX, 21 )\r\n ? ~~dp + this.e + 1 : null, rm, 21 );\r\n\r\n if ( this.c ) {\r\n var i,\r\n arr = str.split('.'),\r\n g1 = +FORMAT.groupSize,\r\n g2 = +FORMAT.secondaryGroupSize,\r\n groupSeparator = FORMAT.groupSeparator,\r\n intPart = arr[0],\r\n fractionPart = arr[1],\r\n isNeg = this.s < 0,\r\n intDigits = isNeg ? intPart.slice(1) : intPart,\r\n len = intDigits.length;\r\n\r\n if (g2) i = g1, g1 = g2, g2 = i, len -= i;\r\n\r\n if ( g1 > 0 && len > 0 ) {\r\n i = len % g1 || g1;\r\n intPart = intDigits.substr( 0, i );\r\n\r\n for ( ; i < len; i += g1 ) {\r\n intPart += groupSeparator + intDigits.substr( i, g1 );\r\n }\r\n\r\n if ( g2 > 0 ) intPart += groupSeparator + intDigits.slice(i);\r\n if (isNeg) intPart = '-' + intPart;\r\n }\r\n\r\n str = fractionPart\r\n ? intPart + FORMAT.decimalSeparator + ( ( g2 = +FORMAT.fractionGroupSize )\r\n ? fractionPart.replace( new RegExp( '\\\\d{' + g2 + '}\\\\B', 'g' ),\r\n '$&' + FORMAT.fractionGroupSeparator )\r\n : fractionPart )\r\n : intPart;\r\n }\r\n\r\n return str;\r\n };\r\n\r\n\r\n /*\r\n * Return a string array representing the value of this BigNumber as a simple fraction with\r\n * an integer numerator and an integer denominator. The denominator will be a positive\r\n * non-zero value less than or equal to the specified maximum denominator. If a maximum\r\n * denominator is not specified, the denominator will be the lowest value necessary to\r\n * represent the number exactly.\r\n *\r\n * [md] {number|string|BigNumber} Integer >= 1 and < Infinity. The maximum denominator.\r\n *\r\n * 'toFraction() max denominator not an integer: {md}'\r\n * 'toFraction() max denominator out of range: {md}'\r\n */\r\n P.toFraction = function (md) {\r\n var arr, d0, d2, e, exp, n, n0, q, s,\r\n k = ERRORS,\r\n x = this,\r\n xc = x.c,\r\n d = new BigNumber(ONE),\r\n n1 = d0 = new BigNumber(ONE),\r\n d1 = n0 = new BigNumber(ONE);\r\n\r\n if ( md != null ) {\r\n ERRORS = false;\r\n n = new BigNumber(md);\r\n ERRORS = k;\r\n\r\n if ( !( k = n.isInt() ) || n.lt(ONE) ) {\r\n\r\n if (ERRORS) {\r\n raise( 22,\r\n 'max denominator ' + ( k ? 'out of range' : 'not an integer' ), md );\r\n }\r\n\r\n // ERRORS is false:\r\n // If md is a finite non-integer >= 1, round it to an integer and use it.\r\n md = !k && n.c && round( n, n.e + 1, 1 ).gte(ONE) ? n : null;\r\n }\r\n }\r\n\r\n if ( !xc ) return x.toString();\r\n s = coeffToString(xc);\r\n\r\n // Determine initial denominator.\r\n // d is a power of 10 and the minimum max denominator that specifies the value exactly.\r\n e = d.e = s.length - x.e - 1;\r\n d.c[0] = POWS_TEN[ ( exp = e % LOG_BASE ) < 0 ? LOG_BASE + exp : exp ];\r\n md = !md || n.cmp(d) > 0 ? ( e > 0 ? d : n1 ) : n;\r\n\r\n exp = MAX_EXP;\r\n MAX_EXP = 1 / 0;\r\n n = new BigNumber(s);\r\n\r\n // n0 = d1 = 0\r\n n0.c[0] = 0;\r\n\r\n for ( ; ; ) {\r\n q = div( n, d, 0, 1 );\r\n d2 = d0.plus( q.times(d1) );\r\n if ( d2.cmp(md) == 1 ) break;\r\n d0 = d1;\r\n d1 = d2;\r\n n1 = n0.plus( q.times( d2 = n1 ) );\r\n n0 = d2;\r\n d = n.minus( q.times( d2 = d ) );\r\n n = d2;\r\n }\r\n\r\n d2 = div( md.minus(d0), d1, 0, 1 );\r\n n0 = n0.plus( d2.times(n1) );\r\n d0 = d0.plus( d2.times(d1) );\r\n n0.s = n1.s = x.s;\r\n e *= 2;\r\n\r\n // Determine which fraction is closer to x, n0/d0 or n1/d1\r\n arr = div( n1, d1, e, ROUNDING_MODE ).minus(x).abs().cmp(\r\n div( n0, d0, e, ROUNDING_MODE ).minus(x).abs() ) < 1\r\n ? [ n1.toString(), d1.toString() ]\r\n : [ n0.toString(), d0.toString() ];\r\n\r\n MAX_EXP = exp;\r\n return arr;\r\n };\r\n\r\n\r\n /*\r\n * Return the value of this BigNumber converted to a number primitive.\r\n */\r\n P.toNumber = function () {\r\n var x = this;\r\n\r\n // Ensure zero has correct sign.\r\n return +x || ( x.s ? x.s * 0 : NaN );\r\n };\r\n\r\n\r\n /*\r\n * Return a BigNumber whose value is the value of this BigNumber raised to the power n.\r\n * If n is negative round according to DECIMAL_PLACES and ROUNDING_MODE.\r\n * If POW_PRECISION is not 0, round to POW_PRECISION using ROUNDING_MODE.\r\n *\r\n * n {number} Integer, -9007199254740992 to 9007199254740992 inclusive.\r\n * (Performs 54 loop iterations for n of 9007199254740992.)\r\n *\r\n * 'pow() exponent not an integer: {n}'\r\n * 'pow() exponent out of range: {n}'\r\n */\r\n P.toPower = P.pow = function (n) {\r\n var k, y,\r\n i = mathfloor( n < 0 ? -n : +n ),\r\n x = this;\r\n\r\n // Pass ยฑInfinity to Math.pow if exponent is out of range.\r\n if ( !isValidInt( n, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 23, 'exponent' ) &&\r\n ( !isFinite(n) || i > MAX_SAFE_INTEGER && ( n /= 0 ) ||\r\n parseFloat(n) != n && !( n = NaN ) ) ) {\r\n return new BigNumber( Math.pow( +x, n ) );\r\n }\r\n\r\n // Truncating each coefficient array to a length of k after each multiplication equates\r\n // to truncating significant digits to POW_PRECISION + [28, 41], i.e. there will be a\r\n // minimum of 28 guard digits retained. (Using + 1.5 would give [9, 21] guard digits.)\r\n k = POW_PRECISION ? mathceil( POW_PRECISION / LOG_BASE + 2 ) : 0;\r\n y = new BigNumber(ONE);\r\n\r\n for ( ; ; ) {\r\n\r\n if ( i % 2 ) {\r\n y = y.times(x);\r\n if ( !y.c ) break;\r\n if ( k && y.c.length > k ) y.c.length = k;\r\n }\r\n\r\n i = mathfloor( i / 2 );\r\n if ( !i ) break;\r\n\r\n x = x.times(x);\r\n if ( k && x.c && x.c.length > k ) x.c.length = k;\r\n }\r\n\r\n if ( n < 0 ) y = ONE.div(y);\r\n return k ? round( y, POW_PRECISION, ROUNDING_MODE ) : y;\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this BigNumber rounded to sd significant digits\r\n * using rounding mode rm or ROUNDING_MODE. If sd is less than the number of digits\r\n * necessary to represent the integer part of the value in fixed-point notation, then use\r\n * exponential notation.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * 'toPrecision() precision not an integer: {sd}'\r\n * 'toPrecision() precision out of range: {sd}'\r\n * 'toPrecision() rounding mode not an integer: {rm}'\r\n * 'toPrecision() rounding mode out of range: {rm}'\r\n */\r\n P.toPrecision = function ( sd, rm ) {\r\n return format( this, sd != null && isValidInt( sd, 1, MAX, 24, 'precision' )\r\n ? sd | 0 : null, rm, 24 );\r\n };\r\n\r\n\r\n /*\r\n * Return a string representing the value of this BigNumber in base b, or base 10 if b is\r\n * omitted. If a base is specified, including base 10, round according to DECIMAL_PLACES and\r\n * ROUNDING_MODE. If a base is not specified, and this BigNumber has a positive exponent\r\n * that is equal to or greater than TO_EXP_POS, or a negative exponent equal to or less than\r\n * TO_EXP_NEG, return exponential notation.\r\n *\r\n * [b] {number} Integer, 2 to 64 inclusive.\r\n *\r\n * 'toString() base not an integer: {b}'\r\n * 'toString() base out of range: {b}'\r\n */\r\n P.toString = function (b) {\r\n var str,\r\n n = this,\r\n s = n.s,\r\n e = n.e;\r\n\r\n // Infinity or NaN?\r\n if ( e === null ) {\r\n\r\n if (s) {\r\n str = 'Infinity';\r\n if ( s < 0 ) str = '-' + str;\r\n } else {\r\n str = 'NaN';\r\n }\r\n } else {\r\n str = coeffToString( n.c );\r\n\r\n if ( b == null || !isValidInt( b, 2, 64, 25, 'base' ) ) {\r\n str = e <= TO_EXP_NEG || e >= TO_EXP_POS\r\n ? toExponential( str, e )\r\n : toFixedPoint( str, e );\r\n } else {\r\n str = convertBase( toFixedPoint( str, e ), b | 0, 10, s );\r\n }\r\n\r\n if ( s < 0 && n.c[0] ) str = '-' + str;\r\n }\r\n\r\n return str;\r\n };\r\n\r\n\r\n /*\r\n * Return a new BigNumber whose value is the value of this BigNumber truncated to a whole\r\n * number.\r\n */\r\n P.truncated = P.trunc = function () {\r\n return round( new BigNumber(this), this.e + 1, 1 );\r\n };\r\n\r\n\r\n\r\n /*\r\n * Return as toString, but do not accept a base argument.\r\n */\r\n P.valueOf = P.toJSON = function () {\r\n return this.toString();\r\n };\r\n\r\n\r\n // Aliases for BigDecimal methods.\r\n //P.add = P.plus; // P.add included above\r\n //P.subtract = P.minus; // P.sub included above\r\n //P.multiply = P.times; // P.mul included above\r\n //P.divide = P.div;\r\n //P.remainder = P.mod;\r\n //P.compareTo = P.cmp;\r\n //P.negate = P.neg;\r\n\r\n\r\n if ( configObj != null ) BigNumber.config(configObj);\r\n\r\n return BigNumber;\r\n }\r\n\r\n\r\n // PRIVATE HELPER FUNCTIONS\r\n\r\n\r\n function bitFloor(n) {\r\n var i = n | 0;\r\n return n > 0 || n === i ? i : i - 1;\r\n }\r\n\r\n\r\n // Return a coefficient array as a string of base 10 digits.\r\n function coeffToString(a) {\r\n var s, z,\r\n i = 1,\r\n j = a.length,\r\n r = a[0] + '';\r\n\r\n for ( ; i < j; ) {\r\n s = a[i++] + '';\r\n z = LOG_BASE - s.length;\r\n for ( ; z--; s = '0' + s );\r\n r += s;\r\n }\r\n\r\n // Determine trailing zeros.\r\n for ( j = r.length; r.charCodeAt(--j) === 48; );\r\n return r.slice( 0, j + 1 || 1 );\r\n }\r\n\r\n\r\n // Compare the value of BigNumbers x and y.\r\n function compare( x, y ) {\r\n var a, b,\r\n xc = x.c,\r\n yc = y.c,\r\n i = x.s,\r\n j = y.s,\r\n k = x.e,\r\n l = y.e;\r\n\r\n // Either NaN?\r\n if ( !i || !j ) return null;\r\n\r\n a = xc && !xc[0];\r\n b = yc && !yc[0];\r\n\r\n // Either zero?\r\n if ( a || b ) return a ? b ? 0 : -j : i;\r\n\r\n // Signs differ?\r\n if ( i != j ) return i;\r\n\r\n a = i < 0;\r\n b = k == l;\r\n\r\n // Either Infinity?\r\n if ( !xc || !yc ) return b ? 0 : !xc ^ a ? 1 : -1;\r\n\r\n // Compare exponents.\r\n if ( !b ) return k > l ^ a ? 1 : -1;\r\n\r\n j = ( k = xc.length ) < ( l = yc.length ) ? k : l;\r\n\r\n // Compare digit by digit.\r\n for ( i = 0; i < j; i++ ) if ( xc[i] != yc[i] ) return xc[i] > yc[i] ^ a ? 1 : -1;\r\n\r\n // Compare lengths.\r\n return k == l ? 0 : k > l ^ a ? 1 : -1;\r\n }\r\n\r\n\r\n /*\r\n * Return true if n is a valid number in range, otherwise false.\r\n * Use for argument validation when ERRORS is false.\r\n * Note: parseInt('1e+1') == 1 but parseFloat('1e+1') == 10.\r\n */\r\n function intValidatorNoErrors( n, min, max ) {\r\n return ( n = truncate(n) ) >= min && n <= max;\r\n }\r\n\r\n\r\n function isArray(obj) {\r\n return Object.prototype.toString.call(obj) == '[object Array]';\r\n }\r\n\r\n\r\n /*\r\n * Convert string of baseIn to an array of numbers of baseOut.\r\n * Eg. convertBase('255', 10, 16) returns [15, 15].\r\n * Eg. convertBase('ff', 16, 10) returns [2, 5, 5].\r\n */\r\n function toBaseOut( str, baseIn, baseOut ) {\r\n var j,\r\n arr = [0],\r\n arrL,\r\n i = 0,\r\n len = str.length;\r\n\r\n for ( ; i < len; ) {\r\n for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn );\r\n arr[ j = 0 ] += ALPHABET.indexOf( str.charAt( i++ ) );\r\n\r\n for ( ; j < arr.length; j++ ) {\r\n\r\n if ( arr[j] > baseOut - 1 ) {\r\n if ( arr[j + 1] == null ) arr[j + 1] = 0;\r\n arr[j + 1] += arr[j] / baseOut | 0;\r\n arr[j] %= baseOut;\r\n }\r\n }\r\n }\r\n\r\n return arr.reverse();\r\n }\r\n\r\n\r\n function toExponential( str, e ) {\r\n return ( str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str ) +\r\n ( e < 0 ? 'e' : 'e+' ) + e;\r\n }\r\n\r\n\r\n function toFixedPoint( str, e ) {\r\n var len, z;\r\n\r\n // Negative exponent?\r\n if ( e < 0 ) {\r\n\r\n // Prepend zeros.\r\n for ( z = '0.'; ++e; z += '0' );\r\n str = z + str;\r\n\r\n // Positive exponent\r\n } else {\r\n len = str.length;\r\n\r\n // Append zeros.\r\n if ( ++e > len ) {\r\n for ( z = '0', e -= len; --e; z += '0' );\r\n str += z;\r\n } else if ( e < len ) {\r\n str = str.slice( 0, e ) + '.' + str.slice(e);\r\n }\r\n }\r\n\r\n return str;\r\n }\r\n\r\n\r\n function truncate(n) {\r\n n = parseFloat(n);\r\n return n < 0 ? mathceil(n) : mathfloor(n);\r\n }\r\n\r\n\r\n // EXPORT\r\n\r\n\r\n BigNumber = another();\r\n\r\n // AMD.\r\n if ( typeof define == 'function' && define.amd ) {\r\n define( function () { return BigNumber; } );\r\n\r\n // Node and other environments that support module.exports.\r\n } else if ( typeof module != 'undefined' && module.exports ) {\r\n module.exports = BigNumber;\r\n if ( !crypto ) try { crypto = require('crypto'); } catch (e) {}\r\n\r\n // Browser.\r\n } else {\r\n global.BigNumber = BigNumber;\r\n }\r\n})(this);\r\n", - "// dont override global variable\nif (typeof web3 !== 'undefined') {\n var web3;\n}\n\nweb3 = require('./lib/web3');\nweb3.providers.HttpProvider = require('./lib/web3/httpprovider');\nweb3.providers.QtSyncProvider = require('./lib/web3/qtsync');\nweb3.eth.contract = require('./lib/web3/contract');\nweb3.abi = require('./lib/solidity/abi');\n\n\n\nmodule.exports = web3;\n" + "var web3 = require('./lib/web3');\nweb3.providers.HttpProvider = require('./lib/web3/httpprovider');\nweb3.providers.QtSyncProvider = require('./lib/web3/qtsync');\nweb3.eth.contract = require('./lib/web3/contract');\nweb3.abi = require('./lib/solidity/abi');\n\n// dont override global variable\nif (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {\n window.web3 = web3;\n}\n\nmodule.exports = web3;\n\n" ] } \ No newline at end of file diff --git a/dist/web3.min.js b/dist/web3.min.js index 3e51b9ad6..8982d3514 100644 --- a/dist/web3.min.js +++ b/dist/web3.min.js @@ -1,2 +1,2 @@ -require=function t(e,n,r){function i(a,u){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(o)return o(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return i(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;av;v++)d.push(h(e.slice(0,s))),e=e.slice(s);n.push(d)}else i.prefixedType("bytes")(t[c].type)?(l=l.slice(s),n.push(h(e.slice(0,s))),e=e.slice(s)):(n.push(h(e.slice(0,s))),e=e.slice(s))}),n},h=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),i=n.extractTypeName(t.name),o=function(){var e=Array.prototype.slice.call(arguments);return l(t.inputs,e)};void 0===e[r]&&(e[r]=o),e[r][i]=o}),e},g=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),i=n.extractTypeName(t.name),o=function(e){return m(t.outputs,e)};void 0===e[r]&&(e[r]=o),e[r][i]=o}),e};e.exports={inputParser:h,outputParser:g,formatInput:l,formatOutput:m}},{"../utils/config":5,"../utils/utils":6,"./formatters":2,"./types":3}],2:[function(t,e){var n=t("bignumber.js"),r=t("../utils/utils"),i=t("../utils/config"),o=function(t){var e=2*i.ETH_PADDING;return n.config(i.ETH_BIGNUMBER_ROUNDING_MODE),r.padLeft(r.toTwosComplement(t).round().toString(16),e)},a=function(t){return r.fromAscii(t,i.ETH_PADDING).substr(2)},u=function(t){return"000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0")},s=function(t){return o(new n(t).times(new n(2).pow(128)))},c=function(t){return"1"===new n(t.substr(0,1),16).toString(2).substr(0,1)},l=function(t){return t=t||"0",c(t)?new n(t,16).minus(new n("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new n(t,16)},f=function(t){return t=t||"0",new n(t,16)},p=function(t){return l(t).dividedBy(new n(2).pow(128))},m=function(t){return f(t).dividedBy(new n(2).pow(128))},h=function(t){return"0x"+t},g=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t?!0:!1},d=function(t){return r.toAscii(t)},v=function(t){return"0x"+t.slice(t.length-40,t.length)};e.exports={formatInputInt:o,formatInputString:a,formatInputBool:u,formatInputReal:s,formatOutputInt:l,formatOutputUInt:f,formatOutputReal:p,formatOutputUReal:m,formatOutputHash:h,formatOutputBool:g,formatOutputString:d,formatOutputAddress:v}},{"../utils/config":5,"../utils/utils":6,"bignumber.js":"bignumber.js"}],3:[function(t,e){var n=t("./formatters"),r=function(t){return function(e){return 0===e.indexOf(t)}},i=function(t){return function(e){return t===e}},o=function(){return[{type:r("uint"),format:n.formatInputInt},{type:r("int"),format:n.formatInputInt},{type:r("bytes"),format:n.formatInputString},{type:r("real"),format:n.formatInputReal},{type:r("ureal"),format:n.formatInputReal},{type:i("address"),format:n.formatInputInt},{type:i("bool"),format:n.formatInputBool}]},a=function(){return[{type:r("uint"),format:n.formatOutputUInt},{type:r("int"),format:n.formatOutputInt},{type:r("bytes"),format:n.formatOutputString},{type:r("real"),format:n.formatOutputReal},{type:r("ureal"),format:n.formatOutputUReal},{type:i("address"),format:n.formatOutputAddress},{type:i("bool"),format:n.formatOutputBool}]};e.exports={prefixedType:r,namedType:i,inputTypes:o,outputTypes:a}},{"./formatters":2}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e){var n=t("bignumber.js"),r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:r,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:n.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3,ETH_DEFAULTBLOCK:"latest"}},{"bignumber.js":"bignumber.js"}],6:[function(t,e){var n=t("bignumber.js"),r={wei:"1",kwei:"1000",ada:"1000",mwei:"1000000",babbage:"1000000",gwei:"1000000000",shannon:"1000000000",szabo:"1000000000000",finney:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},i=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},o=function(t,e){for(var n=!1,r=0;rn;n+=2){var i=parseInt(t.substr(n,2),16);if(0===i)break;e+=String.fromCharCode(i)}return e},u=function(t){for(var e="",n=0;n1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},o.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},o.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return n.getInstance().sendAsync(t,function(n,r){t.callback(null,e.formatOutput(r))})}return this.formatOutput(n.getInstance().send(t))},e.exports=o},{"../utils/utils":6,"./errors":11,"./requestmanager":22}],19:[function(t,e){var n=t("../utils/utils"),r=t("./property"),i=[],o=[new r({name:"listening",getter:"net_listening"}),new r({name:"peerCount",getter:"net_peerCount",outputFormatter:n.toDecimal})];e.exports={methods:i,properties:o}},{"../utils/utils":6,"./property":20}],20:[function(t,e){var n=t("./requestmanager"),r=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};r.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},r.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},r.prototype.attachToObject=function(t){var e={get:this.get.bind(this),set:this.set.bind(this)},n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},Object.defineProperty(t[n[0]],n[1],e)):Object.defineProperty(t,n[0],e)},r.prototype.get=function(){return this.formatOutput(n.getInstance().send({method:this.getter}))},r.prototype.set=function(t){return n.getInstance().send({method:this.setter,params:[this.formatInput(t)]})},e.exports=r},{"./requestmanager":22}],21:[function(t,e){var n=function(){};n.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=n},{}],22:[function(t,e){var n=t("./jsonrpc"),r=t("../utils/utils"),i=t("../utils/config"),o=t("./errors"),a=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls=[],this.timeout=null,void this.poll())};a.getInstance=function(){var t=new a;return t},a.prototype.send=function(t){if(!this.provider)return console.error(o.InvalidProvider),null;var e=n.getInstance().toPayload(t.method,t.params),r=this.provider.send(e);if(!n.getInstance().isValidResponse(r))throw o.InvalidResponse(r);return r.result},a.prototype.sendAsync=function(t,e){if(!this.provider)return e(o.InvalidProvider);var r=n.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(r,function(t,r){return t?e(t):n.getInstance().isValidResponse(r)?void e(null,r.result):e(o.InvalidResponse(r))})},a.prototype.setProvider=function(t){this.provider=t},a.prototype.startPolling=function(t,e,n,r){this.polls.push({data:t,id:e,callback:n,uninstall:r})},a.prototype.stopPolling=function(t){for(var e=this.polls.length;e--;){var n=this.polls[e];n.id===t&&this.polls.splice(e,1)}},a.prototype.reset=function(){this.polls.forEach(function(t){t.uninstall(t.id)}),this.polls=[],this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},a.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),i.ETH_POLLING_TIMEOUT),this.polls.length){if(!this.provider)return void console.error(o.InvalidProvider);var t=n.getInstance().toBatchPayload(this.polls.map(function(t){return t.data})),e=this;this.provider.sendAsync(t,function(t,i){if(!t){if(!r.isArray(i))throw o.InvalidResponse(i);i.map(function(t,n){return t.callback=e.polls[n].callback,t}).filter(function(t){var e=n.getInstance().isValidResponse(t);return e||t.callback(o.InvalidResponse(t)),e}).filter(function(t){return r.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}},e.exports=a},{"../utils/config":5,"../utils/utils":6,"./errors":11,"./jsonrpc":17}],23:[function(t,e){var n=t("./method"),r=t("./formatters"),i=new n({name:"post",call:"shh_post",params:1,inputFormatter:r.inputPostFormatter}),o=new n({name:"newIdentity",call:"shh_newIdentity",params:0}),a=new n({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new n({name:"newGroup",call:"shh_newGroup",params:0}),s=new n({name:"addToGroup",call:"shh_addToGroup",params:0}),c=[i,o,a,u,s];e.exports={methods:c}},{"./formatters":15,"./method":18}],24:[function(t,e){var n=t("../web3"),r=t("../utils/config"),i=function(t){return n.sha3(n.fromAscii(t)).slice(0,2+2*r.ETH_SIGNATURE_LENGTH)},o=function(t){return n.sha3(n.fromAscii(t))};e.exports={functionSignatureFromAscii:i,eventSignatureFromAscii:o}},{"../utils/config":5,"../web3":8}],25:[function(t,e){var n=t("./method"),r=function(){var t=function(t){return"string"==typeof t[0]?"eth_newBlockFilter":"eth_newFilter"},e=new n({name:"newFilter",call:t,params:1}),r=new n({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),i=new n({name:"getLogs",call:"eth_getFilterLogs",params:1}),o=new n({name:"poll",call:"eth_getFilterChanges",params:1});return[e,r,i,o]},i=function(){var t=new n({name:"newFilter",call:"shh_newFilter",params:1}),e=new n({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),r=new n({name:"getLogs",call:"shh_getMessages",params:1}),i=new n({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,r,i]};e.exports={eth:r,shh:i}},{"./method":18}],26:[function(){},{}],"bignumber.js":[function(t,e){!function(n){"use strict";function r(t){function e(t,r){var i,o,a,u,s,c,l=this;if(!(l instanceof e))return J&&S(26,"constructor call without new",t),new e(t,r);if(null!=r&&W(r,2,64,R,"base")){if(r=0|r,c=t+"",10==r)return l=new e(t instanceof e?t:c),P(l,U+l.e+1,C);if((u="number"==typeof t)&&0*t!=0||!new RegExp("^-?"+(i="["+F.slice(0,r)+"]+")+"(?:\\."+i+")?$",37>r?"i":"").test(c))return g(l,c,u,r);u?(l.s=0>1/t?(c=c.slice(1),-1):1,J&&c.replace(/^0\.0*|\./,"").length>15&&S(R,x,t),u=!1):l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1,c=n(c,10,r,l.s)}else{if(t instanceof e)return l.s=t.s,l.e=t.e,l.c=(t=t.c)?t.slice():t,void(R=0);if((u="number"==typeof t)&&0*t==0){if(l.s=0>1/t?(t=-t,-1):1,t===~~t){for(o=0,a=t;a>=10;a/=10,o++);return l.e=o,l.c=[t],void(R=0)}c=t+""}else{if(!d.test(c=t+""))return g(l,c,u);l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1}}for((o=c.indexOf("."))>-1&&(c=c.replace(".","")),(a=c.search(/e/i))>0?(0>o&&(o=a),o+=+c.slice(a+1),c=c.substring(0,a)):0>o&&(o=c.length),a=0;48===c.charCodeAt(a);a++);for(s=c.length;48===c.charCodeAt(--s););if(c=c.slice(a,s+1))if(s=c.length,u&&J&&s>15&&S(R,x,l.s*t),o=o-a-1,o>M)l.c=l.e=null;else if(G>o)l.c=[l.e=0];else{if(l.e=o,l.c=[],a=(o+1)%N,0>o&&(a+=N),s>a){for(a&&l.c.push(+c.slice(0,a)),s-=N;s>a;)l.c.push(+c.slice(a,a+=N));c=c.slice(a),a=N-c.length}else a-=s;for(;a--;c+="0");l.c.push(+c)}else l.c=[l.e=0];R=0}function n(t,n,r,i){var a,u,s,l,p,m,h,g=t.indexOf("."),d=U,v=C;for(37>r&&(t=t.toLowerCase()),g>=0&&(s=V,V=0,t=t.replace(".",""),h=new e(r),p=h.pow(t.length-g),V=s,h.c=c(f(o(p.c),p.e),10,n),h.e=h.c.length),m=c(t,r,n),u=s=m.length;0==m[--s];m.pop());if(!m[0])return"0";if(0>g?--u:(p.c=m,p.e=u,p.s=i,p=k(p,h,d,v,n),m=p.c,l=p.r,u=p.e),a=u+d+1,g=m[a],s=n/2,l=l||0>a||null!=m[a+1],l=4>v?(null!=g||l)&&(0==v||v==(p.s<0?3:2)):g>s||g==s&&(4==v||l||6==v&&1&m[a-1]||v==(p.s<0?8:7)),1>a||!m[0])t=l?f("1",-d):"0";else{if(m.length=a,l)for(--n;++m[--a]>n;)m[a]=0,a||(++u,m.unshift(1));for(s=m.length;!m[--s];);for(g=0,t="";s>=g;t+=F.charAt(m[g++]));t=f(t,u)}return t}function m(t,n,r,i){var a,u,s,c,p;if(r=null!=r&&W(r,0,8,i,w)?0|r:C,!t.c)return t.toString();if(a=t.c[0],s=t.e,null==n)p=o(t.c),p=19==i||24==i&&j>=s?l(p,s):f(p,s);else if(t=P(new e(t),n,r),u=t.e,p=o(t.c),c=p.length,19==i||24==i&&(u>=n||j>=u)){for(;n>c;p+="0",c++);p=l(p,u)}else if(n-=s,p=f(p,u),u+1>c){if(--n>0)for(p+=".";n--;p+="0");}else if(n+=u-c,n>0)for(u+1==c&&(p+=".");n--;p+="0");return t.s<0&&a?"-"+p:p}function E(t,n){var r,i,o=0;for(s(t[0])&&(t=t[0]),r=new e(t[0]);++ot||t>n||t!=p(t))&&S(r,(i||"decimal places")+(e>t||t>n?" out of range":" not an integer"),t),!0}function A(t,e,n){for(var r=1,i=e.length;!e[--i];e.pop());for(i=e[0];i>=10;i/=10,r++);return(n=r+n*N-1)>M?t.c=t.e=null:G>n?t.c=[t.e=0]:(t.e=n,t.c=e),t}function S(t,e,n){var r=new Error(["new BigNumber","cmp","config","div","divToInt","eq","gt","gte","lt","lte","minus","mod","plus","precision","random","round","shift","times","toDigits","toExponential","toFixed","toFormat","toFraction","pow","toPrecision","toString","BigNumber"][t]+"() "+e+": "+n);throw r.name="BigNumber Error",R=0,r}function P(t,e,n,r){var i,o,a,u,s,c,l,f=t.c,p=_;if(f){t:{for(i=1,u=f[0];u>=10;u/=10,i++);if(o=e-i,0>o)o+=N,a=e,s=f[c=0],l=s/p[i-a-1]%10|0;else if(c=v((o+1)/N),c>=f.length){if(!r)break t;for(;f.length<=c;f.push(0));s=l=0,i=1,o%=N,a=o-N+1}else{for(s=u=f[c],i=1;u>=10;u/=10,i++);o%=N,a=o-N+i,l=0>a?0:s/p[i-a-1]%10|0}if(r=r||0>e||null!=f[c+1]||(0>a?s:s%p[i-a-1]),r=4>n?(l||r)&&(0==n||n==(t.s<0?3:2)):l>5||5==l&&(4==n||r||6==n&&(o>0?a>0?s/p[i-a]:0:f[c-1])%10&1||n==(t.s<0?8:7)),1>e||!f[0])return f.length=0,r?(e-=t.e+1,f[0]=p[e%N],t.e=-e||0):f[0]=t.e=0,t;if(0==o?(f.length=c,u=1,c--):(f.length=c+1,u=p[N-o],f[c]=a>0?b(s/p[i-a]%p[a])*u:0),r)for(;;){if(0==c){for(o=1,a=f[0];a>=10;a/=10,o++);for(a=f[0]+=u,u=1;a>=10;a/=10,u++);o!=u&&(t.e++,f[0]==I&&(f[0]=1));break}if(f[c]+=u,f[c]!=I)break;f[c--]=0,u=1}for(o=f.length;0===f[--o];f.pop());}t.e>M?t.c=t.e=null:t.en?null!=(t=i[n++]):void 0};return a(e="DECIMAL_PLACES")&&W(t,0,D,2,e)&&(U=0|t),r[e]=U,a(e="ROUNDING_MODE")&&W(t,0,8,2,e)&&(C=0|t),r[e]=C,a(e="EXPONENTIAL_AT")&&(s(t)?W(t[0],-D,0,2,e)&&W(t[1],0,D,2,e)&&(j=0|t[0],q=0|t[1]):W(t,-D,D,2,e)&&(j=-(q=0|(0>t?-t:t)))),r[e]=[j,q],a(e="RANGE")&&(s(t)?W(t[0],-D,-1,2,e)&&W(t[1],1,D,2,e)&&(G=0|t[0],M=0|t[1]):W(t,-D,D,2,e)&&(0|t?G=-(M=0|(0>t?-t:t)):J&&S(2,e+" cannot be zero",t))),r[e]=[G,M],a(e="ERRORS")&&(t===!!t||1===t||0===t?(R=0,W=(J=!!t)?B:u):J&&S(2,e+y,t)),r[e]=J,a(e="CRYPTO")&&(t===!!t||1===t||0===t?($=!(!t||!h||"object"!=typeof h),t&&!$&&J&&S(2,"crypto unavailable",h)):J&&S(2,e+y,t)),r[e]=$,a(e="MODULO_MODE")&&W(t,0,9,2,e)&&(z=0|t),r[e]=z,a(e="POW_PRECISION")&&W(t,0,D,2,e)&&(V=0|t),r[e]=V,a(e="FORMAT")&&("object"==typeof t?K=t:J&&S(2,e+" not an object",t)),r[e]=K,r},e.max=function(){return E(arguments,H.lt)},e.min=function(){return E(arguments,H.gt)},e.random=function(){var t=9007199254740992,n=Math.random()*t&2097151?function(){return b(Math.random()*t)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)};return function(t){var r,i,o,a,u,s=0,c=[],l=new e(L);if(t=null!=t&&W(t,0,D,14)?0|t:U,a=v(t/N),$)if(h&&h.getRandomValues){for(r=h.getRandomValues(new Uint32Array(a*=2));a>s;)u=131072*r[s]+(r[s+1]>>>11),u>=9e15?(i=h.getRandomValues(new Uint32Array(2)),r[s]=i[0],r[s+1]=i[1]):(c.push(u%1e14),s+=2);s=a/2}else if(h&&h.randomBytes){for(r=h.randomBytes(a*=7);a>s;)u=281474976710656*(31&r[s])+1099511627776*r[s+1]+4294967296*r[s+2]+16777216*r[s+3]+(r[s+4]<<16)+(r[s+5]<<8)+r[s+6],u>=9e15?h.randomBytes(7).copy(r,s):(c.push(u%1e14),s+=7);s=a/7}else J&&S(14,"crypto unavailable",h);if(!s)for(;a>s;)u=n(),9e15>u&&(c[s++]=u%1e14);for(a=c[--s],t%=N,a&&t&&(u=_[N-t],c[s]=b(a/u)*u);0===c[s];c.pop(),s--);if(0>s)c=[o=0];else{for(o=-1;0===c[0];c.shift(),o-=N);for(s=1,u=c[0];u>=10;u/=10,s++);N>s&&(o-=N-s)}return l.e=o,l.c=c,l}}(),k=function(){function t(t,e,n){var r,i,o,a,u=0,s=t.length,c=e%T,l=e/T|0;for(t=t.slice();s--;)o=t[s]%T,a=t[s]/T|0,r=l*o+a*c,i=c*o+r%T*T+u,u=(i/n|0)+(r/T|0)+l*a,t[s]=i%n;return u&&t.unshift(u),t}function n(t,e,n,r){var i,o;if(n!=r)o=n>r?1:-1;else for(i=o=0;n>i;i++)if(t[i]!=e[i]){o=t[i]>e[i]?1:-1;break}return o}function r(t,e,n,r){for(var i=0;n--;)t[n]-=i,i=t[n]1;t.shift());}return function(o,a,u,s,c){var l,f,p,m,h,g,d,v,y,w,x,F,O,_,T,D,E,B=o.s==a.s?1:-1,A=o.c,S=a.c;if(!(A&&A[0]&&S&&S[0]))return new e(o.s&&a.s&&(A?!S||A[0]!=S[0]:S)?A&&0==A[0]||!S?0*B:B/0:0/0);for(v=new e(B),y=v.c=[],f=o.e-a.e,B=u+f+1,c||(c=I,f=i(o.e/N)-i(a.e/N),B=B/N|0),p=0;S[p]==(A[p]||0);p++);if(S[p]>(A[p]||0)&&f--,0>B)y.push(1),m=!0;else{for(_=A.length,D=S.length,p=0,B+=2,h=b(c/(S[0]+1)),h>1&&(S=t(S,h,c),A=t(A,h,c),D=S.length,_=A.length),O=D,w=A.slice(0,D),x=w.length;D>x;w[x++]=0);E=S.slice(),E.unshift(0),T=S[0],S[1]>=c/2&&T++;do h=0,l=n(S,w,D,x),0>l?(F=w[0],D!=x&&(F=F*c+(w[1]||0)),h=b(F/T),h>1?(h>=c&&(h=c-1),g=t(S,h,c),d=g.length,x=w.length,l=n(g,w,d,x),1==l&&(h--,r(g,d>D?E:S,d,c))):(0==h&&(l=h=1),g=S.slice()),d=g.length,x>d&&g.unshift(0),r(w,g,x,c),-1==l&&(x=w.length,l=n(S,w,D,x),1>l&&(h++,r(w,x>D?E:S,x,c))),x=w.length):0===l&&(h++,w=[0]),y[p++]=h,l&&w[0]?w[x++]=A[O]||0:(w=[A[O]],x=1);while((O++<_||null!=w[0])&&B--);m=null!=w[0],y[0]||y.shift()}if(c==I){for(p=1,B=y[0];B>=10;B/=10,p++);P(v,u+(v.e=p+f*N-1)+1,s,m)}else v.e=f,v.r=+m;return v}}(),g=function(){var t=/^(-?)0([xbo])(?=\w[\w.]*$)/i,n=/^([^.]+)\.$/,r=/^\.([^.]+)$/,i=/^-?(Infinity|NaN)$/,o=/^\s*\+(?=[\w.])|^\s+|\s+$/g;return function(a,u,s,c){var l,f=s?u:u.replace(o,"");if(i.test(f))a.s=isNaN(f)?null:0>f?-1:1;else{if(!s&&(f=f.replace(t,function(t,e,n){return l="x"==(n=n.toLowerCase())?16:"b"==n?2:8,c&&c!=l?t:e}),c&&(l=c,f=f.replace(n,"$1").replace(r,"0.$1")),u!=f))return new e(f,l);J&&S(R,"not a"+(c?" base "+c:"")+" number",u),a.s=null}a.c=a.e=null,R=0}}(),H.absoluteValue=H.abs=function(){var t=new e(this);return t.s<0&&(t.s=1),t},H.ceil=function(){return P(new e(this),this.e+1,2)},H.comparedTo=H.cmp=function(t,n){return R=1,a(this,new e(t,n))},H.decimalPlaces=H.dp=function(){var t,e,n=this.c;if(!n)return null;if(t=((e=n.length-1)-i(this.e/N))*N,e=n[e])for(;e%10==0;e/=10,t--);return 0>t&&(t=0),t},H.dividedBy=H.div=function(t,n){return R=3,k(this,new e(t,n),U,C)},H.dividedToIntegerBy=H.divToInt=function(t,n){return R=4,k(this,new e(t,n),0,1)},H.equals=H.eq=function(t,n){return R=5,0===a(this,new e(t,n))},H.floor=function(){return P(new e(this),this.e+1,3)},H.greaterThan=H.gt=function(t,n){return R=6,a(this,new e(t,n))>0},H.greaterThanOrEqualTo=H.gte=function(t,n){return R=7,1===(n=a(this,new e(t,n)))||0===n},H.isFinite=function(){return!!this.c},H.isInteger=H.isInt=function(){return!!this.c&&i(this.e/N)>this.c.length-2},H.isNaN=function(){return!this.s},H.isNegative=H.isNeg=function(){return this.s<0},H.isZero=function(){return!!this.c&&0==this.c[0]},H.lessThan=H.lt=function(t,n){return R=8,a(this,new e(t,n))<0},H.lessThanOrEqualTo=H.lte=function(t,n){return R=9,-1===(n=a(this,new e(t,n)))||0===n},H.minus=H.sub=function(t,n){var r,o,a,u,s=this,c=s.s;if(R=10,t=new e(t,n),n=t.s,!c||!n)return new e(0/0);if(c!=n)return t.s=-n,s.plus(t);var l=s.e/N,f=t.e/N,p=s.c,m=t.c;if(!l||!f){if(!p||!m)return p?(t.s=-n,t):new e(m?s:0/0);if(!p[0]||!m[0])return m[0]?(t.s=-n,t):new e(p[0]?s:3==C?-0:0)}if(l=i(l),f=i(f),p=p.slice(),c=l-f){for((u=0>c)?(c=-c,a=p):(f=l,a=m),a.reverse(),n=c;n--;a.push(0));a.reverse()}else for(o=(u=(c=p.length)<(n=m.length))?c:n,c=n=0;o>n;n++)if(p[n]!=m[n]){u=p[n]0)for(;n--;p[r++]=0);for(n=I-1;o>c;){if(p[--o]0?(s=u,r=l):(a=-a,r=c),r.reverse();a--;r.push(0));r.reverse()}for(a=c.length,n=l.length,0>a-n&&(r=l,l=c,c=r,n=a),a=0;n;)a=(c[--n]=c[n]+l[n]+a)/I|0,c[n]%=I;return a&&(c.unshift(a),++s),A(t,c,s)},H.precision=H.sd=function(t){var e,n,r=this,i=r.c;if(null!=t&&t!==!!t&&1!==t&&0!==t&&(J&&S(13,"argument"+y,t),t!=!!t&&(t=null)),!i)return null;if(n=i.length-1,e=n*N+1,n=i[n]){for(;n%10==0;n/=10,e--);for(n=i[0];n>=10;n/=10,e++);}return t&&r.e+1>e&&(e=r.e+1),e},H.round=function(t,n){var r=new e(this);return(null==t||W(t,0,D,15))&&P(r,~~t+this.e+1,null!=n&&W(n,0,8,15,w)?0|n:C),r},H.shift=function(t){var n=this;return W(t,-O,O,16,"argument")?n.times("1e"+p(t)):new e(n.c&&n.c[0]&&(-O>t||t>O)?n.s*(0>t?0:1/0):n)},H.squareRoot=H.sqrt=function(){var t,n,r,a,u,s=this,c=s.c,l=s.s,f=s.e,p=U+4,m=new e("0.5");if(1!==l||!c||!c[0])return new e(!l||0>l&&(!c||c[0])?0/0:c?s:1/0);if(l=Math.sqrt(+s),0==l||l==1/0?(n=o(c),(n.length+f)%2==0&&(n+="0"),l=Math.sqrt(n),f=i((f+1)/2)-(0>f||f%2),l==1/0?n="1e"+f:(n=l.toExponential(),n=n.slice(0,n.indexOf("e")+1)+f),r=new e(n)):r=new e(l+""),r.c[0])for(f=r.e,l=f+p,3>l&&(l=0);;)if(u=r,r=m.times(u.plus(k(s,u,p,1))),o(u.c).slice(0,l)===(n=o(r.c)).slice(0,l)){if(r.el&&(d=w,w=x,x=d,a=l,l=m,m=a),a=l+m,d=[];a--;d.push(0));for(v=I,b=T,a=m;--a>=0;){for(r=0,h=x[a]%b,g=x[a]/b|0,s=l,u=a+s;u>a;)f=w[--s]%b,p=w[s]/b|0,c=g*f+p*h,f=h*f+c%b*b+d[u]+r,r=(f/v|0)+(c/b|0)+g*p,d[u--]=f%v;d[u]=r}return r?++o:d.shift(),A(t,d,o)},H.toDigits=function(t,n){var r=new e(this);return t=null!=t&&W(t,1,D,18,"precision")?0|t:null,n=null!=n&&W(n,0,8,18,w)?0|n:C,t?P(r,t,n):r},H.toExponential=function(t,e){return m(this,null!=t&&W(t,0,D,19)?~~t+1:null,e,19)},H.toFixed=function(t,e){return m(this,null!=t&&W(t,0,D,20)?~~t+this.e+1:null,e,20)},H.toFormat=function(t,e){var n=m(this,null!=t&&W(t,0,D,21)?~~t+this.e+1:null,e,21);if(this.c){var r,i=n.split("."),o=+K.groupSize,a=+K.secondaryGroupSize,u=K.groupSeparator,s=i[0],c=i[1],l=this.s<0,f=l?s.slice(1):s,p=f.length;if(a&&(r=o,o=a,a=r,p-=r),o>0&&p>0){for(r=p%o||o,s=f.substr(0,r);p>r;r+=o)s+=u+f.substr(r,o);a>0&&(s+=u+f.slice(r)),l&&(s="-"+s)}n=c?s+K.decimalSeparator+((a=+K.fractionGroupSize)?c.replace(new RegExp("\\d{"+a+"}\\B","g"),"$&"+K.fractionGroupSeparator):c):s}return n},H.toFraction=function(t){var n,r,i,a,u,s,c,l,f,p=J,m=this,h=m.c,g=new e(L),d=r=new e(L),v=c=new e(L);if(null!=t&&(J=!1,s=new e(t),J=p,(!(p=s.isInt())||s.lt(L))&&(J&&S(22,"max denominator "+(p?"out of range":"not an integer"),t),t=!p&&s.c&&P(s,s.e+1,1).gte(L)?s:null)),!h)return m.toString();for(f=o(h),a=g.e=f.length-m.e-1,g.c[0]=_[(u=a%N)<0?N+u:u],t=!t||s.cmp(g)>0?a>0?g:d:s,u=M,M=1/0,s=new e(f),c.c[0]=0;l=k(s,g,0,1),i=r.plus(l.times(v)),1!=i.cmp(t);)r=v,v=i,d=c.plus(l.times(i=d)),c=i,g=s.minus(l.times(i=g)),s=i;return i=k(t.minus(r),v,0,1),c=c.plus(i.times(d)),r=r.plus(i.times(v)),c.s=d.s=m.s,a*=2,n=k(d,v,a,C).minus(m).abs().cmp(k(c,r,a,C).minus(m).abs())<1?[d.toString(),v.toString()]:[c.toString(),r.toString()],M=u,n},H.toNumber=function(){var t=this;return+t||(t.s?0*t.s:0/0)},H.toPower=H.pow=function(t){var n,r,i=b(0>t?-t:+t),o=this;if(!W(t,-O,O,23,"exponent")&&(!isFinite(t)||i>O&&(t/=0)||parseFloat(t)!=t&&!(t=0/0)))return new e(Math.pow(+o,t));for(n=V?v(V/N+2):0,r=new e(L);;){if(i%2){if(r=r.times(o),!r.c)break;n&&r.c.length>n&&(r.c.length=n)}if(i=b(i/2),!i)break;o=o.times(o),n&&o.c&&o.c.length>n&&(o.c.length=n)}return 0>t&&(r=L.div(r)),n?P(r,V,C):r},H.toPrecision=function(t,e){return m(this,null!=t&&W(t,1,D,24,"precision")?0|t:null,e,24)},H.toString=function(t){var e,r=this,i=r.s,a=r.e;return null===a?i?(e="Infinity",0>i&&(e="-"+e)):e="NaN":(e=o(r.c),e=null!=t&&W(t,2,64,25,"base")?n(f(e,a),0|t,10,i):j>=a||a>=q?l(e,a):f(e,a),0>i&&r.c[0]&&(e="-"+e)),e},H.truncated=H.trunc=function(){return P(new e(this),this.e+1,1)},H.valueOf=H.toJSON=function(){return this.toString()},null!=t&&e.config(t),e}function i(t){var e=0|t;return t>0||t===e?e:e-1}function o(t){for(var e,n,r=1,i=t.length,o=t[0]+"";i>r;){for(e=t[r++]+"",n=N-e.length;n--;e="0"+e);o+=e}for(i=o.length;48===o.charCodeAt(--i););return o.slice(0,i+1||1)}function a(t,e){var n,r,i=t.c,o=e.c,a=t.s,u=e.s,s=t.e,c=e.e;if(!a||!u)return null;if(n=i&&!i[0],r=o&&!o[0],n||r)return n?r?0:-u:a;if(a!=u)return a;if(n=0>a,r=s==c,!i||!o)return r?0:!i^n?1:-1;if(!r)return s>c^n?1:-1;for(u=(s=i.length)<(c=o.length)?s:c,a=0;u>a;a++)if(i[a]!=o[a])return i[a]>o[a]^n?1:-1;return s==c?0:s>c^n?1:-1}function u(t,e,n){return(t=p(t))>=e&&n>=t}function s(t){return"[object Array]"==Object.prototype.toString.call(t)}function c(t,e,n){for(var r,i,o=[0],a=0,u=t.length;u>a;){for(i=o.length;i--;o[i]*=e);for(o[r=0]+=F.indexOf(t.charAt(a++));rn-1&&(null==o[r+1]&&(o[r+1]=0),o[r+1]+=o[r]/n|0,o[r]%=n)}return o.reverse()}function l(t,e){return(t.length>1?t.charAt(0)+"."+t.slice(1):t)+(0>e?"e":"e+")+e}function f(t,e){var n,r;if(0>e){for(r="0.";++e;r+="0");t=r+t}else if(n=t.length,++e>n){for(r="0",e-=n;--e;r+="0");t+=r}else n>e&&(t=t.slice(0,e)+"."+t.slice(e));return t}function p(t){return t=parseFloat(t),0>t?v(t):b(t)}var m,h,g,d=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,v=Math.ceil,b=Math.floor,y=" not a boolean or binary digit",w="rounding mode",x="number type has more than 15 significant digits",F="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",I=1e14,N=14,O=9007199254740991,_=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],T=1e7,D=1e9;if(m=r(),"function"==typeof define&&define.amd)define(function(){return m});else if("undefined"!=typeof e&&e.exports){if(e.exports=m,!h)try{h=t("crypto")}catch(E){}}else n.BigNumber=m}(this)},{crypto:26}],web3:[function(t,e){if("undefined"!=typeof n)var n;n=t("./lib/web3"),n.providers.HttpProvider=t("./lib/web3/httpprovider"),n.providers.QtSyncProvider=t("./lib/web3/qtsync"),n.eth.contract=t("./lib/web3/contract"),n.abi=t("./lib/solidity/abi"),e.exports=n},{"./lib/solidity/abi":1,"./lib/web3":8,"./lib/web3/contract":9,"./lib/web3/httpprovider":16,"./lib/web3/qtsync":21}]},{},["web3"]); \ No newline at end of file +require=function t(e,n,r){function i(a,u){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(o)return o(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return i(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;av;v++)g.push(h(e.slice(0,a))),e=e.slice(a);n.push(g)}else i.prefixedType("bytes")(t[c].type)?(l=l.slice(a),n.push(h(e.slice(0,a))),e=e.slice(a)):(n.push(h(e.slice(0,a))),e=e.slice(a))}),n},d=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),i=n.extractTypeName(t.name),o=function(){var e=Array.prototype.slice.call(arguments);return f(t.inputs,e)};void 0===e[r]&&(e[r]=o),e[r][i]=o}),e},g=function(t){var e={};return t.forEach(function(t){var r=n.extractDisplayName(t.name),i=n.extractTypeName(t.name),o=function(e){return h(t.outputs,e)};void 0===e[r]&&(e[r]=o),e[r][i]=o}),e},v=function(t,e){var n=a.getConstructor(t,e.length);return n?f(n.inputs,e):(e.length>0&&console.warn("didn't found matching constructor, using default one"),"")};e.exports={inputParser:d,outputParser:g,formatInput:f,formatOutput:h,formatConstructorParams:v}},{"../utils/config":6,"../utils/utils":7,"./formatters":2,"./types":3,"./utils":4}],2:[function(t,e){var n=t("bignumber.js"),r=t("../utils/utils"),i=t("../utils/config"),o=function(t){var e=2*i.ETH_PADDING;return n.config(i.ETH_BIGNUMBER_ROUNDING_MODE),r.padLeft(r.toTwosComplement(t).round().toString(16),e)},a=function(t){return r.fromAscii(t,i.ETH_PADDING).substr(2)},u=function(t){return"000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0")},s=function(t){return o(new n(t).times(new n(2).pow(128)))},c=function(t){return"1"===new n(t.substr(0,1),16).toString(2).substr(0,1)},l=function(t){return t=t||"0",c(t)?new n(t,16).minus(new n("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new n(t,16)},f=function(t){return t=t||"0",new n(t,16)},p=function(t){return l(t).dividedBy(new n(2).pow(128))},m=function(t){return f(t).dividedBy(new n(2).pow(128))},h=function(t){return"0x"+t},d=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t?!0:!1},g=function(t){return r.toAscii(t)},v=function(t){return"0x"+t.slice(t.length-40,t.length)};e.exports={formatInputInt:o,formatInputString:a,formatInputBool:u,formatInputReal:s,formatOutputInt:l,formatOutputUInt:f,formatOutputReal:p,formatOutputUReal:m,formatOutputHash:h,formatOutputBool:d,formatOutputString:g,formatOutputAddress:v}},{"../utils/config":6,"../utils/utils":7,"bignumber.js":"bignumber.js"}],3:[function(t,e){var n=t("./formatters"),r=function(t){return function(e){return 0===e.indexOf(t)}},i=function(t){return function(e){return t===e}},o=function(){return[{type:r("uint"),format:n.formatInputInt},{type:r("int"),format:n.formatInputInt},{type:r("bytes"),format:n.formatInputString},{type:r("real"),format:n.formatInputReal},{type:r("ureal"),format:n.formatInputReal},{type:i("address"),format:n.formatInputInt},{type:i("bool"),format:n.formatInputBool}]},a=function(){return[{type:r("uint"),format:n.formatOutputUInt},{type:r("int"),format:n.formatOutputInt},{type:r("bytes"),format:n.formatOutputString},{type:r("real"),format:n.formatOutputReal},{type:r("ureal"),format:n.formatOutputUReal},{type:i("address"),format:n.formatOutputAddress},{type:i("bool"),format:n.formatOutputBool}]};e.exports={prefixedType:r,namedType:i,inputTypes:o,outputTypes:a}},{"./formatters":2}],4:[function(t,e){var n=function(t,e){return t.filter(function(t){return"constructor"===t.type&&t.inputs.length===e})[0]},r=function(t){return t.filter(function(t){return"function"===t.type})},i=function(t){return t.filter(function(t){return"event"===t.type})};e.exports={getConstructor:n,filterFunctions:r,filterEvents:i}},{}],5:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],6:[function(t,e){var n=t("bignumber.js"),r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:r,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:n.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3,ETH_DEFAULTBLOCK:"latest"}},{"bignumber.js":"bignumber.js"}],7:[function(t,e){var n=t("bignumber.js"),r={wei:"1",kwei:"1000",ada:"1000",mwei:"1000000",babbage:"1000000",gwei:"1000000000",shannon:"1000000000",szabo:"1000000000000",finney:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},i=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},o=function(t,e){for(var n=!1,r=0;rn;n+=2){var i=parseInt(t.substr(n,2),16);if(0===i)break;e+=String.fromCharCode(i)}return e},u=function(t){for(var e="",n=0;n1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},o.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},o.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return n.getInstance().sendAsync(t,function(n,r){t.callback(null,e.formatOutput(r))})}return this.formatOutput(n.getInstance().send(t))},e.exports=o},{"../utils/utils":7,"./errors":12,"./requestmanager":23}],20:[function(t,e){var n=t("../utils/utils"),r=t("./property"),i=[],o=[new r({name:"listening",getter:"net_listening"}),new r({name:"peerCount",getter:"net_peerCount",outputFormatter:n.toDecimal})];e.exports={methods:i,properties:o}},{"../utils/utils":7,"./property":21}],21:[function(t,e){var n=t("./requestmanager"),r=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};r.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},r.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},r.prototype.attachToObject=function(t){var e={get:this.get.bind(this),set:this.set.bind(this)},n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},Object.defineProperty(t[n[0]],n[1],e)):Object.defineProperty(t,n[0],e)},r.prototype.get=function(){return this.formatOutput(n.getInstance().send({method:this.getter}))},r.prototype.set=function(t){return n.getInstance().send({method:this.setter,params:[this.formatInput(t)]})},e.exports=r},{"./requestmanager":23}],22:[function(t,e){var n=function(){};n.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=n},{}],23:[function(t,e){var n=t("./jsonrpc"),r=t("../utils/utils"),i=t("../utils/config"),o=t("./errors"),a=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls=[],this.timeout=null,void this.poll())};a.getInstance=function(){var t=new a;return t},a.prototype.send=function(t){if(!this.provider)return console.error(o.InvalidProvider),null;var e=n.getInstance().toPayload(t.method,t.params),r=this.provider.send(e);if(!n.getInstance().isValidResponse(r))throw o.InvalidResponse(r);return r.result},a.prototype.sendAsync=function(t,e){if(!this.provider)return e(o.InvalidProvider);var r=n.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(r,function(t,r){return t?e(t):n.getInstance().isValidResponse(r)?void e(null,r.result):e(o.InvalidResponse(r))})},a.prototype.setProvider=function(t){this.provider=t},a.prototype.startPolling=function(t,e,n,r){this.polls.push({data:t,id:e,callback:n,uninstall:r})},a.prototype.stopPolling=function(t){for(var e=this.polls.length;e--;){var n=this.polls[e];n.id===t&&this.polls.splice(e,1)}},a.prototype.reset=function(){this.polls.forEach(function(t){t.uninstall(t.id)}),this.polls=[],this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},a.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),i.ETH_POLLING_TIMEOUT),this.polls.length){if(!this.provider)return void console.error(o.InvalidProvider);var t=n.getInstance().toBatchPayload(this.polls.map(function(t){return t.data})),e=this;this.provider.sendAsync(t,function(t,i){if(!t){if(!r.isArray(i))throw o.InvalidResponse(i);i.map(function(t,n){return t.callback=e.polls[n].callback,t}).filter(function(t){var e=n.getInstance().isValidResponse(t);return e||t.callback(o.InvalidResponse(t)),e}).filter(function(t){return r.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}},e.exports=a},{"../utils/config":6,"../utils/utils":7,"./errors":12,"./jsonrpc":18}],24:[function(t,e){var n=t("./method"),r=t("./formatters"),i=new n({name:"post",call:"shh_post",params:1,inputFormatter:r.inputPostFormatter}),o=new n({name:"newIdentity",call:"shh_newIdentity",params:0}),a=new n({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new n({name:"newGroup",call:"shh_newGroup",params:0}),s=new n({name:"addToGroup",call:"shh_addToGroup",params:0}),c=[i,o,a,u,s];e.exports={methods:c}},{"./formatters":16,"./method":19}],25:[function(t,e){var n=t("../web3"),r=t("../utils/config"),i=function(t){return n.sha3(n.fromAscii(t)).slice(0,2+2*r.ETH_SIGNATURE_LENGTH)},o=function(t){return n.sha3(n.fromAscii(t))};e.exports={functionSignatureFromAscii:i,eventSignatureFromAscii:o}},{"../utils/config":6,"../web3":9}],26:[function(t,e){var n=t("./method"),r=function(){var t=function(t){return"string"==typeof t[0]?"eth_newBlockFilter":"eth_newFilter"},e=new n({name:"newFilter",call:t,params:1}),r=new n({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),i=new n({name:"getLogs",call:"eth_getFilterLogs",params:1}),o=new n({name:"poll",call:"eth_getFilterChanges",params:1});return[e,r,i,o]},i=function(){var t=new n({name:"newFilter",call:"shh_newFilter",params:1}),e=new n({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),r=new n({name:"getLogs",call:"shh_getMessages",params:1}),i=new n({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,r,i]};e.exports={eth:r,shh:i}},{"./method":19}],27:[function(){},{}],"bignumber.js":[function(t,e){!function(n){"use strict";function r(t){function e(t,r){var i,o,a,u,s,c,l=this;if(!(l instanceof e))return J&&S(26,"constructor call without new",t),new e(t,r);if(null!=r&&W(r,2,64,R,"base")){if(r=0|r,c=t+"",10==r)return l=new e(t instanceof e?t:c),P(l,L+l.e+1,U);if((u="number"==typeof t)&&0*t!=0||!new RegExp("^-?"+(i="["+F.slice(0,r)+"]+")+"(?:\\."+i+")?$",37>r?"i":"").test(c))return d(l,c,u,r);u?(l.s=0>1/t?(c=c.slice(1),-1):1,J&&c.replace(/^0\.0*|\./,"").length>15&&S(R,x,t),u=!1):l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1,c=n(c,10,r,l.s)}else{if(t instanceof e)return l.s=t.s,l.e=t.e,l.c=(t=t.c)?t.slice():t,void(R=0);if((u="number"==typeof t)&&0*t==0){if(l.s=0>1/t?(t=-t,-1):1,t===~~t){for(o=0,a=t;a>=10;a/=10,o++);return l.e=o,l.c=[t],void(R=0)}c=t+""}else{if(!g.test(c=t+""))return d(l,c,u);l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1}}for((o=c.indexOf("."))>-1&&(c=c.replace(".","")),(a=c.search(/e/i))>0?(0>o&&(o=a),o+=+c.slice(a+1),c=c.substring(0,a)):0>o&&(o=c.length),a=0;48===c.charCodeAt(a);a++);for(s=c.length;48===c.charCodeAt(--s););if(c=c.slice(a,s+1))if(s=c.length,u&&J&&s>15&&S(R,x,l.s*t),o=o-a-1,o>M)l.c=l.e=null;else if(G>o)l.c=[l.e=0];else{if(l.e=o,l.c=[],a=(o+1)%N,0>o&&(a+=N),s>a){for(a&&l.c.push(+c.slice(0,a)),s-=N;s>a;)l.c.push(+c.slice(a,a+=N));c=c.slice(a),a=N-c.length}else a-=s;for(;a--;c+="0");l.c.push(+c)}else l.c=[l.e=0];R=0}function n(t,n,r,i){var a,u,s,l,p,m,h,d=t.indexOf("."),g=L,v=U;for(37>r&&(t=t.toLowerCase()),d>=0&&(s=z,z=0,t=t.replace(".",""),h=new e(r),p=h.pow(t.length-d),z=s,h.c=c(f(o(p.c),p.e),10,n),h.e=h.c.length),m=c(t,r,n),u=s=m.length;0==m[--s];m.pop());if(!m[0])return"0";if(0>d?--u:(p.c=m,p.e=u,p.s=i,p=k(p,h,g,v,n),m=p.c,l=p.r,u=p.e),a=u+g+1,d=m[a],s=n/2,l=l||0>a||null!=m[a+1],l=4>v?(null!=d||l)&&(0==v||v==(p.s<0?3:2)):d>s||d==s&&(4==v||l||6==v&&1&m[a-1]||v==(p.s<0?8:7)),1>a||!m[0])t=l?f("1",-g):"0";else{if(m.length=a,l)for(--n;++m[--a]>n;)m[a]=0,a||(++u,m.unshift(1));for(s=m.length;!m[--s];);for(d=0,t="";s>=d;t+=F.charAt(m[d++]));t=f(t,u)}return t}function m(t,n,r,i){var a,u,s,c,p;if(r=null!=r&&W(r,0,8,i,w)?0|r:U,!t.c)return t.toString();if(a=t.c[0],s=t.e,null==n)p=o(t.c),p=19==i||24==i&&j>=s?l(p,s):f(p,s);else if(t=P(new e(t),n,r),u=t.e,p=o(t.c),c=p.length,19==i||24==i&&(u>=n||j>=u)){for(;n>c;p+="0",c++);p=l(p,u)}else if(n-=s,p=f(p,u),u+1>c){if(--n>0)for(p+=".";n--;p+="0");}else if(n+=u-c,n>0)for(u+1==c&&(p+=".");n--;p+="0");return t.s<0&&a?"-"+p:p}function D(t,n){var r,i,o=0;for(s(t[0])&&(t=t[0]),r=new e(t[0]);++ot||t>n||t!=p(t))&&S(r,(i||"decimal places")+(e>t||t>n?" out of range":" not an integer"),t),!0}function B(t,e,n){for(var r=1,i=e.length;!e[--i];e.pop());for(i=e[0];i>=10;i/=10,r++);return(n=r+n*N-1)>M?t.c=t.e=null:G>n?t.c=[t.e=0]:(t.e=n,t.c=e),t}function S(t,e,n){var r=new Error(["new BigNumber","cmp","config","div","divToInt","eq","gt","gte","lt","lte","minus","mod","plus","precision","random","round","shift","times","toDigits","toExponential","toFixed","toFormat","toFraction","pow","toPrecision","toString","BigNumber"][t]+"() "+e+": "+n);throw r.name="BigNumber Error",R=0,r}function P(t,e,n,r){var i,o,a,u,s,c,l,f=t.c,p=_;if(f){t:{for(i=1,u=f[0];u>=10;u/=10,i++);if(o=e-i,0>o)o+=N,a=e,s=f[c=0],l=s/p[i-a-1]%10|0;else if(c=v((o+1)/N),c>=f.length){if(!r)break t;for(;f.length<=c;f.push(0));s=l=0,i=1,o%=N,a=o-N+1}else{for(s=u=f[c],i=1;u>=10;u/=10,i++);o%=N,a=o-N+i,l=0>a?0:s/p[i-a-1]%10|0}if(r=r||0>e||null!=f[c+1]||(0>a?s:s%p[i-a-1]),r=4>n?(l||r)&&(0==n||n==(t.s<0?3:2)):l>5||5==l&&(4==n||r||6==n&&(o>0?a>0?s/p[i-a]:0:f[c-1])%10&1||n==(t.s<0?8:7)),1>e||!f[0])return f.length=0,r?(e-=t.e+1,f[0]=p[e%N],t.e=-e||0):f[0]=t.e=0,t; +if(0==o?(f.length=c,u=1,c--):(f.length=c+1,u=p[N-o],f[c]=a>0?b(s/p[i-a]%p[a])*u:0),r)for(;;){if(0==c){for(o=1,a=f[0];a>=10;a/=10,o++);for(a=f[0]+=u,u=1;a>=10;a/=10,u++);o!=u&&(t.e++,f[0]==I&&(f[0]=1));break}if(f[c]+=u,f[c]!=I)break;f[c--]=0,u=1}for(o=f.length;0===f[--o];f.pop());}t.e>M?t.c=t.e=null:t.en?null!=(t=i[n++]):void 0};return a(e="DECIMAL_PLACES")&&W(t,0,A,2,e)&&(L=0|t),r[e]=L,a(e="ROUNDING_MODE")&&W(t,0,8,2,e)&&(U=0|t),r[e]=U,a(e="EXPONENTIAL_AT")&&(s(t)?W(t[0],-A,0,2,e)&&W(t[1],0,A,2,e)&&(j=0|t[0],q=0|t[1]):W(t,-A,A,2,e)&&(j=-(q=0|(0>t?-t:t)))),r[e]=[j,q],a(e="RANGE")&&(s(t)?W(t[0],-A,-1,2,e)&&W(t[1],1,A,2,e)&&(G=0|t[0],M=0|t[1]):W(t,-A,A,2,e)&&(0|t?G=-(M=0|(0>t?-t:t)):J&&S(2,e+" cannot be zero",t))),r[e]=[G,M],a(e="ERRORS")&&(t===!!t||1===t||0===t?(R=0,W=(J=!!t)?E:u):J&&S(2,e+y,t)),r[e]=J,a(e="CRYPTO")&&(t===!!t||1===t||0===t?($=!(!t||!h||"object"!=typeof h),t&&!$&&J&&S(2,"crypto unavailable",h)):J&&S(2,e+y,t)),r[e]=$,a(e="MODULO_MODE")&&W(t,0,9,2,e)&&(V=0|t),r[e]=V,a(e="POW_PRECISION")&&W(t,0,A,2,e)&&(z=0|t),r[e]=z,a(e="FORMAT")&&("object"==typeof t?K=t:J&&S(2,e+" not an object",t)),r[e]=K,r},e.max=function(){return D(arguments,H.lt)},e.min=function(){return D(arguments,H.gt)},e.random=function(){var t=9007199254740992,n=Math.random()*t&2097151?function(){return b(Math.random()*t)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)};return function(t){var r,i,o,a,u,s=0,c=[],l=new e(C);if(t=null!=t&&W(t,0,A,14)?0|t:L,a=v(t/N),$)if(h&&h.getRandomValues){for(r=h.getRandomValues(new Uint32Array(a*=2));a>s;)u=131072*r[s]+(r[s+1]>>>11),u>=9e15?(i=h.getRandomValues(new Uint32Array(2)),r[s]=i[0],r[s+1]=i[1]):(c.push(u%1e14),s+=2);s=a/2}else if(h&&h.randomBytes){for(r=h.randomBytes(a*=7);a>s;)u=281474976710656*(31&r[s])+1099511627776*r[s+1]+4294967296*r[s+2]+16777216*r[s+3]+(r[s+4]<<16)+(r[s+5]<<8)+r[s+6],u>=9e15?h.randomBytes(7).copy(r,s):(c.push(u%1e14),s+=7);s=a/7}else J&&S(14,"crypto unavailable",h);if(!s)for(;a>s;)u=n(),9e15>u&&(c[s++]=u%1e14);for(a=c[--s],t%=N,a&&t&&(u=_[N-t],c[s]=b(a/u)*u);0===c[s];c.pop(),s--);if(0>s)c=[o=0];else{for(o=-1;0===c[0];c.shift(),o-=N);for(s=1,u=c[0];u>=10;u/=10,s++);N>s&&(o-=N-s)}return l.e=o,l.c=c,l}}(),k=function(){function t(t,e,n){var r,i,o,a,u=0,s=t.length,c=e%T,l=e/T|0;for(t=t.slice();s--;)o=t[s]%T,a=t[s]/T|0,r=l*o+a*c,i=c*o+r%T*T+u,u=(i/n|0)+(r/T|0)+l*a,t[s]=i%n;return u&&t.unshift(u),t}function n(t,e,n,r){var i,o;if(n!=r)o=n>r?1:-1;else for(i=o=0;n>i;i++)if(t[i]!=e[i]){o=t[i]>e[i]?1:-1;break}return o}function r(t,e,n,r){for(var i=0;n--;)t[n]-=i,i=t[n]1;t.shift());}return function(o,a,u,s,c){var l,f,p,m,h,d,g,v,y,w,x,F,O,_,T,A,D,E=o.s==a.s?1:-1,B=o.c,S=a.c;if(!(B&&B[0]&&S&&S[0]))return new e(o.s&&a.s&&(B?!S||B[0]!=S[0]:S)?B&&0==B[0]||!S?0*E:E/0:0/0);for(v=new e(E),y=v.c=[],f=o.e-a.e,E=u+f+1,c||(c=I,f=i(o.e/N)-i(a.e/N),E=E/N|0),p=0;S[p]==(B[p]||0);p++);if(S[p]>(B[p]||0)&&f--,0>E)y.push(1),m=!0;else{for(_=B.length,A=S.length,p=0,E+=2,h=b(c/(S[0]+1)),h>1&&(S=t(S,h,c),B=t(B,h,c),A=S.length,_=B.length),O=A,w=B.slice(0,A),x=w.length;A>x;w[x++]=0);D=S.slice(),D.unshift(0),T=S[0],S[1]>=c/2&&T++;do h=0,l=n(S,w,A,x),0>l?(F=w[0],A!=x&&(F=F*c+(w[1]||0)),h=b(F/T),h>1?(h>=c&&(h=c-1),d=t(S,h,c),g=d.length,x=w.length,l=n(d,w,g,x),1==l&&(h--,r(d,g>A?D:S,g,c))):(0==h&&(l=h=1),d=S.slice()),g=d.length,x>g&&d.unshift(0),r(w,d,x,c),-1==l&&(x=w.length,l=n(S,w,A,x),1>l&&(h++,r(w,x>A?D:S,x,c))),x=w.length):0===l&&(h++,w=[0]),y[p++]=h,l&&w[0]?w[x++]=B[O]||0:(w=[B[O]],x=1);while((O++<_||null!=w[0])&&E--);m=null!=w[0],y[0]||y.shift()}if(c==I){for(p=1,E=y[0];E>=10;E/=10,p++);P(v,u+(v.e=p+f*N-1)+1,s,m)}else v.e=f,v.r=+m;return v}}(),d=function(){var t=/^(-?)0([xbo])(?=\w[\w.]*$)/i,n=/^([^.]+)\.$/,r=/^\.([^.]+)$/,i=/^-?(Infinity|NaN)$/,o=/^\s*\+(?=[\w.])|^\s+|\s+$/g;return function(a,u,s,c){var l,f=s?u:u.replace(o,"");if(i.test(f))a.s=isNaN(f)?null:0>f?-1:1;else{if(!s&&(f=f.replace(t,function(t,e,n){return l="x"==(n=n.toLowerCase())?16:"b"==n?2:8,c&&c!=l?t:e}),c&&(l=c,f=f.replace(n,"$1").replace(r,"0.$1")),u!=f))return new e(f,l);J&&S(R,"not a"+(c?" base "+c:"")+" number",u),a.s=null}a.c=a.e=null,R=0}}(),H.absoluteValue=H.abs=function(){var t=new e(this);return t.s<0&&(t.s=1),t},H.ceil=function(){return P(new e(this),this.e+1,2)},H.comparedTo=H.cmp=function(t,n){return R=1,a(this,new e(t,n))},H.decimalPlaces=H.dp=function(){var t,e,n=this.c;if(!n)return null;if(t=((e=n.length-1)-i(this.e/N))*N,e=n[e])for(;e%10==0;e/=10,t--);return 0>t&&(t=0),t},H.dividedBy=H.div=function(t,n){return R=3,k(this,new e(t,n),L,U)},H.dividedToIntegerBy=H.divToInt=function(t,n){return R=4,k(this,new e(t,n),0,1)},H.equals=H.eq=function(t,n){return R=5,0===a(this,new e(t,n))},H.floor=function(){return P(new e(this),this.e+1,3)},H.greaterThan=H.gt=function(t,n){return R=6,a(this,new e(t,n))>0},H.greaterThanOrEqualTo=H.gte=function(t,n){return R=7,1===(n=a(this,new e(t,n)))||0===n},H.isFinite=function(){return!!this.c},H.isInteger=H.isInt=function(){return!!this.c&&i(this.e/N)>this.c.length-2},H.isNaN=function(){return!this.s},H.isNegative=H.isNeg=function(){return this.s<0},H.isZero=function(){return!!this.c&&0==this.c[0]},H.lessThan=H.lt=function(t,n){return R=8,a(this,new e(t,n))<0},H.lessThanOrEqualTo=H.lte=function(t,n){return R=9,-1===(n=a(this,new e(t,n)))||0===n},H.minus=H.sub=function(t,n){var r,o,a,u,s=this,c=s.s;if(R=10,t=new e(t,n),n=t.s,!c||!n)return new e(0/0);if(c!=n)return t.s=-n,s.plus(t);var l=s.e/N,f=t.e/N,p=s.c,m=t.c;if(!l||!f){if(!p||!m)return p?(t.s=-n,t):new e(m?s:0/0);if(!p[0]||!m[0])return m[0]?(t.s=-n,t):new e(p[0]?s:3==U?-0:0)}if(l=i(l),f=i(f),p=p.slice(),c=l-f){for((u=0>c)?(c=-c,a=p):(f=l,a=m),a.reverse(),n=c;n--;a.push(0));a.reverse()}else for(o=(u=(c=p.length)<(n=m.length))?c:n,c=n=0;o>n;n++)if(p[n]!=m[n]){u=p[n]0)for(;n--;p[r++]=0);for(n=I-1;o>c;){if(p[--o]0?(s=u,r=l):(a=-a,r=c),r.reverse();a--;r.push(0));r.reverse()}for(a=c.length,n=l.length,0>a-n&&(r=l,l=c,c=r,n=a),a=0;n;)a=(c[--n]=c[n]+l[n]+a)/I|0,c[n]%=I;return a&&(c.unshift(a),++s),B(t,c,s)},H.precision=H.sd=function(t){var e,n,r=this,i=r.c;if(null!=t&&t!==!!t&&1!==t&&0!==t&&(J&&S(13,"argument"+y,t),t!=!!t&&(t=null)),!i)return null;if(n=i.length-1,e=n*N+1,n=i[n]){for(;n%10==0;n/=10,e--);for(n=i[0];n>=10;n/=10,e++);}return t&&r.e+1>e&&(e=r.e+1),e},H.round=function(t,n){var r=new e(this);return(null==t||W(t,0,A,15))&&P(r,~~t+this.e+1,null!=n&&W(n,0,8,15,w)?0|n:U),r},H.shift=function(t){var n=this;return W(t,-O,O,16,"argument")?n.times("1e"+p(t)):new e(n.c&&n.c[0]&&(-O>t||t>O)?n.s*(0>t?0:1/0):n)},H.squareRoot=H.sqrt=function(){var t,n,r,a,u,s=this,c=s.c,l=s.s,f=s.e,p=L+4,m=new e("0.5");if(1!==l||!c||!c[0])return new e(!l||0>l&&(!c||c[0])?0/0:c?s:1/0);if(l=Math.sqrt(+s),0==l||l==1/0?(n=o(c),(n.length+f)%2==0&&(n+="0"),l=Math.sqrt(n),f=i((f+1)/2)-(0>f||f%2),l==1/0?n="1e"+f:(n=l.toExponential(),n=n.slice(0,n.indexOf("e")+1)+f),r=new e(n)):r=new e(l+""),r.c[0])for(f=r.e,l=f+p,3>l&&(l=0);;)if(u=r,r=m.times(u.plus(k(s,u,p,1))),o(u.c).slice(0,l)===(n=o(r.c)).slice(0,l)){if(r.el&&(g=w,w=x,x=g,a=l,l=m,m=a),a=l+m,g=[];a--;g.push(0));for(v=I,b=T,a=m;--a>=0;){for(r=0,h=x[a]%b,d=x[a]/b|0,s=l,u=a+s;u>a;)f=w[--s]%b,p=w[s]/b|0,c=d*f+p*h,f=h*f+c%b*b+g[u]+r,r=(f/v|0)+(c/b|0)+d*p,g[u--]=f%v;g[u]=r}return r?++o:g.shift(),B(t,g,o)},H.toDigits=function(t,n){var r=new e(this);return t=null!=t&&W(t,1,A,18,"precision")?0|t:null,n=null!=n&&W(n,0,8,18,w)?0|n:U,t?P(r,t,n):r},H.toExponential=function(t,e){return m(this,null!=t&&W(t,0,A,19)?~~t+1:null,e,19)},H.toFixed=function(t,e){return m(this,null!=t&&W(t,0,A,20)?~~t+this.e+1:null,e,20)},H.toFormat=function(t,e){var n=m(this,null!=t&&W(t,0,A,21)?~~t+this.e+1:null,e,21);if(this.c){var r,i=n.split("."),o=+K.groupSize,a=+K.secondaryGroupSize,u=K.groupSeparator,s=i[0],c=i[1],l=this.s<0,f=l?s.slice(1):s,p=f.length;if(a&&(r=o,o=a,a=r,p-=r),o>0&&p>0){for(r=p%o||o,s=f.substr(0,r);p>r;r+=o)s+=u+f.substr(r,o);a>0&&(s+=u+f.slice(r)),l&&(s="-"+s)}n=c?s+K.decimalSeparator+((a=+K.fractionGroupSize)?c.replace(new RegExp("\\d{"+a+"}\\B","g"),"$&"+K.fractionGroupSeparator):c):s}return n},H.toFraction=function(t){var n,r,i,a,u,s,c,l,f,p=J,m=this,h=m.c,d=new e(C),g=r=new e(C),v=c=new e(C);if(null!=t&&(J=!1,s=new e(t),J=p,(!(p=s.isInt())||s.lt(C))&&(J&&S(22,"max denominator "+(p?"out of range":"not an integer"),t),t=!p&&s.c&&P(s,s.e+1,1).gte(C)?s:null)),!h)return m.toString();for(f=o(h),a=d.e=f.length-m.e-1,d.c[0]=_[(u=a%N)<0?N+u:u],t=!t||s.cmp(d)>0?a>0?d:g:s,u=M,M=1/0,s=new e(f),c.c[0]=0;l=k(s,d,0,1),i=r.plus(l.times(v)),1!=i.cmp(t);)r=v,v=i,g=c.plus(l.times(i=g)),c=i,d=s.minus(l.times(i=d)),s=i;return i=k(t.minus(r),v,0,1),c=c.plus(i.times(g)),r=r.plus(i.times(v)),c.s=g.s=m.s,a*=2,n=k(g,v,a,U).minus(m).abs().cmp(k(c,r,a,U).minus(m).abs())<1?[g.toString(),v.toString()]:[c.toString(),r.toString()],M=u,n},H.toNumber=function(){var t=this;return+t||(t.s?0*t.s:0/0)},H.toPower=H.pow=function(t){var n,r,i=b(0>t?-t:+t),o=this;if(!W(t,-O,O,23,"exponent")&&(!isFinite(t)||i>O&&(t/=0)||parseFloat(t)!=t&&!(t=0/0)))return new e(Math.pow(+o,t));for(n=z?v(z/N+2):0,r=new e(C);;){if(i%2){if(r=r.times(o),!r.c)break;n&&r.c.length>n&&(r.c.length=n)}if(i=b(i/2),!i)break;o=o.times(o),n&&o.c&&o.c.length>n&&(o.c.length=n)}return 0>t&&(r=C.div(r)),n?P(r,z,U):r},H.toPrecision=function(t,e){return m(this,null!=t&&W(t,1,A,24,"precision")?0|t:null,e,24)},H.toString=function(t){var e,r=this,i=r.s,a=r.e;return null===a?i?(e="Infinity",0>i&&(e="-"+e)):e="NaN":(e=o(r.c),e=null!=t&&W(t,2,64,25,"base")?n(f(e,a),0|t,10,i):j>=a||a>=q?l(e,a):f(e,a),0>i&&r.c[0]&&(e="-"+e)),e},H.truncated=H.trunc=function(){return P(new e(this),this.e+1,1)},H.valueOf=H.toJSON=function(){return this.toString()},null!=t&&e.config(t),e}function i(t){var e=0|t;return t>0||t===e?e:e-1}function o(t){for(var e,n,r=1,i=t.length,o=t[0]+"";i>r;){for(e=t[r++]+"",n=N-e.length;n--;e="0"+e);o+=e}for(i=o.length;48===o.charCodeAt(--i););return o.slice(0,i+1||1)}function a(t,e){var n,r,i=t.c,o=e.c,a=t.s,u=e.s,s=t.e,c=e.e;if(!a||!u)return null;if(n=i&&!i[0],r=o&&!o[0],n||r)return n?r?0:-u:a;if(a!=u)return a;if(n=0>a,r=s==c,!i||!o)return r?0:!i^n?1:-1;if(!r)return s>c^n?1:-1;for(u=(s=i.length)<(c=o.length)?s:c,a=0;u>a;a++)if(i[a]!=o[a])return i[a]>o[a]^n?1:-1;return s==c?0:s>c^n?1:-1}function u(t,e,n){return(t=p(t))>=e&&n>=t}function s(t){return"[object Array]"==Object.prototype.toString.call(t)}function c(t,e,n){for(var r,i,o=[0],a=0,u=t.length;u>a;){for(i=o.length;i--;o[i]*=e);for(o[r=0]+=F.indexOf(t.charAt(a++));rn-1&&(null==o[r+1]&&(o[r+1]=0),o[r+1]+=o[r]/n|0,o[r]%=n)}return o.reverse()}function l(t,e){return(t.length>1?t.charAt(0)+"."+t.slice(1):t)+(0>e?"e":"e+")+e}function f(t,e){var n,r;if(0>e){for(r="0.";++e;r+="0");t=r+t}else if(n=t.length,++e>n){for(r="0",e-=n;--e;r+="0");t+=r}else n>e&&(t=t.slice(0,e)+"."+t.slice(e));return t}function p(t){return t=parseFloat(t),0>t?v(t):b(t)}var m,h,d,g=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,v=Math.ceil,b=Math.floor,y=" not a boolean or binary digit",w="rounding mode",x="number type has more than 15 significant digits",F="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",I=1e14,N=14,O=9007199254740991,_=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],T=1e7,A=1e9;if(m=r(),"function"==typeof define&&define.amd)define(function(){return m});else if("undefined"!=typeof e&&e.exports){if(e.exports=m,!h)try{h=t("crypto")}catch(D){}}else n.BigNumber=m}(this)},{crypto:27}],web3:[function(t,e){var n=t("./lib/web3");n.providers.HttpProvider=t("./lib/web3/httpprovider"),n.providers.QtSyncProvider=t("./lib/web3/qtsync"),n.eth.contract=t("./lib/web3/contract"),n.abi=t("./lib/solidity/abi"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=n),e.exports=n},{"./lib/solidity/abi":1,"./lib/web3":9,"./lib/web3/contract":10,"./lib/web3/httpprovider":17,"./lib/web3/qtsync":22}]},{},["web3"]); \ No newline at end of file diff --git a/index.js b/index.js index ac19e2918..ae231d7d9 100644 --- a/index.js +++ b/index.js @@ -1,14 +1,13 @@ -// dont override global variable -if (typeof web3 !== 'undefined') { - var web3; -} - -web3 = require('./lib/web3'); +var web3 = require('./lib/web3'); web3.providers.HttpProvider = require('./lib/web3/httpprovider'); web3.providers.QtSyncProvider = require('./lib/web3/qtsync'); web3.eth.contract = require('./lib/web3/contract'); web3.abi = require('./lib/solidity/abi'); - +// dont override global variable +if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { + window.web3 = web3; +} module.exports = web3; + diff --git a/lib/solidity/abi.js b/lib/solidity/abi.js index a1a9e18d4..030b11184 100644 --- a/lib/solidity/abi.js +++ b/lib/solidity/abi.js @@ -14,10 +14,10 @@ You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file abi.js - * @authors: - * Marek Kotewicz - * Gav Wood +/** + * @file abi.js + * @author Marek Kotewicz + * @author Gav Wood * @date 2014 */ @@ -25,6 +25,7 @@ var utils = require('../utils/utils'); var c = require('../utils/config'); var types = require('./types'); var f = require('./formatters'); +var solUtils = require('./utils'); /** * throw incorrect type error @@ -237,9 +238,21 @@ var outputParser = function (json) { return parser; }; +var formatConstructorParams = function (abi, params) { + var constructor = solUtils.getConstructor(abi, params.length); + if (!constructor) { + if (params.length > 0) { + console.warn("didn't found matching constructor, using default one"); + } + return ''; + } + return formatInput(constructor.inputs, params); +}; + module.exports = { inputParser: inputParser, outputParser: outputParser, formatInput: formatInput, - formatOutput: formatOutput + formatOutput: formatOutput, + formatConstructorParams: formatConstructorParams }; diff --git a/lib/solidity/utils.js b/lib/solidity/utils.js new file mode 100644 index 000000000..ca0929bb8 --- /dev/null +++ b/lib/solidity/utils.js @@ -0,0 +1,68 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file utils.js + * @author Marek Kotewicz + * @date 2015 + */ + +/** + * Returns the contstructor with matching number of arguments + * + * @method getConstructor + * @param {Array} abi + * @param {Number} numberOfArgs + * @returns {Object} constructor function abi + */ +var getConstructor = function (abi, numberOfArgs) { + return abi.filter(function (f) { + return f.type === 'constructor' && f.inputs.length === numberOfArgs; + })[0]; +}; + +/** + * Filters all functions from input abi + * + * @method filterFunctions + * @param {Array} abi + * @returns {Array} abi array with filtered objects of type 'function' + */ +var filterFunctions = function (json) { + return json.filter(function (current) { + return current.type === 'function'; + }); +}; + +/** + * Filters all events from input abi + * + * @method filterEvents + * @param {Array} abi + * @returns {Array} abi array with filtered objects of type 'event' + */ +var filterEvents = function (json) { + return json.filter(function (current) { + return current.type === 'event'; + }); +}; + +module.exports = { + getConstructor: getConstructor, + filterFunctions: filterFunctions, + filterEvents: filterEvents +}; + diff --git a/lib/utils/utils.js b/lib/utils/utils.js index 8f4e8b3ed..c45310bbc 100644 --- a/lib/utils/utils.js +++ b/lib/utils/utils.js @@ -161,32 +161,6 @@ var extractTypeName = function (name) { return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : ""; }; -/** - * Filters all functions from input abi - * - * @method filterFunctions - * @param {Array} abi - * @returns {Array} abi array with filtered objects of type 'function' - */ -var filterFunctions = function (json) { - return json.filter(function (current) { - return current.type === 'function'; - }); -}; - -/** - * Filters all events from input abi - * - * @method filterEvents - * @param {Array} abi - * @returns {Array} abi array with filtered objects of type 'event' - */ -var filterEvents = function (json) { - return json.filter(function (current) { - return current.type === 'event'; - }); -}; - /** * Converts value to it's decimal representation in string * @@ -349,14 +323,25 @@ var toTwosComplement = function (number) { }; /** - * Checks if the given string has proper length + * Checks if the given string is strictly an address + * + * @method isStrictAddress + * @param {String} address the given HEX adress + * @return {Boolean} +*/ +var isStrictAddress = function (address) { + return /^0x[0-9a-f]{40}$/.test(address); +}; + +/** + * Checks if the given string is an address * * @method isAddress * @param {String} address the given HEX adress * @return {Boolean} */ var isAddress = function (address) { - return /^0x[0-9a-f]{40}$/.test(address); + return /^(0x)?[0-9a-f]{40}$/.test(address); }; /** @@ -367,7 +352,7 @@ var isAddress = function (address) { * @return {String} formatted address */ var toAddress = function (address) { - if (isAddress(address)) { + if (isStrictAddress(address)) { return address; } @@ -471,14 +456,13 @@ module.exports = { fromAscii: fromAscii, extractDisplayName: extractDisplayName, extractTypeName: extractTypeName, - filterFunctions: filterFunctions, - filterEvents: filterEvents, toWei: toWei, fromWei: fromWei, toBigNumber: toBigNumber, toTwosComplement: toTwosComplement, toAddress: toAddress, isBigNumber: isBigNumber, + isStrictAddress: isStrictAddress, isAddress: isAddress, isFunction: isFunction, isString: isString, diff --git a/lib/version.json b/lib/version.json index 765b908ff..e62e9f783 100644 --- a/lib/version.json +++ b/lib/version.json @@ -1,3 +1,3 @@ { - "version": "0.2.5" + "version": "0.2.6" } diff --git a/lib/web3.js b/lib/web3.js index fb01e47e0..983b34a6f 100644 --- a/lib/web3.js +++ b/lib/web3.js @@ -58,7 +58,7 @@ var web3Properties = [ }), new Property({ name: 'version.ethereum', - getter: 'eth_version', + getter: 'eth_protocolVersion', inputFormatter: utils.toDecimal }), new Property({ diff --git a/lib/web3/contract.js b/lib/web3/contract.js index 4ad2b1783..af9eb66fc 100644 --- a/lib/web3/contract.js +++ b/lib/web3/contract.js @@ -21,8 +21,9 @@ */ var web3 = require('../web3'); -var abi = require('../solidity/abi'); +var solAbi = require('../solidity/abi'); var utils = require('../utils/utils'); +var solUtils = require('../solidity/utils'); var eventImpl = require('./event'); var signature = require('./signature'); @@ -42,11 +43,11 @@ var addFunctionRelatedPropertiesToContract = function (contract) { }; var addFunctionsToContract = function (contract, desc, address) { - var inputParser = abi.inputParser(desc); - var outputParser = abi.outputParser(desc); + var inputParser = solAbi.inputParser(desc); + var outputParser = solAbi.outputParser(desc); // create contract functions - utils.filterFunctions(desc).forEach(function (method) { + solUtils.filterFunctions(desc).forEach(function (method) { var displayName = utils.extractDisplayName(method.name); var typeName = utils.extractTypeName(method.name); @@ -98,14 +99,14 @@ var addFunctionsToContract = function (contract, desc, address) { var addEventRelatedPropertiesToContract = function (contract, desc, address) { contract.address = address; contract._onWatchEventResult = function (data) { - var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc)); + var matchingEvent = event.getMatchingEvent(solUtils.filterEvents(desc)); var parser = eventImpl.outputParser(matchingEvent); return parser(data); }; Object.defineProperty(contract, 'topics', { get: function() { - return utils.filterEvents(desc).map(function (e) { + return solUtils.filterEvents(desc).map(function (e) { return signature.eventSignatureFromAscii(e.name); }); } @@ -115,7 +116,7 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) { var addEventsToContract = function (contract, desc, address) { // create contract events - utils.filterEvents(desc).forEach(function (e) { + solUtils.filterEvents(desc).forEach(function (e) { var impl = function () { var params = Array.prototype.slice.call(arguments); @@ -173,7 +174,7 @@ var contract = function (abi) { return Contract.bind(null, abi); }; -function Contract(abi, address) { +function Contract(abi, options) { // workaround for invalid assumption that method.name is the full anonymous prototype of the method. // it's not. it's just the name. the rest of the code assumes it's actually the anonymous @@ -187,6 +188,17 @@ function Contract(abi, address) { } }); + var address = ''; + if (utils.isAddress(options)) { + address = options; + } else { // is a source code! + // TODO, parse the rest of the args + var code = options; + var args = Array.prototype.slice.call(arguments, 2); + var bytes = solAbi.formatConstructorParams(abi, args); + address = web3.eth.sendTransaction({data: code + bytes}); + } + var result = {}; addFunctionRelatedPropertiesToContract(result); addFunctionsToContract(result, abi, address); diff --git a/lib/web3/eth.js b/lib/web3/eth.js index 3ceafb571..af530ff9b 100644 --- a/lib/web3/eth.js +++ b/lib/web3/eth.js @@ -109,8 +109,8 @@ var getBlock = new Method({ var getUncle = new Method({ name: 'getUncle', call: uncleCall, - params: 3, - inputFormatter: [utils.toHex, utils.toHex, function (val) { return !!val; }], + params: 2, + inputFormatter: [utils.toHex, utils.toHex], outputFormatter: formatters.outputBlockFormatter, }); @@ -234,7 +234,7 @@ var properties = [ new Property({ name: 'gasPrice', getter: 'eth_gasPrice', - outputFormatter: formatters.inputNumberFormatter + outputFormatter: formatters.outputBigNumberFormatter }), new Property({ name: 'accounts', diff --git a/package.js b/package.js index 5c0510352..0ddae0fb8 100644 --- a/package.js +++ b/package.js @@ -1,7 +1,7 @@ /* jshint ignore:start */ Package.describe({ name: 'ethereum:js', - version: '0.2.5', + version: '0.2.6', summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC', git: 'https://github.com/ethereum/ethereum.js', // By default, Meteor will default to using README.md for documentation. diff --git a/package.json b/package.json index 91edf8841..4eba5adcc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "web3", "namespace": "ethereum", - "version": "0.2.5", + "version": "0.2.6", "description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC", "main": "./index.js", "directories": { @@ -49,11 +49,11 @@ }, "repository": { "type": "git", - "url": "https://github.com/ethereum/ethereum.js.git" + "url": "https://github.com/ethereum/web3.js.git" }, - "homepage": "https://github.com/ethereum/ethereum.js", + "homepage": "https://github.com/ethereum/web3.js", "bugs": { - "url": "https://github.com/ethereum/ethereum.js/issues" + "url": "https://github.com/ethereum/web3.js/issues" }, "keywords": [ "ethereum", diff --git a/test/abi.formatConstructorParams.js b/test/abi.formatConstructorParams.js new file mode 100644 index 000000000..9113f02c6 --- /dev/null +++ b/test/abi.formatConstructorParams.js @@ -0,0 +1,106 @@ +var chai = require('chai'); +var assert = require('assert'); +var abi = require('../lib/solidity/abi'); + +describe('lib/solidity/abi', function () { + describe('formatConstructorParams', function () { + it('should format uint256 properly', function () { + // given + var description = [{ + "name": "test", + "type": "constructor", + "inputs": [{ + "name": "a", + "type": "uint256" + } + ] + }]; + + // when + var bytes = abi.formatConstructorParams(description, [2]); + + // then + assert.equal(bytes, '0000000000000000000000000000000000000000000000000000000000000002'); + }); + + it('should not find matching constructor', function () { + // given + var description = [{ + "name": "test", + "type": "constructor", + "inputs": [{ + "name": "a", + "type": "uint256" + } + ] + }]; + + // when + var bytes = abi.formatConstructorParams(description, []); + + // then + assert.equal(bytes, ''); + }); + + it('should not find matching constructor2', function () { + // given + var description = [{ + "name": "test", + "type": "constructor", + "inputs": [{ + "name": "a", + "type": "uint256" + } + ] + }]; + + // when + var bytes = abi.formatConstructorParams(description, [1,2]); + + // then + assert.equal(bytes, ''); + }); + + it('should not find matching constructor3', function () { + // given + var description = [{ + "name": "test", + "type": "function", + "inputs": [{ + "name": "a", + "type": "uint256" + } + ] + }]; + + // when + var bytes = abi.formatConstructorParams(description, [2]); + + // then + assert.equal(bytes, ''); + }); + + it('should find matching constructor with multiple args', function () { + // given + var description = [{ + "name": "test", + "type": "constructor", + "inputs": [{ + "name": "a", + "type": "uint256" + }, { + "name": "b", + "type": "uint256" + }] + }]; + + // when + var bytes = abi.formatConstructorParams(description, ['1', '5']); + + // then + assert.equal(bytes, '00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000005'); + }); + }); +}); + + diff --git a/test/abi.inputParser.js b/test/abi.inputParser.js index a488bb2e5..7dc50b537 100644 --- a/test/abi.inputParser.js +++ b/test/abi.inputParser.js @@ -1,6 +1,7 @@ -var assert = require('assert'); +var chai = require('chai'); +var assert = chai.assert; var BigNumber = require('bignumber.js'); -var abi = require('../lib/solidity/abi.js'); +var abi = require('../lib/solidity/abi'); var clone = function (object) { return JSON.parse(JSON.stringify(object)); }; var description = [{ @@ -19,9 +20,9 @@ var description = [{ ] }]; -describe('lib/solidity/abi', function() { - describe('inputParser', function() { - it('should parse input uint', function() { +describe('lib/solidity/abi', function () { + describe('inputParser', function () { + it('should parse input uint', function () { // given var d = clone(description); diff --git a/test/utils.filters.js b/test/utils.filters.js index 5e6870efa..5f37b6f1a 100644 --- a/test/utils.filters.js +++ b/test/utils.filters.js @@ -1,5 +1,5 @@ var assert = require('assert'); -var utils = require('../lib/utils/utils.js'); +var utils = require('../lib/solidity/utils'); describe('lib/utils/utils', function() { it('should filter functions and events from input array properly', function () { diff --git a/test/utils.isAddress.js b/test/utils.isAddress.js index 3ebbce837..a0658e303 100644 --- a/test/utils.isAddress.js +++ b/test/utils.isAddress.js @@ -8,7 +8,7 @@ var tests = [ { value: 'function', is: false}, { value: {}, is: false}, { value: '0xc6d9d2cd449a754c494264e1809c50e34d64562b', is: true }, - { value: 'c6d9d2cd449a754c494264e1809c50e34d64562b', is: false } + { value: 'c6d9d2cd449a754c494264e1809c50e34d64562b', is: true } ]; describe('lib/utils/utils', function () { diff --git a/test/utils.isStrictAddress.js b/test/utils.isStrictAddress.js new file mode 100644 index 000000000..e23e3deec --- /dev/null +++ b/test/utils.isStrictAddress.js @@ -0,0 +1,23 @@ +var chai = require('chai'); +var utils = require('../lib/utils/utils.js'); +var assert = chai.assert; + +var tests = [ + { value: function () {}, is: false}, + { value: new Function(), is: false}, + { value: 'function', is: false}, + { value: {}, is: false}, + { value: '0xc6d9d2cd449a754c494264e1809c50e34d64562b', is: true }, + { value: 'c6d9d2cd449a754c494264e1809c50e34d64562b', is: false } +]; + +describe('lib/utils/utils', function () { + describe('isStrictAddress', function () { + tests.forEach(function (test) { + it('shoud test if value ' + test.value + ' is address: ' + test.is, function () { + assert.equal(utils.isStrictAddress(test.value), test.is); + }); + }); + }); +}); + diff --git a/test/web3.eth.contract.js b/test/web3.eth.contract.js index 0f2fd8640..a657545db 100644 --- a/test/web3.eth.contract.js +++ b/test/web3.eth.contract.js @@ -1,5 +1,7 @@ var assert = require('assert'); var contract = require('../lib/web3/contract.js'); +var FakeHttpProvider = require('./helpers/FakeHttpProvider'); +var web3 = require('../index'); describe('web3.eth.contract', function() { it('should create simple contract with one method from abi with explicit type name', function () { @@ -20,10 +22,11 @@ describe('web3.eth.contract', function() { } ] }]; + var address = '0x1234567890123456789012345678901234567890'; // when var Con = contract(description); - var myCon = new Con(null); + var myCon = new Con(address); // then assert.equal('function', typeof myCon.test); @@ -48,10 +51,11 @@ describe('web3.eth.contract', function() { } ] }]; + var address = '0x1234567890123456789012345678901234567890'; // when var Con = contract(description); - var myCon = new Con(null); + var myCon = new Con(address); // then assert.equal('function', typeof myCon.test); @@ -90,10 +94,11 @@ describe('web3.eth.contract', function() { } ] }]; + var address = '0x1234567890123456789012345678901234567890'; // when var Con = contract(description); - var myCon = new Con(null); + var myCon = new Con(address); // then assert.equal('function', typeof myCon.test); @@ -134,10 +139,11 @@ describe('web3.eth.contract', function() { } ] }]; + var address = '0x1234567890123456789012345678901234567890'; // when var Con = contract(description); - var myCon = new Con(null); + var myCon = new Con(address); // then assert.equal('function', typeof myCon.test); @@ -162,11 +168,11 @@ describe('web3.eth.contract', function() { } ] }]; - + var address = '0x1234567890123456789012345678901234567890'; // when var Con = contract(description); - var myCon = new Con(null); + var myCon = new Con(address); // then assert.equal('undefined', typeof myCon.test); @@ -191,11 +197,11 @@ describe('web3.eth.contract', function() { } ] }]; - + var address = '0x1234567890123456789012345678901234567890'; // when var Con = contract(description); - var myCon = new Con(null); + var myCon = new Con(address); // then assert.equal('function', typeof myCon.test); @@ -203,5 +209,32 @@ describe('web3.eth.contract', function() { }); + it('should create contract with nondefault constructor', function (done) { + var provider = new FakeHttpProvider(); + web3.setProvider(provider); + web3.reset(); // reset different polls + var address = '0x1234567890123456789012345678901234567890'; + var code = '0x31241231231123123123123121cf121212i123123123123123512312412512111111'; + var description = [{ + "name": "test", + "type": "constructor", + "inputs": [{ + "name": "a", + "type": "uint256" + } + ] + }]; + + provider.injectResult(address); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_sendTransaction'); + assert.equal(payload.params[0].data, code + '0000000000000000000000000000000000000000000000000000000000000002'); + done(); + }); + + var Con = contract(description); + var myCon = new Con(code, 2); + }); }); diff --git a/test/web3.eth.gasPrice.js b/test/web3.eth.gasPrice.js new file mode 100644 index 000000000..eb7272b4d --- /dev/null +++ b/test/web3.eth.gasPrice.js @@ -0,0 +1,39 @@ +var chai = require('chai'); +var assert = chai.assert; +var web3 = require('../index'); +var BigNumber = require('bignumber.js'); +var FakeHttpProvider = require('./helpers/FakeHttpProvider'); + +var method = 'gasPrice'; + +var tests = [{ + result: '0x15f90', + formattedResult: new BigNumber(90000), + call: 'eth_'+ method +}]; + +describe('web3.eth', function () { + describe(method, function () { + tests.forEach(function (test, index) { + it('property test: ' + index, function () { + + // given + var provider = new FakeHttpProvider(); + web3.setProvider(provider); + provider.injectResult(test.result); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, test.call); + assert.deepEqual(payload.params, []); + }); + + // when + var result = web3.eth[method]; + + // then + assert.deepEqual(test.formattedResult, result); + }); + }); + }); +}); + diff --git a/test/web3.eth.getUncle.js b/test/web3.eth.getUncle.js index 111865355..c5d723dc9 100644 --- a/test/web3.eth.getUncle.js +++ b/test/web3.eth.getUncle.js @@ -118,19 +118,19 @@ var formattedBlockResultWithTx = { var tests = [{ args: ['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855', 2], - formattedArgs: ['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855', '0x2', false], + formattedArgs: ['0x47d33b27bb249a2dbab4c0612bf9caf4c1950855', '0x2'], result: blockResult, formattedResult: formattedBlockResult, call: 'eth_getUncleByBlockHashAndIndex' },{ args: [436, 1], - formattedArgs: ['0x1b4', '0x1', false], + formattedArgs: ['0x1b4', '0x1'], result: blockResult, formattedResult: formattedBlockResult, call: 'eth_getUncleByBlockNumberAndIndex' },{ args: [436, 1, true], - formattedArgs: ['0x1b4', '0x1', true], + formattedArgs: ['0x1b4', '0x1'], result: blockResultWithTx, formattedResult: formattedBlockResultWithTx, call: 'eth_getUncleByBlockNumberAndIndex' From c417e2313e6a787b01b1c118e96dbd41dd42fd8f Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 10 Apr 2015 14:56:52 +0200 Subject: [PATCH 002/108] additional fields in transaction: blockHash, blockNumber, transactionIndex --- libethereum/ClientBase.cpp | 11 +++++++++++ libethereum/ClientBase.h | 2 ++ libethereum/Interface.h | 2 ++ libweb3jsonrpc/WebThreeStubServerBase.cpp | 22 ++++++++++++++++------ 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f57b2b174..692081f96 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -321,6 +321,11 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const return Transaction(); } +pair ClientBase::transactionLocation(h256 const& _transactionHash) const +{ + return bc().transactionLocation(_transactionHash); +} + Transactions ClientBase::transactions(h256 _blockHash) const { auto bl = bc().block(_blockHash); @@ -419,3 +424,9 @@ h256 ClientBase::hashFromNumber(BlockNumber _number) const return bc().currentHash(); return bc().numberHash(_number); } + +BlockNumber ClientBase::numberFromHash(h256 _blockHash) const +{ + return bc().number(_blockHash); +} + diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 00bb02ed4..2bc36ae15 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -110,10 +110,12 @@ public: virtual LocalisedLogEntries checkWatch(unsigned _watchId) override; virtual h256 hashFromNumber(BlockNumber _number) const override; + virtual BlockNumber numberFromHash(h256 _blockHash) const override; virtual eth::BlockInfo blockInfo(h256 _hash) const override; virtual eth::BlockDetails blockDetails(h256 _hash) const override; virtual eth::Transaction transaction(h256 _transactionHash) const override; virtual eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; + virtual std::pair transactionLocation(h256 const& _transactionHash) const override; virtual eth::Transactions transactions(h256 _blockHash) const override; virtual eth::TransactionHashes transactionHashes(h256 _blockHash) const override; virtual eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index ac41b0ec1..0f4e6a778 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -119,7 +119,9 @@ public: // [BLOCK QUERY API] virtual Transaction transaction(h256 _transactionHash) const = 0; + virtual std::pair transactionLocation(h256 const& _transactionHash) const = 0; virtual h256 hashFromNumber(BlockNumber _number) const = 0; + virtual BlockNumber numberFromHash(h256 _blockHash) const = 0; virtual BlockInfo blockInfo(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 291415a68..c760005de 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -79,7 +79,7 @@ static Json::Value toJson(dev::eth::BlockInfo const& _bi) return res; } -static Json::Value toJson(dev::eth::Transaction const& _t) +static Json::Value toJson(dev::eth::Transaction const& _t, std::pair _location, BlockNumber _blockNumber) { Json::Value res; if (_t) @@ -92,6 +92,9 @@ static Json::Value toJson(dev::eth::Transaction const& _t) res["gasPrice"] = toJS(_t.gasPrice()); res["nonce"] = toJS(_t.nonce()); res["value"] = toJS(_t.value()); + res["blockHash"] = toJS(_location.first); + res["transactionIndex"] = toJS(_location.second); + res["blockNumber"] = toJS(_blockNumber); } return res; } @@ -105,8 +108,8 @@ static Json::Value toJson(dev::eth::BlockInfo const& _bi, UncleHashes const& _us for (h256 h: _us) res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); - for (Transaction const& t: _ts) - res["transactions"].append(toJson(t)); + for (unsigned i = 0; i < _ts.size(); i++) + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); } return res; } @@ -551,7 +554,8 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByHash(string const& _tran { try { - return toJson(client()->transaction(jsToFixed<32>(_transactionHash))); + h256 h = jsToFixed<32>(_transactionHash); + return toJson(client()->transaction(h), client()->transactionLocation(h), client()->numberFromHash(h)); } catch (...) { @@ -563,7 +567,10 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockHashAndIndex(string { try { - return toJson(client()->transaction(jsToFixed<32>(_blockHash), jsToInt(_transactionIndex))); + h256 bh = jsToFixed<32>(_blockHash); + unsigned ti = jsToInt(_transactionIndex); + Transaction t = client()->transaction(bh, ti); + return toJson(t, make_pair(bh, ti), client()->numberFromHash(bh)); } catch (...) { @@ -575,7 +582,10 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockNumberAndIndex(stri { try { - return toJson(client()->transaction(jsToBlockNumber(_blockNumber), jsToInt(_transactionIndex))); + BlockNumber bn = jsToBlockNumber(_blockNumber); + unsigned ti = jsToInt(_transactionIndex); + Transaction t = client()->transaction(bn, ti); + return toJson(t, make_pair(client()->hashFromNumber(bn), ti), bn); } catch (...) { From 6216b33775ee961ad3beabe54426961d95f1bbfa Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 10 Apr 2015 16:55:59 +0200 Subject: [PATCH 003/108] Allow mining without pow check --- libethereum/BlockChain.cpp | 4 ++-- libethereum/BlockChain.h | 2 +- libethereum/State.cpp | 10 +++++----- libethereum/State.h | 4 ++-- mix/MixClient.cpp | 3 +-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cb2d26eff..4df91e3d1 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -347,7 +347,7 @@ pair BlockChain::attemptImport(bytes const& _block, OverlayDB const } } -pair BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force) +pair BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force, bool _checkNonce) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -432,7 +432,7 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); //, bi.coinbaseAddress - auto tdIncrease = s.enactOn(&_block, bi, *this); + auto tdIncrease = s.enactOn(&_block, bi, *this, _checkNonce); BlockLogBlooms blb; BlockReceipts br; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 765e00b03..635399494 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -112,7 +112,7 @@ public: /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks); + std::pair import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks, bool _checkNonce = true); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5631ffe28..1a645ab67 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -274,7 +274,7 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi) +bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, bool _checkNonce) { bool ret = false; // BLOCK @@ -337,7 +337,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi) for (auto it = chain.rbegin(); it != chain.rend(); ++it) { auto b = _bc.block(*it); - enact(&b, _bc); + enact(&b, _bc, _checkNonce); cleanup(true); } } @@ -355,7 +355,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi) return ret; } -u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc) +u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, bool _checkNonce) { #if ETH_TIMED_ENACTMENTS boost::timer t; @@ -383,7 +383,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const t.restart(); #endif - sync(_bc, _bi.parentHash); + sync(_bc, _bi.parentHash, BlockInfo(), _checkNonce); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -392,7 +392,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc); + auto ret = enact(_block, _bc, _checkNonce); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); diff --git a/libethereum/State.h b/libethereum/State.h index 336c58b1a..e1699c256 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -306,11 +306,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo()); + bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), bool _checkNonce = true); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc); + u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, bool _checkNonce); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ff35a6d78..a68bfdf83 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -250,9 +250,8 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - while (!m_state.mine(100, true).completed) {} m_state.completeMine(); - bc().import(m_state.blockData(), m_stateDB); + bc().import(m_state.blockData(), m_stateDB, Aversion::AvoidOldBlocks, false); m_state.sync(bc()); m_startState = m_state; h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; From c7ef6a0d83f82fb06af9921d43f6cc68452279fd Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 10 Apr 2015 12:06:17 -0400 Subject: [PATCH 004/108] Log message instead of assert for invalid auth payload. --- libp2p/RLPxHandshake.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index e311c615a..d437ae839 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -93,7 +93,13 @@ void RLPXHandshake::readAuth() Secret sharedSecret; crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, sharedSecret); m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret ^ m_remoteNonce); - assert(sha3(m_remoteEphemeral) == *(h256*)hepubk.data()); + + if (sha3(m_remoteEphemeral) != *(h256*)hepubk.data()) + { + clog(NetConnect) << "p2p.connect.ingress auth failed (invalid: hash mismatch) for" << m_socket->remoteEndpoint(); + m_nextState = Error; + } + transition(); } else From 07b45657f7bb5ba6b1b1096df69639e1030257bf Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 10 Apr 2015 17:49:16 +0200 Subject: [PATCH 005/108] bool param to enum --- libethcore/Common.h | 11 +++++++++++ libethereum/BlockChain.cpp | 4 ++-- libethereum/BlockChain.h | 2 +- libethereum/State.cpp | 14 +++++++------- libethereum/State.h | 6 +++--- mix/MixClient.cpp | 2 +- 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index ec826d2d1..303adc739 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -96,5 +96,16 @@ enum class ImportResult BadChain }; +struct ImportRequirements +{ + using value = unsigned; + enum + { + ValidNonce = 1, + DontHave = 2, + Default = ValidNonce + }; +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 4df91e3d1..186448d41 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -347,7 +347,7 @@ pair BlockChain::attemptImport(bytes const& _block, OverlayDB const } } -pair BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force, bool _checkNonce) +pair BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force, ImportRequirements::value _ir) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -432,7 +432,7 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); //, bi.coinbaseAddress - auto tdIncrease = s.enactOn(&_block, bi, *this, _checkNonce); + auto tdIncrease = s.enactOn(&_block, bi, *this, _ir); BlockLogBlooms blb; BlockReceipts br; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 635399494..00f41ab0a 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -112,7 +112,7 @@ public: /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks, bool _checkNonce = true); + std::pair import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks, ImportRequirements::value _ir = ImportRequirements::Default); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1a645ab67..6ffd0bdad 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -274,7 +274,7 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, bool _checkNonce) +bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) { bool ret = false; // BLOCK @@ -337,7 +337,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, bool for (auto it = chain.rbegin(); it != chain.rend(); ++it) { auto b = _bc.block(*it); - enact(&b, _bc, _checkNonce); + enact(&b, _bc, _ir); cleanup(true); } } @@ -355,7 +355,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, bool return ret; } -u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, bool _checkNonce) +u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir) { #if ETH_TIMED_ENACTMENTS boost::timer t; @@ -383,7 +383,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const t.restart(); #endif - sync(_bc, _bi.parentHash, BlockInfo(), _checkNonce); + sync(_bc, _bi.parentHash, BlockInfo(), _ir); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -392,7 +392,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _checkNonce); + auto ret = enact(_block, _bc, _ir); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -538,11 +538,11 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga return ret; } -u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) +u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) { // m_currentBlock is assumed to be prepopulated and reset. - BlockInfo bi(_block, _checkNonce ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, ((_ir & (ImportRequirements::ValidNonce | ImportRequirements::DontHave)) == ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); #if !ETH_RELEASE assert(m_previousBlock.hash() == bi.parentHash); diff --git a/libethereum/State.h b/libethereum/State.h index e1699c256..d23347bcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -306,11 +306,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), bool _checkNonce = true); + bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, bool _checkNonce); + u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -338,7 +338,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce = true); + u256 enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index a68bfdf83..63fbbbf43 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -251,7 +251,7 @@ void MixClient::mine() WriteGuard l(x_state); m_state.commitToMine(bc()); m_state.completeMine(); - bc().import(m_state.blockData(), m_stateDB, Aversion::AvoidOldBlocks, false); + bc().import(m_state.blockData(), m_stateDB, Aversion::AvoidOldBlocks, ImportRequirements::ValidNonce | ImportRequirements::DontHave); m_state.sync(bc()); m_startState = m_state; h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; From 6714143a92b6a3531265c3195250150609442dc8 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 10 Apr 2015 21:37:24 +0200 Subject: [PATCH 006/108] fixed blockNumber in jsonrpc transaction --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index dae672f58..138d6a506 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -546,7 +546,8 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByHash(string const& _tran try { h256 h = jsToFixed<32>(_transactionHash); - return toJson(client()->transaction(h), client()->transactionLocation(h), client()->numberFromHash(h)); + auto l = client()->transactionLocation(h); + return toJson(client()->transaction(h), l, client()->numberFromHash(l.first)); } catch (...) { From 38e985e808ef28868d82a3af810062d4ef84c57a Mon Sep 17 00:00:00 2001 From: Alexandre Van de Sande Date: Fri, 10 Apr 2015 17:56:31 -0300 Subject: [PATCH 007/108] created a frame for the step action buttons --- mix/qml/Debugger.qml | 34 +++++----- mix/qml/StepActionImage.qml | 122 ++++++++++++++++++++++++++++++------ 2 files changed, 116 insertions(+), 40 deletions(-) diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index ef83ef390..3b8a87e8a 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -4,6 +4,7 @@ import QtQuick.Controls.Styles 1.1 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import Qt.labs.settings 1.0 +import QtGraphicalEffects 1.0 import "js/Debugger.js" as Debugger import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." @@ -231,9 +232,9 @@ Rectangle { id: playAction enabledStateImg: "qrc:/qml/img/play_button.png" disableStateImg: "qrc:/qml/img/play_button.png" + buttonLeft: true onClicked: projectModel.stateListModel.runState(transactionLog.selectedStateIndex) - width: 30 - height: 30 + width: 23 buttonShortcut: "Ctrl+Shift+F8" buttonTooltip: qsTr("Start Debugging") visible: true @@ -246,8 +247,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/stop_button2x.png" disableStateImg: "qrc:/qml/img/stop_button2x.png" onClicked: Debugger.init(null); - width: 30 - height: 30 + width: 23 buttonShortcut: "Ctrl+Shift+F9" buttonTooltip: qsTr("Stop Debugging") visible: true @@ -259,8 +259,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoutback.png" disableStateImg: "qrc:/qml/img/jumpoutbackdisabled.png" onClicked: Debugger.runBack() - width: 30 - height: 30 + width: 23 buttonShortcut: "Ctrl+Shift+F5" buttonTooltip: qsTr("Run Back") visible: false @@ -272,8 +271,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoutback.png" disableStateImg: "qrc:/qml/img/jumpoutbackdisabled.png" onClicked: Debugger.stepOutBack() - width: 30 - height: 30 + width: 23 buttonShortcut: "Ctrl+Shift+F11" buttonTooltip: qsTr("Step Out Back") } @@ -284,8 +282,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpintoback.png" disableStateImg: "qrc:/qml/img/jumpintobackdisabled.png" onClicked: Debugger.stepIntoBack() - width: 30 - height: 30 + width: 23 buttonShortcut: "Ctrl+F11" buttonTooltip: qsTr("Step Into Back") } @@ -296,8 +293,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoverback.png" disableStateImg: "qrc:/qml/img/jumpoverbackdisabled.png" onClicked: Debugger.stepOverBack() - width: 30 - height: 30 + width: 23 buttonShortcut: "Ctrl+F10" buttonTooltip: qsTr("Step Over Back") } @@ -308,8 +304,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoverforward.png" disableStateImg: "qrc:/qml/img/jumpoverforwarddisabled.png" onClicked: Debugger.stepOverForward() - width: 30 - height: 30 + width: 23 buttonShortcut: "F10" buttonTooltip: qsTr("Step Over Forward") } @@ -320,8 +315,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpintoforward.png" disableStateImg: "qrc:/qml/img/jumpintoforwarddisabled.png" onClicked: Debugger.stepIntoForward() - width: 30 - height: 30 + width: 23 buttonShortcut: "F11" buttonTooltip: qsTr("Step Into Forward") } @@ -332,10 +326,10 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoutforward.png" disableStateImg: "qrc:/qml/img/jumpoutforwarddisabled.png" onClicked: Debugger.stepOutForward() - width: 30 - height: 30 + width: 45 buttonShortcut: "Shift+F11" buttonTooltip: qsTr("Step Out Forward") + buttonRight: true } StepActionImage @@ -344,11 +338,11 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoutforward.png" disableStateImg: "qrc:/qml/img/jumpoutforwarddisabled.png" onClicked: Debugger.runForward() - width: 30 - height: 30 + width: 45 buttonShortcut: "Ctrl+F5" buttonTooltip: qsTr("Run Forward") visible: false + buttonRight: true } Rectangle { diff --git a/mix/qml/StepActionImage.qml b/mix/qml/StepActionImage.qml index 262c99def..a8c800b64 100644 --- a/mix/qml/StepActionImage.qml +++ b/mix/qml/StepActionImage.qml @@ -4,15 +4,22 @@ import QtQuick.Layouts 1.0 import QtQuick.Controls.Styles 1.1 + Rectangle { id: buttonActionContainer - color: "transparent" property string disableStateImg property string enabledStateImg property string buttonTooltip property string buttonShortcut + property bool buttonLeft + property bool buttonRight signal clicked + + color: "transparent" + width: 35 + height: 24 + function enabled(state) { buttonAction.enabled = state; @@ -22,29 +29,104 @@ Rectangle { debugImage.source = disableStateImg; } - Button - { - anchors.fill: parent - id: debugImg -/* iconSource: enabledStateImg -*/ action: buttonAction + Rectangle { + color: "#DCDADA" + width: 10 + height: 24 + radius: 4 + x: 0 + visible: buttonLeft + + Rectangle { + anchors { + left: parent.left + right: parent.right + top: parent.top + bottom: parent.bottom + bottomMargin:debugImg.pressed? 0 : 1; + topMargin:debugImg.pressed? 1 : 0; + } + color: "#FCFBFC" + radius: 3 + } } - Image { - id: debugImage - source: enabledStateImg - anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - width: 15 - height: 15 + Rectangle { + color: "#DCDADA" + width: 10 + height: 24 + radius: 4 + x: 25 + visible: buttonRight + + Rectangle { + anchors { + left: parent.left + right: parent.right + top: parent.top + bottom: parent.bottom + bottomMargin:debugImg.pressed? 0 : 1; + topMargin:debugImg.pressed? 1 : 0; + } + color: "#FCFBFC" + radius: 3 + } } - Action { - tooltip: buttonTooltip - id: buttonAction - shortcut: buttonShortcut - onTriggered: { - buttonActionContainer.clicked(); + + Rectangle { + id: contentRectangle + width: 25 + height: 24 + color: "#DCDADA" + x: 5 + + Rectangle { + anchors { + left: parent.left + right: parent.right + top: parent.top + bottom: parent.bottom + bottomMargin:debugImg.pressed? 0 : 1; + topMargin:debugImg.pressed? 1 : 0; + } + color: "#FCFBFC" + + Image { + id: debugImage + source: enabledStateImg + anchors.centerIn: parent + anchors.topMargin: debugImg.pressed? 1 : 0; + + fillMode: Image.PreserveAspectFit + width: 15 + height: 15 + } + + } + + + Button { + anchors.fill: parent + id: debugImg + action: buttonAction + style: Rectangle { + color: "transparent" + } + } + + + Action { + tooltip: buttonTooltip + id: buttonAction + shortcut: buttonShortcut + onTriggered: { + // contentRectangle.anchors.bottomMargin = 0 + // contentRectangle.anchors.topMargin = 1 + buttonActionContainer.clicked(); + } } } + + } From 89dbad3bf85f854657de05e543be13a7ed4fd09d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Apr 2015 23:12:51 +0200 Subject: [PATCH 008/108] Working GPU miner. --- libethcore/ProofOfWork.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index e24b2087c..a97baca94 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -207,10 +207,10 @@ std::pair EthashCL::mine(BlockInfo const& _header, unsi { m_hook->abort(); static std::random_device s_eng; - uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng)); auto hh = _header.headerHash(WithoutNonce); - cdebug << "Mining with headerhash" << hh << "from nonce" << m_last << "with boundary" << _header.boundary(); - m_miner->search(hh.data(), tryNonce, *m_hook); + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_header.boundary() >> 192); + cdebug << "Mining with headerhash" << hh << "from nonce" << m_last << "with boundary" << _header.boundary() << " (" << upper64OfBoundary << ")"; + m_miner->search(hh.data(), upper64OfBoundary, *m_hook); } m_lastHeader = _header; From 6e78287401e219750e260512cdf385890a95ee46 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Apr 2015 00:45:21 +0200 Subject: [PATCH 009/108] Ability to switch GPU/CPU mining on the fly. --- CMakeLists.txt | 2 ++ alethzero/Main.ui | 18 +++++------ alethzero/MainWin.cpp | 3 ++ eth/main.cpp | 4 --- libethcore/ProofOfWork.cpp | 20 +++--------- libethcore/ProofOfWork.h | 34 ++++++++++----------- libethereum/Client.cpp | 16 +++++++--- libethereum/Client.h | 20 ++++++------ libethereum/ClientBase.h | 3 +- libethereum/Interface.h | 4 ++- libethereum/Miner.cpp | 4 ++- libethereum/Miner.h | 13 ++++---- libethereum/State.cpp | 25 ++------------- libethereum/State.h | 22 +++++++++++-- libweb3jsonrpc/WebThreeStubServerBase.cpp | 5 +++ libweb3jsonrpc/WebThreeStubServerBase.h | 1 + libweb3jsonrpc/abstractwebthreestubserver.h | 7 +++++ libweb3jsonrpc/spec.json | 5 +-- mix/MixClient.cpp | 10 ++++-- mix/MixClient.h | 3 +- test/blockchain.cpp | 7 +++-- test/stateOriginal.cpp | 5 +-- test/webthreestubclient.h | 10 ++++++ 23 files changed, 138 insertions(+), 103 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 100ef9139..e6a906b59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,8 @@ function(configureProject) if (GUI) add_definitions(-DETH_GUI) endif() + + add_definitions(-DETH_TRUE) endfunction() set(CPPETHEREUM 1) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 6c01f57f9..3f3d1e237 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -150,6 +150,7 @@ &Tools + @@ -176,7 +177,6 @@ - @@ -1608,14 +1608,6 @@ font-size: 14pt &Enable LLL Optimizer - - - true - - - &Reserved Debug 1 - - true @@ -1679,6 +1671,14 @@ font-size: 14pt &NatSpec Enabled + + + true + + + &GPU Mining + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index bbacaf539..374829a61 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -707,6 +707,7 @@ void Main::writeSettings() s.setValue("upnp", ui->upnp->isChecked()); s.setValue("forceAddress", ui->forcePublicIP->text()); s.setValue("forceMining", ui->forceMining->isChecked()); + s.setValue("turboMining", ui->turboMining->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked()); s.setValue("natSpec", ui->natSpec->isChecked()); s.setValue("showAll", ui->showAll->isChecked()); @@ -777,6 +778,8 @@ void Main::readSettings(bool _skipGeometry) ui->dropPeers->setChecked(false); ui->forceMining->setChecked(s.value("forceMining", false).toBool()); on_forceMining_triggered(); + ui->turboMining->setChecked(s.value("turboMining", false).toBool()); + on_turboMining_triggered(); ui->paranoia->setChecked(s.value("paranoia", false).toBool()); ui->natSpec->setChecked(s.value("natSpec", true).toBool()); ui->showAll->setChecked(s.value("showAll", false).toBool()); diff --git a/eth/main.cpp b/eth/main.cpp index c83332c20..e9af192f9 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -273,7 +273,6 @@ int main(int argc, char** argv) unsigned mining = ~(unsigned)0; int miners = -1; bool forceMining = false; - bool turboMining = false; KeyPair us = KeyPair::create(); Address coinbase = us.address(); @@ -466,8 +465,6 @@ int main(int argc, char** argv) bootstrap = true; else if (arg == "-f" || arg == "--force-mining") forceMining = true; - else if (arg == "-T" || arg == "--turbo-mining") - turboMining = true; else if (arg == "-i" || arg == "--interactive") interactive = true; #if ETH_JSONRPC @@ -632,7 +629,6 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); - c->setTurboMining(turboMining); c->setAddress(coinbase); } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index a97baca94..f7cf4944b 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -45,12 +45,12 @@ namespace dev namespace eth { -bool EthashCPU::verify(BlockInfo const& _header) +bool EthashPoW::verify(BlockInfo const& _header) { return Ethasher::verify(_header); } -std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo) +std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) { Ethasher::Miner m(_header); @@ -67,8 +67,6 @@ std::pair EthashCPU::mine(BlockInfo const& _header, // // evaluate until we run out of time auto startTime = std::chrono::steady_clock::now(); - if (!_turbo) - std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100)); double best = 1e99; // high enough to be effectively infinity :) Proof result; unsigned hashCount = 0; @@ -102,7 +100,7 @@ std::pair EthashCPU::mine(BlockInfo const& _header, return ret; } -#if ETH_ETHASHCL +#if ETH_ETHASHCL || !ETH_TRUE /* class ethash_cl_miner @@ -186,12 +184,7 @@ EthashCL::~EthashCL() { } -bool EthashCL::verify(BlockInfo const& _header) -{ - return Ethasher::verify(_header); -} - -std::pair EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool, bool) +std::pair EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool) { if (!m_lastHeader || m_lastHeader.seedHash() != _header.seedHash()) { @@ -201,7 +194,7 @@ std::pair EthashCL::mine(BlockInfo const& _header, unsi auto cb = [&](void* d) { Ethasher::get()->readFull(_header, d); }; - m_miner->init(Ethasher::params(_header), cb); + m_miner->init(Ethasher::params(_header), cb, 32); } if (m_lastHeader != _header) { @@ -209,7 +202,6 @@ std::pair EthashCL::mine(BlockInfo const& _header, unsi static std::random_device s_eng; auto hh = _header.headerHash(WithoutNonce); uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_header.boundary() >> 192); - cdebug << "Mining with headerhash" << hh << "from nonce" << m_last << "with boundary" << _header.boundary() << " (" << upper64OfBoundary << ")"; m_miner->search(hh.data(), upper64OfBoundary, *m_hook); } m_lastHeader = _header; @@ -221,11 +213,9 @@ std::pair EthashCL::mine(BlockInfo const& _header, unsi for (auto const& n: found) { auto result = Ethasher::eval(_header, n); - cdebug << "Got nonce " << n << "gives result" << result.value; if (result.value < _header.boundary()) return std::make_pair(MineInfo(true), EthashCL::Proof{n, result.mixHash}); } - assert(false); } return std::make_pair(MineInfo(false), EthashCL::Proof()); } diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 48d52049a..2e04e842c 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -51,7 +51,7 @@ struct MineInfo bool completed = false; }; -class EthashCPU +class EthashPoW { public: struct Proof @@ -61,31 +61,32 @@ public: }; static bool verify(BlockInfo const& _header); - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false); static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + virtual unsigned defaultTimeout() const { return 100; } + virtual std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; +}; + +class EthashCPU: public EthashPoW +{ +public: + std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + protected: Nonce m_last; }; -#if ETH_ETHASHCL +#if ETH_ETHASHCL || !ETH_TRUE class EthashCLHook; -class EthashCL +class EthashCL: public EthashPoW { public: - struct Proof - { - Nonce nonce; - h256 mixHash; - }; - EthashCL(); ~EthashCL(); - static bool verify(BlockInfo const& _header); - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false); - static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + unsigned defaultTimeout() const override { return 500; } protected: Nonce m_last; @@ -107,8 +108,9 @@ public: using Proof = Nonce; static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; } - inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false); + inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; } + unsigned defaultTimeout() const { return 100; } protected: Nonce m_last; @@ -125,7 +127,7 @@ using SHA3ProofOfWork = ProofOfWorkEngine; using ProofOfWork = Ethash; template -std::pair::Proof> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo) +std::pair::Proof> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) { auto headerHashWithoutNonce = _header.headerHash(WithoutNonce); auto difficulty = _header.difficulty; @@ -142,8 +144,6 @@ std::pair::Proof> ProofOfWorkEng // // evaluate until we run out of time auto startTime = std::chrono::steady_clock::now(); - if (!_turbo) - std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100)); double best = 1e99; // high enough to be effectively infinity :) ProofOfWorkEngine::Proof solution; unsigned h = 0; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 8c2d2b4fa..4b197797f 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -345,11 +345,10 @@ void Client::setForceMining(bool _enable) void Client::setMiningThreads(unsigned _threads) { stopMining(); -#if ETH_ETHASHCL - (void)_threads; - unsigned t = 1; -#else auto t = _threads ? _threads : thread::hardware_concurrency(); +#if ETH_ETHASHCL || !ETH_TRUE + if (m_turboMining) + t = 1; #endif WriteGuard l(x_localMiners); m_localMiners.clear(); @@ -368,6 +367,15 @@ MineProgress Client::miningProgress() const return ret; } +uint64_t Client::hashrate() const +{ + uint64_t ret; + ReadGuard l(x_localMiners); + for (LocalMiner const& m: m_localMiners) + ret += m.miningProgress().hashes / m.miningProgress().ms; + return ret / 1000; +} + std::list Client::miningHistory() { std::list ret; diff --git a/libethereum/Client.h b/libethereum/Client.h index 57fe0d9de..cc51f9747 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -188,25 +188,27 @@ public: bool forceMining() const { return m_forceMining; } /// Enable/disable forcing of mining to happen, even without transactions. void setForceMining(bool _enable); - /// Are we mining as fast as we can? + /// Are we allowed to GPU mine? bool turboMining() const { return m_turboMining; } - /// Enable/disable fast mining. - void setTurboMining(bool _enable = true) { m_turboMining = _enable; } + /// Enable/disable GPU mining. + void setTurboMining(bool _enable = true) { bool was = isMining(); stopMining(); m_turboMining = _enable; setMiningThreads(0); if (was) startMining(); } /// Stops mining and sets the number of mining threads (0 for automatic). - virtual void setMiningThreads(unsigned _threads = 0); + void setMiningThreads(unsigned _threads = 0) override; /// Get the effective number of mining threads. - virtual unsigned miningThreads() const { ReadGuard l(x_localMiners); return m_localMiners.size(); } + unsigned miningThreads() const override { ReadGuard l(x_localMiners); return m_localMiners.size(); } /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread - virtual void startMining() { startWorking(); { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.start(); } } + void startMining() override { startWorking(); { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.start(); } } /// Stop mining. /// NOT thread-safe - virtual void stopMining() { { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.stop(); } } + void stopMining() override { { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.stop(); } } /// Are we mining now? - virtual bool isMining() { { ReadGuard l(x_localMiners); if (!m_localMiners.empty() && m_localMiners[0].isRunning()) return true; } return false; } + bool isMining() const override { { ReadGuard l(x_localMiners); if (!m_localMiners.empty() && m_localMiners[0].isRunning()) return true; } return false; } + /// Are we mining now? + uint64_t hashrate() const override; /// Check the progress of the mining. - virtual MineProgress miningProgress() const; + MineProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 00bb02ed4..ddfbf1176 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -146,7 +146,8 @@ public: virtual unsigned miningThreads() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningThreads")); } virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); } virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); } - virtual bool isMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); } + virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); } + virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::hashrate")); } virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); } virtual std::pair getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); } virtual bool submitWork(eth::ProofOfWork::Proof const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } diff --git a/libethereum/Interface.h b/libethereum/Interface.h index ac41b0ec1..02833743e 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -183,7 +183,9 @@ public: /// NOT thread-safe virtual void stopMining() = 0; /// Are we mining now? - virtual bool isMining() = 0; + virtual bool isMining() const = 0; + /// Current hash rate. + virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). virtual std::pair getWork() = 0; diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp index 08bc426dc..b3a65f081 100644 --- a/libethereum/Miner.cpp +++ b/libethereum/Miner.cpp @@ -34,12 +34,14 @@ LocalMiner::LocalMiner(MinerHost* _host, unsigned _id): AsyncMiner(_host, _id), Worker("miner-" + toString(_id)) { + m_pow.reset(_host->turbo() ? new Ethash : (Ethash*)new EthashCPU); } void LocalMiner::setup(MinerHost* _host, unsigned _id) { AsyncMiner::setup(_host, _id); setName("miner-" + toString(m_id)); + m_pow.reset(_host->turbo() ? new Ethash : (Ethash*)new EthashCPU); } void LocalMiner::doWork() @@ -66,7 +68,7 @@ void LocalMiner::doWork() if (m_miningStatus == Mining) { // Mine for a while. - MineInfo mineInfo = m_mineState.mine(100, m_host->turbo()); + MineInfo mineInfo = m_mineState.mine(m_pow.get()); { Guard l(x_mineInfo); diff --git a/libethereum/Miner.h b/libethereum/Miner.h index 7c4f7e767..8c2fc4bb4 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -60,8 +60,8 @@ public: virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. virtual void onProgressed() {} ///< Called once some progress has been made. virtual void onComplete() {} ///< Called once a block is found. - virtual bool turbo() const = 0; ///< @returns true iff the Miner should mine as fast as possible. virtual bool force() const = 0; ///< @returns true iff the Miner should mine regardless of the number of transactions. + virtual bool turbo() const = 0; ///< @returns true iff the Miner should use GPU if possible. }; class Miner @@ -93,7 +93,7 @@ public: virtual void stop() {} /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). - virtual bool isRunning() { return false; } + virtual bool isRunning() const { return false; } protected: MinerHost* m_host = nullptr; ///< Our host. @@ -122,10 +122,10 @@ public: LocalMiner(MinerHost* _host, unsigned _id = 0); /// Move-constructor. - LocalMiner(LocalMiner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); } + LocalMiner(LocalMiner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); std::swap(m_pow, _m.m_pow); } /// Move-assignment. - LocalMiner& operator=(LocalMiner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); return *this; } + LocalMiner& operator=(LocalMiner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); std::swap(m_pow, _m.m_pow); return *this; } /// Destructor. Stops miner. ~LocalMiner() { stop(); } @@ -143,7 +143,7 @@ public: virtual void noteStateChange() override { m_miningStatus = Preparing; } /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). - bool isRunning() { return isWorking(); } + bool isRunning() const override { return isWorking(); } /// @returns true if mining is complete. virtual bool isComplete() const override { return m_miningStatus == Mined; } @@ -167,8 +167,9 @@ private: enum MiningStatus { Waiting, Preparing, Mining, Mined, Stopping, Stopped }; MiningStatus m_miningStatus = Waiting; ///< TODO: consider mutex/atomic variable. State m_mineState; ///< The state on which we are mining, generally equivalent to m_postMine. + std::unique_ptr m_pow; ///< Our miner. - mutable std::mutex x_mineInfo; ///< Lock for the mining progress & history. + mutable Mutex x_mineInfo; ///< Lock for the mining progress & history. MineProgress m_mineProgress; ///< What's our progress? std::list m_mineHistory; ///< What the history of our mining? }; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5631ffe28..c1beee787 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -856,33 +856,12 @@ void State::commitToMine(BlockChain const& _bc) m_committedToMine = true; } -MineInfo State::mine(unsigned _msTimeout, bool _turbo) -{ - // Update difficulty according to timestamp. - m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); - - MineInfo ret; - // TODO: Miner class that keeps dagger between mine calls (or just non-polling mining). - ProofOfWork::Proof r; - tie(ret, r) = m_pow.mine(m_currentBlock, _msTimeout, true, _turbo); - - if (!ret.completed) - m_currentBytes.clear(); - else - { - ProofOfWork::assignResult(r, m_currentBlock); - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock); - } - - return ret; -} - bool State::completeMine(ProofOfWork::Proof const& _nonce) { ProofOfWork::assignResult(_nonce, m_currentBlock); - if (!m_pow.verify(m_currentBlock)) - return false; +// if (!m_pow.verify(m_currentBlock)) +// return false; cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock); diff --git a/libethereum/State.h b/libethereum/State.h index 336c58b1a..1b71038b4 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -168,7 +168,25 @@ public: /// This function is thread-safe. You can safely have other interactions with this object while it is happening. /// @param _msTimeout Timeout before return in milliseconds. /// @returns Information on the mining. - MineInfo mine(unsigned _msTimeout = 1000, bool _turbo = false); + template MineInfo mine(ProofOfWork* _pow) + { + // Update difficulty according to timestamp. + m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); + + MineInfo ret; + typename ProofOfWork::Proof r; + std::tie(ret, r) = _pow->mine(m_currentBlock, _pow->defaultTimeout(), true); + + if (!ret.completed) + m_currentBytes.clear(); + else + { + ProofOfWork::assignResult(r, m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock); + } + + return ret; + } /** Commit to DB and build the final block if the previous call to mine()'s result is completion. * Typically looks like: @@ -371,8 +389,6 @@ private: Address m_ourAddress; ///< Our address (i.e. the address to which fees go). - ProofOfWork m_pow; ///< The PoW mining class. - u256 m_blockReward; static std::string c_defaultPath; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index c86274b15..04bbe7345 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -296,6 +296,11 @@ string WebThreeStubServerBase::eth_coinbase() return toJS(client()->address()); } +string WebThreeStubServerBase::eth_hashrate() +{ + return toJS(client()->hashrate()); +} + bool WebThreeStubServerBase::eth_mining() { return client()->isMining(); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index b57a54c87..22a31a762 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -78,6 +78,7 @@ public: virtual bool net_listening(); virtual std::string eth_protocolVersion(); + virtual std::string eth_hashrate(); virtual std::string eth_coinbase(); virtual bool eth_mining(); virtual std::string eth_gasPrice(); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 6cc5de3e6..0860ecaee 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -18,6 +18,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("net_peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::net_peerCountI); this->bindAndAddMethod(jsonrpc::Procedure("net_listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::net_listeningI); this->bindAndAddMethod(jsonrpc::Procedure("eth_protocolVersion", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_protocolVersionI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_hashrate", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_hashrateI); this->bindAndAddMethod(jsonrpc::Procedure("eth_coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_coinbaseI); this->bindAndAddMethod(jsonrpc::Procedure("eth_mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_miningI); this->bindAndAddMethod(jsonrpc::Procedure("eth_gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_gasPriceI); @@ -98,6 +99,11 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_protocolVersion(); } + inline virtual void eth_hashrateI(const Json::Value &request, Json::Value &response) + { + (void)request; + response = this->eth_hashrate(); + } inline virtual void eth_coinbaseI(const Json::Value &request, Json::Value &response) { (void)request; @@ -309,6 +315,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer getWork() override { return std::pair(); } bool submitWork(eth::ProofOfWork::Proof const&) override { return false; } diff --git a/test/blockchain.cpp b/test/blockchain.cpp index ab01df5a5..15cda8037 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -192,7 +192,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) state.sync(bc, txs, gp); state.commitToMine(bc); MineInfo info; - for (info.completed = false; !info.completed; info = state.mine()) {} + ProofOfWork pow; + for (info.completed = false; !info.completed; info = state.mine(&pow)) {} state.completeMine(); } catch (Exception const& _e) @@ -577,7 +578,7 @@ void overwriteBlockHeader(BlockInfo& _currentBlockHeader, mObject& _blObj) std::pair ret; while (!ProofOfWork::verify(_currentBlockHeader)) { - ret = pow.mine(_currentBlockHeader, 1000, true, true); + ret = pow.mine(_currentBlockHeader, 1000, true); Ethash::assignResult(ret.second, _currentBlockHeader); } } @@ -623,7 +624,7 @@ void updatePoW(BlockInfo& _bi) std::pair ret; while (!ProofOfWork::verify(_bi)) { - ret = pow.mine(_bi, 10000, true, true); + ret = pow.mine(_bi, 10000, true); Ethash::assignResult(ret.second, _bi); } _bi.noteDirty(); diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp index 572e84dcf..40f759434 100644 --- a/test/stateOriginal.cpp +++ b/test/stateOriginal.cpp @@ -68,7 +68,8 @@ BOOST_AUTO_TEST_CASE(Complex) // Mine to get some ether! s.commitToMine(bc); - while (!s.mine(100, true).completed) {} + ProofOfWork pow; + while (!s.mine(&pow).completed) {} s.completeMine(); bc.attemptImport(s.blockData(), stateDB); @@ -88,7 +89,7 @@ BOOST_AUTO_TEST_CASE(Complex) // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - while (!s.mine(100, true).completed) {} + while (!s.mine(&pow).completed) {} s.completeMine(); bc.attemptImport(s.blockData(), stateDB); diff --git a/test/webthreestubclient.h b/test/webthreestubclient.h index a460ddda4..c1fdc3411 100644 --- a/test/webthreestubclient.h +++ b/test/webthreestubclient.h @@ -72,6 +72,16 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + std::string eth_hashrate() throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p = Json::nullValue; + Json::Value result = this->CallMethod("eth_hashrate",p); + if (result.isString()) + return result.asString(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } std::string eth_coinbase() throw (jsonrpc::JsonRpcException) { Json::Value p; From 08a913921b2c0c53fa67002e79278b3f862eddc8 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 10 Apr 2015 19:51:16 -0400 Subject: [PATCH 010/108] Drop unsolicited neighbours packets. Resolves #1556. --- libp2p/NodeTable.cpp | 15 +++++++++++++++ libp2p/NodeTable.h | 8 ++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 2837e8f07..6c2253344 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -178,6 +178,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrendpoint.udp, _node); p.sign(m_secret); + m_findNodeTimout.push_back(make_pair(_node, chrono::steady_clock::now())); m_socketPointer->send(p); } @@ -457,6 +458,20 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case Neighbours::type: { + bool expected = false; + m_findNodeTimout.remove_if([&](NodeIdTimePoint const& t) + { + if (t.first == nodeid && chrono::steady_clock::now() - t.second < c_reqTimeout) + expected = true; + return t.first == nodeid; + }); + + if (!expected) + { + clog(NetConnect) << "Dropping unsolicited Neighbours packet from " << _from.address(); + break; + } + Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); for (auto n: in.nodes) addNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port), bi::tcp::endpoint(bi::address::from_string(n.ipAddress), n.port)); diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 4aee93e99..fe8f87a66 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -131,8 +131,9 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this { friend std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable); using NodeSocket = UDPSocket; - using TimePoint = std::chrono::steady_clock::time_point; - using EvictionTimeout = std::pair, NodeId>; ///< First NodeId may be evicted and replaced with second NodeId. + using TimePoint = std::chrono::steady_clock::time_point; ///< Steady time point. + using NodeIdTimePoint = std::pair; + using EvictionTimeout = std::pair; ///< First NodeId (NodeIdTimePoint) may be evicted and replaced with second NodeId. public: /// Constructor requiring host for I/O, credentials, and IP Address and port to listen on. @@ -271,6 +272,9 @@ private: Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required. std::map m_pubkDiscoverPings; ///< List of pending pings where node entry wasn't created due to unkown pubk. + Mutex x_findNodeTimeout; + std::list m_findNodeTimout; ///< Timeouts for pending Ping and FindNode requests. + ba::io_service& m_io; ///< Used by bucket refresh timer. std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. NodeSocket* m_socketPointer; ///< Set to m_socket.get(). Socket is created in constructor and disconnected in destructor to ensure access to pointer is safe. From 6edb3840d798101d026fe5b58ee9ce6ac8f975c5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Apr 2015 15:52:36 +0200 Subject: [PATCH 011/108] Some early refactoring to support async miners better. --- exp/main.cpp | 2 +- libethcore/ProofOfWork.cpp | 30 ++++++--- libethcore/ProofOfWork.h | 22 +++---- libethereum/Client.cpp | 2 +- libethereum/Client.h | 4 +- libethereum/ClientBase.h | 2 +- libethereum/Interface.h | 2 +- libethereum/Miner.cpp | 6 +- libethereum/Miner.h | 77 +++++++++++++++++++++++ libethereum/State.cpp | 2 +- libethereum/State.h | 4 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- mix/MixClient.h | 2 +- test/blockchain.cpp | 4 +- 14 files changed, 123 insertions(+), 38 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 48562f80e..88f1075a9 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -114,7 +114,7 @@ int main() BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << (h256)u256((bigint(1) << 256) / genesis.difficulty); - std::pair r; + std::pair r; while (!r.first.completed) r = ecl.mine(genesis, 1000); cdebug << r.second.mixHash << r.second.nonce; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index f7cf4944b..ffa787e3e 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -50,16 +50,16 @@ bool EthashPoW::verify(BlockInfo const& _header) return Ethasher::verify(_header); } -std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) +std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) { Ethasher::Miner m(_header); - std::pair ret; + std::pair ret; auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng)); - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); + h256 boundary = _header.boundary(); ret.first.requirement = log2((double)(u256)boundary); // 2^ 0 32 64 128 256 @@ -68,7 +68,7 @@ std::pair EthashCPU::mine(BlockInfo const& _header, // evaluate until we run out of time auto startTime = std::chrono::steady_clock::now(); double best = 1e99; // high enough to be effectively infinity :) - Proof result; + Solution result; unsigned hashCount = 0; for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) { @@ -128,7 +128,7 @@ struct EthashCLHook: public ethash_cl_miner::search_hook { if (m_aborted) return; - cdebug << "Attempting to abort"; +// cdebug << "Attempting to abort"; m_abort = true; for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) std::this_thread::sleep_for(chrono::milliseconds(30)); @@ -148,14 +148,14 @@ protected: for (unsigned i = 0; i < _count; ++i) m_found.push_back((Nonce)(u64)_nonces[i]); m_aborted = true; - cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); +// cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); return true; } virtual bool searched(uint64_t _startNonce, uint32_t _count) override { Guard l(x_all); - cdebug << "Searched" << _count << "from" << _startNonce; +// cdebug << "Searched" << _count << "from" << _startNonce; m_total += _count; m_last = _startNonce + _count; if (m_abort) @@ -184,7 +184,7 @@ EthashCL::~EthashCL() { } -std::pair EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool) +std::pair EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool) { if (!m_lastHeader || m_lastHeader.seedHash() != _header.seedHash()) { @@ -206,7 +206,14 @@ std::pair EthashCL::mine(BlockInfo const& _header, unsi } m_lastHeader = _header; + MineInfo mi; + Solution proof; + mi.requirement = log2((double)(u256)_header.boundary()); + mi.best = 0; + std::this_thread::sleep_for(chrono::milliseconds(_msTimeout)); + + mi.hashes += m_hook->fetchTotal(); auto found = m_hook->fetchFound(); if (!found.empty()) { @@ -214,10 +221,13 @@ std::pair EthashCL::mine(BlockInfo const& _header, unsi { auto result = Ethasher::eval(_header, n); if (result.value < _header.boundary()) - return std::make_pair(MineInfo(true), EthashCL::Proof{n, result.mixHash}); + { + mi.completed = true; + proof = Solution{n, result.mixHash}; + } } } - return std::make_pair(MineInfo(false), EthashCL::Proof()); + return std::make_pair(mi, proof); } #endif diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 2e04e842c..bd8ab58db 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -54,23 +54,23 @@ struct MineInfo class EthashPoW { public: - struct Proof + struct Solution { Nonce nonce; h256 mixHash; }; static bool verify(BlockInfo const& _header); - static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } virtual unsigned defaultTimeout() const { return 100; } - virtual std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; + virtual std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; }; class EthashCPU: public EthashPoW { public: - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; protected: Nonce m_last; @@ -85,7 +85,7 @@ public: EthashCL(); ~EthashCL(); - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; unsigned defaultTimeout() const override { return 500; } protected: @@ -105,11 +105,11 @@ template class ProofOfWorkEngine: public Evaluator { public: - using Proof = Nonce; + using Solution = Nonce; static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; } - inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); - static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; } + inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); + static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r; } unsigned defaultTimeout() const { return 100; } protected: @@ -127,7 +127,7 @@ using SHA3ProofOfWork = ProofOfWorkEngine; using ProofOfWork = Ethash; template -std::pair::Proof> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) +std::pair::Solution> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) { auto headerHashWithoutNonce = _header.headerHash(WithoutNonce); auto difficulty = _header.difficulty; @@ -145,11 +145,11 @@ std::pair::Proof> ProofOfWorkEng // evaluate until we run out of time auto startTime = std::chrono::steady_clock::now(); double best = 1e99; // high enough to be effectively infinity :) - ProofOfWorkEngine::Proof solution; + ProofOfWorkEngine::Solution solution; unsigned h = 0; for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++) { - solution = (ProofOfWorkEngine::Proof)s; + solution = (ProofOfWorkEngine::Solution)s; auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution); best = std::min(best, log2((double)e)); if (e <= d) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 4b197797f..223384c3a 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -452,7 +452,7 @@ pair Client::getWork() return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty()); } -bool Client::submitWork(ProofOfWork::Proof const& _proof) +bool Client::submitWork(ProofOfWork::Solution const& _proof) { Guard l(x_remoteMiner); return m_remoteMiner.submitWork(_proof); diff --git a/libethereum/Client.h b/libethereum/Client.h index cc51f9747..ec852afd2 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -82,7 +82,7 @@ public: h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); } u256 const& difficulty() const { return m_state.info().difficulty; } - bool submitWork(ProofOfWork::Proof const& _result) { return (m_isComplete = m_state.completeMine(_result)); } + bool submitWork(ProofOfWork::Solution const& _result) { return (m_isComplete = m_state.completeMine(_result)); } virtual bool isComplete() const override { return m_isComplete; } virtual bytes const& blockData() const { return m_state.blockData(); } @@ -216,7 +216,7 @@ public: /// nonce (the 'work hash') and the difficulty to be met. virtual std::pair getWork() override; /// Submit the proof for the proof-of-work. - virtual bool submitWork(ProofOfWork::Proof const& _proof) override; + virtual bool submitWork(ProofOfWork::Solution const& _proof) override; // Debug stuff: diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index ddfbf1176..ae6d27578 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -150,7 +150,7 @@ public: virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::hashrate")); } virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); } virtual std::pair getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); } - virtual bool submitWork(eth::ProofOfWork::Proof const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } + virtual bool submitWork(eth::ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 02833743e..cf2e7f5ea 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -190,7 +190,7 @@ public: /// Get hash of the current block to be mined minus the nonce (the 'work hash'). virtual std::pair getWork() = 0; /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Proof const& _proof) = 0; + virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; /// Check the progress of the mining. virtual MineProgress miningProgress() const = 0; diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp index b3a65f081..dc3d9bd9e 100644 --- a/libethereum/Miner.cpp +++ b/libethereum/Miner.cpp @@ -30,11 +30,9 @@ using namespace dev::eth; Miner::~Miner() {} -LocalMiner::LocalMiner(MinerHost* _host, unsigned _id): - AsyncMiner(_host, _id), - Worker("miner-" + toString(_id)) +LocalMiner::LocalMiner(MinerHost* _host, unsigned _id) { - m_pow.reset(_host->turbo() ? new Ethash : (Ethash*)new EthashCPU); + setup(_host, _id); } void LocalMiner::setup(MinerHost* _host, unsigned _id) diff --git a/libethereum/Miner.h b/libethereum/Miner.h index 8c2fc4bb4..86d103db5 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -36,6 +36,15 @@ namespace dev namespace eth { +struct WorkPackage +{ + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; +}; + +static const WorkPackage NullWorkPackage; + /** * @brief Describes the progress of a mining operation. */ @@ -57,6 +66,10 @@ struct MineProgress class MinerHost { public: + // ============================= NEW API ============================= + virtual WorkPackage const& getWork() const { return NullWorkPackage; } + + // ============================= OLD API ============================= virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. virtual void onProgressed() {} ///< Called once some progress has been made. virtual void onComplete() {} ///< Called once a block is found. @@ -174,5 +187,69 @@ private: std::list m_mineHistory; ///< What the history of our mining? }; +/** + * @brief A collective of Miners. + * Miners ask for work, then submit proofs + * @threadsafe + */ +class Farm: public MinerHost +{ +public: + /** + * @brief Sets the current mining mission. + * @param _bi The block (header) we wish to be mining. + */ + void setWork(BlockInfo const& _bi); + + /** + * @brief (Re)start miners for CPU only. + * @returns true if started properly. + */ + bool startCPU(); + + /** + * @brief (Re)start miners for GPU only. + * @returns true if started properly. + */ + bool startGPU(); + + /** + * @brief Stop all mining activities. + */ + void stop(); + + /** + * @brief Get information on the progress of mining this work package. + * @return The progress with mining so far. + */ + MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } + +protected: + /** + * @brief Called by a Miner to retrieve a work package. Reimplemented from MinerHost. + * @return The work package to solve. + */ + virtual WorkPackage const& getWork() const override { ReadGuard l(x_work); return m_work; } + + /** + * @brief Called from a Miner to note a WorkPackage has a solution. + * @param _p The solution. + * @param _wp The WorkPackage that the Solution is for. + * @return true iff the solution was good (implying that mining should be . + */ + virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; + +private: + mutable SharedMutex x_miners; + std::vector> m_miners; + + mutable SharedMutex x_progress; + MineProgress m_progress; + + mutable SharedMutex x_work; + WorkPackage m_work; +}; + + } } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c1beee787..6e94a3406 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -856,7 +856,7 @@ void State::commitToMine(BlockChain const& _bc) m_committedToMine = true; } -bool State::completeMine(ProofOfWork::Proof const& _nonce) +bool State::completeMine(ProofOfWork::Solution const& _nonce) { ProofOfWork::assignResult(_nonce, m_currentBlock); diff --git a/libethereum/State.h b/libethereum/State.h index 1b71038b4..b327378a1 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -162,7 +162,7 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff the given nonce is a proof-of-work for this State's block. - bool completeMine(ProofOfWork::Proof const& _result); + bool completeMine(ProofOfWork::Solution const& _result); /// Attempt to find valid nonce for block that this state represents. /// This function is thread-safe. You can safely have other interactions with this object while it is happening. @@ -174,7 +174,7 @@ public: m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); MineInfo ret; - typename ProofOfWork::Proof r; + typename ProofOfWork::Solution r; std::tie(ret, r) = _pow->mine(m_currentBlock, _pow->defaultTimeout(), true); if (!ret.completed) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 04bbe7345..e987e64cc 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -767,7 +767,7 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const& { try { - return client()->submitWork(ProofOfWork::Proof{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); + return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); } catch (...) { diff --git a/mix/MixClient.h b/mix/MixClient.h index a9ab30048..a5ecbf465 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -71,7 +71,7 @@ public: uint64_t hashrate() const override; eth::MineProgress miningProgress() const override; std::pair getWork() override { return std::pair(); } - bool submitWork(eth::ProofOfWork::Proof const&) override { return false; } + bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } virtual void flushTransactions() override {} /// @returns the last mined block information diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 15cda8037..6d7bc97ef 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -575,7 +575,7 @@ void overwriteBlockHeader(BlockInfo& _currentBlockHeader, mObject& _blObj) _currentBlockHeader = tmp; ProofOfWork pow; - std::pair ret; + std::pair ret; while (!ProofOfWork::verify(_currentBlockHeader)) { ret = pow.mine(_currentBlockHeader, 1000, true); @@ -621,7 +621,7 @@ BlockInfo constructBlock(mObject& _o) void updatePoW(BlockInfo& _bi) { ProofOfWork pow; - std::pair ret; + std::pair ret; while (!ProofOfWork::verify(_bi)) { ret = pow.mine(_bi, 10000, true); From fae9208c0663dd677ec6ba5d055286cd63252fe6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Apr 2015 15:55:01 +0200 Subject: [PATCH 012/108] Add more files. --- libethash-cl/CMakeLists.txt | 47 + libethash-cl/bin2h.cmake | 86 + libethash-cl/cl.hpp | 4014 ++++++++++++++++++++++++ libethash-cl/ethash_cl_miner.cpp | 332 ++ libethash-cl/ethash_cl_miner.h | 43 + libethash-cl/ethash_cl_miner_kernel.cl | 460 +++ 6 files changed, 4982 insertions(+) create mode 100644 libethash-cl/CMakeLists.txt create mode 100644 libethash-cl/bin2h.cmake create mode 100644 libethash-cl/cl.hpp create mode 100644 libethash-cl/ethash_cl_miner.cpp create mode 100644 libethash-cl/ethash_cl_miner.h create mode 100644 libethash-cl/ethash_cl_miner_kernel.cl diff --git a/libethash-cl/CMakeLists.txt b/libethash-cl/CMakeLists.txt new file mode 100644 index 000000000..7b00a22bd --- /dev/null +++ b/libethash-cl/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 2.8) + +set(LIBRARY ethash-cl) +#set(CMAKE_BUILD_TYPE Release) + +include(bin2h.cmake) +bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl + VARIABLE_NAME ethash_cl_miner_kernel + HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) + +if (NOT MSVC) + # Initialize CXXFLAGS for c++11 + set(CMAKE_CXX_FLAGS "-Wall -std=c++11") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + + # Compiler-specific C++11 activation. + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)) + message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.") + endif () + elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + else () + message(FATAL_ERROR "Your C++ compiler does not support C++11.") + endif () +endif() + +set(OpenCL_FOUND TRUE) +set(OpenCL_INCLUDE_DIRS /usr/include/CL) +set(OpenCL_LIBRARIES -lOpenCL) + +if (NOT OpenCL_FOUND) + find_package(OpenCL) +endif() + +if (OpenCL_FOUND) + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -pedantic -fPIC ${CMAKE_CXX_FLAGS}") + include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) + include_directories(..) + add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp) + TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash) +endif() diff --git a/libethash-cl/bin2h.cmake b/libethash-cl/bin2h.cmake new file mode 100644 index 000000000..90ca9cc5b --- /dev/null +++ b/libethash-cl/bin2h.cmake @@ -0,0 +1,86 @@ +# https://gist.github.com/sivachandran/3a0de157dccef822a230 +include(CMakeParseArguments) + +# Function to wrap a given string into multiple lines at the given column position. +# Parameters: +# VARIABLE - The name of the CMake variable holding the string. +# AT_COLUMN - The column position at which string will be wrapped. +function(WRAP_STRING) + set(oneValueArgs VARIABLE AT_COLUMN) + cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) + + string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) + math(EXPR offset "0") + + while(stringLength GREATER 0) + + if(stringLength GREATER ${WRAP_STRING_AT_COLUMN}) + math(EXPR length "${WRAP_STRING_AT_COLUMN}") + else() + math(EXPR length "${stringLength}") + endif() + + string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) + set(lines "${lines}\n${line}") + + math(EXPR stringLength "${stringLength} - ${length}") + math(EXPR offset "${offset} + ${length}") + endwhile() + + set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) +endfunction() + +# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file +# will contain a byte array and integer variable holding the size of the array. +# Parameters +# SOURCE_FILE - The path of source file whose contents will be embedded in the header file. +# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append +# to this name and will be used a variable name for size variable. +# HEADER_FILE - The path of header file. +# APPEND - If specified appends to the header file instead of overwriting it +# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be +# useful if the source file is a text file and we want to use the file contents +# as string. But the size variable holds size of the byte array without this +# null byte. +# Usage: +# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG") +function(BIN2H) + set(options APPEND NULL_TERMINATE) + set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE) + cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN}) + + # reads source file contents as hex string + file(READ ${BIN2H_SOURCE_FILE} hexString HEX) + string(LENGTH ${hexString} hexStringLength) + + # appends null byte if asked + if(BIN2H_NULL_TERMINATE) + set(hexString "${hexString}00") + endif() + + # wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line) + wrap_string(VARIABLE hexString AT_COLUMN 32) + math(EXPR arraySize "${hexStringLength} / 2") + + # adds '0x' prefix and comma suffix before and after every byte respectively + string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString}) + # removes trailing comma + string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) + + # converts the variable name into proper C identifier + IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake + string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) + ENDIF() + string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) + + # declares byte array and the length variables + set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };") + set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};") + + set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n") + if(BIN2H_APPEND) + file(APPEND ${BIN2H_HEADER_FILE} "${declarations}") + else() + file(WRITE ${BIN2H_HEADER_FILE} "${declarations}") + endif() +endfunction() diff --git a/libethash-cl/cl.hpp b/libethash-cl/cl.hpp new file mode 100644 index 000000000..a38498762 --- /dev/null +++ b/libethash-cl/cl.hpp @@ -0,0 +1,4014 @@ +/******************************************************************************* + * Copyright (c) 2008-2010 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +/*! \file + * + * \brief C++ bindings for OpenCL 1.0 (rev 48) and OpenCL 1.1 (rev 33) + * \author Benedict R. Gaster and Laurent Morichetti + * + * Additions and fixes from Brian Cole, March 3rd 2010. + * + * \version 1.1 + * \date June 2010 + * + * Optional extension support + * + * cl + * cl_ext_device_fission + * #define USE_CL_DEVICE_FISSION + */ + +/*! \mainpage + * \section intro Introduction + * For many large applications C++ is the language of choice and so it seems + * reasonable to define C++ bindings for OpenCL. + * + * + * The interface is contained with a single C++ header file \em cl.hpp and all + * definitions are contained within the namespace \em cl. There is no additional + * requirement to include \em cl.h and to use either the C++ or original C + * bindings it is enough to simply include \em cl.hpp. + * + * The bindings themselves are lightweight and correspond closely to the + * underlying C API. Using the C++ bindings introduces no additional execution + * overhead. + * + * For detail documentation on the bindings see: + * + * The OpenCL C++ Wrapper API 1.1 (revision 04) + * http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.1.pdf + * + * \section example Example + * + * The following example shows a general use case for the C++ + * bindings, including support for the optional exception feature and + * also the supplied vector and string classes, see following sections for + * decriptions of these features. + * + * \code + * #define __CL_ENABLE_EXCEPTIONS + * + * #if defined(__APPLE__) || defined(__MACOSX) + * #include + * #else + * #include + * #endif + * #include + * #include + * #include + * + * const char * helloStr = "__kernel void " + * "hello(void) " + * "{ " + * " " + * "} "; + * + * int + * main(void) + * { + * cl_int err = CL_SUCCESS; + * try { + * + * std::vector platforms; + * cl::Platform::get(&platforms); + * if (platforms.size() == 0) { + * std::cout << "Platform size 0\n"; + * return -1; + * } + * + * cl_context_properties properties[] = + * { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; + * cl::Context context(CL_DEVICE_TYPE_CPU, properties); + * + * std::vector devices = context.getInfo(); + * + * cl::Program::Sources source(1, + * std::make_pair(helloStr,strlen(helloStr))); + * cl::Program program_ = cl::Program(context, source); + * program_.build(devices); + * + * cl::Kernel kernel(program_, "hello", &err); + * + * cl::Event event; + * cl::CommandQueue queue(context, devices[0], 0, &err); + * queue.enqueueNDRangeKernel( + * kernel, + * cl::NullRange, + * cl::NDRange(4,4), + * cl::NullRange, + * NULL, + * &event); + * + * event.wait(); + * } + * catch (cl::Error err) { + * std::cerr + * << "ERROR: " + * << err.what() + * << "(" + * << err.err() + * << ")" + * << std::endl; + * } + * + * return EXIT_SUCCESS; + * } + * + * \endcode + * + */ +#ifndef CL_HPP_ +#define CL_HPP_ + +#ifdef _WIN32 +#include +#include +#if defined(USE_DX_INTEROP) +#include +#endif +#endif // _WIN32 + +// +#if defined(USE_CL_DEVICE_FISSION) +#include +#endif + +#if defined(__APPLE__) || defined(__MACOSX) +#include +#include +#else +#include +#include +#endif // !__APPLE__ + +#if !defined(CL_CALLBACK) +#define CL_CALLBACK +#endif //CL_CALLBACK + +#include + +#if !defined(__NO_STD_VECTOR) +#include +#endif + +#if !defined(__NO_STD_STRING) +#include +#endif + +#if defined(linux) || defined(__APPLE__) || defined(__MACOSX) +# include +#endif // linux + +#include + +/*! \namespace cl + * + * \brief The OpenCL C++ bindings are defined within this namespace. + * + */ +namespace cl { + +#define __INIT_CL_EXT_FCN_PTR(name) \ + if(!pfn_##name) { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddress(#name); \ + if(!pfn_##name) { \ + } \ + } + +class Program; +class Device; +class Context; +class CommandQueue; +class Memory; + +#if defined(__CL_ENABLE_EXCEPTIONS) +#include +/*! \class Error + * \brief Exception class + */ +class Error : public std::exception +{ +private: + cl_int err_; + const char * errStr_; +public: + /*! Create a new CL error exception for a given error code + * and corresponding message. + */ + Error(cl_int err, const char * errStr = NULL) : err_(err), errStr_(errStr) + {} + + ~Error() throw() {} + + /*! \brief Get error string associated with exception + * + * \return A memory pointer to the error message string. + */ + virtual const char * what() const throw () + { + if (errStr_ == NULL) { + return "empty"; + } + else { + return errStr_; + } + } + + /*! \brief Get error code associated with exception + * + * \return The error code. + */ + cl_int err(void) const { return err_; } +}; + +#define __ERR_STR(x) #x +#else +#define __ERR_STR(x) NULL +#endif // __CL_ENABLE_EXCEPTIONS + +//! \cond DOXYGEN_DETAIL +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#define __GET_DEVICE_INFO_ERR __ERR_STR(clgetDeviceInfo) +#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) +#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) +#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) +#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) +#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) +#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) +#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) +#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) +#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) +#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) +#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) +#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) +#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) +#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) + +#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) +#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) + +#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) +#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) +#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) +#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) +#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) +#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) +#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) + +#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) +#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) +#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) +#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) + +#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) +#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) +#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) +#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) +#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) +#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) + +#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) +#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) +#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) +#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) +#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) +#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) +#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) +#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) +#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) +#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) +#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) +#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) +#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) +#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) +#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) +#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) +#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) +#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) +#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) +#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) +#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) +#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) + +#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) +#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) + +#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) + +#define __FLUSH_ERR __ERR_STR(clFlush) +#define __FINISH_ERR __ERR_STR(clFinish) + +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) +#endif // __CL_USER_OVERRIDE_ERROR_STRINGS +//! \endcond + +/*! \class string + * \brief Simple string class, that provides a limited subset of std::string + * functionality but avoids many of the issues that come with that class. + */ +class string +{ +private: + ::size_t size_; + char * str_; +public: + string(void) : size_(0), str_(NULL) + { + } + + string(char * str, ::size_t size) : + size_(size), + str_(NULL) + { + str_ = new char[size_+1]; + if (str_ != NULL) { + memcpy(str_, str, size_ * sizeof(char)); + str_[size_] = '\0'; + } + else { + size_ = 0; + } + } + + string(char * str) : + str_(NULL) + { + size_= ::strlen(str); + str_ = new char[size_ + 1]; + if (str_ != NULL) { + memcpy(str_, str, (size_ + 1) * sizeof(char)); + } + else { + size_ = 0; + } + } + + string& operator=(const string& rhs) + { + if (this == &rhs) { + return *this; + } + + if (rhs.size_ == 0 || rhs.str_ == NULL) { + size_ = 0; + str_ = NULL; + } + else { + size_ = rhs.size_; + str_ = new char[size_ + 1]; + if (str_ != NULL) { + memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); + } + else { + size_ = 0; + } + } + + return *this; + } + + string(const string& rhs) + { + *this = rhs; + } + + ~string() + { + if (str_ != NULL) { + delete[] str_; + } + } + + ::size_t size(void) const { return size_; } + ::size_t length(void) const { return size(); } + + const char * c_str(void) const { return (str_) ? str_ : "";} +}; + +#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) +#include +typedef std::string STRING_CLASS; +#elif !defined(__USE_DEV_STRING) +typedef cl::string STRING_CLASS; +#endif + +#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) +#include +#define VECTOR_CLASS std::vector +#elif !defined(__USE_DEV_VECTOR) +#define VECTOR_CLASS cl::vector +#endif + +#if !defined(__MAX_DEFAULT_VECTOR_SIZE) +#define __MAX_DEFAULT_VECTOR_SIZE 10 +#endif + +/*! \class vector + * \brief Fixed sized vector implementation that mirroring + * std::vector functionality. + */ +template +class vector +{ +private: + T data_[N]; + unsigned int size_; + bool empty_; +public: + vector() : + size_(-1), + empty_(true) + {} + + ~vector() {} + + unsigned int size(void) const + { + return size_ + 1; + } + + void clear() + { + size_ = -1; + empty_ = true; + } + + void push_back (const T& x) + { + if (size() < N) { + size_++; + data_[size_] = x; + empty_ = false; + } + } + + void pop_back(void) + { + if (!empty_) { + data_[size_].~T(); + size_--; + if (size_ == -1) { + empty_ = true; + } + } + } + + vector(const vector& vec) : + size_(vec.size_), + empty_(vec.empty_) + { + if (!empty_) { + memcpy(&data_[0], &vec.data_[0], size() * sizeof(T)); + } + } + + vector(unsigned int size, const T& val = T()) : + size_(-1), + empty_(true) + { + for (unsigned int i = 0; i < size; i++) { + push_back(val); + } + } + + vector& operator=(const vector& rhs) + { + if (this == &rhs) { + return *this; + } + + size_ = rhs.size_; + empty_ = rhs.empty_; + + if (!empty_) { + memcpy(&data_[0], &rhs.data_[0], size() * sizeof(T)); + } + + return *this; + } + + bool operator==(vector &vec) + { + if (empty_ && vec.empty_) { + return true; + } + + if (size() != vec.size()) { + return false; + } + + return memcmp(&data_[0], &vec.data_[0], size() * sizeof(T)) == 0 ? true : false; + } + + operator T* () { return data_; } + operator const T* () const { return data_; } + + bool empty (void) const + { + return empty_; + } + + unsigned int max_size (void) const + { + return N; + } + + unsigned int capacity () const + { + return sizeof(T) * N; + } + + T& operator[](int index) + { + return data_[index]; + } + + T operator[](int index) const + { + return data_[index]; + } + + template + void assign(I start, I end) + { + clear(); + while(start < end) { + push_back(*start); + start++; + } + } + + /*! \class iterator + * \brief Iterator class for vectors + */ + class iterator + { + private: + vector vec_; + int index_; + bool initialized_; + public: + iterator(void) : + index_(-1), + initialized_(false) + { + index_ = -1; + initialized_ = false; + } + + ~iterator(void) {} + + static iterator begin(vector &vec) + { + iterator i; + + if (!vec.empty()) { + i.index_ = 0; + } + + i.vec_ = vec; + i.initialized_ = true; + return i; + } + + static iterator end(vector &vec) + { + iterator i; + + if (!vec.empty()) { + i.index_ = vec.size(); + } + i.vec_ = vec; + i.initialized_ = true; + return i; + } + + bool operator==(iterator i) + { + return ((vec_ == i.vec_) && + (index_ == i.index_) && + (initialized_ == i.initialized_)); + } + + bool operator!=(iterator i) + { + return (!(*this==i)); + } + + void operator++() + { + index_++; + } + + void operator++(int x) + { + index_ += x; + } + + void operator--() + { + index_--; + } + + void operator--(int x) + { + index_ -= x; + } + + T operator *() + { + return vec_[index_]; + } + }; + + iterator begin(void) + { + return iterator::begin(*this); + } + + iterator end(void) + { + return iterator::end(*this); + } + + T& front(void) + { + return data_[0]; + } + + T& back(void) + { + return data_[size_]; + } + + const T& front(void) const + { + return data_[0]; + } + + const T& back(void) const + { + return data_[size_]; + } +}; + +/*! + * \brief size_t class used to interface between C++ and + * OpenCL C calls that require arrays of size_t values, who's + * size is known statically. + */ +template +struct size_t : public cl::vector< ::size_t, N> { }; + +namespace detail { + +// GetInfo help struct +template +struct GetInfoHelper +{ + static cl_int + get(Functor f, cl_uint name, T* param) + { + return f(name, sizeof(T), param, NULL); + } +}; + +// Specialized GetInfoHelper for VECTOR_CLASS params +template +struct GetInfoHelper > +{ + static cl_int get(Func f, cl_uint name, VECTOR_CLASS* param) + { + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + T* value = (T*) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + param->assign(&value[0], &value[required/sizeof(T)]); + return CL_SUCCESS; + } +}; + +// Specialized for getInfo +template +struct GetInfoHelper > +{ + static cl_int + get(Func f, cl_uint name, VECTOR_CLASS* param) + { + cl_uint err = f(name, param->size() * sizeof(char *), &(*param)[0], NULL); + if (err != CL_SUCCESS) { + return err; + } + + return CL_SUCCESS; + } +}; + +// Specialized GetInfoHelper for STRING_CLASS params +template +struct GetInfoHelper +{ + static cl_int get(Func f, cl_uint name, STRING_CLASS* param) + { + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + char* value = (char*) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + *param = value; + return CL_SUCCESS; + } +}; + +#define __GET_INFO_HELPER_WITH_RETAIN(CPP_TYPE) \ +namespace detail { \ +template \ +struct GetInfoHelper \ +{ \ + static cl_int get(Func f, cl_uint name, CPP_TYPE* param) \ + { \ + cl_uint err = f(name, sizeof(CPP_TYPE), param, NULL); \ + if (err != CL_SUCCESS) { \ + return err; \ + } \ + \ + return ReferenceHandler::retain((*param)()); \ + } \ +}; \ +} + + +#define __PARAM_NAME_INFO_1_0(F) \ + F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ + F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ + F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_bitfield) \ + F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ + F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ + F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint)\ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ + F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ + F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ + F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ + F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ + F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ + F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ + F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ + \ + F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ + F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ + F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ + F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_uint) \ + \ + F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ + \ + F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ + F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ + F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ + F(cl_mem_info, CL_MEM_HOST_PTR, void*) \ + F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ + \ + F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ + F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ + F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ + F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ + F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ + \ + F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ + F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ + F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_addressing_mode) \ + F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_filter_mode) \ + F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_bool) \ + \ + F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ + F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ + F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ + F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ + F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ + F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ + \ + F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ + F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ + F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ + F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ + \ + F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ + F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ + F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ + F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) + +#if defined(CL_VERSION_1_1) +#define __PARAM_NAME_INFO_1_1(F) \ + F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint)\ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ + \ + F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ + F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ + \ + F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) +#endif // CL_VERSION_1_1 + +#if defined(USE_CL_DEVICE_FISSION) +#define __PARAM_NAME_DEVICE_FISSION(F) \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \ + F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) +#endif // USE_CL_DEVICE_FISSION + +template +struct param_traits {}; + +#define __DECLARE_PARAM_TRAITS(token, param_name, T) \ +struct token; \ +template<> \ +struct param_traits \ +{ \ + enum { value = param_name }; \ + typedef T param_type; \ +}; + +__PARAM_NAME_INFO_1_0(__DECLARE_PARAM_TRAITS) +#if defined(CL_VERSION_1_1) +__PARAM_NAME_INFO_1_1(__DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 + +#if defined(USE_CL_DEVICE_FISSION) +__PARAM_NAME_DEVICE_FISSION(__DECLARE_PARAM_TRAITS); +#endif // USE_CL_DEVICE_FISSION + +#undef __DECLARE_PARAM_TRAITS + +// Convenience functions + +template +inline cl_int +getInfo(Func f, cl_uint name, T* param) +{ + return GetInfoHelper::get(f, name, param); +} + +template +struct GetInfoFunctor0 +{ + Func f_; const Arg0& arg0_; + cl_int operator ()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { return f_(arg0_, param, size, value, size_ret); } +}; + +template +struct GetInfoFunctor1 +{ + Func f_; const Arg0& arg0_; const Arg1& arg1_; + cl_int operator ()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { return f_(arg0_, arg1_, param, size, value, size_ret); } +}; + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, cl_uint name, T* param) +{ + GetInfoFunctor0 f0 = { f, arg0 }; + return GetInfoHelper, T> + ::get(f0, name, param); +} + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param) +{ + GetInfoFunctor1 f0 = { f, arg0, arg1 }; + return GetInfoHelper, T> + ::get(f0, name, param); +} + +template +struct ReferenceHandler +{ }; + +template <> +struct ReferenceHandler +{ + // cl_device_id does not have retain(). + static cl_int retain(cl_device_id) + { return CL_INVALID_DEVICE; } + // cl_device_id does not have release(). + static cl_int release(cl_device_id) + { return CL_INVALID_DEVICE; } +}; + +template <> +struct ReferenceHandler +{ + // cl_platform_id does not have retain(). + static cl_int retain(cl_platform_id) + { return CL_INVALID_PLATFORM; } + // cl_platform_id does not have release(). + static cl_int release(cl_platform_id) + { return CL_INVALID_PLATFORM; } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_context context) + { return ::clRetainContext(context); } + static cl_int release(cl_context context) + { return ::clReleaseContext(context); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_command_queue queue) + { return ::clRetainCommandQueue(queue); } + static cl_int release(cl_command_queue queue) + { return ::clReleaseCommandQueue(queue); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_mem memory) + { return ::clRetainMemObject(memory); } + static cl_int release(cl_mem memory) + { return ::clReleaseMemObject(memory); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_sampler sampler) + { return ::clRetainSampler(sampler); } + static cl_int release(cl_sampler sampler) + { return ::clReleaseSampler(sampler); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_program program) + { return ::clRetainProgram(program); } + static cl_int release(cl_program program) + { return ::clReleaseProgram(program); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_kernel kernel) + { return ::clRetainKernel(kernel); } + static cl_int release(cl_kernel kernel) + { return ::clReleaseKernel(kernel); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_event event) + { return ::clRetainEvent(event); } + static cl_int release(cl_event event) + { return ::clReleaseEvent(event); } +}; + +template +class Wrapper +{ +public: + typedef T cl_type; + +protected: + cl_type object_; + +public: + Wrapper() : object_(NULL) { } + + ~Wrapper() + { + if (object_ != NULL) { release(); } + } + + Wrapper(const Wrapper& rhs) + { + object_ = rhs.object_; + if (object_ != NULL) { retain(); } + } + + Wrapper& operator = (const Wrapper& rhs) + { + if (object_ != NULL) { release(); } + object_ = rhs.object_; + if (object_ != NULL) { retain(); } + return *this; + } + + cl_type operator ()() const { return object_; } + + cl_type& operator ()() { return object_; } + +protected: + + cl_int retain() const + { + return ReferenceHandler::retain(object_); + } + + cl_int release() const + { + return ReferenceHandler::release(object_); + } +}; + +#if defined(__CL_ENABLE_EXCEPTIONS) +static inline cl_int errHandler ( + cl_int err, + const char * errStr = NULL) throw(Error) +{ + if (err != CL_SUCCESS) { + throw Error(err, errStr); + } + return err; +} +#else +static inline cl_int errHandler (cl_int err, const char * errStr = NULL) +{ + return err; +} +#endif // __CL_ENABLE_EXCEPTIONS + +} // namespace detail +//! \endcond + +/*! \stuct ImageFormat + * \brief ImageFormat interface fro cl_image_format. + */ +struct ImageFormat : public cl_image_format +{ + ImageFormat(){} + + ImageFormat(cl_channel_order order, cl_channel_type type) + { + image_channel_order = order; + image_channel_data_type = type; + } + + ImageFormat& operator = (const ImageFormat& rhs) + { + if (this != &rhs) { + this->image_channel_data_type = rhs.image_channel_data_type; + this->image_channel_order = rhs.image_channel_order; + } + return *this; + } +}; + +/*! \class Device + * \brief Device interface for cl_device_id. + */ +class Device : public detail::Wrapper +{ +public: + Device(cl_device_id device) { object_ = device; } + + Device() : detail::Wrapper() { } + + Device(const Device& device) : detail::Wrapper(device) { } + + Device& operator = (const Device& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_device_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetDeviceInfo, object_, name, param), + __GET_DEVICE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_device_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + +#if defined(USE_CL_DEVICE_FISSION) + cl_int createSubDevices( + const cl_device_partition_property_ext * properties, + VECTOR_CLASS* devices) + { + typedef CL_API_ENTRY cl_int + ( CL_API_CALL * PFN_clCreateSubDevicesEXT)( + cl_device_id /*in_device*/, + const cl_device_partition_property_ext * /* properties */, + cl_uint /*num_entries*/, + cl_device_id * /*out_devices*/, + cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1; + + static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; + __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); + + cl_uint n = 0; + cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif +}; + +/*! \class Platform + * \brief Platform interface. + */ +class Platform : public detail::Wrapper +{ +public: + static const Platform null(); + + Platform(cl_platform_id platform) { object_ = platform; } + + Platform() : detail::Wrapper() { } + + Platform(const Platform& platform) : detail::Wrapper(platform) { } + + Platform& operator = (const Platform& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + cl_int getInfo(cl_platform_info name, STRING_CLASS* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetPlatformInfo, object_, name, param), + __GET_PLATFORM_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_platform_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int getDevices( + cl_device_type type, + VECTOR_CLASS* devices) const + { + cl_uint n = 0; + cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = ::clGetDeviceIDs(object_, type, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + +#if defined(USE_DX_INTEROP) + /*! \brief Get the list of available D3D10 devices. + * + * \param d3d_device_source. + * + * \param d3d_object. + * + * \param d3d_device_set. + * + * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device + * values returned in devices can be used to identify a specific OpenCL + * device. If \a devices argument is NULL, this argument is ignored. + * + * \return One of the following values: + * - CL_SUCCESS if the function is executed successfully. + * + * The application can query specific capabilities of the OpenCL device(s) + * returned by cl::getDevices. This can be used by the application to + * determine which device(s) to use. + * + * \note In the case that exceptions are enabled and a return value + * other than CL_SUCCESS is generated, then cl::Error exception is + * generated. + */ + cl_int getDevices( + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + VECTOR_CLASS* devices) const + { + typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clGetDeviceIDsFromD3D10KHR)( + cl_platform_id platform, + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + cl_uint num_entries, + cl_device_id * devices, + cl_uint* num_devices); + + static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; + __INIT_CL_EXT_FCN_PTR(clGetDeviceIDsFromD3D10KHR); + + cl_uint n = 0; + cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + 0, + NULL, + &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + n, + ids, + NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif + + static cl_int get( + VECTOR_CLASS* platforms) + { + cl_uint n = 0; + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id* ids = (cl_platform_id*) alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + platforms->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +}; + +static inline cl_int +UnloadCompiler() +{ + return ::clUnloadCompiler(); +} + +class Context : public detail::Wrapper +{ +public: + Context( + const VECTOR_CLASS& devices, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateContext( + properties, (cl_uint) devices.size(), + (cl_device_id*) &devices.front(), + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + } + + Context( + cl_device_type type, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateContextFromType( + properties, type, notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + } + + Context() : detail::Wrapper() { } + + Context(const Context& context) : detail::Wrapper(context) { } + + Context& operator = (const Context& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_context_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetContextInfo, object_, name, param), + __GET_CONTEXT_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_context_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int getSupportedImageFormats( + cl_mem_flags flags, + cl_mem_object_type type, + VECTOR_CLASS* formats) const + { + cl_uint numEntries; + cl_int err = ::clGetSupportedImageFormats( + object_, + flags, + type, + 0, + NULL, + &numEntries); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + ImageFormat* value = (ImageFormat*) + alloca(numEntries * sizeof(ImageFormat)); + err = ::clGetSupportedImageFormats( + object_, + flags, + type, + numEntries, + (cl_image_format*) value, + NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + formats->assign(&value[0], &value[numEntries]); + return CL_SUCCESS; + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Context) + +/*! \class Event + * \brief Event interface for cl_event. + */ +class Event : public detail::Wrapper +{ +public: + Event() : detail::Wrapper() { } + + Event(const Event& event) : detail::Wrapper(event) { } + + Event& operator = (const Event& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_event_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetEventInfo, object_, name, param), + __GET_EVENT_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_event_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int getProfilingInfo(cl_profiling_info name, T* param) const + { + return detail::errHandler(detail::getInfo( + &::clGetEventProfilingInfo, object_, name, param), + __GET_EVENT_PROFILE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getProfilingInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_profiling_info, name>::param_type param; + cl_int result = getProfilingInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int wait() const + { + return detail::errHandler( + ::clWaitForEvents(1, &object_), + __WAIT_FOR_EVENTS_ERR); + } + +#if defined(CL_VERSION_1_1) + cl_int setCallback( + cl_int type, + void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), + void * user_data = NULL) + { + return detail::errHandler( + ::clSetEventCallback( + object_, + type, + pfn_notify, + user_data), + __SET_EVENT_CALLBACK_ERR); + } +#endif + + static cl_int + waitForEvents(const VECTOR_CLASS& events) + { + return detail::errHandler( + ::clWaitForEvents( + (cl_uint) events.size(), (cl_event*)&events.front()), + __WAIT_FOR_EVENTS_ERR); + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Event) + +#if defined(CL_VERSION_1_1) +/*! \class UserEvent + * \brief User event interface for cl_event. + */ +class UserEvent : public Event +{ +public: + UserEvent( + const Context& context, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateUserEvent( + context(), + &error); + + detail::errHandler(error, __CREATE_USER_EVENT_ERR); + if (err != NULL) { + *err = error; + } + } + + UserEvent() : Event() { } + + UserEvent(const UserEvent& event) : Event(event) { } + + UserEvent& operator = (const UserEvent& rhs) + { + if (this != &rhs) { + Event::operator=(rhs); + } + return *this; + } + + cl_int setStatus(cl_int status) + { + return detail::errHandler( + ::clSetUserEventStatus(object_,status), + __SET_USER_EVENT_STATUS_ERR); + } +}; +#endif + +inline static cl_int +WaitForEvents(const VECTOR_CLASS& events) +{ + return detail::errHandler( + ::clWaitForEvents( + (cl_uint) events.size(), (cl_event*)&events.front()), + __WAIT_FOR_EVENTS_ERR); +} + +/*! \class Memory + * \brief Memory interface for cl_mem. + */ +class Memory : public detail::Wrapper +{ +public: + Memory() : detail::Wrapper() { } + + Memory(const Memory& memory) : detail::Wrapper(memory) { } + + Memory& operator = (const Memory& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_mem_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetMemObjectInfo, object_, name, param), + __GET_MEM_OBJECT_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_mem_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_1) + cl_int setDestructorCallback( + void (CL_CALLBACK * pfn_notify)(cl_mem, void *), + void * user_data = NULL) + { + return detail::errHandler( + ::clSetMemObjectDestructorCallback( + object_, + pfn_notify, + user_data), + __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); + } +#endif + +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Memory) + +/*! \class Buffer + * \brief Memory buffer interface. + */ +class Buffer : public Memory +{ +public: + Buffer( + const Context& context, + cl_mem_flags flags, + ::size_t size, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + Buffer() : Memory() { } + + Buffer(const Buffer& buffer) : Memory(buffer) { } + + Buffer& operator = (const Buffer& rhs) + { + if (this != &rhs) { + Memory::operator=(rhs); + } + return *this; + } + +#if defined(CL_VERSION_1_1) + Buffer createSubBuffer( + cl_mem_flags flags, + cl_buffer_create_type buffer_create_type, + const void * buffer_create_info, + cl_int * err = NULL) + { + Buffer result; + cl_int error; + result.object_ = ::clCreateSubBuffer( + object_, + flags, + buffer_create_type, + buffer_create_info, + &error); + + detail::errHandler(error, __CREATE_SUBBUFFER_ERR); + if (err != NULL) { + *err = error; + } + + return result; + } +#endif +}; + +#if defined (USE_DX_INTEROP) +class BufferD3D10 : public Buffer +{ +public: + typedef CL_API_ENTRY cl_mem (CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)( + cl_context context, cl_mem_flags flags, ID3D10Buffer* buffer, + cl_int* errcode_ret); + + BufferD3D10( + const Context& context, + cl_mem_flags flags, + ID3D10Buffer* bufobj, + cl_int * err = NULL) + { + static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; + __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); + + cl_int error; + object_ = pfn_clCreateFromD3D10BufferKHR( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + BufferD3D10() : Buffer() { } + + BufferD3D10(const BufferD3D10& buffer) : Buffer(buffer) { } + + BufferD3D10& operator = (const BufferD3D10& rhs) + { + if (this != &rhs) { + Buffer::operator=(rhs); + } + return *this; + } +}; +#endif + +/*! \class BufferGL + * \brief Memory buffer interface for GL interop. + */ +class BufferGL : public Buffer +{ +public: + BufferGL( + const Context& context, + cl_mem_flags flags, + GLuint bufobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLBuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + BufferGL() : Buffer() { } + + BufferGL(const BufferGL& buffer) : Buffer(buffer) { } + + BufferGL& operator = (const BufferGL& rhs) + { + if (this != &rhs) { + Buffer::operator=(rhs); + } + return *this; + } + + cl_int getObjectInfo( + cl_gl_object_type *type, + GLuint * gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_,type,gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \class BufferRenderGL + * \brief Memory buffer interface for GL interop with renderbuffer. + */ +class BufferRenderGL : public Buffer +{ +public: + BufferRenderGL( + const Context& context, + cl_mem_flags flags, + GLuint bufobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLRenderbuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + BufferRenderGL() : Buffer() { } + + BufferRenderGL(const BufferGL& buffer) : Buffer(buffer) { } + + BufferRenderGL& operator = (const BufferRenderGL& rhs) + { + if (this != &rhs) { + Buffer::operator=(rhs); + } + return *this; + } + + cl_int getObjectInfo( + cl_gl_object_type *type, + GLuint * gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_,type,gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \class Image + * \brief Base class interface for all images. + */ +class Image : public Memory +{ +protected: + Image() : Memory() { } + + Image(const Image& image) : Memory(image) { } + + Image& operator = (const Image& rhs) + { + if (this != &rhs) { + Memory::operator=(rhs); + } + return *this; + } +public: + template + cl_int getImageInfo(cl_image_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetImageInfo, object_, name, param), + __GET_IMAGE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getImageInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_image_info, name>::param_type param; + cl_int result = getImageInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +}; + +/*! \class Image2D + * \brief Image interface for 2D images. + */ +class Image2D : public Image +{ +public: + Image2D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t row_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateImage2D( + context(), flags,&format, width, height, row_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE2D_ERR); + if (err != NULL) { + *err = error; + } + } + + Image2D() { } + + Image2D(const Image2D& image2D) : Image(image2D) { } + + Image2D& operator = (const Image2D& rhs) + { + if (this != &rhs) { + Image::operator=(rhs); + } + return *this; + } +}; + +/*! \class Image2DGL + * \brief 2D image interface for GL interop. + */ +class Image2DGL : public Image2D +{ +public: + Image2DGL( + const Context& context, + cl_mem_flags flags, + GLenum target, + GLint miplevel, + GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture2D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + Image2DGL() : Image2D() { } + + Image2DGL(const Image2DGL& image) : Image2D(image) { } + + Image2DGL& operator = (const Image2DGL& rhs) + { + if (this != &rhs) { + Image2D::operator=(rhs); + } + return *this; + } +}; + +/*! \class Image3D + * \brief Image interface for 3D images. + */ +class Image3D : public Image +{ +public: + Image3D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t depth, + ::size_t row_pitch = 0, + ::size_t slice_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateImage3D( + context(), flags, &format, width, height, depth, row_pitch, + slice_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE3D_ERR); + if (err != NULL) { + *err = error; + } + } + + Image3D() { } + + Image3D(const Image3D& image3D) : Image(image3D) { } + + Image3D& operator = (const Image3D& rhs) + { + if (this != &rhs) { + Image::operator=(rhs); + } + return *this; + } +}; + +/*! \class Image2DGL + * \brief 2D image interface for GL interop. + */ +class Image3DGL : public Image3D +{ +public: + Image3DGL( + const Context& context, + cl_mem_flags flags, + GLenum target, + GLint miplevel, + GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture3D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + Image3DGL() : Image3D() { } + + Image3DGL(const Image3DGL& image) : Image3D(image) { } + + Image3DGL& operator = (const Image3DGL& rhs) + { + if (this != &rhs) { + Image3D::operator=(rhs); + } + return *this; + } +}; + +/*! \class Sampler + * \brief Sampler interface for cl_sampler. + */ +class Sampler : public detail::Wrapper +{ +public: + Sampler() { } + + Sampler( + const Context& context, + cl_bool normalized_coords, + cl_addressing_mode addressing_mode, + cl_filter_mode filter_mode, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateSampler( + context(), + normalized_coords, + addressing_mode, + filter_mode, + &error); + + detail::errHandler(error, __CREATE_SAMPLER_ERR); + if (err != NULL) { + *err = error; + } + } + + Sampler(const Sampler& sampler) : detail::Wrapper(sampler) { } + + Sampler& operator = (const Sampler& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_sampler_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetSamplerInfo, object_, name, param), + __GET_SAMPLER_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_sampler_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Sampler) + +class Program; +class CommandQueue; +class Kernel; + +/*! \class NDRange + * \brief NDRange interface + */ +class NDRange +{ +private: + size_t<3> sizes_; + cl_uint dimensions_; + +public: + NDRange() + : dimensions_(0) + { } + + NDRange(::size_t size0) + : dimensions_(1) + { + sizes_.push_back(size0); + } + + NDRange(::size_t size0, ::size_t size1) + : dimensions_(2) + { + sizes_.push_back(size0); + sizes_.push_back(size1); + } + + NDRange(::size_t size0, ::size_t size1, ::size_t size2) + : dimensions_(3) + { + sizes_.push_back(size0); + sizes_.push_back(size1); + sizes_.push_back(size2); + } + + operator const ::size_t*() const { return (const ::size_t*) sizes_; } + ::size_t dimensions() const { return dimensions_; } +}; + +static const NDRange NullRange; + +/*! + * \struct LocalSpaceArg + * \brief Local address raper for use with Kernel::setArg + */ +struct LocalSpaceArg +{ + ::size_t size_; +}; + +namespace detail { + +template +struct KernelArgumentHandler +{ + static ::size_t size(const T&) { return sizeof(T); } + static T* ptr(T& value) { return &value; } +}; + +template <> +struct KernelArgumentHandler +{ + static ::size_t size(const LocalSpaceArg& value) { return value.size_; } + static void* ptr(LocalSpaceArg&) { return NULL; } +}; + +} +//! \endcond + +inline LocalSpaceArg +__local(::size_t size) +{ + LocalSpaceArg ret = { size }; + return ret; +} + +class KernelFunctor; + +/*! \class Kernel + * \brief Kernel interface that implements cl_kernel + */ +class Kernel : public detail::Wrapper +{ +public: + inline Kernel(const Program& program, const char* name, cl_int* err = NULL); + + Kernel() { } + + Kernel(const Kernel& kernel) : detail::Wrapper(kernel) { } + + Kernel& operator = (const Kernel& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_kernel_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelInfo, object_, name, param), + __GET_KERNEL_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int getWorkGroupInfo( + const Device& device, cl_kernel_work_group_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetKernelWorkGroupInfo, object_, device(), name, param), + __GET_KERNEL_WORK_GROUP_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getWorkGroupInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_work_group_info, name>::param_type param; + cl_int result = getWorkGroupInfo(device, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int setArg(cl_uint index, T value) + { + return detail::errHandler( + ::clSetKernelArg( + object_, + index, + detail::KernelArgumentHandler::size(value), + detail::KernelArgumentHandler::ptr(value)), + __SET_KERNEL_ARGS_ERR); + } + + cl_int setArg(cl_uint index, ::size_t size, void* argPtr) + { + return detail::errHandler( + ::clSetKernelArg(object_, index, size, argPtr), + __SET_KERNEL_ARGS_ERR); + } + + KernelFunctor bind( + const CommandQueue& queue, + const NDRange& offset, + const NDRange& global, + const NDRange& local); + + KernelFunctor bind( + const CommandQueue& queue, + const NDRange& global, + const NDRange& local); +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Kernel) + +/*! \class Program + * \brief Program interface that implements cl_program. + */ +class Program : public detail::Wrapper +{ +public: + typedef VECTOR_CLASS > Binaries; + typedef VECTOR_CLASS > Sources; + + Program( + const Context& context, + const Sources& sources, + cl_int* err = NULL) + { + cl_int error; + + const ::size_t n = (::size_t)sources.size(); + ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); + const char** strings = (const char**) alloca(n * sizeof(const char*)); + + for (::size_t i = 0; i < n; ++i) { + strings[i] = sources[(int)i].first; + lengths[i] = sources[(int)i].second; + } + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)n, strings, lengths, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + if (err != NULL) { + *err = error; + } + } + + Program( + const Context& context, + const VECTOR_CLASS& devices, + const Binaries& binaries, + VECTOR_CLASS* binaryStatus = NULL, + cl_int* err = NULL) + { + cl_int error; + const ::size_t n = binaries.size(); + ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); + const unsigned char** images = (const unsigned char**) alloca(n * sizeof(const void*)); + + for (::size_t i = 0; i < n; ++i) { + images[i] = (const unsigned char*)binaries[(int)i].first; + lengths[i] = binaries[(int)i].second; + } + + object_ = ::clCreateProgramWithBinary( + context(), (cl_uint) devices.size(), + (cl_device_id*)&devices.front(), + lengths, images, binaryStatus != NULL + ? (cl_int*) &binaryStatus->front() + : NULL, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) { + *err = error; + } + } + + Program() { } + + Program(const Program& program) : detail::Wrapper(program) { } + + Program& operator = (const Program& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + cl_int build( + const VECTOR_CLASS& devices, + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL) const + { + return detail::errHandler( + ::clBuildProgram( + object_, + (cl_uint) + devices.size(), + (cl_device_id*)&devices.front(), + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + + template + cl_int getInfo(cl_program_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetProgramInfo, object_, name, param), + __GET_PROGRAM_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int getBuildInfo( + const Device& device, cl_program_build_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetProgramBuildInfo, object_, device(), name, param), + __GET_PROGRAM_BUILD_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getBuildInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_build_info, name>::param_type param; + cl_int result = getBuildInfo(device, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int createKernels(VECTOR_CLASS* kernels) + { + cl_uint numKernels; + cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + Kernel* value = (Kernel*) alloca(numKernels * sizeof(Kernel)); + err = ::clCreateKernelsInProgram( + object_, numKernels, (cl_kernel*) value, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + kernels->assign(&value[0], &value[numKernels]); + return CL_SUCCESS; + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Program) + +inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) +{ + cl_int error; + + object_ = ::clCreateKernel(program(), name, &error); + detail::errHandler(error, __CREATE_KERNEL_ERR); + + if (err != NULL) { + *err = error; + } + +} + +/*! \class CommandQueue + * \brief CommandQueue interface for cl_command_queue. + */ +class CommandQueue : public detail::Wrapper +{ +public: + CommandQueue( + const Context& context, + const Device& device, + cl_command_queue_properties properties = 0, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) { + *err = error; + } + } + + CommandQueue() { } + + CommandQueue(const CommandQueue& commandQueue) : detail::Wrapper(commandQueue) { } + + CommandQueue& operator = (const CommandQueue& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_command_queue_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetCommandQueueInfo, object_, name, param), + __GET_COMMAND_QUEUE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_command_queue_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int enqueueReadBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueReadBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_READ_BUFFER_ERR); + } + + cl_int enqueueWriteBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueWriteBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_WRITE_BUFFER_ERR); + } + + cl_int enqueueCopyBuffer( + const Buffer& src, + const Buffer& dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyBuffer( + object_, src(), dst(), src_offset, dst_offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQEUE_COPY_BUFFER_ERR); + } + +#if defined(CL_VERSION_1_1) + cl_int enqueueReadBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueReadBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_READ_BUFFER_RECT_ERR); + } + + + cl_int enqueueWriteBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueWriteBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_WRITE_BUFFER_RECT_ERR); + } + + cl_int enqueueCopyBufferRect( + const Buffer& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyBufferRect( + object_, + src(), + dst(), + (const ::size_t *)src_origin, + (const ::size_t *)dst_origin, + (const ::size_t *)region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQEUE_COPY_BUFFER_RECT_ERR); + } +#endif + + cl_int enqueueReadImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueReadImage( + object_, image(), blocking, (const ::size_t *) origin, + (const ::size_t *) region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_READ_IMAGE_ERR); + } + + cl_int enqueueWriteImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueWriteImage( + object_, image(), blocking, (const ::size_t *) origin, + (const ::size_t *) region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_WRITE_IMAGE_ERR); + } + + cl_int enqueueCopyImage( + const Image& src, + const Image& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyImage( + object_, src(), dst(), (const ::size_t *) src_origin, + (const ::size_t *)dst_origin, (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_COPY_IMAGE_ERR); + } + + cl_int enqueueCopyImageToBuffer( + const Image& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& region, + ::size_t dst_offset, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyImageToBuffer( + object_, src(), dst(), (const ::size_t *) src_origin, + (const ::size_t *) region, dst_offset, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); + } + + cl_int enqueueCopyBufferToImage( + const Buffer& src, + const Image& dst, + ::size_t src_offset, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyBufferToImage( + object_, src(), dst(), src_offset, + (const ::size_t *) dst_origin, (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); + } + + void* enqueueMapBuffer( + const Buffer& buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_int error; + void * result = ::clEnqueueMapBuffer( + object_, buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + return result; + } + + void* enqueueMapImage( + const Image& buffer, + cl_bool blocking, + cl_map_flags flags, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t * row_pitch, + ::size_t * slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_int error; + void * result = ::clEnqueueMapImage( + object_, buffer(), blocking, flags, + (const ::size_t *) origin, (const ::size_t *) region, + row_pitch, slice_pitch, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + return result; + } + + cl_int enqueueUnmapMemObject( + const Memory& memory, + void* mapped_ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueUnmapMemObject( + object_, memory(), mapped_ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + } + + cl_int enqueueNDRangeKernel( + const Kernel& kernel, + const NDRange& offset, + const NDRange& global, + const NDRange& local, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueNDRangeKernel( + object_, kernel(), (cl_uint) global.dimensions(), + offset.dimensions() != 0 ? (const ::size_t*) offset : NULL, + (const ::size_t*) global, + local.dimensions() != 0 ? (const ::size_t*) local : NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_NDRANGE_KERNEL_ERR); + } + + cl_int enqueueTask( + const Kernel& kernel, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueTask( + object_, kernel(), + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_TASK_ERR); + } + + cl_int enqueueNativeKernel( + void (*userFptr)(void *), + std::pair args, + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* mem_locs = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_mem * mems = (mem_objects != NULL && mem_objects->size() > 0) + ? (cl_mem*) alloca(mem_objects->size() * sizeof(cl_mem)) + : NULL; + + if (mems != NULL) { + for (unsigned int i = 0; i < mem_objects->size(); i++) { + mems[i] = ((*mem_objects)[i])(); + } + } + + return detail::errHandler( + ::clEnqueueNativeKernel( + object_, userFptr, args.first, args.second, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + mems, + (mem_locs != NULL) ? (const void **) &mem_locs->front() : NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_NATIVE_KERNEL); + } + + cl_int enqueueMarker(Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueMarker(object_, (cl_event*) event), + __ENQUEUE_MARKER_ERR); + } + + cl_int enqueueWaitForEvents(const VECTOR_CLASS& events) const + { + return detail::errHandler( + ::clEnqueueWaitForEvents( + object_, + (cl_uint) events.size(), + (const cl_event*) &events.front()), + __ENQUEUE_WAIT_FOR_EVENTS_ERR); + } + + cl_int enqueueAcquireGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueAcquireGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_ACQUIRE_GL_ERR); + } + + cl_int enqueueReleaseGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueReleaseGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_RELEASE_GL_ERR); + } + +#if defined (USE_DX_INTEROP) +typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); +typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); + + cl_int enqueueAcquireD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; + __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); + + return detail::errHandler( + pfn_clEnqueueAcquireD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_ACQUIRE_GL_ERR); + } + + cl_int enqueueReleaseD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; + __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); + + return detail::errHandler( + pfn_clEnqueueReleaseD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_RELEASE_GL_ERR); + } +#endif + + cl_int enqueueBarrier() const + { + return detail::errHandler( + ::clEnqueueBarrier(object_), + __ENQUEUE_BARRIER_ERR); + } + + cl_int flush() const + { + return detail::errHandler(::clFlush(object_), __FLUSH_ERR); + } + + cl_int finish() const + { + return detail::errHandler(::clFinish(object_), __FINISH_ERR); + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::CommandQueue) + +/*! \class KernelFunctor + * \brief Kernel functor interface + * + * \note Currently only functors of zero to ten arguments are supported. It + * is straightforward to add more and a more general solution, similar to + * Boost.Lambda could be followed if required in the future. + */ +class KernelFunctor +{ +private: + Kernel kernel_; + CommandQueue queue_; + NDRange offset_; + NDRange global_; + NDRange local_; + + cl_int err_; +public: + KernelFunctor() { } + + KernelFunctor( + const Kernel& kernel, + const CommandQueue& queue, + const NDRange& offset, + const NDRange& global, + const NDRange& local) : + kernel_(kernel), + queue_(queue), + offset_(offset), + global_(global), + local_(local), + err_(CL_SUCCESS) + {} + + KernelFunctor& operator=(const KernelFunctor& rhs); + + KernelFunctor(const KernelFunctor& rhs); + + cl_int getError() { return err_; } + + inline Event operator()(const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const A14& a14, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const A14& a14, + const A15& a15, + const VECTOR_CLASS* events = NULL); +}; + +inline KernelFunctor Kernel::bind( + const CommandQueue& queue, + const NDRange& offset, + const NDRange& global, + const NDRange& local) +{ + return KernelFunctor(*this,queue,offset,global,local); +} + +inline KernelFunctor Kernel::bind( + const CommandQueue& queue, + const NDRange& global, + const NDRange& local) +{ + return KernelFunctor(*this,queue,NullRange,global,local); +} + +inline KernelFunctor& KernelFunctor::operator=(const KernelFunctor& rhs) +{ + if (this == &rhs) { + return *this; + } + + kernel_ = rhs.kernel_; + queue_ = rhs.queue_; + offset_ = rhs.offset_; + global_ = rhs.global_; + local_ = rhs.local_; + + return *this; +} + +inline KernelFunctor::KernelFunctor(const KernelFunctor& rhs) : + kernel_(rhs.kernel_), + queue_(rhs.queue_), + offset_(rhs.offset_), + global_(rhs.global_), + local_(rhs.local_) +{ +} + +Event KernelFunctor::operator()(const VECTOR_CLASS* events) +{ + (void)events; + Event event; + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + kernel_.setArg(11,a12); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + kernel_.setArg(11,a12); + kernel_.setArg(12,a13); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const A14& a14, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + kernel_.setArg(11,a12); + kernel_.setArg(12,a13); + kernel_.setArg(13,a14); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const A14& a14, + const A15& a15, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + kernel_.setArg(11,a12); + kernel_.setArg(12,a13); + kernel_.setArg(13,a14); + kernel_.setArg(14,a15); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +#undef __ERR_STR +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#undef __GET_DEVICE_INFO_ERR +#undef __GET_PLATFORM_INFO_ERR +#undef __GET_DEVICE_IDS_ERR +#undef __GET_CONTEXT_INFO_ERR +#undef __GET_EVENT_INFO_ERR +#undef __GET_EVENT_PROFILE_INFO_ERR +#undef __GET_MEM_OBJECT_INFO_ERR +#undef __GET_IMAGE_INFO_ERR +#undef __GET_SAMPLER_INFO_ERR +#undef __GET_KERNEL_INFO_ERR +#undef __GET_KERNEL_WORK_GROUP_INFO_ERR +#undef __GET_PROGRAM_INFO_ERR +#undef __GET_PROGRAM_BUILD_INFO_ERR +#undef __GET_COMMAND_QUEUE_INFO_ERR + +#undef __CREATE_CONTEXT_FROM_TYPE_ERR +#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR + +#undef __CREATE_BUFFER_ERR +#undef __CREATE_SUBBUFFER_ERR +#undef __CREATE_IMAGE2D_ERR +#undef __CREATE_IMAGE3D_ERR +#undef __CREATE_SAMPLER_ERR +#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR + +#undef __CREATE_USER_EVENT_ERR +#undef __SET_USER_EVENT_STATUS_ERR +#undef __SET_EVENT_CALLBACK_ERR + +#undef __WAIT_FOR_EVENTS_ERR + +#undef __CREATE_KERNEL_ERR +#undef __SET_KERNEL_ARGS_ERR +#undef __CREATE_PROGRAM_WITH_SOURCE_ERR +#undef __CREATE_PROGRAM_WITH_BINARY_ERR +#undef __BUILD_PROGRAM_ERR +#undef __CREATE_KERNELS_IN_PROGRAM_ERR + +#undef __CREATE_COMMAND_QUEUE_ERR +#undef __SET_COMMAND_QUEUE_PROPERTY_ERR +#undef __ENQUEUE_READ_BUFFER_ERR +#undef __ENQUEUE_WRITE_BUFFER_ERR +#undef __ENQUEUE_READ_BUFFER_RECT_ERR +#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR +#undef __ENQEUE_COPY_BUFFER_ERR +#undef __ENQEUE_COPY_BUFFER_RECT_ERR +#undef __ENQUEUE_READ_IMAGE_ERR +#undef __ENQUEUE_WRITE_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR +#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR +#undef __ENQUEUE_MAP_BUFFER_ERR +#undef __ENQUEUE_MAP_IMAGE_ERR +#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR +#undef __ENQUEUE_NDRANGE_KERNEL_ERR +#undef __ENQUEUE_TASK_ERR +#undef __ENQUEUE_NATIVE_KERNEL + +#undef __UNLOAD_COMPILER_ERR +#endif //__CL_USER_OVERRIDE_ERROR_STRINGS + +#undef __GET_INFO_HELPER_WITH_RETAIN + +// Extensions +#undef __INIT_CL_EXT_FCN_PTR +#undef __CREATE_SUB_DEVICES + +#if defined(USE_CL_DEVICE_FISSION) +#undef __PARAM_NAME_DEVICE_FISSION +#endif // USE_CL_DEVICE_FISSION + +} // namespace cl + +#endif // CL_HPP_ diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp new file mode 100644 index 000000000..96f1fa582 --- /dev/null +++ b/libethash-cl/ethash_cl_miner.cpp @@ -0,0 +1,332 @@ +/* + This file is part of c-ethash. + + c-ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + c-ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file ethash_cl_miner.cpp +* @author Tim Hughes +* @date 2015 +*/ + + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include +#include "ethash_cl_miner.h" +#include "ethash_cl_miner_kernel.h" + +#define ETHASH_BYTES 32 + +// workaround lame platforms +#if !CL_VERSION_1_2 +#define CL_MAP_WRITE_INVALIDATE_REGION CL_MAP_WRITE +#define CL_MEM_HOST_READ_ONLY 0 +#endif + +#undef min +#undef max + +static void add_definition(std::string& source, char const* id, unsigned value) +{ + char buf[256]; + sprintf(buf, "#define %s %uu\n", id, value); + source.insert(source.begin(), buf, buf + strlen(buf)); +} + +ethash_cl_miner::ethash_cl_miner() +: m_opencl_1_1() +{ +} + +void ethash_cl_miner::finish() +{ + if (m_queue()) + { + m_queue.finish(); + } +} + +bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size) +{ + // store params + m_params = params; + + // get all platforms + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + debugf("No OpenCL platforms found.\n"); + return false; + } + + // use default platform + fprintf(stderr, "Using platform: %s\n", platforms[0].getInfo().c_str()); + + // get GPU device of the default platform + std::vector devices; + platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) + { + debugf("No OpenCL devices found.\n"); + return false; + } + + // use default device + unsigned device_num = 0; + cl::Device& device = devices[device_num]; + std::string device_version = device.getInfo(); + fprintf(stderr, "Using device: %s (%s)\n", device.getInfo().c_str(),device_version.c_str()); + + if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) + { + debugf("OpenCL 1.0 is not supported.\n"); + return false; + } + if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) + { + m_opencl_1_1 = true; + } + + // create context + m_context = cl::Context(std::vector(&device, &device + 1)); + m_queue = cl::CommandQueue(m_context, device); + + // use requested workgroup size, but we require multiple of 8 + m_workgroup_size = ((workgroup_size + 7) / 8) * 8; + + // patch source code + std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); + add_definition(code, "GROUP_SIZE", m_workgroup_size); + add_definition(code, "DAG_SIZE", (unsigned)(params.full_size / ETHASH_MIX_BYTES)); + add_definition(code, "ACCESSES", ETHASH_ACCESSES); + add_definition(code, "MAX_OUTPUTS", c_max_search_results); + //debugf("%s", code.c_str()); + + // create miner OpenCL program + cl::Program::Sources sources; + sources.push_back({code.c_str(), code.size()}); + + cl::Program program(m_context, sources); + try + { + program.build({device}); + } + catch (cl::Error err) + { + debugf("%s\n", program.getBuildInfo(device).c_str()); + return false; + } + m_hash_kernel = cl::Kernel(program, "ethash_hash"); + m_search_kernel = cl::Kernel(program, "ethash_search"); + + // create buffer for dag + m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, params.full_size); + + // create buffer for header + m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); + + // compute dag on CPU + { + // if this throws then it's because we probably need to subdivide the dag uploads for compatibility + void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size); + // memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap. + _fillDAG(dag_ptr); + m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); + } + + // create mining buffers + for (unsigned i = 0; i != c_num_buffers; ++i) + { + m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32*c_hash_batch_size); + m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); + } + return true; +} + +void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count) +{ + struct pending_batch + { + unsigned base; + unsigned count; + unsigned buf; + }; + std::queue pending; + + // update header constant buffer + m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header); + + /* + __kernel void ethash_combined_hash( + __global hash32_t* g_hashes, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + uint isolate + ) + */ + m_hash_kernel.setArg(1, m_header); + m_hash_kernel.setArg(2, m_dag); + m_hash_kernel.setArg(3, nonce); + m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop + + unsigned buf = 0; + for (unsigned i = 0; i < count || !pending.empty(); ) + { + // how many this batch + if (i < count) + { + unsigned const this_count = std::min(count - i, c_hash_batch_size); + unsigned const batch_count = std::max(this_count, m_workgroup_size); + + // supply output hash buffer to kernel + m_hash_kernel.setArg(0, m_hash_buf[buf]); + + // execute it! + m_queue.enqueueNDRangeKernel( + m_hash_kernel, + cl::NullRange, + cl::NDRange(batch_count), + cl::NDRange(m_workgroup_size) + ); + m_queue.flush(); + + pending.push({i, this_count, buf}); + i += this_count; + buf = (buf + 1) % c_num_buffers; + } + + // read results + if (i == count || pending.size() == c_num_buffers) + { + pending_batch const& batch = pending.front(); + + // could use pinned host pointer instead, but this path isn't that important. + uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * ETHASH_BYTES); + memcpy(ret + batch.base*ETHASH_BYTES, hashes, batch.count*ETHASH_BYTES); + m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes); + + pending.pop(); + } + } +} + + +void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook) +{ + struct pending_batch + { + uint64_t start_nonce; + unsigned buf; + }; + std::queue pending; + + static uint32_t const c_zero = 0; + + // update header constant buffer + m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); + for (unsigned i = 0; i != c_num_buffers; ++i) + { + m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); + } + +#if CL_VERSION_1_2 && 0 + cl::Event pre_return_event; + if (!m_opencl_1_1) + { + m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); + } + else +#endif + { + m_queue.finish(); + } + + /* + __kernel void ethash_combined_search( + __global hash32_t* g_hashes, // 0 + __constant hash32_t const* g_header, // 1 + __global hash128_t const* g_dag, // 2 + ulong start_nonce, // 3 + ulong target, // 4 + uint isolate // 5 + ) + */ + m_search_kernel.setArg(1, m_header); + m_search_kernel.setArg(2, m_dag); + + // pass these to stop the compiler unrolling the loops + m_search_kernel.setArg(4, target); + m_search_kernel.setArg(5, ~0u); + + + unsigned buf = 0; + for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size) + { + // supply output buffer to kernel + m_search_kernel.setArg(0, m_search_buf[buf]); + m_search_kernel.setArg(3, start_nonce); + + // execute it! + m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); + + pending.push({start_nonce, buf}); + buf = (buf + 1) % c_num_buffers; + + // read results + if (pending.size() == c_num_buffers) + { + pending_batch const& batch = pending.front(); + + // could use pinned host pointer instead + uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t)); + unsigned num_found = std::min(results[0], c_max_search_results); + + uint64_t nonces[c_max_search_results]; + for (unsigned i = 0; i != num_found; ++i) + { + nonces[i] = batch.start_nonce + results[i+1]; + } + + m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); + + bool exit = num_found && hook.found(nonces, num_found); + exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit + if (exit) + break; + + // reset search buffer if we're still going + if (num_found) + m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero); + + pending.pop(); + } + } + + // not safe to return until this is ready +#if CL_VERSION_1_2 && 0 + if (!m_opencl_1_1) + { + pre_return_event.wait(); + } +#endif +} + diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h new file mode 100644 index 000000000..e478c739f --- /dev/null +++ b/libethash-cl/ethash_cl_miner.h @@ -0,0 +1,43 @@ +#pragma once + +#define __CL_ENABLE_EXCEPTIONS +#define CL_USE_DEPRECATED_OPENCL_2_0_APIS +#include "cl.hpp" +#include +#include +#include + +class ethash_cl_miner +{ +public: + struct search_hook + { + // reports progress, return true to abort + virtual bool found(uint64_t const* nonces, uint32_t count) = 0; + virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; + }; + +public: + ethash_cl_miner(); + + bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64); + + void finish(); + void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); + void search(uint8_t const* header, uint64_t target, search_hook& hook); + +private: + enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 }; + + ethash_params m_params; + cl::Context m_context; + cl::CommandQueue m_queue; + cl::Kernel m_hash_kernel; + cl::Kernel m_search_kernel; + cl::Buffer m_dag; + cl::Buffer m_header; + cl::Buffer m_hash_buf[c_num_buffers]; + cl::Buffer m_search_buf[c_num_buffers]; + unsigned m_workgroup_size; + bool m_opencl_1_1; +}; diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl new file mode 100644 index 000000000..3c8b9dc92 --- /dev/null +++ b/libethash-cl/ethash_cl_miner_kernel.cl @@ -0,0 +1,460 @@ +// author Tim Hughes +// Tested on Radeon HD 7850 +// Hashrate: 15940347 hashes/s +// Bandwidth: 124533 MB/s +// search kernel should fit in <= 84 VGPRS (3 wavefronts) + +#define THREADS_PER_HASH (128 / 16) +#define HASHES_PER_LOOP (GROUP_SIZE / THREADS_PER_HASH) + +#define FNV_PRIME 0x01000193 + +__constant uint2 const Keccak_f1600_RC[24] = { + (uint2)(0x00000001, 0x00000000), + (uint2)(0x00008082, 0x00000000), + (uint2)(0x0000808a, 0x80000000), + (uint2)(0x80008000, 0x80000000), + (uint2)(0x0000808b, 0x00000000), + (uint2)(0x80000001, 0x00000000), + (uint2)(0x80008081, 0x80000000), + (uint2)(0x00008009, 0x80000000), + (uint2)(0x0000008a, 0x00000000), + (uint2)(0x00000088, 0x00000000), + (uint2)(0x80008009, 0x00000000), + (uint2)(0x8000000a, 0x00000000), + (uint2)(0x8000808b, 0x00000000), + (uint2)(0x0000008b, 0x80000000), + (uint2)(0x00008089, 0x80000000), + (uint2)(0x00008003, 0x80000000), + (uint2)(0x00008002, 0x80000000), + (uint2)(0x00000080, 0x80000000), + (uint2)(0x0000800a, 0x00000000), + (uint2)(0x8000000a, 0x80000000), + (uint2)(0x80008081, 0x80000000), + (uint2)(0x00008080, 0x80000000), + (uint2)(0x80000001, 0x00000000), + (uint2)(0x80008008, 0x80000000), +}; + +void keccak_f1600_round(uint2* a, uint r, uint out_size) +{ + #if !__ENDIAN_LITTLE__ + for (uint i = 0; i != 25; ++i) + a[i] = a[i].yx; + #endif + + uint2 b[25]; + uint2 t; + + // Theta + b[0] = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]; + b[1] = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]; + b[2] = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]; + b[3] = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]; + b[4] = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]; + t = b[4] ^ (uint2)(b[1].x << 1 | b[1].y >> 31, b[1].y << 1 | b[1].x >> 31); + a[0] ^= t; + a[5] ^= t; + a[10] ^= t; + a[15] ^= t; + a[20] ^= t; + t = b[0] ^ (uint2)(b[2].x << 1 | b[2].y >> 31, b[2].y << 1 | b[2].x >> 31); + a[1] ^= t; + a[6] ^= t; + a[11] ^= t; + a[16] ^= t; + a[21] ^= t; + t = b[1] ^ (uint2)(b[3].x << 1 | b[3].y >> 31, b[3].y << 1 | b[3].x >> 31); + a[2] ^= t; + a[7] ^= t; + a[12] ^= t; + a[17] ^= t; + a[22] ^= t; + t = b[2] ^ (uint2)(b[4].x << 1 | b[4].y >> 31, b[4].y << 1 | b[4].x >> 31); + a[3] ^= t; + a[8] ^= t; + a[13] ^= t; + a[18] ^= t; + a[23] ^= t; + t = b[3] ^ (uint2)(b[0].x << 1 | b[0].y >> 31, b[0].y << 1 | b[0].x >> 31); + a[4] ^= t; + a[9] ^= t; + a[14] ^= t; + a[19] ^= t; + a[24] ^= t; + + // Rho Pi + b[0] = a[0]; + b[10] = (uint2)(a[1].x << 1 | a[1].y >> 31, a[1].y << 1 | a[1].x >> 31); + b[7] = (uint2)(a[10].x << 3 | a[10].y >> 29, a[10].y << 3 | a[10].x >> 29); + b[11] = (uint2)(a[7].x << 6 | a[7].y >> 26, a[7].y << 6 | a[7].x >> 26); + b[17] = (uint2)(a[11].x << 10 | a[11].y >> 22, a[11].y << 10 | a[11].x >> 22); + b[18] = (uint2)(a[17].x << 15 | a[17].y >> 17, a[17].y << 15 | a[17].x >> 17); + b[3] = (uint2)(a[18].x << 21 | a[18].y >> 11, a[18].y << 21 | a[18].x >> 11); + b[5] = (uint2)(a[3].x << 28 | a[3].y >> 4, a[3].y << 28 | a[3].x >> 4); + b[16] = (uint2)(a[5].y << 4 | a[5].x >> 28, a[5].x << 4 | a[5].y >> 28); + b[8] = (uint2)(a[16].y << 13 | a[16].x >> 19, a[16].x << 13 | a[16].y >> 19); + b[21] = (uint2)(a[8].y << 23 | a[8].x >> 9, a[8].x << 23 | a[8].y >> 9); + b[24] = (uint2)(a[21].x << 2 | a[21].y >> 30, a[21].y << 2 | a[21].x >> 30); + b[4] = (uint2)(a[24].x << 14 | a[24].y >> 18, a[24].y << 14 | a[24].x >> 18); + b[15] = (uint2)(a[4].x << 27 | a[4].y >> 5, a[4].y << 27 | a[4].x >> 5); + b[23] = (uint2)(a[15].y << 9 | a[15].x >> 23, a[15].x << 9 | a[15].y >> 23); + b[19] = (uint2)(a[23].y << 24 | a[23].x >> 8, a[23].x << 24 | a[23].y >> 8); + b[13] = (uint2)(a[19].x << 8 | a[19].y >> 24, a[19].y << 8 | a[19].x >> 24); + b[12] = (uint2)(a[13].x << 25 | a[13].y >> 7, a[13].y << 25 | a[13].x >> 7); + b[2] = (uint2)(a[12].y << 11 | a[12].x >> 21, a[12].x << 11 | a[12].y >> 21); + b[20] = (uint2)(a[2].y << 30 | a[2].x >> 2, a[2].x << 30 | a[2].y >> 2); + b[14] = (uint2)(a[20].x << 18 | a[20].y >> 14, a[20].y << 18 | a[20].x >> 14); + b[22] = (uint2)(a[14].y << 7 | a[14].x >> 25, a[14].x << 7 | a[14].y >> 25); + b[9] = (uint2)(a[22].y << 29 | a[22].x >> 3, a[22].x << 29 | a[22].y >> 3); + b[6] = (uint2)(a[9].x << 20 | a[9].y >> 12, a[9].y << 20 | a[9].x >> 12); + b[1] = (uint2)(a[6].y << 12 | a[6].x >> 20, a[6].x << 12 | a[6].y >> 20); + + // Chi + a[0] = bitselect(b[0] ^ b[2], b[0], b[1]); + a[1] = bitselect(b[1] ^ b[3], b[1], b[2]); + a[2] = bitselect(b[2] ^ b[4], b[2], b[3]); + a[3] = bitselect(b[3] ^ b[0], b[3], b[4]); + if (out_size >= 4) + { + a[4] = bitselect(b[4] ^ b[1], b[4], b[0]); + a[5] = bitselect(b[5] ^ b[7], b[5], b[6]); + a[6] = bitselect(b[6] ^ b[8], b[6], b[7]); + a[7] = bitselect(b[7] ^ b[9], b[7], b[8]); + a[8] = bitselect(b[8] ^ b[5], b[8], b[9]); + if (out_size >= 8) + { + a[9] = bitselect(b[9] ^ b[6], b[9], b[5]); + a[10] = bitselect(b[10] ^ b[12], b[10], b[11]); + a[11] = bitselect(b[11] ^ b[13], b[11], b[12]); + a[12] = bitselect(b[12] ^ b[14], b[12], b[13]); + a[13] = bitselect(b[13] ^ b[10], b[13], b[14]); + a[14] = bitselect(b[14] ^ b[11], b[14], b[10]); + a[15] = bitselect(b[15] ^ b[17], b[15], b[16]); + a[16] = bitselect(b[16] ^ b[18], b[16], b[17]); + a[17] = bitselect(b[17] ^ b[19], b[17], b[18]); + a[18] = bitselect(b[18] ^ b[15], b[18], b[19]); + a[19] = bitselect(b[19] ^ b[16], b[19], b[15]); + a[20] = bitselect(b[20] ^ b[22], b[20], b[21]); + a[21] = bitselect(b[21] ^ b[23], b[21], b[22]); + a[22] = bitselect(b[22] ^ b[24], b[22], b[23]); + a[23] = bitselect(b[23] ^ b[20], b[23], b[24]); + a[24] = bitselect(b[24] ^ b[21], b[24], b[20]); + } + } + + // Iota + a[0] ^= Keccak_f1600_RC[r]; + + #if !__ENDIAN_LITTLE__ + for (uint i = 0; i != 25; ++i) + a[i] = a[i].yx; + #endif +} + +void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate) +{ + for (uint i = in_size; i != 25; ++i) + { + a[i] = 0; + } +#if __ENDIAN_LITTLE__ + a[in_size] ^= 0x0000000000000001; + a[24-out_size*2] ^= 0x8000000000000000; +#else + a[in_size] ^= 0x0100000000000000; + a[24-out_size*2] ^= 0x0000000000000080; +#endif + + // Originally I unrolled the first and last rounds to interface + // better with surrounding code, however I haven't done this + // without causing the AMD compiler to blow up the VGPR usage. + uint r = 0; + do + { + // This dynamic branch stops the AMD compiler unrolling the loop + // and additionally saves about 33% of the VGPRs, enough to gain another + // wavefront. Ideally we'd get 4 in flight, but 3 is the best I can + // massage out of the compiler. It doesn't really seem to matter how + // much we try and help the compiler save VGPRs because it seems to throw + // that information away, hence the implementation of keccak here + // doesn't bother. + if (isolate) + { + keccak_f1600_round((uint2*)a, r++, 25); + } + } + while (r < 23); + + // final round optimised for digest size + keccak_f1600_round((uint2*)a, r++, out_size); +} + +#define copy(dst, src, count) for (uint i = 0; i != count; ++i) { (dst)[i] = (src)[i]; } + +#define countof(x) (sizeof(x) / sizeof(x[0])) + +uint fnv(uint x, uint y) +{ + return x * FNV_PRIME ^ y; +} + +uint4 fnv4(uint4 x, uint4 y) +{ + return x * FNV_PRIME ^ y; +} + +uint fnv_reduce(uint4 v) +{ + return fnv(fnv(fnv(v.x, v.y), v.z), v.w); +} + +typedef union +{ + ulong ulongs[32 / sizeof(ulong)]; + uint uints[32 / sizeof(uint)]; +} hash32_t; + +typedef union +{ + ulong ulongs[64 / sizeof(ulong)]; + uint4 uint4s[64 / sizeof(uint4)]; +} hash64_t; + +typedef union +{ + uint uints[128 / sizeof(uint)]; + uint4 uint4s[128 / sizeof(uint4)]; +} hash128_t; + +hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate) +{ + hash64_t init; + uint const init_size = countof(init.ulongs); + uint const hash_size = countof(header->ulongs); + + // sha3_512(header .. nonce) + ulong state[25]; + copy(state, header->ulongs, hash_size); + state[hash_size] = nonce; + keccak_f1600_no_absorb(state, hash_size + 1, init_size, isolate); + + copy(init.ulongs, state, init_size); + return init; +} + +uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate) +{ + uint4 mix = init; + + // share init0 + if (thread_id == 0) + *share = mix.x; + barrier(CLK_LOCAL_MEM_FENCE); + uint init0 = *share; + + uint a = 0; + do + { + bool update_share = thread_id == (a/4) % THREADS_PER_HASH; + + #pragma unroll + for (uint i = 0; i != 4; ++i) + { + if (update_share) + { + uint m[4] = { mix.x, mix.y, mix.z, mix.w }; + *share = fnv(init0 ^ (a+i), m[i]) % DAG_SIZE; + } + barrier(CLK_LOCAL_MEM_FENCE); + + mix = fnv4(mix, g_dag[*share].uint4s[thread_id]); + } + } + while ((a += 4) != (ACCESSES & isolate)); + + return fnv_reduce(mix); +} + +hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate) +{ + ulong state[25]; + + hash32_t hash; + uint const hash_size = countof(hash.ulongs); + uint const init_size = countof(init->ulongs); + uint const mix_size = countof(mix->ulongs); + + // keccak_256(keccak_512(header..nonce) .. mix); + copy(state, init->ulongs, init_size); + copy(state + init_size, mix->ulongs, mix_size); + keccak_f1600_no_absorb(state, init_size+mix_size, hash_size, isolate); + + // copy out + copy(hash.ulongs, state, hash_size); + return hash; +} + +hash32_t compute_hash_simple( + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong nonce, + uint isolate + ) +{ + hash64_t init = init_hash(g_header, nonce, isolate); + + hash128_t mix; + for (uint i = 0; i != countof(mix.uint4s); ++i) + { + mix.uint4s[i] = init.uint4s[i % countof(init.uint4s)]; + } + + uint mix_val = mix.uints[0]; + uint init0 = mix.uints[0]; + uint a = 0; + do + { + uint pi = fnv(init0 ^ a, mix_val) % DAG_SIZE; + uint n = (a+1) % countof(mix.uints); + + #pragma unroll + for (uint i = 0; i != countof(mix.uints); ++i) + { + mix.uints[i] = fnv(mix.uints[i], g_dag[pi].uints[i]); + mix_val = i == n ? mix.uints[i] : mix_val; + } + } + while (++a != (ACCESSES & isolate)); + + // reduce to output + hash32_t fnv_mix; + for (uint i = 0; i != countof(fnv_mix.uints); ++i) + { + fnv_mix.uints[i] = fnv_reduce(mix.uint4s[i]); + } + + return final_hash(&init, &fnv_mix, isolate); +} + +typedef union +{ + struct + { + hash64_t init; + uint pad; // avoid lds bank conflicts + }; + hash32_t mix; +} compute_hash_share; + +hash32_t compute_hash( + __local compute_hash_share* share, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong nonce, + uint isolate + ) +{ + uint const gid = get_global_id(0); + + // Compute one init hash per work item. + hash64_t init = init_hash(g_header, nonce, isolate); + + // Threads work together in this phase in groups of 8. + uint const thread_id = gid % THREADS_PER_HASH; + uint const hash_id = (gid % GROUP_SIZE) / THREADS_PER_HASH; + + hash32_t mix; + uint i = 0; + do + { + // share init with other threads + if (i == thread_id) + share[hash_id].init = init; + barrier(CLK_LOCAL_MEM_FENCE); + + uint4 thread_init = share[hash_id].init.uint4s[thread_id % (64 / sizeof(uint4))]; + barrier(CLK_LOCAL_MEM_FENCE); + + uint thread_mix = inner_loop(thread_init, thread_id, share[hash_id].mix.uints, g_dag, isolate); + + share[hash_id].mix.uints[thread_id] = thread_mix; + barrier(CLK_LOCAL_MEM_FENCE); + + if (i == thread_id) + mix = share[hash_id].mix; + barrier(CLK_LOCAL_MEM_FENCE); + } + while (++i != (THREADS_PER_HASH & isolate)); + + return final_hash(&init, &mix, isolate); +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_hash_simple( + __global hash32_t* g_hashes, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + uint isolate + ) +{ + uint const gid = get_global_id(0); + g_hashes[gid] = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate); +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_search_simple( + __global volatile uint* restrict g_output, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + ulong target, + uint isolate + ) +{ + uint const gid = get_global_id(0); + hash32_t hash = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate); + if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target) + { + uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1); + g_output[slot] = gid; + } +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_hash( + __global hash32_t* g_hashes, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + uint isolate + ) +{ + __local compute_hash_share share[HASHES_PER_LOOP]; + + uint const gid = get_global_id(0); + g_hashes[gid] = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate); +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_search( + __global volatile uint* restrict g_output, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + ulong target, + uint isolate + ) +{ + __local compute_hash_share share[HASHES_PER_LOOP]; + + uint const gid = get_global_id(0); + hash32_t hash = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate); + + if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target) + { + uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1); + g_output[slot] = gid; + } +} From 3baaad82023fe6b1383f11bc14c01ef6f78cefd4 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 11 Apr 2015 16:03:56 -0400 Subject: [PATCH 013/108] test use of steady_clock for timeout --- test/net.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/net.cpp b/test/net.cpp index ec1efb360..75c67888d 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -145,6 +145,39 @@ public: bool success = false; }; +BOOST_AUTO_TEST_CASE(requestTimeout) +{ + using TimePoint = std::chrono::steady_clock::time_point; + using RequestTimeout = std::pair; + + std::chrono::milliseconds timeout(300); + std::list timeouts; + + NodeId nodeA(sha3("a")); + NodeId nodeB(sha3("b")); + timeouts.push_back(make_pair(nodeA, chrono::steady_clock::now())); + this_thread::sleep_for(std::chrono::milliseconds(100)); + timeouts.push_back(make_pair(nodeB, chrono::steady_clock::now())); + this_thread::sleep_for(std::chrono::milliseconds(210)); + + bool nodeAtriggered = false; + bool nodeBtriggered = false; + timeouts.remove_if([&](RequestTimeout const& t) + { + auto now = chrono::steady_clock::now(); + auto diff = now - t.second; + if (t.first == nodeA && diff < timeout) + nodeAtriggered = true; + if (t.first == nodeB && diff < timeout) + nodeBtriggered = true; + return (t.first == nodeA || t.first == nodeB); + }); + + BOOST_REQUIRE(nodeAtriggered == false); + BOOST_REQUIRE(nodeBtriggered == true); + BOOST_REQUIRE(timeouts.size() == 0); +} + BOOST_AUTO_TEST_CASE(isIPAddressType) { string wildcard = "0.0.0.0"; From 120f123d6dc52c92aa734eb1cca4c9d2f8a318d0 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 12 Apr 2015 04:48:32 +0200 Subject: [PATCH 014/108] first part of FindXXX.cmake changes to enable x64 msvc build --- cmake/FindCURL.cmake | 20 +++++++++++++++++--- cmake/FindJsoncpp.cmake | 18 ++++++++++++++++-- cmake/FindMHD.cmake | 20 ++++++++++++++++++-- cmake/Findjson_rpc_cpp.cmake | 35 +++++++++++++++++++++++++++++------ 4 files changed, 80 insertions(+), 13 deletions(-) diff --git a/cmake/FindCURL.cmake b/cmake/FindCURL.cmake index ba6603784..0b20c4e79 100644 --- a/cmake/FindCURL.cmake +++ b/cmake/FindCURL.cmake @@ -16,10 +16,17 @@ find_path( DOC "curl include dir" ) +# if msvc 64 build +# names from cmake's FindCURL +if (CMAKE_CL_64) + set(CURL_NAMES curl_x64 curllib_x64 libcurl_imp_x64 curllib_static_x64 libcurl_x64) +else () + set(CURL_NAMES curl curllib libcurl_imp curllib_static libcurl) +endif() + find_library( CURL_LIBRARY - # names from cmake's FindCURL - NAMES curl curllib libcurl_imp curllib_static libcurl + NAMES ${CURL_NAMES} DOC "curl library" ) @@ -30,9 +37,16 @@ set(CURL_LIBRARIES ${CURL_LIBRARY}) # same naming convention as in qt (appending debug library with d) # boost is using the same "hack" as us with "optimized" and "debug" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + + if (CMAKE_CL_64) + set(CURL_NAMES_DEBUG curld_x64 libcurld_x64) + else () + set(CURL_NAMES_DEBUG curld libcurld) + endif() + find_library( CURL_LIBRARY_DEBUG - NAMES curld libcurld + NAMES ${CURL_DEBUG} DOC "curl debug library" ) diff --git a/cmake/FindJsoncpp.cmake b/cmake/FindJsoncpp.cmake index c5b9c87d8..711ba667c 100644 --- a/cmake/FindJsoncpp.cmake +++ b/cmake/FindJsoncpp.cmake @@ -17,9 +17,16 @@ find_path( DOC "jsoncpp include dir" ) +# if msvc 64 build +if (CMAKE_CL_64) + set(JSONCPP_NAMES jsoncpp_x64) +else () + set(JSONCPP_NAMES jsoncpp) +endif() + find_library( JSONCPP_LIBRARY - NAMES jsoncpp + NAMES ${JSONCPP_NAMES} DOC "jsoncpp library" ) @@ -30,9 +37,16 @@ set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY}) # same naming convention as in qt (appending debug library with d) # boost is using the same "hack" as us with "optimized" and "debug" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + + if (CMAKE_CL_64) + set(JSONCPP_NAMES_DEBUG jsoncppd_x64) + else () + set(JSONCPP_NAMES_DEBUG jsoncppd) + endif() + find_library( JSONCPP_LIBRARY_DEBUG - NAMES jsoncppd + NAMES ${JSONCPP_NAMES_DEBUG} DOC "jsoncpp debug library" ) diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake index 5cb8a98d6..f836ce391 100755 --- a/cmake/FindMHD.cmake +++ b/cmake/FindMHD.cmake @@ -15,9 +15,16 @@ find_path( DOC "microhttpd include dir" ) +# if msvc 64 build +if (CMAKE_CL_64) + set(MHD_NAMES microhttpd_x64 microhttpd-10_x64 libmicrohttpd_x64 libmicrohttpd-dll_x64) +else () + set(MHD_NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll) +endif() + find_library( MHD_LIBRARY - NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll + NAMES ${MHD_NAMES} DOC "microhttpd library" ) @@ -34,11 +41,20 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") string(REPLACE ".lib" ".dll" MHD_DLL_RELEASE ${MHD_LIBRARY}) string(REPLACE "/lib/" "/bin/" MHD_DLL_RELEASE ${MHD_DLL_RELEASE}) + if (CMAKE_CL_64) + set(MHD_NAMES_DEBUG microhttpd_d_x64 microhttpd-10_d_x64 libmicrohttpd_d_x64 libmicrohttpd-dll_d_x64) + else () + set(MHD_NAMES_DEBUG microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d) + endif() + find_library( MHD_LIBRARY_DEBUG - NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d + NAMES ${MHD_NAMES_DEBUG} DOC "mhd debug library" ) + + set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) + # not sure why this was commented # always use release for now #string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG}) #set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) diff --git a/cmake/Findjson_rpc_cpp.cmake b/cmake/Findjson_rpc_cpp.cmake index 9b64cda2b..ca3439717 100644 --- a/cmake/Findjson_rpc_cpp.cmake +++ b/cmake/Findjson_rpc_cpp.cmake @@ -24,21 +24,32 @@ find_path( DOC "json-rpc-cpp include dir" ) +# if msvc 64 build +if (CMAKE_CL_64) + set(JSON_RPC_CPP_COMMON_NAME jsonrpccpp-common_x64) + set(JSON_RPC_CPP_SERVER_NAME jsonrpccpp-server_x64) + set(JSON_RPC_CPP_CLIENT_NAME jsonrpccpp-client_x64) +else () + set(JSON_RPC_CPP_COMMON_NAME jsonrpccpp-common) + set(JSON_RPC_CPP_SERVER_NAME jsonrpccpp-server) + set(JSON_RPC_CPP_CLIENT_NAME jsonrpccpp-client) +endif() + find_library( JSON_RPC_CPP_COMMON_LIBRARY - NAMES jsonrpccpp-common + NAMES ${JSON_RPC_CPP_COMMON_NAME} DOC "json-rpc-cpp common library" ) find_library( JSON_RPC_CPP_SERVER_LIBRARY - NAMES jsonrpccpp-server + NAMES ${JSON_RPC_CPP_SERVER_NAME} DOC "json-rpc-cpp server library" ) find_library( JSON_RPC_CPP_CLIENT_LIBRARY - NAMES jsonrpccpp-client + NAMES ${JSON_RPC_CPP_CLIENT_NAME} DOC "json-rpc-cpp client library" ) @@ -52,21 +63,33 @@ set (JSON_RPC_CPP_CLIENT_LIBRARIES ${JSON_RPC_CPP_COMMON_LIBRARY} ${JSON_RPC_CPP # same naming convention as in qt (appending debug library with d) # boost is using the same "hack" as us with "optimized" and "debug" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + + # if msvc 64 build + if (CMAKE_CL_64) + set(JSON_RPC_CPP_COMMON_NAME_DEBUG jsonrpccpp-commond_x64) + set(JSON_RPC_CPP_SERVER_NAME_DEBUG jsonrpccpp-serverd_x64) + set(JSON_RPC_CPP_CLIENT_NAME_DEBUG jsonrpccpp-clientd_x64) + else () + set(JSON_RPC_CPP_COMMON_NAME_DEBUG jsonrpccpp-commond) + set(JSON_RPC_CPP_SERVER_NAME_DEBUG jsonrpccpp-serverd) + set(JSON_RPC_CPP_CLIENT_NAME_DEBUG jsonrpccpp-clientd) + endif() + find_library( JSON_RPC_CPP_COMMON_LIBRARY_DEBUG - NAMES jsonrpccpp-commond + NAMES ${JSON_RPC_CPP_COMMON_NAME_DEBUG} DOC "json-rpc-cpp common debug library" ) find_library( JSON_RPC_CPP_SERVER_LIBRARY_DEBUG - NAMES jsonrpccpp-serverd + NAMES ${JSON_RPC_CPP_SERVER_NAME_DEBUG} DOC "json-rpc-cpp server debug library" ) find_library( JSON_RPC_CPP_CLIENT_LIBRARY_DEBUG - NAMES jsonrpccpp-clientd + NAMES ${JSON_RPC_CPP_CLIENT_NAME_DEBUG} DOC "json-rpc-cpp client debug library" ) From 121f4a23ecc28343f2759ae53ed0942aeed5f2a4 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 12 Apr 2015 04:52:19 +0200 Subject: [PATCH 015/108] new versions of precompiled windows deps (with x64) --- extdep/CMakeLists.txt | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/extdep/CMakeLists.txt b/extdep/CMakeLists.txt index e9711754f..8735328eb 100644 --- a/extdep/CMakeLists.txt +++ b/extdep/CMakeLists.txt @@ -34,23 +34,14 @@ if (ETH_COMPILE) # boost include(compile/boost.cmake) else() - eth_download(jsoncpp) - eth_download(microhttpd) - eth_download(json-rpc-cpp - VERSION 4.2 - OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/json-rpc-cpp_osx.sh - ) - - if (APPLE) - eth_download(snappy OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/snappy_osx.sh) - endif() - - eth_download(leveldb OSX_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/scripts/leveldb_osx.sh) + eth_download(curl VERSION 7.4.2) + eth_download(jsoncpp VERSION 1.6.2) + eth_download(microhttpd VERSION 0.9.2) + eth_download(json-rpc-cpp VERSION 0.5.0) eth_download(qt VERSION 5.4) + eth_download(leveldb) eth_download(cryptopp) eth_download(boost) - eth_download(curl) - endif() # will be re-eanbled later From c7c12cabe233b08401443322ef0bac78cc42e352 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 12 Apr 2015 11:32:57 +0200 Subject: [PATCH 016/108] fixed typo --- cmake/FindCURL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindCURL.cmake b/cmake/FindCURL.cmake index 0b20c4e79..60937c64e 100644 --- a/cmake/FindCURL.cmake +++ b/cmake/FindCURL.cmake @@ -46,7 +46,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") find_library( CURL_LIBRARY_DEBUG - NAMES ${CURL_DEBUG} + NAMES ${CURL_NAMES_DEBUG} DOC "curl debug library" ) From b0e0ce64010c4beafb92b8275da99aae9e99a0cc Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 12 Apr 2015 12:09:56 +0200 Subject: [PATCH 017/108] fixed modes of cmake files --- cmake/EthCompilerSettings.cmake | 0 cmake/FindMHD.cmake | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 cmake/EthCompilerSettings.cmake mode change 100755 => 100644 cmake/FindMHD.cmake diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake old mode 100755 new mode 100644 diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake old mode 100755 new mode 100644 From e7c81896675ab68b514896530fe3ec5f3c62714d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 12:14:35 +0200 Subject: [PATCH 018/108] Fixes #1597 --- libethereum/State.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 6e94a3406..e77565837 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -451,7 +451,7 @@ bool State::cull(TransactionQueue& _tq) const { try { - if (i.second.nonce() <= transactionsFrom(i.second.sender())) + if (i.second.nonce() < transactionsFrom(i.second.sender())) { _tq.drop(i.first); ret = true; From 8294f7cd47fdea4d2970b47c17b72b5f109de089 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 12 Apr 2015 12:14:53 +0200 Subject: [PATCH 019/108] comment mhd debug for now --- cmake/FindMHD.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake index f836ce391..594af2369 100644 --- a/cmake/FindMHD.cmake +++ b/cmake/FindMHD.cmake @@ -53,9 +53,8 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") DOC "mhd debug library" ) - set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) # not sure why this was commented - # always use release for now + # always use release for now, need to ask Arkadiy #string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG}) #set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) From 87bb1195a5b1caf1386b12471d5853a086c09c1d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 12:15:17 +0200 Subject: [PATCH 020/108] Half-finished Miner/Farm framework. --- libdevcore/Worker.cpp | 16 ++-- libdevcore/Worker.h | 6 +- libethcore/Miner.cpp | 12 +++ libethcore/Miner.h | 146 +++++++++++++++++++++++++++++ libethcore/ProofOfWork.cpp | 56 ++++++----- libethcore/ProofOfWork.h | 126 ++++++++----------------- libethereum/Client.cpp | 2 +- libethereum/Client.h | 4 +- libethereum/Farm.cpp | 12 +++ libethereum/Farm.h | 153 +++++++++++++++++++++++++++++++ libethereum/Miner.cpp | 2 +- libethereum/Miner.h | 97 +------------------- libethereum/TransactionQueue.cpp | 5 +- libethereum/TransactionQueue.h | 14 ++- libethereumx/Ethereum.h | 2 +- 15 files changed, 432 insertions(+), 221 deletions(-) create mode 100644 libethcore/Miner.cpp create mode 100644 libethcore/Miner.h create mode 100644 libethereum/Farm.cpp create mode 100644 libethereum/Farm.h diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 175323620..bc8fe97f2 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -39,12 +39,7 @@ void Worker::startWorking() { setThreadName(m_name.c_str()); startedWorking(); - while (!m_stop) - { - if (m_idleWaitMs) - this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); - doWork(); - } + workLoop(); cnote << "Finishing up worker thread"; doneWorking(); })); @@ -63,3 +58,12 @@ void Worker::stopWorking() cnote << "Stopped" << m_name; } +void Worker::workLoop() +{ + while (!m_stop) + { + if (m_idleWaitMs) + this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); + doWork(); + } +} diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 40bc118aa..6a35d6c4c 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -57,7 +57,11 @@ protected: virtual void startedWorking() {} /// Called continuously following sleep for m_idleWaitMs. - virtual void doWork() = 0; + virtual void doWork() {} + + /// Overrides doWork(); should call shouldStop() often and exit when true. + virtual void workLoop(); + bool shouldStop() const { return m_stop; } /// Called when is to be stopped, just prior to thread being joined. virtual void doneWorking() {} diff --git a/libethcore/Miner.cpp b/libethcore/Miner.cpp new file mode 100644 index 000000000..d6f15866f --- /dev/null +++ b/libethcore/Miner.cpp @@ -0,0 +1,12 @@ +#include "Miner.h" + +Miner::Miner() +{ + +} + +Miner::~Miner() +{ + +} + diff --git a/libethcore/Miner.h b/libethcore/Miner.h new file mode 100644 index 000000000..a7f17e565 --- /dev/null +++ b/libethcore/Miner.h @@ -0,0 +1,146 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file Miner.h + * @author Alex Leverington + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "State.h" + +namespace dev +{ + +namespace eth +{ + +struct WorkPackage +{ + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; +}; + +static const WorkPackage NullWorkPackage; + +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ + void combine(MiningProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } + double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. + double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. + double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. + unsigned hashes = 0; ///< Total number of hashes computed. + unsigned ms = 0; ///< Total number of milliseconds of mining thus far. +}; + +/** + * @brief Class for hosting one or more Miners. + * @warning Must be implemented in a threadsafe manner since it will be called from multiple + * miner threads. + */ +class FarmFace +{ +public: + /** + * @brief Called from a Miner to note a WorkPackage has a solution. + * @param _p The solution. + * @param _wp The WorkPackage that the Solution is for. + * @return true iff the solution was good (implying that mining should be . + */ + virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; +}; + +/** + * @brief A miner - a member and adoptee of the Farm. + */ +class Miner +{ +public: + using ConstructionInfo = std::pair; + + Miner(ConstructionInfo const& _ci): + m_farm(_ci.first), + m_index(_ci.second) + {} + + // API FOR THE FARM TO CALL IN WITH + + void setWork(WorkPackage const& _work = WorkPackage()) + { + Guard l(x_work); + if (_work.headerHash != h256()) + kickOff(m_work); + else if (m_work.headerHash == h256() && _work.headerHash != h256()) + pause(); + m_work = _work; + } + + unsigned index() const { return m_index; } + +protected: + + // REQUIRED TO BE REIMPLEMENTED BY A SUBCLASS: + + /** + * @brief Begin working on a given work package, discarding any previous work. + * @param _work The package for which to find a solution. + */ + virtual void kickOff(WorkPackage const& _work) = 0; + + /** + * @brief No work left to be done. Pause until told to kickOff(). + */ + virtual void pause() = 0; + + // AVAILABLE FOR A SUBCLASS TO CALL: + + /** + * @brief Notes that the Miner found a solution. + * @param _s The solution. + * @return true if the solution was correct and that the miner should pause. + */ + bool submitProof(ProofOfWork::Solution const& _s) + { + if (m_farm) + { + Guard l(x_work); + return m_farm->submitProof(_s, m_work, this); + } + return true; + } + +private: + FarmFace* m_farm = nullptr; + unsigned m_index; + + Mutex x_work; + WorkPackage m_work; +}; + +} +} diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ffa787e3e..1b3b55f4d 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -45,13 +45,38 @@ namespace dev namespace eth { -bool EthashPoW::verify(BlockInfo const& _header) +void Ethash::CPUMiner::workLoop() { - return Ethasher::verify(_header); -} + Solution solution; + + class Miner + { + public: + Miner(BlockInfo const& _header): + m_headerHash(_header.headerHash(WithoutNonce)), + m_params(Ethasher::params(_header)), + m_datasetPointer(Ethasher::get()->full(_header).data()) + {} + + inline h256 mine(uint64_t _nonce) + { + ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce); +// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer); + return h256(m_ethashReturn.result, h256::ConstructFromPointer); + } + + inline h256 lastMixHash() const + { + return h256(m_ethashReturn.mix_hash, h256::ConstructFromPointer); + } + + private: + ethash_return_value m_ethashReturn; + h256 m_headerHash; + ethash_params m_params; + void const* m_datasetPointer; + }; -std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) -{ Ethasher::Miner m(_header); std::pair ret; @@ -70,34 +95,21 @@ std::pair EthashCPU::mine(BlockInfo const& _heade double best = 1e99; // high enough to be effectively infinity :) Solution result; unsigned hashCount = 0; - for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) + for (; !shouldStop(); tryNonce++, hashCount++) { h256 val(m.mine(tryNonce)); best = std::min(best, log2((double)(u256)val)); if (val <= boundary) { - ret.first.completed = true; - assert(Ethasher::eval(_header, (Nonce)(u64)tryNonce).value == val); - result.mixHash = m.lastMixHash(); - result.nonce = u64(tryNonce); - BlockInfo test = _header; - assignResult(result, test); - assert(verify(test)); - break; + if (submitProof(solution)) + return; } } ret.first.hashes = hashCount; ret.first.best = best; ret.second = result; - if (ret.first.completed) - { - BlockInfo test = _header; - assignResult(result, test); - assert(verify(test)); - } - - return ret; + return; } #if ETH_ETHASHCL || !ETH_TRUE diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index bd8ab58db..3ea177a9a 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "BlockInfo.h" +#include "Miner.h" #define FAKE_DAGGER 1 @@ -51,39 +52,56 @@ struct MineInfo bool completed = false; }; -class EthashPoW +class EthashCLHook; + +class Ethash { -public: - struct Solution - { - Nonce nonce; - h256 mixHash; - }; - static bool verify(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } +public: - virtual unsigned defaultTimeout() const { return 100; } - virtual std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; +struct Solution +{ + Nonce nonce; + h256 mixHash; }; -class EthashCPU: public EthashPoW +static bool verify(BlockInfo const& _header); +static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + +class CPUMiner: public Miner, Worker { public: - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} -protected: - Nonce m_last; + static unsigned instances() { return thread::hardware_concurrency(); } + + void kickOff(WorkPackage const& _work) override + { + stopWorking(); + m_work = _work; + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + + WorkPackage m_work; + MineInfo m_info; }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashCLHook; -class EthashCL: public EthashPoW +class GPUMiner: public NewMiner { public: - EthashCL(); - ~EthashCL(); + GPUMiner(ConstructionInfo const& _ci): NewMiner(_ci) + { + + } + + static unsigned instances() { return 1; } std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; unsigned defaultTimeout() const override { return 500; } @@ -96,81 +114,15 @@ protected: std::unique_ptr m_hook; }; -using Ethash = EthashCL; #else -using Ethash = EthashCPU; -#endif -template -class ProofOfWorkEngine: public Evaluator -{ -public: - using Solution = Nonce; +using GPUMiner = CPUMiner; - static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; } - inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r; } - unsigned defaultTimeout() const { return 100; } - -protected: - Nonce m_last; -}; +#endif -class SHA3Evaluator -{ -public: - static h256 eval(h256 const& _root, Nonce const& _nonce) { h256 b[2] = { _root, h256(_nonce) }; return sha3(bytesConstRef((byte const*)&b[0], 64)); } }; -using SHA3ProofOfWork = ProofOfWorkEngine; - using ProofOfWork = Ethash; -template -std::pair::Solution> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) -{ - auto headerHashWithoutNonce = _header.headerHash(WithoutNonce); - auto difficulty = _header.difficulty; - - std::pair ret; - static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()))); - Nonce::Arith s = (m_last = Nonce::random(s_eng)); - - bigint d = (bigint(1) << 256) / difficulty; - ret.first.requirement = log2((double)d); - - // 2^ 0 32 64 128 256 - // [--------*-------------------------] - // - // evaluate until we run out of time - auto startTime = std::chrono::steady_clock::now(); - double best = 1e99; // high enough to be effectively infinity :) - ProofOfWorkEngine::Solution solution; - unsigned h = 0; - for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++) - { - solution = (ProofOfWorkEngine::Solution)s; - auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution); - best = std::min(best, log2((double)e)); - if (e <= d) - { - ret.first.completed = true; - break; - } - } - ret.first.hashes = h; - ret.first.best = best; - ret.second = solution; - - if (ret.first.completed) - { - BlockInfo test = _header; - assignResult(solution, test); - assert(verify(test)); - } - - return ret; -} - } } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 223384c3a..278c02fa8 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -467,7 +467,7 @@ void Client::doWork() cworkin << "WORK"; h256Set changeds; - auto maintainMiner = [&](Miner& m) + auto maintainMiner = [&](OldMiner& m) { if (m.isComplete()) { diff --git a/libethereum/Client.h b/libethereum/Client.h index ec852afd2..9af501f74 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -72,7 +72,7 @@ private: std::string m_path; }; -class RemoteMiner: public Miner +class RemoteMiner: public OldMiner { public: RemoteMiner() {} @@ -124,7 +124,7 @@ struct ClientDetail: public LogChannel { static const char* name() { return " C */ class Client: public MinerHost, public ClientBase, Worker { - friend class Miner; + friend class OldMiner; public: /// New-style Constructor. diff --git a/libethereum/Farm.cpp b/libethereum/Farm.cpp new file mode 100644 index 000000000..639e4efcf --- /dev/null +++ b/libethereum/Farm.cpp @@ -0,0 +1,12 @@ +#include "Farm.h" + +Farm::Farm() +{ + +} + +Farm::~Farm() +{ + +} + diff --git a/libethereum/Farm.h b/libethereum/Farm.h new file mode 100644 index 000000000..a49038f0d --- /dev/null +++ b/libethereum/Farm.h @@ -0,0 +1,153 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file Miner.h + * @author Alex Leverington + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "Miner.h" + +namespace dev +{ + +namespace eth +{ + +/** + * @brief A collective of Miners. + * Miners ask for work, then submit proofs + * @threadsafe + */ +template +class Farm: public FarmFace +{ +public: + /** + * @brief Sets the current mining mission. + * @param _bi The block (header) we wish to be mining. + */ + void setWork(BlockInfo const& _bi) + { + WriteGuard l(x_work); + m_header = _bi; + m_work.boundary = _bi.boundary(); + m_work.headerHash = _bi.headerHash(WithNonce); + m_work.seedHash = _bi.seedHash(); + ReadGuard l(x_miners); + for (auto const& m: miners) + m->setWork(m_work); + } + + /** + * @brief (Re)start miners for CPU only. + * @returns true if started properly. + */ + bool startCPU() { return start(); } + + /** + * @brief (Re)start miners for GPU only. + * @returns true if started properly. + */ + bool startGPU() { start(); } + + /** + * @brief Stop all mining activities. + */ + void stop() + { + WriteGuard l(x_miners); + m_miners.clear(); + } + + /** + * @brief Get information on the progress of mining this work package. + * @return The progress with mining so far. + */ + MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } + +protected: + // TO BE REIMPLEMENTED BY THE SUBCLASS + /** + * @brief Provides a valid header based upon that received previously with setWork(). + * @param _bi The now-valid header. + * @return true if the header was good and that the Farm should pause until more work is submitted. + */ + virtual bool submitHeader(BlockInfo const& _bi) = 0; + +private: + /** + * @brief Called from a Miner to note a WorkPackage has a solution. + * @param _p The solution. + * @param _wp The WorkPackage that the Solution is for. + * @return true iff the solution was good (implying that mining should be . + */ + bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp, NewMiner* _m) override + { + if (_wp.headerHash != m_work.headerHash) + return false; + + ProofOfWork::assignResult(_p, m_header); + if (submitHeader(m_header)) + { + ReadGuard l(x_miners); + for (std::shared_ptr const& m: m_miners) + if (m.get() != _m) + m->pause(); + m_work.headerHash = h256(); + return true; + } + return false; + } + + /** + * @brief Start a number of miners. + */ + template + bool start() + { + WriteGuard l(x_miners); + if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) + return true; + m_miners.clear(); + m_miners.reserve(MinerType::instances()); + for (unsigned i = 0; i < MinerType::instances(); ++i) + m_miners.push_back(new MinerType(std::make_pair(this, i))); + return true; + } + + mutable SharedMutex x_miners; + std::vector> m_miners; + + mutable SharedMutex x_progress; + MineProgress m_progress; + + mutable SharedMutex x_work; + WorkPackage m_work; + BlockInfo m_header; +}; + +} +} diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp index dc3d9bd9e..b386fe868 100644 --- a/libethereum/Miner.cpp +++ b/libethereum/Miner.cpp @@ -28,7 +28,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -Miner::~Miner() {} +OldMiner::~OldMiner() {} LocalMiner::LocalMiner(MinerHost* _host, unsigned _id) { diff --git a/libethereum/Miner.h b/libethereum/Miner.h index 86d103db5..3abf93770 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "State.h" namespace dev @@ -36,28 +37,6 @@ namespace dev namespace eth { -struct WorkPackage -{ - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; -}; - -static const WorkPackage NullWorkPackage; - -/** - * @brief Describes the progress of a mining operation. - */ -struct MineProgress -{ - void combine(MineProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } - double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. - double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. - double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. - unsigned hashes = 0; ///< Total number of hashes computed. - unsigned ms = 0; ///< Total number of milliseconds of mining thus far. -}; - /** * @brief Class for hosting one or more Miners. * @warning Must be implemented in a threadsafe manner since it will be called from multiple @@ -66,10 +45,6 @@ struct MineProgress class MinerHost { public: - // ============================= NEW API ============================= - virtual WorkPackage const& getWork() const { return NullWorkPackage; } - - // ============================= OLD API ============================= virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. virtual void onProgressed() {} ///< Called once some progress has been made. virtual void onComplete() {} ///< Called once a block is found. @@ -77,17 +52,17 @@ public: virtual bool turbo() const = 0; ///< @returns true iff the Miner should use GPU if possible. }; -class Miner +class OldMiner { public: - virtual ~Miner(); + virtual ~OldMiner(); virtual void noteStateChange() = 0; virtual bool isComplete() const = 0; virtual bytes const& blockData() const = 0; }; -class AsyncMiner: public Miner +class AsyncMiner: public OldMiner { public: /// Null constructor. @@ -187,69 +162,5 @@ private: std::list m_mineHistory; ///< What the history of our mining? }; -/** - * @brief A collective of Miners. - * Miners ask for work, then submit proofs - * @threadsafe - */ -class Farm: public MinerHost -{ -public: - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi); - - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU(); - - /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. - */ - bool startGPU(); - - /** - * @brief Stop all mining activities. - */ - void stop(); - - /** - * @brief Get information on the progress of mining this work package. - * @return The progress with mining so far. - */ - MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } - -protected: - /** - * @brief Called by a Miner to retrieve a work package. Reimplemented from MinerHost. - * @return The work package to solve. - */ - virtual WorkPackage const& getWork() const override { ReadGuard l(x_work); return m_work; } - - /** - * @brief Called from a Miner to note a WorkPackage has a solution. - * @param _p The solution. - * @param _wp The WorkPackage that the Solution is for. - * @return true iff the solution was good (implying that mining should be . - */ - virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; - -private: - mutable SharedMutex x_miners; - std::vector> m_miners; - - mutable SharedMutex x_progress; - MineProgress m_progress; - - mutable SharedMutex x_work; - WorkPackage m_work; -}; - - } } diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 38f3b9429..7c72f53e8 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -28,7 +28,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ImportResult TransactionQueue::import(bytesConstRef _transactionRLP) +ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb) { // Check if we already know this transaction. h256 h = sha3(_transactionRLP); @@ -50,7 +50,8 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP) // If valid, append to blocks. m_current[h] = t; m_known.insert(h); - + if (_cb) + m_callbacks[h] = _cb; ctxq << "Queued vaguely legit-looking transaction" << h.abridged(); } catch (Exception const& _e) diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index 73ce24fbd..ad093b4e5 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -45,8 +46,10 @@ struct TransactionQueueChannel: public LogChannel { static const char* name() { class TransactionQueue { public: - ImportResult import(bytes const& _tx) { return import(&_tx); } - ImportResult import(bytesConstRef _tx); + using ImportCallback = std::function; + + ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx); } + ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback()); void drop(h256 _txHash); @@ -59,10 +62,11 @@ public: void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); } private: - mutable boost::shared_mutex m_lock; ///< General lock. - std::set m_known; ///< Hashes of transactions in both sets. - std::map m_current; ///< Map of SHA3(tx) to tx. + mutable boost::shared_mutex m_lock; ///< General lock. + std::set m_known; ///< Hashes of transactions in both sets. + std::map m_current; ///< Map of SHA3(tx) to tx. std::multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. + std::map> m_callbacks; ///< Called once }; } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 7ff685339..15f00f4ae 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -52,7 +52,7 @@ class Client; */ class Ethereum { - friend class Miner; + friend class OldMiner; public: /// Constructor. After this, everything should be set up to go. From 71c83172c5bd55f9297113a8007f79e70bd040c5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 12:15:56 +0200 Subject: [PATCH 021/108] Fixes #1597 --- libethereum/State.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c1beee787..6d3301cd7 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -451,7 +451,7 @@ bool State::cull(TransactionQueue& _tq) const { try { - if (i.second.nonce() <= transactionsFrom(i.second.sender())) + if (i.second.nonce() < transactionsFrom(i.second.sender())) { _tq.drop(i.first); ret = true; From 927989907fbd3c1af1f30ab8f441d0e846e709ef Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 12:17:28 +0200 Subject: [PATCH 022/108] Avoid ethashcl in exp. Fixes #1594 --- exp/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 7e670cfaa..d2a0e9ead 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -23,10 +23,11 @@ endif() target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) +if (ETHASHCL) target_link_libraries(${EXECUTABLE} ethash-cl) target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} OpenCL) - +endif() install( TARGETS ${EXECUTABLE} DESTINATION bin) From 07f780fa30d827950dbabf67caa86c24c0de092a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 12:22:45 +0200 Subject: [PATCH 023/108] Fixes #1573 --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 04bbe7345..9f765935b 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -607,10 +607,10 @@ Json::Value WebThreeStubServerBase::eth_getCompilers() { Json::Value ret(Json::arrayValue); ret.append("lll"); -#if SOLIDITY +#if ETH_SOLIDITY || !TRUE ret.append("solidity"); #endif -#if SERPENT +#if ETH_SERPENT || !TRUE ret.append("serpent"); #endif return ret; @@ -632,7 +632,7 @@ string WebThreeStubServerBase::eth_compileSerpent(string const& _code) // TODO throw here jsonrpc errors string res; (void)_code; -#if SERPENT +#if ETH_SERPENT || !TRUE try { res = toJS(dev::asBytes(::compile(_code))); @@ -654,7 +654,7 @@ string WebThreeStubServerBase::eth_compileSolidity(string const& _code) // TOOD throw here jsonrpc errors (void)_code; string res; -#if SOLIDITY +#if ETH_SOLIDITY || !TRUE dev::solidity::CompilerStack compiler; try { From cc82d9fbc5db0484af98c2f4d1995a14a314f655 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 15:26:37 +0200 Subject: [PATCH 024/108] GPU Miner prototyped in new API. --- libethcore/Ethasher.cpp | 134 +++++++++++++++++++------------------ libethcore/Ethasher.h | 10 ++- libethcore/ProofOfWork.cpp | 88 ++++++++++++------------ libethcore/ProofOfWork.h | 32 ++++----- 4 files changed, 135 insertions(+), 129 deletions(-) diff --git a/libethcore/Ethasher.cpp b/libethcore/Ethasher.cpp index 6cd2504b3..2118952eb 100644 --- a/libethcore/Ethasher.cpp +++ b/libethcore/Ethasher.cpp @@ -39,6 +39,8 @@ using namespace chrono; using namespace dev; using namespace eth; +#define ETH_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} + Ethasher* dev::eth::Ethasher::s_this = nullptr; Ethasher::~Ethasher() @@ -59,28 +61,35 @@ void Ethasher::killCache(h256 const& _s) void const* Ethasher::light(BlockInfo const& _header) { - RecursiveGuard l(x_this); - if (_header.number > c_ethashEpochLength * 2048) - { - std::ostringstream error; - error << "block number is too high; max is " << c_ethashEpochLength * 2048 << "(was " << _header.number << ")"; - throw std::invalid_argument( error.str() ); - } + return light(_header.seedHash()); +} +void const* Ethasher::light(h256 const& _seedHash) +{ + RecursiveGuard l(x_this); if (!m_lights.count(_header.seedHash())) { - ethash_params p = params((unsigned)_header.number); - m_lights[_header.seedHash()] = ethash_new_light(&p, _header.seedHash().data()); + ethash_params p = params(_seedHash); + m_lights[_seedHash] = ethash_new_light(&p, _seedHash.data()); } - return m_lights[_header.seedHash()]; + return m_lights[_seedHash]; } -#define IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} +bytesConstRef Ethasher::full(BlockInfo const& _header, bytesRef _dest) +{ + return full(_header.seedHash(), _dest); +} -bytesConstRef Ethasher::full(BlockInfo const& _header) +bytesConstRef Ethasher::full(h256 const& _seedHash, bytesRef _dest) { RecursiveGuard l(x_this); - if (!m_fulls.count(_header.seedHash())) + if (m_fulls.count(_seedHash) && _dest) + { + assert(m_fulls.size() <= _dest.size()); + m_fulls.at(_seedHash).copyTo(_dest); + return; + } + if (!m_fulls.count(_seedHash)) { // @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr. /* if (!m_fulls.empty()) @@ -93,9 +102,9 @@ bytesConstRef Ethasher::full(BlockInfo const& _header) boost::filesystem::create_directories(getDataDir("ethash")); } catch (...) {} - auto info = rlpList(c_ethashRevision, _header.seedHash()); + auto info = rlpList(c_ethashRevision, _seedHash); std::string oldMemoFile = getDataDir("ethash") + "/full"; - std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_header.seedHash().ref().cropped(0, 8)); + std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_seedHash.ref().cropped(0, 8)); if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) { // memofile valid - rename. @@ -105,17 +114,26 @@ bytesConstRef Ethasher::full(BlockInfo const& _header) IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); - m_fulls[_header.seedHash()] = contentsNew(memoFile); - if (!m_fulls[_header.seedHash()]) + ethash_params p = params(_seedHash); + assert(!_dest || _dest.size() >= p.full_size); // must be big enough. + + bytesRef r = contentsNew(memoFile, _dest); + if (!r) { - ethash_params p = params((unsigned)_header.number); - m_fulls[_header.seedHash()] = bytesRef(new byte[p.full_size], p.full_size); - auto c = light(_header); - ethash_prep_full(m_fulls[_header.seedHash()].data(), &p, c); - writeFile(memoFile, m_fulls[_header.seedHash()]); + // file didn't exist. + if (_dest) + // buffer was passed in - no insertion into cache nor need to allocate + r = _dest; + else + r = bytesRef(new byte[p.full_size], p.full_size); + ethash_prep_full(r, &p, light(_seedHash)); + writeFile(memoFile, r); } + if (_dest) + return _dest; + m_fulls[_seedHash] = r; } - return m_fulls[_header.seedHash()]; + return m_fulls[_seedHash]; } ethash_params Ethasher::params(BlockInfo const& _header) @@ -123,44 +141,6 @@ ethash_params Ethasher::params(BlockInfo const& _header) return params((unsigned)_header.number); } -void Ethasher::readFull(BlockInfo const& _header, void* _dest) -{ - if (!m_fulls.count(_header.seedHash())) - { - // @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr. -/* if (!m_fulls.empty()) - { - delete [] m_fulls.begin()->second.data(); - m_fulls.erase(m_fulls.begin()); - }*/ - - try { - boost::filesystem::create_directories(getDataDir("ethash")); - } catch (...) {} - - auto info = rlpList(c_ethashRevision, _header.seedHash()); - std::string oldMemoFile = getDataDir("ethash") + "/full"; - std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_header.seedHash().ref().cropped(0, 8)); - if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) - { - // memofile valid - rename. - boost::filesystem::rename(oldMemoFile, memoFile); - } - - IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); - IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); - - ethash_params p = params((unsigned)_header.number); - bytesRef r = contentsNew(memoFile, bytesRef((byte*)_dest, p.full_size)); - if (!r) - { - auto c = light(_header); - ethash_prep_full(_dest, &p, c); - writeFile(memoFile, bytesConstRef((byte*)_dest, p.full_size)); - } - } -} - ethash_params Ethasher::params(unsigned _n) { ethash_params p; @@ -169,6 +149,27 @@ ethash_params Ethasher::params(unsigned _n) return p; } +ethash_params Ethasher::params(h256 const& _seedHash) +{ + unsigned epoch = 0; + try + { + epoch = m_seedHashes.at(_seedHash); + } + catch (...) + { + for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = h256(h)) {} + if (epoch == 2048) + { + std::ostringstream error; + error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (c_ethashEpochLength * 2048); + throw std::invalid_argument(error.str()); + } + m_seedHashes[_seedHash] = epoch; + } + return params(epoch * c_ethashEpochLength); +} + bool Ethasher::verify(BlockInfo const& _header) { if (_header.number >= c_ethashEpochLength * 2048) @@ -208,13 +209,18 @@ bool Ethasher::verify(BlockInfo const& _header) } Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce) +{ + return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); +} + +Ethasher::Result Ethasher::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { auto p = Ethasher::params(_header); ethash_return_value r; - if (Ethasher::get()->m_fulls.count(_header.seedHash())) - ethash_compute_full(&r, Ethasher::get()->full(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); + if (Ethasher::get()->m_fulls.count(_seedHash)) + ethash_compute_full(&r, Ethasher::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); else - ethash_compute_light(&r, Ethasher::get()->light(_header), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); + ethash_compute_light(&r, Ethasher::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce); // cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; } diff --git a/libethcore/Ethasher.h b/libethcore/Ethasher.h index 32622929f..f57c2f4f6 100644 --- a/libethcore/Ethasher.h +++ b/libethcore/Ethasher.h @@ -52,12 +52,14 @@ public: using FullType = void const*; LightType light(BlockInfo const& _header); - bytesConstRef full(BlockInfo const& _header); + LightType light(h256 const& _header); + bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef()); + bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef()); + static ethash_params params(BlockInfo const& _header); + static ethash_params params(h256 const& _seedHash); static ethash_params params(unsigned _n); - void readFull(BlockInfo const& _header, void* _dest); - struct Result { h256 value; @@ -66,6 +68,7 @@ public: static Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } static Result eval(BlockInfo const& _header, Nonce const& _nonce); + static Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); static bool verify(BlockInfo const& _header); class Miner @@ -103,6 +106,7 @@ private: RecursiveMutex x_this; std::map m_lights; std::map m_fulls; + std::map m_seedHashes; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index 1b3b55f4d..97488ee35 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -31,7 +31,7 @@ #include #include #include -#if ETH_ETHASHCL +#if ETH_ETHASHCL || !ETH_TRUE #include #endif #include "BlockInfo.h" @@ -134,10 +134,15 @@ public: }; */ -struct EthashCLHook: public ethash_cl_miner::search_hook +namespace dev { namespace eth { +class EthashCLHook: public ethash_cl_miner::search_hook { +public: + EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + void abort() { + Guard l(x_all); if (m_aborted) return; // cdebug << "Attempting to abort"; @@ -147,21 +152,23 @@ struct EthashCLHook: public ethash_cl_miner::search_hook if (!m_aborted) cwarn << "Couldn't abort. Abandoning OpenCL process."; m_aborted = m_abort = false; - m_found.clear(); } - vector fetchFound() { vector ret; Guard l(x_all); std::swap(ret, m_found); return ret; } uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; } protected: virtual bool found(uint64_t const* _nonces, uint32_t _count) override { - Guard l(x_all); - for (unsigned i = 0; i < _count; ++i) - m_found.push_back((Nonce)(u64)_nonces[i]); - m_aborted = true; // cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); - return true; + for (uint32_t i = 0; i < _count; ++i) + { + if (m_owner->found(_nonces[i])) + { + m_aborted = true; + return true; + } + } + return false; } virtual bool searched(uint64_t _startNonce, uint32_t _count) override @@ -180,66 +187,53 @@ protected: private: Mutex x_all; - vector m_found; uint64_t m_total; uint64_t m_last; bool m_abort = false; bool m_aborted = true; + Ethash::GPUMiner* m_owner = nullptr; }; -EthashCL::EthashCL(): - m_hook(new EthashCLHook) +} } + +Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): + Miner(_ci), + m_hook(new EthashCLHook(this)) { } -EthashCL::~EthashCL() +void Ethash::GPUMiner::report(uint64_t _nonce) { + Nonce n = (Nonce)(u64)_nonce; + Ethasher::Result r = Ethasher::eval(m_work.seedHash, m_work.headerHash, n); + if (r.value < m_work.boundary) + return submitProof(Solution{n, r.mixHash}); + return false; } -std::pair EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool) +void Ethash::GPUMiner::kickOff(WorkPackage const& _work) { - if (!m_lastHeader || m_lastHeader.seedHash() != _header.seedHash()) + if (!m_miner || m_minerSeed != _work.seedHash) { if (m_miner) m_hook->abort(); m_miner.reset(new ethash_cl_miner); - auto cb = [&](void* d) { - Ethasher::get()->readFull(_header, d); - }; - m_miner->init(Ethasher::params(_header), cb, 32); + auto p = Ethasher::params(_work.seedHash); + auto cb = [&](void* d) { Ethasher::get()->readFull(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; + m_miner->init(p, cb, 32); } - if (m_lastHeader != _header) + if (m_lastWork.headerHash != _work.headerHash) { m_hook->abort(); - static std::random_device s_eng; - auto hh = _header.headerHash(WithoutNonce); - uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_header.boundary() >> 192); - m_miner->search(hh.data(), upper64OfBoundary, *m_hook); + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); + m_miner->search(_work.headerHash, upper64OfBoundary, *m_hook); } - m_lastHeader = _header; - - MineInfo mi; - Solution proof; - mi.requirement = log2((double)(u256)_header.boundary()); - mi.best = 0; - - std::this_thread::sleep_for(chrono::milliseconds(_msTimeout)); + m_work = _work; +} - mi.hashes += m_hook->fetchTotal(); - auto found = m_hook->fetchFound(); - if (!found.empty()) - { - for (auto const& n: found) - { - auto result = Ethasher::eval(_header, n); - if (result.value < _header.boundary()) - { - mi.completed = true; - proof = Solution{n, result.mixHash}; - } - } - } - return std::make_pair(mi, proof); +void Ethash::GPUMiner::pause() +{ + m_hook->abort(); } #endif diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 3ea177a9a..f66bc77c9 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -34,7 +34,6 @@ #define FAKE_DAGGER 1 class ethash_cl_miner; -struct ethash_cl_search_hook; namespace dev { @@ -52,8 +51,6 @@ struct MineInfo bool completed = false; }; -class EthashCLHook; - class Ethash { @@ -75,6 +72,7 @@ public: static unsigned instances() { return thread::hardware_concurrency(); } +protected: void kickOff(WorkPackage const& _work) override { stopWorking(); @@ -93,25 +91,29 @@ private: #if ETH_ETHASHCL || !ETH_TRUE -class GPUMiner: public NewMiner +class EthashCLHook; + +class GPUMiner: public Miner { -public: - GPUMiner(ConstructionInfo const& _ci): NewMiner(_ci) - { + friend class EthashCLHook; - } +public: + GPUMiner(ConstructionInfo const& _ci); static unsigned instances() { return 1; } - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; - unsigned defaultTimeout() const override { return 500; } - protected: - Nonce m_last; - BlockInfo m_lastHeader; - Nonce m_mined; - std::unique_ptr m_miner; + void kickOff(WorkPackage const& _work) override; + void pause() override; + +private: + void report(uint64_t _nonce); + std::unique_ptr m_hook; + std::unique_ptr m_miner; + h256 m_minerSeed; + WorkPackage m_lastWork; ///< Work loaded into m_miner. + MineInfo m_info; }; #else From 2eab7a7c22883cfda35f341609f6af53b05ebc72 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 16:34:35 +0200 Subject: [PATCH 025/108] Fixes some build issues. --- libethereum/Client.cpp | 2 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 4b197797f..87eff7f08 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -369,7 +369,7 @@ MineProgress Client::miningProgress() const uint64_t Client::hashrate() const { - uint64_t ret; + uint64_t ret = 0; ReadGuard l(x_localMiners); for (LocalMiner const& m: m_localMiners) ret += m.miningProgress().hashes / m.miningProgress().ms; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 9f765935b..5b6c833bc 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -26,7 +26,7 @@ #include #include -#if ETH_SOLIDITY +#if ETH_SOLIDITY || !ETH_TRUE #include #include #include @@ -38,7 +38,7 @@ #include #include #include -#if ETH_SERPENT +#if ETH_SERPENT || !ETH_TRUE #include #endif #include "WebThreeStubServerBase.h" @@ -632,7 +632,7 @@ string WebThreeStubServerBase::eth_compileSerpent(string const& _code) // TODO throw here jsonrpc errors string res; (void)_code; -#if ETH_SERPENT || !TRUE +#if ETH_SERPENT || !ETH_TRUE try { res = toJS(dev::asBytes(::compile(_code))); @@ -654,7 +654,7 @@ string WebThreeStubServerBase::eth_compileSolidity(string const& _code) // TOOD throw here jsonrpc errors (void)_code; string res; -#if ETH_SOLIDITY || !TRUE +#if ETH_SOLIDITY || !ETH_TRUE dev::solidity::CompilerStack compiler; try { From 97a18e33feb60d72630ee26837cde4a775313dd9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 16:36:11 +0200 Subject: [PATCH 026/108] Avoid llvm warning. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 87eff7f08..d8723430d 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -264,7 +264,7 @@ static string filtersToString(T const& _fs) { stringstream ret; ret << "{"; - bool i = false; + unsigned i = 0; for (h256 const& f: _fs) ret << (i++ ? ", " : "") << (f == PendingChangedFilter ? "pending" : f == ChainChangedFilter ? "chain" : f.abridged()); ret << "}"; From 2fb7883a12b8ffed27fa025cdb1bbd86da7f112f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 20:17:33 +0200 Subject: [PATCH 027/108] Refactor just about everything important in the core. TODO: make compile :-) --- libethcore/Common.cpp | 2 - libethcore/Common.h | 37 +++ libethcore/Ethash.cpp | 241 ++++++++++++++++ libethcore/Ethash.h | 128 +++++++++ libethcore/{Ethasher.cpp => EthashAux.cpp} | 144 ++++------ libethcore/EthashAux.h | 63 +++++ libethcore/Ethasher.h | 113 -------- libethcore/Miner.cpp | 12 - libethcore/Miner.h | 38 ++- libethcore/ProofOfWork.cpp | 220 +-------------- libethcore/ProofOfWork.h | 109 +------- libethereum/BlockChain.cpp | 29 +- libethereum/BlockChain.h | 5 +- libethereum/BlockQueue.cpp | 1 + libethereum/BlockQueue.h | 3 + libethereum/Client.cpp | 309 +++++++++------------ libethereum/Client.h | 67 +++-- libethereum/ClientBase.h | 2 - libethereum/Farm.cpp | 12 - libethereum/Farm.h | 41 +-- libethereum/State.cpp | 14 - libethereum/State.h | 31 +-- libethereum/TransactionQueue.cpp | 1 + libethereum/TransactionQueue.h | 6 +- 24 files changed, 801 insertions(+), 827 deletions(-) create mode 100644 libethcore/Ethash.cpp create mode 100644 libethcore/Ethash.h rename libethcore/{Ethasher.cpp => EthashAux.cpp} (60%) create mode 100644 libethcore/EthashAux.h delete mode 100644 libethcore/Ethasher.h diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 572ade3e2..f0e749aaa 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -22,7 +22,6 @@ #include "Common.h" #include #include -#include "Ethasher.h" #include "Exceptions.h" using namespace std; using namespace dev; @@ -33,7 +32,6 @@ namespace dev namespace eth { -const unsigned c_ethashVersion = c_ethashRevision; const unsigned c_protocolVersion = 60; const unsigned c_minorProtocolVersion = 0; const unsigned c_databaseBaseVersion = 9; diff --git a/libethcore/Common.h b/libethcore/Common.h index ec826d2d1..b5291648b 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -96,5 +96,42 @@ enum class ImportResult BadChain }; +class Signal; + +class Handler +{ +public: + Handler() = default; + Handler(Handler const&) = delete; + ~Handler() { reset(); } + + Handler& operator=(Handler const& _h) = delete; + + void reset(); + +private: + Handler(unsigned _i, Signal* _s): m_i(_i), m_s(_s) {} + + unsigned m_i = 0; + Signal* m_s = nullptr; +}; + +/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight. +class Signal +{ +public: + using Callback = std::function; + using Callbacks = std::vector; + + Handler add(Callback const& _h) { auto n = m_onReady.size() ? m_onReady.rbegin()->first + 1 : 0; m_onReady[n] = _h; return Handler(n, this); } + + void operator()() { for (auto const& f: m_fire) f.second(); } + +private: + std::map m_fire; +}; + +inline void Handler::reset() { if (m_s) m_s->m_fire->erase(m_i); m_s = nullptr; } + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp new file mode 100644 index 000000000..82e349b4c --- /dev/null +++ b/libethcore/Ethash.cpp @@ -0,0 +1,241 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Ethash.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Ethash.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if ETH_ETHASHCL || !ETH_TRUE +#include +#endif +#include "BlockInfo.h" +#include "EthashAux.h" +using namespace std; +using namespace std::chrono; + +namespace dev +{ +namespace eth +{ + +const Ethash::WorkPackage Ethash::NullWorkPackage; + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::prep(BlockInfo const& _header) +{ + if (_header.number % ETHASH_EPOCH_LENGTH == 1) + EthashAux::full(bi); +} + +bool Ethash::preVerify(BlockInfo const& _header) +{ + if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + return false; + + h256 boundary = u256((bigint(1) << 256) / _header.difficulty); + + return ethash_quick_check_difficulty( + _header.headerHash(WithoutNonce).data(), + (uint64_t)(u64)_header.nonce, + _header.mixHash.data(), + boundary.data()); +} + +bool Ethash::verify(BlockInfo const& _header) +{ + bool pre = preVerify(_header); +#if !ETH_DEBUG + if (!pre) + return false; +#endif + + h256 boundary = u256((bigint(1) << 256) / _header.difficulty); + auto result = eval(_header); + bool slow = result.value <= boundary && result.mixHash == _header.mixHash; + +#if ETH_DEBUG || !ETH_TRUE + if (!pre && slow) + { + cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; + cwarn << "headerHash:" << _header.headerHash(WithoutNonce); + cwarn << "nonce:" << _header.nonce; + cwarn << "mixHash:" << _header.mixHash; + cwarn << "difficulty:" << _header.difficulty; + cwarn << "boundary:" << boundary; + cwarn << "result.value:" << result.value; + cwarn << "result.mixHash:" << result.mixHash; + } +#endif + + return slow; +} + +void Ethash::CPUMiner::workLoop() +{ + auto tid = std::this_thread::get_id(); + static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); + + uint64_t tryNonce = Nonce::random(s_eng); + ethash_return_value ethashReturn; + + auto p = Ethash::params(m_work.seedHash); + void const* dagPointer = Ethash::full(m_work.headerHash).data(); + uint8_t const* headerHashPointer = m_work.headerHash.data(); + h256 boundary = m_work.boundary(); + unsigned hashCount = 0; + for (; !shouldStop(); tryNonce++, hashCount++) + { + ethash_compute_full(ðashReturn, dagPointer, &p, headerHashPointer, tryNonce); + h256 value = h256(ethashReturn.result, h256::ConstructFromPointer); + if (value <= boundary && submitProof(Solution{value, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) + break; + } +} + +#if ETH_ETHASHCL || !ETH_TRUE + +namespace dev { namespace eth { + +class EthashCLHook: public ethash_cl_miner::search_hook +{ +public: + EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + + void abort() + { + Guard l(x_all); + if (m_aborted) + return; +// cdebug << "Attempting to abort"; + m_abort = true; + for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) + std::this_thread::sleep_for(chrono::milliseconds(30)); + if (!m_aborted) + cwarn << "Couldn't abort. Abandoning OpenCL process."; + m_aborted = m_abort = false; + } + + uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; } + +protected: + virtual bool found(uint64_t const* _nonces, uint32_t _count) override + { +// cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); + for (uint32_t i = 0; i < _count; ++i) + { + if (m_owner->found(_nonces[i])) + { + m_aborted = true; + return true; + } + } + return false; + } + + virtual bool searched(uint64_t _startNonce, uint32_t _count) override + { + Guard l(x_all); +// cdebug << "Searched" << _count << "from" << _startNonce; + m_total += _count; + m_last = _startNonce + _count; + if (m_abort) + { + m_aborted = true; + return true; + } + return false; + } + +private: + Mutex x_all; + uint64_t m_total; + uint64_t m_last; + bool m_abort = false; + bool m_aborted = true; + Ethash::GPUMiner* m_owner = nullptr; +}; + +} } + +Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): + Miner(_ci), + m_hook(new EthashCLHook(this)) +{ +} + +void Ethash::GPUMiner::report(uint64_t _nonce) +{ + Nonce n = (Nonce)(u64)_nonce; + Result r = Ethash::eval(m_work.seedHash, m_work.headerHash, n); + if (r.value < m_work.boundary) + return submitProof(Solution{n, r.mixHash}); + return false; +} + +void Ethash::GPUMiner::kickOff(WorkPackage const& _work) +{ + if (!m_miner || m_minerSeed != _work.seedHash) + { + if (m_miner) + m_hook->abort(); + m_miner.reset(new ethash_cl_miner); + auto p = Ethash::params(_work.seedHash); + auto cb = [&](void* d) { EthashAux::readFull(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; + m_miner->init(p, cb, 32); + } + if (m_lastWork.headerHash != _work.headerHash) + { + m_hook->abort(); + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); + m_miner->search(_work.headerHash, upper64OfBoundary, *m_hook); + } + m_work = _work; +} + +void Ethash::GPUMiner::pause() +{ + m_hook->abort(); +} + +#endif + +} +} diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h new file mode 100644 index 000000000..bdd6bf6c5 --- /dev/null +++ b/libethcore/Ethash.h @@ -0,0 +1,128 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Ethash.h + * @author Gav Wood + * @date 2014 + * + * A proof of work algorithm. + */ + +#pragma once + +#include +#include +#include +#include "Common.h" +#include "BlockInfo.h" +#include "Miner.h" + +class ethash_cl_miner; + +namespace dev +{ +namespace eth +{ + +class Ethash +{ +public: + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + static std::string name(); + static unsigned revision(); + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + static void prep(BlockInfo const& _header); + + class CPUMiner: public Miner, Worker + { + public: + CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} + + static unsigned instances() { return thread::hardware_concurrency(); } + + protected: + void kickOff(WorkPackage const& _work) override + { + stopWorking(); + m_work = _work; + startWorking(); + } + + void pause() override { stopWorking(); } + + private: + void workLoop() override; + + WorkPackage m_work; + MineInfo m_info; + }; + +#if ETH_ETHASHCL || !ETH_TRUE + class EthashCLHook; + class GPUMiner: public Miner + { + friend class EthashCLHook; + + public: + GPUMiner(ConstructionInfo const& _ci); + + static unsigned instances() { return 1; } + + protected: + void kickOff(WorkPackage const& _work) override; + void pause() override; + + private: + void report(uint64_t _nonce); + + std::unique_ptr m_hook; + std::unique_ptr m_miner; + h256 m_minerSeed; + WorkPackage m_lastWork; ///< Work loaded into m_miner. + MineInfo m_info; + }; +#else + using GPUMiner = CPUMiner; +#endif +}; + +using ProofOfWork = Ethash; +using Solution = Ethash::Solution; + +} +} diff --git a/libethcore/Ethasher.cpp b/libethcore/EthashAux.cpp similarity index 60% rename from libethcore/Ethasher.cpp rename to libethcore/EthashAux.cpp index 2118952eb..a6143e264 100644 --- a/libethcore/Ethasher.cpp +++ b/libethcore/EthashAux.cpp @@ -14,11 +14,13 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file Ethasher.cpp +/** @file EthashAux.cpp * @author Gav Wood * @date 2014 */ +#include "EthashAux.h" + #include #include #include @@ -33,7 +35,6 @@ #include #include #include "BlockInfo.h" -#include "Ethasher.h" using namespace std; using namespace chrono; using namespace dev; @@ -41,15 +42,50 @@ using namespace eth; #define ETH_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} -Ethasher* dev::eth::Ethasher::s_this = nullptr; +EthashAux* dev::eth::EthashAux::s_this = nullptr; -Ethasher::~Ethasher() +EthashAux::~EthashAux() { while (!m_lights.empty()) killCache(m_lights.begin()->first); } -void Ethasher::killCache(h256 const& _s) +ethash_params EthashAux::params(BlockInfo const& _header) +{ + return params((unsigned)_header.number); +} + +ethash_params EthashAux::params(unsigned _n) +{ + ethash_params p; + p.cache_size = ethash_get_cachesize(_n); + p.full_size = ethash_get_datasize(_n); + return p; +} + +ethash_params EthashAux::params(h256 const& _seedHash) +{ + RecursiveGuard l(get()->x_this); + unsigned epoch = 0; + try + { + epoch = get()->m_seedHashes.at(_seedHash); + } + catch (...) + { + for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = h256(h)) {} + if (epoch == 2048) + { + std::ostringstream error; + error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048); + throw std::invalid_argument(error.str()); + } + get()->m_seedHashes[_seedHash] = epoch; + } + return params(epoch * ETHASH_EPOCH_LENGTH); +} + +void EthashAux::killCache(h256 const& _s) { RecursiveGuard l(x_this); if (m_lights.count(_s)) @@ -59,12 +95,12 @@ void Ethasher::killCache(h256 const& _s) } } -void const* Ethasher::light(BlockInfo const& _header) +void const* EthashAux::light(BlockInfo const& _header) { return light(_header.seedHash()); } -void const* Ethasher::light(h256 const& _seedHash) +void const* EthashAux::light(h256 const& _seedHash) { RecursiveGuard l(x_this); if (!m_lights.count(_header.seedHash())) @@ -75,12 +111,12 @@ void const* Ethasher::light(h256 const& _seedHash) return m_lights[_seedHash]; } -bytesConstRef Ethasher::full(BlockInfo const& _header, bytesRef _dest) +bytesConstRef EthashAux::full(BlockInfo const& _header, bytesRef _dest) { return full(_header.seedHash(), _dest); } -bytesConstRef Ethasher::full(h256 const& _seedHash, bytesRef _dest) +bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) { RecursiveGuard l(x_this); if (m_fulls.count(_seedHash) && _dest) @@ -102,9 +138,9 @@ bytesConstRef Ethasher::full(h256 const& _seedHash, bytesRef _dest) boost::filesystem::create_directories(getDataDir("ethash")); } catch (...) {} - auto info = rlpList(c_ethashRevision, _seedHash); + auto info = rlpList(revision(), _seedHash); std::string oldMemoFile = getDataDir("ethash") + "/full"; - std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_seedHash.ref().cropped(0, 8)); + std::string memoFile = getDataDir("ethash") + "/full-R" + toString(ETHASH_REVISION) + "-" + toHex(_seedHash.ref().cropped(0, 8)); if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) { // memofile valid - rename. @@ -136,91 +172,19 @@ bytesConstRef Ethasher::full(h256 const& _seedHash, bytesRef _dest) return m_fulls[_seedHash]; } -ethash_params Ethasher::params(BlockInfo const& _header) -{ - return params((unsigned)_header.number); -} - -ethash_params Ethasher::params(unsigned _n) -{ - ethash_params p; - p.cache_size = ethash_get_cachesize(_n); - p.full_size = ethash_get_datasize(_n); - return p; -} - -ethash_params Ethasher::params(h256 const& _seedHash) -{ - unsigned epoch = 0; - try - { - epoch = m_seedHashes.at(_seedHash); - } - catch (...) - { - for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = h256(h)) {} - if (epoch == 2048) - { - std::ostringstream error; - error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (c_ethashEpochLength * 2048); - throw std::invalid_argument(error.str()); - } - m_seedHashes[_seedHash] = epoch; - } - return params(epoch * c_ethashEpochLength); -} - -bool Ethasher::verify(BlockInfo const& _header) -{ - if (_header.number >= c_ethashEpochLength * 2048) - return false; - - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - - bool quick = ethash_quick_check_difficulty( - _header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - _header.mixHash.data(), - boundary.data()); - -#if !ETH_DEBUG - if (!quick) - return false; -#endif - - auto result = eval(_header); - bool slow = result.value <= boundary && result.mixHash == _header.mixHash; - -#if ETH_DEBUG - if (!quick && slow) - { - cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << boundary; - cwarn << "result.value:" << result.value; - cwarn << "result.mixHash:" << result.mixHash; - } -#endif - - return slow; -} - -Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce) +Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); } -Ethasher::Result Ethasher::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { - auto p = Ethasher::params(_header); + auto p = EthashAux::params(_header); ethash_return_value r; - if (Ethasher::get()->m_fulls.count(_seedHash)) - ethash_compute_full(&r, Ethasher::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); + if (EthashAux::get()->m_fulls.count(_seedHash)) + ethash_compute_full(&r, EthashAux::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); else - ethash_compute_light(&r, Ethasher::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce); -// cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); + ethash_compute_light(&r, EthashAux::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce); +// cdebug << "EthashAux::eval sha3(cache):" << sha3(EthashAux::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h new file mode 100644 index 000000000..bfd01a594 --- /dev/null +++ b/libethcore/EthashAux.h @@ -0,0 +1,63 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file EthashAux.cpp + * @author Gav Wood + * @date 2014 + */ + +#include +#include "Ethash.h" + +namespace dev +{ +namespace eth{ + +class EthashAux +{ + EthashAux() {} + ~EthashAux(); + + static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; } + + using LightType = void const*; + using FullType = void const*; + + static ethash_params params(BlockInfo const& _header); + static ethash_params params(h256 const& _seedHash); + static ethash_params params(unsigned _n); + static LightType light(BlockInfo const& _header); + static LightType light(h256 const& _header); + static bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef()); + static bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef()); + + static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); + static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + +private: + void killCache(h256 const& _s); + + static Ethash* s_this; + RecursiveMutex x_this; + + std::map m_lights; + std::map m_fulls; + std::map m_seedHashes; +}; + +} +} diff --git a/libethcore/Ethasher.h b/libethcore/Ethasher.h deleted file mode 100644 index f57c2f4f6..000000000 --- a/libethcore/Ethasher.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Ethasher.h - * @author Gav Wood - * @date 2014 - * - * ProofOfWork algorithm. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include // TODO: REMOVE once everything merged into this class and an opaque API can be provided. -static const unsigned c_ethashRevision = ETHASH_REVISION; -static const unsigned c_ethashEpochLength = ETHASH_EPOCH_LENGTH; -#include "Common.h" -#include "BlockInfo.h" - -namespace dev -{ -namespace eth -{ - -class Ethasher -{ -public: - Ethasher() {} - ~Ethasher(); - - static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; } - - using LightType = void const*; - using FullType = void const*; - - LightType light(BlockInfo const& _header); - LightType light(h256 const& _header); - bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef()); - bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef()); - - static ethash_params params(BlockInfo const& _header); - static ethash_params params(h256 const& _seedHash); - static ethash_params params(unsigned _n); - - struct Result - { - h256 value; - h256 mixHash; - }; - - static Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } - static Result eval(BlockInfo const& _header, Nonce const& _nonce); - static Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); - static bool verify(BlockInfo const& _header); - - class Miner - { - public: - Miner(BlockInfo const& _header): - m_headerHash(_header.headerHash(WithoutNonce)), - m_params(Ethasher::params(_header)), - m_datasetPointer(Ethasher::get()->full(_header).data()) - {} - - inline h256 mine(uint64_t _nonce) - { - ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce); -// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer); - return h256(m_ethashReturn.result, h256::ConstructFromPointer); - } - - inline h256 lastMixHash() const - { - return h256(m_ethashReturn.mix_hash, h256::ConstructFromPointer); - } - - private: - ethash_return_value m_ethashReturn; - h256 m_headerHash; - ethash_params m_params; - void const* m_datasetPointer; - }; - -private: - void killCache(h256 const& _s); - - static Ethasher* s_this; - RecursiveMutex x_this; - std::map m_lights; - std::map m_fulls; - std::map m_seedHashes; -}; - -} -} diff --git a/libethcore/Miner.cpp b/libethcore/Miner.cpp index d6f15866f..e69de29bb 100644 --- a/libethcore/Miner.cpp +++ b/libethcore/Miner.cpp @@ -1,12 +0,0 @@ -#include "Miner.h" - -Miner::Miner() -{ - -} - -Miner::~Miner() -{ - -} - diff --git a/libethcore/Miner.h b/libethcore/Miner.h index a7f17e565..e7157e660 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -15,9 +15,8 @@ along with cpp-ethereum. If not, see . */ /** @file Miner.h - * @author Alex Leverington * @author Gav Wood - * @date 2014 + * @date 2015 */ #pragma once @@ -28,7 +27,6 @@ #include #include #include -#include "State.h" namespace dev { @@ -36,15 +34,17 @@ namespace dev namespace eth { -struct WorkPackage +struct MineInfo { - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; + MineInfo() = default; + MineInfo(bool _completed): completed(_completed) {} + void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; } + double requirement = 0; + double best = 1e99; + unsigned hashes = 0; + bool completed = false; }; -static const WorkPackage NullWorkPackage; - /** * @brief Describes the progress of a mining operation. */ @@ -58,30 +58,40 @@ struct MiningProgress unsigned ms = 0; ///< Total number of milliseconds of mining thus far. }; +template class Miner; + /** * @brief Class for hosting one or more Miners. * @warning Must be implemented in a threadsafe manner since it will be called from multiple * miner threads. */ -class FarmFace +template class FarmFace { public: + using WorkPackage = typename PoW::WorkPackage; + using Solution = typename PoW::Solution; + using Miner = Miner; + /** * @brief Called from a Miner to note a WorkPackage has a solution. * @param _p The solution. * @param _wp The WorkPackage that the Solution is for. + * @param _finder The miner that found it. * @return true iff the solution was good (implying that mining should be . */ - virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; + virtual bool submitProof(Solution const& _p, WorkPackage const& _wp, Miner* _finder) = 0; }; /** * @brief A miner - a member and adoptee of the Farm. */ -class Miner +template class Miner { public: - using ConstructionInfo = std::pair; + using ConstructionInfo = std::pair*, unsigned>; + using WorkPackage = typename PoW::WorkPackage; + using Solution = typename PoW::Solution; + using FarmFace = FarmFace; Miner(ConstructionInfo const& _ci): m_farm(_ci.first), @@ -124,7 +134,7 @@ protected: * @param _s The solution. * @return true if the solution was correct and that the miner should pause. */ - bool submitProof(ProofOfWork::Solution const& _s) + bool submitProof(Solution const& _s) { if (m_farm) { diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index 97488ee35..ec910f7f2 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -19,224 +19,6 @@ * @date 2014 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if ETH_ETHASHCL || !ETH_TRUE -#include -#endif -#include "BlockInfo.h" -#include "Ethasher.h" #include "ProofOfWork.h" using namespace std; -using namespace std::chrono; - -namespace dev -{ -namespace eth -{ - -void Ethash::CPUMiner::workLoop() -{ - Solution solution; - - class Miner - { - public: - Miner(BlockInfo const& _header): - m_headerHash(_header.headerHash(WithoutNonce)), - m_params(Ethasher::params(_header)), - m_datasetPointer(Ethasher::get()->full(_header).data()) - {} - - inline h256 mine(uint64_t _nonce) - { - ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce); -// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer); - return h256(m_ethashReturn.result, h256::ConstructFromPointer); - } - - inline h256 lastMixHash() const - { - return h256(m_ethashReturn.mix_hash, h256::ConstructFromPointer); - } - - private: - ethash_return_value m_ethashReturn; - h256 m_headerHash; - ethash_params m_params; - void const* m_datasetPointer; - }; - - Ethasher::Miner m(_header); - - std::pair ret; - auto tid = std::this_thread::get_id(); - static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); - uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng)); - - h256 boundary = _header.boundary(); - ret.first.requirement = log2((double)(u256)boundary); - - // 2^ 0 32 64 128 256 - // [--------*-------------------------] - // - // evaluate until we run out of time - auto startTime = std::chrono::steady_clock::now(); - double best = 1e99; // high enough to be effectively infinity :) - Solution result; - unsigned hashCount = 0; - for (; !shouldStop(); tryNonce++, hashCount++) - { - h256 val(m.mine(tryNonce)); - best = std::min(best, log2((double)(u256)val)); - if (val <= boundary) - { - if (submitProof(solution)) - return; - } - } - ret.first.hashes = hashCount; - ret.first.best = best; - ret.second = result; - - return; -} - -#if ETH_ETHASHCL || !ETH_TRUE - -/* -class ethash_cl_miner -{ -public: - struct search_hook - { - // reports progress, return true to abort - virtual bool found(uint64_t const* nonces, uint32_t count) = 0; - virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; - }; - - ethash_cl_miner(); - - bool init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size = 64); - - void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); - void search(uint8_t const* header, uint64_t target, search_hook& hook); -}; -*/ - -namespace dev { namespace eth { -class EthashCLHook: public ethash_cl_miner::search_hook -{ -public: - EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} - - void abort() - { - Guard l(x_all); - if (m_aborted) - return; -// cdebug << "Attempting to abort"; - m_abort = true; - for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) - std::this_thread::sleep_for(chrono::milliseconds(30)); - if (!m_aborted) - cwarn << "Couldn't abort. Abandoning OpenCL process."; - m_aborted = m_abort = false; - } - - uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; } - -protected: - virtual bool found(uint64_t const* _nonces, uint32_t _count) override - { -// cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); - for (uint32_t i = 0; i < _count; ++i) - { - if (m_owner->found(_nonces[i])) - { - m_aborted = true; - return true; - } - } - return false; - } - - virtual bool searched(uint64_t _startNonce, uint32_t _count) override - { - Guard l(x_all); -// cdebug << "Searched" << _count << "from" << _startNonce; - m_total += _count; - m_last = _startNonce + _count; - if (m_abort) - { - m_aborted = true; - return true; - } - return false; - } - -private: - Mutex x_all; - uint64_t m_total; - uint64_t m_last; - bool m_abort = false; - bool m_aborted = true; - Ethash::GPUMiner* m_owner = nullptr; -}; - -} } - -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): - Miner(_ci), - m_hook(new EthashCLHook(this)) -{ -} - -void Ethash::GPUMiner::report(uint64_t _nonce) -{ - Nonce n = (Nonce)(u64)_nonce; - Ethasher::Result r = Ethasher::eval(m_work.seedHash, m_work.headerHash, n); - if (r.value < m_work.boundary) - return submitProof(Solution{n, r.mixHash}); - return false; -} - -void Ethash::GPUMiner::kickOff(WorkPackage const& _work) -{ - if (!m_miner || m_minerSeed != _work.seedHash) - { - if (m_miner) - m_hook->abort(); - m_miner.reset(new ethash_cl_miner); - auto p = Ethasher::params(_work.seedHash); - auto cb = [&](void* d) { Ethasher::get()->readFull(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; - m_miner->init(p, cb, 32); - } - if (m_lastWork.headerHash != _work.headerHash) - { - m_hook->abort(); - uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); - m_miner->search(_work.headerHash, upper64OfBoundary, *m_hook); - } - m_work = _work; -} - -void Ethash::GPUMiner::pause() -{ - m_hook->abort(); -} - -#endif - -} -} +using namespace dev; diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index f66bc77c9..764207aef 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -18,112 +18,29 @@ * @author Gav Wood * @date 2014 * - * ProofOfWork algorithm. Or not. + * Determines the PoW algorithm. */ #pragma once -#include -#include -#include -#include -#include "Common.h" -#include "BlockInfo.h" -#include "Miner.h" - -#define FAKE_DAGGER 1 - -class ethash_cl_miner; +#include "Ethash.h" namespace dev { namespace eth { -struct MineInfo -{ - MineInfo() = default; - MineInfo(bool _completed): completed(_completed) {} - void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; } - double requirement = 0; - double best = 1e99; - unsigned hashes = 0; - bool completed = false; -}; - -class Ethash -{ - -public: - -struct Solution -{ - Nonce nonce; - h256 mixHash; -}; - -static bool verify(BlockInfo const& _header); -static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } - -class CPUMiner: public Miner, Worker -{ -public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - static unsigned instances() { return thread::hardware_concurrency(); } - -protected: - void kickOff(WorkPackage const& _work) override - { - stopWorking(); - m_work = _work; - startWorking(); - } - - void pause() override { stopWorking(); } - -private: - void workLoop() override; - - WorkPackage m_work; - MineInfo m_info; -}; - -#if ETH_ETHASHCL || !ETH_TRUE - -class EthashCLHook; - -class GPUMiner: public Miner -{ - friend class EthashCLHook; - -public: - GPUMiner(ConstructionInfo const& _ci); - - static unsigned instances() { return 1; } - -protected: - void kickOff(WorkPackage const& _work) override; - void pause() override; - -private: - void report(uint64_t _nonce); - - std::unique_ptr m_hook; - std::unique_ptr m_miner; - h256 m_minerSeed; - WorkPackage m_lastWork; ///< Work loaded into m_miner. - MineInfo m_info; -}; - -#else - -using GPUMiner = CPUMiner; - -#endif - -}; - +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * void assignResult(BlockInfo&, Result) + * and a few others. TODO + */ using ProofOfWork = Ethash; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index bf2bce4fe..0ff0a3628 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -231,8 +231,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); BlockInfo bi(b); - if (bi.number % c_ethashEpochLength == 1) - Ethasher::get()->full(bi); + ProofOfWork::prep(bi); if (bi.parentHash != lastHash) { @@ -307,14 +306,8 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st try { auto r = import(block, _stateDB); - bool isOld = true; - for (auto const& h: r.first) - if (h == r.second) - isOld = false; - else if (isOld) - dead.push_back(h); - else - fresh.push_back(h); + fresh += r.first; + dead += r.second; } catch (UnknownParent) { @@ -334,7 +327,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); } -pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force) noexcept +ImportRoute BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force) noexcept { try { @@ -347,7 +340,7 @@ pair BlockChain::attemptImport(bytes const& _block, OverlayDB const } } -pair BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force) +ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -626,7 +619,17 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, cnote << "checkBest:" << checkBest; #endif - return make_pair(route, common); + h256s fresh; + h256s dead; + bool isOld = true; + for (auto const& h: route) + if (h == common) + isOld = false; + else if (isOld) + dead.push_back(h); + else + fresh.push_back(h); + return make_pair(fresh, dead); } void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 765e00b03..cdff566fb 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -68,6 +68,7 @@ ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0); using BlocksHash = std::map; using TransactionHashes = h256s; using UncleHashes = h256s; +using ImportRoute = std::pair; enum { ExtraDetails = 0, @@ -108,11 +109,11 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks) noexcept; + ImportRoute attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6f8c64827..e9dd99cd1 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -102,6 +102,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) m_readySet.insert(h); noteReadyWithoutWriteGuard(h); + m_onReady(); return ImportResult::Success; } } diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index ce0582db2..f5cdf7ab5 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -83,6 +83,8 @@ public: /// Get some infomration on the current status. BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } + template Handler onReady(T const& _t) { return m_onReady.add(_t); } + private: void noteReadyWithoutWriteGuard(h256 _b); void notePresentWithoutWriteGuard(bytesConstRef _block); @@ -95,6 +97,7 @@ private: std::multimap> m_unknown; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears. std::multimap m_future; ///< Set of blocks that are not yet valid. std::set m_knownBad; ///< Set of blocks that we know will never be valid. + Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 278c02fa8..9c6b87293 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -117,7 +117,7 @@ void BasicGasPricer::update(BlockChain const& _bc) } } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId, int _miners): +Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): Worker("eth"), m_vc(_dbPath), m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), @@ -126,14 +126,14 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for m_preMine(m_stateDB, BaseState::CanonGenesis), m_postMine(m_stateDB) { + m_tqReady = m_tq->onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); + m_bqReady = m_bq->onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); + m_farm->onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_gp->update(m_bc); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); - if (_miners > -1) - setMiningThreads(_miners); - else - setMiningThreads(); if (_dbPath.size()) Defaults::setDBPath(_dbPath); m_vc.setOk(); @@ -142,7 +142,7 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for startWorking(); } -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId, int _miners): +Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): Worker("eth"), m_vc(_dbPath), m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), @@ -151,14 +151,14 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_preMine(m_stateDB), m_postMine(m_stateDB) { + m_tq->onReady([=](){ this->onTransactionQueueReady(); }); + m_bq->onReady([=](){ this->onBlockQueueReady(); }); + m_farm->onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_gp->update(m_bc); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); - if (_miners > -1) - setMiningThreads(_miners); - else - setMiningThreads(); if (_dbPath.size()) Defaults::setDBPath(_dbPath); m_vc.setOk(); @@ -229,8 +229,6 @@ void Client::killChain() doWork(); - setMiningThreads(0); - startWorking(); if (wasMining) startMining(); @@ -271,26 +269,6 @@ static string filtersToString(T const& _fs) return ret.str(); } -void Client::noteChanged(h256Set const& _filters) -{ - Guard l(x_filtersWatches); - if (_filters.size()) - cnote << "noteChanged(" << filtersToString(_filters) << ")"; - // accrue all changes left in each filter into the watches. - for (auto& w: m_watches) - if (_filters.count(w.second.id)) - { - cwatch << "!!!" << w.first << (m_filters.count(w.second.id) ? w.second.id.abridged() : w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); - if (m_filters.count(w.second.id)) // Normal filtering watch - w.second.changes += m_filters.at(w.second.id).changes; - else // Special ('pending'/'latest') watch - w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); - } - // clear the filters now. - for (auto& i: m_filters) - i.second.changes.clear(); -} - void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash) { Guard l(x_filtersWatches); @@ -342,22 +320,6 @@ void Client::setForceMining(bool _enable) m.noteStateChange(); } -void Client::setMiningThreads(unsigned _threads) -{ - stopMining(); - auto t = _threads ? _threads : thread::hardware_concurrency(); -#if ETH_ETHASHCL || !ETH_TRUE - if (m_turboMining) - t = 1; -#endif - WriteGuard l(x_localMiners); - m_localMiners.clear(); - m_localMiners.resize(t); - unsigned i = 0; - for (auto& m: m_localMiners) - m.setup(this, i++); -} - MineProgress Client::miningProgress() const { MineProgress ret; @@ -452,160 +414,161 @@ pair Client::getWork() return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty()); } -bool Client::submitWork(ProofOfWork::Solution const& _proof) +bool Client::submitWork(ProofOfWork::Solution const& _solution) { - Guard l(x_remoteMiner); - return m_remoteMiner.submitWork(_proof); + bytes newBlock; + { + WriteGuard l(x_stateDB); + if (!m_postMine.completeMine(_solution)) + return false; + newBlock = m_postMine.blockData(); + } + + ImportRoute ir = m_bc.attemptImport(newBlock, m_stateDB); + if (!ir.first.empty()) + onChainChanged(ir); + return true; } -void Client::doWork() +void Client::syncBlockQueue() { - // TODO: Use condition variable rather than polling. - - bool stillGotWork = false; - - cworkin << "WORK"; - h256Set changeds; - - auto maintainMiner = [&](OldMiner& m) - { - if (m.isComplete()) - { - // TODO: enable a short-circuit option since we mined it. will need to get the end state from the miner. - auto lm = dynamic_cast(&m); - h256s hs; - h256 c; - if (false && lm && !m_verifyOwnBlocks) - { - // TODO: implement - //m_bc.attemptImport(m_blockData(), m_stateDB, lm->state()); - // TODO: derive hs from lm->state() - } - else - { - cwork << "CHAIN <== postSTATE"; - WriteGuard l(x_stateDB); - tie(hs, c) = m_bc.attemptImport(m.blockData(), m_stateDB); - } - if (hs.size()) - { - for (auto const& h: hs) - if (h != c) - appendFromNewBlock(h, changeds); - changeds.insert(ChainChangedFilter); - } - for (auto& m: m_localMiners) - m.noteStateChange(); - } - }; - { - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - maintainMiner(m); - } - { - Guard l(x_remoteMiner); - maintainMiner(m_remoteMiner); - } + ImportResult ir; - // Synchronise state to block chain. - // This should remove any transactions on our queue that are included within our state. - // It also guarantees that the state reflects the longest (valid!) chain on the block chain. - // This might mean reverting to an earlier state and replaying some blocks, or, (worst-case: - // if there are no checkpoints before our fork) reverting to the genesis block and replaying - // all blocks. - // Resynchronise state with block chain & trans - bool resyncStateNeeded = false; { WriteGuard l(x_stateDB); cwork << "BQ ==> CHAIN ==> STATE"; OverlayDB db = m_stateDB; x_stateDB.unlock(); - h256s fresh; - h256s dead; - bool sgw; - tie(fresh, dead, sgw) = m_bc.sync(m_bq, db, 100); - - // insert transactions that we are declaring the dead part of the chain - for (auto const& h: dead) - { - clog(ClientNote) << "Dead block:" << h.abridged(); - for (auto const& t: m_bc.transactions(h)) - { - clog(ClientNote) << "Resubmitting transaction " << Transaction(t, CheckTransaction::None); - m_tq.import(t); - } - } - // remove transactions from m_tq nicely rather than relying on out of date nonce later on. - for (auto const& h: fresh) - { - clog(ClientChat) << "Live block:" << h.abridged(); - for (auto const& th: m_bc.transactionHashes(h)) - { - clog(ClientNote) << "Safely dropping transaction " << th.abridged(); - m_tq.drop(th); - } - } + tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); - stillGotWork = stillGotWork | sgw; - if (!fresh.empty()) - { - for (auto i: fresh) - appendFromNewBlock(i, changeds); - changeds.insert(ChainChangedFilter); - } x_stateDB.lock(); if (fresh.size()) m_stateDB = db; + } + + if (!ir.first.empty()) + onChainChanged(ir); + return true; +} + +void Client::syncTransactionQueue() +{ + // returns TransactionReceipts, once for each transaction. + cwork << "postSTATE <== TQ"; + TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); + if (newPendingReceipts.size()) + { + for (size_t i = 0; i < newPendingReceipts.size(); i++) + appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - cwork << "preSTATE <== CHAIN"; - if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) + changeds.insert(PendingChangedFilter); + + if (isMining()) + cnote << "Additional transaction ready: Restarting mining operation."; + resyncStateNeeded = true; + if (auto h = m_host.lock()) + h->noteNewTransactions(); + } +} + +void Client::onChainChanged(ImportRoute const& _ir) +{ + // insert transactions that we are declaring the dead part of the chain + for (auto const& h: _ir.second) + { + clog(ClientNote) << "Dead block:" << h.abridged(); + for (auto const& t: m_bc.transactions(h)) { - if (isMining()) - cnote << "New block on chain: Restarting mining operation."; - m_postMine = m_preMine; - resyncStateNeeded = true; - changeds.insert(PendingChangedFilter); - // TODO: Move transactions pending from m_postMine back to transaction queue. + clog(ClientNote) << "Resubmitting transaction " << Transaction(t, CheckTransaction::None); + m_tq.import(t); } + } - // returns TransactionReceipts, once for each transaction. - cwork << "postSTATE <== TQ"; - TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); - if (newPendingReceipts.size()) + // remove transactions from m_tq nicely rather than relying on out of date nonce later on. + for (auto const& h: _ir.first) + { + clog(ClientChat) << "Live block:" << h.abridged(); + for (auto const& th: m_bc.transactionHashes(h)) { - for (size_t i = 0; i < newPendingReceipts.size(); i++) - appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - - changeds.insert(PendingChangedFilter); - - if (isMining()) - cnote << "Additional transaction ready: Restarting mining operation."; - resyncStateNeeded = true; - if (auto h = m_host.lock()) - h->noteNewTransactions(); + clog(ClientNote) << "Safely dropping transaction " << th.abridged(); + m_tq.drop(th); } } - if (!changeds.empty()) - if (auto h = m_host.lock()) - h->noteNewBlocks(); + if (auto h = m_host.lock()) + h->noteNewBlocks(); + + h256Set changeds; + for (auto const& h: _ir.first) + if (h != _ir.second) + appendFromNewBlock(h, changeds); + changeds.insert(ChainChangedFilter); + noteChanged(changeds); + + // RESTART MINING - if (resyncStateNeeded) + // LOCKS NEEDED? + Guard l(x_stateDB); + cwork << "preSTATE <== CHAIN"; + if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) { - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - m.noteStateChange(); + if (isMining()) + cnote << "New block on chain: Restarting mining operation."; + m_postMine = m_preMine; + resyncStateNeeded = true; + changeds.insert(PendingChangedFilter); + + m_postMine.commitToMine(m_bc); + m_farm.setWork(m_postMine.info()); } +} - cwork << "noteChanged" << changeds.size() << "items"; - noteChanged(changeds); - cworkout << "WORK"; +void Client::noteChanged(h256Set const& _filters) +{ + Guard l(x_filtersWatches); + if (_filters.size()) + cnote << "noteChanged(" << filtersToString(_filters) << ")"; + // accrue all changes left in each filter into the watches. + for (auto& w: m_watches) + if (_filters.count(w.second.id)) + { + cwatch << "!!!" << w.first << (m_filters.count(w.second.id) ? w.second.id.abridged() : w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); + if (m_filters.count(w.second.id)) // Normal filtering watch + w.second.changes += m_filters.at(w.second.id).changes; + else // Special ('pending'/'latest') watch + w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); + } + // clear the filters now. + for (auto& i: m_filters) + i.second.changes.clear(); +} + +void Client::doWork() +{ + // TODO: Use condition variable rather than this rubbish. + + Guard l(x_fakeSignalSystemState); + + if (m_syncTransactionQueue) + { + m_syncTransactionQueue = false; + syncTransactionQueue(); + } + + if (m_syncBlockQueue) + { + m_syncBlockQueue = false; + syncBlockQueue(); + } + + checkWatchGarbage(); - if (!stillGotWork) - this_thread::sleep_for(chrono::milliseconds(100)); + this_thread::sleep_for(chrono::milliseconds(20)); +} +void Client::checkWatchGarbage() +{ if (chrono::system_clock::now() - m_lastGarbageCollection > chrono::seconds(5)) { // watches garbage collection diff --git a/libethereum/Client.h b/libethereum/Client.h index 9af501f74..8eac2e577 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -42,6 +42,7 @@ #include "CommonNet.h" #include "Miner.h" #include "ABI.h" +#include "Farm.h" #include "ClientBase.h" namespace dev @@ -122,7 +123,7 @@ struct ClientDetail: public LogChannel { static const char* name() { return " C /** * @brief Main API hub for interfacing with Ethereum. */ -class Client: public MinerHost, public ClientBase, Worker +class Client: public ClientBase, Worker { friend class OldMiner; @@ -132,8 +133,7 @@ public: p2p::Host* _host, std::string const& _dbPath = std::string(), WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0, - int _miners = -1 + u256 _networkId = 0 ); explicit Client( @@ -141,8 +141,7 @@ public: std::shared_ptr _gpForAdoption, // pass it in with new. std::string const& _dbPath = std::string(), WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0, - int _miners = -1 + u256 _networkId = 0 ); /// Destructor. @@ -191,31 +190,31 @@ public: /// Are we allowed to GPU mine? bool turboMining() const { return m_turboMining; } /// Enable/disable GPU mining. - void setTurboMining(bool _enable = true) { bool was = isMining(); stopMining(); m_turboMining = _enable; setMiningThreads(0); if (was) startMining(); } + void setTurboMining(bool _enable = true) { m_turboMining = _enable; if (isMining()) startMining(); } - /// Stops mining and sets the number of mining threads (0 for automatic). - void setMiningThreads(unsigned _threads = 0) override; - /// Get the effective number of mining threads. - unsigned miningThreads() const override { ReadGuard l(x_localMiners); return m_localMiners.size(); } /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread - void startMining() override { startWorking(); { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.start(); } } + void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); } /// Stop mining. /// NOT thread-safe - void stopMining() override { { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.stop(); } } - /// Are we mining now? - bool isMining() const override { { ReadGuard l(x_localMiners); if (!m_localMiners.empty() && m_localMiners[0].isRunning()) return true; } return false; } + void stopMining() override { m_farm.stop(); } /// Are we mining now? + bool isMining() const override { return m_farm.isMining(); } + /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MineProgress miningProgress() const override; + MiningProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. virtual std::pair getWork() override; - /// Submit the proof for the proof-of-work. + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ virtual bool submitWork(ProofOfWork::Solution const& _proof) override; // Debug stuff: @@ -261,10 +260,23 @@ private: /// Called when Worker is exiting. virtual void doneWorking(); - /// Overrides for being a mining host. - virtual void setupState(State& _s); - virtual bool turbo() const { return m_turboMining; } - virtual bool force() const { return m_forceMining; } + /// Magically called when the chain has changed. An import route is provided. + /// Called by either submitWork() or in our main thread through syncBlockQueue(). + void onChainChanged(ImportRoute const& _ir); + + /// Signal handler for when the block queue needs processing. + void syncBlockQueue(); + + /// Signal handler for when the block queue needs processing. + void syncTransactionQueue(); + + /// Magically called when m_tq needs syncing. Be nice and don't block. + void onTransactionQueueReady() { Guard l(x_fakeSignalSystemState); m_syncTransactionQueue = true; } + + /// Magically called when m_tq needs syncing. Be nice and don't block. + void onBlockQueueReady() { Guard l(x_fakeSignalSystemState); m_syncBlockQueue = true; } + + void checkWatchGarbage(); VersionChecker m_vc; ///< Dummy object to check & update the protocol version. CanonBlockChain m_bc; ///< Maintains block database. @@ -278,17 +290,24 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. + Farm m_farm; ///< Our mining farm. mutable Mutex x_remoteMiner; ///< The remote miner lock. RemoteMiner m_remoteMiner; ///< The remote miner. - std::vector m_localMiners; ///< The in-process miners. - mutable SharedMutex x_localMiners; ///< The in-process miners lock. - bool m_paranoia = false; ///< Should we be paranoid about our state? + Handler m_tqReady; + Handler m_bqReady; + bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping. bool m_forceMining = false; ///< Mine even when there are no transactions pending? - bool m_verifyOwnBlocks = true; ///< Should be verify blocks that we mined? + bool m_paranoia = false; ///< Should we be paranoid about our state? mutable std::chrono::system_clock::time_point m_lastGarbageCollection; + ///< When did we last both doing GC on the watches? + + // TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables) + mutable Mutex x_fakeSignalSystemState; + bool m_syncTransactionQueue = false; + bool m_syncBlockQueue = false; }; } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index ae6d27578..4b3cc5002 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -142,8 +142,6 @@ public: /// TODO: consider moving it to a separate interface - virtual void setMiningThreads(unsigned _threads) override { (void)_threads; BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::setMiningThreads")); } - virtual unsigned miningThreads() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningThreads")); } virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); } virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); } virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); } diff --git a/libethereum/Farm.cpp b/libethereum/Farm.cpp index 639e4efcf..e69de29bb 100644 --- a/libethereum/Farm.cpp +++ b/libethereum/Farm.cpp @@ -1,12 +0,0 @@ -#include "Farm.h" - -Farm::Farm() -{ - -} - -Farm::~Farm() -{ - -} - diff --git a/libethereum/Farm.h b/libethereum/Farm.h index a49038f0d..55d1aa8df 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -14,10 +14,9 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file Miner.h - * @author Alex Leverington +/** @file Farm.h * @author Gav Wood - * @date 2014 + * @date 2015 */ #pragma once @@ -28,7 +27,8 @@ #include #include #include -#include "Miner.h" +#include +#include namespace dev { @@ -41,8 +41,8 @@ namespace eth * Miners ask for work, then submit proofs * @threadsafe */ -template -class Farm: public FarmFace +template +class Farm: public FarmFace { public: /** @@ -65,13 +65,13 @@ public: * @brief (Re)start miners for CPU only. * @returns true if started properly. */ - bool startCPU() { return start(); } + bool startCPU() { return start(); } /** * @brief (Re)start miners for GPU only. * @returns true if started properly. */ - bool startGPU() { start(); } + bool startGPU() { start(); } /** * @brief Stop all mining activities. @@ -82,20 +82,24 @@ public: m_miners.clear(); } + bool isMining() const + { + ReadGuard l(x_miners); + return !m_miners.empty(); + } + /** * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } + MiningProgress const& miningProgress() const { ReadGuard l(x_progress); return m_progress; } -protected: - // TO BE REIMPLEMENTED BY THE SUBCLASS /** * @brief Provides a valid header based upon that received previously with setWork(). * @param _bi The now-valid header. * @return true if the header was good and that the Farm should pause until more work is submitted. */ - virtual bool submitHeader(BlockInfo const& _bi) = 0; + void onSolutionFound(function _handler) { m_onSolutionFound = _handler; } private: /** @@ -104,16 +108,15 @@ private: * @param _wp The WorkPackage that the Solution is for. * @return true iff the solution was good (implying that mining should be . */ - bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp, NewMiner* _m) override + bool submitProof(Solution const& _s, WorkPackage const& _wp, Miner* _m) override { if (_wp.headerHash != m_work.headerHash) return false; - ProofOfWork::assignResult(_p, m_header); - if (submitHeader(m_header)) + if (m_onSolutionFound && m_onSolutionFound(_s)) { ReadGuard l(x_miners); - for (std::shared_ptr const& m: m_miners) + for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->pause(); m_work.headerHash = h256(); @@ -139,14 +142,16 @@ private: } mutable SharedMutex x_miners; - std::vector> m_miners; + std::vector> m_miners; mutable SharedMutex x_progress; - MineProgress m_progress; + MiningProgress m_progress; mutable SharedMutex x_work; WorkPackage m_work; BlockInfo m_header; + + function m_onSolutionFound; }; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e77565837..75618eb5f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -856,20 +856,6 @@ void State::commitToMine(BlockChain const& _bc) m_committedToMine = true; } -bool State::completeMine(ProofOfWork::Solution const& _nonce) -{ - ProofOfWork::assignResult(_nonce, m_currentBlock); - -// if (!m_pow.verify(m_currentBlock)) -// return false; - - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock); - - completeMine(); - - return true; -} - void State::completeMine() { cdebug << "Completing mine!"; diff --git a/libethereum/State.h b/libethereum/State.h index b327378a1..36a505481 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include "TransactionQueue.h" @@ -162,30 +163,19 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff the given nonce is a proof-of-work for this State's block. - bool completeMine(ProofOfWork::Solution const& _result); - - /// Attempt to find valid nonce for block that this state represents. - /// This function is thread-safe. You can safely have other interactions with this object while it is happening. - /// @param _msTimeout Timeout before return in milliseconds. - /// @returns Information on the mining. - template MineInfo mine(ProofOfWork* _pow) + template + bool completeMine(typename PoW::Solution const& _result) { - // Update difficulty according to timestamp. - m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); + PoW::assignResult(_result, m_currentBlock); - MineInfo ret; - typename ProofOfWork::Solution r; - std::tie(ret, r) = _pow->mine(m_currentBlock, _pow->defaultTimeout(), true); + // if (!m_pow.verify(m_currentBlock)) + // return false; - if (!ret.completed) - m_currentBytes.clear(); - else - { - ProofOfWork::assignResult(r, m_currentBlock); - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock); - } + cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - return ret; + completeMine(); + + return true; } /** Commit to DB and build the final block if the previous call to mine()'s result is completion. @@ -369,7 +359,6 @@ private: /// Debugging only. Good for checking the Trie is in shape. void paranoia(std::string const& _when, bool _enforceRefs = false) const; - OverlayDB m_db; ///< Our overlay for the state tree. SecureTrieDB m_state; ///< Our state tree, as an OverlayDB DB. Transactions m_transactions; ///< The current list of transactions that we've included in the state. diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 7c72f53e8..506de2d2f 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -53,6 +53,7 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb if (_cb) m_callbacks[h] = _cb; ctxq << "Queued vaguely legit-looking transaction" << h.abridged(); + m_onReady(); } catch (Exception const& _e) { diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index ad093b4e5..e18f47e80 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -26,7 +26,7 @@ #include #include #include -#include "libethcore/Common.h" +#include #include "Transaction.h" namespace dev @@ -60,13 +60,15 @@ public: void noteGood(std::pair const& _t); void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); } + template Handler onReady(T const& _t) { return m_onReady.add(_t); } private: mutable boost::shared_mutex m_lock; ///< General lock. std::set m_known; ///< Hashes of transactions in both sets. std::map m_current; ///< Map of SHA3(tx) to tx. std::multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. - std::map> m_callbacks; ///< Called once + std::map> m_callbacks; ///< Called once. + Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. }; } From 1a67af3115eb16383f1e5b806426f37e7ea4d818 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 23:25:20 +0200 Subject: [PATCH 028/108] Fix configuraion issues. --- CMakeLists.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6a906b59..05862d9f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,7 +136,6 @@ if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") endif () createDefaultCacheConfig() -configureProject() # Force chromium. set (ETH_HAVE_WEBENGINE 1) @@ -263,6 +262,8 @@ elseif (BUNDLE STREQUAL "user") set(TESTS OFF) endif () +configureProject() + # Default CMAKE_BUILD_TYPE to "Release". set(CMAKE_BUILD_TYPE CACHE STRING "Release") if ("x${CMAKE_BUILD_TYPE}" STREQUAL "x") @@ -272,7 +273,11 @@ endif () # Default TARGET_PLATFORM to "linux". set(TARGET_PLATFORM CACHE STRING "linux") if ("x${TARGET_PLATFORM}" STREQUAL "x") - set(TARGET_PLATFORM "linux") + if (WIN32) + set(TARGET_PLATFORM "windows") + else () + set(TARGET_PLATFORM "linux") + endif () endif () message("------------------------------------------------------------------------") @@ -308,7 +313,7 @@ include(EthCompilerSettings) message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") -# this must be an include, as a function it would messs up with variable scope! +# this must be an include, as a function it would mess up with variable scope! include(EthDependencies) include(EthExecutableHelper) From be2480d85ef8ffcd83066620a7ace4c42326e3dc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 00:08:52 +0200 Subject: [PATCH 029/108] Compile fixes. --- libethcore/Common.h | 37 +++++++++++++------------------ libethcore/Ethash.cpp | 40 +++++++++++++++------------------- libethcore/Ethash.h | 12 ++++++---- libethcore/EthashAux.cpp | 36 +++++++++++++++--------------- libethcore/EthashAux.h | 6 +++-- libethcore/Miner.h | 16 ++++++++------ libethereum/Client.h | 2 +- libethereum/Farm.h | 2 +- libethereum/Interface.h | 5 ----- libethereum/TransactionQueue.h | 2 +- mix/MixClient.cpp | 10 --------- mix/MixClient.h | 2 -- 12 files changed, 75 insertions(+), 95 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index b5291648b..4d01055f1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -96,42 +96,35 @@ enum class ImportResult BadChain }; -class Signal; - -class Handler +/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight. +class Signal { public: - Handler() = default; - Handler(Handler const&) = delete; - ~Handler() { reset(); } + class HandlerAux + { + friend class Signal; - Handler& operator=(Handler const& _h) = delete; + public: + ~HandlerAux() { if (m_s) m_s->m_fire.erase(m_i); m_s = nullptr; } - void reset(); - -private: - Handler(unsigned _i, Signal* _s): m_i(_i), m_s(_s) {} + private: + HandlerAux(unsigned _i, Signal* _s): m_i(_i), m_s(_s) {} - unsigned m_i = 0; - Signal* m_s = nullptr; -}; + unsigned m_i = 0; + Signal* m_s = nullptr; + }; -/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight. -class Signal -{ -public: using Callback = std::function; - using Callbacks = std::vector; - Handler add(Callback const& _h) { auto n = m_onReady.size() ? m_onReady.rbegin()->first + 1 : 0; m_onReady[n] = _h; return Handler(n, this); } + std::shared_ptr add(Callback const& _h) { auto n = m_fire.empty() ? 0 : (m_fire.rbegin()->first + 1); m_fire[n] = _h; return std::shared_ptr(new HandlerAux(n, this)); } void operator()() { for (auto const& f: m_fire) f.second(); } private: - std::map m_fire; + std::map m_fire; }; -inline void Handler::reset() { if (m_s) m_s->m_fire->erase(m_i); m_s = nullptr; } +using Handler = std::shared_ptr; } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 82e349b4c..f3b4d1b18 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ unsigned Ethash::revision() void Ethash::prep(BlockInfo const& _header) { if (_header.number % ETHASH_EPOCH_LENGTH == 1) - EthashAux::full(bi); + EthashAux::full(_header); } bool Ethash::preVerify(BlockInfo const& _header) @@ -88,7 +88,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - auto result = eval(_header); + auto result = EthashAux::eval(_header); bool slow = result.value <= boundary && result.mixHash == _header.mixHash; #if ETH_DEBUG || !ETH_TRUE @@ -111,29 +111,27 @@ bool Ethash::verify(BlockInfo const& _header) void Ethash::CPUMiner::workLoop() { auto tid = std::this_thread::get_id(); - static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); + static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); - uint64_t tryNonce = Nonce::random(s_eng); + uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng); ethash_return_value ethashReturn; - auto p = Ethash::params(m_work.seedHash); - void const* dagPointer = Ethash::full(m_work.headerHash).data(); + auto p = EthashAux::params(m_work.seedHash); + void const* dagPointer = EthashAux::full(m_work.headerHash).data(); uint8_t const* headerHashPointer = m_work.headerHash.data(); - h256 boundary = m_work.boundary(); + h256 boundary = m_work.boundary; unsigned hashCount = 0; for (; !shouldStop(); tryNonce++, hashCount++) { ethash_compute_full(ðashReturn, dagPointer, &p, headerHashPointer, tryNonce); h256 value = h256(ethashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{value, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) break; } } #if ETH_ETHASHCL || !ETH_TRUE -namespace dev { namespace eth { - class EthashCLHook: public ethash_cl_miner::search_hook { public: @@ -148,8 +146,8 @@ public: m_abort = true; for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) std::this_thread::sleep_for(chrono::milliseconds(30)); - if (!m_aborted) - cwarn << "Couldn't abort. Abandoning OpenCL process."; +// if (!m_aborted) +// cwarn << "Couldn't abort. Abandoning OpenCL process."; m_aborted = m_abort = false; } @@ -161,7 +159,7 @@ protected: // cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); for (uint32_t i = 0; i < _count; ++i) { - if (m_owner->found(_nonces[i])) + if (m_owner->report(_nonces[i])) { m_aborted = true; return true; @@ -193,19 +191,17 @@ private: Ethash::GPUMiner* m_owner = nullptr; }; -} } - Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), m_hook(new EthashCLHook(this)) { } -void Ethash::GPUMiner::report(uint64_t _nonce) +bool Ethash::GPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = Ethash::eval(m_work.seedHash, m_work.headerHash, n); - if (r.value < m_work.boundary) + Result r = EthashAux::eval(m_lastWork.seedHash, m_lastWork.headerHash, n); + if (r.value < m_lastWork.boundary) return submitProof(Solution{n, r.mixHash}); return false; } @@ -217,17 +213,17 @@ void Ethash::GPUMiner::kickOff(WorkPackage const& _work) if (m_miner) m_hook->abort(); m_miner.reset(new ethash_cl_miner); - auto p = Ethash::params(_work.seedHash); - auto cb = [&](void* d) { EthashAux::readFull(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; + auto p = EthashAux::params(_work.seedHash); + auto cb = [&](void* d) { EthashAux::full(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; m_miner->init(p, cb, 32); } if (m_lastWork.headerHash != _work.headerHash) { m_hook->abort(); uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); - m_miner->search(_work.headerHash, upper64OfBoundary, *m_hook); + m_miner->search(_work.headerHash.data(), upper64OfBoundary, *m_hook); } - m_work = _work; + m_lastWork = _work; } void Ethash::GPUMiner::pause() diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index bdd6bf6c5..b87f06549 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "Common.h" #include "BlockInfo.h" #include "Miner.h" @@ -37,9 +38,13 @@ namespace dev namespace eth { +class EthashCLHook; + class Ethash { public: + using Miner = GenericMiner; + struct Solution { Nonce nonce; @@ -73,7 +78,7 @@ public: public: CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - static unsigned instances() { return thread::hardware_concurrency(); } + static unsigned instances() { return std::thread::hardware_concurrency(); } protected: void kickOff(WorkPackage const& _work) override @@ -93,10 +98,9 @@ public: }; #if ETH_ETHASHCL || !ETH_TRUE - class EthashCLHook; class GPUMiner: public Miner { - friend class EthashCLHook; + friend class dev::eth::EthashCLHook; public: GPUMiner(ConstructionInfo const& _ci); @@ -108,7 +112,7 @@ public: void pause() override; private: - void report(uint64_t _nonce); + bool report(uint64_t _nonce); std::unique_ptr m_hook; std::unique_ptr m_miner; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index a6143e264..969310dac 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -102,13 +102,13 @@ void const* EthashAux::light(BlockInfo const& _header) void const* EthashAux::light(h256 const& _seedHash) { - RecursiveGuard l(x_this); - if (!m_lights.count(_header.seedHash())) + RecursiveGuard l(get()->x_this); + if (!get()->m_lights.count(_seedHash)) { ethash_params p = params(_seedHash); - m_lights[_seedHash] = ethash_new_light(&p, _seedHash.data()); + get()->m_lights[_seedHash] = ethash_new_light(&p, _seedHash.data()); } - return m_lights[_seedHash]; + return get()->m_lights[_seedHash]; } bytesConstRef EthashAux::full(BlockInfo const& _header, bytesRef _dest) @@ -118,14 +118,14 @@ bytesConstRef EthashAux::full(BlockInfo const& _header, bytesRef _dest) bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) { - RecursiveGuard l(x_this); - if (m_fulls.count(_seedHash) && _dest) + RecursiveGuard l(get()->x_this); + if (get()->m_fulls.count(_seedHash) && _dest) { - assert(m_fulls.size() <= _dest.size()); - m_fulls.at(_seedHash).copyTo(_dest); - return; + assert(get()->m_fulls.size() <= _dest.size()); + get()->m_fulls.at(_seedHash).copyTo(_dest); + return _dest; } - if (!m_fulls.count(_seedHash)) + if (!get()->m_fulls.count(_seedHash)) { // @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr. /* if (!m_fulls.empty()) @@ -138,7 +138,7 @@ bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) boost::filesystem::create_directories(getDataDir("ethash")); } catch (...) {} - auto info = rlpList(revision(), _seedHash); + auto info = rlpList(Ethash::revision(), _seedHash); std::string oldMemoFile = getDataDir("ethash") + "/full"; std::string memoFile = getDataDir("ethash") + "/full-R" + toString(ETHASH_REVISION) + "-" + toHex(_seedHash.ref().cropped(0, 8)); if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) @@ -147,8 +147,8 @@ bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) boost::filesystem::rename(oldMemoFile, memoFile); } - IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); - IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); + ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); + ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); ethash_params p = params(_seedHash); assert(!_dest || _dest.size() >= p.full_size); // must be big enough. @@ -162,14 +162,14 @@ bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) r = _dest; else r = bytesRef(new byte[p.full_size], p.full_size); - ethash_prep_full(r, &p, light(_seedHash)); + ethash_prep_full(r.data(), &p, light(_seedHash)); writeFile(memoFile, r); } if (_dest) return _dest; - m_fulls[_seedHash] = r; + get()->m_fulls[_seedHash] = r; } - return m_fulls[_seedHash]; + return get()->m_fulls[_seedHash]; } Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) @@ -179,12 +179,12 @@ Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { - auto p = EthashAux::params(_header); + auto p = EthashAux::params(_seedHash); ethash_return_value r; if (EthashAux::get()->m_fulls.count(_seedHash)) ethash_compute_full(&r, EthashAux::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); else ethash_compute_light(&r, EthashAux::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce); // cdebug << "EthashAux::eval sha3(cache):" << sha3(EthashAux::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); - return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; + return Ethash::Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index bfd01a594..aec1089a2 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -28,7 +28,7 @@ namespace eth{ class EthashAux { - EthashAux() {} +public: ~EthashAux(); static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; } @@ -49,9 +49,11 @@ class EthashAux static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: + EthashAux() {} + void killCache(h256 const& _s); - static Ethash* s_this; + static EthashAux* s_this; RecursiveMutex x_this; std::map m_lights; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index e7157e660..9372c06b1 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -58,19 +58,19 @@ struct MiningProgress unsigned ms = 0; ///< Total number of milliseconds of mining thus far. }; -template class Miner; +template class GenericMiner; /** * @brief Class for hosting one or more Miners. * @warning Must be implemented in a threadsafe manner since it will be called from multiple * miner threads. */ -template class FarmFace +template class GenericFarmFace { public: using WorkPackage = typename PoW::WorkPackage; using Solution = typename PoW::Solution; - using Miner = Miner; + using Miner = GenericMiner; /** * @brief Called from a Miner to note a WorkPackage has a solution. @@ -85,15 +85,15 @@ public: /** * @brief A miner - a member and adoptee of the Farm. */ -template class Miner +template class GenericMiner { public: - using ConstructionInfo = std::pair*, unsigned>; using WorkPackage = typename PoW::WorkPackage; using Solution = typename PoW::Solution; - using FarmFace = FarmFace; + using FarmFace = GenericFarmFace; + using ConstructionInfo = std::pair; - Miner(ConstructionInfo const& _ci): + GenericMiner(ConstructionInfo const& _ci): m_farm(_ci.first), m_index(_ci.second) {} @@ -144,6 +144,8 @@ protected: return true; } + WorkPackage const& work() const { return m_work; } + private: FarmFace* m_farm = nullptr; unsigned m_index; diff --git a/libethereum/Client.h b/libethereum/Client.h index 8eac2e577..a136033e5 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -290,7 +290,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - Farm m_farm; ///< Our mining farm. + GenericFarm m_farm; ///< Our mining farm. mutable Mutex x_remoteMiner; ///< The remote miner lock. RemoteMiner m_remoteMiner; ///< The remote miner. diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 55d1aa8df..39988c8d7 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -42,7 +42,7 @@ namespace eth * @threadsafe */ template -class Farm: public FarmFace +class GenericFarm: public GenericFarmFace { public: /** diff --git a/libethereum/Interface.h b/libethereum/Interface.h index cf2e7f5ea..134bed53b 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -171,11 +171,6 @@ public: /// Get the coinbase address. virtual Address address() const = 0; - /// Stops mining and sets the number of mining threads (0 for automatic). - virtual void setMiningThreads(unsigned _threads = 0) = 0; - /// Get the effective number of mining threads. - virtual unsigned miningThreads() const = 0; - /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread virtual void startMining() = 0; diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index e18f47e80..c3df00d25 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -48,7 +48,7 @@ class TransactionQueue public: using ImportCallback = std::function; - ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx); } + ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx, _cb); } ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback()); void drop(h256 _txHash); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index dd7047d26..254ceb325 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -372,16 +372,6 @@ void MixClient::setAddress(Address _us) m_state.setAddress(_us); } -void MixClient::setMiningThreads(unsigned _threads) -{ - m_miningThreads = _threads; -} - -unsigned MixClient::miningThreads() const -{ - return m_miningThreads; -} - void MixClient::startMining() { //no-op diff --git a/mix/MixClient.h b/mix/MixClient.h index a5ecbf465..0d1cce2bc 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -63,8 +63,6 @@ public: dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); void setAddress(Address _us) override; - void setMiningThreads(unsigned _threads) override; - unsigned miningThreads() const override; void startMining() override; void stopMining() override; bool isMining() const override; From db3e0831c3940fc0108a61741b5391b453822e8b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 00:34:42 +0200 Subject: [PATCH 030/108] Various compile fixes. --- libethcore/Ethash.cpp | 9 ++ libethcore/Ethash.h | 6 +- libethereum/BlockChain.cpp | 3 +- libethereum/BlockChain.h | 2 +- libethereum/Client.cpp | 7 +- libethereum/Client.h | 24 +----- libethereum/Farm.h | 4 +- libethereum/Interface.h | 4 +- libethereum/Miner.cpp | 94 --------------------- libethereum/Miner.h | 166 ------------------------------------- 10 files changed, 22 insertions(+), 297 deletions(-) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f3b4d1b18..ac54ebe4d 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -59,6 +59,15 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) +{ + WorkPackage ret; + ret.boundary = _bi.boundary(); + ret.headerHash = _bi.headerHash(WithNonce); + ret.seedHash = _bi.seedHash(); + return ret; +} + void Ethash::prep(BlockInfo const& _header) { if (_header.number % ETHASH_EPOCH_LENGTH == 1) diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index b87f06549..458cb4e6c 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -68,10 +68,11 @@ public: static std::string name(); static unsigned revision(); + static void prep(BlockInfo const& _header); static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } - static void prep(BlockInfo const& _header); class CPUMiner: public Miner, Worker { @@ -125,8 +126,5 @@ public: #endif }; -using ProofOfWork = Ethash; -using Solution = Ethash::Solution; - } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 0ff0a3628..b73a79c49 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "GenesisInfo.h" #include "State.h" @@ -336,7 +335,7 @@ ImportRoute BlockChain::attemptImport(bytes const& _block, OverlayDB const& _sta catch (...) { cwarn << "Unexpected exception! Could not import block!" << boost::current_exception_diagnostic_information(); - return make_pair(h256s(), h256()); + return make_pair(h256s(), h256s()); } } diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index cdff566fb..8b4a3dce4 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -68,7 +68,7 @@ ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0); using BlocksHash = std::map; using TransactionHashes = h256s; using UncleHashes = h256s; -using ImportRoute = std::pair; +using ImportRoute = std::pair; enum { ExtraDetails = 0, diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 9c6b87293..532c092ff 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -404,14 +404,17 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -pair Client::getWork() +ProofOfWork::WorkPackage Client::getWork() { Guard l(x_remoteMiner); + BlockInfo bi; { ReadGuard l(x_stateDB); m_remoteMiner.update(m_postMine, m_bc); + m_postMine.commitToMine(m_bc); + bi = m_postMine.info(); } - return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty()); + return ProofOfWork::package(bi); } bool Client::submitWork(ProofOfWork::Solution const& _solution) diff --git a/libethereum/Client.h b/libethereum/Client.h index a136033e5..9f6bbfeb6 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -73,28 +73,6 @@ private: std::string m_path; }; -class RemoteMiner: public OldMiner -{ -public: - RemoteMiner() {} - - void update(State const& _provisional, BlockChain const& _bc) { m_state = _provisional; m_state.commitToMine(_bc); } - - h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); } - u256 const& difficulty() const { return m_state.info().difficulty; } - - bool submitWork(ProofOfWork::Solution const& _result) { return (m_isComplete = m_state.completeMine(_result)); } - - virtual bool isComplete() const override { return m_isComplete; } - virtual bytes const& blockData() const { return m_state.blockData(); } - - virtual void noteStateChange() override {} - -private: - bool m_isComplete = false; - State m_state; -}; - class BasicGasPricer: public GasPricer { public: @@ -209,7 +187,7 @@ public: /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. - virtual std::pair getWork() override; + virtual ProofOfWork::WorkPackage getWork() override; /** @brief Submit the proof for the proof-of-work. * @param _s A valid solution. diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 39988c8d7..137c137d3 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -53,9 +53,7 @@ public: { WriteGuard l(x_work); m_header = _bi; - m_work.boundary = _bi.boundary(); - m_work.headerHash = _bi.headerHash(WithNonce); - m_work.seedHash = _bi.seedHash(); + m_work = PoW::package(m_header); ReadGuard l(x_miners); for (auto const& m: miners) m->setWork(m_work); diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 134bed53b..0ab81728b 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -26,11 +26,11 @@ #include #include #include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" #include "BlockDetails.h" -#include "Miner.h" namespace dev { @@ -188,7 +188,7 @@ public: virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; /// Check the progress of the mining. - virtual MineProgress miningProgress() const = 0; + virtual MiningProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp index b386fe868..e69de29bb 100644 --- a/libethereum/Miner.cpp +++ b/libethereum/Miner.cpp @@ -1,94 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** @file Miner.cpp - * @author Gav Wood - * @author Giacomo Tazzari - * @date 2014 - */ - -#include "Miner.h" - -#include -#include "State.h" -using namespace std; -using namespace dev; -using namespace dev::eth; - -OldMiner::~OldMiner() {} - -LocalMiner::LocalMiner(MinerHost* _host, unsigned _id) -{ - setup(_host, _id); -} - -void LocalMiner::setup(MinerHost* _host, unsigned _id) -{ - AsyncMiner::setup(_host, _id); - setName("miner-" + toString(m_id)); - m_pow.reset(_host->turbo() ? new Ethash : (Ethash*)new EthashCPU); -} - -void LocalMiner::doWork() -{ - // Do some mining. - if (m_miningStatus != Waiting && m_miningStatus != Mined) - { - if (m_miningStatus == Preparing) - { - m_host->setupState(m_mineState); - if (m_host->force() || m_mineState.pending().size()) - m_miningStatus = Mining; - else - m_miningStatus = Waiting; - - { - Guard l(x_mineInfo); - m_mineProgress.best = (double)-1; - m_mineProgress.hashes = 0; - m_mineProgress.ms = 0; - } - } - - if (m_miningStatus == Mining) - { - // Mine for a while. - MineInfo mineInfo = m_mineState.mine(m_pow.get()); - - { - Guard l(x_mineInfo); - m_mineProgress.best = min(m_mineProgress.best, mineInfo.best); - m_mineProgress.current = mineInfo.best; - m_mineProgress.requirement = mineInfo.requirement; - m_mineProgress.ms += 100; - m_mineProgress.hashes += mineInfo.hashes; - m_mineHistory.push_back(mineInfo); - } - if (mineInfo.completed) - { - m_mineState.completeMine(); - m_host->onComplete(); - m_miningStatus = Mined; - } - else - m_host->onProgressed(); - } - } - else - { - this_thread::sleep_for(chrono::milliseconds(100)); - } -} diff --git a/libethereum/Miner.h b/libethereum/Miner.h index 3abf93770..e69de29bb 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -1,166 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** @file Miner.h - * @author Alex Leverington - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "State.h" - -namespace dev -{ - -namespace eth -{ - -/** - * @brief Class for hosting one or more Miners. - * @warning Must be implemented in a threadsafe manner since it will be called from multiple - * miner threads. - */ -class MinerHost -{ -public: - virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. - virtual void onProgressed() {} ///< Called once some progress has been made. - virtual void onComplete() {} ///< Called once a block is found. - virtual bool force() const = 0; ///< @returns true iff the Miner should mine regardless of the number of transactions. - virtual bool turbo() const = 0; ///< @returns true iff the Miner should use GPU if possible. -}; - -class OldMiner -{ -public: - virtual ~OldMiner(); - - virtual void noteStateChange() = 0; - virtual bool isComplete() const = 0; - virtual bytes const& blockData() const = 0; -}; - -class AsyncMiner: public OldMiner -{ -public: - /// Null constructor. - AsyncMiner(): m_host(nullptr) {} - - /// Constructor. - AsyncMiner(MinerHost* _host, unsigned _id = 0): m_host(_host), m_id(_id) {} - - /// Setup its basics. - void setup(MinerHost* _host, unsigned _id = 0) { m_host = _host; m_id = _id; } - - /// Start mining. - virtual void start() {} - - /// Stop mining. - virtual void stop() {} - - /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). - virtual bool isRunning() const { return false; } - -protected: - MinerHost* m_host = nullptr; ///< Our host. - unsigned m_id = 0; ///< Our unique id. -}; - -/** - * @brief Implements Miner. - * To begin mining, use start() & stop(). noteStateChange() can be used to reset the mining and set up the - * State object according to the host. Use isRunning() to determine if the miner has been start()ed. - * Use isComplete() to determine if the miner has finished mining. - * - * blockData() can be used to retrieve the complete block, ready for insertion into the BlockChain. - * - * Information on the mining can be queried through miningProgress() and miningHistory(). - * @threadsafe - * @todo Signal Miner to restart once with condition variables. - */ -class LocalMiner: public AsyncMiner, Worker -{ -public: - /// Null constructor. - LocalMiner() {} - - /// Constructor. - LocalMiner(MinerHost* _host, unsigned _id = 0); - - /// Move-constructor. - LocalMiner(LocalMiner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); std::swap(m_pow, _m.m_pow); } - - /// Move-assignment. - LocalMiner& operator=(LocalMiner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); std::swap(m_pow, _m.m_pow); return *this; } - - /// Destructor. Stops miner. - ~LocalMiner() { stop(); } - - /// Setup its basics. - void setup(MinerHost* _host, unsigned _id = 0); - - /// Start mining. - void start() { startWorking(); } - - /// Stop mining. - void stop() { stopWorking(); } - - /// Call to notify Miner of a state change. - virtual void noteStateChange() override { m_miningStatus = Preparing; } - - /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). - bool isRunning() const override { return isWorking(); } - - /// @returns true if mining is complete. - virtual bool isComplete() const override { return m_miningStatus == Mined; } - - /// @returns the internal State object. - virtual bytes const& blockData() const override { return m_mineState.blockData(); } - - /// Check the progress of the mining. - MineProgress miningProgress() const { Guard l(x_mineInfo); return m_mineProgress; } - - /// Get and clear the mining history. - std::list miningHistory() { Guard l(x_mineInfo); auto ret = m_mineHistory; m_mineHistory.clear(); return ret; } - - /// @returns the state on which we mined. - State const& state() const { return m_mineState; } - -private: - /// Do some work on the mining. - virtual void doWork(); - - enum MiningStatus { Waiting, Preparing, Mining, Mined, Stopping, Stopped }; - MiningStatus m_miningStatus = Waiting; ///< TODO: consider mutex/atomic variable. - State m_mineState; ///< The state on which we are mining, generally equivalent to m_postMine. - std::unique_ptr m_pow; ///< Our miner. - - mutable Mutex x_mineInfo; ///< Lock for the mining progress & history. - MineProgress m_mineProgress; ///< What's our progress? - std::list m_mineHistory; ///< What the history of our mining? -}; - -} -} From 405653c250105daa0d2881d7f427343722aa0256 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 01:38:04 +0200 Subject: [PATCH 031/108] Lots of build fixes. Now minimal version builds ok. --- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 11 +- libethash-cl/ethash_cl_miner.cpp | 2 + libethash-cl/ethash_cl_miner.h | 2 + libethcore/Common.cpp | 3 +- libethcore/Common.h | 3 - libethcore/Ethash.cpp | 14 ++- libethcore/Ethash.h | 6 +- libethereum/Client.cpp | 124 ++++++++++------------ libethereum/Client.h | 10 +- libethereum/ClientBase.cpp | 4 +- libethereum/ClientBase.h | 43 ++++---- libethereum/Farm.h | 33 ++++-- libethereum/Interface.h | 2 +- libethereum/Miner.cpp | 0 libethereum/Miner.h | 0 libweb3jsonrpc/WebThreeStubServerBase.cpp | 5 +- libwebthree/WebThree.cpp | 4 +- libwebthree/WebThree.h | 3 +- 19 files changed, 143 insertions(+), 128 deletions(-) delete mode 100644 libethereum/Miner.cpp delete mode 100644 libethereum/Miner.h diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 374829a61..03d216a17 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -164,7 +164,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%2 D%3 H%4 v%5").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(c_ethashVersion).arg(dev::Version)); + ui->blockCount->setText(QString("PV%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(ProofOfWork::name()).arg(ProofOfWork::revision()).arg(dev::Version)); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); diff --git a/eth/main.cpp b/eth/main.cpp index e9af192f9..05826dc0f 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #if ETH_READLINE #include #include @@ -44,7 +45,6 @@ #include #include #endif -#include #include "BuildInfo.h" using namespace std; using namespace dev; @@ -210,7 +210,7 @@ void doInitDAG(unsigned _n) BlockInfo bi; bi.number = _n; cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; - Ethasher::get()->full(bi); + Ethash::prep(bi); exit(0); } @@ -271,7 +271,6 @@ int main(int argc, char** argv) /// Mining params unsigned mining = ~(unsigned)0; - int miners = -1; bool forceMining = false; KeyPair us = KeyPair::create(); Address coinbase = us.address(); @@ -477,8 +476,6 @@ int main(int argc, char** argv) g_logVerbosity = atoi(argv[++i]); else if ((arg == "-x" || arg == "--peers") && i + 1 < argc) peers = atoi(argv[++i]); - else if ((arg == "-t" || arg == "--miners") && i + 1 < argc) - miners = atoi(argv[++i]); else if ((arg == "-o" || arg == "--mode") && i + 1 < argc) { string m = argv[++i]; @@ -537,9 +534,7 @@ int main(int argc, char** argv) killChain, nodeMode == NodeMode::Full ? set{"eth", "shh"} : set(), netPrefs, - &nodesState, - miners - ); + &nodesState); if (mode == OperationMode::DAGInit) doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0)); diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 96f1fa582..016d8af58 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -50,6 +50,8 @@ static void add_definition(std::string& source, char const* id, unsigned value) source.insert(source.begin(), buf, buf + strlen(buf)); } +ethash_cl_miner::search_hook::~search_hook() {} + ethash_cl_miner::ethash_cl_miner() : m_opencl_1_1() { diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index e478c739f..d3d9f0223 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -12,6 +12,8 @@ class ethash_cl_miner public: struct search_hook { + virtual ~search_hook(); // always a virtual destructor for a class with virtuals. + // reports progress, return true to abort virtual bool found(uint64_t const* nonces, uint32_t count) = 0; virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index f0e749aaa..a0ceb389e 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,7 @@ #include #include #include "Exceptions.h" +#include "ProofOfWork.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -41,7 +42,7 @@ const unsigned c_databaseVersionModifier = 1; const unsigned c_databaseVersionModifier = 0; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (c_ethashVersion << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 4d01055f1..bb704405a 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -41,9 +41,6 @@ extern const unsigned c_minorProtocolVersion; /// Current database version. extern const unsigned c_databaseVersion; -/// Current database version. -extern const unsigned c_ethashVersion; - /// User-friendly string representation of the amount _b in wei. std::string formatBalance(bigint const& _b); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index ac54ebe4d..03c7a3654 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -70,8 +70,7 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) void Ethash::prep(BlockInfo const& _header) { - if (_header.number % ETHASH_EPOCH_LENGTH == 1) - EthashAux::full(_header); + EthashAux::full(_header); } bool Ethash::preVerify(BlockInfo const& _header) @@ -206,6 +205,12 @@ Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): { } +Ethash::GPUMiner::~GPUMiner() +{ + delete m_hook; + delete m_miner; +} + bool Ethash::GPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; @@ -221,7 +226,10 @@ void Ethash::GPUMiner::kickOff(WorkPackage const& _work) { if (m_miner) m_hook->abort(); - m_miner.reset(new ethash_cl_miner); + + delete m_miner; + m_miner = new ethash_cl_miner; + auto p = EthashAux::params(_work.seedHash); auto cb = [&](void* d) { EthashAux::full(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; m_miner->init(p, cb, 32); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 458cb4e6c..1a7d82149 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -105,6 +105,7 @@ public: public: GPUMiner(ConstructionInfo const& _ci); + ~GPUMiner(); static unsigned instances() { return 1; } @@ -115,8 +116,9 @@ public: private: bool report(uint64_t _nonce); - std::unique_ptr m_hook; - std::unique_ptr m_miner; + EthashCLHook* m_hook; + ethash_cl_miner* m_miner; + h256 m_minerSeed; WorkPackage m_lastWork; ///< Work loaded into m_miner. MineInfo m_info; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 532c092ff..17fb0bf0d 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -126,9 +126,9 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for m_preMine(m_stateDB, BaseState::CanonGenesis), m_postMine(m_stateDB) { - m_tqReady = m_tq->onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); - m_bqReady = m_bq->onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); - m_farm->onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); + m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); + m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); @@ -151,9 +151,9 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_preMine(m_stateDB), m_postMine(m_stateDB) { - m_tq->onReady([=](){ this->onTransactionQueueReady(); }); - m_bq->onReady([=](){ this->onBlockQueueReady(); }); - m_farm->onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); + m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); + m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); @@ -210,7 +210,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_localMiners.clear(); + m_farm.stop(); m_preMine = State(); m_postMine = State(); @@ -248,11 +248,7 @@ void Client::clearPending() m_postMine = m_preMine; } - { - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - m.noteStateChange(); - } + startMining(); noteChanged(changeds); } @@ -315,34 +311,23 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed) void Client::setForceMining(bool _enable) { m_forceMining = _enable; - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - m.noteStateChange(); + startMining(); } -MineProgress Client::miningProgress() const +MiningProgress Client::miningProgress() const { - MineProgress ret; - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - ret.combine(m.miningProgress()); - return ret; + return MiningProgress(); } uint64_t Client::hashrate() const { - uint64_t ret; - ReadGuard l(x_localMiners); - for (LocalMiner const& m: m_localMiners) - ret += m.miningProgress().hashes / m.miningProgress().ms; - return ret / 1000; + return 0; } std::list Client::miningHistory() { std::list ret; - - ReadGuard l(x_localMiners); +/* ReadGuard l(x_localMiners); if (m_localMiners.empty()) return ret; ret = m_localMiners[0].miningHistory(); @@ -353,11 +338,11 @@ std::list Client::miningHistory() auto li = l.begin(); for (; ri != ret.end() && li != l.end(); ++ri, ++li) ri->combine(*li); - } + }*/ return ret; } -void Client::setupState(State& _s) +/*void Client::setupState(State& _s) { { ReadGuard l(x_stateDB); @@ -378,7 +363,7 @@ void Client::setupState(State& _s) } else _s.commitToMine(m_bc); -} +}*/ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice, Address const& _from) { @@ -406,15 +391,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 ProofOfWork::WorkPackage Client::getWork() { - Guard l(x_remoteMiner); - BlockInfo bi; - { - ReadGuard l(x_stateDB); - m_remoteMiner.update(m_postMine, m_bc); - m_postMine.commitToMine(m_bc); - bi = m_postMine.info(); - } - return ProofOfWork::package(bi); + return ProofOfWork::package(m_miningInfo); } bool Client::submitWork(ProofOfWork::Solution const& _solution) @@ -422,7 +399,7 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) bytes newBlock; { WriteGuard l(x_stateDB); - if (!m_postMine.completeMine(_solution)) + if (!m_postMine.completeMine(_solution)) return false; newBlock = m_postMine.blockData(); } @@ -435,7 +412,7 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) void Client::syncBlockQueue() { - ImportResult ir; + ImportRoute ir; { WriteGuard l(x_stateDB); @@ -446,30 +423,33 @@ void Client::syncBlockQueue() tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); x_stateDB.lock(); - if (fresh.size()) - m_stateDB = db; + if (ir.first.empty()) + return; + m_stateDB = db; } - - if (!ir.first.empty()) - onChainChanged(ir); - return true; + onChainChanged(ir); } void Client::syncTransactionQueue() { // returns TransactionReceipts, once for each transaction. cwork << "postSTATE <== TQ"; + + h256Set changeds; TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); if (newPendingReceipts.size()) { for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - changeds.insert(PendingChangedFilter); - if (isMining()) - cnote << "Additional transaction ready: Restarting mining operation."; - resyncStateNeeded = true; + // TODO: Tell farm about new transaction (i.e. restartProofOfWork mining). + onPostStateChanged(); + + // Tell watches about the new transactions. + noteChanged(changeds); + + // Tell network about the new transactions. if (auto h = m_host.lock()) h->noteNewTransactions(); } @@ -504,27 +484,41 @@ void Client::onChainChanged(ImportRoute const& _ir) h256Set changeds; for (auto const& h: _ir.first) - if (h != _ir.second) - appendFromNewBlock(h, changeds); + appendFromNewBlock(h, changeds); changeds.insert(ChainChangedFilter); - noteChanged(changeds); // RESTART MINING - // LOCKS NEEDED? - Guard l(x_stateDB); - cwork << "preSTATE <== CHAIN"; - if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) + // LOCKS REALLY NEEDED? { - if (isMining()) - cnote << "New block on chain: Restarting mining operation."; - m_postMine = m_preMine; - resyncStateNeeded = true; - changeds.insert(PendingChangedFilter); + ReadGuard l(x_stateDB); + if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) + { + if (isMining()) + cnote << "New block on chain."; + + m_postMine = m_preMine; + changeds.insert(PendingChangedFilter); + + x_stateDB.unlock(); + onPostStateChanged(); + x_stateDB.lock(); + } + } + + noteChanged(changeds); +} +void Client::onPostStateChanged() +{ + cnote << "Post state changed: Restarting mining..."; + { + WriteGuard l(x_stateDB); m_postMine.commitToMine(m_bc); - m_farm.setWork(m_postMine.info()); + m_miningInfo = m_postMine.info(); } + + m_farm.setWork(m_miningInfo); } void Client::noteChanged(h256Set const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index 9f6bbfeb6..2235c4459 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -40,7 +40,6 @@ #include "TransactionQueue.h" #include "State.h" #include "CommonNet.h" -#include "Miner.h" #include "ABI.h" #include "Farm.h" #include "ClientBase.h" @@ -103,8 +102,6 @@ struct ClientDetail: public LogChannel { static const char* name() { return " C */ class Client: public ClientBase, Worker { - friend class OldMiner; - public: /// New-style Constructor. explicit Client( @@ -254,6 +251,10 @@ private: /// Magically called when m_tq needs syncing. Be nice and don't block. void onBlockQueueReady() { Guard l(x_fakeSignalSystemState); m_syncBlockQueue = true; } + /// Called when the post state has changed (i.e. when more transactions are in it or we're mining on a new block). + /// This updates m_miningInfo. + void onPostStateChanged(); + void checkWatchGarbage(); VersionChecker m_vc; ///< Dummy object to check & update the protocol version. @@ -265,12 +266,11 @@ private: OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it. State m_preMine; ///< The present state of the client. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). + BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine). std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. GenericFarm m_farm; ///< Our mining farm. - mutable Mutex x_remoteMiner; ///< The remote miner lock. - RemoteMiner m_remoteMiner; ///< The remote miner. Handler m_tqReady; Handler m_bqReady; diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 5a0aef7c3..ecc0fb7f5 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -20,10 +20,12 @@ * @date 2015 */ -#include #include "ClientBase.h" + +#include #include "BlockChain.h" #include "Executive.h" +#include "State.h" using namespace std; using namespace dev; diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 4b3cc5002..15dbbf1ab 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -25,6 +25,7 @@ #include #include "Interface.h" #include "LogFilter.h" +#include "TransactionQueue.h" namespace dev { @@ -60,15 +61,15 @@ struct ClientWatch }; struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; -#define cwatch dev::LogOutputStream() +#define cwatch LogOutputStream() struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; }; struct WorkOutChannel: public LogChannel { static const char* name() { return "() -#define cworkin dev::LogOutputStream() -#define cworkout dev::LogOutputStream() +#define cwork LogOutputStream() +#define cworkin LogOutputStream() +#define cworkout LogOutputStream() -class ClientBase: public dev::eth::Interface +class ClientBase: public Interface { public: ClientBase() {} @@ -110,18 +111,18 @@ public: virtual LocalisedLogEntries checkWatch(unsigned _watchId) override; virtual h256 hashFromNumber(BlockNumber _number) const override; - virtual eth::BlockInfo blockInfo(h256 _hash) const override; - virtual eth::BlockDetails blockDetails(h256 _hash) const override; - virtual eth::Transaction transaction(h256 _transactionHash) const override; - virtual eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; - virtual eth::Transactions transactions(h256 _blockHash) const override; - virtual eth::TransactionHashes transactionHashes(h256 _blockHash) const override; - virtual eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; - virtual eth::UncleHashes uncleHashes(h256 _blockHash) const override; + virtual BlockInfo blockInfo(h256 _hash) const override; + virtual BlockDetails blockDetails(h256 _hash) const override; + virtual Transaction transaction(h256 _transactionHash) const override; + virtual Transaction transaction(h256 _blockHash, unsigned _i) const override; + virtual Transactions transactions(h256 _blockHash) const override; + virtual TransactionHashes transactionHashes(h256 _blockHash) const override; + virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const override; + virtual UncleHashes uncleHashes(h256 _blockHash) const override; virtual unsigned transactionCount(h256 _blockHash) const override; virtual unsigned uncleCount(h256 _blockHash) const override; virtual unsigned number() const override; - virtual eth::Transactions pending() const override; + virtual Transactions pending() const override; virtual h256s pendingHashes() const override; void injectBlock(bytes const& _block); @@ -142,13 +143,13 @@ public: /// TODO: consider moving it to a separate interface - virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); } - virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); } - virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); } - virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::hashrate")); } - virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); } - virtual std::pair getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); } - virtual bool submitWork(eth::ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } + virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); } + virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::stopMining")); } + virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } + virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } + virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } + virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } + virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 137c137d3..09c7f0e78 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace dev { @@ -45,17 +46,25 @@ template class GenericFarm: public GenericFarmFace { public: + using WorkPackage = typename PoW::WorkPackage; + using Solution = typename PoW::Solution; + using Miner = GenericMiner; + /** * @brief Sets the current mining mission. * @param _bi The block (header) we wish to be mining. */ void setWork(BlockInfo const& _bi) { - WriteGuard l(x_work); - m_header = _bi; - m_work = PoW::package(m_header); - ReadGuard l(x_miners); - for (auto const& m: miners) + WorkPackage w; + { + WriteGuard l(x_work); + m_header = _bi; + w = m_work = PoW::package(m_header); + } + + ReadGuard l2(x_miners); + for (auto const& m: m_miners) m->setWork(m_work); } @@ -63,13 +72,13 @@ public: * @brief (Re)start miners for CPU only. * @returns true if started properly. */ - bool startCPU() { return start(); } + bool startCPU() { return start(); } /** * @brief (Re)start miners for GPU only. * @returns true if started properly. */ - bool startGPU() { start(); } + bool startGPU() { return start(); } /** * @brief Stop all mining activities. @@ -92,12 +101,14 @@ public: */ MiningProgress const& miningProgress() const { ReadGuard l(x_progress); return m_progress; } + using SolutionFound = std::function; + /** * @brief Provides a valid header based upon that received previously with setWork(). * @param _bi The now-valid header. * @return true if the header was good and that the Farm should pause until more work is submitted. */ - void onSolutionFound(function _handler) { m_onSolutionFound = _handler; } + void onSolutionFound(SolutionFound const& _handler) { m_onSolutionFound = _handler; } private: /** @@ -116,7 +127,7 @@ private: ReadGuard l(x_miners); for (std::shared_ptr const& m: m_miners) if (m.get() != _m) - m->pause(); + m->setWork(); m_work.headerHash = h256(); return true; } @@ -135,7 +146,7 @@ private: m_miners.clear(); m_miners.reserve(MinerType::instances()); for (unsigned i = 0; i < MinerType::instances(); ++i) - m_miners.push_back(new MinerType(std::make_pair(this, i))); + m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); return true; } @@ -149,7 +160,7 @@ private: WorkPackage m_work; BlockInfo m_header; - function m_onSolutionFound; + SolutionFound m_onSolutionFound; }; } diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 0ab81728b..b72a29c00 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -183,7 +183,7 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual std::pair getWork() = 0; + virtual ProofOfWork::WorkPackage getWork() = 0; /// Submit the nonce for the proof-of-work. virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/libethereum/Miner.h b/libethereum/Miner.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index e987e64cc..267961fd9 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -758,8 +758,9 @@ Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); auto r = client()->getWork(); - ret.append(toJS(r.first)); - ret.append(toJS(r.second)); + ret.append(toJS(r.headerHash)); + ret.append(toJS(r.seedHash)); + ret.append(toJS(r.boundary)); return ret; } diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 8ea2133f0..bbe0d55ec 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -42,7 +42,7 @@ WebThreeDirect::WebThreeDirect( WithExisting _we, std::set const& _interfaces, NetworkPreferences const& _n, - bytesConstRef _network, int _miners + bytesConstRef _network ): m_clientVersion(_clientVersion), m_net(_clientVersion, _n, _network) @@ -50,7 +50,7 @@ WebThreeDirect::WebThreeDirect( if (_dbPath.size()) Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0, _miners)); + m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); if (_interfaces.count("shh")) m_whisper = m_net.registerCapability(new WhisperHost); diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index 87cf62d4a..90a4aa3c2 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -112,8 +112,7 @@ public: WithExisting _we = WithExisting::Trust, std::set const& _interfaces = {"eth", "shh"}, p2p::NetworkPreferences const& _n = p2p::NetworkPreferences(), - bytesConstRef _network = bytesConstRef(), - int _miners = -1 + bytesConstRef _network = bytesConstRef() ); /// Destructor. From 3a59525ef6961be2e43d75b18a12eabde85ac7a3 Mon Sep 17 00:00:00 2001 From: winsvega Date: Thu, 9 Apr 2015 18:13:31 +0300 Subject: [PATCH 032/108] BlockTests: add expect section --- test/TestHelper.cpp | 1 - test/bcInvalidHeaderTestFiller.json | 193 +++++++++++++++++++++++----- test/bcJS_API_TestFiller.json | 15 +++ test/bcValidBlockTestFiller.json | 54 +++++++- test/blockchain.cpp | 19 ++- test/stTransactionTestFiller.json | 45 +++++++ test/ttTransactionTestFiller.json | 21 ++- 7 files changed, 308 insertions(+), 40 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index e86b84aad..45fe55b07 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -671,7 +671,6 @@ Options::Options() memory = true; inputLimits = true; bigData = true; - checkState = true; } } } diff --git a/test/bcInvalidHeaderTestFiller.json b/test/bcInvalidHeaderTestFiller.json index 2d23ca039..9c9bdacd5 100644 --- a/test/bcInvalidHeaderTestFiller.json +++ b/test/bcInvalidHeaderTestFiller.json @@ -17,9 +17,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -44,7 +49,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -54,7 +59,6 @@ }, "log1_wrongBloom" : { - "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", @@ -72,10 +76,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -100,7 +108,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -127,9 +135,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -144,7 +157,7 @@ "blocks" : [ { "blockHeader" : { - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1" + "coinbase" : "0x9888f1f195afa192cfee860698584c030f4c9db1" }, "transactions" : [ { @@ -154,7 +167,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -181,9 +194,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -208,7 +226,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -217,7 +235,7 @@ ] }, - "DifferentExtraData" : { + "DifferentExtraData1025" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", @@ -235,9 +253,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -252,7 +275,7 @@ "blocks" : [ { "blockHeader" : { - "extraData" : "0x42" + "extraData" : "0x0101020304050607080910111213141516171819202122232410000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000100000000000000000002000000000000000000030000000000000000000400000000000000000005000000000000000000060000000000000000000700000000000000000008000000000000000000090000000000000000000100000000000000000001000000000000000000020000000000000000000300000000000000000004000000000000000000050000000000000000000600000000000000000007000000000000000000080000000000000000000900000000000000000001000000000000000000010000000000000000000200000000000000000003000000000000000000040000000000000000000500000000000000000006000000000000000000070000000000000000000800000000000000000009000000000000000000010000000000000000000" }, "transactions" : [ { @@ -262,7 +285,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -289,9 +312,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -316,7 +344,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -344,9 +372,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -371,7 +404,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -398,9 +431,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -425,7 +463,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -452,9 +490,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -479,7 +522,66 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "wrongParentHash2" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "blocks" : [ + { + "blockHeader" : { + "parentHash" : "0x6151889c8f14ab46e32ee0b1894bc276416385d068a1ade000d0dadef9b08b18" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" } ], "uncleHeaders" : [ @@ -506,9 +608,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -533,7 +640,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -560,9 +667,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -587,7 +699,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -614,9 +726,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -641,7 +758,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -668,9 +785,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -695,7 +817,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ @@ -722,9 +844,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", + "balance" : "100000000000", "nonce" : "0", "code" : "", "storage": {} @@ -749,7 +876,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" + "value" : "5000" } ], "uncleHeaders" : [ diff --git a/test/bcJS_API_TestFiller.json b/test/bcJS_API_TestFiller.json index 468b3b2e8..fe7396e59 100644 --- a/test/bcJS_API_TestFiller.json +++ b/test/bcJS_API_TestFiller.json @@ -17,6 +17,21 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "70" + }, + "6295ee1b4f6dd65047762f924ecd367c17eabf8f" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x01" : "0x42", + "0x02" : "0x23", + "0x03" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x04" : "0x01", + "0x05" : "0x55114a49" + } + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", diff --git a/test/bcValidBlockTestFiller.json b/test/bcValidBlockTestFiller.json index c0ed86437..3529c61ee 100644 --- a/test/bcValidBlockTestFiller.json +++ b/test/bcValidBlockTestFiller.json @@ -1,5 +1,4 @@ { - "diff1024" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -18,6 +17,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "10" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -64,6 +68,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "10" + }, + "8888f1f195afa192cfee860698584c030f4c9db1" : { + "balance" : "1500000000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -109,6 +121,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -127,7 +144,7 @@ "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "0" + "value" : "100" } ], "uncleHeaders" : [ @@ -154,6 +171,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "10" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -199,6 +221,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "8000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -253,6 +280,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "5000000000" + }, + "8888f1f195afa192cfee860698584c030f4c9db1" : { + "balance" : "1500000000000210000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -307,6 +342,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "5000000100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -358,6 +398,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "8888f1f195afa192cfee860698584c030f4c9db1" : { + "balance" : "1500000000002500000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -403,6 +448,11 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "5000000100" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 15cda8037..b225d313b 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -288,12 +288,24 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blObj.erase(blObj.find("blockHeader")); blObj.erase(blObj.find("uncleHeaders")); blObj.erase(blObj.find("transactions")); + state = State(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + importer.importState(o["pre"].get_obj(), state); } blArray.push_back(blObj); } + + if (o.count("expect") > 0) + { + stateOptionsMap expectStateMap; + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); + ImportTest::checkExpectedState(stateExpect, state, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); + o.erase(o.find("expect")); + } + o["blocks"] = blArray; o["postState"] = fillJsonWithState(state); - } + }//_fillin else { @@ -667,6 +679,11 @@ RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs, byt BOOST_AUTO_TEST_SUITE(BlockChainTests) +BOOST_AUTO_TEST_CASE(bcForkBlockTest) +{ + dev::test::executeTests("bcForkBlockTest", "/BlockTests", dev::test::doBlockchainTests); +} + BOOST_AUTO_TEST_CASE(bcInvalidRLPTest) { dev::test::executeTests("bcInvalidRLPTest", "/BlockTests", dev::test::doBlockchainTests); diff --git a/test/stTransactionTestFiller.json b/test/stTransactionTestFiller.json index 28e7318fd..70d329d6c 100644 --- a/test/stTransactionTestFiller.json +++ b/test/stTransactionTestFiller.json @@ -79,6 +79,49 @@ } }, + "EmptyTransaction3" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "1000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "expect" : { + "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { + "balance" : "21000" + }, + "6295ee1b4f6dd65047762f924ecd367c17eabf8f" : { + "code" : "0x" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "79000", + "nonce" : "1" + } + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "", + "gasLimit" : "22000", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "", + "value" : "" + } + }, + "TransactionSendingToEmpty" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", @@ -640,6 +683,7 @@ }, "expect" : { "0000000000000000000000000000000000000000" : { + "balance" : "0", "storage" : { "0x" : "0x0c", "0x01" : "0x0c", @@ -794,6 +838,7 @@ "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" }, "expect" : { + "balance" : "0", "0000000000000000000000000000000000000000" : { "storage" : { "0x" : "0x0c", diff --git a/test/ttTransactionTestFiller.json b/test/ttTransactionTestFiller.json index 1d4f5bcdd..cb39b533c 100644 --- a/test/ttTransactionTestFiller.json +++ b/test/ttTransactionTestFiller.json @@ -347,7 +347,7 @@ } }, - "TransactionWithSvalueWrongSize" : { + "TransactionWithSvalueWrongSize" : { "transaction" : { "data" : "", @@ -407,7 +407,7 @@ } }, - "TransactionWithHihghGasPrice" : { + "TransactionWithHihghGasPrice" : { "transaction" : { "data" : "", @@ -422,7 +422,7 @@ } }, - "TransactionWithGasLimitxPriceOverflow" : { + "TransactionWithGasLimitxPriceOverflow" : { "transaction" : { "data" : "", @@ -612,5 +612,20 @@ "v": "28", "value": "0" } + }, + + "RSsecp256k1" : { + "transaction" : + { + "data" : "0x5544", + "gasLimit" : "2000", + "gasPrice" : "1", + "nonce" : "3", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10", + "v" : "28", + "r" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "s" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" + } } } From 6e7a73af96c3f3df4692191354f8c63fb8e66d05 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 10 Apr 2015 20:49:29 +0300 Subject: [PATCH 033/108] Check State: Block Test + Transaction --- test/blockchain.cpp | 10 ++-- test/transaction.cpp | 71 ++++++++++++++++++---------- test/ttTransactionTestFiller.json | 78 +++++++++++++++++-------------- 3 files changed, 96 insertions(+), 63 deletions(-) diff --git a/test/blockchain.cpp b/test/blockchain.cpp index b225d313b..23bfd665b 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -53,6 +53,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); State state(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateTemp(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); importer.importState(o["pre"].get_obj(), state); o["pre"] = fillJsonWithState(state); state.commit(); @@ -89,7 +90,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) for (auto const& bl: o["blocks"].get_array()) { mObject blObj = bl.get_obj(); - + stateTemp = state; // get txs TransactionQueue txs; ZeroGasPricer gp; @@ -180,7 +181,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } uncleHeaderObj_pre = uncleHeaderObj; - } + } //for blObj["uncleHeaders"].get_array() blObj["uncleHeaders"] = aUncleList; bc.sync(uncleBlockQueue, state.db(), 4); @@ -288,11 +289,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blObj.erase(blObj.find("blockHeader")); blObj.erase(blObj.find("uncleHeaders")); blObj.erase(blObj.find("transactions")); - state = State(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); - importer.importState(o["pre"].get_obj(), state); + state = stateTemp; //revert state as if it was before executing this block } blArray.push_back(blObj); - } + } //for blocks if (o.count("expect") > 0) { diff --git a/test/transaction.cpp b/test/transaction.cpp index 7aa073f29..daf8368d4 100644 --- a/test/transaction.cpp +++ b/test/transaction.cpp @@ -36,8 +36,54 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) cerr << i.first << endl; mObject& o = i.second.get_obj(); - if (_fillin == false) + if (_fillin) { + BOOST_REQUIRE(o.count("transaction") > 0); + mObject tObj = o["transaction"].get_obj(); + + //Construct Rlp of the given transaction + RLPStream rlpStream = createRLPStreamFromTransactionFields(tObj); + o["rlp"] = "0x" + toHex(rlpStream.out()); + + try + { + Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); + if (!txFromFields.signature().isValid()) + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); + + o["sender"] = toString(txFromFields.sender()); + } + catch(Exception const& _e) + { + //Transaction is InValid + cnote << "Transaction Exception: " << diagnostic_information(_e); + o.erase(o.find("transaction")); + if (o.count("expect") > 0) + { + bool expectInValid = (o["expect"].get_str() == "invalid"); + if (Options::get().checkState) + BOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction " << i.first << " is not expected to be invalid!"); + else + BOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction " << i.first << " is not expected to be invalid!"); + + o.erase(o.find("expect")); + } + } + + //Transaction is Valid + if (o.count("expect") > 0) + { + bool expectValid = (o["expect"].get_str() == "valid"); + if (Options::get().checkState) + BOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction " << i.first << " is not expected to be valid!"); + else + BOOST_WARN_MESSAGE(expectValid, "Check state: Transaction " << i.first << " is not expected to be valid!"); + + o.erase(o.find("expect")); + } + } + else + { BOOST_REQUIRE(o.count("rlp") > 0); Transaction txFromRlp; try @@ -80,29 +126,6 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) Address addressReaded = Address(o["sender"].get_str()); BOOST_CHECK_MESSAGE(txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!"); } - else - { - BOOST_REQUIRE(o.count("transaction") > 0); - mObject tObj = o["transaction"].get_obj(); - - //Construct Rlp of the given transaction - RLPStream rlpStream = createRLPStreamFromTransactionFields(tObj); - o["rlp"] = "0x" + toHex(rlpStream.out()); - - try - { - Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); - if (!txFromFields.signature().isValid()) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); - - o["sender"] = toString(txFromFields.sender()); - } - catch(Exception const& _e) - { - cnote << "Transaction Exception: " << diagnostic_information(_e); - o.erase(o.find("transaction")); - } - } }//for }//doTransactionTests diff --git a/test/ttTransactionTestFiller.json b/test/ttTransactionTestFiller.json index cb39b533c..b75947e87 100644 --- a/test/ttTransactionTestFiller.json +++ b/test/ttTransactionTestFiller.json @@ -1,5 +1,6 @@ { "RightVRSTest" : { + "expect" : "valid", "transaction" : { "data" : "0x5544", @@ -15,6 +16,7 @@ }, "V_overflow32bit" : { + "expect" : "invalid", "transaction" : { "data" : "0x5544", @@ -30,6 +32,7 @@ }, "V_overflow32bitSigned" : { + "expect" : "invalid", "transaction" : { "data" : "0x5544", @@ -45,6 +48,7 @@ }, "V_overflow64bit" : { + "expect" : "invalid", "transaction" : { "data" : "0x5544", @@ -60,6 +64,7 @@ }, "V_overflow64bitSigned" : { + "expect" : "invalid", "transaction" : { "data" : "0x5544", @@ -75,6 +80,7 @@ }, "WrongVRSTestVEqual26" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -90,6 +96,7 @@ }, "WrongVRSTestVEqual29" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -105,6 +112,7 @@ }, "WrongVRSTestVEqual31" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -120,6 +128,7 @@ }, "WrongVRSTestVOverflow" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -135,6 +144,7 @@ }, "WrongVRSTestIncorrectSize" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -151,6 +161,7 @@ "SenderTest" : { "//" : "sender a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "expect" : "valid", "transaction" : { "data" : "", @@ -167,6 +178,7 @@ }, "DataTest" : { + "expect" : "valid", "transaction" : { "data" : "0x0358ac39584bc98a7c979f984b03", @@ -183,6 +195,7 @@ }, "TransactionWithTooManyRLPElements" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -199,6 +212,7 @@ }, "TransactionWithTooFewRLPElements" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -212,6 +226,7 @@ }, "TransactionWithHihghValue" : { + "expect" : "valid", "transaction" : { "data" : "", @@ -228,6 +243,7 @@ "TransactionWithHihghValueOverflow" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -243,6 +259,7 @@ }, "TransactionWithSvalueHigh" : { + "expect" : "valid", "transaction" : { "data" : "", @@ -258,6 +275,7 @@ }, "TransactionWithSvalueTooHigh" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -273,6 +291,7 @@ }, "TransactionWithSvalueOverflow" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -288,6 +307,7 @@ }, "TransactionWithRvalueOverflow" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -303,6 +323,7 @@ }, "TransactionWithRvalueHigh" : { + "expect" : "valid", "transaction" : { "data" : "", @@ -318,6 +339,7 @@ }, "TransactionWithRvalueTooHigh" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -333,6 +355,7 @@ }, "TransactionWithRvalueWrongSize" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -348,6 +371,7 @@ }, "TransactionWithSvalueWrongSize" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -363,6 +387,7 @@ }, "TransactionWithHihghNonce" : { + "expect" : "valid", "transaction" : { "data" : "", @@ -378,6 +403,7 @@ }, "TransactionWithNonceOverflow" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -393,6 +419,7 @@ }, "TransactionWithHihghGas" : { + "expect" : "valid", "transaction" : { "data" : "", @@ -408,6 +435,7 @@ }, "TransactionWithHihghGasPrice" : { + "expect" : "valid", "transaction" : { "data" : "", @@ -423,6 +451,7 @@ }, "TransactionWithGasLimitxPriceOverflow" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -438,6 +467,7 @@ }, "TransactionWithGasPriceOverflow" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -453,6 +483,7 @@ }, "TransactionWithGasLimitOverflow" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -468,6 +499,7 @@ }, "AddressMoreThan20PrefixedBy0" : { + "expect" : "invalid", "transaction" : { "data" : "0x12", @@ -483,14 +515,15 @@ }, "EmptyTransaction" : { + "expect" : "valid", "transaction" : { "data" : "", - "gasLimit" : "", - "gasPrice" : "", - "nonce" : "", + "gasLimit" : "0", + "gasPrice" : "0", + "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "", + "value" : "0", "v" : "27", "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" @@ -498,6 +531,7 @@ }, "AddressMoreThan20" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -513,6 +547,7 @@ }, "AddressLessThan20" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -528,6 +563,7 @@ }, "AddressLessThan20Prefixed0" : { + "expect" : "invalid", "transaction" : { "data" : "", @@ -542,37 +578,8 @@ } }, - "ValuesAsHex" : { - "transaction" : - { - "data" : "", - "gasLimit" : "0xadc053", - "gasPrice" : "1", - "nonce" : "0xffdc5", - "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "value" : "4294820140", - "v" : "28", - "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", - "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" - } - }, - - "ValuesAsDec" : { - "transaction" : - { - "data" : "", - "gasLimit" : "11386963", - "gasPrice" : "1", - "nonce" : "1048005", - "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "value" : "4501151495864620", - "v" : "28", - "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", - "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" - } - }, - "unpadedRValue": { + "expect" : "valid", "transaction": { "nonce": "13", "gasPrice": "0x09184e72a000", @@ -587,6 +594,7 @@ }, "libsecp256k1test": { + "expect" : "valid", "transaction": { "nonce": "", "gasPrice": "0x09184e72a000", @@ -601,6 +609,7 @@ }, "dataTx_bcValidBlockTest": { + "expect" : "valid", "transaction": { "nonce": "0", "gasPrice": "50", @@ -615,6 +624,7 @@ }, "RSsecp256k1" : { + "expect" : "valid", "transaction" : { "data" : "0x5544", From 2857ab260c9dfa21bad719d333d231cb0d606ffa Mon Sep 17 00:00:00 2001 From: winsvega Date: Sat, 11 Apr 2015 02:45:48 +0300 Subject: [PATCH 034/108] Check State: expect in blocks transactions test fetched to POC changes --- test/bcUncleTestFiller.json | 133 ++++++++++++++++++++++++++++ test/transaction.cpp | 8 +- test/ttTransactionTestFiller.json | 138 ++++++++++++++++++------------ 3 files changed, 222 insertions(+), 57 deletions(-) diff --git a/test/bcUncleTestFiller.json b/test/bcUncleTestFiller.json index 9c0cedc3b..e67cfeecd 100644 --- a/test/bcUncleTestFiller.json +++ b/test/bcUncleTestFiller.json @@ -17,6 +17,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -95,6 +103,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -188,6 +204,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -281,6 +305,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -374,6 +406,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -470,6 +510,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -566,6 +614,20 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "bcde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + }, + "ccde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -677,6 +739,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -806,6 +876,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "40" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "4" + }, + "bcde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1125000000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -914,6 +995,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "50" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "5" + }, + "bcde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "937500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -1037,6 +1129,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "60" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "6" + }, + "bcde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "750000000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -1175,6 +1278,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "70" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "7" + }, + "bcde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "562500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -1328,6 +1442,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "80" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "8" + }, + "bcde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "375000000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -1496,6 +1621,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "80" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "8" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", diff --git a/test/transaction.cpp b/test/transaction.cpp index daf8368d4..b87cc37e9 100644 --- a/test/transaction.cpp +++ b/test/transaction.cpp @@ -62,9 +62,9 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { bool expectInValid = (o["expect"].get_str() == "invalid"); if (Options::get().checkState) - BOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction " << i.first << " is not expected to be invalid!"); + BOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!"); else - BOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction " << i.first << " is not expected to be invalid!"); + BOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!"); o.erase(o.find("expect")); } @@ -75,9 +75,9 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { bool expectValid = (o["expect"].get_str() == "valid"); if (Options::get().checkState) - BOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction " << i.first << " is not expected to be valid!"); + BOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!"); else - BOOST_WARN_MESSAGE(expectValid, "Check state: Transaction " << i.first << " is not expected to be valid!"); + BOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!"); o.erase(o.find("expect")); } diff --git a/test/ttTransactionTestFiller.json b/test/ttTransactionTestFiller.json index b75947e87..1dcc0f94e 100644 --- a/test/ttTransactionTestFiller.json +++ b/test/ttTransactionTestFiller.json @@ -3,8 +3,24 @@ "expect" : "valid", "transaction" : { - "data" : "0x5544", - "gasLimit" : "2000", + "data" : "0x", + "gasLimit" : "21000", + "gasPrice" : "1", + "nonce" : "3", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10", + "v" : "28", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" + } + }, + + "NotEnoughGasLimit" : { + "expect" : "invalid", + "transaction" : + { + "data" : "0x", + "gasLimit" : "20000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -20,7 +36,7 @@ "transaction" : { "data" : "0x5544", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -36,7 +52,7 @@ "transaction" : { "data" : "0x5544", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -52,7 +68,7 @@ "transaction" : { "data" : "0x5544", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -68,7 +84,7 @@ "transaction" : { "data" : "0x5544", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -84,7 +100,7 @@ "transaction" : { "data" : "", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -100,7 +116,7 @@ "transaction" : { "data" : "", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -116,7 +132,7 @@ "transaction" : { "data" : "", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -132,7 +148,7 @@ "transaction" : { "data" : "", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -148,7 +164,7 @@ "transaction" : { "data" : "", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -160,12 +176,12 @@ }, "SenderTest" : { - "//" : "sender a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "//" : "sender 0f65fe9276bc9a24ae7083ae28e2660ef72df99e", "expect" : "valid", "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -177,12 +193,29 @@ } }, - "DataTest" : { + "DataTestNotEnoughGAS" : { + "expect" : "invalid", + "transaction" : + { + "data" : "0x0358ac39584bc98a7c979f984b03", + "gasLimit" : "21020", + "gasPrice" : "1", + "nonce" : "0", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "secretkey 45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + } + }, + + "DataTestEnoughGAS" : { "expect" : "valid", "transaction" : { "data" : "0x0358ac39584bc98a7c979f984b03", - "gasLimit" : "850", + "gasLimit" : "23000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -199,7 +232,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -230,7 +263,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -242,12 +275,12 @@ }, - "TransactionWithHihghValueOverflow" : { + "TransactionWithHighValueOverflow" : { "expect" : "invalid", "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -263,7 +296,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -279,7 +312,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -295,7 +328,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -311,7 +344,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -323,11 +356,11 @@ }, "TransactionWithRvalueHigh" : { - "expect" : "valid", + "expect" : "invalid", "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -343,7 +376,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -354,12 +387,12 @@ } }, - "TransactionWithRvalueWrongSize" : { - "expect" : "invalid", + "TransactionWithRvaluePrefixed00" : { + "expect" : "valid", "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -370,12 +403,12 @@ } }, - "TransactionWithSvalueWrongSize" : { - "expect" : "invalid", + "TransactionWithSvaluePrefixed00" : { + "expect" : "valid", "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -391,7 +424,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -407,7 +440,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "115792089237316195423570985008687907853269984665640564039457584007913129639936", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -439,7 +472,7 @@ "transaction" : { "data" : "", - "gasLimit" : "1000", + "gasLimit" : "21000", "gasPrice" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -451,7 +484,7 @@ }, "TransactionWithGasLimitxPriceOverflow" : { - "expect" : "invalid", + "expect" : "valid", "transaction" : { "data" : "", @@ -471,7 +504,7 @@ "transaction" : { "data" : "", - "gasLimit" : "850", + "gasLimit" : "21000", "gasPrice" : "115792089237316195423570985008687907853269984665640564039457584007913129639936", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -503,7 +536,7 @@ "transaction" : { "data" : "0x12", - "gasLimit" : "1000", + "gasLimit" : "21000", "gasPrice" : "123", "nonce" : "54", "to" : "0x0000000000000000095e7baea6a6c7c4c2dfeb977efac326af552d87", @@ -515,7 +548,7 @@ }, "EmptyTransaction" : { - "expect" : "valid", + "expect" : "invalid", "transaction" : { "data" : "", @@ -535,7 +568,7 @@ "transaction" : { "data" : "", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b1c", @@ -551,7 +584,7 @@ "transaction" : { "data" : "", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "b9331677e6ebf", @@ -563,11 +596,11 @@ }, "AddressLessThan20Prefixed0" : { - "expect" : "invalid", + "expect" : "valid", "transaction" : { "data" : "", - "gasLimit" : "2000", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "0", "to" : "0x000000000000000000000000000b9331677e6ebf", @@ -583,7 +616,7 @@ "transaction": { "nonce": "13", "gasPrice": "0x09184e72a000", - "gasLimit": "0x2710", + "gasLimit": "0xf710", "to": "7c47ef93268a311f4cad0c750724299e9b72c268", "data": "0x379607f50000000000000000000000000000000000000000000000000000000000000005", "r": "0x006ab6dda9f4df56ea45583af36660329147f1753f3724ea5eb9ed83e812ca77", @@ -596,15 +629,15 @@ "libsecp256k1test": { "expect" : "valid", "transaction": { - "nonce": "", + "nonce": "0", "gasPrice": "0x09184e72a000", - "gasLimit": "0x1388", + "gasLimit": "0xf388", "to": "", - "data": "", + "data": "0x", "r": "44", "s": "4", "v": "27", - "value": "" + "value": "0" } }, @@ -624,11 +657,10 @@ }, "RSsecp256k1" : { - "expect" : "valid", - "transaction" : - { - "data" : "0x5544", - "gasLimit" : "2000", + "expect" : "invalid", + "transaction" : { + "data" : "0x", + "gasLimit" : "21000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", From 7477b435f63867bea045bb3f5c69623523a92e54 Mon Sep 17 00:00:00 2001 From: winsvega Date: Sun, 12 Apr 2015 17:14:14 +0300 Subject: [PATCH 035/108] Check State: Block Tests --- test/bcUncleHeaderValiditiyFiller.json | 98 ++++++++++++++++++++++++++ test/blockchain.cpp | 2 +- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/test/bcUncleHeaderValiditiyFiller.json b/test/bcUncleHeaderValiditiyFiller.json index 9725a3241..ee36e230d 100644 --- a/test/bcUncleHeaderValiditiyFiller.json +++ b/test/bcUncleHeaderValiditiyFiller.json @@ -17,6 +17,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -110,6 +121,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -204,6 +226,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -298,6 +331,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -392,6 +436,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -486,6 +541,17 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -580,6 +646,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -674,6 +748,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -768,6 +850,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", @@ -862,6 +952,14 @@ "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000000", diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 23bfd665b..35fa8ccd7 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -617,7 +617,7 @@ BlockInfo constructBlock(mObject& _o) catch (Exception const& _e) { cnote << "block population did throw an exception: " << diagnostic_information(_e); - BOOST_ERROR("Failed block population with Exception: " << _e.what()); + //BOOST_ERROR("Failed block population with Exception: " << _e.what()); } catch (std::exception const& _e) { From 59e8f899a072be329c5dd3fb361354a6603a82ad Mon Sep 17 00:00:00 2001 From: winsvega Date: Mon, 13 Apr 2015 13:02:51 +0300 Subject: [PATCH 036/108] Check State: Style --- test/blockchain.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 35fa8ccd7..97171e3f2 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -617,7 +617,6 @@ BlockInfo constructBlock(mObject& _o) catch (Exception const& _e) { cnote << "block population did throw an exception: " << diagnostic_information(_e); - //BOOST_ERROR("Failed block population with Exception: " << _e.what()); } catch (std::exception const& _e) { From 77dd1ce169413613c8059e0701dd2e5e3e6ed718 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 13 Apr 2015 13:31:08 +0200 Subject: [PATCH 037/108] LogsPane ui changes --- mix/qml/LogsPane.qml | 8 +++++++- mix/qml/StatusPane.qml | 27 ++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index 175f7d96b..6b8a66638 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -6,7 +6,9 @@ import org.ethereum.qml.SortFilterProxyModel 1.0 Rectangle { - property variant currentStatus; + property variant currentStatus + property int contentXPos: logStyle.generic.layout.dateWidth + logStyle.generic.layout.typeWidth - 70 + function clear() { logsModel.clear(); @@ -117,6 +119,10 @@ Rectangle return cl; } + Component.onCompleted: + { + logsPane.contentXPos = logContent.x + } MouseArea { diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index f3bde4a04..9cf1238ad 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -284,14 +284,17 @@ Rectangle { { if (logsContainer.state === "opened") { + statusContainer.visible = true logsContainer.state = "closed" } else { + statusContainer.visible = false logsContainer.state = "opened"; logsContainer.focus = true; forceActiveFocus(); - calCoord(); + calCoord() + move() } } @@ -304,20 +307,30 @@ Rectangle { function calCoord() { + if (!logsContainer.parent.parent) + return var top = logsContainer; while (top.parent) top = top.parent var coordinates = logsContainer.mapToItem(top, 0, 0); logsContainer.parent = top; logsShadow.parent = top; - logsContainer.x = status.x + statusContainer.x - logStyle.generic.layout.dateWidth - logStyle.generic.layout.typeWidth + 70 - logsShadow.x = status.x + statusContainer.x - logStyle.generic.layout.dateWidth - logStyle.generic.layout.typeWidth + 70; + top.onWidthChanged.connect(move) + top.onHeightChanged.connect(move) + } + + function move() + { + var statusGlobalCoord = status.mapToItem(null, 0, 0); + console.log("ddd " + statusGlobalCoord.x); + logsContainer.x = statusGlobalCoord.x - logPane.contentXPos + logsShadow.x = statusGlobalCoord.x - logPane.contentXPos logsShadow.z = 1 logsContainer.z = 2 if (Qt.platform.os === "osx") { - logsContainer.y = statusContainer.y; - logsShadow.y = statusContainer.y; + logsContainer.y = statusGlobalCoord.y; + logsShadow.y = statusGlobalCoord.y; } } @@ -328,6 +341,10 @@ Rectangle { LogsPane { id: logPane; + onContentXPosChanged: + { + parent.move(); + } } states: [ From 81baf8b8a400ffc49faf8a59455c7b9f038aed60 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 13 Apr 2015 14:20:54 +0200 Subject: [PATCH 038/108] fixed deps on buildbot server && updated findMHD --- cmake/FindMHD.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake index 594af2369..b3f4dc546 100644 --- a/cmake/FindMHD.cmake +++ b/cmake/FindMHD.cmake @@ -38,8 +38,8 @@ set(MHD_LIBRARIES ${MHD_LIBRARY}) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") #TODO: place dlls into CMAKE_CFG_INTDIR subfolders - string(REPLACE ".lib" ".dll" MHD_DLL_RELEASE ${MHD_LIBRARY}) - string(REPLACE "/lib/" "/bin/" MHD_DLL_RELEASE ${MHD_DLL_RELEASE}) + #string(REPLACE ".lib" ".dll" MHD_DLL_RELEASE ${MHD_LIBRARY}) + #string(REPLACE "/lib/" "/bin/" MHD_DLL_RELEASE ${MHD_DLL_RELEASE}) if (CMAKE_CL_64) set(MHD_NAMES_DEBUG microhttpd_d_x64 microhttpd-10_d_x64 libmicrohttpd_d_x64 libmicrohttpd-dll_d_x64) @@ -56,7 +56,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # not sure why this was commented # always use release for now, need to ask Arkadiy #string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG}) - #set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) + set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) endif() From 3de1ab95b01b5b3654e6a92f0ed3dd6e0527172e Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 13 Apr 2015 14:52:37 +0200 Subject: [PATCH 039/108] UI changes on status panel --- mix/qml/StatusPane.qml | 46 ++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 118c3f21d..8e00eb759 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -187,25 +187,32 @@ Rectangle { else width = undefined } + } - Button - { - anchors.fill: parent - id: toolTip - action: toolTipInfo - text: "" - z: 3; - style: - ButtonStyle { - background:Rectangle { - color: "transparent" - } + Button + { + anchors.fill: parent + id: toolTip + action: toolTipInfo + text: "" + z: 3; + style: + ButtonStyle { + background:Rectangle { + color: "transparent" } - MouseArea { - anchors.fill: parent - onClicked: { + } + MouseArea { + anchors.fill: parent + onClicked: { + var globalCoord = goToLineBtn.mapToItem(statusContainer, 0, 0); + if (mouseX > globalCoord.x + && mouseX < globalCoord.x + goToLineBtn.width + && mouseY > globalCoord.y + && mouseY < globalCoord.y + goToLineBtn.height) + goToCompilationError.trigger(goToLineBtn); + else logsContainer.toggle(); - } } } } @@ -240,13 +247,13 @@ Rectangle { background: Rectangle { color: "transparent" - Image { + Image { source: "qrc:/qml/img/warningicon.png" height: 30 width: 30 sourceSize.width: 30 - sourceSize.height: 30 - anchors.centerIn: parent + sourceSize.height: 30 + anchors.centerIn: parent } } } @@ -335,7 +342,6 @@ Rectangle { function move() { var statusGlobalCoord = status.mapToItem(null, 0, 0); - console.log("ddd " + statusGlobalCoord.x); logsContainer.x = statusGlobalCoord.x - logPane.contentXPos logsShadow.x = statusGlobalCoord.x - logPane.contentXPos logsShadow.z = 1 From 5acf1a1f4b149588e874215b8a3d9a42c9ee2c5d Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 13 Apr 2015 15:49:07 +0200 Subject: [PATCH 040/108] Bug Fix #1585 --- mix/ClientModel.cpp | 4 +++- mix/Web3Server.h | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 41aa55249..29d4556ce 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -222,12 +222,14 @@ void ClientModel::executeSequence(vector const& _sequence, emit runStarted(); emit runStateChanged(); + //m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_client->userAccounts(), m_client.get())); + m_client->resetState(_balances); + m_web3Server.setAccounts(m_client->userAccounts()); //run sequence m_runFuture = QtConcurrent::run([=]() { try { - m_client->resetState(_balances); onStateReset(); for (TransactionSettings const& transaction: _sequence) { diff --git a/mix/Web3Server.h b/mix/Web3Server.h index cfe5c889e..b8a059295 100644 --- a/mix/Web3Server.h +++ b/mix/Web3Server.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of cpp-ethereum. - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file Web3Server.h * @author Arkadiy Paronyan arkadiy@ethdev.com From eee5d083e32a518ce98ffc28cfdf79a781d9c3f0 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 13 Apr 2015 16:55:26 +0200 Subject: [PATCH 041/108] copying mhd dlls --- cmake/EthDependencies.cmake | 1 + cmake/EthExecutableHelper.cmake | 7 +++++++ cmake/FindMHD.cmake | 14 +++++++------- eth/CMakeLists.txt | 4 +++- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 61c87efd2..9c38b6919 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -59,6 +59,7 @@ if (JSONRPC) find_package(MHD) message(" - microhttpd header: ${MHD_INCLUDE_DIRS}") message(" - microhttpd lib : ${MHD_LIBRARIES}") + message(" - microhttpd dll : ${MHD_DLLS}") endif() #JSONRPC diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 0c529881f..8d7bb6770 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -43,6 +43,13 @@ macro(eth_add_executable EXECUTABLE) endmacro() +macro(eth_copy_dlls EXECUTABLE DLLS) + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMNAND ${CMAKE_COMMAND} + -DLIBS="${DLLS}" + -DCONFIGURATION="$" + -DDESTINATION="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" +endmacro() + # # this function requires the following variables to be specified: # ETH_DEPENDENCY_INSTALL_DIR diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake index b3f4dc546..1915b2f19 100644 --- a/cmake/FindMHD.cmake +++ b/cmake/FindMHD.cmake @@ -37,10 +37,6 @@ set(MHD_LIBRARIES ${MHD_LIBRARY}) # official MHD project actually uses _d suffix if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - #TODO: place dlls into CMAKE_CFG_INTDIR subfolders - #string(REPLACE ".lib" ".dll" MHD_DLL_RELEASE ${MHD_LIBRARY}) - #string(REPLACE "/lib/" "/bin/" MHD_DLL_RELEASE ${MHD_DLL_RELEASE}) - if (CMAKE_CL_64) set(MHD_NAMES_DEBUG microhttpd_d_x64 microhttpd-10_d_x64 libmicrohttpd_d_x64 libmicrohttpd-dll_d_x64) else () @@ -53,11 +49,15 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") DOC "mhd debug library" ) - # not sure why this was commented - # always use release for now, need to ask Arkadiy - #string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG}) set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) + # prepare dlls + string(REPLACE ".lib" ".dll" MHD_DLL ${MHD_LIBRARY}) + string(REPLACE "/lib/" "/bin/" MHD_DLL ${MHD_DLL}) + string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG}) + string(REPLACE "/lib/" "/bin/" MHD_DLL_DEBUG ${MHD_DLL_DEBUG}) + set(MHD_DLLS optimized ${MHD_DLL} debug ${MHD_DLL_DEBUG}) + endif() include(FindPackageHandleStandardArgs) diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index fbc6a8b24..047f81c49 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -29,7 +29,9 @@ target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethash) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + eth_copy_dlls(${EXECUTABLE} ${MHD_DLLS}) + #add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + endif() install( TARGETS ${EXECUTABLE} DESTINATION bin ) From be039ba17035b335581081a457c1917e3560b5f3 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 13 Apr 2015 17:01:09 +0200 Subject: [PATCH 042/108] fixed cmake files --- cmake/EthExecutableHelper.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 8d7bb6770..a2d2de8b9 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -48,6 +48,7 @@ macro(eth_copy_dlls EXECUTABLE DLLS) -DLIBS="${DLLS}" -DCONFIGURATION="$" -DDESTINATION="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" + ) endmacro() # From 339fd2e1dd71e7473530ecdf62635d251c25b1c8 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 13 Apr 2015 17:07:45 +0200 Subject: [PATCH 043/108] missing cmake script --- cmake/scripts/copydlls.cmake | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cmake/scripts/copydlls.cmake diff --git a/cmake/scripts/copydlls.cmake b/cmake/scripts/copydlls.cmake new file mode 100644 index 000000000..49c2e1c03 --- /dev/null +++ b/cmake/scripts/copydlls.cmake @@ -0,0 +1,17 @@ +# this module expects +# DLLS +# CONFIGURATION +# DESTINATION + +# example usage: +# cmake -DLLS=${MHD_LIBRARIES} -DCONFIGURATION=Release -DDESTINATION=dest -P scripts/copydlls.cmake + +# expects DLLS to be in format optimized;path_to_dll.dll;debug;path_to_dll_d.dll +if (${CONFIGURATION} STREQUAL "Release") + list(GET DLLS 1 DLL) +else () # Debug + list(GET DLLS 3 DLL) +endif() + +execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${DLL}" "${DESTINATION}") + From 559e3753e1a3cbeb4ac2f4163e6d5327fbb182fd Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 13 Apr 2015 17:31:03 +0200 Subject: [PATCH 044/108] bugfixes --- mix/ClientModel.cpp | 5 +- mix/CodeModel.cpp | 5 +- mix/qml.qrc | 5 +- mix/qml/DeploymentDialog.qml | 6 +- mix/qml/MainContent.qml | 1 + mix/qml/ProjectList.qml | 1 + mix/qml/ProjectModel.qml | 9 +- mix/qml/StepActionImage.qml | 30 +-- mix/qml/js/NetworkDeployment.js | 351 ++++++++++++++++++++++++++++++++ mix/qml/js/ProjectModel.js | 345 +------------------------------ mix/test/qml/TestMain.qml | 4 +- mix/test/qml/js/TestProject.js | 20 ++ 12 files changed, 417 insertions(+), 365 deletions(-) create mode 100644 mix/qml/js/NetworkDeployment.js create mode 100644 mix/test/qml/js/TestProject.js diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 41aa55249..8f8df4f5d 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -216,7 +216,10 @@ void ClientModel::setupState(QVariantMap _state) void ClientModel::executeSequence(vector const& _sequence, map const& _balances) { if (m_running) - BOOST_THROW_EXCEPTION(ExecutionStateException()); + { + qWarning() << "Waiting for current execution to complete"; + m_runFuture.waitForFinished(); + } m_running = true; emit runStarted(); diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index a5a0255d2..e99763be3 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -269,7 +269,10 @@ void CodeModel::runCompilationJob(int _jobId) if (c_predefinedContracts.count(n) != 0) continue; QString name = QString::fromStdString(n); - QString sourceName = QString::fromStdString(*cs.getContractDefinition(n).getLocation().sourceName); + ContractDefinition const& contractDefinition = cs.getContractDefinition(n); + if (!contractDefinition.isFullyImplemented()) + continue; + QString sourceName = QString::fromStdString(*contractDefinition.getLocation().sourceName); auto sourceIter = m_pendingContracts.find(sourceName); QString source = sourceIter != m_pendingContracts.end() ? sourceIter->second : QString(); CompiledContract* contract = new CompiledContract(cs, name, source); diff --git a/mix/qml.qrc b/mix/qml.qrc index 01074edb3..6cbc97a78 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -48,8 +48,8 @@ qml/StatusPaneStyle.qml qml/StepActionImage.qml qml/StorageView.qml - qml/StatesComboBox.qml - qml/StructView.qml + qml/StatesComboBox.qml + qml/StructView.qml qml/Style.qml qml/TabStyle.qml qml/TransactionDialog.qml @@ -63,5 +63,6 @@ qml/js/TransactionHelper.js qml/js/Printer.js qml/js/ansi2html.js + qml/js/NetworkDeployment.js diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 1e230f088..9235bfaab 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -6,7 +6,7 @@ import QtQuick.Dialogs 1.2 import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper -import "js/ProjectModel.js" as ProjectModelCode +import "js/NetworkDeployment.js" as NetworkDeploymentCode import "js/QEtherHelper.js" as QEtherHelper import "." @@ -356,7 +356,7 @@ Dialog { tooltip: qsTr("Deploy contract(s) and Package resources files.") onTriggered: { var inError = []; - var ethUrl = ProjectModelCode.formatAppUrl(applicationUrlEth.text); + var ethUrl = NetworkDeploymentCode.formatAppUrl(applicationUrlEth.text); for (var k in ethUrl) { if (ethUrl[k].length > 32) @@ -367,7 +367,7 @@ Dialog { if (contractRedeploy.checked) deployWarningDialog.open(); else - ProjectModelCode.startDeployProject(false); + NetworkDeploymentCode.startDeployProject(false); } } } diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index ca08485c3..67f45f973 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -24,6 +24,7 @@ Rectangle { property alias webViewVisible: webPreview.visible property alias webView: webPreview property alias projectViewVisible: projectList.visible + property alias projectNavigator: projectList property alias runOnProjectLoad: mainSettings.runOnProjectLoad property alias rightPane: rightView property alias codeEditor: codeEditor diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index a98c2587b..f3f844d71 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -8,6 +8,7 @@ import "." Item { property bool renameMode: false; + property alias sections: sectionRepeater ProjectFilesStyle { id: projectFilesStyle diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 509ef3719..b15c996fb 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -5,6 +5,7 @@ import QtQuick.Controls 1.0 import QtQuick.Dialogs 1.1 import Qt.labs.settings 1.0 import "js/ProjectModel.js" as ProjectModelCode +import "js/NetworkDeployment.js" as NetworkDeploymentCode Item { id: projectModel @@ -69,9 +70,9 @@ Item { function getDocumentIdByName(documentName) { return ProjectModelCode.getDocumentIdByName(documentName); } function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); } function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } - function deployProject() { ProjectModelCode.deployProject(false); } - function registerToUrlHint() { ProjectModelCode.registerToUrlHint(); } - function formatAppUrl() { ProjectModelCode.formatAppUrl(url); } + function deployProject() { NetworkDeploymentCode.deployProject(false); } + function registerToUrlHint() { NetworkDeploymentCode.registerToUrlHint(); } + function formatAppUrl() { NetworkDeploymentCode.formatAppUrl(url); } Connections { target: mainApplication @@ -155,7 +156,7 @@ Item { icon: StandardIcon.Question standardButtons: StandardButton.Ok | StandardButton.Abort onAccepted: { - ProjectModelCode.startDeployProject(true); + NetworkDeploymentCode.startDeployProject(true); } } diff --git a/mix/qml/StepActionImage.qml b/mix/qml/StepActionImage.qml index a8c800b64..e2a1ab8e9 100644 --- a/mix/qml/StepActionImage.qml +++ b/mix/qml/StepActionImage.qml @@ -3,8 +3,6 @@ import QtQuick.Controls 1.1 import QtQuick.Layouts 1.0 import QtQuick.Controls.Styles 1.1 - - Rectangle { id: buttonActionContainer property string disableStateImg @@ -15,7 +13,6 @@ Rectangle { property bool buttonRight signal clicked - color: "transparent" width: 35 height: 24 @@ -43,8 +40,8 @@ Rectangle { right: parent.right top: parent.top bottom: parent.bottom - bottomMargin:debugImg.pressed? 0 : 1; - topMargin:debugImg.pressed? 1 : 0; + bottomMargin: debugImg.pressed ? 0 : 1; + topMargin: debugImg.pressed ? 1 : 0; } color: "#FCFBFC" radius: 3 @@ -65,15 +62,14 @@ Rectangle { right: parent.right top: parent.top bottom: parent.bottom - bottomMargin:debugImg.pressed? 0 : 1; - topMargin:debugImg.pressed? 1 : 0; + bottomMargin: debugImg.pressed ? 0 : 1; + topMargin: debugImg.pressed? 1 : 0; } color: "#FCFBFC" radius: 3 } } - Rectangle { id: contentRectangle width: 25 @@ -87,8 +83,8 @@ Rectangle { right: parent.right top: parent.top bottom: parent.bottom - bottomMargin:debugImg.pressed? 0 : 1; - topMargin:debugImg.pressed? 1 : 0; + bottomMargin: debugImg.pressed ? 0 : 1; + topMargin: debugImg.pressed ? 1 : 0; } color: "#FCFBFC" @@ -96,7 +92,7 @@ Rectangle { id: debugImage source: enabledStateImg anchors.centerIn: parent - anchors.topMargin: debugImg.pressed? 1 : 0; + anchors.topMargin: debugImg.pressed ? 1 : 0; fillMode: Image.PreserveAspectFit width: 15 @@ -105,28 +101,24 @@ Rectangle { } - Button { anchors.fill: parent id: debugImg action: buttonAction - style: Rectangle { - color: "transparent" + style: ButtonStyle { + background: Rectangle { + color: "transparent" + } } } - Action { tooltip: buttonTooltip id: buttonAction shortcut: buttonShortcut onTriggered: { - // contentRectangle.anchors.bottomMargin = 0 - // contentRectangle.anchors.topMargin = 1 buttonActionContainer.clicked(); } } } - - } diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js new file mode 100644 index 000000000..627277f20 --- /dev/null +++ b/mix/qml/js/NetworkDeployment.js @@ -0,0 +1,351 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file NetworkDeployment.js + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @author Yann yann@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ +Qt.include("TransactionHelper.js") + + +var jsonRpcRequestId = 1; +function deployProject(force) { + saveAll(); //TODO: ask user + deploymentDialog.open(); +} + +function startDeployProject(erasePrevious) +{ + var date = new Date(); + var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); + if (!erasePrevious) + { + finalizeDeployment(deploymentId, projectModel.deploymentAddresses); + return; + } + + var jsonRpcUrl = "http://127.0.0.1:8080"; + console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); + deploymentStarted(); + + var ctrNames = Object.keys(codeModel.contracts); + var ctrAddresses = {}; + deployContracts(0, ctrAddresses, ctrNames, function (){ + finalizeDeployment(deploymentId, ctrAddresses); + }); +} + +function deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack) +{ + var code = codeModel.contracts[ctrNames[ctrIndex]].codeHex; + var requests = [{ + jsonrpc: "2.0", + method: "eth_sendTransaction", + params: [ { "from": deploymentDialog.currentAccount, "gas": deploymentDialog.gasToUse, "code": code } ], + id: 0 + }]; + rpcCall(requests, function (httpCall, response){ + var txt = qsTr("Please wait while " + ctrNames[ctrIndex] + " is published ...") + deploymentStepChanged(txt); + console.log(txt); + ctrAddresses[ctrNames[ctrIndex]] = JSON.parse(response)[0].result + deploymentDialog.waitForTrCountToIncrement(function(status) { + if (status === -1) + { + trCountIncrementTimeOut(); + return; + } + ctrIndex++; + if (ctrIndex < ctrNames.length) + deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack); + else + callBack(); + }); + }); +} + +function finalizeDeployment(deploymentId, addresses) { + deploymentStepChanged(qsTr("Packaging application ...")); + var deploymentDir = projectPath + deploymentId + "/"; + projectModel.deploymentDir = deploymentDir; + fileIo.makeDir(deploymentDir); + for (var i = 0; i < projectListModel.count; i++) { + var doc = projectListModel.get(i); + if (doc.isContract) + continue; + if (doc.isHtml) { + //inject the script to access contract API + //TODO: use a template + var html = fileIo.readFile(doc.path); + var insertAt = html.indexOf("") + if (insertAt < 0) + insertAt = 0; + else + insertAt += 6; + html = html.substr(0, insertAt) + + "" + + html.substr(insertAt); + fileIo.writeFile(deploymentDir + doc.fileName, html); + } + else + fileIo.copyFile(doc.path, deploymentDir + doc.fileName); + } + //write deployment js + var deploymentJs = + "// Autogenerated by Mix\n" + + "contracts = {};\n"; + for (var c in codeModel.contracts) { + var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]"; + deploymentJs += contractAccessor + " = {\n" + + "\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" + + "\taddress: \"" + addresses[c] + "\"\n" + + "};\n" + + contractAccessor + ".contractClass = web3.eth.contract(" + contractAccessor + ".interface);\n" + + contractAccessor + ".contract = new " + contractAccessor + ".contractClass(" + contractAccessor + ".address);\n"; + } + fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); + deploymentAddresses = addresses; + saveProject(); + + var packageRet = fileIo.makePackage(deploymentDir); + deploymentDialog.packageHash = packageRet[0]; + deploymentDialog.packageBase64 = packageRet[1]; + deploymentDialog.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0]; + + var applicationUrlEth = deploymentDialog.applicationUrlEth; + + applicationUrlEth = formatAppUrl(applicationUrlEth); + deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); + checkEthPath(applicationUrlEth, function () { + deploymentComplete(); + deployResourcesDialog.text = qsTr("Register Web Application to finalize deployment."); + deployResourcesDialog.open(); + }); +} + +function checkEthPath(dappUrl, callBack) +{ + if (dappUrl.length === 1) + registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar. + else + { + // the first owned reigstrar must have been created to follow the path. + var str = createString(dappUrl[0]); + var requests = []; + requests.push({ + //register() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "gas": 150000, "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + rpcCall(requests, function (httpRequest, response) { + var res = JSON.parse(response); + var addr = normalizeAddress(res[0].result); + if (addr.replace(/0+/g, "") === "") + { + var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + ". Please register using Registration Dapp. Aborting."); + deploymentError(errorTxt); + console.log(errorTxt); + } + else + { + dappUrl.splice(0, 1); + checkRegistration(dappUrl, addr, callBack); + } + }); + } +} + +function checkRegistration(dappUrl, addr, callBack) +{ + if (dappUrl.length === 1) + registerContentHash(addr, callBack); // We do not create the register for the last part, just registering the content hash. + else + { + var txt = qsTr("Checking " + JSON.stringify(dappUrl) + " ... in registrar " + addr); + deploymentStepChanged(txt); + console.log(txt); + var requests = []; + var registrar = {} + var str = createString(dappUrl[0]); + requests.push({ + //getOwner() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "gas" : 2000, "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ], + id: jsonRpcRequestId++ + }); + + requests.push({ + //register() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x6be16bed" + str.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function (httpRequest, response) { + var res = JSON.parse(response); + var nextAddr = normalizeAddress(res[1].result); + var errorTxt; + if (res[1].result === "0x") + { + errorTxt = qsTr("Error when creating new owned regsitrar. Please use the regsitration Dapp. Aborting"); + deploymentError(errorTxt); + console.log(errorTxt); + } + else if (normalizeAddress(deploymentDialog.currentAccount) !== normalizeAddress(res[0].result)) + { + errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting"); + deploymentError(errorTxt); + console.log(errorTxt); + } + else if (nextAddr.replace(/0+/g, "") !== "") + { + dappUrl.splice(0, 1); + checkRegistration(dappUrl, nextAddr, callBack); + } + else + { + var txt = qsTr("Registering sub domain " + dappUrl[0] + " ..."); + console.log(txt); + deploymentStepChanged(txt); + //current registrar is owned => ownedregistrar creation and continue. + requests = []; + + requests.push({ + jsonrpc: "2.0", + method: "eth_sendTransaction", + params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function(httpRequest, response) { + var newCtrAddress = normalizeAddress(JSON.parse(response)[0].result); + requests = []; + var txt = qsTr("Please wait " + dappUrl[0] + " is registering ..."); + deploymentStepChanged(txt); + console.log(txt); + deploymentDialog.waitForTrCountToIncrement(function(status) { + if (status === -1) + { + trCountIncrementTimeOut(); + return; + } + var crLevel = createString(dappUrl[0]).encodeValueAsString(); + requests.push({ + //setRegister() + jsonrpc: "2.0", + method: "eth_sendTransaction", + params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function(request, response){ + dappUrl.splice(0, 1); + checkRegistration(dappUrl, newCtrAddress, callBack); + }); + }); + }); + } + }); + } +} + +function trCountIncrementTimeOut() +{ + var error = qsTr("Something went wrong during the deployment. Please verify the amount of gas for this transaction and check your balance.") + console.log(error); + deploymentError(error); +} + +function registerContentHash(registrar, callBack) +{ + var txt = qsTr("Finalizing Dapp registration ..."); + deploymentStepChanged(txt); + console.log(txt); + var requests = []; + var paramTitle = clientModel.encodeAbiString(projectModel.projectTitle); + requests.push({ + //setContent() + jsonrpc: "2.0", + method: "eth_sendTransaction", + params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle + deploymentDialog.packageHash } ], + id: jsonRpcRequestId++ + }); + rpcCall(requests, function (httpRequest, response) { + callBack(); + }); +} + +function registerToUrlHint() +{ + deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ..."); + var requests = []; + var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); + requests.push({ + //urlHint => suggestUrl + jsonrpc: "2.0", + method: "eth_sendTransaction", + params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 30000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function (httpRequest, response) { + deploymentComplete(); + }); +} + +function normalizeAddress(addr) +{ + addr = addr.replace('0x', ''); + if (addr.length <= 40) + return addr; + var left = addr.length - 40; + return addr.substring(left); +} + +function formatAppUrl(url) +{ + if (url.toLowerCase().indexOf("eth://") === 0) + url = url.substring(6); + if (url.toLowerCase().indexOf(projectModel.projectTitle + ".") === 0) + url = url.substring(projectModel.projectTitle.length + 1); + if (url === "") + return [projectModel.projectTitle]; + + var ret; + if (url.indexOf("/") === -1) + ret = url.split('.').reverse(); + else + { + var slash = url.indexOf("/"); + var left = url.substring(0, slash); + var leftA = left.split("."); + leftA.reverse(); + + var right = url.substring(slash + 1); + var rightA = right.split('/'); + ret = leftA.concat(rightA); + } + if (ret[0].toLowerCase() === "eth") + ret.splice(0, 1); + ret.push(projectModel.projectTitle); + return ret; +} diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 993eacf3a..6ec906996 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -19,8 +19,6 @@ * @date 2015 * Ethereum IDE client. */ -Qt.include("QEtherHelper.js") -Qt.include("TransactionHelper.js") var htmlTemplate = "\n\n\n\n\n\n\n"; var contractTemplate = "contract Contract {\n}\n"; @@ -83,7 +81,10 @@ function saveProjectFile() deploymentDir: projectModel.deploymentDir }; for (var i = 0; i < projectListModel.count; i++) - projectData.files.push(projectListModel.get(i).fileName); + projectData.files.push({ + title: projectListModel.get(i).name, + fileName: projectListModel.get(i).fileName, + }); projectFileSaving(projectData); var json = JSON.stringify(projectData, null, "\t"); @@ -122,7 +123,11 @@ function loadProject(path) { projectData.files = []; for(var i = 0; i < projectData.files.length; i++) { - addFile(projectData.files[i]); + var entry = projectData.files[i]; + if (typeof(entry) === "string") + addFile(entry); //TODO: remove old project file support + else + addFile(entry.fileName, entry.title); } if (mainApplication.trackLastProject) projectSettings.lastProjectPath = path; @@ -140,7 +145,7 @@ function loadProject(path) { }); } -function addFile(fileName) { +function addFile(fileName, title) { var p = projectPath + fileName; var extension = fileName.substring(fileName.lastIndexOf("."), fileName.length); var isContract = extension === ".sol"; @@ -154,7 +159,7 @@ function addFile(fileName) { contract: false, path: p, fileName: fileName, - name: fileName, + name: title !== undefined ? title : fileName, documentId: fileName, syntaxMode: syntaxMode, isText: isContract || isHtml || isCss || isJs, @@ -344,331 +349,3 @@ function generateFileName(name, extension) { } while (fileIo.fileExists(filePath)); return fileName } - - -var jsonRpcRequestId = 1; -function deployProject(force) { - saveAll(); //TODO: ask user - deploymentDialog.open(); -} - -function startDeployProject(erasePrevious) -{ - var date = new Date(); - var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); - if (!erasePrevious) - { - finalizeDeployment(deploymentId, projectModel.deploymentAddresses); - return; - } - - var jsonRpcUrl = "http://127.0.0.1:8080"; - console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); - deploymentStarted(); - - var ctrNames = Object.keys(codeModel.contracts); - var ctrAddresses = {}; - deployContracts(0, ctrAddresses, ctrNames, function (){ - finalizeDeployment(deploymentId, ctrAddresses); - }); -} - -function deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack) -{ - var code = codeModel.contracts[ctrNames[ctrIndex]].codeHex; - var requests = [{ - jsonrpc: "2.0", - method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": deploymentDialog.gasToUse, "code": code } ], - id: 0 - }]; - rpcCall(requests, function (httpCall, response){ - var txt = qsTr("Please wait while " + ctrNames[ctrIndex] + " is published ...") - deploymentStepChanged(txt); - console.log(txt); - ctrAddresses[ctrNames[ctrIndex]] = JSON.parse(response)[0].result - deploymentDialog.waitForTrCountToIncrement(function(status) { - if (status === -1) - { - trCountIncrementTimeOut(); - return; - } - ctrIndex++; - if (ctrIndex < ctrNames.length) - deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack); - else - callBack(); - }); - }); -} - -function finalizeDeployment(deploymentId, addresses) { - deploymentStepChanged(qsTr("Packaging application ...")); - var deploymentDir = projectPath + deploymentId + "/"; - projectModel.deploymentDir = deploymentDir; - fileIo.makeDir(deploymentDir); - for (var i = 0; i < projectListModel.count; i++) { - var doc = projectListModel.get(i); - if (doc.isContract) - continue; - if (doc.isHtml) { - //inject the script to access contract API - //TODO: use a template - var html = fileIo.readFile(doc.path); - var insertAt = html.indexOf("") - if (insertAt < 0) - insertAt = 0; - else - insertAt += 6; - html = html.substr(0, insertAt) + - "" + - html.substr(insertAt); - fileIo.writeFile(deploymentDir + doc.fileName, html); - } - else - fileIo.copyFile(doc.path, deploymentDir + doc.fileName); - } - //write deployment js - var deploymentJs = - "// Autogenerated by Mix\n" + - "contracts = {};\n"; - for (var c in codeModel.contracts) { - var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]"; - deploymentJs += contractAccessor + " = {\n" + - "\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" + - "\taddress: \"" + addresses[c] + "\"\n" + - "};\n" + - contractAccessor + ".contractClass = web3.eth.contract(" + contractAccessor + ".interface);\n" + - contractAccessor + ".contract = new " + contractAccessor + ".contractClass(" + contractAccessor + ".address);\n"; - } - fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); - deploymentAddresses = addresses; - saveProject(); - - var packageRet = fileIo.makePackage(deploymentDir); - deploymentDialog.packageHash = packageRet[0]; - deploymentDialog.packageBase64 = packageRet[1]; - deploymentDialog.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0]; - - var applicationUrlEth = deploymentDialog.applicationUrlEth; - - applicationUrlEth = formatAppUrl(applicationUrlEth); - deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); - checkEthPath(applicationUrlEth, function () { - deploymentComplete(); - deployResourcesDialog.text = qsTr("Register Web Application to finalize deployment."); - deployResourcesDialog.open(); - }); -} - -function checkEthPath(dappUrl, callBack) -{ - if (dappUrl.length === 1) - registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar. - else - { - // the first owned reigstrar must have been created to follow the path. - var str = createString(dappUrl[0]); - var requests = []; - requests.push({ - //register() - jsonrpc: "2.0", - method: "eth_call", - params: [ { "gas": 150000, "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); - rpcCall(requests, function (httpRequest, response) { - var res = JSON.parse(response); - var addr = normalizeAddress(res[0].result); - if (addr.replace(/0+/g, "") === "") - { - var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + ". Please register using Registration Dapp. Aborting."); - deploymentError(errorTxt); - console.log(errorTxt); - } - else - { - dappUrl.splice(0, 1); - checkRegistration(dappUrl, addr, callBack); - } - }); - } -} - -function checkRegistration(dappUrl, addr, callBack) -{ - if (dappUrl.length === 1) - registerContentHash(addr, callBack); // We do not create the register for the last part, just registering the content hash. - else - { - var txt = qsTr("Checking " + JSON.stringify(dappUrl) + " ... in registrar " + addr); - deploymentStepChanged(txt); - console.log(txt); - var requests = []; - var registrar = {} - var str = createString(dappUrl[0]); - requests.push({ - //getOwner() - jsonrpc: "2.0", - method: "eth_call", - params: [ { "gas" : 2000, "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ], - id: jsonRpcRequestId++ - }); - - requests.push({ - //register() - jsonrpc: "2.0", - method: "eth_call", - params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x6be16bed" + str.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function (httpRequest, response) { - var res = JSON.parse(response); - var nextAddr = normalizeAddress(res[1].result); - var errorTxt; - if (res[1].result === "0x") - { - errorTxt = qsTr("Error when creating new owned regsitrar. Please use the regsitration Dapp. Aborting"); - deploymentError(errorTxt); - console.log(errorTxt); - } - else if (normalizeAddress(deploymentDialog.currentAccount) !== normalizeAddress(res[0].result)) - { - errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting"); - deploymentError(errorTxt); - console.log(errorTxt); - } - else if (nextAddr.replace(/0+/g, "") !== "") - { - dappUrl.splice(0, 1); - checkRegistration(dappUrl, nextAddr, callBack); - } - else - { - var txt = qsTr("Registering sub domain " + dappUrl[0] + " ..."); - console.log(txt); - deploymentStepChanged(txt); - //current registrar is owned => ownedregistrar creation and continue. - requests = []; - - requests.push({ - jsonrpc: "2.0", - method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function(httpRequest, response) { - var newCtrAddress = normalizeAddress(JSON.parse(response)[0].result); - requests = []; - var txt = qsTr("Please wait " + dappUrl[0] + " is registering ..."); - deploymentStepChanged(txt); - console.log(txt); - deploymentDialog.waitForTrCountToIncrement(function(status) { - if (status === -1) - { - trCountIncrementTimeOut(); - return; - } - var crLevel = createString(dappUrl[0]).encodeValueAsString(); - requests.push({ - //setRegister() - jsonrpc: "2.0", - method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function(request, response){ - dappUrl.splice(0, 1); - checkRegistration(dappUrl, newCtrAddress, callBack); - }); - }); - }); - } - }); - } -} - -function trCountIncrementTimeOut() -{ - var error = qsTr("Something went wrong during the deployment. Please verify the amount of gas for this transaction and check your balance.") - console.log(error); - deploymentError(error); -} - -function registerContentHash(registrar, callBack) -{ - var txt = qsTr("Finalizing Dapp registration ..."); - deploymentStepChanged(txt); - console.log(txt); - var requests = []; - var paramTitle = clientModel.encodeAbiString(projectModel.projectTitle); - requests.push({ - //setContent() - jsonrpc: "2.0", - method: "eth_sendTransaction", - params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle + deploymentDialog.packageHash } ], - id: jsonRpcRequestId++ - }); - rpcCall(requests, function (httpRequest, response) { - callBack(); - }); -} - -function registerToUrlHint() -{ - deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ..."); - var requests = []; - var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); - requests.push({ - //urlHint => suggestUrl - jsonrpc: "2.0", - method: "eth_sendTransaction", - params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 30000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function (httpRequest, response) { - deploymentComplete(); - }); -} - -function normalizeAddress(addr) -{ - addr = addr.replace('0x', ''); - if (addr.length <= 40) - return addr; - var left = addr.length - 40; - return addr.substring(left); -} - -function formatAppUrl(url) -{ - if (url.toLowerCase().indexOf("eth://") === 0) - url = url.substring(6); - if (url.toLowerCase().indexOf(projectModel.projectTitle + ".") === 0) - url = url.substring(projectModel.projectTitle.length + 1); - if (url === "") - return [projectModel.projectTitle]; - - var ret; - if (url.indexOf("/") === -1) - ret = url.split('.').reverse(); - else - { - var slash = url.indexOf("/"); - var left = url.substring(0, slash); - var leftA = left.split("."); - leftA.reverse(); - - var right = url.substring(slash + 1); - var rightA = right.split('/'); - ret = leftA.concat(rightA); - } - if (ret[0].toLowerCase() === "eth") - ret.splice(0, 1); - ret.push(projectModel.projectTitle); - return ret; -} diff --git a/mix/test/qml/TestMain.qml b/mix/test/qml/TestMain.qml index bf449d2dd..70b96be00 100644 --- a/mix/test/qml/TestMain.qml +++ b/mix/test/qml/TestMain.qml @@ -4,6 +4,7 @@ import org.ethereum.qml.TestService 1.0 import "../../qml" import "js/TestDebugger.js" as TestDebugger import "js/TestTutorial.js" as TestTutorial +import "js/TestProject.js" as TestProject TestCase { @@ -49,9 +50,9 @@ TestCase function editContract(c) { mainApplication.mainContent.codeEditor.getEditor("contract.sol").setText(c); - ts.keyPressChar(mainApplication, "S", Qt.ControlModifier, 200); //Ctrl+S if (!ts.waitForSignal(mainApplication.codeModel, "compilationComplete()", 5000)) fail("not compiled"); + ts.keyPressChar(mainApplication, "S", Qt.ControlModifier, 200); //Ctrl+S } function editHtml(c) @@ -74,5 +75,6 @@ TestCase function test_dbg_transactionWithParameter() { TestDebugger.test_transactionWithParameter(); } function test_dbg_constructorParameters() { TestDebugger.test_constructorParameters(); } function test_dbg_arrayParametersAndStorage() { TestDebugger.test_arrayParametersAndStorage(); } + function test_project_contractRename() { TestProject.test_contractRename(); } } diff --git a/mix/test/qml/js/TestProject.js b/mix/test/qml/js/TestProject.js new file mode 100644 index 000000000..c0b698d1e --- /dev/null +++ b/mix/test/qml/js/TestProject.js @@ -0,0 +1,20 @@ +function test_contractRename() +{ + newProject(); + //if (!ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000)) + // fail("Error running transaction"); + tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Contract"); + editContract("contract Renamed {}"); + if (!ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000)) + fail("Error running transaction"); + wait(1000); + tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Renamed"); + mainApplication.projectModel.stateListModel.editState(0); + mainApplication.projectModel.stateDialog.model.editTransaction(2); + var transactionDialog = mainApplication.projectModel.stateDialog.transactionDialog; + tryCompare(transactionDialog, "contractId", "Renamed"); + tryCompare(transactionDialog, "functionId", "Renamed"); + transactionDialog.close(); + mainApplication.projectModel.stateDialog.close(); + tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(2), "contract", "Renamed"); +} From d04f74aa625630d1f863740c65a910ddd845e1ec Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 13 Apr 2015 17:33:04 +0200 Subject: [PATCH 045/108] style --- mix/test/qml/js/TestProject.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/mix/test/qml/js/TestProject.js b/mix/test/qml/js/TestProject.js index c0b698d1e..d81b72942 100644 --- a/mix/test/qml/js/TestProject.js +++ b/mix/test/qml/js/TestProject.js @@ -1,8 +1,6 @@ function test_contractRename() { newProject(); - //if (!ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000)) - // fail("Error running transaction"); tryCompare(mainApplication.mainContent.projectNavigator.sections.itemAt(0).model.get(0), "name", "Contract"); editContract("contract Renamed {}"); if (!ts.waitForSignal(mainApplication.clientModel, "runComplete()", 5000)) From 2693659e5656f388934c7e144714cf521f1f76ad Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 18:12:05 +0200 Subject: [PATCH 046/108] Various fixes for mining. --- alethzero/DownloadView.h | 1 - alethzero/MainWin.cpp | 10 ++-- alethzero/MiningView.cpp | 11 ++-- alethzero/MiningView.h | 4 +- eth/main.cpp | 17 +++--- exp/main.cpp | 54 +++++++++++++++---- libdevcore/Worker.h | 3 ++ libethcore/Ethash.cpp | 52 +++++++++--------- libethcore/Ethash.h | 22 +++++--- libethcore/Miner.h | 35 ++++++------ libethereum/Farm.h | 45 ++++++++++++---- mix/MixClient.cpp | 23 +++++--- mix/MixClient.h | 4 +- neth/main.cpp | 10 +--- test/TestHelper.cpp | 31 +++++++++++ test/TestHelper.h | 5 +- test/blockchain.cpp | 111 ++++++++++++++------------------------- test/dagger.cpp | 12 ++--- test/stateOriginal.cpp | 11 ++-- third/MainWin.cpp | 2 +- 20 files changed, 269 insertions(+), 194 deletions(-) diff --git a/alethzero/DownloadView.h b/alethzero/DownloadView.h index 22a11651c..d0fc445f8 100644 --- a/alethzero/DownloadView.h +++ b/alethzero/DownloadView.h @@ -32,7 +32,6 @@ #endif namespace dev { namespace eth { -struct MineInfo; class DownloadMan; }} diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 03d216a17..2e4478594 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -45,7 +45,7 @@ #endif #include #include -#include +#include #include #include #include @@ -164,7 +164,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(ProofOfWork::name()).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); @@ -952,7 +952,7 @@ void Main::on_preview_triggered() void Main::refreshMining() { - MineProgress p = ethereum()->miningProgress(); + MiningProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining"); if (!ui->miningView->isVisible()) return; @@ -1481,7 +1481,7 @@ void Main::on_blocks_currentItemChanged() s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { - auto e = Ethasher::eval(info); + auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash << "" << "
"; } @@ -1510,7 +1510,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Nonce: " << uncle.nonce << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = Ethasher::eval(uncle); + auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash) diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index 63d1fcf99..e020408ea 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MineProgress; +using dev::eth::MiningProgress; // functions using dev::toString; @@ -50,12 +50,13 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MineProgress const& _p) +void MiningView::appendStats(list const& _i, MiningProgress const& _p) { + (void)_p; if (_i.empty()) return; - unsigned o = m_values.size(); +/* unsigned o = m_values.size(); for (MineInfo const& i: _i) { m_values.push_back(i.best); @@ -91,7 +92,7 @@ void MiningView::appendStats(list const& _i, MineProgress const& _p) m_completes.erase(remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}), m_completes.end()); m_progress = _p; - update(); + update();*/ } void MiningView::resetStats() @@ -101,6 +102,7 @@ void MiningView::resetStats() void MiningView::paintEvent(QPaintEvent*) { + /* Grapher g; QPainter p(this); @@ -115,4 +117,5 @@ void MiningView::paintEvent(QPaintEvent*) g.ruleY(r - 1, QColor(128, 128, 128)); for (auto r: m_completes) g.ruleY(r, QColor(192, 64, 64)); + */ } diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 8f3135f75..65b9f2ec9 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MineProgress const& _p); + void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MineProgress m_progress; + dev::eth::MiningProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/eth/main.cpp b/eth/main.cpp index 05826dc0f..0ac53fab5 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -126,20 +126,22 @@ void help() #if ETH_JSONRPC << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl +#endif +#if ETH_EVMJIT + << " -J,--jit Enable EVM JIT (default: off)." << endl #endif << " -K,--kill First kill the blockchain." << endl << " --listen-ip Listen on the given port for incoming connections (default: 30303)." << endl << " -l,--listen Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl << " -u,--public-ip Force public ip to given (default: auto)." << endl << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl - << " -n,--upnp Use upnp for NAT (default: on)." << endl + << " -n,-u,--upnp Use upnp for NAT (default: on)." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl << " -p,--port Connect to remote port (default: 30303)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl << " -R,--rebuild First rebuild the blockchain from the existing database." << endl << " -r,--remote Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl - << " -t,--miners Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl << " -V,--version Show the version and exit." << endl @@ -337,7 +339,7 @@ int main(int argc, char** argv) exportFrom = argv[++i]; else if (arg == "--only" && i + 1 < argc) exportTo = exportFrom = argv[++i]; - else if ((arg == "-n" || arg == "--upnp") && i + 1 < argc) + else if ((arg == "-n" || arg == "-u" || arg == "--upnp") && i + 1 < argc) { string m = argv[++i]; if (isTrue(m)) @@ -489,15 +491,12 @@ int main(int argc, char** argv) return -1; } } - else if (arg == "--jit") - { #if ETH_EVMJIT + else if (arg == "-J" || arg == "--jit") + { jit = true; -#else - cerr << "EVM JIT not enabled" << endl; - return -1; -#endif } +#endif else if (arg == "-h" || arg == "--help") help(); else if (arg == "-V" || arg == "--version") diff --git a/exp/main.cpp b/exp/main.cpp index 88f1075a9..933fda1a6 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,9 +34,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -109,18 +109,50 @@ int main() #else int main() { -#if ETH_ETHASHCL - EthashCL ecl; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; - cdebug << (h256)u256((bigint(1) << 256) / genesis.difficulty); - std::pair r; - while (!r.first.completed) - r = ecl.mine(genesis, 1000); - cdebug << r.second.mixHash << r.second.nonce; - EthashCL::assignResult(r.second, genesis); - assert(EthashCPU::verify(genesis)); -#endif + cdebug << genesis.boundary(); + + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + BlockInfo bi = g; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + ProofOfWork::assignResult(sol, bi); + return completed = true; + }); + f.setWork(bi); + for (unsigned i = 0; !completed && i < timeout * 10; ++i, cout << f.miningProgress() << "\r" << flush) + this_thread::sleep_for(chrono::milliseconds(100)); + cdebug << bi.mixHash << bi.nonce << (Ethash::verify(bi) ? "GOOD" : "bad"); + }; + + f.startCPU(); + mine(f, genesis, 10); + mine(f, genesis, 10); + f.startGPU(); + + cdebug << "Good:"; + genesis.difficulty = 1 << 18; + genesis.noteDirty(); + mine(f, genesis, 3); + + cdebug << "Bad:"; + genesis.difficulty = (u256(1) << 40); + genesis.noteDirty(); + mine(f, genesis, 3); + + cdebug << "Good:"; + genesis.difficulty = 1 << 18; + genesis.noteDirty(); + mine(f, genesis, 3); + + cdebug << "Bad:"; + genesis.difficulty = (u256(1) << 40); + genesis.noteDirty(); + mine(f, genesis, 3); + return 0; } #endif diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 6a35d6c4c..24ff4cc15 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -66,6 +66,9 @@ protected: /// Called when is to be stopped, just prior to thread being joined. virtual void doneWorking() {} + /// Blocks caller into worker thread has finished. + void join() const { Guard l(x_work); try { if (m_work) m_work->join(); } catch (...) {} } + private: std::string m_name; unsigned m_idleWaitMs = 0; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 03c7a3654..f66188976 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -63,7 +63,7 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithNonce); + ret.headerHash = _bi.headerHash(WithoutNonce); ret.seedHash = _bi.seedHash(); return ret; } @@ -95,9 +95,8 @@ bool Ethash::verify(BlockInfo const& _header) return false; #endif - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); auto result = EthashAux::eval(_header); - bool slow = result.value <= boundary && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; #if ETH_DEBUG || !ETH_TRUE if (!pre && slow) @@ -107,7 +106,7 @@ bool Ethash::verify(BlockInfo const& _header) cwarn << "nonce:" << _header.nonce; cwarn << "mixHash:" << _header.mixHash; cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << boundary; + cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } @@ -125,16 +124,18 @@ void Ethash::CPUMiner::workLoop() ethash_return_value ethashReturn; auto p = EthashAux::params(m_work.seedHash); - void const* dagPointer = EthashAux::full(m_work.headerHash).data(); + void const* dagPointer = EthashAux::full(m_work.seedHash).data(); uint8_t const* headerHashPointer = m_work.headerHash.data(); h256 boundary = m_work.boundary; - unsigned hashCount = 0; + unsigned hashCount = 1; for (; !shouldStop(); tryNonce++, hashCount++) { ethash_compute_full(ðashReturn, dagPointer, &p, headerHashPointer, tryNonce); h256 value = h256(ethashReturn.result, h256::ConstructFromPointer); if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) break; + if (!(hashCount % 1000)) + accumulateHashes(1000); } } @@ -148,6 +149,7 @@ public: void abort() { Guard l(x_all); + m_owner->m_work.headerHash = h256(); if (m_aborted) return; // cdebug << "Attempting to abort"; @@ -159,8 +161,6 @@ public: m_aborted = m_abort = false; } - uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; } - protected: virtual bool found(uint64_t const* _nonces, uint32_t _count) override { @@ -180,7 +180,7 @@ protected: { Guard l(x_all); // cdebug << "Searched" << _count << "from" << _startNonce; - m_total += _count; + m_owner->accumulateHashes(_count); m_last = _startNonce + _count; if (m_abort) { @@ -192,7 +192,6 @@ protected: private: Mutex x_all; - uint64_t m_total; uint64_t m_last; bool m_abort = false; bool m_aborted = true; @@ -214,38 +213,43 @@ Ethash::GPUMiner::~GPUMiner() bool Ethash::GPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = EthashAux::eval(m_lastWork.seedHash, m_lastWork.headerHash, n); - if (r.value < m_lastWork.boundary) + Result r = EthashAux::eval(m_work.seedHash, m_work.headerHash, n); + if (r.value < m_work.boundary) return submitProof(Solution{n, r.mixHash}); return false; } void Ethash::GPUMiner::kickOff(WorkPackage const& _work) { - if (!m_miner || m_minerSeed != _work.seedHash) + m_work = _work; + startWorking(); +} + +void Ethash::GPUMiner::workLoop() +{ + // take local copy of work since it may end up being overwritten by kickOff/pause. + WorkPackage w = m_work; + if (!m_miner || m_minerSeed != w.seedHash) { - if (m_miner) - m_hook->abort(); + m_minerSeed = w.seedHash; delete m_miner; m_miner = new ethash_cl_miner; - auto p = EthashAux::params(_work.seedHash); - auto cb = [&](void* d) { EthashAux::full(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; + auto p = EthashAux::params(m_minerSeed); + auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; m_miner->init(p, cb, 32); } - if (m_lastWork.headerHash != _work.headerHash) - { - m_hook->abort(); - uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); - m_miner->search(_work.headerHash.data(), upper64OfBoundary, *m_hook); - } - m_lastWork = _work; + + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); + m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); } void Ethash::GPUMiner::pause() { m_hook->abort(); + stopWorking(); + m_work.headerHash = h256(); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 1a7d82149..8f1ba3eb3 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -59,6 +59,11 @@ public: struct WorkPackage { + WorkPackage() = default; + + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + h256 boundary; h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; @@ -89,17 +94,16 @@ public: startWorking(); } - void pause() override { stopWorking(); } + void pause() override { stopWorking(); m_work.reset(); } private: void workLoop() override; WorkPackage m_work; - MineInfo m_info; }; #if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner + class GPUMiner: public Miner, Worker { friend class dev::eth::EthashCLHook; @@ -114,14 +118,16 @@ public: void pause() override; private: + void workLoop() override; bool report(uint64_t _nonce); - EthashCLHook* m_hook; - ethash_cl_miner* m_miner; + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; - h256 m_minerSeed; - WorkPackage m_lastWork; ///< Work loaded into m_miner. - MineInfo m_info; + h256 m_minerSeed; ///< Last seed in m_miner + WorkPackage m_work; ///< Work to be done by GPU, set with kickOff and picked up in workLoop. }; #else using GPUMiner = CPUMiner; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 9372c06b1..ea51b0eb5 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -34,30 +34,24 @@ namespace dev namespace eth { -struct MineInfo -{ - MineInfo() = default; - MineInfo(bool _completed): completed(_completed) {} - void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; } - double requirement = 0; - double best = 1e99; - unsigned hashes = 0; - bool completed = false; -}; - /** * @brief Describes the progress of a mining operation. */ struct MiningProgress { - void combine(MiningProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } - double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. - double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. - double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } unsigned hashes = 0; ///< Total number of hashes computed. unsigned ms = 0; ///< Total number of milliseconds of mining thus far. }; +struct MineInfo: public MiningProgress {}; + +inline std::ostream& operator<<(std::ostream& _out, MiningProgress const& _p) +{ + _out << (_p.hashes * 1000 / _p.ms) << "H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << "s"; + return _out; +} + template class GenericMiner; /** @@ -103,13 +97,18 @@ public: void setWork(WorkPackage const& _work = WorkPackage()) { Guard l(x_work); + if (_work.headerHash == m_work.headerHash) + return; if (_work.headerHash != h256()) - kickOff(m_work); + kickOff(_work); else if (m_work.headerHash == h256() && _work.headerHash != h256()) pause(); m_work = _work; + m_hashCount = 0; } + unsigned hashCount() { return m_hashCount; } + unsigned index() const { return m_index; } protected: @@ -146,12 +145,16 @@ protected: WorkPackage const& work() const { return m_work; } + void accumulateHashes(unsigned _n) { m_hashCount += _n; } + private: FarmFace* m_farm = nullptr; unsigned m_index; Mutex x_work; WorkPackage m_work; + + unsigned m_hashCount = 0; }; } diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 09c7f0e78..c20c27e6d 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -56,16 +56,16 @@ public: */ void setWork(BlockInfo const& _bi) { - WorkPackage w; - { - WriteGuard l(x_work); - m_header = _bi; - w = m_work = PoW::package(m_header); - } - + WriteGuard l(x_work); ReadGuard l2(x_miners); + m_header = _bi; + auto p = PoW::package(m_header); + if (p.headerHash == m_work.headerHash) + return; + m_work = p; for (auto const& m: m_miners) m->setWork(m_work); + resetTimer(); } /** @@ -99,7 +99,19 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const { ReadGuard l(x_progress); return m_progress; } + MiningProgress const& miningProgress() const + { + MiningProgress p; + p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); + { + ReadGuard l2(x_miners); + for (auto const& i: m_miners) + p.hashes += i->hashCount(); + } + ReadGuard l(x_progress); + m_progress = p; + return m_progress; + } using SolutionFound = std::function; @@ -110,6 +122,8 @@ public: */ void onSolutionFound(SolutionFound const& _handler) { m_onSolutionFound = _handler; } + WorkPackage work() const { ReadGuard l(x_work); return m_work; } + private: /** * @brief Called from a Miner to note a WorkPackage has a solution. @@ -140,21 +154,32 @@ private: template bool start() { - WriteGuard l(x_miners); + ReadGuard l(x_work); + WriteGuard l2(x_miners); if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) return true; m_miners.clear(); m_miners.reserve(MinerType::instances()); for (unsigned i = 0; i < MinerType::instances(); ++i) + { m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + resetTimer(); return true; } + void resetTimer() + { + m_lastStart = std::chrono::steady_clock::now(); + } + mutable SharedMutex x_miners; std::vector> m_miners; mutable SharedMutex x_progress; - MiningProgress m_progress; + mutable MiningProgress m_progress; + std::chrono::steady_clock::time_point m_lastStart; mutable SharedMutex x_work; WorkPackage m_work; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 254ceb325..f9513e80c 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -20,6 +20,7 @@ * Ethereum IDE client. */ +#include "MixClient.h" #include #include #include @@ -28,10 +29,8 @@ #include #include #include - #include "Exceptions.h" -#include "MixClient.h" - +using namespace std; using namespace dev; using namespace dev::eth; @@ -250,9 +249,17 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - ProofOfWork pow; - while (!m_state.mine(&pow).completed) {} - m_state.completeMine(); + GenericFarm f; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + return completed = m_state.completeMine(sol); + }); + f.setWork(m_state.info()); + f.startCPU(); + while (!completed) + this_thread::sleep_for(chrono::milliseconds(20)); + bc().import(m_state.blockData(), m_stateDB); m_state.sync(bc()); m_startState = m_state; @@ -392,9 +399,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MineProgress MixClient::miningProgress() const +eth::MiningProgress MixClient::miningProgress() const { - return eth::MineProgress(); + return eth::MiningProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index 0d1cce2bc..81087f3b4 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -67,8 +67,8 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MineProgress miningProgress() const override; - std::pair getWork() override { return std::pair(); } + eth::MiningProgress miningProgress() const override; + eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } virtual void flushTransactions() override {} diff --git a/neth/main.cpp b/neth/main.cpp index fd3d3f403..4c38da0a4 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -40,7 +40,6 @@ #include #include #endif -#include #include "BuildInfo.h" #undef KEY_EVENT // from windows.h @@ -332,7 +331,6 @@ int main(int argc, char** argv) unsigned mining = ~(unsigned)0; NodeMode mode = NodeMode::Full; unsigned peers = 5; - int miners = -1; #if ETH_JSONRPC int jsonrpc = 8080; #endif @@ -502,8 +500,6 @@ int main(int argc, char** argv) g_logVerbosity = atoi(argv[++i]); else if ((arg == "-x" || arg == "--peers") && i + 1 < argc) peers = atoi(argv[++i]); - else if ((arg == "-t" || arg == "--miners") && i + 1 < argc) - miners = atoi(argv[++i]); else if ((arg == "-o" || arg == "--mode") && i + 1 < argc) { string m = argv[++i]; @@ -553,9 +549,7 @@ int main(int argc, char** argv) killChain ? WithExisting::Kill : WithExisting::Trust, mode == NodeMode::Full ? set{"eth", "shh"} : set(), netPrefs, - &nodesState, - miners - ); + &nodesState); web3.setIdealPeerCount(peers); std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); @@ -1253,7 +1247,7 @@ int main(int argc, char** argv) if (c && c->isMining()) { mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON"); - dev::eth::MineProgress p = c->miningProgress(); + dev::eth::MiningProgress p = c->miningProgress(); auto speed = boost::format("%2% kH/s @ %1%s") % (p.ms / 1000) % (p.ms ? p.hashes / p.ms : 0); mvwprintw(consolewin, qheight - 2, width / 4 - speed.str().length() - 2, speed.str().c_str()); } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index e86b84aad..8b528b3ee 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -62,6 +62,37 @@ void connectClients(Client& c1, Client& c2) c2.connect("127.0.0.1", c1Port); #endif } + +void mine(State& s, BlockChain const& _bc) +{ + s.commitToMine(_bc); + GenericFarm f; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + return completed = s.completeMine(sol); + }); + f.setWork(s.info()); + f.startCPU(); + while (!completed) + this_thread::sleep_for(chrono::milliseconds(20)); +} + +void mine(BlockInfo& _bi) +{ + GenericFarm f; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + ProofOfWork::assignResult(sol, _bi); + return completed = true; + }); + f.setWork(_bi); + f.startCPU(); + while (!completed) + this_thread::sleep_for(chrono::milliseconds(20)); +} + } namespace test diff --git a/test/TestHelper.h b/test/TestHelper.h index 04ca95be4..92745bc36 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -36,9 +36,12 @@ namespace eth { class Client; +class State; void mine(Client& c, int numBlocks); void connectClients(Client& c1, Client& c2); +void mine(State& _s, BlockChain const& _bc); +void mine(BlockInfo& _bi); } @@ -225,7 +228,5 @@ public: }; }; - - } } diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 6d7bc97ef..258117695 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -190,11 +190,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { state.sync(bc); state.sync(bc, txs, gp); - state.commitToMine(bc); - MineInfo info; - ProofOfWork pow; - for (info.completed = false; !info.completed; info = state.mine(&pow)) {} - state.completeMine(); + mine(state, bc); } catch (Exception const& _e) { @@ -519,76 +515,55 @@ bytes createBlockRLPFromFields(mObject& _tObj) return rlpStream.out(); } -void overwriteBlockHeader(BlockInfo& _currentBlockHeader, mObject& _blObj) +void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { - if (_blObj["blockHeader"].get_obj().size() != 14) + auto ho = _blObj["blockHeader"].get_obj(); + if (ho.size() != 14) { - - BlockInfo tmp = _currentBlockHeader; - - if (_blObj["blockHeader"].get_obj().count("parentHash")) - tmp.parentHash = h256(_blObj["blockHeader"].get_obj()["parentHash"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("uncleHash")) - tmp.sha3Uncles = h256(_blObj["blockHeader"].get_obj()["uncleHash"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("coinbase")) - tmp.coinbaseAddress = Address(_blObj["blockHeader"].get_obj()["coinbase"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("stateRoot")) - tmp.stateRoot = h256(_blObj["blockHeader"].get_obj()["stateRoot"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("transactionsTrie")) - tmp.transactionsRoot = h256(_blObj["blockHeader"].get_obj()["transactionsTrie"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("receiptTrie")) - tmp.receiptsRoot = h256(_blObj["blockHeader"].get_obj()["receiptTrie"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("bloom")) - tmp.logBloom = LogBloom(_blObj["blockHeader"].get_obj()["bloom"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("difficulty")) - tmp.difficulty = toInt(_blObj["blockHeader"].get_obj()["difficulty"]); - - if (_blObj["blockHeader"].get_obj().count("number")) - tmp.number = toInt(_blObj["blockHeader"].get_obj()["number"]); - - if (_blObj["blockHeader"].get_obj().count("gasLimit")) - tmp.gasLimit = toInt(_blObj["blockHeader"].get_obj()["gasLimit"]); - - if (_blObj["blockHeader"].get_obj().count("gasUsed")) - tmp.gasUsed = toInt(_blObj["blockHeader"].get_obj()["gasUsed"]); - - if (_blObj["blockHeader"].get_obj().count("timestamp")) - tmp.timestamp = toInt(_blObj["blockHeader"].get_obj()["timestamp"]); - - if (_blObj["blockHeader"].get_obj().count("extraData")) - tmp.extraData = importByteArray(_blObj["blockHeader"].get_obj()["extraData"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("mixHash")) - tmp.mixHash = h256(_blObj["blockHeader"].get_obj()["mixHash"].get_str()); + BlockInfo tmp = _header; + if (ho.count("parentHash")) + tmp.parentHash = h256(ho["parentHash"].get_str()); + if (ho.count("uncleHash")) + tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + if (ho.count("coinbase")) + tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + if (ho.count("stateRoot")) + tmp.stateRoot = h256(ho["stateRoot"].get_str()); + if (ho.count("transactionsTrie")) + tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + if (ho.count("receiptTrie")) + tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + if (ho.count("bloom")) + tmp.logBloom = LogBloom(ho["bloom"].get_str()); + if (ho.count("difficulty")) + tmp.difficulty = toInt(ho["difficulty"]); + if (ho.count("number")) + tmp.number = toInt(ho["number"]); + if (ho.count("gasLimit")) + tmp.gasLimit = toInt(ho["gasLimit"]); + if (ho.count("gasUsed")) + tmp.gasUsed = toInt(ho["gasUsed"]); + if (ho.count("timestamp")) + tmp.timestamp = toInt(ho["timestamp"]); + if (ho.count("extraData")) + tmp.extraData = importByteArray(ho["extraData"].get_str()); + if (ho.count("mixHash")) + tmp.mixHash = h256(ho["mixHash"].get_str()); + tmp.noteDirty(); // find new valid nonce - - if (tmp != _currentBlockHeader) + if (tmp != _header) { - _currentBlockHeader = tmp; - - ProofOfWork pow; - std::pair ret; - while (!ProofOfWork::verify(_currentBlockHeader)) - { - ret = pow.mine(_currentBlockHeader, 1000, true); - Ethash::assignResult(ret.second, _currentBlockHeader); - } + mine(tmp); + _header = tmp; } } else { // take the blockheader as is - const bytes c_blockRLP = createBlockRLPFromFields(_blObj["blockHeader"].get_obj()); + const bytes c_blockRLP = createBlockRLPFromFields(ho); const RLP c_bRLP(c_blockRLP); - _currentBlockHeader.populateFromHeader(c_bRLP, IgnoreNonce); + _header.populateFromHeader(c_bRLP, IgnoreNonce); } } @@ -620,13 +595,7 @@ BlockInfo constructBlock(mObject& _o) void updatePoW(BlockInfo& _bi) { - ProofOfWork pow; - std::pair ret; - while (!ProofOfWork::verify(_bi)) - { - ret = pow.mine(_bi, 10000, true); - Ethash::assignResult(ret.second, _bi); - } + mine(_bi); _bi.noteDirty(); } diff --git a/test/dagger.cpp b/test/dagger.cpp index 4abba5090..367c422ad 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -25,7 +25,7 @@ #include "JsonSpiritHeaders.h" #include #include -#include +#include #include #include "TestHelper.h" @@ -63,18 +63,18 @@ BOOST_AUTO_TEST_CASE(basic_test) unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); - BOOST_REQUIRE_EQUAL(Ethasher::get()->params(header).cache_size, cacheSize); - BOOST_REQUIRE_EQUAL(sha3(bytesConstRef((byte const*)Ethasher::get()->light(header), cacheSize)), cacheHash); + BOOST_REQUIRE_EQUAL(EthashAux::get()->params(header).cache_size, cacheSize); + BOOST_REQUIRE_EQUAL(sha3(bytesConstRef((byte const*)EthashAux::get()->light(header), cacheSize)), cacheHash); #if TEST_FULL unsigned fullSize(o["full_size"].get_int()); h256 fullHash(o["full_hash"].get_str()); - BOOST_REQUIRE_EQUAL(Ethasher::get()->full(header).size(), fullSize); - BOOST_REQUIRE_EQUAL(sha3(Ethasher::get()->full(header)), fullHash); + BOOST_REQUIRE_EQUAL(EthashAux::get()->full(header).size(), fullSize); + BOOST_REQUIRE_EQUAL(sha3(EthashAux::get()->full(header)), fullHash); #endif h256 result(o["result"].get_str()); - Ethasher::Result r = Ethasher::eval(header); + Ethash::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp index 40f759434..e1a3c7c4a 100644 --- a/test/stateOriginal.cpp +++ b/test/stateOriginal.cpp @@ -25,7 +25,9 @@ #include #include #include +#include #include +#include "TestHelper.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -67,10 +69,8 @@ BOOST_AUTO_TEST_CASE(Complex) cout << s; // Mine to get some ether! - s.commitToMine(bc); - ProofOfWork pow; - while (!s.mine(&pow).completed) {} - s.completeMine(); + mine(s, bc); + bc.attemptImport(s.blockData(), stateDB); cout << bc; @@ -89,8 +89,7 @@ BOOST_AUTO_TEST_CASE(Complex) // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - while (!s.mine(&pow).completed) {} - s.completeMine(); + mine(s, bc); bc.attemptImport(s.blockData(), stateDB); cout << bc; diff --git a/third/MainWin.cpp b/third/MainWin.cpp index b03723131..12625ffbc 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -465,7 +465,7 @@ void Main::on_urlEdit_returnPressed() void Main::refreshMining() { - dev::eth::MineProgress p = ethereum()->miningProgress(); + dev::eth::MiningProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining"); } From 98a2805b5c399dba5cbb77b56967c35457218182 Mon Sep 17 00:00:00 2001 From: ethdev zug Date: Mon, 13 Apr 2015 17:35:29 +0100 Subject: [PATCH 047/108] fixed copying dlls --- alethzero/CMakeLists.txt | 2 +- cmake/EthExecutableHelper.cmake | 21 +++++++++++++-------- cmake/scripts/copydlls.cmake | 13 +++++++------ eth/CMakeLists.txt | 4 +--- ethrpctest/CMakeLists.txt | 2 +- third/CMakeLists.txt | 2 +- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index c81c86222..e0cdab589 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -64,5 +64,5 @@ if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")) endif() # eth_install_executable is defined in cmake/EthExecutableHelper.cmake -eth_install_executable(${EXECUTABLE} DLLS ${MHD_DLL_RELEASE}) +eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index a2d2de8b9..be4f7ccd1 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -44,10 +44,18 @@ macro(eth_add_executable EXECUTABLE) endmacro() macro(eth_copy_dlls EXECUTABLE DLLS) - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMNAND ${CMAKE_COMMAND} - -DLIBS="${DLLS}" - -DCONFIGURATION="$" - -DDESTINATION="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" + # dlls must be unsubstitud list variable (without ${}) in format + # optimized;path_to_dll.dll;debug;path_to_dlld.dll + list(GET ${DLLS} 1 DLL_RELEASE) + list(GET ${DLLS} 3 DLL_DEBUG) + add_custom_command(TARGET ${EXECUTABLE} + POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS + -DDLL_RELEASE="${DLL_RELEASE}" + -DDLL_DEBUG="${DLL_DEBUG}" + -DCONF="$" + -DDESTINATION="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" + -P "${ETH_SCRIPTS_DIR}/copydlls.cmake" ) endmacro() @@ -115,10 +123,7 @@ macro(eth_install_executable EXECUTABLE) #copy additional dlls foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS}) - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS -E copy ${dll} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" - ) + eth_copy_dlls(${EXECUTABLE} ${dll}) endforeach(dll) install( TARGETS ${EXECUTABLE} RUNTIME diff --git a/cmake/scripts/copydlls.cmake b/cmake/scripts/copydlls.cmake index 49c2e1c03..6d86b8e4e 100644 --- a/cmake/scripts/copydlls.cmake +++ b/cmake/scripts/copydlls.cmake @@ -1,16 +1,17 @@ # this module expects # DLLS -# CONFIGURATION +# CONF # DESTINATION # example usage: -# cmake -DLLS=${MHD_LIBRARIES} -DCONFIGURATION=Release -DDESTINATION=dest -P scripts/copydlls.cmake +# cmake -DDLL_DEBUG=xd.dll -DDLL_RELEASE=x.dll -DCONFIGURATION=Release -DDESTINATION=dest -P scripts/copydlls.cmake -# expects DLLS to be in format optimized;path_to_dll.dll;debug;path_to_dll_d.dll -if (${CONFIGURATION} STREQUAL "Release") - list(GET DLLS 1 DLL) +# this script is created cause we do not know configuration in multiconfiguration generators at cmake configure phase ;) + +if ("${CONF}" STREQUAL "Release") + set(DLL ${DLL_RELEASE}) else () # Debug - list(GET DLLS 3 DLL) + set(DLL ${DLL_DEBUG}) endif() execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${DLL}" "${DESTINATION}") diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index 047f81c49..2b354dab2 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -29,9 +29,7 @@ target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethash) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) - eth_copy_dlls(${EXECUTABLE} ${MHD_DLLS}) - #add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") - + eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) endif() install( TARGETS ${EXECUTABLE} DESTINATION bin ) diff --git a/ethrpctest/CMakeLists.txt b/ethrpctest/CMakeLists.txt index 5d3fef542..e28b08d70 100644 --- a/ethrpctest/CMakeLists.txt +++ b/ethrpctest/CMakeLists.txt @@ -28,7 +28,7 @@ target_link_libraries(${EXECUTABLE} testutils) target_link_libraries(${EXECUTABLE} web3jsonrpc) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) endif() install( TARGETS ${EXECUTABLE} DESTINATION bin ) diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt index 397f2b7a6..a173d10fd 100644 --- a/third/CMakeLists.txt +++ b/third/CMakeLists.txt @@ -52,5 +52,5 @@ target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} jsqrc) # eth_install_executable is defined in cmake/EthExecutableHelper.cmake -eth_install_executable(${EXECUTABLE} DLLS ${MHD_DLL_RELEASE}) +eth_install_executable(${EXECUTABLE} DLLS MHD_DLLS) From cedc840185fbfa32ec19b368efbb68c19f4e97b8 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 13 Apr 2015 15:23:22 -0400 Subject: [PATCH 048/108] defer failure when H of pubk doesn't match (reverts back to release functionality where assert() is skipped) --- libp2p/RLPxHandshake.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index d437ae839..bb9af2ef7 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -95,10 +95,7 @@ void RLPXHandshake::readAuth() m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret ^ m_remoteNonce); if (sha3(m_remoteEphemeral) != *(h256*)hepubk.data()) - { clog(NetConnect) << "p2p.connect.ingress auth failed (invalid: hash mismatch) for" << m_socket->remoteEndpoint(); - m_nextState = Error; - } transition(); } From 54e40484c1b9bf2ffcd2a0d08426ebff313d6b3f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 21:36:55 +0200 Subject: [PATCH 049/108] Thread management fixes for Farm. --- exp/main.cpp | 21 +++++++++------------ libdevcore/Worker.cpp | 22 +++++++++++++++++----- libdevcore/Worker.h | 10 +++++++++- libethcore/Ethash.cpp | 36 +++++++++++++++++++++--------------- libethcore/Ethash.h | 10 +++------- libethcore/Miner.h | 31 ++++++++++++++++++------------- libethereum/Farm.h | 7 ++++++- 7 files changed, 83 insertions(+), 54 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 933fda1a6..2055c49e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -125,33 +125,30 @@ int main() f.setWork(bi); for (unsigned i = 0; !completed && i < timeout * 10; ++i, cout << f.miningProgress() << "\r" << flush) this_thread::sleep_for(chrono::milliseconds(100)); + cout << endl << flush; cdebug << bi.mixHash << bi.nonce << (Ethash::verify(bi) ? "GOOD" : "bad"); }; + Ethash::prep(genesis); + + genesis.difficulty = u256(1) << 40; + genesis.noteDirty(); f.startCPU(); mine(f, genesis, 10); - mine(f, genesis, 10); + f.startGPU(); cdebug << "Good:"; genesis.difficulty = 1 << 18; genesis.noteDirty(); - mine(f, genesis, 3); + mine(f, genesis, 30); cdebug << "Bad:"; genesis.difficulty = (u256(1) << 40); genesis.noteDirty(); - mine(f, genesis, 3); + mine(f, genesis, 30); - cdebug << "Good:"; - genesis.difficulty = 1 << 18; - genesis.noteDirty(); - mine(f, genesis, 3); - - cdebug << "Bad:"; - genesis.difficulty = (u256(1) << 40); - genesis.noteDirty(); - mine(f, genesis, 3); + f.stop(); return 0; } diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index bc8fe97f2..65e8efcbb 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -27,12 +27,20 @@ using namespace std; using namespace dev; -void Worker::startWorking() +void Worker::startWorking(IfRunning _ir) { cnote << "startWorking for thread" << m_name; Guard l(x_work); - if (m_work) - return; + + if (m_work && m_work->joinable()) + try { + if (_ir == IfRunning::Detach) + m_work->detach(); + else if (_ir == IfRunning::Join) + m_work->join(); + else + return; + } catch (...) {} cnote << "Spawning" << m_name; m_stop = false; m_work.reset(new thread([&]() @@ -40,6 +48,7 @@ void Worker::startWorking() setThreadName(m_name.c_str()); startedWorking(); workLoop(); + m_work->detach(); cnote << "Finishing up worker thread"; doneWorking(); })); @@ -49,11 +58,14 @@ void Worker::stopWorking() { cnote << "stopWorking for thread" << m_name; Guard l(x_work); - if (!m_work) + if (!m_work || !m_work->joinable()) return; cnote << "Stopping" << m_name; m_stop = true; - m_work->join(); + try { + m_work->join(); + } + catch (...) {} m_work.reset(); cnote << "Stopped" << m_name; } diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 24ff4cc15..287ff6d6f 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -23,11 +23,19 @@ #include #include +#include #include "Guards.h" namespace dev { +enum class IfRunning +{ + Fail, + Join, + Detach +}; + class Worker { protected: @@ -45,7 +53,7 @@ protected: void setName(std::string _n) { if (!isWorking()) m_name = _n; } /// Starts worker thread; causes startedWorking() to be called. - void startWorking(); + void startWorking(IfRunning _ir = IfRunning::Fail); /// Stop worker thread; causes call to stopWorking(). void stopWorking(); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f66188976..3dd9d3b60 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -30,9 +30,10 @@ #include #include #include +#include +#include #include #include -#include #include #if ETH_ETHASHCL || !ETH_TRUE #include @@ -123,10 +124,12 @@ void Ethash::CPUMiner::workLoop() uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng); ethash_return_value ethashReturn; - auto p = EthashAux::params(m_work.seedHash); - void const* dagPointer = EthashAux::full(m_work.seedHash).data(); - uint8_t const* headerHashPointer = m_work.headerHash.data(); - h256 boundary = m_work.boundary; + WorkPackage w = work(); + + auto p = EthashAux::params(w.seedHash); + void const* dagPointer = EthashAux::full(w.seedHash).data(); + uint8_t const* headerHashPointer = w.headerHash.data(); + h256 boundary = w.boundary; unsigned hashCount = 1; for (; !shouldStop(); tryNonce++, hashCount++) { @@ -149,7 +152,6 @@ public: void abort() { Guard l(x_all); - m_owner->m_work.headerHash = h256(); if (m_aborted) return; // cdebug << "Attempting to abort"; @@ -158,13 +160,17 @@ public: std::this_thread::sleep_for(chrono::milliseconds(30)); // if (!m_aborted) // cwarn << "Couldn't abort. Abandoning OpenCL process."; + } + + void reset() + { m_aborted = m_abort = false; } protected: virtual bool found(uint64_t const* _nonces, uint32_t _count) override { -// cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); +// dev::operator <<(std::cerr << "Found nonces: ", vector(_nonces, _nonces + _count)) << std::endl; for (uint32_t i = 0; i < _count; ++i) { if (m_owner->report(_nonces[i])) @@ -179,7 +185,7 @@ protected: virtual bool searched(uint64_t _startNonce, uint32_t _count) override { Guard l(x_all); -// cdebug << "Searched" << _count << "from" << _startNonce; +// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; m_owner->accumulateHashes(_count); m_last = _startNonce + _count; if (m_abort) @@ -206,29 +212,30 @@ Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Ethash::GPUMiner::~GPUMiner() { - delete m_hook; + pause(); delete m_miner; + delete m_hook; } bool Ethash::GPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = EthashAux::eval(m_work.seedHash, m_work.headerHash, n); - if (r.value < m_work.boundary) + Result r = EthashAux::eval(work().seedHash, work().headerHash, n); + if (r.value < work().boundary) return submitProof(Solution{n, r.mixHash}); return false; } -void Ethash::GPUMiner::kickOff(WorkPackage const& _work) +void Ethash::GPUMiner::kickOff() { - m_work = _work; + m_hook->reset(); startWorking(); } void Ethash::GPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. - WorkPackage w = m_work; + WorkPackage w = work(); if (!m_miner || m_minerSeed != w.seedHash) { m_minerSeed = w.seedHash; @@ -249,7 +256,6 @@ void Ethash::GPUMiner::pause() { m_hook->abort(); stopWorking(); - m_work.headerHash = h256(); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 8f1ba3eb3..06e6b9e96 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,19 +87,16 @@ public: static unsigned instances() { return std::thread::hardware_concurrency(); } protected: - void kickOff(WorkPackage const& _work) override + void kickOff() override { stopWorking(); - m_work = _work; startWorking(); } - void pause() override { stopWorking(); m_work.reset(); } + void pause() override { stopWorking(); } private: void workLoop() override; - - WorkPackage m_work; }; #if ETH_ETHASHCL || !ETH_TRUE @@ -114,7 +111,7 @@ public: static unsigned instances() { return 1; } protected: - void kickOff(WorkPackage const& _work) override; + void kickOff() override; void pause() override; private: @@ -127,7 +124,6 @@ public: ethash_cl_miner* m_miner = nullptr; h256 m_minerSeed; ///< Last seed in m_miner - WorkPackage m_work; ///< Work to be done by GPU, set with kickOff and picked up in workLoop. }; #else using GPUMiner = CPUMiner; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index ea51b0eb5..084cc59ff 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -40,13 +40,13 @@ namespace eth struct MiningProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - unsigned hashes = 0; ///< Total number of hashes computed. - unsigned ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. }; struct MineInfo: public MiningProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress const& _p) +inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) { _out << (_p.hashes * 1000 / _p.ms) << "H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << "s"; return _out; @@ -97,17 +97,19 @@ public: void setWork(WorkPackage const& _work = WorkPackage()) { Guard l(x_work); - if (_work.headerHash == m_work.headerHash) - return; - if (_work.headerHash != h256()) - kickOff(_work); - else if (m_work.headerHash == h256() && _work.headerHash != h256()) - pause(); + auto old = m_work; m_work = _work; + if (!!m_work) + { + pause(); + kickOff(); + } + else if (!m_work && !!old) + pause(); m_hashCount = 0; } - unsigned hashCount() { return m_hashCount; } + uint64_t hashCount() { return m_hashCount; } unsigned index() const { return m_index; } @@ -119,7 +121,7 @@ protected: * @brief Begin working on a given work package, discarding any previous work. * @param _work The package for which to find a solution. */ - virtual void kickOff(WorkPackage const& _work) = 0; + virtual void kickOff() = 0; /** * @brief No work left to be done. Pause until told to kickOff(). @@ -138,7 +140,10 @@ protected: if (m_farm) { Guard l(x_work); - return m_farm->submitProof(_s, m_work, this); + if (!m_farm->submitProof(_s, m_work, this)) + return false; + m_work.reset(); + return true; } return true; } @@ -154,7 +159,7 @@ private: Mutex x_work; WorkPackage m_work; - unsigned m_hashCount = 0; + uint64_t m_hashCount = 0; }; } diff --git a/libethereum/Farm.h b/libethereum/Farm.h index c20c27e6d..6b65e37c2 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -50,6 +50,11 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + ~GenericFarm() + { + stop(); + } + /** * @brief Sets the current mining mission. * @param _bi The block (header) we wish to be mining. @@ -142,7 +147,7 @@ private: for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->setWork(); - m_work.headerHash = h256(); + m_work.reset(); return true; } return false; From e195a254dae62a064a82807d450c2553a47b830e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 22:49:17 +0200 Subject: [PATCH 050/108] Fix CPU mining deadlock bug. --- exp/main.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++- libethcore/Miner.h | 6 ++-- libethereum/Farm.h | 4 ++- 3 files changed, 78 insertions(+), 6 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 2055c49e1..54b75d0e2 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -25,6 +25,7 @@ #include "libethash-cl/cl.hpp" #endif #include +#include #include #include #include @@ -106,7 +107,7 @@ int main() cnote << "State after transaction: " << s; cnote << before.diff(s); } -#else +#elif 0 int main() { GenericFarm f; @@ -152,5 +153,76 @@ int main() return 0; } +#else + +void mine(State& s, BlockChain const& _bc) +{ + s.commitToMine(_bc); + GenericFarm f; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + return completed = s.completeMine(sol); + }); + f.setWork(s.info()); + f.startCPU(); + while (!completed) + this_thread::sleep_for(chrono::milliseconds(20)); +} + +int main() +{ + cnote << "Testing State..."; + + KeyPair me = sha3("Gav Wood"); + KeyPair myMiner = sha3("Gav's Miner"); +// KeyPair you = sha3("123"); + + Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); + + OverlayDB stateDB = State::openDB(); + CanonBlockChain bc; + cout << bc; + + State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + cout << s; + + // Sync up - this won't do much until we use the last state. + s.sync(bc); + + cout << s; + + // Mine to get some ether! + mine(s, bc); + + bc.attemptImport(s.blockData(), stateDB); + + cout << bc; + + s.sync(bc); + + cout << s; + + // Inject a transaction to transfer funds from miner to me. + Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); + assert(t.sender() == myMiner.address()); + s.execute(bc.lastHashes(), t); + + cout << s; + + // Mine to get some ether and set in stone. + s.commitToMine(bc); + s.commitToMine(bc); + mine(s, bc); + bc.attemptImport(s.blockData(), stateDB); + + cout << bc; + + s.sync(bc); + + cout << s; + + return 0; +} #endif diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 084cc59ff..a048b0238 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -69,11 +69,11 @@ public: /** * @brief Called from a Miner to note a WorkPackage has a solution. * @param _p The solution. - * @param _wp The WorkPackage that the Solution is for. + * @param _wp The WorkPackage that the Solution is for; this will be reset if the work is accepted. * @param _finder The miner that found it. * @return true iff the solution was good (implying that mining should be . */ - virtual bool submitProof(Solution const& _p, WorkPackage const& _wp, Miner* _finder) = 0; + virtual bool submitProof(Solution const& _p, WorkPackage& io_wp, Miner* _finder) = 0; }; /** @@ -139,10 +139,8 @@ protected: { if (m_farm) { - Guard l(x_work); if (!m_farm->submitProof(_s, m_work, this)) return false; - m_work.reset(); return true; } return true; diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 6b65e37c2..56bbcb9df 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -136,8 +136,9 @@ private: * @param _wp The WorkPackage that the Solution is for. * @return true iff the solution was good (implying that mining should be . */ - bool submitProof(Solution const& _s, WorkPackage const& _wp, Miner* _m) override + bool submitProof(Solution const& _s, WorkPackage& _wp, Miner* _m) override { + ReadGuard l(x_work); if (_wp.headerHash != m_work.headerHash) return false; @@ -147,6 +148,7 @@ private: for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->setWork(); + _wp.reset(); m_work.reset(); return true; } From e77c9e8c89671ee04bd913a5d7a49785a67a2de8 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 13 Apr 2015 22:57:57 +0200 Subject: [PATCH 051/108] cryptopp && leveldb are looking for x64 libs --- cmake/FindCryptoPP.cmake | 12 ++++++++++-- cmake/FindLevelDB.cmake | 18 ++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cmake/FindCryptoPP.cmake b/cmake/FindCryptoPP.cmake index a9e7183c0..90ea4925d 100644 --- a/cmake/FindCryptoPP.cmake +++ b/cmake/FindCryptoPP.cmake @@ -53,14 +53,22 @@ FIND_PATH (CRYPTOPP_INCLUDE_DIR PATH_SUFFIXES include DOC "CryptoPP include directory") +if (CMAKE_CL_64) + set(CRYPTOPP_NAMES cryptlib_x64 cryptopp_x64) + set(CRYPTOPP_NAMES_DEBUG cryptlibd_x64 cryptoppd_x64) +else () + set(CRYPTOPP_NAMES cryptlib cryptopp) + set(CRYPTOPP_NAMES_DEBUG cryptlibd cryptoppd) +endif() + FIND_LIBRARY (CRYPTOPP_LIBRARY_DEBUG - NAMES cryptlibd cryptoppd + NAMES ${CRYPTOPP_NAMES_DEBUG} HINTS ${CRYPTOPP_ROOT_DIR} PATH_SUFFIXES lib DOC "CryptoPP debug library") FIND_LIBRARY (CRYPTOPP_LIBRARY_RELEASE - NAMES cryptlib cryptopp + NAMES ${CRYPTOPP_NAMES} HINTS ${CRYPTOPP_ROOT_DIR} PATH_SUFFIXES lib DOC "CryptoPP release library") diff --git a/cmake/FindLevelDB.cmake b/cmake/FindLevelDB.cmake index b1a9a5815..82b1e277e 100644 --- a/cmake/FindLevelDB.cmake +++ b/cmake/FindLevelDB.cmake @@ -16,9 +16,16 @@ find_path( DOC "leveldb include dir" ) +# if msvc 64 build +if (CMAKE_CL_64) + set(LEVELDB_NAMES leveldb_x64) +else () + set(LEVELDB_NAMES leveldb) +endif() + find_library( LEVELDB_LIBRARY - NAMES leveldb + NAMES ${LEVELDB_NAMES} DOC "leveldb library" ) @@ -29,9 +36,16 @@ set(LEVELDB_LIBRARIES ${LEVELDB_LIBRARY}) # same naming convention as in qt (appending debug library with d) # boost is using the same "hack" as us with "optimized" and "debug" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + + if (CMAKE_CL_64) + set(LEVELDB_NAMES_DEBUG leveldbd_x64) + else () + set(LEVELDB_NAMES_DEBUG leveldbd) + endif() + find_library( LEVELDB_LIBRARY_DEBUG - NAMES leveldbd + NAMES ${LEVELDB_NAMES_DEBUG} DOC "leveldb debug library" ) From dd7135882586b530f6df0004db599a2fbe7a80fe Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 02:44:01 -0400 Subject: [PATCH 052/108] proper neighbours packet size w/test --- libp2p/NodeTable.cpp | 2 +- test/net.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 2837e8f07..ce76e9751 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -468,7 +468,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes); vector> nearest = nearestNodeEntries(in.target); - static unsigned const nlimit = (m_socketPointer->maxDatagramSize - 13) / 87; + static unsigned const nlimit = (m_socketPointer->maxDatagramSize - 111) / 87; for (unsigned offset = 0; offset < nearest.size(); offset += nlimit) { Neighbours out(_from, nearest, offset, nlimit); diff --git a/test/net.cpp b/test/net.cpp index ec1efb360..c6aeec8f1 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -190,6 +190,33 @@ BOOST_AUTO_TEST_CASE(v2PingNodePacket) BOOST_REQUIRE(p.version == 2); } +BOOST_AUTO_TEST_CASE(neighboursPacketLength) +{ + KeyPair k = KeyPair::create(); + std::vector> testNodes(TestNodeTable::createTestNodes(16)); + bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); + + // hash(32), signature(65), overhead: packet(2), type(1), nodeList(2), ts(9), + static unsigned const nlimit = (1280 - 111) / 87; + for (unsigned offset = 0; offset < testNodes.size(); offset += nlimit) + { + Neighbours out(to); + + auto limit = nlimit ? std::min(testNodes.size(), (size_t)(offset + nlimit)) : testNodes.size(); + for (auto i = offset; i < limit; i++) + { + Neighbours::Node node; + node.ipAddress = boost::asio::ip::address::from_string("200.200.200.200").to_string(); + node.port = testNodes[i].second; + node.node = testNodes[i].first.pub(); + out.nodes.push_back(node); + } + + out.sign(k.sec()); + BOOST_REQUIRE_LE(out.data.size(), 1280); + } +} + BOOST_AUTO_TEST_CASE(test_neighbours_packet) { KeyPair k = KeyPair::create(); From 7492c9c83334868ecb208b7036d000ae4b6b0462 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 02:59:16 -0400 Subject: [PATCH 053/108] fix typo --- libp2p/NodeTable.cpp | 4 ++-- libp2p/NodeTable.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 6c2253344..1c0883b6a 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -178,7 +178,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrendpoint.udp, _node); p.sign(m_secret); - m_findNodeTimout.push_back(make_pair(_node, chrono::steady_clock::now())); + m_findNodeTimeout.push_back(make_pair(_node, chrono::steady_clock::now())); m_socketPointer->send(p); } @@ -459,7 +459,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case Neighbours::type: { bool expected = false; - m_findNodeTimout.remove_if([&](NodeIdTimePoint const& t) + m_findNodeTimeout.remove_if([&](NodeIdTimePoint const& t) { if (t.first == nodeid && chrono::steady_clock::now() - t.second < c_reqTimeout) expected = true; diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index fe8f87a66..bd7d121f4 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -273,7 +273,7 @@ private: std::map m_pubkDiscoverPings; ///< List of pending pings where node entry wasn't created due to unkown pubk. Mutex x_findNodeTimeout; - std::list m_findNodeTimout; ///< Timeouts for pending Ping and FindNode requests. + std::list m_findNodeTimeout; ///< Timeouts for pending Ping and FindNode requests. ba::io_service& m_io; ///< Used by bucket refresh timer. std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. From 7c3a920e1d1c7ea8ac58d8d27430f391d1b48878 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 09:39:00 +0200 Subject: [PATCH 054/108] Various threading fixes. --- CMakeLists.txt | 9 +++++++++ alethzero/CMakeLists.txt | 2 +- alethzero/Transact.cpp | 4 ++-- exp/main.cpp | 28 ++++++++++++++++++++++++++-- libdevcore/Worker.cpp | 4 ++-- libethcore/Miner.h | 31 ++++++++++++++++++------------- libethereum/Client.cpp | 34 ++++++++++++++++++++++++++++++---- libethereum/Client.h | 9 ++++++--- libethereum/Farm.h | 33 ++++++++++++--------------------- 9 files changed, 106 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6a906b59..25b7dcb50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,6 +244,15 @@ elseif (BUNDLE STREQUAL "full") set(TOOLS ON) set(TESTS ON) set(FATDB ON) +elseif (BUNDLE STREQUAL "core") + set(SERPENT OFF) + set(SOLIDITY ON) + set(USENPM OFF) + set(GUI ON) + set(NCURSES OFF) + set(TOOLS ON) + set(TESTS OFF) + set(FATDB ON) elseif (BUNDLE STREQUAL "tests") set(SERPENT ${DECENT_PLATFORM}) set(SOLIDITY ON) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index c81c86222..b60bca425 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -59,7 +59,7 @@ target_link_libraries(${EXECUTABLE} jsqrc) target_link_libraries(${EXECUTABLE} natspec) target_link_libraries(${EXECUTABLE} ${MHD_LIBRARIES}) -if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")) +if (SERPENT) target_link_libraries(${EXECUTABLE} serpent) endif() diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index f1f7477fe..1ebdf9e23 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -37,7 +37,7 @@ #include #include #include -#ifndef _MSC_VER +#if ETH_SERPENT #include #include #endif @@ -220,7 +220,7 @@ static tuple, bytes, string> userInputToCode(string const& _user, errors.push_back("Solidity: Uncaught exception"); } } -#ifndef _MSC_VER +#if ETH_SERPENT else if (sourceIsSerpent(_user)) { try diff --git a/exp/main.cpp b/exp/main.cpp index 54b75d0e2..20f287f43 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -153,7 +154,7 @@ int main() return 0; } -#else +#elif 0 void mine(State& s, BlockChain const& _bc) { @@ -169,7 +170,7 @@ void mine(State& s, BlockChain const& _bc) while (!completed) this_thread::sleep_for(chrono::milliseconds(20)); } - +#elif 0 int main() { cnote << "Testing State..."; @@ -224,5 +225,28 @@ int main() return 0; } +#else +int main() +{ + string tempDir = boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count()); + + KeyPair myMiner = sha3("Gav's Miner"); + + p2p::Host net("Test"); + cdebug << "Path:" << tempDir; + Client c(&net, tempDir); + + c.setAddress(myMiner.address()); + + this_thread::sleep_for(chrono::milliseconds(1000)); + + c.startMining(); + + this_thread::sleep_for(chrono::milliseconds(6000)); + + c.stopMining(); + + return 0; +} #endif diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 65e8efcbb..8c1fbb9c7 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -29,7 +29,7 @@ using namespace dev; void Worker::startWorking(IfRunning _ir) { - cnote << "startWorking for thread" << m_name; +// cnote << "startWorking for thread" << m_name; Guard l(x_work); if (m_work && m_work->joinable()) @@ -56,7 +56,7 @@ void Worker::startWorking(IfRunning _ir) void Worker::stopWorking() { - cnote << "stopWorking for thread" << m_name; +// cnote << "stopWorking for thread" << m_name; Guard l(x_work); if (!m_work || !m_work->joinable()) return; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index a048b0238..51a0ff6f6 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -73,11 +73,12 @@ public: * @param _finder The miner that found it. * @return true iff the solution was good (implying that mining should be . */ - virtual bool submitProof(Solution const& _p, WorkPackage& io_wp, Miner* _finder) = 0; + virtual bool submitProof(Solution const& _p, Miner* _finder) = 0; }; /** * @brief A miner - a member and adoptee of the Farm. + * @warning Not threadsafe. It is assumed Farm will synchronise calls to/from this class. */ template class GenericMiner { @@ -96,15 +97,17 @@ public: void setWork(WorkPackage const& _work = WorkPackage()) { - Guard l(x_work); auto old = m_work; - m_work = _work; - if (!!m_work) + { + Guard l(x_work); + m_work = _work; + } + if (!!_work) { pause(); kickOff(); } - else if (!m_work && !!old) + else if (!_work && !!old) pause(); m_hashCount = 0; } @@ -137,16 +140,18 @@ protected: */ bool submitProof(Solution const& _s) { - if (m_farm) + if (!m_farm) + return true; + if (m_farm->submitProof(_s, this)) { - if (!m_farm->submitProof(_s, m_work, this)) - return false; + Guard l(x_work); + m_work.reset(); return true; } - return true; + return false; } - WorkPackage const& work() const { return m_work; } + WorkPackage const& work() const { Guard l(x_work); return m_work; } void accumulateHashes(unsigned _n) { m_hashCount += _n; } @@ -154,10 +159,10 @@ private: FarmFace* m_farm = nullptr; unsigned m_index; - Mutex x_work; - WorkPackage m_work; - uint64_t m_hashCount = 0; + + WorkPackage m_work; + mutable Mutex x_work; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 17fb0bf0d..54fed6b01 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -192,6 +192,27 @@ bool Client::isSyncing() const return false; } +void Client::startedWorking() +{ + // Synchronise the state according to the head of the block chain. + // TODO: currently it contains keys for *all* blocks. Make it remove old ones. + cdebug << "startedWorking()"; + WriteGuard l(x_stateDB); + + cdebug << m_bc.number() << m_bc.currentHash(); + + cdebug << "Pre:" << m_preMine.info(); + cdebug << "Post:" << m_postMine.info(); + cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); + + m_preMine.sync(m_bc); + m_postMine = m_preMine; + + cdebug << "Pre:" << m_preMine.info(); + cdebug << "Post:" << m_postMine.info(); + cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); +} + void Client::doneWorking() { // Synchronise the state according to the head of the block chain. @@ -403,10 +424,11 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) return false; newBlock = m_postMine.blockData(); } - + m_bq.import(&newBlock, m_bc); +/* ImportRoute ir = m_bc.attemptImport(newBlock, m_stateDB); if (!ir.first.empty()) - onChainChanged(ir); + onChainChanged(ir);*/ return true; } @@ -500,9 +522,9 @@ void Client::onChainChanged(ImportRoute const& _ir) m_postMine = m_preMine; changeds.insert(PendingChangedFilter); - x_stateDB.unlock(); + x_stateDB.unlock_shared(); onPostStateChanged(); - x_stateDB.lock(); + x_stateDB.lock_shared(); } } @@ -514,8 +536,12 @@ void Client::onPostStateChanged() cnote << "Post state changed: Restarting mining..."; { WriteGuard l(x_stateDB); + cdebug << "Pre:" << m_preMine.info(); m_postMine.commitToMine(m_bc); m_miningInfo = m_postMine.info(); + cdebug << "Pre:" << m_preMine.info(); + cdebug << "Post:" << m_postMine.info(); + cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); } m_farm.setWork(m_miningInfo); diff --git a/libethereum/Client.h b/libethereum/Client.h index 2235c4459..16033a11f 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -169,7 +169,7 @@ public: /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread - void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); } + void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); onPostStateChanged(); } /// Stop mining. /// NOT thread-safe void stopMining() override { m_farm.stop(); } @@ -229,11 +229,14 @@ protected: void noteChanged(h256Set const& _filters); private: + /// Called when Worker is starting. + void startedWorking() override; + /// Do some work. Handles blockchain maintenance and mining. - virtual void doWork(); + void doWork() override; /// Called when Worker is exiting. - virtual void doneWorking(); + void doneWorking() override; /// Magically called when the chain has changed. An import route is provided. /// Called by either submitWork() or in our main thread through syncBlockQueue(). diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 56bbcb9df..afca853ed 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -61,8 +61,7 @@ public: */ void setWork(BlockInfo const& _bi) { - WriteGuard l(x_work); - ReadGuard l2(x_miners); + WriteGuard l(x_minerWork); m_header = _bi; auto p = PoW::package(m_header); if (p.headerHash == m_work.headerHash) @@ -90,14 +89,14 @@ public: */ void stop() { - WriteGuard l(x_miners); + WriteGuard l(x_minerWork); m_miners.clear(); + m_work.reset(); } bool isMining() const { - ReadGuard l(x_miners); - return !m_miners.empty(); + return !!m_work; } /** @@ -109,7 +108,7 @@ public: MiningProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { - ReadGuard l2(x_miners); + ReadGuard l2(x_minerWork); for (auto const& i: m_miners) p.hashes += i->hashCount(); } @@ -127,7 +126,7 @@ public: */ void onSolutionFound(SolutionFound const& _handler) { m_onSolutionFound = _handler; } - WorkPackage work() const { ReadGuard l(x_work); return m_work; } + WorkPackage work() const { ReadGuard l(x_minerWork); return m_work; } private: /** @@ -136,19 +135,14 @@ private: * @param _wp The WorkPackage that the Solution is for. * @return true iff the solution was good (implying that mining should be . */ - bool submitProof(Solution const& _s, WorkPackage& _wp, Miner* _m) override + bool submitProof(Solution const& _s, Miner* _m) override { - ReadGuard l(x_work); - if (_wp.headerHash != m_work.headerHash) - return false; - if (m_onSolutionFound && m_onSolutionFound(_s)) { - ReadGuard l(x_miners); + WriteGuard ul(x_minerWork); for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->setWork(); - _wp.reset(); m_work.reset(); return true; } @@ -161,8 +155,7 @@ private: template bool start() { - ReadGuard l(x_work); - WriteGuard l2(x_miners); + WriteGuard l(x_minerWork); if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) return true; m_miners.clear(); @@ -181,17 +174,15 @@ private: m_lastStart = std::chrono::steady_clock::now(); } - mutable SharedMutex x_miners; + mutable SharedMutex x_minerWork; std::vector> m_miners; + WorkPackage m_work; + BlockInfo m_header; mutable SharedMutex x_progress; mutable MiningProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; - mutable SharedMutex x_work; - WorkPackage m_work; - BlockInfo m_header; - SolutionFound m_onSolutionFound; }; From 4586d94be44ba7f6b08194643b1a46912444fce3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 09:44:22 +0200 Subject: [PATCH 055/108] Nicities for caktux :-) --- eth/main.cpp | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index e9af192f9..08f4b1de4 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -139,13 +139,11 @@ void help() << " -R,--rebuild First rebuild the blockchain from the existing database." << endl << " -r,--remote Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl + << " -S,--temporary-secret Set the secret key for use with send command, for this session only." << endl << " -t,--miners Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl << " -V,--version Show the version and exit." << endl -#if ETH_EVMJIT - << " --jit Use EVM JIT (default: off)." << endl -#endif ; exit(0); } @@ -273,8 +271,9 @@ int main(int argc, char** argv) unsigned mining = ~(unsigned)0; int miners = -1; bool forceMining = false; - KeyPair us = KeyPair::create(); - Address coinbase = us.address(); + KeyPair sigKey = KeyPair::create(); + Secret sessionSecret; + Address coinbase = sigKey.address(); /// Structured logging params bool structuredLogging = false; @@ -290,7 +289,7 @@ int main(int argc, char** argv) if (b.size()) { RLP config(b); - us = KeyPair(config[0].toHash()); + sigKey = KeyPair(config[0].toHash()); coinbase = config[1].toHash
(); } @@ -373,7 +372,9 @@ int main(int argc, char** argv) return -1; } else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) - us = KeyPair(h256(fromHex(argv[++i]))); + sigKey = KeyPair(h256(fromHex(argv[++i]))); + else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc) + sessionSecret = h256(fromHex(argv[++i])); else if (arg == "--structured-logging-format" && i + 1 < argc) structuredLoggingFormat = string(argv[++i]); else if (arg == "--structured-logging") @@ -514,10 +515,13 @@ int main(int argc, char** argv) { RLPStream config(2); - config << us.secret() << coinbase; + config << sigKey.secret() << coinbase; writeFile(configFile, config.out()); } + if (sessionSecret) + sigKey = KeyPair(sessionSecret); + // Two codepaths is necessary since named block require database, but numbered // blocks are superuseful to have when database is already open in another process. if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock)) @@ -632,7 +636,7 @@ int main(int argc, char** argv) c->setAddress(coinbase); } - cout << "Transaction Signer: " << us.address() << endl; + cout << "Transaction Signer: " << sigKey.address() << endl; cout << "Mining Benefactor: " << coinbase << endl; web3.startNetwork(); @@ -647,8 +651,7 @@ int main(int argc, char** argv) if (jsonrpc > -1) { jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); - jsonrpcServer->setIdentities({us}); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({sigKey}))); jsonrpcServer->StartListening(); } #endif @@ -772,8 +775,7 @@ int main(int argc, char** argv) if (jsonrpc < 0) jsonrpc = SensibleHttpPort; jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); - jsonrpcServer->setIdentities({us}); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({sigKey}))); jsonrpcServer->StartListening(); } else if (cmd == "jsonstop") @@ -785,12 +787,11 @@ int main(int argc, char** argv) #endif else if (cmd == "address") { - cout << "Current address:" << endl - << toHex(us.address().asArray()) << endl; + cout << "Current address:" << endl << sigKey.address() << endl; } else if (cmd == "secret") { - cout << "Secret Key: " << toHex(us.secret().asArray()) << endl; + cout << "Secret Key: " << sigKey.secret() << endl; } else if (c && cmd == "block") { @@ -805,7 +806,7 @@ int main(int argc, char** argv) } else if (c && cmd == "balance") { - cout << "Current balance: " << formatBalance( c->balanceAt(us.address())) << " = " <balanceAt(us.address()) << " wei" << endl; + cout << "Current balance: " << formatBalance( c->balanceAt(sigKey.address())) << " = " <balanceAt(sigKey.address()) << " wei" << endl; } else if (c && cmd == "transact") { @@ -921,7 +922,7 @@ int main(int argc, char** argv) try { Address dest = h160(fromHex(hexAddr, WhenError::Throw)); - c->submitTransaction(us.secret(), amount, dest, bytes(), minGas); + c->submitTransaction(sigKey.secret(), amount, dest, bytes(), minGas); } catch (BadHexCharacter& _e) { @@ -990,7 +991,7 @@ int main(int argc, char** argv) else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else - c->submitTransaction(us.secret(), endowment, init, gas, gasPrice); + c->submitTransaction(sigKey.secret(), endowment, init, gas, gasPrice); } else cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX"; @@ -1107,7 +1108,7 @@ int main(int argc, char** argv) { string hexSec; iss >> hexSec; - us = KeyPair(h256(fromHex(hexSec))); + sigKey = KeyPair(h256(fromHex(hexSec))); } else cwarn << "Require parameter: setSecret HEXSECRETKEY"; @@ -1147,7 +1148,7 @@ int main(int argc, char** argv) string path; iss >> path; RLPStream config(2); - config << us.secret() << coinbase; + config << sigKey.secret() << coinbase; writeFile(path, config.out()); } else @@ -1163,7 +1164,7 @@ int main(int argc, char** argv) if (b.size()) { RLP config(b); - us = KeyPair(config[0].toHash()); + sigKey = KeyPair(config[0].toHash()); coinbase = config[1].toHash
(); } else From cfd8274097952bd4490f2fdeef0d8d97f2fc5820 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 10:18:34 +0200 Subject: [PATCH 056/108] AlethZero fixes. --- eth/main.cpp | 45 ++++++++++++++++++++-------------------- libethcore/BlockInfo.cpp | 9 ++++++-- libethcore/BlockInfo.h | 1 + libethcore/EthashAux.cpp | 29 +++++++++++++++++++++++--- libethcore/EthashAux.h | 4 +++- 5 files changed, 60 insertions(+), 28 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 0ac53fab5..24bf839aa 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -142,12 +142,10 @@ void help() << " -R,--rebuild First rebuild the blockchain from the existing database." << endl << " -r,--remote Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl + << " -S,--temporary-secret Set the secret key for use with send command, for this session only." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl << " -V,--version Show the version and exit." << endl -#if ETH_EVMJIT - << " --jit Use EVM JIT (default: off)." << endl -#endif ; exit(0); } @@ -274,8 +272,9 @@ int main(int argc, char** argv) /// Mining params unsigned mining = ~(unsigned)0; bool forceMining = false; - KeyPair us = KeyPair::create(); - Address coinbase = us.address(); + KeyPair sigKey = KeyPair::create(); + Secret sessionSecret; + Address coinbase = sigKey.address(); /// Structured logging params bool structuredLogging = false; @@ -291,7 +290,7 @@ int main(int argc, char** argv) if (b.size()) { RLP config(b); - us = KeyPair(config[0].toHash()); + sigKey = KeyPair(config[0].toHash()); coinbase = config[1].toHash
(); } @@ -374,7 +373,9 @@ int main(int argc, char** argv) return -1; } else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) - us = KeyPair(h256(fromHex(argv[++i]))); + sigKey = KeyPair(h256(fromHex(argv[++i]))); + else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc) + sessionSecret = h256(fromHex(argv[++i])); else if (arg == "--structured-logging-format" && i + 1 < argc) structuredLoggingFormat = string(argv[++i]); else if (arg == "--structured-logging") @@ -510,10 +511,13 @@ int main(int argc, char** argv) { RLPStream config(2); - config << us.secret() << coinbase; + config << sigKey.secret() << coinbase; writeFile(configFile, config.out()); } + if (sessionSecret) + sigKey = KeyPair(sessionSecret); + // Two codepaths is necessary since named block require database, but numbered // blocks are superuseful to have when database is already open in another process. if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock)) @@ -626,7 +630,7 @@ int main(int argc, char** argv) c->setAddress(coinbase); } - cout << "Transaction Signer: " << us.address() << endl; + cout << "Transaction Signer: " << sigKey.address() << endl; cout << "Mining Benefactor: " << coinbase << endl; web3.startNetwork(); @@ -641,8 +645,7 @@ int main(int argc, char** argv) if (jsonrpc > -1) { jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); - jsonrpcServer->setIdentities({us}); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({sigKey}))); jsonrpcServer->StartListening(); } #endif @@ -766,8 +769,7 @@ int main(int argc, char** argv) if (jsonrpc < 0) jsonrpc = SensibleHttpPort; jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); - jsonrpcServer->setIdentities({us}); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({sigKey}))); jsonrpcServer->StartListening(); } else if (cmd == "jsonstop") @@ -779,12 +781,11 @@ int main(int argc, char** argv) #endif else if (cmd == "address") { - cout << "Current address:" << endl - << toHex(us.address().asArray()) << endl; + cout << "Current address:" << endl << sigKey.address() << endl; } else if (cmd == "secret") { - cout << "Secret Key: " << toHex(us.secret().asArray()) << endl; + cout << "Secret Key: " << sigKey.secret() << endl; } else if (c && cmd == "block") { @@ -799,7 +800,7 @@ int main(int argc, char** argv) } else if (c && cmd == "balance") { - cout << "Current balance: " << formatBalance( c->balanceAt(us.address())) << " = " <balanceAt(us.address()) << " wei" << endl; + cout << "Current balance: " << formatBalance( c->balanceAt(sigKey.address())) << " = " <balanceAt(sigKey.address()) << " wei" << endl; } else if (c && cmd == "transact") { @@ -915,7 +916,7 @@ int main(int argc, char** argv) try { Address dest = h160(fromHex(hexAddr, WhenError::Throw)); - c->submitTransaction(us.secret(), amount, dest, bytes(), minGas); + c->submitTransaction(sigKey.secret(), amount, dest, bytes(), minGas); } catch (BadHexCharacter& _e) { @@ -984,7 +985,7 @@ int main(int argc, char** argv) else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else - c->submitTransaction(us.secret(), endowment, init, gas, gasPrice); + c->submitTransaction(sigKey.secret(), endowment, init, gas, gasPrice); } else cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX"; @@ -1101,7 +1102,7 @@ int main(int argc, char** argv) { string hexSec; iss >> hexSec; - us = KeyPair(h256(fromHex(hexSec))); + sigKey = KeyPair(h256(fromHex(hexSec))); } else cwarn << "Require parameter: setSecret HEXSECRETKEY"; @@ -1141,7 +1142,7 @@ int main(int argc, char** argv) string path; iss >> path; RLPStream config(2); - config << us.secret() << coinbase; + config << sigKey.secret() << coinbase; writeFile(path, config.out()); } else @@ -1157,7 +1158,7 @@ int main(int argc, char** argv) if (b.size()) { RLP config(b); - us = KeyPair(config[0].toHash()); + sigKey = KeyPair(config[0].toHash()); coinbase = config[1].toHash
(); } else diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 6cd431931..b45bdc57e 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -23,6 +23,7 @@ #include #include #include +#include "EthashAux.h" #include "ProofOfWork.h" #include "Exceptions.h" #include "Params.h" @@ -63,8 +64,7 @@ void BlockInfo::clear() h256 const& BlockInfo::seedHash() const { if (!m_seedHash) - for (u256 n = number; n >= c_epochDuration; n -= c_epochDuration) - m_seedHash = sha3(m_seedHash); + m_seedHash = EthashAux::seedHash((unsigned)number); return m_seedHash; } @@ -145,9 +145,14 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const throw; } + if (number > ~(unsigned)0) + throw InvalidNumber(); + // check it hashes according to proof of work or that it's the genesis block. if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty)); + else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) + BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty)); if (_s != CheckNothing) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index dffff73f4..79c12ebb4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -39,6 +39,7 @@ enum IncludeNonce enum Strictness { CheckEverything, + QuickNonce, IgnoreNonce, CheckNothing }; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 969310dac..fb4c2820d 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,24 +63,47 @@ ethash_params EthashAux::params(unsigned _n) return p; } +h256 EthashAux::seedHash(unsigned _number) +{ + unsigned epoch = _number / ETHASH_EPOCH_LENGTH; + RecursiveGuard l(get()->x_this); + if (_number < get()->m_seedHashes.size()) + return get()->m_seedHashes[_number]; + h256 ret; + unsigned n = 0; + if (!get()->m_seedHashes.empty()) + { + ret = get()->m_seedHashes.back(); + n = get()->m_seedHashes.size() - 1; + } + cdebug << "Searching for seedHash of epoch " << epoch; + for (; n < epoch; ++n, ret = sha3(ret)) + cdebug << "Epoch" << n << "is" << ret.abridged(); + return ret; +} + ethash_params EthashAux::params(h256 const& _seedHash) { RecursiveGuard l(get()->x_this); unsigned epoch = 0; try { - epoch = get()->m_seedHashes.at(_seedHash); + epoch = get()->m_epochs.at(_seedHash); } catch (...) { - for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = h256(h)) {} + cdebug << "Searching for seedHash " << _seedHash.abridged(); + for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h)) + { + cdebug << "Epoch" << epoch << "is" << h.abridged(); + } if (epoch == 2048) { std::ostringstream error; error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048); throw std::invalid_argument(error.str()); } - get()->m_seedHashes[_seedHash] = epoch; + get()->m_epochs[_seedHash] = epoch; } return params(epoch * ETHASH_EPOCH_LENGTH); } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index aec1089a2..94c2243e0 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -36,6 +36,7 @@ public: using LightType = void const*; using FullType = void const*; + static h256 seedHash(unsigned _number); static ethash_params params(BlockInfo const& _header); static ethash_params params(h256 const& _seedHash); static ethash_params params(unsigned _n); @@ -58,7 +59,8 @@ private: std::map m_lights; std::map m_fulls; - std::map m_seedHashes; + std::map m_epochs; + h256s m_seedHashes; }; } From 1b05e078e48bf9b6eb64218d956f9b07c0b55bd3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 10:37:11 +0200 Subject: [PATCH 057/108] Marginally better Client async code. --- libethereum/Client.cpp | 14 ++++---------- libethereum/Client.h | 9 ++++----- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 54fed6b01..c99b13425 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -571,19 +571,13 @@ void Client::doWork() { // TODO: Use condition variable rather than this rubbish. - Guard l(x_fakeSignalSystemState); - - if (m_syncTransactionQueue) - { - m_syncTransactionQueue = false; + bool t = true; + if (m_syncTransactionQueue.compare_exchange_strong(t, false)) syncTransactionQueue(); - } - if (m_syncBlockQueue) - { - m_syncBlockQueue = false; + t = true; + if (m_syncBlockQueue.compare_exchange_strong(t, false)) syncBlockQueue(); - } checkWatchGarbage(); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16033a11f..289df3fe0 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -249,10 +249,10 @@ private: void syncTransactionQueue(); /// Magically called when m_tq needs syncing. Be nice and don't block. - void onTransactionQueueReady() { Guard l(x_fakeSignalSystemState); m_syncTransactionQueue = true; } + void onTransactionQueueReady() { m_syncTransactionQueue = true; } /// Magically called when m_tq needs syncing. Be nice and don't block. - void onBlockQueueReady() { Guard l(x_fakeSignalSystemState); m_syncBlockQueue = true; } + void onBlockQueueReady() { m_syncBlockQueue = true; } /// Called when the post state has changed (i.e. when more transactions are in it or we're mining on a new block). /// This updates m_miningInfo. @@ -286,9 +286,8 @@ private: ///< When did we last both doing GC on the watches? // TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables) - mutable Mutex x_fakeSignalSystemState; - bool m_syncTransactionQueue = false; - bool m_syncBlockQueue = false; + std::atomic m_syncTransactionQueue = {false}; + std::atomic m_syncBlockQueue = {false}; }; } From 6c4cbaaae75c296e4c4d06b76145015e914b2879 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 14 Apr 2015 11:11:04 +0200 Subject: [PATCH 058/108] option in StateDialog.qml to select the coinbase address. --- mix/ClientModel.cpp | 15 ++++++++----- mix/ClientModel.h | 8 ++++--- mix/MixClient.cpp | 4 ++-- mix/MixClient.h | 2 +- mix/qml/StateDialog.qml | 44 +++++++++++++++++++++++++++++++++++--- mix/qml/StateListModel.qml | 15 ++++++++----- 6 files changed, 69 insertions(+), 19 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 29d4556ce..85142e242 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -134,12 +134,17 @@ void ClientModel::mine() }); } -QString ClientModel::newAddress() +QString ClientModel::newSecret() { KeyPair a = KeyPair::create(); return QString::fromStdString(toHex(a.secret().ref())); } +QString ClientModel::address(QString const& _secret) +{ + return QString::fromStdString(toHex(KeyPair(Secret(_secret.toStdString())).address().ref())); +} + QString ClientModel::encodeAbiString(QString _string) { ContractCallDataEncoder encoder; @@ -210,10 +215,10 @@ void ClientModel::setupState(QVariantMap _state) transactionSequence.push_back(transactionSettings); } } - executeSequence(transactionSequence, accounts); + executeSequence(transactionSequence, accounts, Secret(_state.value("miner").toMap().value("secret").toString().toStdString())); } -void ClientModel::executeSequence(vector const& _sequence, map const& _balances) +void ClientModel::executeSequence(vector const& _sequence, map const& _balances, Secret const& _miner) { if (m_running) BOOST_THROW_EXCEPTION(ExecutionStateException()); @@ -223,8 +228,8 @@ void ClientModel::executeSequence(vector const& _sequence, emit runStateChanged(); //m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_client->userAccounts(), m_client.get())); - m_client->resetState(_balances); - m_web3Server.setAccounts(m_client->userAccounts()); + m_client->resetState(_balances, _miner); + m_web3Server->setAccounts(m_client->userAccounts()); //run sequence m_runFuture = QtConcurrent::run([=]() { diff --git a/mix/ClientModel.h b/mix/ClientModel.h index ddc0e6cf1..dcb62f55d 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -162,8 +162,10 @@ public slots: Q_INVOKABLE void debugRecord(unsigned _index); /// Show the debugger for an empty record Q_INVOKABLE void emptyRecord(); - /// Generate new adress - Q_INVOKABLE QString newAddress(); + /// Generate new secret + Q_INVOKABLE QString newSecret(); + /// retrieve the address of @arg _secret + Q_INVOKABLE QString address(QString const& _secret); /// Encode a string to ABI parameter. Returns a hex string Q_INVOKABLE QString encodeAbiString(QString _string); @@ -207,7 +209,7 @@ private: RecordLogEntry* lastBlock() const; QVariantMap contractAddresses() const; QVariantMap gasCosts() const; - void executeSequence(std::vector const& _sequence, std::map const& _balances); + void executeSequence(std::vector const& _sequence, std::map const& _balances, Secret const& _miner); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void onNewTransaction(); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index dd7047d26..5c905ef0b 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -67,7 +67,7 @@ MixClient::~MixClient() { } -void MixClient::resetState(std::map _accounts) +void MixClient::resetState(std::map _accounts, Secret _miner) { WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,7 +91,7 @@ void MixClient::resetState(std::map _accounts) h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, genesisState.begin()->first); + m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); m_state.sync(bc()); m_startState = m_state; WriteGuard lx(x_executions); diff --git a/mix/MixClient.h b/mix/MixClient.h index a9ab30048..93a674d96 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -48,7 +48,7 @@ public: MixClient(std::string const& _dbPath); virtual ~MixClient(); /// Reset state to the empty state with given balance. - void resetState(std::map _accounts); + void resetState(std::map _accounts, Secret _miner = Secret()); void mine(); ExecutionResult lastExecution() const; ExecutionResult execution(unsigned _index) const; diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 2d07e4b31..d609808ea 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -14,7 +14,7 @@ Dialog { modality: Qt.ApplicationModal width: 630 - height: 480 + height: 500 title: qsTr("Edit State") visible: false @@ -45,16 +45,22 @@ Dialog { accountsModel.clear(); stateAccounts = []; + var miner = 0; + for (var k = 0; k < item.accounts.length; k++) { accountsModel.append(item.accounts[k]); stateAccounts.push(item.accounts[k]); + if (item.accounts[k].name === item.miner.name) + miner = k; } visible = true; isDefault = setDefault; titleField.focus = true; defaultCheckBox.enabled = !isDefault; + comboMiner.model = stateAccounts; + comboMiner.currentIndex = miner; forceActiveFocus(); } @@ -75,6 +81,14 @@ Dialog { } item.transactions = stateTransactions; item.accounts = stateAccounts; + for (var k = 0; k < stateAccounts.length; k++) + { + if (stateAccounts[k].name === comboMiner.currentText) + { + item.miner = stateAccounts[k]; + break; + } + } return item; } contentItem: Rectangle { @@ -159,7 +173,7 @@ Dialog { TableViewColumn { role: "name" title: qsTr("Name") - width: 150 + width: 230 delegate: Item { RowLayout { @@ -190,7 +204,12 @@ Dialog { anchors.verticalCenter: parent.verticalCenter onTextChanged: { if (styleData.row > -1) - stateAccounts[styleData.row].name = text; + { + stateAccounts[styleData.row].name = text + var index = comboMiner.currentIndex; + comboMiner.model = stateAccounts; + comboMiner.currentIndex = index; + } } text: { return styleData.value @@ -226,6 +245,25 @@ Dialog { Layout.fillWidth: true } + RowLayout + { + Layout.fillWidth: true + DefaultLabel { + Layout.preferredWidth: 85 + text: qsTr("Miner") + } + ComboBox { + id: comboMiner + textRole: "name" + Layout.fillWidth: true + } + } + + CommonSeparator + { + Layout.fillWidth: true + } + RowLayout { Layout.fillWidth: true diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index a0cb25eb3..fbb384caf 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -21,7 +21,8 @@ Item { return { title: s.title, transactions: s.transactions.map(fromPlainTransactionItem), - accounts: s.accounts.map(fromPlainAccountItem) + accounts: s.accounts.map(fromPlainAccountItem), + miner: s.miner }; } @@ -37,6 +38,7 @@ Item { function fromPlainTransactionItem(t) { if (!t.sender) t.sender = defaultAccount; //support for old project + var r = { contractId: t.contractId, functionId: t.functionId, @@ -59,7 +61,8 @@ Item { return { title: s.title, transactions: s.transactions.map(toPlainTransactionItem), - accounts: s.accounts.map(toPlainAccountItem) + accounts: s.accounts.map(toPlainAccountItem), + miner: s.miner }; } @@ -81,7 +84,7 @@ Item { balance: { value: t.balance.value, unit: t.balance.unit - } + }, }; } @@ -95,6 +98,7 @@ Item { gasAuto: t.gasAuto, gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit }, stdContract: t.stdContract, + sender: t.sender, parameters: {} }; for (var key in t.parameters) @@ -176,8 +180,9 @@ Item { function newAccount(_balance, _unit, _secret) { if (!_secret) - _secret = clientModel.newAddress(); - var name = qsTr("Account") + "-" + _secret.substring(0, 4); + _secret = clientModel.newSecret(); + var address = clientModel.address(_secret); + var name = qsTr("Account") + "-" + address.substring(0, 4); return { name: name, secret: _secret, balance: QEtherHelper.createEther(_balance, _unit) }; } From fbcf1f1a2ed7754dbd862aecfaabd9b586f20038 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 14 Apr 2015 11:21:53 +0200 Subject: [PATCH 059/108] small changes --- mix/ClientModel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 85142e242..2119729fb 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -227,7 +227,6 @@ void ClientModel::executeSequence(vector const& _sequence, emit runStarted(); emit runStateChanged(); - //m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_client->userAccounts(), m_client.get())); m_client->resetState(_balances, _miner); m_web3Server->setAccounts(m_client->userAccounts()); //run sequence From 48dd9f3482cb9ab89ad261ef56aae8cbac430b4d Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 14 Apr 2015 11:54:28 +0200 Subject: [PATCH 060/108] replaced Aversion with ImportRequirements --- libethcore/Common.h | 6 +++--- libethereum/BlockChain.cpp | 10 +++++----- libethereum/BlockChain.h | 10 ++-------- libethereum/State.cpp | 2 +- mix/MixClient.cpp | 2 +- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 303adc739..12ac55735 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -101,9 +101,9 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, - DontHave = 2, - Default = ValidNonce + ValidNonce = 1, ///< Validate Nonce + DontHave = 2, ///< Avoid old blocks + Default = ValidNonce | DontHave }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 751dafc16..633b5b382 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -240,7 +240,7 @@ void BlockChain::rebuild(std::string const& _path, std::function BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); } -pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force) noexcept +pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept { try { - return import(_block, _stateDB, _force); + return import(_block, _stateDB, _ir); } catch (...) { @@ -347,7 +347,7 @@ pair BlockChain::attemptImport(bytes const& _block, OverlayDB const } } -pair BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force, ImportRequirements::value _ir) +pair BlockChain::import(bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -386,7 +386,7 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, #endif // Check block doesn't already exist first! - if (isKnown(bi.hash()) && _force == Aversion::AvoidOldBlocks) + if (isKnown(bi.hash()) && (_ir & ImportRequirements::DontHave)) { clog(BlockChainNote) << bi.hash() << ": Not new."; BOOST_THROW_EXCEPTION(AlreadyHaveBlock()); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 00f41ab0a..6b6a3ffe2 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -80,12 +80,6 @@ enum { using ProgressCallback = std::function; -enum class Aversion -{ - AvoidOldBlocks, - ImportOldBlocks -}; - /** * @brief Implements the blockchain database. All data this gives is disk-backed. * @threadsafe @@ -108,11 +102,11 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks, ImportRequirements::value _ir = ImportRequirements::Default); + std::pair import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index a4548ce60..73d0d3783 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -542,7 +542,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement { // m_currentBlock is assumed to be prepopulated and reset. - BlockInfo bi(_block, ((_ir & (ImportRequirements::ValidNonce | ImportRequirements::DontHave)) == ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); #if !ETH_RELEASE assert(m_previousBlock.hash() == bi.parentHash); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index c15117d67..e2eac7c20 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -251,7 +251,7 @@ void MixClient::mine() WriteGuard l(x_state); m_state.commitToMine(bc()); m_state.completeMine(); - bc().import(m_state.blockData(), m_stateDB, Aversion::AvoidOldBlocks, ImportRequirements::ValidNonce | ImportRequirements::DontHave); + bc().import(m_state.blockData(), m_stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce); m_state.sync(bc()); m_startState = m_state; h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; From 8e3ef1ee5c1e3ea522a89e64136a9d61d84b7109 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 12:43:00 +0200 Subject: [PATCH 061/108] Fix to ethash seedHash caching. --- alethzero/Main.ui | 6 ++++ alethzero/MainWin.cpp | 5 +++ alethzero/MainWin.h | 1 + eth/main.cpp | 41 +++++++++++++++++++++- libdevcore/Guards.h | 71 ++++++++++++++++++++++++++++++++++++++ libethcore/EthashAux.cpp | 33 +++++++++--------- libethcore/EthashAux.h | 2 +- libethcore/Params.cpp | 1 - libethcore/Params.h | 1 - libethereum/BlockQueue.cpp | 12 +++++++ libethereum/BlockQueue.h | 3 ++ libethereum/Client.cpp | 47 ++++++++++++++----------- libethereum/Client.h | 4 ++- libethereum/Farm.h | 6 +++- 14 files changed, 190 insertions(+), 43 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 3f3d1e237..8e48793c9 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -180,6 +180,7 @@ + @@ -1679,6 +1680,11 @@ font-size: 14pt &GPU Mining + + + Retry Unknown Parent Blocks + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2e4478594..a60875ba6 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1752,6 +1752,11 @@ void Main::on_clearPending_triggered() refreshAll(); } +void Main::on_retryUnknown_triggered() +{ + ethereum()->retryUnkonwn(); +} + void Main::on_killBlockchain_triggered() { writeSettings(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index a5c74eeaa..a8579ed01 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -163,6 +163,7 @@ private slots: void on_usePrivate_triggered(); void on_turboMining_triggered(); void on_jitvm_triggered(); + void on_retryUnknown_triggered(); // Debugger void on_debugCurrent_triggered(); diff --git a/eth/main.cpp b/eth/main.cpp index 24bf839aa..461494cef 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,11 +32,12 @@ #include #include #include +#include +#include #include #include #include #include -#include #if ETH_READLINE #include #include @@ -111,6 +112,7 @@ void help() << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -B,--block-fees Set the block fee profit in the reference unit e.g. ยข (Default: 15)." << endl << " -c,--client-name Add a name to your client's version string (default: blank)." << endl + << " -C,--check-pow Check PoW credentials for validity." << endl << " -d,--db-path Load database from path (default: ~/.ethereum " << endl << " /Etherum or Library/Application Support/Ethereum)." << endl << " -D,--create-dag Create the DAG in preparation for mining on given block and exit." << endl @@ -401,6 +403,43 @@ int main(int argc, char** argv) return -1; } } + else if ((arg == "-C" || arg == "--check-pow") && i + 4 < argc) + { + string m; + try + { + BlockInfo bi; + m = boost::to_lower_copy(string(argv[++i])); + h256 powHash(m); + m = boost::to_lower_copy(string(argv[++i])); + h256 seedHash; + if (m.size() == 64 || m.size() == 66) + seedHash = h256(m); + else + seedHash = EthashAux::seedHash(stol(m)); + m = boost::to_lower_copy(string(argv[++i])); + bi.difficulty = u256(m); + auto boundary = bi.boundary(); + m = boost::to_lower_copy(string(argv[++i])); + bi.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bool valid = r.value < boundary; + cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; + cout << r.value << (valid ? " < " : " >= ") << boundary << endl; + cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " with seed as " << seedHash << endl; + if (valid) + cout << "(mixHash = " << r.mixHash << ")" << endl; + cout << "SHA3( light(seed) ) = " << sha3(bytesConstRef((byte const*)EthashAux::light(seedHash), EthashAux::params(seedHash).cache_size)) << endl; + exit(0); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << m << endl; + return -1; + } + } else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) { try diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index f5c64b041..4229428ce 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -38,4 +38,75 @@ using UpgradableGuard = boost::upgrade_lock; using UpgradeGuard = boost::upgrade_to_unique_lock; using WriteGuard = boost::unique_lock; +template +struct GenericGuardBool: GuardType +{ + GenericGuardBool(MutexType& _m): GuardType(_m) {} + bool b = true; +}; +template +struct GenericUnguardBool +{ + GenericUnguardBool(MutexType& _m): m(_m) { m.unlock(); } + ~GenericUnguardBool() { m.lock(); } + bool b = true; + MutexType& m; +}; +template +struct GenericUnguardSharedBool +{ + GenericUnguardSharedBool(MutexType& _m): m(_m) { m.unlock_shared(); } + ~GenericUnguardSharedBool() { m.lock_shared(); } + bool b = true; + MutexType& m; +}; + +/** @brief Simple block guard. + * The expression/block following is guarded though the given mutex. + * Usage: + * @code + * Mutex m; + * unsigned d; + * ... + * ETH_GUARDED(m) d = 1; + * ... + * ETH_GUARDED(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; } + * @endcode + * + * There are several variants of this basic mechanism for different Mutex types and Guards. + * + * There is also the UNGUARD variant which allows an unguarded expression/block to exist within a + * guarded expression. eg: + * + * @code + * Mutex m; + * int d; + * ... + * ETH_GUARDED(m) + * { + * for (auto d = 50; d > 25; --d) + * foo(d); + * ETH_UNGUARDED(m) + * bar(); + * for (; d > 0; --d) + * foo(d); + * } + * @endcode + */ + +#define ETH_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_READ_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_WRITE_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_RECURSIVE_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_UNGUARDED(MUTEX) \ + for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_READ_UNGUARDED(MUTEX) \ + for (GenericUnguardSharedBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_WRITE_UNGUARDED(MUTEX) \ + for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) + } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index fb4c2820d..061af566e 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -67,19 +67,24 @@ h256 EthashAux::seedHash(unsigned _number) { unsigned epoch = _number / ETHASH_EPOCH_LENGTH; RecursiveGuard l(get()->x_this); - if (_number < get()->m_seedHashes.size()) - return get()->m_seedHashes[_number]; - h256 ret; - unsigned n = 0; - if (!get()->m_seedHashes.empty()) + if (epoch >= get()->m_seedHashes.size()) { - ret = get()->m_seedHashes.back(); - n = get()->m_seedHashes.size() - 1; + h256 ret; + unsigned n = 0; + if (!get()->m_seedHashes.empty()) + { + ret = get()->m_seedHashes.back(); + n = get()->m_seedHashes.size() - 1; + } + get()->m_seedHashes.resize(epoch + 1); + cdebug << "Searching for seedHash of epoch " << epoch; + for (; n <= epoch; ++n, ret = sha3(ret)) + { + get()->m_seedHashes[n] = ret; + cdebug << "Epoch" << n << "is" << ret.abridged(); + } } - cdebug << "Searching for seedHash of epoch " << epoch; - for (; n < epoch; ++n, ret = sha3(ret)) - cdebug << "Epoch" << n << "is" << ret.abridged(); - return ret; + return get()->m_seedHashes[epoch]; } ethash_params EthashAux::params(h256 const& _seedHash) @@ -93,17 +98,13 @@ ethash_params EthashAux::params(h256 const& _seedHash) catch (...) { cdebug << "Searching for seedHash " << _seedHash.abridged(); - for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h)) - { - cdebug << "Epoch" << epoch << "is" << h.abridged(); - } + for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {} if (epoch == 2048) { std::ostringstream error; error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048); throw std::invalid_argument(error.str()); } - get()->m_epochs[_seedHash] = epoch; } return params(epoch * ETHASH_EPOCH_LENGTH); } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 94c2243e0..c927a012b 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -41,7 +41,7 @@ public: static ethash_params params(h256 const& _seedHash); static ethash_params params(unsigned _n); static LightType light(BlockInfo const& _header); - static LightType light(h256 const& _header); + static LightType light(h256 const& _seedHash); static bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef()); static bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef()); diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp index 029f8b47a..655c8a78b 100644 --- a/libethcore/Params.cpp +++ b/libethcore/Params.cpp @@ -30,7 +30,6 @@ namespace eth //--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json u256 const c_genesisDifficulty = 131072; u256 const c_maximumExtraDataSize = 1024; -u256 const c_epochDuration = 30000; u256 const c_genesisGasLimit = 3141592; u256 const c_minGasLimit = 125000; u256 const c_gasLimitBoundDivisor = 1024; diff --git a/libethcore/Params.h b/libethcore/Params.h index 46b30e2c3..b957f9737 100644 --- a/libethcore/Params.h +++ b/libethcore/Params.h @@ -37,7 +37,6 @@ extern u256 const c_minimumDifficulty; extern u256 const c_difficultyBoundDivisor; extern u256 const c_durationLimit; extern u256 const c_maximumExtraDataSize; -extern u256 const c_epochDuration; extern u256 const c_stackLimit; extern u256 const c_tierStepGas[8]; ///< Once per operation, for a selection of them. diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index e9dd99cd1..b76e4bed6 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -183,3 +183,15 @@ void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) m_unknown.erase(r.first, r.second); } } + +void BlockQueue::retryAllUnknown() +{ + for (auto it = m_unknown.begin(); it != m_unknown.end(); ++it) + { + m_ready.push_back(it->second.second); + auto newReady = it->second.first; + m_unknownSet.erase(newReady); + m_readySet.insert(newReady); + } + m_unknown.clear(); +} diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index f5cdf7ab5..4a503d114 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -71,6 +71,9 @@ public: /// Notify the queue that the chain has changed and a new block has attained 'ready' status (i.e. is in the chain). void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); } + /// Force a retry of all the blocks with unknown parents. + void retryAllUnknown(); + /// Get information on the items queued. std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index c99b13425..0660b6cee 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -436,15 +436,12 @@ void Client::syncBlockQueue() { ImportRoute ir; + cwork << "BQ ==> CHAIN ==> STATE"; { WriteGuard l(x_stateDB); - cwork << "BQ ==> CHAIN ==> STATE"; OverlayDB db = m_stateDB; - x_stateDB.unlock(); - - tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); - - x_stateDB.lock(); + ETH_WRITE_UNGUARDED(x_stateDB) + tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); if (ir.first.empty()) return; m_stateDB = db; @@ -458,7 +455,11 @@ void Client::syncTransactionQueue() cwork << "postSTATE <== TQ"; h256Set changeds; - TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); + TransactionReceipts newPendingReceipts; + + ETH_WRITE_GUARDED(x_stateDB) + newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); + if (newPendingReceipts.size()) { for (size_t i = 0; i < newPendingReceipts.size(); i++) @@ -512,8 +513,7 @@ void Client::onChainChanged(ImportRoute const& _ir) // RESTART MINING // LOCKS REALLY NEEDED? - { - ReadGuard l(x_stateDB); + ETH_WRITE_GUARDED(x_stateDB) if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) { if (isMining()) @@ -522,11 +522,9 @@ void Client::onChainChanged(ImportRoute const& _ir) m_postMine = m_preMine; changeds.insert(PendingChangedFilter); - x_stateDB.unlock_shared(); - onPostStateChanged(); - x_stateDB.lock_shared(); + ETH_WRITE_UNGUARDED(x_stateDB) + onPostStateChanged(); } - } noteChanged(changeds); } @@ -534,17 +532,24 @@ void Client::onChainChanged(ImportRoute const& _ir) void Client::onPostStateChanged() { cnote << "Post state changed: Restarting mining..."; + if (isMining()) { - WriteGuard l(x_stateDB); - cdebug << "Pre:" << m_preMine.info(); - m_postMine.commitToMine(m_bc); - m_miningInfo = m_postMine.info(); - cdebug << "Pre:" << m_preMine.info(); - cdebug << "Post:" << m_postMine.info(); - cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); + { + WriteGuard l(x_stateDB); + m_postMine.commitToMine(m_bc); + m_miningInfo = m_postMine.info(); + } + m_farm.setWork(m_miningInfo); } +} - m_farm.setWork(m_miningInfo); +void Client::startMining() +{ + if (m_turboMining) + m_farm.startGPU(); + else + m_farm.startCPU(); + onPostStateChanged(); } void Client::noteChanged(h256Set const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index 289df3fe0..dedb3bcf1 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -169,7 +169,7 @@ public: /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread - void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); onPostStateChanged(); } + void startMining() override; /// Stop mining. /// NOT thread-safe void stopMining() override { m_farm.stop(); } @@ -202,6 +202,8 @@ public: void clearPending(); /// Kills the blockchain. Just for debug use. void killChain(); + /// Retries all blocks with unknown parents. + void retryUnkonwn() { m_bq.retryAllUnknown(); } protected: /// InterfaceStub methods diff --git a/libethereum/Farm.h b/libethereum/Farm.h index afca853ed..26d4b139e 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -92,11 +92,12 @@ public: WriteGuard l(x_minerWork); m_miners.clear(); m_work.reset(); + m_isMining = false; } bool isMining() const { - return !!m_work; + return m_isMining; } /** @@ -165,6 +166,7 @@ private: m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); m_miners.back()->setWork(m_work); } + m_isMining = true; resetTimer(); return true; } @@ -179,6 +181,8 @@ private: WorkPackage m_work; BlockInfo m_header; + std::atomic m_isMining = {false}; + mutable SharedMutex x_progress; mutable MiningProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; From ecfe6acc95f75a1039a4a8853b767b3b68722e29 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 12:54:03 +0200 Subject: [PATCH 062/108] Version bump. Minor fix. --- libdevcore/Common.cpp | 2 +- libethereum/Client.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index b6e8e7f93..78b3d9c30 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.7"; +char const* Version = "0.9.8"; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 0660b6cee..df6815d9e 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -332,7 +332,8 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed) void Client::setForceMining(bool _enable) { m_forceMining = _enable; - startMining(); + if (isMining()) + startMining(); } MiningProgress Client::miningProgress() const From 6cf2a93e20f4d1e459364543385449c36f17250f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Apr 2015 15:52:36 +0200 Subject: [PATCH 063/108] Some early refactoring to support async miners better. --- exp/main.cpp | 2 +- libethcore/ProofOfWork.cpp | 30 ++++++--- libethcore/ProofOfWork.h | 22 +++---- libethereum/Client.cpp | 2 +- libethereum/Client.h | 4 +- libethereum/ClientBase.h | 2 +- libethereum/Interface.h | 2 +- libethereum/Miner.cpp | 6 +- libethereum/Miner.h | 77 +++++++++++++++++++++++ libethereum/State.cpp | 2 +- libethereum/State.h | 4 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- mix/MixClient.h | 2 +- test/blockchain.cpp | 4 +- 14 files changed, 123 insertions(+), 38 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 48562f80e..88f1075a9 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -114,7 +114,7 @@ int main() BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << (h256)u256((bigint(1) << 256) / genesis.difficulty); - std::pair r; + std::pair r; while (!r.first.completed) r = ecl.mine(genesis, 1000); cdebug << r.second.mixHash << r.second.nonce; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index f7cf4944b..ffa787e3e 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -50,16 +50,16 @@ bool EthashPoW::verify(BlockInfo const& _header) return Ethasher::verify(_header); } -std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) +std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) { Ethasher::Miner m(_header); - std::pair ret; + std::pair ret; auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng)); - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); + h256 boundary = _header.boundary(); ret.first.requirement = log2((double)(u256)boundary); // 2^ 0 32 64 128 256 @@ -68,7 +68,7 @@ std::pair EthashCPU::mine(BlockInfo const& _header, // evaluate until we run out of time auto startTime = std::chrono::steady_clock::now(); double best = 1e99; // high enough to be effectively infinity :) - Proof result; + Solution result; unsigned hashCount = 0; for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) { @@ -128,7 +128,7 @@ struct EthashCLHook: public ethash_cl_miner::search_hook { if (m_aborted) return; - cdebug << "Attempting to abort"; +// cdebug << "Attempting to abort"; m_abort = true; for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) std::this_thread::sleep_for(chrono::milliseconds(30)); @@ -148,14 +148,14 @@ protected: for (unsigned i = 0; i < _count; ++i) m_found.push_back((Nonce)(u64)_nonces[i]); m_aborted = true; - cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); +// cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); return true; } virtual bool searched(uint64_t _startNonce, uint32_t _count) override { Guard l(x_all); - cdebug << "Searched" << _count << "from" << _startNonce; +// cdebug << "Searched" << _count << "from" << _startNonce; m_total += _count; m_last = _startNonce + _count; if (m_abort) @@ -184,7 +184,7 @@ EthashCL::~EthashCL() { } -std::pair EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool) +std::pair EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool) { if (!m_lastHeader || m_lastHeader.seedHash() != _header.seedHash()) { @@ -206,7 +206,14 @@ std::pair EthashCL::mine(BlockInfo const& _header, unsi } m_lastHeader = _header; + MineInfo mi; + Solution proof; + mi.requirement = log2((double)(u256)_header.boundary()); + mi.best = 0; + std::this_thread::sleep_for(chrono::milliseconds(_msTimeout)); + + mi.hashes += m_hook->fetchTotal(); auto found = m_hook->fetchFound(); if (!found.empty()) { @@ -214,10 +221,13 @@ std::pair EthashCL::mine(BlockInfo const& _header, unsi { auto result = Ethasher::eval(_header, n); if (result.value < _header.boundary()) - return std::make_pair(MineInfo(true), EthashCL::Proof{n, result.mixHash}); + { + mi.completed = true; + proof = Solution{n, result.mixHash}; + } } } - return std::make_pair(MineInfo(false), EthashCL::Proof()); + return std::make_pair(mi, proof); } #endif diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 2e04e842c..bd8ab58db 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -54,23 +54,23 @@ struct MineInfo class EthashPoW { public: - struct Proof + struct Solution { Nonce nonce; h256 mixHash; }; static bool verify(BlockInfo const& _header); - static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } virtual unsigned defaultTimeout() const { return 100; } - virtual std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; + virtual std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; }; class EthashCPU: public EthashPoW { public: - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; protected: Nonce m_last; @@ -85,7 +85,7 @@ public: EthashCL(); ~EthashCL(); - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; unsigned defaultTimeout() const override { return 500; } protected: @@ -105,11 +105,11 @@ template class ProofOfWorkEngine: public Evaluator { public: - using Proof = Nonce; + using Solution = Nonce; static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; } - inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); - static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; } + inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); + static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r; } unsigned defaultTimeout() const { return 100; } protected: @@ -127,7 +127,7 @@ using SHA3ProofOfWork = ProofOfWorkEngine; using ProofOfWork = Ethash; template -std::pair::Proof> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) +std::pair::Solution> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) { auto headerHashWithoutNonce = _header.headerHash(WithoutNonce); auto difficulty = _header.difficulty; @@ -145,11 +145,11 @@ std::pair::Proof> ProofOfWorkEng // evaluate until we run out of time auto startTime = std::chrono::steady_clock::now(); double best = 1e99; // high enough to be effectively infinity :) - ProofOfWorkEngine::Proof solution; + ProofOfWorkEngine::Solution solution; unsigned h = 0; for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++) { - solution = (ProofOfWorkEngine::Proof)s; + solution = (ProofOfWorkEngine::Solution)s; auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution); best = std::min(best, log2((double)e)); if (e <= d) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index d8723430d..b2f5ff63c 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -452,7 +452,7 @@ pair Client::getWork() return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty()); } -bool Client::submitWork(ProofOfWork::Proof const& _proof) +bool Client::submitWork(ProofOfWork::Solution const& _proof) { Guard l(x_remoteMiner); return m_remoteMiner.submitWork(_proof); diff --git a/libethereum/Client.h b/libethereum/Client.h index cc51f9747..ec852afd2 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -82,7 +82,7 @@ public: h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); } u256 const& difficulty() const { return m_state.info().difficulty; } - bool submitWork(ProofOfWork::Proof const& _result) { return (m_isComplete = m_state.completeMine(_result)); } + bool submitWork(ProofOfWork::Solution const& _result) { return (m_isComplete = m_state.completeMine(_result)); } virtual bool isComplete() const override { return m_isComplete; } virtual bytes const& blockData() const { return m_state.blockData(); } @@ -216,7 +216,7 @@ public: /// nonce (the 'work hash') and the difficulty to be met. virtual std::pair getWork() override; /// Submit the proof for the proof-of-work. - virtual bool submitWork(ProofOfWork::Proof const& _proof) override; + virtual bool submitWork(ProofOfWork::Solution const& _proof) override; // Debug stuff: diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index ddfbf1176..ae6d27578 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -150,7 +150,7 @@ public: virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::hashrate")); } virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); } virtual std::pair getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); } - virtual bool submitWork(eth::ProofOfWork::Proof const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } + virtual bool submitWork(eth::ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 02833743e..cf2e7f5ea 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -190,7 +190,7 @@ public: /// Get hash of the current block to be mined minus the nonce (the 'work hash'). virtual std::pair getWork() = 0; /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Proof const& _proof) = 0; + virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; /// Check the progress of the mining. virtual MineProgress miningProgress() const = 0; diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp index b3a65f081..dc3d9bd9e 100644 --- a/libethereum/Miner.cpp +++ b/libethereum/Miner.cpp @@ -30,11 +30,9 @@ using namespace dev::eth; Miner::~Miner() {} -LocalMiner::LocalMiner(MinerHost* _host, unsigned _id): - AsyncMiner(_host, _id), - Worker("miner-" + toString(_id)) +LocalMiner::LocalMiner(MinerHost* _host, unsigned _id) { - m_pow.reset(_host->turbo() ? new Ethash : (Ethash*)new EthashCPU); + setup(_host, _id); } void LocalMiner::setup(MinerHost* _host, unsigned _id) diff --git a/libethereum/Miner.h b/libethereum/Miner.h index 8c2fc4bb4..86d103db5 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -36,6 +36,15 @@ namespace dev namespace eth { +struct WorkPackage +{ + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; +}; + +static const WorkPackage NullWorkPackage; + /** * @brief Describes the progress of a mining operation. */ @@ -57,6 +66,10 @@ struct MineProgress class MinerHost { public: + // ============================= NEW API ============================= + virtual WorkPackage const& getWork() const { return NullWorkPackage; } + + // ============================= OLD API ============================= virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. virtual void onProgressed() {} ///< Called once some progress has been made. virtual void onComplete() {} ///< Called once a block is found. @@ -174,5 +187,69 @@ private: std::list m_mineHistory; ///< What the history of our mining? }; +/** + * @brief A collective of Miners. + * Miners ask for work, then submit proofs + * @threadsafe + */ +class Farm: public MinerHost +{ +public: + /** + * @brief Sets the current mining mission. + * @param _bi The block (header) we wish to be mining. + */ + void setWork(BlockInfo const& _bi); + + /** + * @brief (Re)start miners for CPU only. + * @returns true if started properly. + */ + bool startCPU(); + + /** + * @brief (Re)start miners for GPU only. + * @returns true if started properly. + */ + bool startGPU(); + + /** + * @brief Stop all mining activities. + */ + void stop(); + + /** + * @brief Get information on the progress of mining this work package. + * @return The progress with mining so far. + */ + MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } + +protected: + /** + * @brief Called by a Miner to retrieve a work package. Reimplemented from MinerHost. + * @return The work package to solve. + */ + virtual WorkPackage const& getWork() const override { ReadGuard l(x_work); return m_work; } + + /** + * @brief Called from a Miner to note a WorkPackage has a solution. + * @param _p The solution. + * @param _wp The WorkPackage that the Solution is for. + * @return true iff the solution was good (implying that mining should be . + */ + virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; + +private: + mutable SharedMutex x_miners; + std::vector> m_miners; + + mutable SharedMutex x_progress; + MineProgress m_progress; + + mutable SharedMutex x_work; + WorkPackage m_work; +}; + + } } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 6d3301cd7..e77565837 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -856,7 +856,7 @@ void State::commitToMine(BlockChain const& _bc) m_committedToMine = true; } -bool State::completeMine(ProofOfWork::Proof const& _nonce) +bool State::completeMine(ProofOfWork::Solution const& _nonce) { ProofOfWork::assignResult(_nonce, m_currentBlock); diff --git a/libethereum/State.h b/libethereum/State.h index 1b71038b4..b327378a1 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -162,7 +162,7 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff the given nonce is a proof-of-work for this State's block. - bool completeMine(ProofOfWork::Proof const& _result); + bool completeMine(ProofOfWork::Solution const& _result); /// Attempt to find valid nonce for block that this state represents. /// This function is thread-safe. You can safely have other interactions with this object while it is happening. @@ -174,7 +174,7 @@ public: m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); MineInfo ret; - typename ProofOfWork::Proof r; + typename ProofOfWork::Solution r; std::tie(ret, r) = _pow->mine(m_currentBlock, _pow->defaultTimeout(), true); if (!ret.completed) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 5b6c833bc..7e7b83e3c 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -767,7 +767,7 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const& { try { - return client()->submitWork(ProofOfWork::Proof{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); + return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); } catch (...) { diff --git a/mix/MixClient.h b/mix/MixClient.h index 93a674d96..357e22930 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -71,7 +71,7 @@ public: uint64_t hashrate() const override; eth::MineProgress miningProgress() const override; std::pair getWork() override { return std::pair(); } - bool submitWork(eth::ProofOfWork::Proof const&) override { return false; } + bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } virtual void flushTransactions() override {} /// @returns the last mined block information diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 97171e3f2..8f5605898 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -587,7 +587,7 @@ void overwriteBlockHeader(BlockInfo& _currentBlockHeader, mObject& _blObj) _currentBlockHeader = tmp; ProofOfWork pow; - std::pair ret; + std::pair ret; while (!ProofOfWork::verify(_currentBlockHeader)) { ret = pow.mine(_currentBlockHeader, 1000, true); @@ -632,7 +632,7 @@ BlockInfo constructBlock(mObject& _o) void updatePoW(BlockInfo& _bi) { ProofOfWork pow; - std::pair ret; + std::pair ret; while (!ProofOfWork::verify(_bi)) { ret = pow.mine(_bi, 10000, true); From 0b665270b6d7cb8f8b75eb2a3b1d8d80715ca01f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Apr 2015 15:55:01 +0200 Subject: [PATCH 064/108] Add more files. --- libethash-cl/CMakeLists.txt | 47 + libethash-cl/bin2h.cmake | 86 + libethash-cl/cl.hpp | 4014 ++++++++++++++++++++++++ libethash-cl/ethash_cl_miner.cpp | 332 ++ libethash-cl/ethash_cl_miner.h | 43 + libethash-cl/ethash_cl_miner_kernel.cl | 460 +++ 6 files changed, 4982 insertions(+) create mode 100644 libethash-cl/CMakeLists.txt create mode 100644 libethash-cl/bin2h.cmake create mode 100644 libethash-cl/cl.hpp create mode 100644 libethash-cl/ethash_cl_miner.cpp create mode 100644 libethash-cl/ethash_cl_miner.h create mode 100644 libethash-cl/ethash_cl_miner_kernel.cl diff --git a/libethash-cl/CMakeLists.txt b/libethash-cl/CMakeLists.txt new file mode 100644 index 000000000..7b00a22bd --- /dev/null +++ b/libethash-cl/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 2.8) + +set(LIBRARY ethash-cl) +#set(CMAKE_BUILD_TYPE Release) + +include(bin2h.cmake) +bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl + VARIABLE_NAME ethash_cl_miner_kernel + HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) + +if (NOT MSVC) + # Initialize CXXFLAGS for c++11 + set(CMAKE_CXX_FLAGS "-Wall -std=c++11") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + + # Compiler-specific C++11 activation. + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)) + message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.") + endif () + elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + else () + message(FATAL_ERROR "Your C++ compiler does not support C++11.") + endif () +endif() + +set(OpenCL_FOUND TRUE) +set(OpenCL_INCLUDE_DIRS /usr/include/CL) +set(OpenCL_LIBRARIES -lOpenCL) + +if (NOT OpenCL_FOUND) + find_package(OpenCL) +endif() + +if (OpenCL_FOUND) + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -pedantic -fPIC ${CMAKE_CXX_FLAGS}") + include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) + include_directories(..) + add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp) + TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash) +endif() diff --git a/libethash-cl/bin2h.cmake b/libethash-cl/bin2h.cmake new file mode 100644 index 000000000..90ca9cc5b --- /dev/null +++ b/libethash-cl/bin2h.cmake @@ -0,0 +1,86 @@ +# https://gist.github.com/sivachandran/3a0de157dccef822a230 +include(CMakeParseArguments) + +# Function to wrap a given string into multiple lines at the given column position. +# Parameters: +# VARIABLE - The name of the CMake variable holding the string. +# AT_COLUMN - The column position at which string will be wrapped. +function(WRAP_STRING) + set(oneValueArgs VARIABLE AT_COLUMN) + cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) + + string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) + math(EXPR offset "0") + + while(stringLength GREATER 0) + + if(stringLength GREATER ${WRAP_STRING_AT_COLUMN}) + math(EXPR length "${WRAP_STRING_AT_COLUMN}") + else() + math(EXPR length "${stringLength}") + endif() + + string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) + set(lines "${lines}\n${line}") + + math(EXPR stringLength "${stringLength} - ${length}") + math(EXPR offset "${offset} + ${length}") + endwhile() + + set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) +endfunction() + +# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file +# will contain a byte array and integer variable holding the size of the array. +# Parameters +# SOURCE_FILE - The path of source file whose contents will be embedded in the header file. +# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append +# to this name and will be used a variable name for size variable. +# HEADER_FILE - The path of header file. +# APPEND - If specified appends to the header file instead of overwriting it +# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be +# useful if the source file is a text file and we want to use the file contents +# as string. But the size variable holds size of the byte array without this +# null byte. +# Usage: +# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG") +function(BIN2H) + set(options APPEND NULL_TERMINATE) + set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE) + cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN}) + + # reads source file contents as hex string + file(READ ${BIN2H_SOURCE_FILE} hexString HEX) + string(LENGTH ${hexString} hexStringLength) + + # appends null byte if asked + if(BIN2H_NULL_TERMINATE) + set(hexString "${hexString}00") + endif() + + # wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line) + wrap_string(VARIABLE hexString AT_COLUMN 32) + math(EXPR arraySize "${hexStringLength} / 2") + + # adds '0x' prefix and comma suffix before and after every byte respectively + string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString}) + # removes trailing comma + string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) + + # converts the variable name into proper C identifier + IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake + string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) + ENDIF() + string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) + + # declares byte array and the length variables + set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };") + set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};") + + set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n") + if(BIN2H_APPEND) + file(APPEND ${BIN2H_HEADER_FILE} "${declarations}") + else() + file(WRITE ${BIN2H_HEADER_FILE} "${declarations}") + endif() +endfunction() diff --git a/libethash-cl/cl.hpp b/libethash-cl/cl.hpp new file mode 100644 index 000000000..a38498762 --- /dev/null +++ b/libethash-cl/cl.hpp @@ -0,0 +1,4014 @@ +/******************************************************************************* + * Copyright (c) 2008-2010 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +/*! \file + * + * \brief C++ bindings for OpenCL 1.0 (rev 48) and OpenCL 1.1 (rev 33) + * \author Benedict R. Gaster and Laurent Morichetti + * + * Additions and fixes from Brian Cole, March 3rd 2010. + * + * \version 1.1 + * \date June 2010 + * + * Optional extension support + * + * cl + * cl_ext_device_fission + * #define USE_CL_DEVICE_FISSION + */ + +/*! \mainpage + * \section intro Introduction + * For many large applications C++ is the language of choice and so it seems + * reasonable to define C++ bindings for OpenCL. + * + * + * The interface is contained with a single C++ header file \em cl.hpp and all + * definitions are contained within the namespace \em cl. There is no additional + * requirement to include \em cl.h and to use either the C++ or original C + * bindings it is enough to simply include \em cl.hpp. + * + * The bindings themselves are lightweight and correspond closely to the + * underlying C API. Using the C++ bindings introduces no additional execution + * overhead. + * + * For detail documentation on the bindings see: + * + * The OpenCL C++ Wrapper API 1.1 (revision 04) + * http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.1.pdf + * + * \section example Example + * + * The following example shows a general use case for the C++ + * bindings, including support for the optional exception feature and + * also the supplied vector and string classes, see following sections for + * decriptions of these features. + * + * \code + * #define __CL_ENABLE_EXCEPTIONS + * + * #if defined(__APPLE__) || defined(__MACOSX) + * #include + * #else + * #include + * #endif + * #include + * #include + * #include + * + * const char * helloStr = "__kernel void " + * "hello(void) " + * "{ " + * " " + * "} "; + * + * int + * main(void) + * { + * cl_int err = CL_SUCCESS; + * try { + * + * std::vector platforms; + * cl::Platform::get(&platforms); + * if (platforms.size() == 0) { + * std::cout << "Platform size 0\n"; + * return -1; + * } + * + * cl_context_properties properties[] = + * { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; + * cl::Context context(CL_DEVICE_TYPE_CPU, properties); + * + * std::vector devices = context.getInfo(); + * + * cl::Program::Sources source(1, + * std::make_pair(helloStr,strlen(helloStr))); + * cl::Program program_ = cl::Program(context, source); + * program_.build(devices); + * + * cl::Kernel kernel(program_, "hello", &err); + * + * cl::Event event; + * cl::CommandQueue queue(context, devices[0], 0, &err); + * queue.enqueueNDRangeKernel( + * kernel, + * cl::NullRange, + * cl::NDRange(4,4), + * cl::NullRange, + * NULL, + * &event); + * + * event.wait(); + * } + * catch (cl::Error err) { + * std::cerr + * << "ERROR: " + * << err.what() + * << "(" + * << err.err() + * << ")" + * << std::endl; + * } + * + * return EXIT_SUCCESS; + * } + * + * \endcode + * + */ +#ifndef CL_HPP_ +#define CL_HPP_ + +#ifdef _WIN32 +#include +#include +#if defined(USE_DX_INTEROP) +#include +#endif +#endif // _WIN32 + +// +#if defined(USE_CL_DEVICE_FISSION) +#include +#endif + +#if defined(__APPLE__) || defined(__MACOSX) +#include +#include +#else +#include +#include +#endif // !__APPLE__ + +#if !defined(CL_CALLBACK) +#define CL_CALLBACK +#endif //CL_CALLBACK + +#include + +#if !defined(__NO_STD_VECTOR) +#include +#endif + +#if !defined(__NO_STD_STRING) +#include +#endif + +#if defined(linux) || defined(__APPLE__) || defined(__MACOSX) +# include +#endif // linux + +#include + +/*! \namespace cl + * + * \brief The OpenCL C++ bindings are defined within this namespace. + * + */ +namespace cl { + +#define __INIT_CL_EXT_FCN_PTR(name) \ + if(!pfn_##name) { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddress(#name); \ + if(!pfn_##name) { \ + } \ + } + +class Program; +class Device; +class Context; +class CommandQueue; +class Memory; + +#if defined(__CL_ENABLE_EXCEPTIONS) +#include +/*! \class Error + * \brief Exception class + */ +class Error : public std::exception +{ +private: + cl_int err_; + const char * errStr_; +public: + /*! Create a new CL error exception for a given error code + * and corresponding message. + */ + Error(cl_int err, const char * errStr = NULL) : err_(err), errStr_(errStr) + {} + + ~Error() throw() {} + + /*! \brief Get error string associated with exception + * + * \return A memory pointer to the error message string. + */ + virtual const char * what() const throw () + { + if (errStr_ == NULL) { + return "empty"; + } + else { + return errStr_; + } + } + + /*! \brief Get error code associated with exception + * + * \return The error code. + */ + cl_int err(void) const { return err_; } +}; + +#define __ERR_STR(x) #x +#else +#define __ERR_STR(x) NULL +#endif // __CL_ENABLE_EXCEPTIONS + +//! \cond DOXYGEN_DETAIL +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#define __GET_DEVICE_INFO_ERR __ERR_STR(clgetDeviceInfo) +#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) +#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) +#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) +#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) +#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) +#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) +#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) +#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) +#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) +#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) +#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) +#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) +#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) +#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) + +#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) +#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) + +#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) +#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) +#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) +#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) +#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) +#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) +#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) + +#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) +#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) +#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) +#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) + +#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) +#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) +#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) +#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) +#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) +#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) + +#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) +#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) +#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) +#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) +#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) +#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) +#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) +#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) +#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) +#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) +#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) +#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) +#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) +#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) +#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) +#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) +#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) +#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) +#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) +#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) +#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) +#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) + +#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) +#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) + +#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) + +#define __FLUSH_ERR __ERR_STR(clFlush) +#define __FINISH_ERR __ERR_STR(clFinish) + +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) +#endif // __CL_USER_OVERRIDE_ERROR_STRINGS +//! \endcond + +/*! \class string + * \brief Simple string class, that provides a limited subset of std::string + * functionality but avoids many of the issues that come with that class. + */ +class string +{ +private: + ::size_t size_; + char * str_; +public: + string(void) : size_(0), str_(NULL) + { + } + + string(char * str, ::size_t size) : + size_(size), + str_(NULL) + { + str_ = new char[size_+1]; + if (str_ != NULL) { + memcpy(str_, str, size_ * sizeof(char)); + str_[size_] = '\0'; + } + else { + size_ = 0; + } + } + + string(char * str) : + str_(NULL) + { + size_= ::strlen(str); + str_ = new char[size_ + 1]; + if (str_ != NULL) { + memcpy(str_, str, (size_ + 1) * sizeof(char)); + } + else { + size_ = 0; + } + } + + string& operator=(const string& rhs) + { + if (this == &rhs) { + return *this; + } + + if (rhs.size_ == 0 || rhs.str_ == NULL) { + size_ = 0; + str_ = NULL; + } + else { + size_ = rhs.size_; + str_ = new char[size_ + 1]; + if (str_ != NULL) { + memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); + } + else { + size_ = 0; + } + } + + return *this; + } + + string(const string& rhs) + { + *this = rhs; + } + + ~string() + { + if (str_ != NULL) { + delete[] str_; + } + } + + ::size_t size(void) const { return size_; } + ::size_t length(void) const { return size(); } + + const char * c_str(void) const { return (str_) ? str_ : "";} +}; + +#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) +#include +typedef std::string STRING_CLASS; +#elif !defined(__USE_DEV_STRING) +typedef cl::string STRING_CLASS; +#endif + +#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) +#include +#define VECTOR_CLASS std::vector +#elif !defined(__USE_DEV_VECTOR) +#define VECTOR_CLASS cl::vector +#endif + +#if !defined(__MAX_DEFAULT_VECTOR_SIZE) +#define __MAX_DEFAULT_VECTOR_SIZE 10 +#endif + +/*! \class vector + * \brief Fixed sized vector implementation that mirroring + * std::vector functionality. + */ +template +class vector +{ +private: + T data_[N]; + unsigned int size_; + bool empty_; +public: + vector() : + size_(-1), + empty_(true) + {} + + ~vector() {} + + unsigned int size(void) const + { + return size_ + 1; + } + + void clear() + { + size_ = -1; + empty_ = true; + } + + void push_back (const T& x) + { + if (size() < N) { + size_++; + data_[size_] = x; + empty_ = false; + } + } + + void pop_back(void) + { + if (!empty_) { + data_[size_].~T(); + size_--; + if (size_ == -1) { + empty_ = true; + } + } + } + + vector(const vector& vec) : + size_(vec.size_), + empty_(vec.empty_) + { + if (!empty_) { + memcpy(&data_[0], &vec.data_[0], size() * sizeof(T)); + } + } + + vector(unsigned int size, const T& val = T()) : + size_(-1), + empty_(true) + { + for (unsigned int i = 0; i < size; i++) { + push_back(val); + } + } + + vector& operator=(const vector& rhs) + { + if (this == &rhs) { + return *this; + } + + size_ = rhs.size_; + empty_ = rhs.empty_; + + if (!empty_) { + memcpy(&data_[0], &rhs.data_[0], size() * sizeof(T)); + } + + return *this; + } + + bool operator==(vector &vec) + { + if (empty_ && vec.empty_) { + return true; + } + + if (size() != vec.size()) { + return false; + } + + return memcmp(&data_[0], &vec.data_[0], size() * sizeof(T)) == 0 ? true : false; + } + + operator T* () { return data_; } + operator const T* () const { return data_; } + + bool empty (void) const + { + return empty_; + } + + unsigned int max_size (void) const + { + return N; + } + + unsigned int capacity () const + { + return sizeof(T) * N; + } + + T& operator[](int index) + { + return data_[index]; + } + + T operator[](int index) const + { + return data_[index]; + } + + template + void assign(I start, I end) + { + clear(); + while(start < end) { + push_back(*start); + start++; + } + } + + /*! \class iterator + * \brief Iterator class for vectors + */ + class iterator + { + private: + vector vec_; + int index_; + bool initialized_; + public: + iterator(void) : + index_(-1), + initialized_(false) + { + index_ = -1; + initialized_ = false; + } + + ~iterator(void) {} + + static iterator begin(vector &vec) + { + iterator i; + + if (!vec.empty()) { + i.index_ = 0; + } + + i.vec_ = vec; + i.initialized_ = true; + return i; + } + + static iterator end(vector &vec) + { + iterator i; + + if (!vec.empty()) { + i.index_ = vec.size(); + } + i.vec_ = vec; + i.initialized_ = true; + return i; + } + + bool operator==(iterator i) + { + return ((vec_ == i.vec_) && + (index_ == i.index_) && + (initialized_ == i.initialized_)); + } + + bool operator!=(iterator i) + { + return (!(*this==i)); + } + + void operator++() + { + index_++; + } + + void operator++(int x) + { + index_ += x; + } + + void operator--() + { + index_--; + } + + void operator--(int x) + { + index_ -= x; + } + + T operator *() + { + return vec_[index_]; + } + }; + + iterator begin(void) + { + return iterator::begin(*this); + } + + iterator end(void) + { + return iterator::end(*this); + } + + T& front(void) + { + return data_[0]; + } + + T& back(void) + { + return data_[size_]; + } + + const T& front(void) const + { + return data_[0]; + } + + const T& back(void) const + { + return data_[size_]; + } +}; + +/*! + * \brief size_t class used to interface between C++ and + * OpenCL C calls that require arrays of size_t values, who's + * size is known statically. + */ +template +struct size_t : public cl::vector< ::size_t, N> { }; + +namespace detail { + +// GetInfo help struct +template +struct GetInfoHelper +{ + static cl_int + get(Functor f, cl_uint name, T* param) + { + return f(name, sizeof(T), param, NULL); + } +}; + +// Specialized GetInfoHelper for VECTOR_CLASS params +template +struct GetInfoHelper > +{ + static cl_int get(Func f, cl_uint name, VECTOR_CLASS* param) + { + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + T* value = (T*) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + param->assign(&value[0], &value[required/sizeof(T)]); + return CL_SUCCESS; + } +}; + +// Specialized for getInfo +template +struct GetInfoHelper > +{ + static cl_int + get(Func f, cl_uint name, VECTOR_CLASS* param) + { + cl_uint err = f(name, param->size() * sizeof(char *), &(*param)[0], NULL); + if (err != CL_SUCCESS) { + return err; + } + + return CL_SUCCESS; + } +}; + +// Specialized GetInfoHelper for STRING_CLASS params +template +struct GetInfoHelper +{ + static cl_int get(Func f, cl_uint name, STRING_CLASS* param) + { + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + char* value = (char*) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + *param = value; + return CL_SUCCESS; + } +}; + +#define __GET_INFO_HELPER_WITH_RETAIN(CPP_TYPE) \ +namespace detail { \ +template \ +struct GetInfoHelper \ +{ \ + static cl_int get(Func f, cl_uint name, CPP_TYPE* param) \ + { \ + cl_uint err = f(name, sizeof(CPP_TYPE), param, NULL); \ + if (err != CL_SUCCESS) { \ + return err; \ + } \ + \ + return ReferenceHandler::retain((*param)()); \ + } \ +}; \ +} + + +#define __PARAM_NAME_INFO_1_0(F) \ + F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ + F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ + F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_bitfield) \ + F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ + F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ + F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint)\ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ + F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ + F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ + F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ + F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ + F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ + F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ + F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ + \ + F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ + F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ + F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ + F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_uint) \ + \ + F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ + \ + F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ + F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ + F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ + F(cl_mem_info, CL_MEM_HOST_PTR, void*) \ + F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ + \ + F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ + F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ + F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ + F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ + F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ + \ + F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ + F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ + F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_addressing_mode) \ + F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_filter_mode) \ + F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_bool) \ + \ + F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ + F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ + F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ + F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ + F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ + F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ + \ + F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ + F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ + F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ + F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ + \ + F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ + F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ + F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ + F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) + +#if defined(CL_VERSION_1_1) +#define __PARAM_NAME_INFO_1_1(F) \ + F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint)\ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ + \ + F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ + F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ + \ + F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) +#endif // CL_VERSION_1_1 + +#if defined(USE_CL_DEVICE_FISSION) +#define __PARAM_NAME_DEVICE_FISSION(F) \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \ + F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) +#endif // USE_CL_DEVICE_FISSION + +template +struct param_traits {}; + +#define __DECLARE_PARAM_TRAITS(token, param_name, T) \ +struct token; \ +template<> \ +struct param_traits \ +{ \ + enum { value = param_name }; \ + typedef T param_type; \ +}; + +__PARAM_NAME_INFO_1_0(__DECLARE_PARAM_TRAITS) +#if defined(CL_VERSION_1_1) +__PARAM_NAME_INFO_1_1(__DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 + +#if defined(USE_CL_DEVICE_FISSION) +__PARAM_NAME_DEVICE_FISSION(__DECLARE_PARAM_TRAITS); +#endif // USE_CL_DEVICE_FISSION + +#undef __DECLARE_PARAM_TRAITS + +// Convenience functions + +template +inline cl_int +getInfo(Func f, cl_uint name, T* param) +{ + return GetInfoHelper::get(f, name, param); +} + +template +struct GetInfoFunctor0 +{ + Func f_; const Arg0& arg0_; + cl_int operator ()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { return f_(arg0_, param, size, value, size_ret); } +}; + +template +struct GetInfoFunctor1 +{ + Func f_; const Arg0& arg0_; const Arg1& arg1_; + cl_int operator ()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { return f_(arg0_, arg1_, param, size, value, size_ret); } +}; + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, cl_uint name, T* param) +{ + GetInfoFunctor0 f0 = { f, arg0 }; + return GetInfoHelper, T> + ::get(f0, name, param); +} + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param) +{ + GetInfoFunctor1 f0 = { f, arg0, arg1 }; + return GetInfoHelper, T> + ::get(f0, name, param); +} + +template +struct ReferenceHandler +{ }; + +template <> +struct ReferenceHandler +{ + // cl_device_id does not have retain(). + static cl_int retain(cl_device_id) + { return CL_INVALID_DEVICE; } + // cl_device_id does not have release(). + static cl_int release(cl_device_id) + { return CL_INVALID_DEVICE; } +}; + +template <> +struct ReferenceHandler +{ + // cl_platform_id does not have retain(). + static cl_int retain(cl_platform_id) + { return CL_INVALID_PLATFORM; } + // cl_platform_id does not have release(). + static cl_int release(cl_platform_id) + { return CL_INVALID_PLATFORM; } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_context context) + { return ::clRetainContext(context); } + static cl_int release(cl_context context) + { return ::clReleaseContext(context); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_command_queue queue) + { return ::clRetainCommandQueue(queue); } + static cl_int release(cl_command_queue queue) + { return ::clReleaseCommandQueue(queue); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_mem memory) + { return ::clRetainMemObject(memory); } + static cl_int release(cl_mem memory) + { return ::clReleaseMemObject(memory); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_sampler sampler) + { return ::clRetainSampler(sampler); } + static cl_int release(cl_sampler sampler) + { return ::clReleaseSampler(sampler); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_program program) + { return ::clRetainProgram(program); } + static cl_int release(cl_program program) + { return ::clReleaseProgram(program); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_kernel kernel) + { return ::clRetainKernel(kernel); } + static cl_int release(cl_kernel kernel) + { return ::clReleaseKernel(kernel); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_event event) + { return ::clRetainEvent(event); } + static cl_int release(cl_event event) + { return ::clReleaseEvent(event); } +}; + +template +class Wrapper +{ +public: + typedef T cl_type; + +protected: + cl_type object_; + +public: + Wrapper() : object_(NULL) { } + + ~Wrapper() + { + if (object_ != NULL) { release(); } + } + + Wrapper(const Wrapper& rhs) + { + object_ = rhs.object_; + if (object_ != NULL) { retain(); } + } + + Wrapper& operator = (const Wrapper& rhs) + { + if (object_ != NULL) { release(); } + object_ = rhs.object_; + if (object_ != NULL) { retain(); } + return *this; + } + + cl_type operator ()() const { return object_; } + + cl_type& operator ()() { return object_; } + +protected: + + cl_int retain() const + { + return ReferenceHandler::retain(object_); + } + + cl_int release() const + { + return ReferenceHandler::release(object_); + } +}; + +#if defined(__CL_ENABLE_EXCEPTIONS) +static inline cl_int errHandler ( + cl_int err, + const char * errStr = NULL) throw(Error) +{ + if (err != CL_SUCCESS) { + throw Error(err, errStr); + } + return err; +} +#else +static inline cl_int errHandler (cl_int err, const char * errStr = NULL) +{ + return err; +} +#endif // __CL_ENABLE_EXCEPTIONS + +} // namespace detail +//! \endcond + +/*! \stuct ImageFormat + * \brief ImageFormat interface fro cl_image_format. + */ +struct ImageFormat : public cl_image_format +{ + ImageFormat(){} + + ImageFormat(cl_channel_order order, cl_channel_type type) + { + image_channel_order = order; + image_channel_data_type = type; + } + + ImageFormat& operator = (const ImageFormat& rhs) + { + if (this != &rhs) { + this->image_channel_data_type = rhs.image_channel_data_type; + this->image_channel_order = rhs.image_channel_order; + } + return *this; + } +}; + +/*! \class Device + * \brief Device interface for cl_device_id. + */ +class Device : public detail::Wrapper +{ +public: + Device(cl_device_id device) { object_ = device; } + + Device() : detail::Wrapper() { } + + Device(const Device& device) : detail::Wrapper(device) { } + + Device& operator = (const Device& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_device_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetDeviceInfo, object_, name, param), + __GET_DEVICE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_device_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + +#if defined(USE_CL_DEVICE_FISSION) + cl_int createSubDevices( + const cl_device_partition_property_ext * properties, + VECTOR_CLASS* devices) + { + typedef CL_API_ENTRY cl_int + ( CL_API_CALL * PFN_clCreateSubDevicesEXT)( + cl_device_id /*in_device*/, + const cl_device_partition_property_ext * /* properties */, + cl_uint /*num_entries*/, + cl_device_id * /*out_devices*/, + cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1; + + static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; + __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); + + cl_uint n = 0; + cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif +}; + +/*! \class Platform + * \brief Platform interface. + */ +class Platform : public detail::Wrapper +{ +public: + static const Platform null(); + + Platform(cl_platform_id platform) { object_ = platform; } + + Platform() : detail::Wrapper() { } + + Platform(const Platform& platform) : detail::Wrapper(platform) { } + + Platform& operator = (const Platform& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + cl_int getInfo(cl_platform_info name, STRING_CLASS* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetPlatformInfo, object_, name, param), + __GET_PLATFORM_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_platform_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int getDevices( + cl_device_type type, + VECTOR_CLASS* devices) const + { + cl_uint n = 0; + cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = ::clGetDeviceIDs(object_, type, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + +#if defined(USE_DX_INTEROP) + /*! \brief Get the list of available D3D10 devices. + * + * \param d3d_device_source. + * + * \param d3d_object. + * + * \param d3d_device_set. + * + * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device + * values returned in devices can be used to identify a specific OpenCL + * device. If \a devices argument is NULL, this argument is ignored. + * + * \return One of the following values: + * - CL_SUCCESS if the function is executed successfully. + * + * The application can query specific capabilities of the OpenCL device(s) + * returned by cl::getDevices. This can be used by the application to + * determine which device(s) to use. + * + * \note In the case that exceptions are enabled and a return value + * other than CL_SUCCESS is generated, then cl::Error exception is + * generated. + */ + cl_int getDevices( + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + VECTOR_CLASS* devices) const + { + typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clGetDeviceIDsFromD3D10KHR)( + cl_platform_id platform, + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + cl_uint num_entries, + cl_device_id * devices, + cl_uint* num_devices); + + static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; + __INIT_CL_EXT_FCN_PTR(clGetDeviceIDsFromD3D10KHR); + + cl_uint n = 0; + cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + 0, + NULL, + &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + n, + ids, + NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif + + static cl_int get( + VECTOR_CLASS* platforms) + { + cl_uint n = 0; + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id* ids = (cl_platform_id*) alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + platforms->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +}; + +static inline cl_int +UnloadCompiler() +{ + return ::clUnloadCompiler(); +} + +class Context : public detail::Wrapper +{ +public: + Context( + const VECTOR_CLASS& devices, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateContext( + properties, (cl_uint) devices.size(), + (cl_device_id*) &devices.front(), + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + } + + Context( + cl_device_type type, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateContextFromType( + properties, type, notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + } + + Context() : detail::Wrapper() { } + + Context(const Context& context) : detail::Wrapper(context) { } + + Context& operator = (const Context& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_context_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetContextInfo, object_, name, param), + __GET_CONTEXT_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_context_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int getSupportedImageFormats( + cl_mem_flags flags, + cl_mem_object_type type, + VECTOR_CLASS* formats) const + { + cl_uint numEntries; + cl_int err = ::clGetSupportedImageFormats( + object_, + flags, + type, + 0, + NULL, + &numEntries); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + ImageFormat* value = (ImageFormat*) + alloca(numEntries * sizeof(ImageFormat)); + err = ::clGetSupportedImageFormats( + object_, + flags, + type, + numEntries, + (cl_image_format*) value, + NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + formats->assign(&value[0], &value[numEntries]); + return CL_SUCCESS; + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Context) + +/*! \class Event + * \brief Event interface for cl_event. + */ +class Event : public detail::Wrapper +{ +public: + Event() : detail::Wrapper() { } + + Event(const Event& event) : detail::Wrapper(event) { } + + Event& operator = (const Event& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_event_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetEventInfo, object_, name, param), + __GET_EVENT_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_event_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int getProfilingInfo(cl_profiling_info name, T* param) const + { + return detail::errHandler(detail::getInfo( + &::clGetEventProfilingInfo, object_, name, param), + __GET_EVENT_PROFILE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getProfilingInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_profiling_info, name>::param_type param; + cl_int result = getProfilingInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int wait() const + { + return detail::errHandler( + ::clWaitForEvents(1, &object_), + __WAIT_FOR_EVENTS_ERR); + } + +#if defined(CL_VERSION_1_1) + cl_int setCallback( + cl_int type, + void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), + void * user_data = NULL) + { + return detail::errHandler( + ::clSetEventCallback( + object_, + type, + pfn_notify, + user_data), + __SET_EVENT_CALLBACK_ERR); + } +#endif + + static cl_int + waitForEvents(const VECTOR_CLASS& events) + { + return detail::errHandler( + ::clWaitForEvents( + (cl_uint) events.size(), (cl_event*)&events.front()), + __WAIT_FOR_EVENTS_ERR); + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Event) + +#if defined(CL_VERSION_1_1) +/*! \class UserEvent + * \brief User event interface for cl_event. + */ +class UserEvent : public Event +{ +public: + UserEvent( + const Context& context, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateUserEvent( + context(), + &error); + + detail::errHandler(error, __CREATE_USER_EVENT_ERR); + if (err != NULL) { + *err = error; + } + } + + UserEvent() : Event() { } + + UserEvent(const UserEvent& event) : Event(event) { } + + UserEvent& operator = (const UserEvent& rhs) + { + if (this != &rhs) { + Event::operator=(rhs); + } + return *this; + } + + cl_int setStatus(cl_int status) + { + return detail::errHandler( + ::clSetUserEventStatus(object_,status), + __SET_USER_EVENT_STATUS_ERR); + } +}; +#endif + +inline static cl_int +WaitForEvents(const VECTOR_CLASS& events) +{ + return detail::errHandler( + ::clWaitForEvents( + (cl_uint) events.size(), (cl_event*)&events.front()), + __WAIT_FOR_EVENTS_ERR); +} + +/*! \class Memory + * \brief Memory interface for cl_mem. + */ +class Memory : public detail::Wrapper +{ +public: + Memory() : detail::Wrapper() { } + + Memory(const Memory& memory) : detail::Wrapper(memory) { } + + Memory& operator = (const Memory& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_mem_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetMemObjectInfo, object_, name, param), + __GET_MEM_OBJECT_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_mem_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_1) + cl_int setDestructorCallback( + void (CL_CALLBACK * pfn_notify)(cl_mem, void *), + void * user_data = NULL) + { + return detail::errHandler( + ::clSetMemObjectDestructorCallback( + object_, + pfn_notify, + user_data), + __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); + } +#endif + +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Memory) + +/*! \class Buffer + * \brief Memory buffer interface. + */ +class Buffer : public Memory +{ +public: + Buffer( + const Context& context, + cl_mem_flags flags, + ::size_t size, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + Buffer() : Memory() { } + + Buffer(const Buffer& buffer) : Memory(buffer) { } + + Buffer& operator = (const Buffer& rhs) + { + if (this != &rhs) { + Memory::operator=(rhs); + } + return *this; + } + +#if defined(CL_VERSION_1_1) + Buffer createSubBuffer( + cl_mem_flags flags, + cl_buffer_create_type buffer_create_type, + const void * buffer_create_info, + cl_int * err = NULL) + { + Buffer result; + cl_int error; + result.object_ = ::clCreateSubBuffer( + object_, + flags, + buffer_create_type, + buffer_create_info, + &error); + + detail::errHandler(error, __CREATE_SUBBUFFER_ERR); + if (err != NULL) { + *err = error; + } + + return result; + } +#endif +}; + +#if defined (USE_DX_INTEROP) +class BufferD3D10 : public Buffer +{ +public: + typedef CL_API_ENTRY cl_mem (CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)( + cl_context context, cl_mem_flags flags, ID3D10Buffer* buffer, + cl_int* errcode_ret); + + BufferD3D10( + const Context& context, + cl_mem_flags flags, + ID3D10Buffer* bufobj, + cl_int * err = NULL) + { + static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; + __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); + + cl_int error; + object_ = pfn_clCreateFromD3D10BufferKHR( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + BufferD3D10() : Buffer() { } + + BufferD3D10(const BufferD3D10& buffer) : Buffer(buffer) { } + + BufferD3D10& operator = (const BufferD3D10& rhs) + { + if (this != &rhs) { + Buffer::operator=(rhs); + } + return *this; + } +}; +#endif + +/*! \class BufferGL + * \brief Memory buffer interface for GL interop. + */ +class BufferGL : public Buffer +{ +public: + BufferGL( + const Context& context, + cl_mem_flags flags, + GLuint bufobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLBuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + BufferGL() : Buffer() { } + + BufferGL(const BufferGL& buffer) : Buffer(buffer) { } + + BufferGL& operator = (const BufferGL& rhs) + { + if (this != &rhs) { + Buffer::operator=(rhs); + } + return *this; + } + + cl_int getObjectInfo( + cl_gl_object_type *type, + GLuint * gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_,type,gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \class BufferRenderGL + * \brief Memory buffer interface for GL interop with renderbuffer. + */ +class BufferRenderGL : public Buffer +{ +public: + BufferRenderGL( + const Context& context, + cl_mem_flags flags, + GLuint bufobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLRenderbuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + BufferRenderGL() : Buffer() { } + + BufferRenderGL(const BufferGL& buffer) : Buffer(buffer) { } + + BufferRenderGL& operator = (const BufferRenderGL& rhs) + { + if (this != &rhs) { + Buffer::operator=(rhs); + } + return *this; + } + + cl_int getObjectInfo( + cl_gl_object_type *type, + GLuint * gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_,type,gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \class Image + * \brief Base class interface for all images. + */ +class Image : public Memory +{ +protected: + Image() : Memory() { } + + Image(const Image& image) : Memory(image) { } + + Image& operator = (const Image& rhs) + { + if (this != &rhs) { + Memory::operator=(rhs); + } + return *this; + } +public: + template + cl_int getImageInfo(cl_image_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetImageInfo, object_, name, param), + __GET_IMAGE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getImageInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_image_info, name>::param_type param; + cl_int result = getImageInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +}; + +/*! \class Image2D + * \brief Image interface for 2D images. + */ +class Image2D : public Image +{ +public: + Image2D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t row_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateImage2D( + context(), flags,&format, width, height, row_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE2D_ERR); + if (err != NULL) { + *err = error; + } + } + + Image2D() { } + + Image2D(const Image2D& image2D) : Image(image2D) { } + + Image2D& operator = (const Image2D& rhs) + { + if (this != &rhs) { + Image::operator=(rhs); + } + return *this; + } +}; + +/*! \class Image2DGL + * \brief 2D image interface for GL interop. + */ +class Image2DGL : public Image2D +{ +public: + Image2DGL( + const Context& context, + cl_mem_flags flags, + GLenum target, + GLint miplevel, + GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture2D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + Image2DGL() : Image2D() { } + + Image2DGL(const Image2DGL& image) : Image2D(image) { } + + Image2DGL& operator = (const Image2DGL& rhs) + { + if (this != &rhs) { + Image2D::operator=(rhs); + } + return *this; + } +}; + +/*! \class Image3D + * \brief Image interface for 3D images. + */ +class Image3D : public Image +{ +public: + Image3D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t depth, + ::size_t row_pitch = 0, + ::size_t slice_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateImage3D( + context(), flags, &format, width, height, depth, row_pitch, + slice_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE3D_ERR); + if (err != NULL) { + *err = error; + } + } + + Image3D() { } + + Image3D(const Image3D& image3D) : Image(image3D) { } + + Image3D& operator = (const Image3D& rhs) + { + if (this != &rhs) { + Image::operator=(rhs); + } + return *this; + } +}; + +/*! \class Image2DGL + * \brief 2D image interface for GL interop. + */ +class Image3DGL : public Image3D +{ +public: + Image3DGL( + const Context& context, + cl_mem_flags flags, + GLenum target, + GLint miplevel, + GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture3D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + Image3DGL() : Image3D() { } + + Image3DGL(const Image3DGL& image) : Image3D(image) { } + + Image3DGL& operator = (const Image3DGL& rhs) + { + if (this != &rhs) { + Image3D::operator=(rhs); + } + return *this; + } +}; + +/*! \class Sampler + * \brief Sampler interface for cl_sampler. + */ +class Sampler : public detail::Wrapper +{ +public: + Sampler() { } + + Sampler( + const Context& context, + cl_bool normalized_coords, + cl_addressing_mode addressing_mode, + cl_filter_mode filter_mode, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateSampler( + context(), + normalized_coords, + addressing_mode, + filter_mode, + &error); + + detail::errHandler(error, __CREATE_SAMPLER_ERR); + if (err != NULL) { + *err = error; + } + } + + Sampler(const Sampler& sampler) : detail::Wrapper(sampler) { } + + Sampler& operator = (const Sampler& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_sampler_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetSamplerInfo, object_, name, param), + __GET_SAMPLER_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_sampler_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Sampler) + +class Program; +class CommandQueue; +class Kernel; + +/*! \class NDRange + * \brief NDRange interface + */ +class NDRange +{ +private: + size_t<3> sizes_; + cl_uint dimensions_; + +public: + NDRange() + : dimensions_(0) + { } + + NDRange(::size_t size0) + : dimensions_(1) + { + sizes_.push_back(size0); + } + + NDRange(::size_t size0, ::size_t size1) + : dimensions_(2) + { + sizes_.push_back(size0); + sizes_.push_back(size1); + } + + NDRange(::size_t size0, ::size_t size1, ::size_t size2) + : dimensions_(3) + { + sizes_.push_back(size0); + sizes_.push_back(size1); + sizes_.push_back(size2); + } + + operator const ::size_t*() const { return (const ::size_t*) sizes_; } + ::size_t dimensions() const { return dimensions_; } +}; + +static const NDRange NullRange; + +/*! + * \struct LocalSpaceArg + * \brief Local address raper for use with Kernel::setArg + */ +struct LocalSpaceArg +{ + ::size_t size_; +}; + +namespace detail { + +template +struct KernelArgumentHandler +{ + static ::size_t size(const T&) { return sizeof(T); } + static T* ptr(T& value) { return &value; } +}; + +template <> +struct KernelArgumentHandler +{ + static ::size_t size(const LocalSpaceArg& value) { return value.size_; } + static void* ptr(LocalSpaceArg&) { return NULL; } +}; + +} +//! \endcond + +inline LocalSpaceArg +__local(::size_t size) +{ + LocalSpaceArg ret = { size }; + return ret; +} + +class KernelFunctor; + +/*! \class Kernel + * \brief Kernel interface that implements cl_kernel + */ +class Kernel : public detail::Wrapper +{ +public: + inline Kernel(const Program& program, const char* name, cl_int* err = NULL); + + Kernel() { } + + Kernel(const Kernel& kernel) : detail::Wrapper(kernel) { } + + Kernel& operator = (const Kernel& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_kernel_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelInfo, object_, name, param), + __GET_KERNEL_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int getWorkGroupInfo( + const Device& device, cl_kernel_work_group_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetKernelWorkGroupInfo, object_, device(), name, param), + __GET_KERNEL_WORK_GROUP_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getWorkGroupInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_work_group_info, name>::param_type param; + cl_int result = getWorkGroupInfo(device, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int setArg(cl_uint index, T value) + { + return detail::errHandler( + ::clSetKernelArg( + object_, + index, + detail::KernelArgumentHandler::size(value), + detail::KernelArgumentHandler::ptr(value)), + __SET_KERNEL_ARGS_ERR); + } + + cl_int setArg(cl_uint index, ::size_t size, void* argPtr) + { + return detail::errHandler( + ::clSetKernelArg(object_, index, size, argPtr), + __SET_KERNEL_ARGS_ERR); + } + + KernelFunctor bind( + const CommandQueue& queue, + const NDRange& offset, + const NDRange& global, + const NDRange& local); + + KernelFunctor bind( + const CommandQueue& queue, + const NDRange& global, + const NDRange& local); +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Kernel) + +/*! \class Program + * \brief Program interface that implements cl_program. + */ +class Program : public detail::Wrapper +{ +public: + typedef VECTOR_CLASS > Binaries; + typedef VECTOR_CLASS > Sources; + + Program( + const Context& context, + const Sources& sources, + cl_int* err = NULL) + { + cl_int error; + + const ::size_t n = (::size_t)sources.size(); + ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); + const char** strings = (const char**) alloca(n * sizeof(const char*)); + + for (::size_t i = 0; i < n; ++i) { + strings[i] = sources[(int)i].first; + lengths[i] = sources[(int)i].second; + } + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)n, strings, lengths, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + if (err != NULL) { + *err = error; + } + } + + Program( + const Context& context, + const VECTOR_CLASS& devices, + const Binaries& binaries, + VECTOR_CLASS* binaryStatus = NULL, + cl_int* err = NULL) + { + cl_int error; + const ::size_t n = binaries.size(); + ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); + const unsigned char** images = (const unsigned char**) alloca(n * sizeof(const void*)); + + for (::size_t i = 0; i < n; ++i) { + images[i] = (const unsigned char*)binaries[(int)i].first; + lengths[i] = binaries[(int)i].second; + } + + object_ = ::clCreateProgramWithBinary( + context(), (cl_uint) devices.size(), + (cl_device_id*)&devices.front(), + lengths, images, binaryStatus != NULL + ? (cl_int*) &binaryStatus->front() + : NULL, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) { + *err = error; + } + } + + Program() { } + + Program(const Program& program) : detail::Wrapper(program) { } + + Program& operator = (const Program& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + cl_int build( + const VECTOR_CLASS& devices, + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL) const + { + return detail::errHandler( + ::clBuildProgram( + object_, + (cl_uint) + devices.size(), + (cl_device_id*)&devices.front(), + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + + template + cl_int getInfo(cl_program_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetProgramInfo, object_, name, param), + __GET_PROGRAM_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int getBuildInfo( + const Device& device, cl_program_build_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetProgramBuildInfo, object_, device(), name, param), + __GET_PROGRAM_BUILD_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getBuildInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_build_info, name>::param_type param; + cl_int result = getBuildInfo(device, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int createKernels(VECTOR_CLASS* kernels) + { + cl_uint numKernels; + cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + Kernel* value = (Kernel*) alloca(numKernels * sizeof(Kernel)); + err = ::clCreateKernelsInProgram( + object_, numKernels, (cl_kernel*) value, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + kernels->assign(&value[0], &value[numKernels]); + return CL_SUCCESS; + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::Program) + +inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) +{ + cl_int error; + + object_ = ::clCreateKernel(program(), name, &error); + detail::errHandler(error, __CREATE_KERNEL_ERR); + + if (err != NULL) { + *err = error; + } + +} + +/*! \class CommandQueue + * \brief CommandQueue interface for cl_command_queue. + */ +class CommandQueue : public detail::Wrapper +{ +public: + CommandQueue( + const Context& context, + const Device& device, + cl_command_queue_properties properties = 0, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) { + *err = error; + } + } + + CommandQueue() { } + + CommandQueue(const CommandQueue& commandQueue) : detail::Wrapper(commandQueue) { } + + CommandQueue& operator = (const CommandQueue& rhs) + { + if (this != &rhs) { + detail::Wrapper::operator=(rhs); + } + return *this; + } + + template + cl_int getInfo(cl_command_queue_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetCommandQueueInfo, object_, name, param), + __GET_COMMAND_QUEUE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_command_queue_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int enqueueReadBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueReadBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_READ_BUFFER_ERR); + } + + cl_int enqueueWriteBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueWriteBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_WRITE_BUFFER_ERR); + } + + cl_int enqueueCopyBuffer( + const Buffer& src, + const Buffer& dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyBuffer( + object_, src(), dst(), src_offset, dst_offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQEUE_COPY_BUFFER_ERR); + } + +#if defined(CL_VERSION_1_1) + cl_int enqueueReadBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueReadBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_READ_BUFFER_RECT_ERR); + } + + + cl_int enqueueWriteBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueWriteBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_WRITE_BUFFER_RECT_ERR); + } + + cl_int enqueueCopyBufferRect( + const Buffer& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyBufferRect( + object_, + src(), + dst(), + (const ::size_t *)src_origin, + (const ::size_t *)dst_origin, + (const ::size_t *)region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQEUE_COPY_BUFFER_RECT_ERR); + } +#endif + + cl_int enqueueReadImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueReadImage( + object_, image(), blocking, (const ::size_t *) origin, + (const ::size_t *) region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_READ_IMAGE_ERR); + } + + cl_int enqueueWriteImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueWriteImage( + object_, image(), blocking, (const ::size_t *) origin, + (const ::size_t *) region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_WRITE_IMAGE_ERR); + } + + cl_int enqueueCopyImage( + const Image& src, + const Image& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyImage( + object_, src(), dst(), (const ::size_t *) src_origin, + (const ::size_t *)dst_origin, (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_COPY_IMAGE_ERR); + } + + cl_int enqueueCopyImageToBuffer( + const Image& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& region, + ::size_t dst_offset, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyImageToBuffer( + object_, src(), dst(), (const ::size_t *) src_origin, + (const ::size_t *) region, dst_offset, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); + } + + cl_int enqueueCopyBufferToImage( + const Buffer& src, + const Image& dst, + ::size_t src_offset, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueCopyBufferToImage( + object_, src(), dst(), src_offset, + (const ::size_t *) dst_origin, (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); + } + + void* enqueueMapBuffer( + const Buffer& buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_int error; + void * result = ::clEnqueueMapBuffer( + object_, buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + return result; + } + + void* enqueueMapImage( + const Image& buffer, + cl_bool blocking, + cl_map_flags flags, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t * row_pitch, + ::size_t * slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_int error; + void * result = ::clEnqueueMapImage( + object_, buffer(), blocking, flags, + (const ::size_t *) origin, (const ::size_t *) region, + row_pitch, slice_pitch, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + return result; + } + + cl_int enqueueUnmapMemObject( + const Memory& memory, + void* mapped_ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueUnmapMemObject( + object_, memory(), mapped_ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + } + + cl_int enqueueNDRangeKernel( + const Kernel& kernel, + const NDRange& offset, + const NDRange& global, + const NDRange& local, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueNDRangeKernel( + object_, kernel(), (cl_uint) global.dimensions(), + offset.dimensions() != 0 ? (const ::size_t*) offset : NULL, + (const ::size_t*) global, + local.dimensions() != 0 ? (const ::size_t*) local : NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_NDRANGE_KERNEL_ERR); + } + + cl_int enqueueTask( + const Kernel& kernel, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueTask( + object_, kernel(), + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_TASK_ERR); + } + + cl_int enqueueNativeKernel( + void (*userFptr)(void *), + std::pair args, + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* mem_locs = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_mem * mems = (mem_objects != NULL && mem_objects->size() > 0) + ? (cl_mem*) alloca(mem_objects->size() * sizeof(cl_mem)) + : NULL; + + if (mems != NULL) { + for (unsigned int i = 0; i < mem_objects->size(); i++) { + mems[i] = ((*mem_objects)[i])(); + } + } + + return detail::errHandler( + ::clEnqueueNativeKernel( + object_, userFptr, args.first, args.second, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + mems, + (mem_locs != NULL) ? (const void **) &mem_locs->front() : NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_NATIVE_KERNEL); + } + + cl_int enqueueMarker(Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueMarker(object_, (cl_event*) event), + __ENQUEUE_MARKER_ERR); + } + + cl_int enqueueWaitForEvents(const VECTOR_CLASS& events) const + { + return detail::errHandler( + ::clEnqueueWaitForEvents( + object_, + (cl_uint) events.size(), + (const cl_event*) &events.front()), + __ENQUEUE_WAIT_FOR_EVENTS_ERR); + } + + cl_int enqueueAcquireGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueAcquireGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_ACQUIRE_GL_ERR); + } + + cl_int enqueueReleaseGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + return detail::errHandler( + ::clEnqueueReleaseGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_RELEASE_GL_ERR); + } + +#if defined (USE_DX_INTEROP) +typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); +typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); + + cl_int enqueueAcquireD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; + __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); + + return detail::errHandler( + pfn_clEnqueueAcquireD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_ACQUIRE_GL_ERR); + } + + cl_int enqueueReleaseD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; + __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); + + return detail::errHandler( + pfn_clEnqueueReleaseD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL) ? (cl_event*) &events->front() : NULL, + (cl_event*) event), + __ENQUEUE_RELEASE_GL_ERR); + } +#endif + + cl_int enqueueBarrier() const + { + return detail::errHandler( + ::clEnqueueBarrier(object_), + __ENQUEUE_BARRIER_ERR); + } + + cl_int flush() const + { + return detail::errHandler(::clFlush(object_), __FLUSH_ERR); + } + + cl_int finish() const + { + return detail::errHandler(::clFinish(object_), __FINISH_ERR); + } +}; + +__GET_INFO_HELPER_WITH_RETAIN(cl::CommandQueue) + +/*! \class KernelFunctor + * \brief Kernel functor interface + * + * \note Currently only functors of zero to ten arguments are supported. It + * is straightforward to add more and a more general solution, similar to + * Boost.Lambda could be followed if required in the future. + */ +class KernelFunctor +{ +private: + Kernel kernel_; + CommandQueue queue_; + NDRange offset_; + NDRange global_; + NDRange local_; + + cl_int err_; +public: + KernelFunctor() { } + + KernelFunctor( + const Kernel& kernel, + const CommandQueue& queue, + const NDRange& offset, + const NDRange& global, + const NDRange& local) : + kernel_(kernel), + queue_(queue), + offset_(offset), + global_(global), + local_(local), + err_(CL_SUCCESS) + {} + + KernelFunctor& operator=(const KernelFunctor& rhs); + + KernelFunctor(const KernelFunctor& rhs); + + cl_int getError() { return err_; } + + inline Event operator()(const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const A14& a14, + const VECTOR_CLASS* events = NULL); + + template + inline Event operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const A14& a14, + const A15& a15, + const VECTOR_CLASS* events = NULL); +}; + +inline KernelFunctor Kernel::bind( + const CommandQueue& queue, + const NDRange& offset, + const NDRange& global, + const NDRange& local) +{ + return KernelFunctor(*this,queue,offset,global,local); +} + +inline KernelFunctor Kernel::bind( + const CommandQueue& queue, + const NDRange& global, + const NDRange& local) +{ + return KernelFunctor(*this,queue,NullRange,global,local); +} + +inline KernelFunctor& KernelFunctor::operator=(const KernelFunctor& rhs) +{ + if (this == &rhs) { + return *this; + } + + kernel_ = rhs.kernel_; + queue_ = rhs.queue_; + offset_ = rhs.offset_; + global_ = rhs.global_; + local_ = rhs.local_; + + return *this; +} + +inline KernelFunctor::KernelFunctor(const KernelFunctor& rhs) : + kernel_(rhs.kernel_), + queue_(rhs.queue_), + offset_(rhs.offset_), + global_(rhs.global_), + local_(rhs.local_) +{ +} + +Event KernelFunctor::operator()(const VECTOR_CLASS* events) +{ + (void)events; + Event event; + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + kernel_.setArg(11,a12); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + kernel_.setArg(11,a12); + kernel_.setArg(12,a13); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const A14& a14, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + kernel_.setArg(11,a12); + kernel_.setArg(12,a13); + kernel_.setArg(13,a14); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +template +Event KernelFunctor::operator()( + const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6, + const A7& a7, + const A8& a8, + const A9& a9, + const A10& a10, + const A11& a11, + const A12& a12, + const A13& a13, + const A14& a14, + const A15& a15, + const VECTOR_CLASS* events) +{ + Event event; + + kernel_.setArg(0,a1); + kernel_.setArg(1,a2); + kernel_.setArg(2,a3); + kernel_.setArg(3,a4); + kernel_.setArg(4,a5); + kernel_.setArg(5,a6); + kernel_.setArg(6,a7); + kernel_.setArg(7,a8); + kernel_.setArg(8,a9); + kernel_.setArg(9,a10); + kernel_.setArg(10,a11); + kernel_.setArg(11,a12); + kernel_.setArg(12,a13); + kernel_.setArg(13,a14); + kernel_.setArg(14,a15); + + err_ = queue_.enqueueNDRangeKernel( + kernel_, + offset_, + global_, + local_, + NULL, // bgaster_fixme - do we want to allow wait event lists? + &event); + + return event; +} + +#undef __ERR_STR +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#undef __GET_DEVICE_INFO_ERR +#undef __GET_PLATFORM_INFO_ERR +#undef __GET_DEVICE_IDS_ERR +#undef __GET_CONTEXT_INFO_ERR +#undef __GET_EVENT_INFO_ERR +#undef __GET_EVENT_PROFILE_INFO_ERR +#undef __GET_MEM_OBJECT_INFO_ERR +#undef __GET_IMAGE_INFO_ERR +#undef __GET_SAMPLER_INFO_ERR +#undef __GET_KERNEL_INFO_ERR +#undef __GET_KERNEL_WORK_GROUP_INFO_ERR +#undef __GET_PROGRAM_INFO_ERR +#undef __GET_PROGRAM_BUILD_INFO_ERR +#undef __GET_COMMAND_QUEUE_INFO_ERR + +#undef __CREATE_CONTEXT_FROM_TYPE_ERR +#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR + +#undef __CREATE_BUFFER_ERR +#undef __CREATE_SUBBUFFER_ERR +#undef __CREATE_IMAGE2D_ERR +#undef __CREATE_IMAGE3D_ERR +#undef __CREATE_SAMPLER_ERR +#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR + +#undef __CREATE_USER_EVENT_ERR +#undef __SET_USER_EVENT_STATUS_ERR +#undef __SET_EVENT_CALLBACK_ERR + +#undef __WAIT_FOR_EVENTS_ERR + +#undef __CREATE_KERNEL_ERR +#undef __SET_KERNEL_ARGS_ERR +#undef __CREATE_PROGRAM_WITH_SOURCE_ERR +#undef __CREATE_PROGRAM_WITH_BINARY_ERR +#undef __BUILD_PROGRAM_ERR +#undef __CREATE_KERNELS_IN_PROGRAM_ERR + +#undef __CREATE_COMMAND_QUEUE_ERR +#undef __SET_COMMAND_QUEUE_PROPERTY_ERR +#undef __ENQUEUE_READ_BUFFER_ERR +#undef __ENQUEUE_WRITE_BUFFER_ERR +#undef __ENQUEUE_READ_BUFFER_RECT_ERR +#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR +#undef __ENQEUE_COPY_BUFFER_ERR +#undef __ENQEUE_COPY_BUFFER_RECT_ERR +#undef __ENQUEUE_READ_IMAGE_ERR +#undef __ENQUEUE_WRITE_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR +#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR +#undef __ENQUEUE_MAP_BUFFER_ERR +#undef __ENQUEUE_MAP_IMAGE_ERR +#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR +#undef __ENQUEUE_NDRANGE_KERNEL_ERR +#undef __ENQUEUE_TASK_ERR +#undef __ENQUEUE_NATIVE_KERNEL + +#undef __UNLOAD_COMPILER_ERR +#endif //__CL_USER_OVERRIDE_ERROR_STRINGS + +#undef __GET_INFO_HELPER_WITH_RETAIN + +// Extensions +#undef __INIT_CL_EXT_FCN_PTR +#undef __CREATE_SUB_DEVICES + +#if defined(USE_CL_DEVICE_FISSION) +#undef __PARAM_NAME_DEVICE_FISSION +#endif // USE_CL_DEVICE_FISSION + +} // namespace cl + +#endif // CL_HPP_ diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp new file mode 100644 index 000000000..96f1fa582 --- /dev/null +++ b/libethash-cl/ethash_cl_miner.cpp @@ -0,0 +1,332 @@ +/* + This file is part of c-ethash. + + c-ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + c-ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file ethash_cl_miner.cpp +* @author Tim Hughes +* @date 2015 +*/ + + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include +#include "ethash_cl_miner.h" +#include "ethash_cl_miner_kernel.h" + +#define ETHASH_BYTES 32 + +// workaround lame platforms +#if !CL_VERSION_1_2 +#define CL_MAP_WRITE_INVALIDATE_REGION CL_MAP_WRITE +#define CL_MEM_HOST_READ_ONLY 0 +#endif + +#undef min +#undef max + +static void add_definition(std::string& source, char const* id, unsigned value) +{ + char buf[256]; + sprintf(buf, "#define %s %uu\n", id, value); + source.insert(source.begin(), buf, buf + strlen(buf)); +} + +ethash_cl_miner::ethash_cl_miner() +: m_opencl_1_1() +{ +} + +void ethash_cl_miner::finish() +{ + if (m_queue()) + { + m_queue.finish(); + } +} + +bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size) +{ + // store params + m_params = params; + + // get all platforms + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + debugf("No OpenCL platforms found.\n"); + return false; + } + + // use default platform + fprintf(stderr, "Using platform: %s\n", platforms[0].getInfo().c_str()); + + // get GPU device of the default platform + std::vector devices; + platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) + { + debugf("No OpenCL devices found.\n"); + return false; + } + + // use default device + unsigned device_num = 0; + cl::Device& device = devices[device_num]; + std::string device_version = device.getInfo(); + fprintf(stderr, "Using device: %s (%s)\n", device.getInfo().c_str(),device_version.c_str()); + + if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) + { + debugf("OpenCL 1.0 is not supported.\n"); + return false; + } + if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) + { + m_opencl_1_1 = true; + } + + // create context + m_context = cl::Context(std::vector(&device, &device + 1)); + m_queue = cl::CommandQueue(m_context, device); + + // use requested workgroup size, but we require multiple of 8 + m_workgroup_size = ((workgroup_size + 7) / 8) * 8; + + // patch source code + std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); + add_definition(code, "GROUP_SIZE", m_workgroup_size); + add_definition(code, "DAG_SIZE", (unsigned)(params.full_size / ETHASH_MIX_BYTES)); + add_definition(code, "ACCESSES", ETHASH_ACCESSES); + add_definition(code, "MAX_OUTPUTS", c_max_search_results); + //debugf("%s", code.c_str()); + + // create miner OpenCL program + cl::Program::Sources sources; + sources.push_back({code.c_str(), code.size()}); + + cl::Program program(m_context, sources); + try + { + program.build({device}); + } + catch (cl::Error err) + { + debugf("%s\n", program.getBuildInfo(device).c_str()); + return false; + } + m_hash_kernel = cl::Kernel(program, "ethash_hash"); + m_search_kernel = cl::Kernel(program, "ethash_search"); + + // create buffer for dag + m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, params.full_size); + + // create buffer for header + m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); + + // compute dag on CPU + { + // if this throws then it's because we probably need to subdivide the dag uploads for compatibility + void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size); + // memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap. + _fillDAG(dag_ptr); + m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); + } + + // create mining buffers + for (unsigned i = 0; i != c_num_buffers; ++i) + { + m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32*c_hash_batch_size); + m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); + } + return true; +} + +void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count) +{ + struct pending_batch + { + unsigned base; + unsigned count; + unsigned buf; + }; + std::queue pending; + + // update header constant buffer + m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header); + + /* + __kernel void ethash_combined_hash( + __global hash32_t* g_hashes, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + uint isolate + ) + */ + m_hash_kernel.setArg(1, m_header); + m_hash_kernel.setArg(2, m_dag); + m_hash_kernel.setArg(3, nonce); + m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop + + unsigned buf = 0; + for (unsigned i = 0; i < count || !pending.empty(); ) + { + // how many this batch + if (i < count) + { + unsigned const this_count = std::min(count - i, c_hash_batch_size); + unsigned const batch_count = std::max(this_count, m_workgroup_size); + + // supply output hash buffer to kernel + m_hash_kernel.setArg(0, m_hash_buf[buf]); + + // execute it! + m_queue.enqueueNDRangeKernel( + m_hash_kernel, + cl::NullRange, + cl::NDRange(batch_count), + cl::NDRange(m_workgroup_size) + ); + m_queue.flush(); + + pending.push({i, this_count, buf}); + i += this_count; + buf = (buf + 1) % c_num_buffers; + } + + // read results + if (i == count || pending.size() == c_num_buffers) + { + pending_batch const& batch = pending.front(); + + // could use pinned host pointer instead, but this path isn't that important. + uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * ETHASH_BYTES); + memcpy(ret + batch.base*ETHASH_BYTES, hashes, batch.count*ETHASH_BYTES); + m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes); + + pending.pop(); + } + } +} + + +void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook) +{ + struct pending_batch + { + uint64_t start_nonce; + unsigned buf; + }; + std::queue pending; + + static uint32_t const c_zero = 0; + + // update header constant buffer + m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); + for (unsigned i = 0; i != c_num_buffers; ++i) + { + m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); + } + +#if CL_VERSION_1_2 && 0 + cl::Event pre_return_event; + if (!m_opencl_1_1) + { + m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); + } + else +#endif + { + m_queue.finish(); + } + + /* + __kernel void ethash_combined_search( + __global hash32_t* g_hashes, // 0 + __constant hash32_t const* g_header, // 1 + __global hash128_t const* g_dag, // 2 + ulong start_nonce, // 3 + ulong target, // 4 + uint isolate // 5 + ) + */ + m_search_kernel.setArg(1, m_header); + m_search_kernel.setArg(2, m_dag); + + // pass these to stop the compiler unrolling the loops + m_search_kernel.setArg(4, target); + m_search_kernel.setArg(5, ~0u); + + + unsigned buf = 0; + for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size) + { + // supply output buffer to kernel + m_search_kernel.setArg(0, m_search_buf[buf]); + m_search_kernel.setArg(3, start_nonce); + + // execute it! + m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); + + pending.push({start_nonce, buf}); + buf = (buf + 1) % c_num_buffers; + + // read results + if (pending.size() == c_num_buffers) + { + pending_batch const& batch = pending.front(); + + // could use pinned host pointer instead + uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t)); + unsigned num_found = std::min(results[0], c_max_search_results); + + uint64_t nonces[c_max_search_results]; + for (unsigned i = 0; i != num_found; ++i) + { + nonces[i] = batch.start_nonce + results[i+1]; + } + + m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); + + bool exit = num_found && hook.found(nonces, num_found); + exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit + if (exit) + break; + + // reset search buffer if we're still going + if (num_found) + m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero); + + pending.pop(); + } + } + + // not safe to return until this is ready +#if CL_VERSION_1_2 && 0 + if (!m_opencl_1_1) + { + pre_return_event.wait(); + } +#endif +} + diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h new file mode 100644 index 000000000..e478c739f --- /dev/null +++ b/libethash-cl/ethash_cl_miner.h @@ -0,0 +1,43 @@ +#pragma once + +#define __CL_ENABLE_EXCEPTIONS +#define CL_USE_DEPRECATED_OPENCL_2_0_APIS +#include "cl.hpp" +#include +#include +#include + +class ethash_cl_miner +{ +public: + struct search_hook + { + // reports progress, return true to abort + virtual bool found(uint64_t const* nonces, uint32_t count) = 0; + virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; + }; + +public: + ethash_cl_miner(); + + bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64); + + void finish(); + void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); + void search(uint8_t const* header, uint64_t target, search_hook& hook); + +private: + enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 }; + + ethash_params m_params; + cl::Context m_context; + cl::CommandQueue m_queue; + cl::Kernel m_hash_kernel; + cl::Kernel m_search_kernel; + cl::Buffer m_dag; + cl::Buffer m_header; + cl::Buffer m_hash_buf[c_num_buffers]; + cl::Buffer m_search_buf[c_num_buffers]; + unsigned m_workgroup_size; + bool m_opencl_1_1; +}; diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl new file mode 100644 index 000000000..3c8b9dc92 --- /dev/null +++ b/libethash-cl/ethash_cl_miner_kernel.cl @@ -0,0 +1,460 @@ +// author Tim Hughes +// Tested on Radeon HD 7850 +// Hashrate: 15940347 hashes/s +// Bandwidth: 124533 MB/s +// search kernel should fit in <= 84 VGPRS (3 wavefronts) + +#define THREADS_PER_HASH (128 / 16) +#define HASHES_PER_LOOP (GROUP_SIZE / THREADS_PER_HASH) + +#define FNV_PRIME 0x01000193 + +__constant uint2 const Keccak_f1600_RC[24] = { + (uint2)(0x00000001, 0x00000000), + (uint2)(0x00008082, 0x00000000), + (uint2)(0x0000808a, 0x80000000), + (uint2)(0x80008000, 0x80000000), + (uint2)(0x0000808b, 0x00000000), + (uint2)(0x80000001, 0x00000000), + (uint2)(0x80008081, 0x80000000), + (uint2)(0x00008009, 0x80000000), + (uint2)(0x0000008a, 0x00000000), + (uint2)(0x00000088, 0x00000000), + (uint2)(0x80008009, 0x00000000), + (uint2)(0x8000000a, 0x00000000), + (uint2)(0x8000808b, 0x00000000), + (uint2)(0x0000008b, 0x80000000), + (uint2)(0x00008089, 0x80000000), + (uint2)(0x00008003, 0x80000000), + (uint2)(0x00008002, 0x80000000), + (uint2)(0x00000080, 0x80000000), + (uint2)(0x0000800a, 0x00000000), + (uint2)(0x8000000a, 0x80000000), + (uint2)(0x80008081, 0x80000000), + (uint2)(0x00008080, 0x80000000), + (uint2)(0x80000001, 0x00000000), + (uint2)(0x80008008, 0x80000000), +}; + +void keccak_f1600_round(uint2* a, uint r, uint out_size) +{ + #if !__ENDIAN_LITTLE__ + for (uint i = 0; i != 25; ++i) + a[i] = a[i].yx; + #endif + + uint2 b[25]; + uint2 t; + + // Theta + b[0] = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]; + b[1] = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]; + b[2] = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]; + b[3] = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]; + b[4] = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]; + t = b[4] ^ (uint2)(b[1].x << 1 | b[1].y >> 31, b[1].y << 1 | b[1].x >> 31); + a[0] ^= t; + a[5] ^= t; + a[10] ^= t; + a[15] ^= t; + a[20] ^= t; + t = b[0] ^ (uint2)(b[2].x << 1 | b[2].y >> 31, b[2].y << 1 | b[2].x >> 31); + a[1] ^= t; + a[6] ^= t; + a[11] ^= t; + a[16] ^= t; + a[21] ^= t; + t = b[1] ^ (uint2)(b[3].x << 1 | b[3].y >> 31, b[3].y << 1 | b[3].x >> 31); + a[2] ^= t; + a[7] ^= t; + a[12] ^= t; + a[17] ^= t; + a[22] ^= t; + t = b[2] ^ (uint2)(b[4].x << 1 | b[4].y >> 31, b[4].y << 1 | b[4].x >> 31); + a[3] ^= t; + a[8] ^= t; + a[13] ^= t; + a[18] ^= t; + a[23] ^= t; + t = b[3] ^ (uint2)(b[0].x << 1 | b[0].y >> 31, b[0].y << 1 | b[0].x >> 31); + a[4] ^= t; + a[9] ^= t; + a[14] ^= t; + a[19] ^= t; + a[24] ^= t; + + // Rho Pi + b[0] = a[0]; + b[10] = (uint2)(a[1].x << 1 | a[1].y >> 31, a[1].y << 1 | a[1].x >> 31); + b[7] = (uint2)(a[10].x << 3 | a[10].y >> 29, a[10].y << 3 | a[10].x >> 29); + b[11] = (uint2)(a[7].x << 6 | a[7].y >> 26, a[7].y << 6 | a[7].x >> 26); + b[17] = (uint2)(a[11].x << 10 | a[11].y >> 22, a[11].y << 10 | a[11].x >> 22); + b[18] = (uint2)(a[17].x << 15 | a[17].y >> 17, a[17].y << 15 | a[17].x >> 17); + b[3] = (uint2)(a[18].x << 21 | a[18].y >> 11, a[18].y << 21 | a[18].x >> 11); + b[5] = (uint2)(a[3].x << 28 | a[3].y >> 4, a[3].y << 28 | a[3].x >> 4); + b[16] = (uint2)(a[5].y << 4 | a[5].x >> 28, a[5].x << 4 | a[5].y >> 28); + b[8] = (uint2)(a[16].y << 13 | a[16].x >> 19, a[16].x << 13 | a[16].y >> 19); + b[21] = (uint2)(a[8].y << 23 | a[8].x >> 9, a[8].x << 23 | a[8].y >> 9); + b[24] = (uint2)(a[21].x << 2 | a[21].y >> 30, a[21].y << 2 | a[21].x >> 30); + b[4] = (uint2)(a[24].x << 14 | a[24].y >> 18, a[24].y << 14 | a[24].x >> 18); + b[15] = (uint2)(a[4].x << 27 | a[4].y >> 5, a[4].y << 27 | a[4].x >> 5); + b[23] = (uint2)(a[15].y << 9 | a[15].x >> 23, a[15].x << 9 | a[15].y >> 23); + b[19] = (uint2)(a[23].y << 24 | a[23].x >> 8, a[23].x << 24 | a[23].y >> 8); + b[13] = (uint2)(a[19].x << 8 | a[19].y >> 24, a[19].y << 8 | a[19].x >> 24); + b[12] = (uint2)(a[13].x << 25 | a[13].y >> 7, a[13].y << 25 | a[13].x >> 7); + b[2] = (uint2)(a[12].y << 11 | a[12].x >> 21, a[12].x << 11 | a[12].y >> 21); + b[20] = (uint2)(a[2].y << 30 | a[2].x >> 2, a[2].x << 30 | a[2].y >> 2); + b[14] = (uint2)(a[20].x << 18 | a[20].y >> 14, a[20].y << 18 | a[20].x >> 14); + b[22] = (uint2)(a[14].y << 7 | a[14].x >> 25, a[14].x << 7 | a[14].y >> 25); + b[9] = (uint2)(a[22].y << 29 | a[22].x >> 3, a[22].x << 29 | a[22].y >> 3); + b[6] = (uint2)(a[9].x << 20 | a[9].y >> 12, a[9].y << 20 | a[9].x >> 12); + b[1] = (uint2)(a[6].y << 12 | a[6].x >> 20, a[6].x << 12 | a[6].y >> 20); + + // Chi + a[0] = bitselect(b[0] ^ b[2], b[0], b[1]); + a[1] = bitselect(b[1] ^ b[3], b[1], b[2]); + a[2] = bitselect(b[2] ^ b[4], b[2], b[3]); + a[3] = bitselect(b[3] ^ b[0], b[3], b[4]); + if (out_size >= 4) + { + a[4] = bitselect(b[4] ^ b[1], b[4], b[0]); + a[5] = bitselect(b[5] ^ b[7], b[5], b[6]); + a[6] = bitselect(b[6] ^ b[8], b[6], b[7]); + a[7] = bitselect(b[7] ^ b[9], b[7], b[8]); + a[8] = bitselect(b[8] ^ b[5], b[8], b[9]); + if (out_size >= 8) + { + a[9] = bitselect(b[9] ^ b[6], b[9], b[5]); + a[10] = bitselect(b[10] ^ b[12], b[10], b[11]); + a[11] = bitselect(b[11] ^ b[13], b[11], b[12]); + a[12] = bitselect(b[12] ^ b[14], b[12], b[13]); + a[13] = bitselect(b[13] ^ b[10], b[13], b[14]); + a[14] = bitselect(b[14] ^ b[11], b[14], b[10]); + a[15] = bitselect(b[15] ^ b[17], b[15], b[16]); + a[16] = bitselect(b[16] ^ b[18], b[16], b[17]); + a[17] = bitselect(b[17] ^ b[19], b[17], b[18]); + a[18] = bitselect(b[18] ^ b[15], b[18], b[19]); + a[19] = bitselect(b[19] ^ b[16], b[19], b[15]); + a[20] = bitselect(b[20] ^ b[22], b[20], b[21]); + a[21] = bitselect(b[21] ^ b[23], b[21], b[22]); + a[22] = bitselect(b[22] ^ b[24], b[22], b[23]); + a[23] = bitselect(b[23] ^ b[20], b[23], b[24]); + a[24] = bitselect(b[24] ^ b[21], b[24], b[20]); + } + } + + // Iota + a[0] ^= Keccak_f1600_RC[r]; + + #if !__ENDIAN_LITTLE__ + for (uint i = 0; i != 25; ++i) + a[i] = a[i].yx; + #endif +} + +void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate) +{ + for (uint i = in_size; i != 25; ++i) + { + a[i] = 0; + } +#if __ENDIAN_LITTLE__ + a[in_size] ^= 0x0000000000000001; + a[24-out_size*2] ^= 0x8000000000000000; +#else + a[in_size] ^= 0x0100000000000000; + a[24-out_size*2] ^= 0x0000000000000080; +#endif + + // Originally I unrolled the first and last rounds to interface + // better with surrounding code, however I haven't done this + // without causing the AMD compiler to blow up the VGPR usage. + uint r = 0; + do + { + // This dynamic branch stops the AMD compiler unrolling the loop + // and additionally saves about 33% of the VGPRs, enough to gain another + // wavefront. Ideally we'd get 4 in flight, but 3 is the best I can + // massage out of the compiler. It doesn't really seem to matter how + // much we try and help the compiler save VGPRs because it seems to throw + // that information away, hence the implementation of keccak here + // doesn't bother. + if (isolate) + { + keccak_f1600_round((uint2*)a, r++, 25); + } + } + while (r < 23); + + // final round optimised for digest size + keccak_f1600_round((uint2*)a, r++, out_size); +} + +#define copy(dst, src, count) for (uint i = 0; i != count; ++i) { (dst)[i] = (src)[i]; } + +#define countof(x) (sizeof(x) / sizeof(x[0])) + +uint fnv(uint x, uint y) +{ + return x * FNV_PRIME ^ y; +} + +uint4 fnv4(uint4 x, uint4 y) +{ + return x * FNV_PRIME ^ y; +} + +uint fnv_reduce(uint4 v) +{ + return fnv(fnv(fnv(v.x, v.y), v.z), v.w); +} + +typedef union +{ + ulong ulongs[32 / sizeof(ulong)]; + uint uints[32 / sizeof(uint)]; +} hash32_t; + +typedef union +{ + ulong ulongs[64 / sizeof(ulong)]; + uint4 uint4s[64 / sizeof(uint4)]; +} hash64_t; + +typedef union +{ + uint uints[128 / sizeof(uint)]; + uint4 uint4s[128 / sizeof(uint4)]; +} hash128_t; + +hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate) +{ + hash64_t init; + uint const init_size = countof(init.ulongs); + uint const hash_size = countof(header->ulongs); + + // sha3_512(header .. nonce) + ulong state[25]; + copy(state, header->ulongs, hash_size); + state[hash_size] = nonce; + keccak_f1600_no_absorb(state, hash_size + 1, init_size, isolate); + + copy(init.ulongs, state, init_size); + return init; +} + +uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate) +{ + uint4 mix = init; + + // share init0 + if (thread_id == 0) + *share = mix.x; + barrier(CLK_LOCAL_MEM_FENCE); + uint init0 = *share; + + uint a = 0; + do + { + bool update_share = thread_id == (a/4) % THREADS_PER_HASH; + + #pragma unroll + for (uint i = 0; i != 4; ++i) + { + if (update_share) + { + uint m[4] = { mix.x, mix.y, mix.z, mix.w }; + *share = fnv(init0 ^ (a+i), m[i]) % DAG_SIZE; + } + barrier(CLK_LOCAL_MEM_FENCE); + + mix = fnv4(mix, g_dag[*share].uint4s[thread_id]); + } + } + while ((a += 4) != (ACCESSES & isolate)); + + return fnv_reduce(mix); +} + +hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate) +{ + ulong state[25]; + + hash32_t hash; + uint const hash_size = countof(hash.ulongs); + uint const init_size = countof(init->ulongs); + uint const mix_size = countof(mix->ulongs); + + // keccak_256(keccak_512(header..nonce) .. mix); + copy(state, init->ulongs, init_size); + copy(state + init_size, mix->ulongs, mix_size); + keccak_f1600_no_absorb(state, init_size+mix_size, hash_size, isolate); + + // copy out + copy(hash.ulongs, state, hash_size); + return hash; +} + +hash32_t compute_hash_simple( + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong nonce, + uint isolate + ) +{ + hash64_t init = init_hash(g_header, nonce, isolate); + + hash128_t mix; + for (uint i = 0; i != countof(mix.uint4s); ++i) + { + mix.uint4s[i] = init.uint4s[i % countof(init.uint4s)]; + } + + uint mix_val = mix.uints[0]; + uint init0 = mix.uints[0]; + uint a = 0; + do + { + uint pi = fnv(init0 ^ a, mix_val) % DAG_SIZE; + uint n = (a+1) % countof(mix.uints); + + #pragma unroll + for (uint i = 0; i != countof(mix.uints); ++i) + { + mix.uints[i] = fnv(mix.uints[i], g_dag[pi].uints[i]); + mix_val = i == n ? mix.uints[i] : mix_val; + } + } + while (++a != (ACCESSES & isolate)); + + // reduce to output + hash32_t fnv_mix; + for (uint i = 0; i != countof(fnv_mix.uints); ++i) + { + fnv_mix.uints[i] = fnv_reduce(mix.uint4s[i]); + } + + return final_hash(&init, &fnv_mix, isolate); +} + +typedef union +{ + struct + { + hash64_t init; + uint pad; // avoid lds bank conflicts + }; + hash32_t mix; +} compute_hash_share; + +hash32_t compute_hash( + __local compute_hash_share* share, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong nonce, + uint isolate + ) +{ + uint const gid = get_global_id(0); + + // Compute one init hash per work item. + hash64_t init = init_hash(g_header, nonce, isolate); + + // Threads work together in this phase in groups of 8. + uint const thread_id = gid % THREADS_PER_HASH; + uint const hash_id = (gid % GROUP_SIZE) / THREADS_PER_HASH; + + hash32_t mix; + uint i = 0; + do + { + // share init with other threads + if (i == thread_id) + share[hash_id].init = init; + barrier(CLK_LOCAL_MEM_FENCE); + + uint4 thread_init = share[hash_id].init.uint4s[thread_id % (64 / sizeof(uint4))]; + barrier(CLK_LOCAL_MEM_FENCE); + + uint thread_mix = inner_loop(thread_init, thread_id, share[hash_id].mix.uints, g_dag, isolate); + + share[hash_id].mix.uints[thread_id] = thread_mix; + barrier(CLK_LOCAL_MEM_FENCE); + + if (i == thread_id) + mix = share[hash_id].mix; + barrier(CLK_LOCAL_MEM_FENCE); + } + while (++i != (THREADS_PER_HASH & isolate)); + + return final_hash(&init, &mix, isolate); +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_hash_simple( + __global hash32_t* g_hashes, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + uint isolate + ) +{ + uint const gid = get_global_id(0); + g_hashes[gid] = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate); +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_search_simple( + __global volatile uint* restrict g_output, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + ulong target, + uint isolate + ) +{ + uint const gid = get_global_id(0); + hash32_t hash = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate); + if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target) + { + uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1); + g_output[slot] = gid; + } +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_hash( + __global hash32_t* g_hashes, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + uint isolate + ) +{ + __local compute_hash_share share[HASHES_PER_LOOP]; + + uint const gid = get_global_id(0); + g_hashes[gid] = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate); +} + +__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1))) +__kernel void ethash_search( + __global volatile uint* restrict g_output, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + ulong target, + uint isolate + ) +{ + __local compute_hash_share share[HASHES_PER_LOOP]; + + uint const gid = get_global_id(0); + hash32_t hash = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate); + + if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target) + { + uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1); + g_output[slot] = gid; + } +} From d715f17d87498faa58f0d41dff2753c249b15fc7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 12:15:17 +0200 Subject: [PATCH 065/108] Half-finished Miner/Farm framework. --- libdevcore/Worker.cpp | 16 ++-- libdevcore/Worker.h | 6 +- libethcore/Miner.cpp | 12 +++ libethcore/Miner.h | 146 +++++++++++++++++++++++++++++ libethcore/ProofOfWork.cpp | 56 ++++++----- libethcore/ProofOfWork.h | 126 ++++++++----------------- libethereum/Client.cpp | 2 +- libethereum/Client.h | 4 +- libethereum/Farm.cpp | 12 +++ libethereum/Farm.h | 153 +++++++++++++++++++++++++++++++ libethereum/Miner.cpp | 2 +- libethereum/Miner.h | 97 +------------------- libethereum/TransactionQueue.cpp | 5 +- libethereum/TransactionQueue.h | 14 ++- libethereumx/Ethereum.h | 2 +- 15 files changed, 432 insertions(+), 221 deletions(-) create mode 100644 libethcore/Miner.cpp create mode 100644 libethcore/Miner.h create mode 100644 libethereum/Farm.cpp create mode 100644 libethereum/Farm.h diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 175323620..bc8fe97f2 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -39,12 +39,7 @@ void Worker::startWorking() { setThreadName(m_name.c_str()); startedWorking(); - while (!m_stop) - { - if (m_idleWaitMs) - this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); - doWork(); - } + workLoop(); cnote << "Finishing up worker thread"; doneWorking(); })); @@ -63,3 +58,12 @@ void Worker::stopWorking() cnote << "Stopped" << m_name; } +void Worker::workLoop() +{ + while (!m_stop) + { + if (m_idleWaitMs) + this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); + doWork(); + } +} diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 40bc118aa..6a35d6c4c 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -57,7 +57,11 @@ protected: virtual void startedWorking() {} /// Called continuously following sleep for m_idleWaitMs. - virtual void doWork() = 0; + virtual void doWork() {} + + /// Overrides doWork(); should call shouldStop() often and exit when true. + virtual void workLoop(); + bool shouldStop() const { return m_stop; } /// Called when is to be stopped, just prior to thread being joined. virtual void doneWorking() {} diff --git a/libethcore/Miner.cpp b/libethcore/Miner.cpp new file mode 100644 index 000000000..d6f15866f --- /dev/null +++ b/libethcore/Miner.cpp @@ -0,0 +1,12 @@ +#include "Miner.h" + +Miner::Miner() +{ + +} + +Miner::~Miner() +{ + +} + diff --git a/libethcore/Miner.h b/libethcore/Miner.h new file mode 100644 index 000000000..a7f17e565 --- /dev/null +++ b/libethcore/Miner.h @@ -0,0 +1,146 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file Miner.h + * @author Alex Leverington + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "State.h" + +namespace dev +{ + +namespace eth +{ + +struct WorkPackage +{ + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; +}; + +static const WorkPackage NullWorkPackage; + +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ + void combine(MiningProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } + double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. + double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. + double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. + unsigned hashes = 0; ///< Total number of hashes computed. + unsigned ms = 0; ///< Total number of milliseconds of mining thus far. +}; + +/** + * @brief Class for hosting one or more Miners. + * @warning Must be implemented in a threadsafe manner since it will be called from multiple + * miner threads. + */ +class FarmFace +{ +public: + /** + * @brief Called from a Miner to note a WorkPackage has a solution. + * @param _p The solution. + * @param _wp The WorkPackage that the Solution is for. + * @return true iff the solution was good (implying that mining should be . + */ + virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; +}; + +/** + * @brief A miner - a member and adoptee of the Farm. + */ +class Miner +{ +public: + using ConstructionInfo = std::pair; + + Miner(ConstructionInfo const& _ci): + m_farm(_ci.first), + m_index(_ci.second) + {} + + // API FOR THE FARM TO CALL IN WITH + + void setWork(WorkPackage const& _work = WorkPackage()) + { + Guard l(x_work); + if (_work.headerHash != h256()) + kickOff(m_work); + else if (m_work.headerHash == h256() && _work.headerHash != h256()) + pause(); + m_work = _work; + } + + unsigned index() const { return m_index; } + +protected: + + // REQUIRED TO BE REIMPLEMENTED BY A SUBCLASS: + + /** + * @brief Begin working on a given work package, discarding any previous work. + * @param _work The package for which to find a solution. + */ + virtual void kickOff(WorkPackage const& _work) = 0; + + /** + * @brief No work left to be done. Pause until told to kickOff(). + */ + virtual void pause() = 0; + + // AVAILABLE FOR A SUBCLASS TO CALL: + + /** + * @brief Notes that the Miner found a solution. + * @param _s The solution. + * @return true if the solution was correct and that the miner should pause. + */ + bool submitProof(ProofOfWork::Solution const& _s) + { + if (m_farm) + { + Guard l(x_work); + return m_farm->submitProof(_s, m_work, this); + } + return true; + } + +private: + FarmFace* m_farm = nullptr; + unsigned m_index; + + Mutex x_work; + WorkPackage m_work; +}; + +} +} diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ffa787e3e..1b3b55f4d 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -45,13 +45,38 @@ namespace dev namespace eth { -bool EthashPoW::verify(BlockInfo const& _header) +void Ethash::CPUMiner::workLoop() { - return Ethasher::verify(_header); -} + Solution solution; + + class Miner + { + public: + Miner(BlockInfo const& _header): + m_headerHash(_header.headerHash(WithoutNonce)), + m_params(Ethasher::params(_header)), + m_datasetPointer(Ethasher::get()->full(_header).data()) + {} + + inline h256 mine(uint64_t _nonce) + { + ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce); +// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer); + return h256(m_ethashReturn.result, h256::ConstructFromPointer); + } + + inline h256 lastMixHash() const + { + return h256(m_ethashReturn.mix_hash, h256::ConstructFromPointer); + } + + private: + ethash_return_value m_ethashReturn; + h256 m_headerHash; + ethash_params m_params; + void const* m_datasetPointer; + }; -std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) -{ Ethasher::Miner m(_header); std::pair ret; @@ -70,34 +95,21 @@ std::pair EthashCPU::mine(BlockInfo const& _heade double best = 1e99; // high enough to be effectively infinity :) Solution result; unsigned hashCount = 0; - for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) + for (; !shouldStop(); tryNonce++, hashCount++) { h256 val(m.mine(tryNonce)); best = std::min(best, log2((double)(u256)val)); if (val <= boundary) { - ret.first.completed = true; - assert(Ethasher::eval(_header, (Nonce)(u64)tryNonce).value == val); - result.mixHash = m.lastMixHash(); - result.nonce = u64(tryNonce); - BlockInfo test = _header; - assignResult(result, test); - assert(verify(test)); - break; + if (submitProof(solution)) + return; } } ret.first.hashes = hashCount; ret.first.best = best; ret.second = result; - if (ret.first.completed) - { - BlockInfo test = _header; - assignResult(result, test); - assert(verify(test)); - } - - return ret; + return; } #if ETH_ETHASHCL || !ETH_TRUE diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index bd8ab58db..3ea177a9a 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "BlockInfo.h" +#include "Miner.h" #define FAKE_DAGGER 1 @@ -51,39 +52,56 @@ struct MineInfo bool completed = false; }; -class EthashPoW +class EthashCLHook; + +class Ethash { -public: - struct Solution - { - Nonce nonce; - h256 mixHash; - }; - static bool verify(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } +public: - virtual unsigned defaultTimeout() const { return 100; } - virtual std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; +struct Solution +{ + Nonce nonce; + h256 mixHash; }; -class EthashCPU: public EthashPoW +static bool verify(BlockInfo const& _header); +static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + +class CPUMiner: public Miner, Worker { public: - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} -protected: - Nonce m_last; + static unsigned instances() { return thread::hardware_concurrency(); } + + void kickOff(WorkPackage const& _work) override + { + stopWorking(); + m_work = _work; + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + + WorkPackage m_work; + MineInfo m_info; }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashCLHook; -class EthashCL: public EthashPoW +class GPUMiner: public NewMiner { public: - EthashCL(); - ~EthashCL(); + GPUMiner(ConstructionInfo const& _ci): NewMiner(_ci) + { + + } + + static unsigned instances() { return 1; } std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; unsigned defaultTimeout() const override { return 500; } @@ -96,81 +114,15 @@ protected: std::unique_ptr m_hook; }; -using Ethash = EthashCL; #else -using Ethash = EthashCPU; -#endif -template -class ProofOfWorkEngine: public Evaluator -{ -public: - using Solution = Nonce; +using GPUMiner = CPUMiner; - static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; } - inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r; } - unsigned defaultTimeout() const { return 100; } - -protected: - Nonce m_last; -}; +#endif -class SHA3Evaluator -{ -public: - static h256 eval(h256 const& _root, Nonce const& _nonce) { h256 b[2] = { _root, h256(_nonce) }; return sha3(bytesConstRef((byte const*)&b[0], 64)); } }; -using SHA3ProofOfWork = ProofOfWorkEngine; - using ProofOfWork = Ethash; -template -std::pair::Solution> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) -{ - auto headerHashWithoutNonce = _header.headerHash(WithoutNonce); - auto difficulty = _header.difficulty; - - std::pair ret; - static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()))); - Nonce::Arith s = (m_last = Nonce::random(s_eng)); - - bigint d = (bigint(1) << 256) / difficulty; - ret.first.requirement = log2((double)d); - - // 2^ 0 32 64 128 256 - // [--------*-------------------------] - // - // evaluate until we run out of time - auto startTime = std::chrono::steady_clock::now(); - double best = 1e99; // high enough to be effectively infinity :) - ProofOfWorkEngine::Solution solution; - unsigned h = 0; - for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++) - { - solution = (ProofOfWorkEngine::Solution)s; - auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution); - best = std::min(best, log2((double)e)); - if (e <= d) - { - ret.first.completed = true; - break; - } - } - ret.first.hashes = h; - ret.first.best = best; - ret.second = solution; - - if (ret.first.completed) - { - BlockInfo test = _header; - assignResult(solution, test); - assert(verify(test)); - } - - return ret; -} - } } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index b2f5ff63c..e7c91c03f 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -467,7 +467,7 @@ void Client::doWork() cworkin << "WORK"; h256Set changeds; - auto maintainMiner = [&](Miner& m) + auto maintainMiner = [&](OldMiner& m) { if (m.isComplete()) { diff --git a/libethereum/Client.h b/libethereum/Client.h index ec852afd2..9af501f74 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -72,7 +72,7 @@ private: std::string m_path; }; -class RemoteMiner: public Miner +class RemoteMiner: public OldMiner { public: RemoteMiner() {} @@ -124,7 +124,7 @@ struct ClientDetail: public LogChannel { static const char* name() { return " C */ class Client: public MinerHost, public ClientBase, Worker { - friend class Miner; + friend class OldMiner; public: /// New-style Constructor. diff --git a/libethereum/Farm.cpp b/libethereum/Farm.cpp new file mode 100644 index 000000000..639e4efcf --- /dev/null +++ b/libethereum/Farm.cpp @@ -0,0 +1,12 @@ +#include "Farm.h" + +Farm::Farm() +{ + +} + +Farm::~Farm() +{ + +} + diff --git a/libethereum/Farm.h b/libethereum/Farm.h new file mode 100644 index 000000000..a49038f0d --- /dev/null +++ b/libethereum/Farm.h @@ -0,0 +1,153 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file Miner.h + * @author Alex Leverington + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "Miner.h" + +namespace dev +{ + +namespace eth +{ + +/** + * @brief A collective of Miners. + * Miners ask for work, then submit proofs + * @threadsafe + */ +template +class Farm: public FarmFace +{ +public: + /** + * @brief Sets the current mining mission. + * @param _bi The block (header) we wish to be mining. + */ + void setWork(BlockInfo const& _bi) + { + WriteGuard l(x_work); + m_header = _bi; + m_work.boundary = _bi.boundary(); + m_work.headerHash = _bi.headerHash(WithNonce); + m_work.seedHash = _bi.seedHash(); + ReadGuard l(x_miners); + for (auto const& m: miners) + m->setWork(m_work); + } + + /** + * @brief (Re)start miners for CPU only. + * @returns true if started properly. + */ + bool startCPU() { return start(); } + + /** + * @brief (Re)start miners for GPU only. + * @returns true if started properly. + */ + bool startGPU() { start(); } + + /** + * @brief Stop all mining activities. + */ + void stop() + { + WriteGuard l(x_miners); + m_miners.clear(); + } + + /** + * @brief Get information on the progress of mining this work package. + * @return The progress with mining so far. + */ + MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } + +protected: + // TO BE REIMPLEMENTED BY THE SUBCLASS + /** + * @brief Provides a valid header based upon that received previously with setWork(). + * @param _bi The now-valid header. + * @return true if the header was good and that the Farm should pause until more work is submitted. + */ + virtual bool submitHeader(BlockInfo const& _bi) = 0; + +private: + /** + * @brief Called from a Miner to note a WorkPackage has a solution. + * @param _p The solution. + * @param _wp The WorkPackage that the Solution is for. + * @return true iff the solution was good (implying that mining should be . + */ + bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp, NewMiner* _m) override + { + if (_wp.headerHash != m_work.headerHash) + return false; + + ProofOfWork::assignResult(_p, m_header); + if (submitHeader(m_header)) + { + ReadGuard l(x_miners); + for (std::shared_ptr const& m: m_miners) + if (m.get() != _m) + m->pause(); + m_work.headerHash = h256(); + return true; + } + return false; + } + + /** + * @brief Start a number of miners. + */ + template + bool start() + { + WriteGuard l(x_miners); + if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) + return true; + m_miners.clear(); + m_miners.reserve(MinerType::instances()); + for (unsigned i = 0; i < MinerType::instances(); ++i) + m_miners.push_back(new MinerType(std::make_pair(this, i))); + return true; + } + + mutable SharedMutex x_miners; + std::vector> m_miners; + + mutable SharedMutex x_progress; + MineProgress m_progress; + + mutable SharedMutex x_work; + WorkPackage m_work; + BlockInfo m_header; +}; + +} +} diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp index dc3d9bd9e..b386fe868 100644 --- a/libethereum/Miner.cpp +++ b/libethereum/Miner.cpp @@ -28,7 +28,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -Miner::~Miner() {} +OldMiner::~OldMiner() {} LocalMiner::LocalMiner(MinerHost* _host, unsigned _id) { diff --git a/libethereum/Miner.h b/libethereum/Miner.h index 86d103db5..3abf93770 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "State.h" namespace dev @@ -36,28 +37,6 @@ namespace dev namespace eth { -struct WorkPackage -{ - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; -}; - -static const WorkPackage NullWorkPackage; - -/** - * @brief Describes the progress of a mining operation. - */ -struct MineProgress -{ - void combine(MineProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } - double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. - double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. - double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. - unsigned hashes = 0; ///< Total number of hashes computed. - unsigned ms = 0; ///< Total number of milliseconds of mining thus far. -}; - /** * @brief Class for hosting one or more Miners. * @warning Must be implemented in a threadsafe manner since it will be called from multiple @@ -66,10 +45,6 @@ struct MineProgress class MinerHost { public: - // ============================= NEW API ============================= - virtual WorkPackage const& getWork() const { return NullWorkPackage; } - - // ============================= OLD API ============================= virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. virtual void onProgressed() {} ///< Called once some progress has been made. virtual void onComplete() {} ///< Called once a block is found. @@ -77,17 +52,17 @@ public: virtual bool turbo() const = 0; ///< @returns true iff the Miner should use GPU if possible. }; -class Miner +class OldMiner { public: - virtual ~Miner(); + virtual ~OldMiner(); virtual void noteStateChange() = 0; virtual bool isComplete() const = 0; virtual bytes const& blockData() const = 0; }; -class AsyncMiner: public Miner +class AsyncMiner: public OldMiner { public: /// Null constructor. @@ -187,69 +162,5 @@ private: std::list m_mineHistory; ///< What the history of our mining? }; -/** - * @brief A collective of Miners. - * Miners ask for work, then submit proofs - * @threadsafe - */ -class Farm: public MinerHost -{ -public: - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi); - - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU(); - - /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. - */ - bool startGPU(); - - /** - * @brief Stop all mining activities. - */ - void stop(); - - /** - * @brief Get information on the progress of mining this work package. - * @return The progress with mining so far. - */ - MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } - -protected: - /** - * @brief Called by a Miner to retrieve a work package. Reimplemented from MinerHost. - * @return The work package to solve. - */ - virtual WorkPackage const& getWork() const override { ReadGuard l(x_work); return m_work; } - - /** - * @brief Called from a Miner to note a WorkPackage has a solution. - * @param _p The solution. - * @param _wp The WorkPackage that the Solution is for. - * @return true iff the solution was good (implying that mining should be . - */ - virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; - -private: - mutable SharedMutex x_miners; - std::vector> m_miners; - - mutable SharedMutex x_progress; - MineProgress m_progress; - - mutable SharedMutex x_work; - WorkPackage m_work; -}; - - } } diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 38f3b9429..7c72f53e8 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -28,7 +28,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ImportResult TransactionQueue::import(bytesConstRef _transactionRLP) +ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb) { // Check if we already know this transaction. h256 h = sha3(_transactionRLP); @@ -50,7 +50,8 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP) // If valid, append to blocks. m_current[h] = t; m_known.insert(h); - + if (_cb) + m_callbacks[h] = _cb; ctxq << "Queued vaguely legit-looking transaction" << h.abridged(); } catch (Exception const& _e) diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index 73ce24fbd..ad093b4e5 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -45,8 +46,10 @@ struct TransactionQueueChannel: public LogChannel { static const char* name() { class TransactionQueue { public: - ImportResult import(bytes const& _tx) { return import(&_tx); } - ImportResult import(bytesConstRef _tx); + using ImportCallback = std::function; + + ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx); } + ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback()); void drop(h256 _txHash); @@ -59,10 +62,11 @@ public: void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); } private: - mutable boost::shared_mutex m_lock; ///< General lock. - std::set m_known; ///< Hashes of transactions in both sets. - std::map m_current; ///< Map of SHA3(tx) to tx. + mutable boost::shared_mutex m_lock; ///< General lock. + std::set m_known; ///< Hashes of transactions in both sets. + std::map m_current; ///< Map of SHA3(tx) to tx. std::multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. + std::map> m_callbacks; ///< Called once }; } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 7ff685339..15f00f4ae 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -52,7 +52,7 @@ class Client; */ class Ethereum { - friend class Miner; + friend class OldMiner; public: /// Constructor. After this, everything should be set up to go. From 87a160ab21b9316b6386c94db14aff1e0444c4a0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 15:26:37 +0200 Subject: [PATCH 066/108] GPU Miner prototyped in new API. --- libethcore/Ethasher.cpp | 134 +++++++++++++++++++------------------ libethcore/Ethasher.h | 10 ++- libethcore/ProofOfWork.cpp | 88 ++++++++++++------------ libethcore/ProofOfWork.h | 32 ++++----- 4 files changed, 135 insertions(+), 129 deletions(-) diff --git a/libethcore/Ethasher.cpp b/libethcore/Ethasher.cpp index 6cd2504b3..2118952eb 100644 --- a/libethcore/Ethasher.cpp +++ b/libethcore/Ethasher.cpp @@ -39,6 +39,8 @@ using namespace chrono; using namespace dev; using namespace eth; +#define ETH_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} + Ethasher* dev::eth::Ethasher::s_this = nullptr; Ethasher::~Ethasher() @@ -59,28 +61,35 @@ void Ethasher::killCache(h256 const& _s) void const* Ethasher::light(BlockInfo const& _header) { - RecursiveGuard l(x_this); - if (_header.number > c_ethashEpochLength * 2048) - { - std::ostringstream error; - error << "block number is too high; max is " << c_ethashEpochLength * 2048 << "(was " << _header.number << ")"; - throw std::invalid_argument( error.str() ); - } + return light(_header.seedHash()); +} +void const* Ethasher::light(h256 const& _seedHash) +{ + RecursiveGuard l(x_this); if (!m_lights.count(_header.seedHash())) { - ethash_params p = params((unsigned)_header.number); - m_lights[_header.seedHash()] = ethash_new_light(&p, _header.seedHash().data()); + ethash_params p = params(_seedHash); + m_lights[_seedHash] = ethash_new_light(&p, _seedHash.data()); } - return m_lights[_header.seedHash()]; + return m_lights[_seedHash]; } -#define IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} +bytesConstRef Ethasher::full(BlockInfo const& _header, bytesRef _dest) +{ + return full(_header.seedHash(), _dest); +} -bytesConstRef Ethasher::full(BlockInfo const& _header) +bytesConstRef Ethasher::full(h256 const& _seedHash, bytesRef _dest) { RecursiveGuard l(x_this); - if (!m_fulls.count(_header.seedHash())) + if (m_fulls.count(_seedHash) && _dest) + { + assert(m_fulls.size() <= _dest.size()); + m_fulls.at(_seedHash).copyTo(_dest); + return; + } + if (!m_fulls.count(_seedHash)) { // @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr. /* if (!m_fulls.empty()) @@ -93,9 +102,9 @@ bytesConstRef Ethasher::full(BlockInfo const& _header) boost::filesystem::create_directories(getDataDir("ethash")); } catch (...) {} - auto info = rlpList(c_ethashRevision, _header.seedHash()); + auto info = rlpList(c_ethashRevision, _seedHash); std::string oldMemoFile = getDataDir("ethash") + "/full"; - std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_header.seedHash().ref().cropped(0, 8)); + std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_seedHash.ref().cropped(0, 8)); if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) { // memofile valid - rename. @@ -105,17 +114,26 @@ bytesConstRef Ethasher::full(BlockInfo const& _header) IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); - m_fulls[_header.seedHash()] = contentsNew(memoFile); - if (!m_fulls[_header.seedHash()]) + ethash_params p = params(_seedHash); + assert(!_dest || _dest.size() >= p.full_size); // must be big enough. + + bytesRef r = contentsNew(memoFile, _dest); + if (!r) { - ethash_params p = params((unsigned)_header.number); - m_fulls[_header.seedHash()] = bytesRef(new byte[p.full_size], p.full_size); - auto c = light(_header); - ethash_prep_full(m_fulls[_header.seedHash()].data(), &p, c); - writeFile(memoFile, m_fulls[_header.seedHash()]); + // file didn't exist. + if (_dest) + // buffer was passed in - no insertion into cache nor need to allocate + r = _dest; + else + r = bytesRef(new byte[p.full_size], p.full_size); + ethash_prep_full(r, &p, light(_seedHash)); + writeFile(memoFile, r); } + if (_dest) + return _dest; + m_fulls[_seedHash] = r; } - return m_fulls[_header.seedHash()]; + return m_fulls[_seedHash]; } ethash_params Ethasher::params(BlockInfo const& _header) @@ -123,44 +141,6 @@ ethash_params Ethasher::params(BlockInfo const& _header) return params((unsigned)_header.number); } -void Ethasher::readFull(BlockInfo const& _header, void* _dest) -{ - if (!m_fulls.count(_header.seedHash())) - { - // @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr. -/* if (!m_fulls.empty()) - { - delete [] m_fulls.begin()->second.data(); - m_fulls.erase(m_fulls.begin()); - }*/ - - try { - boost::filesystem::create_directories(getDataDir("ethash")); - } catch (...) {} - - auto info = rlpList(c_ethashRevision, _header.seedHash()); - std::string oldMemoFile = getDataDir("ethash") + "/full"; - std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_header.seedHash().ref().cropped(0, 8)); - if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) - { - // memofile valid - rename. - boost::filesystem::rename(oldMemoFile, memoFile); - } - - IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); - IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); - - ethash_params p = params((unsigned)_header.number); - bytesRef r = contentsNew(memoFile, bytesRef((byte*)_dest, p.full_size)); - if (!r) - { - auto c = light(_header); - ethash_prep_full(_dest, &p, c); - writeFile(memoFile, bytesConstRef((byte*)_dest, p.full_size)); - } - } -} - ethash_params Ethasher::params(unsigned _n) { ethash_params p; @@ -169,6 +149,27 @@ ethash_params Ethasher::params(unsigned _n) return p; } +ethash_params Ethasher::params(h256 const& _seedHash) +{ + unsigned epoch = 0; + try + { + epoch = m_seedHashes.at(_seedHash); + } + catch (...) + { + for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = h256(h)) {} + if (epoch == 2048) + { + std::ostringstream error; + error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (c_ethashEpochLength * 2048); + throw std::invalid_argument(error.str()); + } + m_seedHashes[_seedHash] = epoch; + } + return params(epoch * c_ethashEpochLength); +} + bool Ethasher::verify(BlockInfo const& _header) { if (_header.number >= c_ethashEpochLength * 2048) @@ -208,13 +209,18 @@ bool Ethasher::verify(BlockInfo const& _header) } Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce) +{ + return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); +} + +Ethasher::Result Ethasher::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { auto p = Ethasher::params(_header); ethash_return_value r; - if (Ethasher::get()->m_fulls.count(_header.seedHash())) - ethash_compute_full(&r, Ethasher::get()->full(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); + if (Ethasher::get()->m_fulls.count(_seedHash)) + ethash_compute_full(&r, Ethasher::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); else - ethash_compute_light(&r, Ethasher::get()->light(_header), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); + ethash_compute_light(&r, Ethasher::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce); // cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; } diff --git a/libethcore/Ethasher.h b/libethcore/Ethasher.h index 32622929f..f57c2f4f6 100644 --- a/libethcore/Ethasher.h +++ b/libethcore/Ethasher.h @@ -52,12 +52,14 @@ public: using FullType = void const*; LightType light(BlockInfo const& _header); - bytesConstRef full(BlockInfo const& _header); + LightType light(h256 const& _header); + bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef()); + bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef()); + static ethash_params params(BlockInfo const& _header); + static ethash_params params(h256 const& _seedHash); static ethash_params params(unsigned _n); - void readFull(BlockInfo const& _header, void* _dest); - struct Result { h256 value; @@ -66,6 +68,7 @@ public: static Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } static Result eval(BlockInfo const& _header, Nonce const& _nonce); + static Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); static bool verify(BlockInfo const& _header); class Miner @@ -103,6 +106,7 @@ private: RecursiveMutex x_this; std::map m_lights; std::map m_fulls; + std::map m_seedHashes; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index 1b3b55f4d..97488ee35 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -31,7 +31,7 @@ #include #include #include -#if ETH_ETHASHCL +#if ETH_ETHASHCL || !ETH_TRUE #include #endif #include "BlockInfo.h" @@ -134,10 +134,15 @@ public: }; */ -struct EthashCLHook: public ethash_cl_miner::search_hook +namespace dev { namespace eth { +class EthashCLHook: public ethash_cl_miner::search_hook { +public: + EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + void abort() { + Guard l(x_all); if (m_aborted) return; // cdebug << "Attempting to abort"; @@ -147,21 +152,23 @@ struct EthashCLHook: public ethash_cl_miner::search_hook if (!m_aborted) cwarn << "Couldn't abort. Abandoning OpenCL process."; m_aborted = m_abort = false; - m_found.clear(); } - vector fetchFound() { vector ret; Guard l(x_all); std::swap(ret, m_found); return ret; } uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; } protected: virtual bool found(uint64_t const* _nonces, uint32_t _count) override { - Guard l(x_all); - for (unsigned i = 0; i < _count; ++i) - m_found.push_back((Nonce)(u64)_nonces[i]); - m_aborted = true; // cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); - return true; + for (uint32_t i = 0; i < _count; ++i) + { + if (m_owner->found(_nonces[i])) + { + m_aborted = true; + return true; + } + } + return false; } virtual bool searched(uint64_t _startNonce, uint32_t _count) override @@ -180,66 +187,53 @@ protected: private: Mutex x_all; - vector m_found; uint64_t m_total; uint64_t m_last; bool m_abort = false; bool m_aborted = true; + Ethash::GPUMiner* m_owner = nullptr; }; -EthashCL::EthashCL(): - m_hook(new EthashCLHook) +} } + +Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): + Miner(_ci), + m_hook(new EthashCLHook(this)) { } -EthashCL::~EthashCL() +void Ethash::GPUMiner::report(uint64_t _nonce) { + Nonce n = (Nonce)(u64)_nonce; + Ethasher::Result r = Ethasher::eval(m_work.seedHash, m_work.headerHash, n); + if (r.value < m_work.boundary) + return submitProof(Solution{n, r.mixHash}); + return false; } -std::pair EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool) +void Ethash::GPUMiner::kickOff(WorkPackage const& _work) { - if (!m_lastHeader || m_lastHeader.seedHash() != _header.seedHash()) + if (!m_miner || m_minerSeed != _work.seedHash) { if (m_miner) m_hook->abort(); m_miner.reset(new ethash_cl_miner); - auto cb = [&](void* d) { - Ethasher::get()->readFull(_header, d); - }; - m_miner->init(Ethasher::params(_header), cb, 32); + auto p = Ethasher::params(_work.seedHash); + auto cb = [&](void* d) { Ethasher::get()->readFull(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; + m_miner->init(p, cb, 32); } - if (m_lastHeader != _header) + if (m_lastWork.headerHash != _work.headerHash) { m_hook->abort(); - static std::random_device s_eng; - auto hh = _header.headerHash(WithoutNonce); - uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_header.boundary() >> 192); - m_miner->search(hh.data(), upper64OfBoundary, *m_hook); + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); + m_miner->search(_work.headerHash, upper64OfBoundary, *m_hook); } - m_lastHeader = _header; - - MineInfo mi; - Solution proof; - mi.requirement = log2((double)(u256)_header.boundary()); - mi.best = 0; - - std::this_thread::sleep_for(chrono::milliseconds(_msTimeout)); + m_work = _work; +} - mi.hashes += m_hook->fetchTotal(); - auto found = m_hook->fetchFound(); - if (!found.empty()) - { - for (auto const& n: found) - { - auto result = Ethasher::eval(_header, n); - if (result.value < _header.boundary()) - { - mi.completed = true; - proof = Solution{n, result.mixHash}; - } - } - } - return std::make_pair(mi, proof); +void Ethash::GPUMiner::pause() +{ + m_hook->abort(); } #endif diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 3ea177a9a..f66bc77c9 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -34,7 +34,6 @@ #define FAKE_DAGGER 1 class ethash_cl_miner; -struct ethash_cl_search_hook; namespace dev { @@ -52,8 +51,6 @@ struct MineInfo bool completed = false; }; -class EthashCLHook; - class Ethash { @@ -75,6 +72,7 @@ public: static unsigned instances() { return thread::hardware_concurrency(); } +protected: void kickOff(WorkPackage const& _work) override { stopWorking(); @@ -93,25 +91,29 @@ private: #if ETH_ETHASHCL || !ETH_TRUE -class GPUMiner: public NewMiner +class EthashCLHook; + +class GPUMiner: public Miner { -public: - GPUMiner(ConstructionInfo const& _ci): NewMiner(_ci) - { + friend class EthashCLHook; - } +public: + GPUMiner(ConstructionInfo const& _ci); static unsigned instances() { return 1; } - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; - unsigned defaultTimeout() const override { return 500; } - protected: - Nonce m_last; - BlockInfo m_lastHeader; - Nonce m_mined; - std::unique_ptr m_miner; + void kickOff(WorkPackage const& _work) override; + void pause() override; + +private: + void report(uint64_t _nonce); + std::unique_ptr m_hook; + std::unique_ptr m_miner; + h256 m_minerSeed; + WorkPackage m_lastWork; ///< Work loaded into m_miner. + MineInfo m_info; }; #else From c1045d47117704eb30616a42ae733bd8dbfbfd76 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 20:17:33 +0200 Subject: [PATCH 067/108] Refactor just about everything important in the core. TODO: make compile :-) --- libethcore/Common.cpp | 2 - libethcore/Common.h | 37 +++ libethcore/Ethash.cpp | 241 ++++++++++++++++ libethcore/Ethash.h | 128 +++++++++ libethcore/{Ethasher.cpp => EthashAux.cpp} | 144 ++++------ libethcore/EthashAux.h | 63 +++++ libethcore/Ethasher.h | 113 -------- libethcore/Miner.cpp | 12 - libethcore/Miner.h | 38 ++- libethcore/ProofOfWork.cpp | 220 +-------------- libethcore/ProofOfWork.h | 109 +------- libethereum/BlockChain.cpp | 29 +- libethereum/BlockChain.h | 5 +- libethereum/BlockQueue.cpp | 1 + libethereum/BlockQueue.h | 3 + libethereum/Client.cpp | 309 +++++++++------------ libethereum/Client.h | 67 +++-- libethereum/ClientBase.h | 2 - libethereum/Farm.cpp | 12 - libethereum/Farm.h | 41 +-- libethereum/State.cpp | 14 - libethereum/State.h | 31 +-- libethereum/TransactionQueue.cpp | 1 + libethereum/TransactionQueue.h | 6 +- 24 files changed, 801 insertions(+), 827 deletions(-) create mode 100644 libethcore/Ethash.cpp create mode 100644 libethcore/Ethash.h rename libethcore/{Ethasher.cpp => EthashAux.cpp} (60%) create mode 100644 libethcore/EthashAux.h delete mode 100644 libethcore/Ethasher.h diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 572ade3e2..f0e749aaa 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -22,7 +22,6 @@ #include "Common.h" #include #include -#include "Ethasher.h" #include "Exceptions.h" using namespace std; using namespace dev; @@ -33,7 +32,6 @@ namespace dev namespace eth { -const unsigned c_ethashVersion = c_ethashRevision; const unsigned c_protocolVersion = 60; const unsigned c_minorProtocolVersion = 0; const unsigned c_databaseBaseVersion = 9; diff --git a/libethcore/Common.h b/libethcore/Common.h index ec826d2d1..b5291648b 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -96,5 +96,42 @@ enum class ImportResult BadChain }; +class Signal; + +class Handler +{ +public: + Handler() = default; + Handler(Handler const&) = delete; + ~Handler() { reset(); } + + Handler& operator=(Handler const& _h) = delete; + + void reset(); + +private: + Handler(unsigned _i, Signal* _s): m_i(_i), m_s(_s) {} + + unsigned m_i = 0; + Signal* m_s = nullptr; +}; + +/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight. +class Signal +{ +public: + using Callback = std::function; + using Callbacks = std::vector; + + Handler add(Callback const& _h) { auto n = m_onReady.size() ? m_onReady.rbegin()->first + 1 : 0; m_onReady[n] = _h; return Handler(n, this); } + + void operator()() { for (auto const& f: m_fire) f.second(); } + +private: + std::map m_fire; +}; + +inline void Handler::reset() { if (m_s) m_s->m_fire->erase(m_i); m_s = nullptr; } + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp new file mode 100644 index 000000000..82e349b4c --- /dev/null +++ b/libethcore/Ethash.cpp @@ -0,0 +1,241 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Ethash.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Ethash.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if ETH_ETHASHCL || !ETH_TRUE +#include +#endif +#include "BlockInfo.h" +#include "EthashAux.h" +using namespace std; +using namespace std::chrono; + +namespace dev +{ +namespace eth +{ + +const Ethash::WorkPackage Ethash::NullWorkPackage; + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::prep(BlockInfo const& _header) +{ + if (_header.number % ETHASH_EPOCH_LENGTH == 1) + EthashAux::full(bi); +} + +bool Ethash::preVerify(BlockInfo const& _header) +{ + if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + return false; + + h256 boundary = u256((bigint(1) << 256) / _header.difficulty); + + return ethash_quick_check_difficulty( + _header.headerHash(WithoutNonce).data(), + (uint64_t)(u64)_header.nonce, + _header.mixHash.data(), + boundary.data()); +} + +bool Ethash::verify(BlockInfo const& _header) +{ + bool pre = preVerify(_header); +#if !ETH_DEBUG + if (!pre) + return false; +#endif + + h256 boundary = u256((bigint(1) << 256) / _header.difficulty); + auto result = eval(_header); + bool slow = result.value <= boundary && result.mixHash == _header.mixHash; + +#if ETH_DEBUG || !ETH_TRUE + if (!pre && slow) + { + cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; + cwarn << "headerHash:" << _header.headerHash(WithoutNonce); + cwarn << "nonce:" << _header.nonce; + cwarn << "mixHash:" << _header.mixHash; + cwarn << "difficulty:" << _header.difficulty; + cwarn << "boundary:" << boundary; + cwarn << "result.value:" << result.value; + cwarn << "result.mixHash:" << result.mixHash; + } +#endif + + return slow; +} + +void Ethash::CPUMiner::workLoop() +{ + auto tid = std::this_thread::get_id(); + static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); + + uint64_t tryNonce = Nonce::random(s_eng); + ethash_return_value ethashReturn; + + auto p = Ethash::params(m_work.seedHash); + void const* dagPointer = Ethash::full(m_work.headerHash).data(); + uint8_t const* headerHashPointer = m_work.headerHash.data(); + h256 boundary = m_work.boundary(); + unsigned hashCount = 0; + for (; !shouldStop(); tryNonce++, hashCount++) + { + ethash_compute_full(ðashReturn, dagPointer, &p, headerHashPointer, tryNonce); + h256 value = h256(ethashReturn.result, h256::ConstructFromPointer); + if (value <= boundary && submitProof(Solution{value, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) + break; + } +} + +#if ETH_ETHASHCL || !ETH_TRUE + +namespace dev { namespace eth { + +class EthashCLHook: public ethash_cl_miner::search_hook +{ +public: + EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + + void abort() + { + Guard l(x_all); + if (m_aborted) + return; +// cdebug << "Attempting to abort"; + m_abort = true; + for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) + std::this_thread::sleep_for(chrono::milliseconds(30)); + if (!m_aborted) + cwarn << "Couldn't abort. Abandoning OpenCL process."; + m_aborted = m_abort = false; + } + + uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; } + +protected: + virtual bool found(uint64_t const* _nonces, uint32_t _count) override + { +// cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); + for (uint32_t i = 0; i < _count; ++i) + { + if (m_owner->found(_nonces[i])) + { + m_aborted = true; + return true; + } + } + return false; + } + + virtual bool searched(uint64_t _startNonce, uint32_t _count) override + { + Guard l(x_all); +// cdebug << "Searched" << _count << "from" << _startNonce; + m_total += _count; + m_last = _startNonce + _count; + if (m_abort) + { + m_aborted = true; + return true; + } + return false; + } + +private: + Mutex x_all; + uint64_t m_total; + uint64_t m_last; + bool m_abort = false; + bool m_aborted = true; + Ethash::GPUMiner* m_owner = nullptr; +}; + +} } + +Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): + Miner(_ci), + m_hook(new EthashCLHook(this)) +{ +} + +void Ethash::GPUMiner::report(uint64_t _nonce) +{ + Nonce n = (Nonce)(u64)_nonce; + Result r = Ethash::eval(m_work.seedHash, m_work.headerHash, n); + if (r.value < m_work.boundary) + return submitProof(Solution{n, r.mixHash}); + return false; +} + +void Ethash::GPUMiner::kickOff(WorkPackage const& _work) +{ + if (!m_miner || m_minerSeed != _work.seedHash) + { + if (m_miner) + m_hook->abort(); + m_miner.reset(new ethash_cl_miner); + auto p = Ethash::params(_work.seedHash); + auto cb = [&](void* d) { EthashAux::readFull(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; + m_miner->init(p, cb, 32); + } + if (m_lastWork.headerHash != _work.headerHash) + { + m_hook->abort(); + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); + m_miner->search(_work.headerHash, upper64OfBoundary, *m_hook); + } + m_work = _work; +} + +void Ethash::GPUMiner::pause() +{ + m_hook->abort(); +} + +#endif + +} +} diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h new file mode 100644 index 000000000..bdd6bf6c5 --- /dev/null +++ b/libethcore/Ethash.h @@ -0,0 +1,128 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Ethash.h + * @author Gav Wood + * @date 2014 + * + * A proof of work algorithm. + */ + +#pragma once + +#include +#include +#include +#include "Common.h" +#include "BlockInfo.h" +#include "Miner.h" + +class ethash_cl_miner; + +namespace dev +{ +namespace eth +{ + +class Ethash +{ +public: + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + static std::string name(); + static unsigned revision(); + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + static void prep(BlockInfo const& _header); + + class CPUMiner: public Miner, Worker + { + public: + CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} + + static unsigned instances() { return thread::hardware_concurrency(); } + + protected: + void kickOff(WorkPackage const& _work) override + { + stopWorking(); + m_work = _work; + startWorking(); + } + + void pause() override { stopWorking(); } + + private: + void workLoop() override; + + WorkPackage m_work; + MineInfo m_info; + }; + +#if ETH_ETHASHCL || !ETH_TRUE + class EthashCLHook; + class GPUMiner: public Miner + { + friend class EthashCLHook; + + public: + GPUMiner(ConstructionInfo const& _ci); + + static unsigned instances() { return 1; } + + protected: + void kickOff(WorkPackage const& _work) override; + void pause() override; + + private: + void report(uint64_t _nonce); + + std::unique_ptr m_hook; + std::unique_ptr m_miner; + h256 m_minerSeed; + WorkPackage m_lastWork; ///< Work loaded into m_miner. + MineInfo m_info; + }; +#else + using GPUMiner = CPUMiner; +#endif +}; + +using ProofOfWork = Ethash; +using Solution = Ethash::Solution; + +} +} diff --git a/libethcore/Ethasher.cpp b/libethcore/EthashAux.cpp similarity index 60% rename from libethcore/Ethasher.cpp rename to libethcore/EthashAux.cpp index 2118952eb..a6143e264 100644 --- a/libethcore/Ethasher.cpp +++ b/libethcore/EthashAux.cpp @@ -14,11 +14,13 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file Ethasher.cpp +/** @file EthashAux.cpp * @author Gav Wood * @date 2014 */ +#include "EthashAux.h" + #include #include #include @@ -33,7 +35,6 @@ #include #include #include "BlockInfo.h" -#include "Ethasher.h" using namespace std; using namespace chrono; using namespace dev; @@ -41,15 +42,50 @@ using namespace eth; #define ETH_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} -Ethasher* dev::eth::Ethasher::s_this = nullptr; +EthashAux* dev::eth::EthashAux::s_this = nullptr; -Ethasher::~Ethasher() +EthashAux::~EthashAux() { while (!m_lights.empty()) killCache(m_lights.begin()->first); } -void Ethasher::killCache(h256 const& _s) +ethash_params EthashAux::params(BlockInfo const& _header) +{ + return params((unsigned)_header.number); +} + +ethash_params EthashAux::params(unsigned _n) +{ + ethash_params p; + p.cache_size = ethash_get_cachesize(_n); + p.full_size = ethash_get_datasize(_n); + return p; +} + +ethash_params EthashAux::params(h256 const& _seedHash) +{ + RecursiveGuard l(get()->x_this); + unsigned epoch = 0; + try + { + epoch = get()->m_seedHashes.at(_seedHash); + } + catch (...) + { + for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = h256(h)) {} + if (epoch == 2048) + { + std::ostringstream error; + error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048); + throw std::invalid_argument(error.str()); + } + get()->m_seedHashes[_seedHash] = epoch; + } + return params(epoch * ETHASH_EPOCH_LENGTH); +} + +void EthashAux::killCache(h256 const& _s) { RecursiveGuard l(x_this); if (m_lights.count(_s)) @@ -59,12 +95,12 @@ void Ethasher::killCache(h256 const& _s) } } -void const* Ethasher::light(BlockInfo const& _header) +void const* EthashAux::light(BlockInfo const& _header) { return light(_header.seedHash()); } -void const* Ethasher::light(h256 const& _seedHash) +void const* EthashAux::light(h256 const& _seedHash) { RecursiveGuard l(x_this); if (!m_lights.count(_header.seedHash())) @@ -75,12 +111,12 @@ void const* Ethasher::light(h256 const& _seedHash) return m_lights[_seedHash]; } -bytesConstRef Ethasher::full(BlockInfo const& _header, bytesRef _dest) +bytesConstRef EthashAux::full(BlockInfo const& _header, bytesRef _dest) { return full(_header.seedHash(), _dest); } -bytesConstRef Ethasher::full(h256 const& _seedHash, bytesRef _dest) +bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) { RecursiveGuard l(x_this); if (m_fulls.count(_seedHash) && _dest) @@ -102,9 +138,9 @@ bytesConstRef Ethasher::full(h256 const& _seedHash, bytesRef _dest) boost::filesystem::create_directories(getDataDir("ethash")); } catch (...) {} - auto info = rlpList(c_ethashRevision, _seedHash); + auto info = rlpList(revision(), _seedHash); std::string oldMemoFile = getDataDir("ethash") + "/full"; - std::string memoFile = getDataDir("ethash") + "/full-R" + toString(c_ethashRevision) + "-" + toHex(_seedHash.ref().cropped(0, 8)); + std::string memoFile = getDataDir("ethash") + "/full-R" + toString(ETHASH_REVISION) + "-" + toHex(_seedHash.ref().cropped(0, 8)); if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) { // memofile valid - rename. @@ -136,91 +172,19 @@ bytesConstRef Ethasher::full(h256 const& _seedHash, bytesRef _dest) return m_fulls[_seedHash]; } -ethash_params Ethasher::params(BlockInfo const& _header) -{ - return params((unsigned)_header.number); -} - -ethash_params Ethasher::params(unsigned _n) -{ - ethash_params p; - p.cache_size = ethash_get_cachesize(_n); - p.full_size = ethash_get_datasize(_n); - return p; -} - -ethash_params Ethasher::params(h256 const& _seedHash) -{ - unsigned epoch = 0; - try - { - epoch = m_seedHashes.at(_seedHash); - } - catch (...) - { - for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = h256(h)) {} - if (epoch == 2048) - { - std::ostringstream error; - error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (c_ethashEpochLength * 2048); - throw std::invalid_argument(error.str()); - } - m_seedHashes[_seedHash] = epoch; - } - return params(epoch * c_ethashEpochLength); -} - -bool Ethasher::verify(BlockInfo const& _header) -{ - if (_header.number >= c_ethashEpochLength * 2048) - return false; - - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - - bool quick = ethash_quick_check_difficulty( - _header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - _header.mixHash.data(), - boundary.data()); - -#if !ETH_DEBUG - if (!quick) - return false; -#endif - - auto result = eval(_header); - bool slow = result.value <= boundary && result.mixHash == _header.mixHash; - -#if ETH_DEBUG - if (!quick && slow) - { - cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << boundary; - cwarn << "result.value:" << result.value; - cwarn << "result.mixHash:" << result.mixHash; - } -#endif - - return slow; -} - -Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce) +Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); } -Ethasher::Result Ethasher::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { - auto p = Ethasher::params(_header); + auto p = EthashAux::params(_header); ethash_return_value r; - if (Ethasher::get()->m_fulls.count(_seedHash)) - ethash_compute_full(&r, Ethasher::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); + if (EthashAux::get()->m_fulls.count(_seedHash)) + ethash_compute_full(&r, EthashAux::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); else - ethash_compute_light(&r, Ethasher::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce); -// cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); + ethash_compute_light(&r, EthashAux::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce); +// cdebug << "EthashAux::eval sha3(cache):" << sha3(EthashAux::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h new file mode 100644 index 000000000..bfd01a594 --- /dev/null +++ b/libethcore/EthashAux.h @@ -0,0 +1,63 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file EthashAux.cpp + * @author Gav Wood + * @date 2014 + */ + +#include +#include "Ethash.h" + +namespace dev +{ +namespace eth{ + +class EthashAux +{ + EthashAux() {} + ~EthashAux(); + + static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; } + + using LightType = void const*; + using FullType = void const*; + + static ethash_params params(BlockInfo const& _header); + static ethash_params params(h256 const& _seedHash); + static ethash_params params(unsigned _n); + static LightType light(BlockInfo const& _header); + static LightType light(h256 const& _header); + static bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef()); + static bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef()); + + static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); + static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + +private: + void killCache(h256 const& _s); + + static Ethash* s_this; + RecursiveMutex x_this; + + std::map m_lights; + std::map m_fulls; + std::map m_seedHashes; +}; + +} +} diff --git a/libethcore/Ethasher.h b/libethcore/Ethasher.h deleted file mode 100644 index f57c2f4f6..000000000 --- a/libethcore/Ethasher.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Ethasher.h - * @author Gav Wood - * @date 2014 - * - * ProofOfWork algorithm. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include // TODO: REMOVE once everything merged into this class and an opaque API can be provided. -static const unsigned c_ethashRevision = ETHASH_REVISION; -static const unsigned c_ethashEpochLength = ETHASH_EPOCH_LENGTH; -#include "Common.h" -#include "BlockInfo.h" - -namespace dev -{ -namespace eth -{ - -class Ethasher -{ -public: - Ethasher() {} - ~Ethasher(); - - static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; } - - using LightType = void const*; - using FullType = void const*; - - LightType light(BlockInfo const& _header); - LightType light(h256 const& _header); - bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef()); - bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef()); - - static ethash_params params(BlockInfo const& _header); - static ethash_params params(h256 const& _seedHash); - static ethash_params params(unsigned _n); - - struct Result - { - h256 value; - h256 mixHash; - }; - - static Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } - static Result eval(BlockInfo const& _header, Nonce const& _nonce); - static Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); - static bool verify(BlockInfo const& _header); - - class Miner - { - public: - Miner(BlockInfo const& _header): - m_headerHash(_header.headerHash(WithoutNonce)), - m_params(Ethasher::params(_header)), - m_datasetPointer(Ethasher::get()->full(_header).data()) - {} - - inline h256 mine(uint64_t _nonce) - { - ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce); -// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer); - return h256(m_ethashReturn.result, h256::ConstructFromPointer); - } - - inline h256 lastMixHash() const - { - return h256(m_ethashReturn.mix_hash, h256::ConstructFromPointer); - } - - private: - ethash_return_value m_ethashReturn; - h256 m_headerHash; - ethash_params m_params; - void const* m_datasetPointer; - }; - -private: - void killCache(h256 const& _s); - - static Ethasher* s_this; - RecursiveMutex x_this; - std::map m_lights; - std::map m_fulls; - std::map m_seedHashes; -}; - -} -} diff --git a/libethcore/Miner.cpp b/libethcore/Miner.cpp index d6f15866f..e69de29bb 100644 --- a/libethcore/Miner.cpp +++ b/libethcore/Miner.cpp @@ -1,12 +0,0 @@ -#include "Miner.h" - -Miner::Miner() -{ - -} - -Miner::~Miner() -{ - -} - diff --git a/libethcore/Miner.h b/libethcore/Miner.h index a7f17e565..e7157e660 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -15,9 +15,8 @@ along with cpp-ethereum. If not, see . */ /** @file Miner.h - * @author Alex Leverington * @author Gav Wood - * @date 2014 + * @date 2015 */ #pragma once @@ -28,7 +27,6 @@ #include #include #include -#include "State.h" namespace dev { @@ -36,15 +34,17 @@ namespace dev namespace eth { -struct WorkPackage +struct MineInfo { - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; + MineInfo() = default; + MineInfo(bool _completed): completed(_completed) {} + void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; } + double requirement = 0; + double best = 1e99; + unsigned hashes = 0; + bool completed = false; }; -static const WorkPackage NullWorkPackage; - /** * @brief Describes the progress of a mining operation. */ @@ -58,30 +58,40 @@ struct MiningProgress unsigned ms = 0; ///< Total number of milliseconds of mining thus far. }; +template class Miner; + /** * @brief Class for hosting one or more Miners. * @warning Must be implemented in a threadsafe manner since it will be called from multiple * miner threads. */ -class FarmFace +template class FarmFace { public: + using WorkPackage = typename PoW::WorkPackage; + using Solution = typename PoW::Solution; + using Miner = Miner; + /** * @brief Called from a Miner to note a WorkPackage has a solution. * @param _p The solution. * @param _wp The WorkPackage that the Solution is for. + * @param _finder The miner that found it. * @return true iff the solution was good (implying that mining should be . */ - virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; + virtual bool submitProof(Solution const& _p, WorkPackage const& _wp, Miner* _finder) = 0; }; /** * @brief A miner - a member and adoptee of the Farm. */ -class Miner +template class Miner { public: - using ConstructionInfo = std::pair; + using ConstructionInfo = std::pair*, unsigned>; + using WorkPackage = typename PoW::WorkPackage; + using Solution = typename PoW::Solution; + using FarmFace = FarmFace; Miner(ConstructionInfo const& _ci): m_farm(_ci.first), @@ -124,7 +134,7 @@ protected: * @param _s The solution. * @return true if the solution was correct and that the miner should pause. */ - bool submitProof(ProofOfWork::Solution const& _s) + bool submitProof(Solution const& _s) { if (m_farm) { diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index 97488ee35..ec910f7f2 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -19,224 +19,6 @@ * @date 2014 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if ETH_ETHASHCL || !ETH_TRUE -#include -#endif -#include "BlockInfo.h" -#include "Ethasher.h" #include "ProofOfWork.h" using namespace std; -using namespace std::chrono; - -namespace dev -{ -namespace eth -{ - -void Ethash::CPUMiner::workLoop() -{ - Solution solution; - - class Miner - { - public: - Miner(BlockInfo const& _header): - m_headerHash(_header.headerHash(WithoutNonce)), - m_params(Ethasher::params(_header)), - m_datasetPointer(Ethasher::get()->full(_header).data()) - {} - - inline h256 mine(uint64_t _nonce) - { - ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce); -// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer); - return h256(m_ethashReturn.result, h256::ConstructFromPointer); - } - - inline h256 lastMixHash() const - { - return h256(m_ethashReturn.mix_hash, h256::ConstructFromPointer); - } - - private: - ethash_return_value m_ethashReturn; - h256 m_headerHash; - ethash_params m_params; - void const* m_datasetPointer; - }; - - Ethasher::Miner m(_header); - - std::pair ret; - auto tid = std::this_thread::get_id(); - static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); - uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng)); - - h256 boundary = _header.boundary(); - ret.first.requirement = log2((double)(u256)boundary); - - // 2^ 0 32 64 128 256 - // [--------*-------------------------] - // - // evaluate until we run out of time - auto startTime = std::chrono::steady_clock::now(); - double best = 1e99; // high enough to be effectively infinity :) - Solution result; - unsigned hashCount = 0; - for (; !shouldStop(); tryNonce++, hashCount++) - { - h256 val(m.mine(tryNonce)); - best = std::min(best, log2((double)(u256)val)); - if (val <= boundary) - { - if (submitProof(solution)) - return; - } - } - ret.first.hashes = hashCount; - ret.first.best = best; - ret.second = result; - - return; -} - -#if ETH_ETHASHCL || !ETH_TRUE - -/* -class ethash_cl_miner -{ -public: - struct search_hook - { - // reports progress, return true to abort - virtual bool found(uint64_t const* nonces, uint32_t count) = 0; - virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; - }; - - ethash_cl_miner(); - - bool init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size = 64); - - void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); - void search(uint8_t const* header, uint64_t target, search_hook& hook); -}; -*/ - -namespace dev { namespace eth { -class EthashCLHook: public ethash_cl_miner::search_hook -{ -public: - EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} - - void abort() - { - Guard l(x_all); - if (m_aborted) - return; -// cdebug << "Attempting to abort"; - m_abort = true; - for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) - std::this_thread::sleep_for(chrono::milliseconds(30)); - if (!m_aborted) - cwarn << "Couldn't abort. Abandoning OpenCL process."; - m_aborted = m_abort = false; - } - - uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; } - -protected: - virtual bool found(uint64_t const* _nonces, uint32_t _count) override - { -// cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); - for (uint32_t i = 0; i < _count; ++i) - { - if (m_owner->found(_nonces[i])) - { - m_aborted = true; - return true; - } - } - return false; - } - - virtual bool searched(uint64_t _startNonce, uint32_t _count) override - { - Guard l(x_all); -// cdebug << "Searched" << _count << "from" << _startNonce; - m_total += _count; - m_last = _startNonce + _count; - if (m_abort) - { - m_aborted = true; - return true; - } - return false; - } - -private: - Mutex x_all; - uint64_t m_total; - uint64_t m_last; - bool m_abort = false; - bool m_aborted = true; - Ethash::GPUMiner* m_owner = nullptr; -}; - -} } - -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): - Miner(_ci), - m_hook(new EthashCLHook(this)) -{ -} - -void Ethash::GPUMiner::report(uint64_t _nonce) -{ - Nonce n = (Nonce)(u64)_nonce; - Ethasher::Result r = Ethasher::eval(m_work.seedHash, m_work.headerHash, n); - if (r.value < m_work.boundary) - return submitProof(Solution{n, r.mixHash}); - return false; -} - -void Ethash::GPUMiner::kickOff(WorkPackage const& _work) -{ - if (!m_miner || m_minerSeed != _work.seedHash) - { - if (m_miner) - m_hook->abort(); - m_miner.reset(new ethash_cl_miner); - auto p = Ethasher::params(_work.seedHash); - auto cb = [&](void* d) { Ethasher::get()->readFull(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; - m_miner->init(p, cb, 32); - } - if (m_lastWork.headerHash != _work.headerHash) - { - m_hook->abort(); - uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); - m_miner->search(_work.headerHash, upper64OfBoundary, *m_hook); - } - m_work = _work; -} - -void Ethash::GPUMiner::pause() -{ - m_hook->abort(); -} - -#endif - -} -} +using namespace dev; diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index f66bc77c9..764207aef 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -18,112 +18,29 @@ * @author Gav Wood * @date 2014 * - * ProofOfWork algorithm. Or not. + * Determines the PoW algorithm. */ #pragma once -#include -#include -#include -#include -#include "Common.h" -#include "BlockInfo.h" -#include "Miner.h" - -#define FAKE_DAGGER 1 - -class ethash_cl_miner; +#include "Ethash.h" namespace dev { namespace eth { -struct MineInfo -{ - MineInfo() = default; - MineInfo(bool _completed): completed(_completed) {} - void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; } - double requirement = 0; - double best = 1e99; - unsigned hashes = 0; - bool completed = false; -}; - -class Ethash -{ - -public: - -struct Solution -{ - Nonce nonce; - h256 mixHash; -}; - -static bool verify(BlockInfo const& _header); -static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } - -class CPUMiner: public Miner, Worker -{ -public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - static unsigned instances() { return thread::hardware_concurrency(); } - -protected: - void kickOff(WorkPackage const& _work) override - { - stopWorking(); - m_work = _work; - startWorking(); - } - - void pause() override { stopWorking(); } - -private: - void workLoop() override; - - WorkPackage m_work; - MineInfo m_info; -}; - -#if ETH_ETHASHCL || !ETH_TRUE - -class EthashCLHook; - -class GPUMiner: public Miner -{ - friend class EthashCLHook; - -public: - GPUMiner(ConstructionInfo const& _ci); - - static unsigned instances() { return 1; } - -protected: - void kickOff(WorkPackage const& _work) override; - void pause() override; - -private: - void report(uint64_t _nonce); - - std::unique_ptr m_hook; - std::unique_ptr m_miner; - h256 m_minerSeed; - WorkPackage m_lastWork; ///< Work loaded into m_miner. - MineInfo m_info; -}; - -#else - -using GPUMiner = CPUMiner; - -#endif - -}; - +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * void assignResult(BlockInfo&, Result) + * and a few others. TODO + */ using ProofOfWork = Ethash; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index bf2bce4fe..0ff0a3628 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -231,8 +231,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); BlockInfo bi(b); - if (bi.number % c_ethashEpochLength == 1) - Ethasher::get()->full(bi); + ProofOfWork::prep(bi); if (bi.parentHash != lastHash) { @@ -307,14 +306,8 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st try { auto r = import(block, _stateDB); - bool isOld = true; - for (auto const& h: r.first) - if (h == r.second) - isOld = false; - else if (isOld) - dead.push_back(h); - else - fresh.push_back(h); + fresh += r.first; + dead += r.second; } catch (UnknownParent) { @@ -334,7 +327,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); } -pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force) noexcept +ImportRoute BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force) noexcept { try { @@ -347,7 +340,7 @@ pair BlockChain::attemptImport(bytes const& _block, OverlayDB const } } -pair BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force) +ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Aversion _force) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -626,7 +619,17 @@ pair BlockChain::import(bytes const& _block, OverlayDB const& _db, cnote << "checkBest:" << checkBest; #endif - return make_pair(route, common); + h256s fresh; + h256s dead; + bool isOld = true; + for (auto const& h: route) + if (h == common) + isOld = false; + else if (isOld) + dead.push_back(h); + else + fresh.push_back(h); + return make_pair(fresh, dead); } void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 765e00b03..cdff566fb 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -68,6 +68,7 @@ ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0); using BlocksHash = std::map; using TransactionHashes = h256s; using UncleHashes = h256s; +using ImportRoute = std::pair; enum { ExtraDetails = 0, @@ -108,11 +109,11 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks) noexcept; + ImportRoute attemptImport(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, Aversion _force = Aversion::AvoidOldBlocks); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6f8c64827..e9dd99cd1 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -102,6 +102,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) m_readySet.insert(h); noteReadyWithoutWriteGuard(h); + m_onReady(); return ImportResult::Success; } } diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index ce0582db2..f5cdf7ab5 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -83,6 +83,8 @@ public: /// Get some infomration on the current status. BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } + template Handler onReady(T const& _t) { return m_onReady.add(_t); } + private: void noteReadyWithoutWriteGuard(h256 _b); void notePresentWithoutWriteGuard(bytesConstRef _block); @@ -95,6 +97,7 @@ private: std::multimap> m_unknown; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears. std::multimap m_future; ///< Set of blocks that are not yet valid. std::set m_knownBad; ///< Set of blocks that we know will never be valid. + Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index e7c91c03f..15a7c9bec 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -117,7 +117,7 @@ void BasicGasPricer::update(BlockChain const& _bc) } } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId, int _miners): +Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): Worker("eth"), m_vc(_dbPath), m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), @@ -126,14 +126,14 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for m_preMine(m_stateDB, BaseState::CanonGenesis), m_postMine(m_stateDB) { + m_tqReady = m_tq->onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); + m_bqReady = m_bq->onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); + m_farm->onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_gp->update(m_bc); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); - if (_miners > -1) - setMiningThreads(_miners); - else - setMiningThreads(); if (_dbPath.size()) Defaults::setDBPath(_dbPath); m_vc.setOk(); @@ -142,7 +142,7 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for startWorking(); } -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId, int _miners): +Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): Worker("eth"), m_vc(_dbPath), m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), @@ -151,14 +151,14 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_preMine(m_stateDB), m_postMine(m_stateDB) { + m_tq->onReady([=](){ this->onTransactionQueueReady(); }); + m_bq->onReady([=](){ this->onBlockQueueReady(); }); + m_farm->onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_gp->update(m_bc); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); - if (_miners > -1) - setMiningThreads(_miners); - else - setMiningThreads(); if (_dbPath.size()) Defaults::setDBPath(_dbPath); m_vc.setOk(); @@ -229,8 +229,6 @@ void Client::killChain() doWork(); - setMiningThreads(0); - startWorking(); if (wasMining) startMining(); @@ -271,26 +269,6 @@ static string filtersToString(T const& _fs) return ret.str(); } -void Client::noteChanged(h256Set const& _filters) -{ - Guard l(x_filtersWatches); - if (_filters.size()) - cnote << "noteChanged(" << filtersToString(_filters) << ")"; - // accrue all changes left in each filter into the watches. - for (auto& w: m_watches) - if (_filters.count(w.second.id)) - { - cwatch << "!!!" << w.first << (m_filters.count(w.second.id) ? w.second.id.abridged() : w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); - if (m_filters.count(w.second.id)) // Normal filtering watch - w.second.changes += m_filters.at(w.second.id).changes; - else // Special ('pending'/'latest') watch - w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); - } - // clear the filters now. - for (auto& i: m_filters) - i.second.changes.clear(); -} - void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash) { Guard l(x_filtersWatches); @@ -342,22 +320,6 @@ void Client::setForceMining(bool _enable) m.noteStateChange(); } -void Client::setMiningThreads(unsigned _threads) -{ - stopMining(); - auto t = _threads ? _threads : thread::hardware_concurrency(); -#if ETH_ETHASHCL || !ETH_TRUE - if (m_turboMining) - t = 1; -#endif - WriteGuard l(x_localMiners); - m_localMiners.clear(); - m_localMiners.resize(t); - unsigned i = 0; - for (auto& m: m_localMiners) - m.setup(this, i++); -} - MineProgress Client::miningProgress() const { MineProgress ret; @@ -452,160 +414,161 @@ pair Client::getWork() return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty()); } -bool Client::submitWork(ProofOfWork::Solution const& _proof) +bool Client::submitWork(ProofOfWork::Solution const& _solution) { - Guard l(x_remoteMiner); - return m_remoteMiner.submitWork(_proof); + bytes newBlock; + { + WriteGuard l(x_stateDB); + if (!m_postMine.completeMine(_solution)) + return false; + newBlock = m_postMine.blockData(); + } + + ImportRoute ir = m_bc.attemptImport(newBlock, m_stateDB); + if (!ir.first.empty()) + onChainChanged(ir); + return true; } -void Client::doWork() +void Client::syncBlockQueue() { - // TODO: Use condition variable rather than polling. - - bool stillGotWork = false; - - cworkin << "WORK"; - h256Set changeds; - - auto maintainMiner = [&](OldMiner& m) - { - if (m.isComplete()) - { - // TODO: enable a short-circuit option since we mined it. will need to get the end state from the miner. - auto lm = dynamic_cast(&m); - h256s hs; - h256 c; - if (false && lm && !m_verifyOwnBlocks) - { - // TODO: implement - //m_bc.attemptImport(m_blockData(), m_stateDB, lm->state()); - // TODO: derive hs from lm->state() - } - else - { - cwork << "CHAIN <== postSTATE"; - WriteGuard l(x_stateDB); - tie(hs, c) = m_bc.attemptImport(m.blockData(), m_stateDB); - } - if (hs.size()) - { - for (auto const& h: hs) - if (h != c) - appendFromNewBlock(h, changeds); - changeds.insert(ChainChangedFilter); - } - for (auto& m: m_localMiners) - m.noteStateChange(); - } - }; - { - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - maintainMiner(m); - } - { - Guard l(x_remoteMiner); - maintainMiner(m_remoteMiner); - } + ImportResult ir; - // Synchronise state to block chain. - // This should remove any transactions on our queue that are included within our state. - // It also guarantees that the state reflects the longest (valid!) chain on the block chain. - // This might mean reverting to an earlier state and replaying some blocks, or, (worst-case: - // if there are no checkpoints before our fork) reverting to the genesis block and replaying - // all blocks. - // Resynchronise state with block chain & trans - bool resyncStateNeeded = false; { WriteGuard l(x_stateDB); cwork << "BQ ==> CHAIN ==> STATE"; OverlayDB db = m_stateDB; x_stateDB.unlock(); - h256s fresh; - h256s dead; - bool sgw; - tie(fresh, dead, sgw) = m_bc.sync(m_bq, db, 100); - - // insert transactions that we are declaring the dead part of the chain - for (auto const& h: dead) - { - clog(ClientNote) << "Dead block:" << h.abridged(); - for (auto const& t: m_bc.transactions(h)) - { - clog(ClientNote) << "Resubmitting transaction " << Transaction(t, CheckTransaction::None); - m_tq.import(t); - } - } - // remove transactions from m_tq nicely rather than relying on out of date nonce later on. - for (auto const& h: fresh) - { - clog(ClientChat) << "Live block:" << h.abridged(); - for (auto const& th: m_bc.transactionHashes(h)) - { - clog(ClientNote) << "Safely dropping transaction " << th.abridged(); - m_tq.drop(th); - } - } + tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); - stillGotWork = stillGotWork | sgw; - if (!fresh.empty()) - { - for (auto i: fresh) - appendFromNewBlock(i, changeds); - changeds.insert(ChainChangedFilter); - } x_stateDB.lock(); if (fresh.size()) m_stateDB = db; + } + + if (!ir.first.empty()) + onChainChanged(ir); + return true; +} + +void Client::syncTransactionQueue() +{ + // returns TransactionReceipts, once for each transaction. + cwork << "postSTATE <== TQ"; + TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); + if (newPendingReceipts.size()) + { + for (size_t i = 0; i < newPendingReceipts.size(); i++) + appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - cwork << "preSTATE <== CHAIN"; - if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) + changeds.insert(PendingChangedFilter); + + if (isMining()) + cnote << "Additional transaction ready: Restarting mining operation."; + resyncStateNeeded = true; + if (auto h = m_host.lock()) + h->noteNewTransactions(); + } +} + +void Client::onChainChanged(ImportRoute const& _ir) +{ + // insert transactions that we are declaring the dead part of the chain + for (auto const& h: _ir.second) + { + clog(ClientNote) << "Dead block:" << h.abridged(); + for (auto const& t: m_bc.transactions(h)) { - if (isMining()) - cnote << "New block on chain: Restarting mining operation."; - m_postMine = m_preMine; - resyncStateNeeded = true; - changeds.insert(PendingChangedFilter); - // TODO: Move transactions pending from m_postMine back to transaction queue. + clog(ClientNote) << "Resubmitting transaction " << Transaction(t, CheckTransaction::None); + m_tq.import(t); } + } - // returns TransactionReceipts, once for each transaction. - cwork << "postSTATE <== TQ"; - TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); - if (newPendingReceipts.size()) + // remove transactions from m_tq nicely rather than relying on out of date nonce later on. + for (auto const& h: _ir.first) + { + clog(ClientChat) << "Live block:" << h.abridged(); + for (auto const& th: m_bc.transactionHashes(h)) { - for (size_t i = 0; i < newPendingReceipts.size(); i++) - appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - - changeds.insert(PendingChangedFilter); - - if (isMining()) - cnote << "Additional transaction ready: Restarting mining operation."; - resyncStateNeeded = true; - if (auto h = m_host.lock()) - h->noteNewTransactions(); + clog(ClientNote) << "Safely dropping transaction " << th.abridged(); + m_tq.drop(th); } } - if (!changeds.empty()) - if (auto h = m_host.lock()) - h->noteNewBlocks(); + if (auto h = m_host.lock()) + h->noteNewBlocks(); + + h256Set changeds; + for (auto const& h: _ir.first) + if (h != _ir.second) + appendFromNewBlock(h, changeds); + changeds.insert(ChainChangedFilter); + noteChanged(changeds); + + // RESTART MINING - if (resyncStateNeeded) + // LOCKS NEEDED? + Guard l(x_stateDB); + cwork << "preSTATE <== CHAIN"; + if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) { - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - m.noteStateChange(); + if (isMining()) + cnote << "New block on chain: Restarting mining operation."; + m_postMine = m_preMine; + resyncStateNeeded = true; + changeds.insert(PendingChangedFilter); + + m_postMine.commitToMine(m_bc); + m_farm.setWork(m_postMine.info()); } +} - cwork << "noteChanged" << changeds.size() << "items"; - noteChanged(changeds); - cworkout << "WORK"; +void Client::noteChanged(h256Set const& _filters) +{ + Guard l(x_filtersWatches); + if (_filters.size()) + cnote << "noteChanged(" << filtersToString(_filters) << ")"; + // accrue all changes left in each filter into the watches. + for (auto& w: m_watches) + if (_filters.count(w.second.id)) + { + cwatch << "!!!" << w.first << (m_filters.count(w.second.id) ? w.second.id.abridged() : w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); + if (m_filters.count(w.second.id)) // Normal filtering watch + w.second.changes += m_filters.at(w.second.id).changes; + else // Special ('pending'/'latest') watch + w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); + } + // clear the filters now. + for (auto& i: m_filters) + i.second.changes.clear(); +} + +void Client::doWork() +{ + // TODO: Use condition variable rather than this rubbish. + + Guard l(x_fakeSignalSystemState); + + if (m_syncTransactionQueue) + { + m_syncTransactionQueue = false; + syncTransactionQueue(); + } + + if (m_syncBlockQueue) + { + m_syncBlockQueue = false; + syncBlockQueue(); + } + + checkWatchGarbage(); - if (!stillGotWork) - this_thread::sleep_for(chrono::milliseconds(100)); + this_thread::sleep_for(chrono::milliseconds(20)); +} +void Client::checkWatchGarbage() +{ if (chrono::system_clock::now() - m_lastGarbageCollection > chrono::seconds(5)) { // watches garbage collection diff --git a/libethereum/Client.h b/libethereum/Client.h index 9af501f74..8eac2e577 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -42,6 +42,7 @@ #include "CommonNet.h" #include "Miner.h" #include "ABI.h" +#include "Farm.h" #include "ClientBase.h" namespace dev @@ -122,7 +123,7 @@ struct ClientDetail: public LogChannel { static const char* name() { return " C /** * @brief Main API hub for interfacing with Ethereum. */ -class Client: public MinerHost, public ClientBase, Worker +class Client: public ClientBase, Worker { friend class OldMiner; @@ -132,8 +133,7 @@ public: p2p::Host* _host, std::string const& _dbPath = std::string(), WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0, - int _miners = -1 + u256 _networkId = 0 ); explicit Client( @@ -141,8 +141,7 @@ public: std::shared_ptr _gpForAdoption, // pass it in with new. std::string const& _dbPath = std::string(), WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0, - int _miners = -1 + u256 _networkId = 0 ); /// Destructor. @@ -191,31 +190,31 @@ public: /// Are we allowed to GPU mine? bool turboMining() const { return m_turboMining; } /// Enable/disable GPU mining. - void setTurboMining(bool _enable = true) { bool was = isMining(); stopMining(); m_turboMining = _enable; setMiningThreads(0); if (was) startMining(); } + void setTurboMining(bool _enable = true) { m_turboMining = _enable; if (isMining()) startMining(); } - /// Stops mining and sets the number of mining threads (0 for automatic). - void setMiningThreads(unsigned _threads = 0) override; - /// Get the effective number of mining threads. - unsigned miningThreads() const override { ReadGuard l(x_localMiners); return m_localMiners.size(); } /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread - void startMining() override { startWorking(); { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.start(); } } + void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); } /// Stop mining. /// NOT thread-safe - void stopMining() override { { ReadGuard l(x_localMiners); for (auto& m: m_localMiners) m.stop(); } } - /// Are we mining now? - bool isMining() const override { { ReadGuard l(x_localMiners); if (!m_localMiners.empty() && m_localMiners[0].isRunning()) return true; } return false; } + void stopMining() override { m_farm.stop(); } /// Are we mining now? + bool isMining() const override { return m_farm.isMining(); } + /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MineProgress miningProgress() const override; + MiningProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. virtual std::pair getWork() override; - /// Submit the proof for the proof-of-work. + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ virtual bool submitWork(ProofOfWork::Solution const& _proof) override; // Debug stuff: @@ -261,10 +260,23 @@ private: /// Called when Worker is exiting. virtual void doneWorking(); - /// Overrides for being a mining host. - virtual void setupState(State& _s); - virtual bool turbo() const { return m_turboMining; } - virtual bool force() const { return m_forceMining; } + /// Magically called when the chain has changed. An import route is provided. + /// Called by either submitWork() or in our main thread through syncBlockQueue(). + void onChainChanged(ImportRoute const& _ir); + + /// Signal handler for when the block queue needs processing. + void syncBlockQueue(); + + /// Signal handler for when the block queue needs processing. + void syncTransactionQueue(); + + /// Magically called when m_tq needs syncing. Be nice and don't block. + void onTransactionQueueReady() { Guard l(x_fakeSignalSystemState); m_syncTransactionQueue = true; } + + /// Magically called when m_tq needs syncing. Be nice and don't block. + void onBlockQueueReady() { Guard l(x_fakeSignalSystemState); m_syncBlockQueue = true; } + + void checkWatchGarbage(); VersionChecker m_vc; ///< Dummy object to check & update the protocol version. CanonBlockChain m_bc; ///< Maintains block database. @@ -278,17 +290,24 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. + Farm m_farm; ///< Our mining farm. mutable Mutex x_remoteMiner; ///< The remote miner lock. RemoteMiner m_remoteMiner; ///< The remote miner. - std::vector m_localMiners; ///< The in-process miners. - mutable SharedMutex x_localMiners; ///< The in-process miners lock. - bool m_paranoia = false; ///< Should we be paranoid about our state? + Handler m_tqReady; + Handler m_bqReady; + bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping. bool m_forceMining = false; ///< Mine even when there are no transactions pending? - bool m_verifyOwnBlocks = true; ///< Should be verify blocks that we mined? + bool m_paranoia = false; ///< Should we be paranoid about our state? mutable std::chrono::system_clock::time_point m_lastGarbageCollection; + ///< When did we last both doing GC on the watches? + + // TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables) + mutable Mutex x_fakeSignalSystemState; + bool m_syncTransactionQueue = false; + bool m_syncBlockQueue = false; }; } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index ae6d27578..4b3cc5002 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -142,8 +142,6 @@ public: /// TODO: consider moving it to a separate interface - virtual void setMiningThreads(unsigned _threads) override { (void)_threads; BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::setMiningThreads")); } - virtual unsigned miningThreads() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningThreads")); } virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); } virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); } virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); } diff --git a/libethereum/Farm.cpp b/libethereum/Farm.cpp index 639e4efcf..e69de29bb 100644 --- a/libethereum/Farm.cpp +++ b/libethereum/Farm.cpp @@ -1,12 +0,0 @@ -#include "Farm.h" - -Farm::Farm() -{ - -} - -Farm::~Farm() -{ - -} - diff --git a/libethereum/Farm.h b/libethereum/Farm.h index a49038f0d..55d1aa8df 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -14,10 +14,9 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file Miner.h - * @author Alex Leverington +/** @file Farm.h * @author Gav Wood - * @date 2014 + * @date 2015 */ #pragma once @@ -28,7 +27,8 @@ #include #include #include -#include "Miner.h" +#include +#include namespace dev { @@ -41,8 +41,8 @@ namespace eth * Miners ask for work, then submit proofs * @threadsafe */ -template -class Farm: public FarmFace +template +class Farm: public FarmFace { public: /** @@ -65,13 +65,13 @@ public: * @brief (Re)start miners for CPU only. * @returns true if started properly. */ - bool startCPU() { return start(); } + bool startCPU() { return start(); } /** * @brief (Re)start miners for GPU only. * @returns true if started properly. */ - bool startGPU() { start(); } + bool startGPU() { start(); } /** * @brief Stop all mining activities. @@ -82,20 +82,24 @@ public: m_miners.clear(); } + bool isMining() const + { + ReadGuard l(x_miners); + return !m_miners.empty(); + } + /** * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } + MiningProgress const& miningProgress() const { ReadGuard l(x_progress); return m_progress; } -protected: - // TO BE REIMPLEMENTED BY THE SUBCLASS /** * @brief Provides a valid header based upon that received previously with setWork(). * @param _bi The now-valid header. * @return true if the header was good and that the Farm should pause until more work is submitted. */ - virtual bool submitHeader(BlockInfo const& _bi) = 0; + void onSolutionFound(function _handler) { m_onSolutionFound = _handler; } private: /** @@ -104,16 +108,15 @@ private: * @param _wp The WorkPackage that the Solution is for. * @return true iff the solution was good (implying that mining should be . */ - bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp, NewMiner* _m) override + bool submitProof(Solution const& _s, WorkPackage const& _wp, Miner* _m) override { if (_wp.headerHash != m_work.headerHash) return false; - ProofOfWork::assignResult(_p, m_header); - if (submitHeader(m_header)) + if (m_onSolutionFound && m_onSolutionFound(_s)) { ReadGuard l(x_miners); - for (std::shared_ptr const& m: m_miners) + for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->pause(); m_work.headerHash = h256(); @@ -139,14 +142,16 @@ private: } mutable SharedMutex x_miners; - std::vector> m_miners; + std::vector> m_miners; mutable SharedMutex x_progress; - MineProgress m_progress; + MiningProgress m_progress; mutable SharedMutex x_work; WorkPackage m_work; BlockInfo m_header; + + function m_onSolutionFound; }; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e77565837..75618eb5f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -856,20 +856,6 @@ void State::commitToMine(BlockChain const& _bc) m_committedToMine = true; } -bool State::completeMine(ProofOfWork::Solution const& _nonce) -{ - ProofOfWork::assignResult(_nonce, m_currentBlock); - -// if (!m_pow.verify(m_currentBlock)) -// return false; - - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock); - - completeMine(); - - return true; -} - void State::completeMine() { cdebug << "Completing mine!"; diff --git a/libethereum/State.h b/libethereum/State.h index b327378a1..36a505481 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include "TransactionQueue.h" @@ -162,30 +163,19 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff the given nonce is a proof-of-work for this State's block. - bool completeMine(ProofOfWork::Solution const& _result); - - /// Attempt to find valid nonce for block that this state represents. - /// This function is thread-safe. You can safely have other interactions with this object while it is happening. - /// @param _msTimeout Timeout before return in milliseconds. - /// @returns Information on the mining. - template MineInfo mine(ProofOfWork* _pow) + template + bool completeMine(typename PoW::Solution const& _result) { - // Update difficulty according to timestamp. - m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); + PoW::assignResult(_result, m_currentBlock); - MineInfo ret; - typename ProofOfWork::Solution r; - std::tie(ret, r) = _pow->mine(m_currentBlock, _pow->defaultTimeout(), true); + // if (!m_pow.verify(m_currentBlock)) + // return false; - if (!ret.completed) - m_currentBytes.clear(); - else - { - ProofOfWork::assignResult(r, m_currentBlock); - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock); - } + cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - return ret; + completeMine(); + + return true; } /** Commit to DB and build the final block if the previous call to mine()'s result is completion. @@ -369,7 +359,6 @@ private: /// Debugging only. Good for checking the Trie is in shape. void paranoia(std::string const& _when, bool _enforceRefs = false) const; - OverlayDB m_db; ///< Our overlay for the state tree. SecureTrieDB m_state; ///< Our state tree, as an OverlayDB DB. Transactions m_transactions; ///< The current list of transactions that we've included in the state. diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 7c72f53e8..506de2d2f 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -53,6 +53,7 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb if (_cb) m_callbacks[h] = _cb; ctxq << "Queued vaguely legit-looking transaction" << h.abridged(); + m_onReady(); } catch (Exception const& _e) { diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index ad093b4e5..e18f47e80 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -26,7 +26,7 @@ #include #include #include -#include "libethcore/Common.h" +#include #include "Transaction.h" namespace dev @@ -60,13 +60,15 @@ public: void noteGood(std::pair const& _t); void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); } + template Handler onReady(T const& _t) { return m_onReady.add(_t); } private: mutable boost::shared_mutex m_lock; ///< General lock. std::set m_known; ///< Hashes of transactions in both sets. std::map m_current; ///< Map of SHA3(tx) to tx. std::multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. - std::map> m_callbacks; ///< Called once + std::map> m_callbacks; ///< Called once. + Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast. }; } From 15f74352e3352faaa55477b6eeee83f36c4b0128 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 00:08:52 +0200 Subject: [PATCH 068/108] Compile fixes. --- libethcore/Common.h | 37 +++++++++++++------------------ libethcore/Ethash.cpp | 40 +++++++++++++++------------------- libethcore/Ethash.h | 12 ++++++---- libethcore/EthashAux.cpp | 36 +++++++++++++++--------------- libethcore/EthashAux.h | 6 +++-- libethcore/Miner.h | 16 ++++++++------ libethereum/Client.h | 2 +- libethereum/Farm.h | 2 +- libethereum/Interface.h | 5 ----- libethereum/TransactionQueue.h | 2 +- mix/MixClient.cpp | 10 --------- mix/MixClient.h | 2 -- 12 files changed, 75 insertions(+), 95 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index b5291648b..4d01055f1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -96,42 +96,35 @@ enum class ImportResult BadChain }; -class Signal; - -class Handler +/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight. +class Signal { public: - Handler() = default; - Handler(Handler const&) = delete; - ~Handler() { reset(); } + class HandlerAux + { + friend class Signal; - Handler& operator=(Handler const& _h) = delete; + public: + ~HandlerAux() { if (m_s) m_s->m_fire.erase(m_i); m_s = nullptr; } - void reset(); - -private: - Handler(unsigned _i, Signal* _s): m_i(_i), m_s(_s) {} + private: + HandlerAux(unsigned _i, Signal* _s): m_i(_i), m_s(_s) {} - unsigned m_i = 0; - Signal* m_s = nullptr; -}; + unsigned m_i = 0; + Signal* m_s = nullptr; + }; -/// Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight. -class Signal -{ -public: using Callback = std::function; - using Callbacks = std::vector; - Handler add(Callback const& _h) { auto n = m_onReady.size() ? m_onReady.rbegin()->first + 1 : 0; m_onReady[n] = _h; return Handler(n, this); } + std::shared_ptr add(Callback const& _h) { auto n = m_fire.empty() ? 0 : (m_fire.rbegin()->first + 1); m_fire[n] = _h; return std::shared_ptr(new HandlerAux(n, this)); } void operator()() { for (auto const& f: m_fire) f.second(); } private: - std::map m_fire; + std::map m_fire; }; -inline void Handler::reset() { if (m_s) m_s->m_fire->erase(m_i); m_s = nullptr; } +using Handler = std::shared_ptr; } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 82e349b4c..f3b4d1b18 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ unsigned Ethash::revision() void Ethash::prep(BlockInfo const& _header) { if (_header.number % ETHASH_EPOCH_LENGTH == 1) - EthashAux::full(bi); + EthashAux::full(_header); } bool Ethash::preVerify(BlockInfo const& _header) @@ -88,7 +88,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - auto result = eval(_header); + auto result = EthashAux::eval(_header); bool slow = result.value <= boundary && result.mixHash == _header.mixHash; #if ETH_DEBUG || !ETH_TRUE @@ -111,29 +111,27 @@ bool Ethash::verify(BlockInfo const& _header) void Ethash::CPUMiner::workLoop() { auto tid = std::this_thread::get_id(); - static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()) + std::hash()(tid))); + static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); - uint64_t tryNonce = Nonce::random(s_eng); + uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng); ethash_return_value ethashReturn; - auto p = Ethash::params(m_work.seedHash); - void const* dagPointer = Ethash::full(m_work.headerHash).data(); + auto p = EthashAux::params(m_work.seedHash); + void const* dagPointer = EthashAux::full(m_work.headerHash).data(); uint8_t const* headerHashPointer = m_work.headerHash.data(); - h256 boundary = m_work.boundary(); + h256 boundary = m_work.boundary; unsigned hashCount = 0; for (; !shouldStop(); tryNonce++, hashCount++) { ethash_compute_full(ðashReturn, dagPointer, &p, headerHashPointer, tryNonce); h256 value = h256(ethashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{value, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) break; } } #if ETH_ETHASHCL || !ETH_TRUE -namespace dev { namespace eth { - class EthashCLHook: public ethash_cl_miner::search_hook { public: @@ -148,8 +146,8 @@ public: m_abort = true; for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) std::this_thread::sleep_for(chrono::milliseconds(30)); - if (!m_aborted) - cwarn << "Couldn't abort. Abandoning OpenCL process."; +// if (!m_aborted) +// cwarn << "Couldn't abort. Abandoning OpenCL process."; m_aborted = m_abort = false; } @@ -161,7 +159,7 @@ protected: // cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); for (uint32_t i = 0; i < _count; ++i) { - if (m_owner->found(_nonces[i])) + if (m_owner->report(_nonces[i])) { m_aborted = true; return true; @@ -193,19 +191,17 @@ private: Ethash::GPUMiner* m_owner = nullptr; }; -} } - Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), m_hook(new EthashCLHook(this)) { } -void Ethash::GPUMiner::report(uint64_t _nonce) +bool Ethash::GPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = Ethash::eval(m_work.seedHash, m_work.headerHash, n); - if (r.value < m_work.boundary) + Result r = EthashAux::eval(m_lastWork.seedHash, m_lastWork.headerHash, n); + if (r.value < m_lastWork.boundary) return submitProof(Solution{n, r.mixHash}); return false; } @@ -217,17 +213,17 @@ void Ethash::GPUMiner::kickOff(WorkPackage const& _work) if (m_miner) m_hook->abort(); m_miner.reset(new ethash_cl_miner); - auto p = Ethash::params(_work.seedHash); - auto cb = [&](void* d) { EthashAux::readFull(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; + auto p = EthashAux::params(_work.seedHash); + auto cb = [&](void* d) { EthashAux::full(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; m_miner->init(p, cb, 32); } if (m_lastWork.headerHash != _work.headerHash) { m_hook->abort(); uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); - m_miner->search(_work.headerHash, upper64OfBoundary, *m_hook); + m_miner->search(_work.headerHash.data(), upper64OfBoundary, *m_hook); } - m_work = _work; + m_lastWork = _work; } void Ethash::GPUMiner::pause() diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index bdd6bf6c5..b87f06549 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "Common.h" #include "BlockInfo.h" #include "Miner.h" @@ -37,9 +38,13 @@ namespace dev namespace eth { +class EthashCLHook; + class Ethash { public: + using Miner = GenericMiner; + struct Solution { Nonce nonce; @@ -73,7 +78,7 @@ public: public: CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - static unsigned instances() { return thread::hardware_concurrency(); } + static unsigned instances() { return std::thread::hardware_concurrency(); } protected: void kickOff(WorkPackage const& _work) override @@ -93,10 +98,9 @@ public: }; #if ETH_ETHASHCL || !ETH_TRUE - class EthashCLHook; class GPUMiner: public Miner { - friend class EthashCLHook; + friend class dev::eth::EthashCLHook; public: GPUMiner(ConstructionInfo const& _ci); @@ -108,7 +112,7 @@ public: void pause() override; private: - void report(uint64_t _nonce); + bool report(uint64_t _nonce); std::unique_ptr m_hook; std::unique_ptr m_miner; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index a6143e264..969310dac 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -102,13 +102,13 @@ void const* EthashAux::light(BlockInfo const& _header) void const* EthashAux::light(h256 const& _seedHash) { - RecursiveGuard l(x_this); - if (!m_lights.count(_header.seedHash())) + RecursiveGuard l(get()->x_this); + if (!get()->m_lights.count(_seedHash)) { ethash_params p = params(_seedHash); - m_lights[_seedHash] = ethash_new_light(&p, _seedHash.data()); + get()->m_lights[_seedHash] = ethash_new_light(&p, _seedHash.data()); } - return m_lights[_seedHash]; + return get()->m_lights[_seedHash]; } bytesConstRef EthashAux::full(BlockInfo const& _header, bytesRef _dest) @@ -118,14 +118,14 @@ bytesConstRef EthashAux::full(BlockInfo const& _header, bytesRef _dest) bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) { - RecursiveGuard l(x_this); - if (m_fulls.count(_seedHash) && _dest) + RecursiveGuard l(get()->x_this); + if (get()->m_fulls.count(_seedHash) && _dest) { - assert(m_fulls.size() <= _dest.size()); - m_fulls.at(_seedHash).copyTo(_dest); - return; + assert(get()->m_fulls.size() <= _dest.size()); + get()->m_fulls.at(_seedHash).copyTo(_dest); + return _dest; } - if (!m_fulls.count(_seedHash)) + if (!get()->m_fulls.count(_seedHash)) { // @memoryleak @bug place it on a pile for deletion - perhaps use shared_ptr. /* if (!m_fulls.empty()) @@ -138,7 +138,7 @@ bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) boost::filesystem::create_directories(getDataDir("ethash")); } catch (...) {} - auto info = rlpList(revision(), _seedHash); + auto info = rlpList(Ethash::revision(), _seedHash); std::string oldMemoFile = getDataDir("ethash") + "/full"; std::string memoFile = getDataDir("ethash") + "/full-R" + toString(ETHASH_REVISION) + "-" + toHex(_seedHash.ref().cropped(0, 8)); if (boost::filesystem::exists(oldMemoFile) && contents(oldMemoFile + ".info") == info) @@ -147,8 +147,8 @@ bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) boost::filesystem::rename(oldMemoFile, memoFile); } - IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); - IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); + ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile)); + ETH_IGNORE_EXCEPTIONS(boost::filesystem::remove(oldMemoFile + ".info")); ethash_params p = params(_seedHash); assert(!_dest || _dest.size() >= p.full_size); // must be big enough. @@ -162,14 +162,14 @@ bytesConstRef EthashAux::full(h256 const& _seedHash, bytesRef _dest) r = _dest; else r = bytesRef(new byte[p.full_size], p.full_size); - ethash_prep_full(r, &p, light(_seedHash)); + ethash_prep_full(r.data(), &p, light(_seedHash)); writeFile(memoFile, r); } if (_dest) return _dest; - m_fulls[_seedHash] = r; + get()->m_fulls[_seedHash] = r; } - return m_fulls[_seedHash]; + return get()->m_fulls[_seedHash]; } Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) @@ -179,12 +179,12 @@ Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { - auto p = EthashAux::params(_header); + auto p = EthashAux::params(_seedHash); ethash_return_value r; if (EthashAux::get()->m_fulls.count(_seedHash)) ethash_compute_full(&r, EthashAux::get()->full(_seedHash).data(), &p, _headerHash.data(), (uint64_t)(u64)_nonce); else ethash_compute_light(&r, EthashAux::get()->light(_seedHash), &p, _headerHash.data(), (uint64_t)(u64)_nonce); // cdebug << "EthashAux::eval sha3(cache):" << sha3(EthashAux::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); - return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; + return Ethash::Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index bfd01a594..aec1089a2 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -28,7 +28,7 @@ namespace eth{ class EthashAux { - EthashAux() {} +public: ~EthashAux(); static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; } @@ -49,9 +49,11 @@ class EthashAux static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: + EthashAux() {} + void killCache(h256 const& _s); - static Ethash* s_this; + static EthashAux* s_this; RecursiveMutex x_this; std::map m_lights; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index e7157e660..9372c06b1 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -58,19 +58,19 @@ struct MiningProgress unsigned ms = 0; ///< Total number of milliseconds of mining thus far. }; -template class Miner; +template class GenericMiner; /** * @brief Class for hosting one or more Miners. * @warning Must be implemented in a threadsafe manner since it will be called from multiple * miner threads. */ -template class FarmFace +template class GenericFarmFace { public: using WorkPackage = typename PoW::WorkPackage; using Solution = typename PoW::Solution; - using Miner = Miner; + using Miner = GenericMiner; /** * @brief Called from a Miner to note a WorkPackage has a solution. @@ -85,15 +85,15 @@ public: /** * @brief A miner - a member and adoptee of the Farm. */ -template class Miner +template class GenericMiner { public: - using ConstructionInfo = std::pair*, unsigned>; using WorkPackage = typename PoW::WorkPackage; using Solution = typename PoW::Solution; - using FarmFace = FarmFace; + using FarmFace = GenericFarmFace; + using ConstructionInfo = std::pair; - Miner(ConstructionInfo const& _ci): + GenericMiner(ConstructionInfo const& _ci): m_farm(_ci.first), m_index(_ci.second) {} @@ -144,6 +144,8 @@ protected: return true; } + WorkPackage const& work() const { return m_work; } + private: FarmFace* m_farm = nullptr; unsigned m_index; diff --git a/libethereum/Client.h b/libethereum/Client.h index 8eac2e577..a136033e5 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -290,7 +290,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - Farm m_farm; ///< Our mining farm. + GenericFarm m_farm; ///< Our mining farm. mutable Mutex x_remoteMiner; ///< The remote miner lock. RemoteMiner m_remoteMiner; ///< The remote miner. diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 55d1aa8df..39988c8d7 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -42,7 +42,7 @@ namespace eth * @threadsafe */ template -class Farm: public FarmFace +class GenericFarm: public GenericFarmFace { public: /** diff --git a/libethereum/Interface.h b/libethereum/Interface.h index cf2e7f5ea..134bed53b 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -171,11 +171,6 @@ public: /// Get the coinbase address. virtual Address address() const = 0; - /// Stops mining and sets the number of mining threads (0 for automatic). - virtual void setMiningThreads(unsigned _threads = 0) = 0; - /// Get the effective number of mining threads. - virtual unsigned miningThreads() const = 0; - /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread virtual void startMining() = 0; diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index e18f47e80..c3df00d25 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -48,7 +48,7 @@ class TransactionQueue public: using ImportCallback = std::function; - ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx); } + ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx, _cb); } ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback()); void drop(h256 _txHash); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 5c905ef0b..2e8bd5384 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -372,16 +372,6 @@ void MixClient::setAddress(Address _us) m_state.setAddress(_us); } -void MixClient::setMiningThreads(unsigned _threads) -{ - m_miningThreads = _threads; -} - -unsigned MixClient::miningThreads() const -{ - return m_miningThreads; -} - void MixClient::startMining() { //no-op diff --git a/mix/MixClient.h b/mix/MixClient.h index 357e22930..649c7694f 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -63,8 +63,6 @@ public: dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); void setAddress(Address _us) override; - void setMiningThreads(unsigned _threads) override; - unsigned miningThreads() const override; void startMining() override; void stopMining() override; bool isMining() const override; From e7008b58776a59834d6361467a541b404cb9a99a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 00:34:42 +0200 Subject: [PATCH 069/108] Various compile fixes. --- libethcore/Ethash.cpp | 9 ++ libethcore/Ethash.h | 6 +- libethereum/BlockChain.cpp | 3 +- libethereum/BlockChain.h | 2 +- libethereum/Client.cpp | 7 +- libethereum/Client.h | 24 +----- libethereum/Farm.h | 4 +- libethereum/Interface.h | 4 +- libethereum/Miner.cpp | 94 --------------------- libethereum/Miner.h | 166 ------------------------------------- 10 files changed, 22 insertions(+), 297 deletions(-) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f3b4d1b18..ac54ebe4d 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -59,6 +59,15 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) +{ + WorkPackage ret; + ret.boundary = _bi.boundary(); + ret.headerHash = _bi.headerHash(WithNonce); + ret.seedHash = _bi.seedHash(); + return ret; +} + void Ethash::prep(BlockInfo const& _header) { if (_header.number % ETHASH_EPOCH_LENGTH == 1) diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index b87f06549..458cb4e6c 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -68,10 +68,11 @@ public: static std::string name(); static unsigned revision(); + static void prep(BlockInfo const& _header); static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } - static void prep(BlockInfo const& _header); class CPUMiner: public Miner, Worker { @@ -125,8 +126,5 @@ public: #endif }; -using ProofOfWork = Ethash; -using Solution = Ethash::Solution; - } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 0ff0a3628..b73a79c49 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "GenesisInfo.h" #include "State.h" @@ -336,7 +335,7 @@ ImportRoute BlockChain::attemptImport(bytes const& _block, OverlayDB const& _sta catch (...) { cwarn << "Unexpected exception! Could not import block!" << boost::current_exception_diagnostic_information(); - return make_pair(h256s(), h256()); + return make_pair(h256s(), h256s()); } } diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index cdff566fb..8b4a3dce4 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -68,7 +68,7 @@ ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0); using BlocksHash = std::map; using TransactionHashes = h256s; using UncleHashes = h256s; -using ImportRoute = std::pair; +using ImportRoute = std::pair; enum { ExtraDetails = 0, diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 15a7c9bec..81023f9ef 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -404,14 +404,17 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -pair Client::getWork() +ProofOfWork::WorkPackage Client::getWork() { Guard l(x_remoteMiner); + BlockInfo bi; { ReadGuard l(x_stateDB); m_remoteMiner.update(m_postMine, m_bc); + m_postMine.commitToMine(m_bc); + bi = m_postMine.info(); } - return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty()); + return ProofOfWork::package(bi); } bool Client::submitWork(ProofOfWork::Solution const& _solution) diff --git a/libethereum/Client.h b/libethereum/Client.h index a136033e5..9f6bbfeb6 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -73,28 +73,6 @@ private: std::string m_path; }; -class RemoteMiner: public OldMiner -{ -public: - RemoteMiner() {} - - void update(State const& _provisional, BlockChain const& _bc) { m_state = _provisional; m_state.commitToMine(_bc); } - - h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); } - u256 const& difficulty() const { return m_state.info().difficulty; } - - bool submitWork(ProofOfWork::Solution const& _result) { return (m_isComplete = m_state.completeMine(_result)); } - - virtual bool isComplete() const override { return m_isComplete; } - virtual bytes const& blockData() const { return m_state.blockData(); } - - virtual void noteStateChange() override {} - -private: - bool m_isComplete = false; - State m_state; -}; - class BasicGasPricer: public GasPricer { public: @@ -209,7 +187,7 @@ public: /// Update to the latest transactions and get hash of the current block to be mined minus the /// nonce (the 'work hash') and the difficulty to be met. - virtual std::pair getWork() override; + virtual ProofOfWork::WorkPackage getWork() override; /** @brief Submit the proof for the proof-of-work. * @param _s A valid solution. diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 39988c8d7..137c137d3 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -53,9 +53,7 @@ public: { WriteGuard l(x_work); m_header = _bi; - m_work.boundary = _bi.boundary(); - m_work.headerHash = _bi.headerHash(WithNonce); - m_work.seedHash = _bi.seedHash(); + m_work = PoW::package(m_header); ReadGuard l(x_miners); for (auto const& m: miners) m->setWork(m_work); diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 134bed53b..0ab81728b 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -26,11 +26,11 @@ #include #include #include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" #include "BlockDetails.h" -#include "Miner.h" namespace dev { @@ -188,7 +188,7 @@ public: virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; /// Check the progress of the mining. - virtual MineProgress miningProgress() const = 0; + virtual MiningProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp index b386fe868..e69de29bb 100644 --- a/libethereum/Miner.cpp +++ b/libethereum/Miner.cpp @@ -1,94 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** @file Miner.cpp - * @author Gav Wood - * @author Giacomo Tazzari - * @date 2014 - */ - -#include "Miner.h" - -#include -#include "State.h" -using namespace std; -using namespace dev; -using namespace dev::eth; - -OldMiner::~OldMiner() {} - -LocalMiner::LocalMiner(MinerHost* _host, unsigned _id) -{ - setup(_host, _id); -} - -void LocalMiner::setup(MinerHost* _host, unsigned _id) -{ - AsyncMiner::setup(_host, _id); - setName("miner-" + toString(m_id)); - m_pow.reset(_host->turbo() ? new Ethash : (Ethash*)new EthashCPU); -} - -void LocalMiner::doWork() -{ - // Do some mining. - if (m_miningStatus != Waiting && m_miningStatus != Mined) - { - if (m_miningStatus == Preparing) - { - m_host->setupState(m_mineState); - if (m_host->force() || m_mineState.pending().size()) - m_miningStatus = Mining; - else - m_miningStatus = Waiting; - - { - Guard l(x_mineInfo); - m_mineProgress.best = (double)-1; - m_mineProgress.hashes = 0; - m_mineProgress.ms = 0; - } - } - - if (m_miningStatus == Mining) - { - // Mine for a while. - MineInfo mineInfo = m_mineState.mine(m_pow.get()); - - { - Guard l(x_mineInfo); - m_mineProgress.best = min(m_mineProgress.best, mineInfo.best); - m_mineProgress.current = mineInfo.best; - m_mineProgress.requirement = mineInfo.requirement; - m_mineProgress.ms += 100; - m_mineProgress.hashes += mineInfo.hashes; - m_mineHistory.push_back(mineInfo); - } - if (mineInfo.completed) - { - m_mineState.completeMine(); - m_host->onComplete(); - m_miningStatus = Mined; - } - else - m_host->onProgressed(); - } - } - else - { - this_thread::sleep_for(chrono::milliseconds(100)); - } -} diff --git a/libethereum/Miner.h b/libethereum/Miner.h index 3abf93770..e69de29bb 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -1,166 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . - */ -/** @file Miner.h - * @author Alex Leverington - * @author Gav Wood - * @date 2014 - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "State.h" - -namespace dev -{ - -namespace eth -{ - -/** - * @brief Class for hosting one or more Miners. - * @warning Must be implemented in a threadsafe manner since it will be called from multiple - * miner threads. - */ -class MinerHost -{ -public: - virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. - virtual void onProgressed() {} ///< Called once some progress has been made. - virtual void onComplete() {} ///< Called once a block is found. - virtual bool force() const = 0; ///< @returns true iff the Miner should mine regardless of the number of transactions. - virtual bool turbo() const = 0; ///< @returns true iff the Miner should use GPU if possible. -}; - -class OldMiner -{ -public: - virtual ~OldMiner(); - - virtual void noteStateChange() = 0; - virtual bool isComplete() const = 0; - virtual bytes const& blockData() const = 0; -}; - -class AsyncMiner: public OldMiner -{ -public: - /// Null constructor. - AsyncMiner(): m_host(nullptr) {} - - /// Constructor. - AsyncMiner(MinerHost* _host, unsigned _id = 0): m_host(_host), m_id(_id) {} - - /// Setup its basics. - void setup(MinerHost* _host, unsigned _id = 0) { m_host = _host; m_id = _id; } - - /// Start mining. - virtual void start() {} - - /// Stop mining. - virtual void stop() {} - - /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). - virtual bool isRunning() const { return false; } - -protected: - MinerHost* m_host = nullptr; ///< Our host. - unsigned m_id = 0; ///< Our unique id. -}; - -/** - * @brief Implements Miner. - * To begin mining, use start() & stop(). noteStateChange() can be used to reset the mining and set up the - * State object according to the host. Use isRunning() to determine if the miner has been start()ed. - * Use isComplete() to determine if the miner has finished mining. - * - * blockData() can be used to retrieve the complete block, ready for insertion into the BlockChain. - * - * Information on the mining can be queried through miningProgress() and miningHistory(). - * @threadsafe - * @todo Signal Miner to restart once with condition variables. - */ -class LocalMiner: public AsyncMiner, Worker -{ -public: - /// Null constructor. - LocalMiner() {} - - /// Constructor. - LocalMiner(MinerHost* _host, unsigned _id = 0); - - /// Move-constructor. - LocalMiner(LocalMiner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); std::swap(m_pow, _m.m_pow); } - - /// Move-assignment. - LocalMiner& operator=(LocalMiner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); std::swap(m_pow, _m.m_pow); return *this; } - - /// Destructor. Stops miner. - ~LocalMiner() { stop(); } - - /// Setup its basics. - void setup(MinerHost* _host, unsigned _id = 0); - - /// Start mining. - void start() { startWorking(); } - - /// Stop mining. - void stop() { stopWorking(); } - - /// Call to notify Miner of a state change. - virtual void noteStateChange() override { m_miningStatus = Preparing; } - - /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). - bool isRunning() const override { return isWorking(); } - - /// @returns true if mining is complete. - virtual bool isComplete() const override { return m_miningStatus == Mined; } - - /// @returns the internal State object. - virtual bytes const& blockData() const override { return m_mineState.blockData(); } - - /// Check the progress of the mining. - MineProgress miningProgress() const { Guard l(x_mineInfo); return m_mineProgress; } - - /// Get and clear the mining history. - std::list miningHistory() { Guard l(x_mineInfo); auto ret = m_mineHistory; m_mineHistory.clear(); return ret; } - - /// @returns the state on which we mined. - State const& state() const { return m_mineState; } - -private: - /// Do some work on the mining. - virtual void doWork(); - - enum MiningStatus { Waiting, Preparing, Mining, Mined, Stopping, Stopped }; - MiningStatus m_miningStatus = Waiting; ///< TODO: consider mutex/atomic variable. - State m_mineState; ///< The state on which we are mining, generally equivalent to m_postMine. - std::unique_ptr m_pow; ///< Our miner. - - mutable Mutex x_mineInfo; ///< Lock for the mining progress & history. - MineProgress m_mineProgress; ///< What's our progress? - std::list m_mineHistory; ///< What the history of our mining? -}; - -} -} From f22540f0e05f4984d2f590e9a3a63c164b89ab5f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 01:38:04 +0200 Subject: [PATCH 070/108] Lots of build fixes. Now minimal version builds ok. --- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 11 +- libethash-cl/ethash_cl_miner.cpp | 2 + libethash-cl/ethash_cl_miner.h | 2 + libethcore/Common.cpp | 3 +- libethcore/Common.h | 3 - libethcore/Ethash.cpp | 14 ++- libethcore/Ethash.h | 6 +- libethereum/Client.cpp | 124 ++++++++++------------ libethereum/Client.h | 10 +- libethereum/ClientBase.cpp | 4 +- libethereum/ClientBase.h | 43 ++++---- libethereum/Farm.h | 33 ++++-- libethereum/Interface.h | 2 +- libethereum/Miner.cpp | 0 libethereum/Miner.h | 0 libweb3jsonrpc/WebThreeStubServerBase.cpp | 5 +- libwebthree/WebThree.cpp | 4 +- libwebthree/WebThree.h | 3 +- 19 files changed, 143 insertions(+), 128 deletions(-) delete mode 100644 libethereum/Miner.cpp delete mode 100644 libethereum/Miner.h diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 374829a61..03d216a17 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -164,7 +164,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%2 D%3 H%4 v%5").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(c_ethashVersion).arg(dev::Version)); + ui->blockCount->setText(QString("PV%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(ProofOfWork::name()).arg(ProofOfWork::revision()).arg(dev::Version)); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); diff --git a/eth/main.cpp b/eth/main.cpp index 08f4b1de4..66abefd54 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #if ETH_READLINE #include #include @@ -44,7 +45,6 @@ #include #include #endif -#include #include "BuildInfo.h" using namespace std; using namespace dev; @@ -208,7 +208,7 @@ void doInitDAG(unsigned _n) BlockInfo bi; bi.number = _n; cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; - Ethasher::get()->full(bi); + Ethash::prep(bi); exit(0); } @@ -269,7 +269,6 @@ int main(int argc, char** argv) /// Mining params unsigned mining = ~(unsigned)0; - int miners = -1; bool forceMining = false; KeyPair sigKey = KeyPair::create(); Secret sessionSecret; @@ -478,8 +477,6 @@ int main(int argc, char** argv) g_logVerbosity = atoi(argv[++i]); else if ((arg == "-x" || arg == "--peers") && i + 1 < argc) peers = atoi(argv[++i]); - else if ((arg == "-t" || arg == "--miners") && i + 1 < argc) - miners = atoi(argv[++i]); else if ((arg == "-o" || arg == "--mode") && i + 1 < argc) { string m = argv[++i]; @@ -541,9 +538,7 @@ int main(int argc, char** argv) killChain, nodeMode == NodeMode::Full ? set{"eth", "shh"} : set(), netPrefs, - &nodesState, - miners - ); + &nodesState); if (mode == OperationMode::DAGInit) doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0)); diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 96f1fa582..016d8af58 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -50,6 +50,8 @@ static void add_definition(std::string& source, char const* id, unsigned value) source.insert(source.begin(), buf, buf + strlen(buf)); } +ethash_cl_miner::search_hook::~search_hook() {} + ethash_cl_miner::ethash_cl_miner() : m_opencl_1_1() { diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index e478c739f..d3d9f0223 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -12,6 +12,8 @@ class ethash_cl_miner public: struct search_hook { + virtual ~search_hook(); // always a virtual destructor for a class with virtuals. + // reports progress, return true to abort virtual bool found(uint64_t const* nonces, uint32_t count) = 0; virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index f0e749aaa..a0ceb389e 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,7 @@ #include #include #include "Exceptions.h" +#include "ProofOfWork.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -41,7 +42,7 @@ const unsigned c_databaseVersionModifier = 1; const unsigned c_databaseVersionModifier = 0; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (c_ethashVersion << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 4d01055f1..bb704405a 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -41,9 +41,6 @@ extern const unsigned c_minorProtocolVersion; /// Current database version. extern const unsigned c_databaseVersion; -/// Current database version. -extern const unsigned c_ethashVersion; - /// User-friendly string representation of the amount _b in wei. std::string formatBalance(bigint const& _b); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index ac54ebe4d..03c7a3654 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -70,8 +70,7 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) void Ethash::prep(BlockInfo const& _header) { - if (_header.number % ETHASH_EPOCH_LENGTH == 1) - EthashAux::full(_header); + EthashAux::full(_header); } bool Ethash::preVerify(BlockInfo const& _header) @@ -206,6 +205,12 @@ Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): { } +Ethash::GPUMiner::~GPUMiner() +{ + delete m_hook; + delete m_miner; +} + bool Ethash::GPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; @@ -221,7 +226,10 @@ void Ethash::GPUMiner::kickOff(WorkPackage const& _work) { if (m_miner) m_hook->abort(); - m_miner.reset(new ethash_cl_miner); + + delete m_miner; + m_miner = new ethash_cl_miner; + auto p = EthashAux::params(_work.seedHash); auto cb = [&](void* d) { EthashAux::full(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; m_miner->init(p, cb, 32); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 458cb4e6c..1a7d82149 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -105,6 +105,7 @@ public: public: GPUMiner(ConstructionInfo const& _ci); + ~GPUMiner(); static unsigned instances() { return 1; } @@ -115,8 +116,9 @@ public: private: bool report(uint64_t _nonce); - std::unique_ptr m_hook; - std::unique_ptr m_miner; + EthashCLHook* m_hook; + ethash_cl_miner* m_miner; + h256 m_minerSeed; WorkPackage m_lastWork; ///< Work loaded into m_miner. MineInfo m_info; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 81023f9ef..79216f609 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -126,9 +126,9 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for m_preMine(m_stateDB, BaseState::CanonGenesis), m_postMine(m_stateDB) { - m_tqReady = m_tq->onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); - m_bqReady = m_bq->onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); - m_farm->onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); + m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); + m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); @@ -151,9 +151,9 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_preMine(m_stateDB), m_postMine(m_stateDB) { - m_tq->onReady([=](){ this->onTransactionQueueReady(); }); - m_bq->onReady([=](){ this->onBlockQueueReady(); }); - m_farm->onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); + m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); + m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); @@ -210,7 +210,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_localMiners.clear(); + m_farm.stop(); m_preMine = State(); m_postMine = State(); @@ -248,11 +248,7 @@ void Client::clearPending() m_postMine = m_preMine; } - { - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - m.noteStateChange(); - } + startMining(); noteChanged(changeds); } @@ -315,34 +311,23 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed) void Client::setForceMining(bool _enable) { m_forceMining = _enable; - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - m.noteStateChange(); + startMining(); } -MineProgress Client::miningProgress() const +MiningProgress Client::miningProgress() const { - MineProgress ret; - ReadGuard l(x_localMiners); - for (auto& m: m_localMiners) - ret.combine(m.miningProgress()); - return ret; + return MiningProgress(); } uint64_t Client::hashrate() const { - uint64_t ret = 0; - ReadGuard l(x_localMiners); - for (LocalMiner const& m: m_localMiners) - ret += m.miningProgress().hashes / m.miningProgress().ms; - return ret / 1000; + return 0; } std::list Client::miningHistory() { std::list ret; - - ReadGuard l(x_localMiners); +/* ReadGuard l(x_localMiners); if (m_localMiners.empty()) return ret; ret = m_localMiners[0].miningHistory(); @@ -353,11 +338,11 @@ std::list Client::miningHistory() auto li = l.begin(); for (; ri != ret.end() && li != l.end(); ++ri, ++li) ri->combine(*li); - } + }*/ return ret; } -void Client::setupState(State& _s) +/*void Client::setupState(State& _s) { { ReadGuard l(x_stateDB); @@ -378,7 +363,7 @@ void Client::setupState(State& _s) } else _s.commitToMine(m_bc); -} +}*/ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice, Address const& _from) { @@ -406,15 +391,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 ProofOfWork::WorkPackage Client::getWork() { - Guard l(x_remoteMiner); - BlockInfo bi; - { - ReadGuard l(x_stateDB); - m_remoteMiner.update(m_postMine, m_bc); - m_postMine.commitToMine(m_bc); - bi = m_postMine.info(); - } - return ProofOfWork::package(bi); + return ProofOfWork::package(m_miningInfo); } bool Client::submitWork(ProofOfWork::Solution const& _solution) @@ -422,7 +399,7 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) bytes newBlock; { WriteGuard l(x_stateDB); - if (!m_postMine.completeMine(_solution)) + if (!m_postMine.completeMine(_solution)) return false; newBlock = m_postMine.blockData(); } @@ -435,7 +412,7 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) void Client::syncBlockQueue() { - ImportResult ir; + ImportRoute ir; { WriteGuard l(x_stateDB); @@ -446,30 +423,33 @@ void Client::syncBlockQueue() tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); x_stateDB.lock(); - if (fresh.size()) - m_stateDB = db; + if (ir.first.empty()) + return; + m_stateDB = db; } - - if (!ir.first.empty()) - onChainChanged(ir); - return true; + onChainChanged(ir); } void Client::syncTransactionQueue() { // returns TransactionReceipts, once for each transaction. cwork << "postSTATE <== TQ"; + + h256Set changeds; TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); if (newPendingReceipts.size()) { for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - changeds.insert(PendingChangedFilter); - if (isMining()) - cnote << "Additional transaction ready: Restarting mining operation."; - resyncStateNeeded = true; + // TODO: Tell farm about new transaction (i.e. restartProofOfWork mining). + onPostStateChanged(); + + // Tell watches about the new transactions. + noteChanged(changeds); + + // Tell network about the new transactions. if (auto h = m_host.lock()) h->noteNewTransactions(); } @@ -504,27 +484,41 @@ void Client::onChainChanged(ImportRoute const& _ir) h256Set changeds; for (auto const& h: _ir.first) - if (h != _ir.second) - appendFromNewBlock(h, changeds); + appendFromNewBlock(h, changeds); changeds.insert(ChainChangedFilter); - noteChanged(changeds); // RESTART MINING - // LOCKS NEEDED? - Guard l(x_stateDB); - cwork << "preSTATE <== CHAIN"; - if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) + // LOCKS REALLY NEEDED? { - if (isMining()) - cnote << "New block on chain: Restarting mining operation."; - m_postMine = m_preMine; - resyncStateNeeded = true; - changeds.insert(PendingChangedFilter); + ReadGuard l(x_stateDB); + if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) + { + if (isMining()) + cnote << "New block on chain."; + + m_postMine = m_preMine; + changeds.insert(PendingChangedFilter); + + x_stateDB.unlock(); + onPostStateChanged(); + x_stateDB.lock(); + } + } + + noteChanged(changeds); +} +void Client::onPostStateChanged() +{ + cnote << "Post state changed: Restarting mining..."; + { + WriteGuard l(x_stateDB); m_postMine.commitToMine(m_bc); - m_farm.setWork(m_postMine.info()); + m_miningInfo = m_postMine.info(); } + + m_farm.setWork(m_miningInfo); } void Client::noteChanged(h256Set const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index 9f6bbfeb6..2235c4459 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -40,7 +40,6 @@ #include "TransactionQueue.h" #include "State.h" #include "CommonNet.h" -#include "Miner.h" #include "ABI.h" #include "Farm.h" #include "ClientBase.h" @@ -103,8 +102,6 @@ struct ClientDetail: public LogChannel { static const char* name() { return " C */ class Client: public ClientBase, Worker { - friend class OldMiner; - public: /// New-style Constructor. explicit Client( @@ -254,6 +251,10 @@ private: /// Magically called when m_tq needs syncing. Be nice and don't block. void onBlockQueueReady() { Guard l(x_fakeSignalSystemState); m_syncBlockQueue = true; } + /// Called when the post state has changed (i.e. when more transactions are in it or we're mining on a new block). + /// This updates m_miningInfo. + void onPostStateChanged(); + void checkWatchGarbage(); VersionChecker m_vc; ///< Dummy object to check & update the protocol version. @@ -265,12 +266,11 @@ private: OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it. State m_preMine; ///< The present state of the client. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). + BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine). std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. GenericFarm m_farm; ///< Our mining farm. - mutable Mutex x_remoteMiner; ///< The remote miner lock. - RemoteMiner m_remoteMiner; ///< The remote miner. Handler m_tqReady; Handler m_bqReady; diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 5a0aef7c3..ecc0fb7f5 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -20,10 +20,12 @@ * @date 2015 */ -#include #include "ClientBase.h" + +#include #include "BlockChain.h" #include "Executive.h" +#include "State.h" using namespace std; using namespace dev; diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 4b3cc5002..15dbbf1ab 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -25,6 +25,7 @@ #include #include "Interface.h" #include "LogFilter.h" +#include "TransactionQueue.h" namespace dev { @@ -60,15 +61,15 @@ struct ClientWatch }; struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; -#define cwatch dev::LogOutputStream() +#define cwatch LogOutputStream() struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; }; struct WorkOutChannel: public LogChannel { static const char* name() { return "() -#define cworkin dev::LogOutputStream() -#define cworkout dev::LogOutputStream() +#define cwork LogOutputStream() +#define cworkin LogOutputStream() +#define cworkout LogOutputStream() -class ClientBase: public dev::eth::Interface +class ClientBase: public Interface { public: ClientBase() {} @@ -110,18 +111,18 @@ public: virtual LocalisedLogEntries checkWatch(unsigned _watchId) override; virtual h256 hashFromNumber(BlockNumber _number) const override; - virtual eth::BlockInfo blockInfo(h256 _hash) const override; - virtual eth::BlockDetails blockDetails(h256 _hash) const override; - virtual eth::Transaction transaction(h256 _transactionHash) const override; - virtual eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; - virtual eth::Transactions transactions(h256 _blockHash) const override; - virtual eth::TransactionHashes transactionHashes(h256 _blockHash) const override; - virtual eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; - virtual eth::UncleHashes uncleHashes(h256 _blockHash) const override; + virtual BlockInfo blockInfo(h256 _hash) const override; + virtual BlockDetails blockDetails(h256 _hash) const override; + virtual Transaction transaction(h256 _transactionHash) const override; + virtual Transaction transaction(h256 _blockHash, unsigned _i) const override; + virtual Transactions transactions(h256 _blockHash) const override; + virtual TransactionHashes transactionHashes(h256 _blockHash) const override; + virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const override; + virtual UncleHashes uncleHashes(h256 _blockHash) const override; virtual unsigned transactionCount(h256 _blockHash) const override; virtual unsigned uncleCount(h256 _blockHash) const override; virtual unsigned number() const override; - virtual eth::Transactions pending() const override; + virtual Transactions pending() const override; virtual h256s pendingHashes() const override; void injectBlock(bytes const& _block); @@ -142,13 +143,13 @@ public: /// TODO: consider moving it to a separate interface - virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); } - virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); } - virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); } - virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::hashrate")); } - virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); } - virtual std::pair getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); } - virtual bool submitWork(eth::ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } + virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); } + virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::stopMining")); } + virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } + virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } + virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } + virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } + virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 137c137d3..09c7f0e78 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace dev { @@ -45,17 +46,25 @@ template class GenericFarm: public GenericFarmFace { public: + using WorkPackage = typename PoW::WorkPackage; + using Solution = typename PoW::Solution; + using Miner = GenericMiner; + /** * @brief Sets the current mining mission. * @param _bi The block (header) we wish to be mining. */ void setWork(BlockInfo const& _bi) { - WriteGuard l(x_work); - m_header = _bi; - m_work = PoW::package(m_header); - ReadGuard l(x_miners); - for (auto const& m: miners) + WorkPackage w; + { + WriteGuard l(x_work); + m_header = _bi; + w = m_work = PoW::package(m_header); + } + + ReadGuard l2(x_miners); + for (auto const& m: m_miners) m->setWork(m_work); } @@ -63,13 +72,13 @@ public: * @brief (Re)start miners for CPU only. * @returns true if started properly. */ - bool startCPU() { return start(); } + bool startCPU() { return start(); } /** * @brief (Re)start miners for GPU only. * @returns true if started properly. */ - bool startGPU() { start(); } + bool startGPU() { return start(); } /** * @brief Stop all mining activities. @@ -92,12 +101,14 @@ public: */ MiningProgress const& miningProgress() const { ReadGuard l(x_progress); return m_progress; } + using SolutionFound = std::function; + /** * @brief Provides a valid header based upon that received previously with setWork(). * @param _bi The now-valid header. * @return true if the header was good and that the Farm should pause until more work is submitted. */ - void onSolutionFound(function _handler) { m_onSolutionFound = _handler; } + void onSolutionFound(SolutionFound const& _handler) { m_onSolutionFound = _handler; } private: /** @@ -116,7 +127,7 @@ private: ReadGuard l(x_miners); for (std::shared_ptr const& m: m_miners) if (m.get() != _m) - m->pause(); + m->setWork(); m_work.headerHash = h256(); return true; } @@ -135,7 +146,7 @@ private: m_miners.clear(); m_miners.reserve(MinerType::instances()); for (unsigned i = 0; i < MinerType::instances(); ++i) - m_miners.push_back(new MinerType(std::make_pair(this, i))); + m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); return true; } @@ -149,7 +160,7 @@ private: WorkPackage m_work; BlockInfo m_header; - function m_onSolutionFound; + SolutionFound m_onSolutionFound; }; } diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 0ab81728b..b72a29c00 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -183,7 +183,7 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual std::pair getWork() = 0; + virtual ProofOfWork::WorkPackage getWork() = 0; /// Submit the nonce for the proof-of-work. virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/libethereum/Miner.h b/libethereum/Miner.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 7e7b83e3c..65fb71a5c 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -758,8 +758,9 @@ Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); auto r = client()->getWork(); - ret.append(toJS(r.first)); - ret.append(toJS(r.second)); + ret.append(toJS(r.headerHash)); + ret.append(toJS(r.seedHash)); + ret.append(toJS(r.boundary)); return ret; } diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 8ea2133f0..bbe0d55ec 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -42,7 +42,7 @@ WebThreeDirect::WebThreeDirect( WithExisting _we, std::set const& _interfaces, NetworkPreferences const& _n, - bytesConstRef _network, int _miners + bytesConstRef _network ): m_clientVersion(_clientVersion), m_net(_clientVersion, _n, _network) @@ -50,7 +50,7 @@ WebThreeDirect::WebThreeDirect( if (_dbPath.size()) Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0, _miners)); + m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); if (_interfaces.count("shh")) m_whisper = m_net.registerCapability(new WhisperHost); diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index 87cf62d4a..90a4aa3c2 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -112,8 +112,7 @@ public: WithExisting _we = WithExisting::Trust, std::set const& _interfaces = {"eth", "shh"}, p2p::NetworkPreferences const& _n = p2p::NetworkPreferences(), - bytesConstRef _network = bytesConstRef(), - int _miners = -1 + bytesConstRef _network = bytesConstRef() ); /// Destructor. From cd4478e4cf87963ca488590072b4b26f385a7d22 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 18:12:05 +0200 Subject: [PATCH 071/108] Various fixes for mining. --- alethzero/DownloadView.h | 1 - alethzero/MainWin.cpp | 10 ++-- alethzero/MiningView.cpp | 11 ++-- alethzero/MiningView.h | 4 +- eth/main.cpp | 17 +++--- exp/main.cpp | 54 +++++++++++++++---- libdevcore/Worker.h | 3 ++ libethcore/Ethash.cpp | 52 +++++++++--------- libethcore/Ethash.h | 22 +++++--- libethcore/Miner.h | 35 ++++++------ libethereum/Farm.h | 45 ++++++++++++---- mix/MixClient.cpp | 23 +++++--- mix/MixClient.h | 4 +- neth/main.cpp | 10 +--- test/TestHelper.cpp | 31 +++++++++++ test/TestHelper.h | 5 +- test/blockchain.cpp | 111 ++++++++++++++------------------------- test/dagger.cpp | 12 ++--- test/stateOriginal.cpp | 11 ++-- third/MainWin.cpp | 2 +- 20 files changed, 269 insertions(+), 194 deletions(-) diff --git a/alethzero/DownloadView.h b/alethzero/DownloadView.h index 22a11651c..d0fc445f8 100644 --- a/alethzero/DownloadView.h +++ b/alethzero/DownloadView.h @@ -32,7 +32,6 @@ #endif namespace dev { namespace eth { -struct MineInfo; class DownloadMan; }} diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 03d216a17..2e4478594 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -45,7 +45,7 @@ #endif #include #include -#include +#include #include #include #include @@ -164,7 +164,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(ProofOfWork::name()).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); @@ -952,7 +952,7 @@ void Main::on_preview_triggered() void Main::refreshMining() { - MineProgress p = ethereum()->miningProgress(); + MiningProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining"); if (!ui->miningView->isVisible()) return; @@ -1481,7 +1481,7 @@ void Main::on_blocks_currentItemChanged() s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { - auto e = Ethasher::eval(info); + auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash << "" << "
"; } @@ -1510,7 +1510,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Nonce: " << uncle.nonce << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = Ethasher::eval(uncle); + auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash) diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index 63d1fcf99..e020408ea 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MineProgress; +using dev::eth::MiningProgress; // functions using dev::toString; @@ -50,12 +50,13 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MineProgress const& _p) +void MiningView::appendStats(list const& _i, MiningProgress const& _p) { + (void)_p; if (_i.empty()) return; - unsigned o = m_values.size(); +/* unsigned o = m_values.size(); for (MineInfo const& i: _i) { m_values.push_back(i.best); @@ -91,7 +92,7 @@ void MiningView::appendStats(list const& _i, MineProgress const& _p) m_completes.erase(remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}), m_completes.end()); m_progress = _p; - update(); + update();*/ } void MiningView::resetStats() @@ -101,6 +102,7 @@ void MiningView::resetStats() void MiningView::paintEvent(QPaintEvent*) { + /* Grapher g; QPainter p(this); @@ -115,4 +117,5 @@ void MiningView::paintEvent(QPaintEvent*) g.ruleY(r - 1, QColor(128, 128, 128)); for (auto r: m_completes) g.ruleY(r, QColor(192, 64, 64)); + */ } diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 8f3135f75..65b9f2ec9 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MineProgress const& _p); + void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MineProgress m_progress; + dev::eth::MiningProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/eth/main.cpp b/eth/main.cpp index 66abefd54..24bf839aa 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -126,13 +126,16 @@ void help() #if ETH_JSONRPC << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl +#endif +#if ETH_EVMJIT + << " -J,--jit Enable EVM JIT (default: off)." << endl #endif << " -K,--kill First kill the blockchain." << endl << " --listen-ip Listen on the given port for incoming connections (default: 30303)." << endl << " -l,--listen Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl << " -u,--public-ip Force public ip to given (default: auto)." << endl << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl - << " -n,--upnp Use upnp for NAT (default: on)." << endl + << " -n,-u,--upnp Use upnp for NAT (default: on)." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl << " -p,--port Connect to remote port (default: 30303)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl @@ -140,7 +143,6 @@ void help() << " -r,--remote Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl << " -S,--temporary-secret Set the secret key for use with send command, for this session only." << endl - << " -t,--miners Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl << " -V,--version Show the version and exit." << endl @@ -336,7 +338,7 @@ int main(int argc, char** argv) exportFrom = argv[++i]; else if (arg == "--only" && i + 1 < argc) exportTo = exportFrom = argv[++i]; - else if ((arg == "-n" || arg == "--upnp") && i + 1 < argc) + else if ((arg == "-n" || arg == "-u" || arg == "--upnp") && i + 1 < argc) { string m = argv[++i]; if (isTrue(m)) @@ -490,15 +492,12 @@ int main(int argc, char** argv) return -1; } } - else if (arg == "--jit") - { #if ETH_EVMJIT + else if (arg == "-J" || arg == "--jit") + { jit = true; -#else - cerr << "EVM JIT not enabled" << endl; - return -1; -#endif } +#endif else if (arg == "-h" || arg == "--help") help(); else if (arg == "-V" || arg == "--version") diff --git a/exp/main.cpp b/exp/main.cpp index 88f1075a9..933fda1a6 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,9 +34,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -109,18 +109,50 @@ int main() #else int main() { -#if ETH_ETHASHCL - EthashCL ecl; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; - cdebug << (h256)u256((bigint(1) << 256) / genesis.difficulty); - std::pair r; - while (!r.first.completed) - r = ecl.mine(genesis, 1000); - cdebug << r.second.mixHash << r.second.nonce; - EthashCL::assignResult(r.second, genesis); - assert(EthashCPU::verify(genesis)); -#endif + cdebug << genesis.boundary(); + + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + BlockInfo bi = g; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + ProofOfWork::assignResult(sol, bi); + return completed = true; + }); + f.setWork(bi); + for (unsigned i = 0; !completed && i < timeout * 10; ++i, cout << f.miningProgress() << "\r" << flush) + this_thread::sleep_for(chrono::milliseconds(100)); + cdebug << bi.mixHash << bi.nonce << (Ethash::verify(bi) ? "GOOD" : "bad"); + }; + + f.startCPU(); + mine(f, genesis, 10); + mine(f, genesis, 10); + f.startGPU(); + + cdebug << "Good:"; + genesis.difficulty = 1 << 18; + genesis.noteDirty(); + mine(f, genesis, 3); + + cdebug << "Bad:"; + genesis.difficulty = (u256(1) << 40); + genesis.noteDirty(); + mine(f, genesis, 3); + + cdebug << "Good:"; + genesis.difficulty = 1 << 18; + genesis.noteDirty(); + mine(f, genesis, 3); + + cdebug << "Bad:"; + genesis.difficulty = (u256(1) << 40); + genesis.noteDirty(); + mine(f, genesis, 3); + return 0; } #endif diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 6a35d6c4c..24ff4cc15 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -66,6 +66,9 @@ protected: /// Called when is to be stopped, just prior to thread being joined. virtual void doneWorking() {} + /// Blocks caller into worker thread has finished. + void join() const { Guard l(x_work); try { if (m_work) m_work->join(); } catch (...) {} } + private: std::string m_name; unsigned m_idleWaitMs = 0; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 03c7a3654..f66188976 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -63,7 +63,7 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithNonce); + ret.headerHash = _bi.headerHash(WithoutNonce); ret.seedHash = _bi.seedHash(); return ret; } @@ -95,9 +95,8 @@ bool Ethash::verify(BlockInfo const& _header) return false; #endif - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); auto result = EthashAux::eval(_header); - bool slow = result.value <= boundary && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; #if ETH_DEBUG || !ETH_TRUE if (!pre && slow) @@ -107,7 +106,7 @@ bool Ethash::verify(BlockInfo const& _header) cwarn << "nonce:" << _header.nonce; cwarn << "mixHash:" << _header.mixHash; cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << boundary; + cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } @@ -125,16 +124,18 @@ void Ethash::CPUMiner::workLoop() ethash_return_value ethashReturn; auto p = EthashAux::params(m_work.seedHash); - void const* dagPointer = EthashAux::full(m_work.headerHash).data(); + void const* dagPointer = EthashAux::full(m_work.seedHash).data(); uint8_t const* headerHashPointer = m_work.headerHash.data(); h256 boundary = m_work.boundary; - unsigned hashCount = 0; + unsigned hashCount = 1; for (; !shouldStop(); tryNonce++, hashCount++) { ethash_compute_full(ðashReturn, dagPointer, &p, headerHashPointer, tryNonce); h256 value = h256(ethashReturn.result, h256::ConstructFromPointer); if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256(ethashReturn.mix_hash, h256::ConstructFromPointer)})) break; + if (!(hashCount % 1000)) + accumulateHashes(1000); } } @@ -148,6 +149,7 @@ public: void abort() { Guard l(x_all); + m_owner->m_work.headerHash = h256(); if (m_aborted) return; // cdebug << "Attempting to abort"; @@ -159,8 +161,6 @@ public: m_aborted = m_abort = false; } - uint64_t fetchTotal() { Guard l(x_all); auto ret = m_total; m_total = 0; return ret; } - protected: virtual bool found(uint64_t const* _nonces, uint32_t _count) override { @@ -180,7 +180,7 @@ protected: { Guard l(x_all); // cdebug << "Searched" << _count << "from" << _startNonce; - m_total += _count; + m_owner->accumulateHashes(_count); m_last = _startNonce + _count; if (m_abort) { @@ -192,7 +192,6 @@ protected: private: Mutex x_all; - uint64_t m_total; uint64_t m_last; bool m_abort = false; bool m_aborted = true; @@ -214,38 +213,43 @@ Ethash::GPUMiner::~GPUMiner() bool Ethash::GPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = EthashAux::eval(m_lastWork.seedHash, m_lastWork.headerHash, n); - if (r.value < m_lastWork.boundary) + Result r = EthashAux::eval(m_work.seedHash, m_work.headerHash, n); + if (r.value < m_work.boundary) return submitProof(Solution{n, r.mixHash}); return false; } void Ethash::GPUMiner::kickOff(WorkPackage const& _work) { - if (!m_miner || m_minerSeed != _work.seedHash) + m_work = _work; + startWorking(); +} + +void Ethash::GPUMiner::workLoop() +{ + // take local copy of work since it may end up being overwritten by kickOff/pause. + WorkPackage w = m_work; + if (!m_miner || m_minerSeed != w.seedHash) { - if (m_miner) - m_hook->abort(); + m_minerSeed = w.seedHash; delete m_miner; m_miner = new ethash_cl_miner; - auto p = EthashAux::params(_work.seedHash); - auto cb = [&](void* d) { EthashAux::full(_work.seedHash, bytesRef((byte*)d, p.full_size)); }; + auto p = EthashAux::params(m_minerSeed); + auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; m_miner->init(p, cb, 32); } - if (m_lastWork.headerHash != _work.headerHash) - { - m_hook->abort(); - uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)_work.boundary >> 192); - m_miner->search(_work.headerHash.data(), upper64OfBoundary, *m_hook); - } - m_lastWork = _work; + + uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); + m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); } void Ethash::GPUMiner::pause() { m_hook->abort(); + stopWorking(); + m_work.headerHash = h256(); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 1a7d82149..8f1ba3eb3 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -59,6 +59,11 @@ public: struct WorkPackage { + WorkPackage() = default; + + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + h256 boundary; h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; @@ -89,17 +94,16 @@ public: startWorking(); } - void pause() override { stopWorking(); } + void pause() override { stopWorking(); m_work.reset(); } private: void workLoop() override; WorkPackage m_work; - MineInfo m_info; }; #if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner + class GPUMiner: public Miner, Worker { friend class dev::eth::EthashCLHook; @@ -114,14 +118,16 @@ public: void pause() override; private: + void workLoop() override; bool report(uint64_t _nonce); - EthashCLHook* m_hook; - ethash_cl_miner* m_miner; + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; - h256 m_minerSeed; - WorkPackage m_lastWork; ///< Work loaded into m_miner. - MineInfo m_info; + h256 m_minerSeed; ///< Last seed in m_miner + WorkPackage m_work; ///< Work to be done by GPU, set with kickOff and picked up in workLoop. }; #else using GPUMiner = CPUMiner; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 9372c06b1..ea51b0eb5 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -34,30 +34,24 @@ namespace dev namespace eth { -struct MineInfo -{ - MineInfo() = default; - MineInfo(bool _completed): completed(_completed) {} - void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; } - double requirement = 0; - double best = 1e99; - unsigned hashes = 0; - bool completed = false; -}; - /** * @brief Describes the progress of a mining operation. */ struct MiningProgress { - void combine(MiningProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } - double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. - double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. - double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } unsigned hashes = 0; ///< Total number of hashes computed. unsigned ms = 0; ///< Total number of milliseconds of mining thus far. }; +struct MineInfo: public MiningProgress {}; + +inline std::ostream& operator<<(std::ostream& _out, MiningProgress const& _p) +{ + _out << (_p.hashes * 1000 / _p.ms) << "H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << "s"; + return _out; +} + template class GenericMiner; /** @@ -103,13 +97,18 @@ public: void setWork(WorkPackage const& _work = WorkPackage()) { Guard l(x_work); + if (_work.headerHash == m_work.headerHash) + return; if (_work.headerHash != h256()) - kickOff(m_work); + kickOff(_work); else if (m_work.headerHash == h256() && _work.headerHash != h256()) pause(); m_work = _work; + m_hashCount = 0; } + unsigned hashCount() { return m_hashCount; } + unsigned index() const { return m_index; } protected: @@ -146,12 +145,16 @@ protected: WorkPackage const& work() const { return m_work; } + void accumulateHashes(unsigned _n) { m_hashCount += _n; } + private: FarmFace* m_farm = nullptr; unsigned m_index; Mutex x_work; WorkPackage m_work; + + unsigned m_hashCount = 0; }; } diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 09c7f0e78..c20c27e6d 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -56,16 +56,16 @@ public: */ void setWork(BlockInfo const& _bi) { - WorkPackage w; - { - WriteGuard l(x_work); - m_header = _bi; - w = m_work = PoW::package(m_header); - } - + WriteGuard l(x_work); ReadGuard l2(x_miners); + m_header = _bi; + auto p = PoW::package(m_header); + if (p.headerHash == m_work.headerHash) + return; + m_work = p; for (auto const& m: m_miners) m->setWork(m_work); + resetTimer(); } /** @@ -99,7 +99,19 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const { ReadGuard l(x_progress); return m_progress; } + MiningProgress const& miningProgress() const + { + MiningProgress p; + p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); + { + ReadGuard l2(x_miners); + for (auto const& i: m_miners) + p.hashes += i->hashCount(); + } + ReadGuard l(x_progress); + m_progress = p; + return m_progress; + } using SolutionFound = std::function; @@ -110,6 +122,8 @@ public: */ void onSolutionFound(SolutionFound const& _handler) { m_onSolutionFound = _handler; } + WorkPackage work() const { ReadGuard l(x_work); return m_work; } + private: /** * @brief Called from a Miner to note a WorkPackage has a solution. @@ -140,21 +154,32 @@ private: template bool start() { - WriteGuard l(x_miners); + ReadGuard l(x_work); + WriteGuard l2(x_miners); if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) return true; m_miners.clear(); m_miners.reserve(MinerType::instances()); for (unsigned i = 0; i < MinerType::instances(); ++i) + { m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + resetTimer(); return true; } + void resetTimer() + { + m_lastStart = std::chrono::steady_clock::now(); + } + mutable SharedMutex x_miners; std::vector> m_miners; mutable SharedMutex x_progress; - MiningProgress m_progress; + mutable MiningProgress m_progress; + std::chrono::steady_clock::time_point m_lastStart; mutable SharedMutex x_work; WorkPackage m_work; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 2e8bd5384..76552fb06 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -20,6 +20,7 @@ * Ethereum IDE client. */ +#include "MixClient.h" #include #include #include @@ -28,10 +29,8 @@ #include #include #include - #include "Exceptions.h" -#include "MixClient.h" - +using namespace std; using namespace dev; using namespace dev::eth; @@ -250,9 +249,17 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - ProofOfWork pow; - while (!m_state.mine(&pow).completed) {} - m_state.completeMine(); + GenericFarm f; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + return completed = m_state.completeMine(sol); + }); + f.setWork(m_state.info()); + f.startCPU(); + while (!completed) + this_thread::sleep_for(chrono::milliseconds(20)); + bc().import(m_state.blockData(), m_stateDB); m_state.sync(bc()); m_startState = m_state; @@ -392,9 +399,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MineProgress MixClient::miningProgress() const +eth::MiningProgress MixClient::miningProgress() const { - return eth::MineProgress(); + return eth::MiningProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index 649c7694f..c496df754 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -67,8 +67,8 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MineProgress miningProgress() const override; - std::pair getWork() override { return std::pair(); } + eth::MiningProgress miningProgress() const override; + eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } virtual void flushTransactions() override {} diff --git a/neth/main.cpp b/neth/main.cpp index fd3d3f403..4c38da0a4 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -40,7 +40,6 @@ #include #include #endif -#include #include "BuildInfo.h" #undef KEY_EVENT // from windows.h @@ -332,7 +331,6 @@ int main(int argc, char** argv) unsigned mining = ~(unsigned)0; NodeMode mode = NodeMode::Full; unsigned peers = 5; - int miners = -1; #if ETH_JSONRPC int jsonrpc = 8080; #endif @@ -502,8 +500,6 @@ int main(int argc, char** argv) g_logVerbosity = atoi(argv[++i]); else if ((arg == "-x" || arg == "--peers") && i + 1 < argc) peers = atoi(argv[++i]); - else if ((arg == "-t" || arg == "--miners") && i + 1 < argc) - miners = atoi(argv[++i]); else if ((arg == "-o" || arg == "--mode") && i + 1 < argc) { string m = argv[++i]; @@ -553,9 +549,7 @@ int main(int argc, char** argv) killChain ? WithExisting::Kill : WithExisting::Trust, mode == NodeMode::Full ? set{"eth", "shh"} : set(), netPrefs, - &nodesState, - miners - ); + &nodesState); web3.setIdealPeerCount(peers); std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); @@ -1253,7 +1247,7 @@ int main(int argc, char** argv) if (c && c->isMining()) { mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON"); - dev::eth::MineProgress p = c->miningProgress(); + dev::eth::MiningProgress p = c->miningProgress(); auto speed = boost::format("%2% kH/s @ %1%s") % (p.ms / 1000) % (p.ms ? p.hashes / p.ms : 0); mvwprintw(consolewin, qheight - 2, width / 4 - speed.str().length() - 2, speed.str().c_str()); } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 45fe55b07..93c564e62 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -62,6 +62,37 @@ void connectClients(Client& c1, Client& c2) c2.connect("127.0.0.1", c1Port); #endif } + +void mine(State& s, BlockChain const& _bc) +{ + s.commitToMine(_bc); + GenericFarm f; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + return completed = s.completeMine(sol); + }); + f.setWork(s.info()); + f.startCPU(); + while (!completed) + this_thread::sleep_for(chrono::milliseconds(20)); +} + +void mine(BlockInfo& _bi) +{ + GenericFarm f; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + ProofOfWork::assignResult(sol, _bi); + return completed = true; + }); + f.setWork(_bi); + f.startCPU(); + while (!completed) + this_thread::sleep_for(chrono::milliseconds(20)); +} + } namespace test diff --git a/test/TestHelper.h b/test/TestHelper.h index 04ca95be4..92745bc36 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -36,9 +36,12 @@ namespace eth { class Client; +class State; void mine(Client& c, int numBlocks); void connectClients(Client& c1, Client& c2); +void mine(State& _s, BlockChain const& _bc); +void mine(BlockInfo& _bi); } @@ -225,7 +228,5 @@ public: }; }; - - } } diff --git a/test/blockchain.cpp b/test/blockchain.cpp index 8f5605898..4aa70c63a 100644 --- a/test/blockchain.cpp +++ b/test/blockchain.cpp @@ -191,11 +191,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { state.sync(bc); state.sync(bc, txs, gp); - state.commitToMine(bc); - MineInfo info; - ProofOfWork pow; - for (info.completed = false; !info.completed; info = state.mine(&pow)) {} - state.completeMine(); + mine(state, bc); } catch (Exception const& _e) { @@ -531,76 +527,55 @@ bytes createBlockRLPFromFields(mObject& _tObj) return rlpStream.out(); } -void overwriteBlockHeader(BlockInfo& _currentBlockHeader, mObject& _blObj) +void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { - if (_blObj["blockHeader"].get_obj().size() != 14) + auto ho = _blObj["blockHeader"].get_obj(); + if (ho.size() != 14) { - - BlockInfo tmp = _currentBlockHeader; - - if (_blObj["blockHeader"].get_obj().count("parentHash")) - tmp.parentHash = h256(_blObj["blockHeader"].get_obj()["parentHash"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("uncleHash")) - tmp.sha3Uncles = h256(_blObj["blockHeader"].get_obj()["uncleHash"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("coinbase")) - tmp.coinbaseAddress = Address(_blObj["blockHeader"].get_obj()["coinbase"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("stateRoot")) - tmp.stateRoot = h256(_blObj["blockHeader"].get_obj()["stateRoot"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("transactionsTrie")) - tmp.transactionsRoot = h256(_blObj["blockHeader"].get_obj()["transactionsTrie"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("receiptTrie")) - tmp.receiptsRoot = h256(_blObj["blockHeader"].get_obj()["receiptTrie"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("bloom")) - tmp.logBloom = LogBloom(_blObj["blockHeader"].get_obj()["bloom"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("difficulty")) - tmp.difficulty = toInt(_blObj["blockHeader"].get_obj()["difficulty"]); - - if (_blObj["blockHeader"].get_obj().count("number")) - tmp.number = toInt(_blObj["blockHeader"].get_obj()["number"]); - - if (_blObj["blockHeader"].get_obj().count("gasLimit")) - tmp.gasLimit = toInt(_blObj["blockHeader"].get_obj()["gasLimit"]); - - if (_blObj["blockHeader"].get_obj().count("gasUsed")) - tmp.gasUsed = toInt(_blObj["blockHeader"].get_obj()["gasUsed"]); - - if (_blObj["blockHeader"].get_obj().count("timestamp")) - tmp.timestamp = toInt(_blObj["blockHeader"].get_obj()["timestamp"]); - - if (_blObj["blockHeader"].get_obj().count("extraData")) - tmp.extraData = importByteArray(_blObj["blockHeader"].get_obj()["extraData"].get_str()); - - if (_blObj["blockHeader"].get_obj().count("mixHash")) - tmp.mixHash = h256(_blObj["blockHeader"].get_obj()["mixHash"].get_str()); + BlockInfo tmp = _header; + if (ho.count("parentHash")) + tmp.parentHash = h256(ho["parentHash"].get_str()); + if (ho.count("uncleHash")) + tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + if (ho.count("coinbase")) + tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + if (ho.count("stateRoot")) + tmp.stateRoot = h256(ho["stateRoot"].get_str()); + if (ho.count("transactionsTrie")) + tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + if (ho.count("receiptTrie")) + tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + if (ho.count("bloom")) + tmp.logBloom = LogBloom(ho["bloom"].get_str()); + if (ho.count("difficulty")) + tmp.difficulty = toInt(ho["difficulty"]); + if (ho.count("number")) + tmp.number = toInt(ho["number"]); + if (ho.count("gasLimit")) + tmp.gasLimit = toInt(ho["gasLimit"]); + if (ho.count("gasUsed")) + tmp.gasUsed = toInt(ho["gasUsed"]); + if (ho.count("timestamp")) + tmp.timestamp = toInt(ho["timestamp"]); + if (ho.count("extraData")) + tmp.extraData = importByteArray(ho["extraData"].get_str()); + if (ho.count("mixHash")) + tmp.mixHash = h256(ho["mixHash"].get_str()); + tmp.noteDirty(); // find new valid nonce - - if (tmp != _currentBlockHeader) + if (tmp != _header) { - _currentBlockHeader = tmp; - - ProofOfWork pow; - std::pair ret; - while (!ProofOfWork::verify(_currentBlockHeader)) - { - ret = pow.mine(_currentBlockHeader, 1000, true); - Ethash::assignResult(ret.second, _currentBlockHeader); - } + mine(tmp); + _header = tmp; } } else { // take the blockheader as is - const bytes c_blockRLP = createBlockRLPFromFields(_blObj["blockHeader"].get_obj()); + const bytes c_blockRLP = createBlockRLPFromFields(ho); const RLP c_bRLP(c_blockRLP); - _currentBlockHeader.populateFromHeader(c_bRLP, IgnoreNonce); + _header.populateFromHeader(c_bRLP, IgnoreNonce); } } @@ -631,13 +606,7 @@ BlockInfo constructBlock(mObject& _o) void updatePoW(BlockInfo& _bi) { - ProofOfWork pow; - std::pair ret; - while (!ProofOfWork::verify(_bi)) - { - ret = pow.mine(_bi, 10000, true); - Ethash::assignResult(ret.second, _bi); - } + mine(_bi); _bi.noteDirty(); } diff --git a/test/dagger.cpp b/test/dagger.cpp index 4abba5090..367c422ad 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -25,7 +25,7 @@ #include "JsonSpiritHeaders.h" #include #include -#include +#include #include #include "TestHelper.h" @@ -63,18 +63,18 @@ BOOST_AUTO_TEST_CASE(basic_test) unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); - BOOST_REQUIRE_EQUAL(Ethasher::get()->params(header).cache_size, cacheSize); - BOOST_REQUIRE_EQUAL(sha3(bytesConstRef((byte const*)Ethasher::get()->light(header), cacheSize)), cacheHash); + BOOST_REQUIRE_EQUAL(EthashAux::get()->params(header).cache_size, cacheSize); + BOOST_REQUIRE_EQUAL(sha3(bytesConstRef((byte const*)EthashAux::get()->light(header), cacheSize)), cacheHash); #if TEST_FULL unsigned fullSize(o["full_size"].get_int()); h256 fullHash(o["full_hash"].get_str()); - BOOST_REQUIRE_EQUAL(Ethasher::get()->full(header).size(), fullSize); - BOOST_REQUIRE_EQUAL(sha3(Ethasher::get()->full(header)), fullHash); + BOOST_REQUIRE_EQUAL(EthashAux::get()->full(header).size(), fullSize); + BOOST_REQUIRE_EQUAL(sha3(EthashAux::get()->full(header)), fullHash); #endif h256 result(o["result"].get_str()); - Ethasher::Result r = Ethasher::eval(header); + Ethash::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp index 40f759434..e1a3c7c4a 100644 --- a/test/stateOriginal.cpp +++ b/test/stateOriginal.cpp @@ -25,7 +25,9 @@ #include #include #include +#include #include +#include "TestHelper.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -67,10 +69,8 @@ BOOST_AUTO_TEST_CASE(Complex) cout << s; // Mine to get some ether! - s.commitToMine(bc); - ProofOfWork pow; - while (!s.mine(&pow).completed) {} - s.completeMine(); + mine(s, bc); + bc.attemptImport(s.blockData(), stateDB); cout << bc; @@ -89,8 +89,7 @@ BOOST_AUTO_TEST_CASE(Complex) // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - while (!s.mine(&pow).completed) {} - s.completeMine(); + mine(s, bc); bc.attemptImport(s.blockData(), stateDB); cout << bc; diff --git a/third/MainWin.cpp b/third/MainWin.cpp index b03723131..12625ffbc 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -465,7 +465,7 @@ void Main::on_urlEdit_returnPressed() void Main::refreshMining() { - dev::eth::MineProgress p = ethereum()->miningProgress(); + dev::eth::MiningProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining"); } From e5ac73bf0fddf6d0a803ed99f14217f10bc573fa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 21:36:55 +0200 Subject: [PATCH 072/108] Thread management fixes for Farm. --- exp/main.cpp | 21 +++++++++------------ libdevcore/Worker.cpp | 22 +++++++++++++++++----- libdevcore/Worker.h | 10 +++++++++- libethcore/Ethash.cpp | 36 +++++++++++++++++++++--------------- libethcore/Ethash.h | 10 +++------- libethcore/Miner.h | 31 ++++++++++++++++++------------- libethereum/Farm.h | 7 ++++++- 7 files changed, 83 insertions(+), 54 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 933fda1a6..2055c49e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -125,33 +125,30 @@ int main() f.setWork(bi); for (unsigned i = 0; !completed && i < timeout * 10; ++i, cout << f.miningProgress() << "\r" << flush) this_thread::sleep_for(chrono::milliseconds(100)); + cout << endl << flush; cdebug << bi.mixHash << bi.nonce << (Ethash::verify(bi) ? "GOOD" : "bad"); }; + Ethash::prep(genesis); + + genesis.difficulty = u256(1) << 40; + genesis.noteDirty(); f.startCPU(); mine(f, genesis, 10); - mine(f, genesis, 10); + f.startGPU(); cdebug << "Good:"; genesis.difficulty = 1 << 18; genesis.noteDirty(); - mine(f, genesis, 3); + mine(f, genesis, 30); cdebug << "Bad:"; genesis.difficulty = (u256(1) << 40); genesis.noteDirty(); - mine(f, genesis, 3); + mine(f, genesis, 30); - cdebug << "Good:"; - genesis.difficulty = 1 << 18; - genesis.noteDirty(); - mine(f, genesis, 3); - - cdebug << "Bad:"; - genesis.difficulty = (u256(1) << 40); - genesis.noteDirty(); - mine(f, genesis, 3); + f.stop(); return 0; } diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index bc8fe97f2..65e8efcbb 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -27,12 +27,20 @@ using namespace std; using namespace dev; -void Worker::startWorking() +void Worker::startWorking(IfRunning _ir) { cnote << "startWorking for thread" << m_name; Guard l(x_work); - if (m_work) - return; + + if (m_work && m_work->joinable()) + try { + if (_ir == IfRunning::Detach) + m_work->detach(); + else if (_ir == IfRunning::Join) + m_work->join(); + else + return; + } catch (...) {} cnote << "Spawning" << m_name; m_stop = false; m_work.reset(new thread([&]() @@ -40,6 +48,7 @@ void Worker::startWorking() setThreadName(m_name.c_str()); startedWorking(); workLoop(); + m_work->detach(); cnote << "Finishing up worker thread"; doneWorking(); })); @@ -49,11 +58,14 @@ void Worker::stopWorking() { cnote << "stopWorking for thread" << m_name; Guard l(x_work); - if (!m_work) + if (!m_work || !m_work->joinable()) return; cnote << "Stopping" << m_name; m_stop = true; - m_work->join(); + try { + m_work->join(); + } + catch (...) {} m_work.reset(); cnote << "Stopped" << m_name; } diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 24ff4cc15..287ff6d6f 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -23,11 +23,19 @@ #include #include +#include #include "Guards.h" namespace dev { +enum class IfRunning +{ + Fail, + Join, + Detach +}; + class Worker { protected: @@ -45,7 +53,7 @@ protected: void setName(std::string _n) { if (!isWorking()) m_name = _n; } /// Starts worker thread; causes startedWorking() to be called. - void startWorking(); + void startWorking(IfRunning _ir = IfRunning::Fail); /// Stop worker thread; causes call to stopWorking(). void stopWorking(); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f66188976..3dd9d3b60 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -30,9 +30,10 @@ #include #include #include +#include +#include #include #include -#include #include #if ETH_ETHASHCL || !ETH_TRUE #include @@ -123,10 +124,12 @@ void Ethash::CPUMiner::workLoop() uint64_t tryNonce = (uint64_t)(u64)Nonce::random(s_eng); ethash_return_value ethashReturn; - auto p = EthashAux::params(m_work.seedHash); - void const* dagPointer = EthashAux::full(m_work.seedHash).data(); - uint8_t const* headerHashPointer = m_work.headerHash.data(); - h256 boundary = m_work.boundary; + WorkPackage w = work(); + + auto p = EthashAux::params(w.seedHash); + void const* dagPointer = EthashAux::full(w.seedHash).data(); + uint8_t const* headerHashPointer = w.headerHash.data(); + h256 boundary = w.boundary; unsigned hashCount = 1; for (; !shouldStop(); tryNonce++, hashCount++) { @@ -149,7 +152,6 @@ public: void abort() { Guard l(x_all); - m_owner->m_work.headerHash = h256(); if (m_aborted) return; // cdebug << "Attempting to abort"; @@ -158,13 +160,17 @@ public: std::this_thread::sleep_for(chrono::milliseconds(30)); // if (!m_aborted) // cwarn << "Couldn't abort. Abandoning OpenCL process."; + } + + void reset() + { m_aborted = m_abort = false; } protected: virtual bool found(uint64_t const* _nonces, uint32_t _count) override { -// cdebug << "Found nonces: " << vector(_nonces, _nonces + _count); +// dev::operator <<(std::cerr << "Found nonces: ", vector(_nonces, _nonces + _count)) << std::endl; for (uint32_t i = 0; i < _count; ++i) { if (m_owner->report(_nonces[i])) @@ -179,7 +185,7 @@ protected: virtual bool searched(uint64_t _startNonce, uint32_t _count) override { Guard l(x_all); -// cdebug << "Searched" << _count << "from" << _startNonce; +// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; m_owner->accumulateHashes(_count); m_last = _startNonce + _count; if (m_abort) @@ -206,29 +212,30 @@ Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Ethash::GPUMiner::~GPUMiner() { - delete m_hook; + pause(); delete m_miner; + delete m_hook; } bool Ethash::GPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; - Result r = EthashAux::eval(m_work.seedHash, m_work.headerHash, n); - if (r.value < m_work.boundary) + Result r = EthashAux::eval(work().seedHash, work().headerHash, n); + if (r.value < work().boundary) return submitProof(Solution{n, r.mixHash}); return false; } -void Ethash::GPUMiner::kickOff(WorkPackage const& _work) +void Ethash::GPUMiner::kickOff() { - m_work = _work; + m_hook->reset(); startWorking(); } void Ethash::GPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. - WorkPackage w = m_work; + WorkPackage w = work(); if (!m_miner || m_minerSeed != w.seedHash) { m_minerSeed = w.seedHash; @@ -249,7 +256,6 @@ void Ethash::GPUMiner::pause() { m_hook->abort(); stopWorking(); - m_work.headerHash = h256(); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 8f1ba3eb3..06e6b9e96 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,19 +87,16 @@ public: static unsigned instances() { return std::thread::hardware_concurrency(); } protected: - void kickOff(WorkPackage const& _work) override + void kickOff() override { stopWorking(); - m_work = _work; startWorking(); } - void pause() override { stopWorking(); m_work.reset(); } + void pause() override { stopWorking(); } private: void workLoop() override; - - WorkPackage m_work; }; #if ETH_ETHASHCL || !ETH_TRUE @@ -114,7 +111,7 @@ public: static unsigned instances() { return 1; } protected: - void kickOff(WorkPackage const& _work) override; + void kickOff() override; void pause() override; private: @@ -127,7 +124,6 @@ public: ethash_cl_miner* m_miner = nullptr; h256 m_minerSeed; ///< Last seed in m_miner - WorkPackage m_work; ///< Work to be done by GPU, set with kickOff and picked up in workLoop. }; #else using GPUMiner = CPUMiner; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index ea51b0eb5..084cc59ff 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -40,13 +40,13 @@ namespace eth struct MiningProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - unsigned hashes = 0; ///< Total number of hashes computed. - unsigned ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. }; struct MineInfo: public MiningProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress const& _p) +inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) { _out << (_p.hashes * 1000 / _p.ms) << "H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << "s"; return _out; @@ -97,17 +97,19 @@ public: void setWork(WorkPackage const& _work = WorkPackage()) { Guard l(x_work); - if (_work.headerHash == m_work.headerHash) - return; - if (_work.headerHash != h256()) - kickOff(_work); - else if (m_work.headerHash == h256() && _work.headerHash != h256()) - pause(); + auto old = m_work; m_work = _work; + if (!!m_work) + { + pause(); + kickOff(); + } + else if (!m_work && !!old) + pause(); m_hashCount = 0; } - unsigned hashCount() { return m_hashCount; } + uint64_t hashCount() { return m_hashCount; } unsigned index() const { return m_index; } @@ -119,7 +121,7 @@ protected: * @brief Begin working on a given work package, discarding any previous work. * @param _work The package for which to find a solution. */ - virtual void kickOff(WorkPackage const& _work) = 0; + virtual void kickOff() = 0; /** * @brief No work left to be done. Pause until told to kickOff(). @@ -138,7 +140,10 @@ protected: if (m_farm) { Guard l(x_work); - return m_farm->submitProof(_s, m_work, this); + if (!m_farm->submitProof(_s, m_work, this)) + return false; + m_work.reset(); + return true; } return true; } @@ -154,7 +159,7 @@ private: Mutex x_work; WorkPackage m_work; - unsigned m_hashCount = 0; + uint64_t m_hashCount = 0; }; } diff --git a/libethereum/Farm.h b/libethereum/Farm.h index c20c27e6d..6b65e37c2 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -50,6 +50,11 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + ~GenericFarm() + { + stop(); + } + /** * @brief Sets the current mining mission. * @param _bi The block (header) we wish to be mining. @@ -142,7 +147,7 @@ private: for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->setWork(); - m_work.headerHash = h256(); + m_work.reset(); return true; } return false; From 6067c939cdb867d84f2b355acceb6834814aaf1f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Apr 2015 22:49:17 +0200 Subject: [PATCH 073/108] Fix CPU mining deadlock bug. --- exp/main.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++- libethcore/Miner.h | 6 ++-- libethereum/Farm.h | 4 ++- 3 files changed, 78 insertions(+), 6 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 2055c49e1..54b75d0e2 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -25,6 +25,7 @@ #include "libethash-cl/cl.hpp" #endif #include +#include #include #include #include @@ -106,7 +107,7 @@ int main() cnote << "State after transaction: " << s; cnote << before.diff(s); } -#else +#elif 0 int main() { GenericFarm f; @@ -152,5 +153,76 @@ int main() return 0; } +#else + +void mine(State& s, BlockChain const& _bc) +{ + s.commitToMine(_bc); + GenericFarm f; + bool completed = false; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + return completed = s.completeMine(sol); + }); + f.setWork(s.info()); + f.startCPU(); + while (!completed) + this_thread::sleep_for(chrono::milliseconds(20)); +} + +int main() +{ + cnote << "Testing State..."; + + KeyPair me = sha3("Gav Wood"); + KeyPair myMiner = sha3("Gav's Miner"); +// KeyPair you = sha3("123"); + + Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); + + OverlayDB stateDB = State::openDB(); + CanonBlockChain bc; + cout << bc; + + State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + cout << s; + + // Sync up - this won't do much until we use the last state. + s.sync(bc); + + cout << s; + + // Mine to get some ether! + mine(s, bc); + + bc.attemptImport(s.blockData(), stateDB); + + cout << bc; + + s.sync(bc); + + cout << s; + + // Inject a transaction to transfer funds from miner to me. + Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); + assert(t.sender() == myMiner.address()); + s.execute(bc.lastHashes(), t); + + cout << s; + + // Mine to get some ether and set in stone. + s.commitToMine(bc); + s.commitToMine(bc); + mine(s, bc); + bc.attemptImport(s.blockData(), stateDB); + + cout << bc; + + s.sync(bc); + + cout << s; + + return 0; +} #endif diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 084cc59ff..a048b0238 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -69,11 +69,11 @@ public: /** * @brief Called from a Miner to note a WorkPackage has a solution. * @param _p The solution. - * @param _wp The WorkPackage that the Solution is for. + * @param _wp The WorkPackage that the Solution is for; this will be reset if the work is accepted. * @param _finder The miner that found it. * @return true iff the solution was good (implying that mining should be . */ - virtual bool submitProof(Solution const& _p, WorkPackage const& _wp, Miner* _finder) = 0; + virtual bool submitProof(Solution const& _p, WorkPackage& io_wp, Miner* _finder) = 0; }; /** @@ -139,10 +139,8 @@ protected: { if (m_farm) { - Guard l(x_work); if (!m_farm->submitProof(_s, m_work, this)) return false; - m_work.reset(); return true; } return true; diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 6b65e37c2..56bbcb9df 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -136,8 +136,9 @@ private: * @param _wp The WorkPackage that the Solution is for. * @return true iff the solution was good (implying that mining should be . */ - bool submitProof(Solution const& _s, WorkPackage const& _wp, Miner* _m) override + bool submitProof(Solution const& _s, WorkPackage& _wp, Miner* _m) override { + ReadGuard l(x_work); if (_wp.headerHash != m_work.headerHash) return false; @@ -147,6 +148,7 @@ private: for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->setWork(); + _wp.reset(); m_work.reset(); return true; } From 192761a4b1ae38390b07cf24deacce69fd9a7184 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 09:39:00 +0200 Subject: [PATCH 074/108] Various threading fixes. --- CMakeLists.txt | 9 +++++++++ alethzero/CMakeLists.txt | 2 +- alethzero/Transact.cpp | 4 ++-- exp/main.cpp | 28 ++++++++++++++++++++++++++-- libdevcore/Worker.cpp | 4 ++-- libethcore/Miner.h | 31 ++++++++++++++++++------------- libethereum/Client.cpp | 34 ++++++++++++++++++++++++++++++---- libethereum/Client.h | 9 ++++++--- libethereum/Farm.h | 33 ++++++++++++--------------------- 9 files changed, 106 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05862d9f1..9c90dec46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,6 +243,15 @@ elseif (BUNDLE STREQUAL "full") set(TOOLS ON) set(TESTS ON) set(FATDB ON) +elseif (BUNDLE STREQUAL "core") + set(SERPENT OFF) + set(SOLIDITY ON) + set(USENPM OFF) + set(GUI ON) + set(NCURSES OFF) + set(TOOLS ON) + set(TESTS OFF) + set(FATDB ON) elseif (BUNDLE STREQUAL "tests") set(SERPENT ${DECENT_PLATFORM}) set(SOLIDITY ON) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index c81c86222..b60bca425 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -59,7 +59,7 @@ target_link_libraries(${EXECUTABLE} jsqrc) target_link_libraries(${EXECUTABLE} natspec) target_link_libraries(${EXECUTABLE} ${MHD_LIBRARIES}) -if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")) +if (SERPENT) target_link_libraries(${EXECUTABLE} serpent) endif() diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index f1f7477fe..1ebdf9e23 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -37,7 +37,7 @@ #include #include #include -#ifndef _MSC_VER +#if ETH_SERPENT #include #include #endif @@ -220,7 +220,7 @@ static tuple, bytes, string> userInputToCode(string const& _user, errors.push_back("Solidity: Uncaught exception"); } } -#ifndef _MSC_VER +#if ETH_SERPENT else if (sourceIsSerpent(_user)) { try diff --git a/exp/main.cpp b/exp/main.cpp index 54b75d0e2..20f287f43 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -153,7 +154,7 @@ int main() return 0; } -#else +#elif 0 void mine(State& s, BlockChain const& _bc) { @@ -169,7 +170,7 @@ void mine(State& s, BlockChain const& _bc) while (!completed) this_thread::sleep_for(chrono::milliseconds(20)); } - +#elif 0 int main() { cnote << "Testing State..."; @@ -224,5 +225,28 @@ int main() return 0; } +#else +int main() +{ + string tempDir = boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count()); + + KeyPair myMiner = sha3("Gav's Miner"); + + p2p::Host net("Test"); + cdebug << "Path:" << tempDir; + Client c(&net, tempDir); + + c.setAddress(myMiner.address()); + + this_thread::sleep_for(chrono::milliseconds(1000)); + + c.startMining(); + + this_thread::sleep_for(chrono::milliseconds(6000)); + + c.stopMining(); + + return 0; +} #endif diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 65e8efcbb..8c1fbb9c7 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -29,7 +29,7 @@ using namespace dev; void Worker::startWorking(IfRunning _ir) { - cnote << "startWorking for thread" << m_name; +// cnote << "startWorking for thread" << m_name; Guard l(x_work); if (m_work && m_work->joinable()) @@ -56,7 +56,7 @@ void Worker::startWorking(IfRunning _ir) void Worker::stopWorking() { - cnote << "stopWorking for thread" << m_name; +// cnote << "stopWorking for thread" << m_name; Guard l(x_work); if (!m_work || !m_work->joinable()) return; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index a048b0238..51a0ff6f6 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -73,11 +73,12 @@ public: * @param _finder The miner that found it. * @return true iff the solution was good (implying that mining should be . */ - virtual bool submitProof(Solution const& _p, WorkPackage& io_wp, Miner* _finder) = 0; + virtual bool submitProof(Solution const& _p, Miner* _finder) = 0; }; /** * @brief A miner - a member and adoptee of the Farm. + * @warning Not threadsafe. It is assumed Farm will synchronise calls to/from this class. */ template class GenericMiner { @@ -96,15 +97,17 @@ public: void setWork(WorkPackage const& _work = WorkPackage()) { - Guard l(x_work); auto old = m_work; - m_work = _work; - if (!!m_work) + { + Guard l(x_work); + m_work = _work; + } + if (!!_work) { pause(); kickOff(); } - else if (!m_work && !!old) + else if (!_work && !!old) pause(); m_hashCount = 0; } @@ -137,16 +140,18 @@ protected: */ bool submitProof(Solution const& _s) { - if (m_farm) + if (!m_farm) + return true; + if (m_farm->submitProof(_s, this)) { - if (!m_farm->submitProof(_s, m_work, this)) - return false; + Guard l(x_work); + m_work.reset(); return true; } - return true; + return false; } - WorkPackage const& work() const { return m_work; } + WorkPackage const& work() const { Guard l(x_work); return m_work; } void accumulateHashes(unsigned _n) { m_hashCount += _n; } @@ -154,10 +159,10 @@ private: FarmFace* m_farm = nullptr; unsigned m_index; - Mutex x_work; - WorkPackage m_work; - uint64_t m_hashCount = 0; + + WorkPackage m_work; + mutable Mutex x_work; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 79216f609..46da3e1f7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -192,6 +192,27 @@ bool Client::isSyncing() const return false; } +void Client::startedWorking() +{ + // Synchronise the state according to the head of the block chain. + // TODO: currently it contains keys for *all* blocks. Make it remove old ones. + cdebug << "startedWorking()"; + WriteGuard l(x_stateDB); + + cdebug << m_bc.number() << m_bc.currentHash(); + + cdebug << "Pre:" << m_preMine.info(); + cdebug << "Post:" << m_postMine.info(); + cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); + + m_preMine.sync(m_bc); + m_postMine = m_preMine; + + cdebug << "Pre:" << m_preMine.info(); + cdebug << "Post:" << m_postMine.info(); + cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); +} + void Client::doneWorking() { // Synchronise the state according to the head of the block chain. @@ -403,10 +424,11 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) return false; newBlock = m_postMine.blockData(); } - + m_bq.import(&newBlock, m_bc); +/* ImportRoute ir = m_bc.attemptImport(newBlock, m_stateDB); if (!ir.first.empty()) - onChainChanged(ir); + onChainChanged(ir);*/ return true; } @@ -500,9 +522,9 @@ void Client::onChainChanged(ImportRoute const& _ir) m_postMine = m_preMine; changeds.insert(PendingChangedFilter); - x_stateDB.unlock(); + x_stateDB.unlock_shared(); onPostStateChanged(); - x_stateDB.lock(); + x_stateDB.lock_shared(); } } @@ -514,8 +536,12 @@ void Client::onPostStateChanged() cnote << "Post state changed: Restarting mining..."; { WriteGuard l(x_stateDB); + cdebug << "Pre:" << m_preMine.info(); m_postMine.commitToMine(m_bc); m_miningInfo = m_postMine.info(); + cdebug << "Pre:" << m_preMine.info(); + cdebug << "Post:" << m_postMine.info(); + cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); } m_farm.setWork(m_miningInfo); diff --git a/libethereum/Client.h b/libethereum/Client.h index 2235c4459..16033a11f 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -169,7 +169,7 @@ public: /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread - void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); } + void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); onPostStateChanged(); } /// Stop mining. /// NOT thread-safe void stopMining() override { m_farm.stop(); } @@ -229,11 +229,14 @@ protected: void noteChanged(h256Set const& _filters); private: + /// Called when Worker is starting. + void startedWorking() override; + /// Do some work. Handles blockchain maintenance and mining. - virtual void doWork(); + void doWork() override; /// Called when Worker is exiting. - virtual void doneWorking(); + void doneWorking() override; /// Magically called when the chain has changed. An import route is provided. /// Called by either submitWork() or in our main thread through syncBlockQueue(). diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 56bbcb9df..afca853ed 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -61,8 +61,7 @@ public: */ void setWork(BlockInfo const& _bi) { - WriteGuard l(x_work); - ReadGuard l2(x_miners); + WriteGuard l(x_minerWork); m_header = _bi; auto p = PoW::package(m_header); if (p.headerHash == m_work.headerHash) @@ -90,14 +89,14 @@ public: */ void stop() { - WriteGuard l(x_miners); + WriteGuard l(x_minerWork); m_miners.clear(); + m_work.reset(); } bool isMining() const { - ReadGuard l(x_miners); - return !m_miners.empty(); + return !!m_work; } /** @@ -109,7 +108,7 @@ public: MiningProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { - ReadGuard l2(x_miners); + ReadGuard l2(x_minerWork); for (auto const& i: m_miners) p.hashes += i->hashCount(); } @@ -127,7 +126,7 @@ public: */ void onSolutionFound(SolutionFound const& _handler) { m_onSolutionFound = _handler; } - WorkPackage work() const { ReadGuard l(x_work); return m_work; } + WorkPackage work() const { ReadGuard l(x_minerWork); return m_work; } private: /** @@ -136,19 +135,14 @@ private: * @param _wp The WorkPackage that the Solution is for. * @return true iff the solution was good (implying that mining should be . */ - bool submitProof(Solution const& _s, WorkPackage& _wp, Miner* _m) override + bool submitProof(Solution const& _s, Miner* _m) override { - ReadGuard l(x_work); - if (_wp.headerHash != m_work.headerHash) - return false; - if (m_onSolutionFound && m_onSolutionFound(_s)) { - ReadGuard l(x_miners); + WriteGuard ul(x_minerWork); for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->setWork(); - _wp.reset(); m_work.reset(); return true; } @@ -161,8 +155,7 @@ private: template bool start() { - ReadGuard l(x_work); - WriteGuard l2(x_miners); + WriteGuard l(x_minerWork); if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) return true; m_miners.clear(); @@ -181,17 +174,15 @@ private: m_lastStart = std::chrono::steady_clock::now(); } - mutable SharedMutex x_miners; + mutable SharedMutex x_minerWork; std::vector> m_miners; + WorkPackage m_work; + BlockInfo m_header; mutable SharedMutex x_progress; mutable MiningProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; - mutable SharedMutex x_work; - WorkPackage m_work; - BlockInfo m_header; - SolutionFound m_onSolutionFound; }; From 45bacf856602f156ebe9a5fd3ceeff330b765216 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 10:18:34 +0200 Subject: [PATCH 075/108] AlethZero fixes. --- libethcore/BlockInfo.cpp | 9 +++++++-- libethcore/BlockInfo.h | 1 + libethcore/EthashAux.cpp | 29 ++++++++++++++++++++++++++--- libethcore/EthashAux.h | 4 +++- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 6cd431931..b45bdc57e 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -23,6 +23,7 @@ #include #include #include +#include "EthashAux.h" #include "ProofOfWork.h" #include "Exceptions.h" #include "Params.h" @@ -63,8 +64,7 @@ void BlockInfo::clear() h256 const& BlockInfo::seedHash() const { if (!m_seedHash) - for (u256 n = number; n >= c_epochDuration; n -= c_epochDuration) - m_seedHash = sha3(m_seedHash); + m_seedHash = EthashAux::seedHash((unsigned)number); return m_seedHash; } @@ -145,9 +145,14 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const throw; } + if (number > ~(unsigned)0) + throw InvalidNumber(); + // check it hashes according to proof of work or that it's the genesis block. if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty)); + else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) + BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty)); if (_s != CheckNothing) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index dffff73f4..79c12ebb4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -39,6 +39,7 @@ enum IncludeNonce enum Strictness { CheckEverything, + QuickNonce, IgnoreNonce, CheckNothing }; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 969310dac..fb4c2820d 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,24 +63,47 @@ ethash_params EthashAux::params(unsigned _n) return p; } +h256 EthashAux::seedHash(unsigned _number) +{ + unsigned epoch = _number / ETHASH_EPOCH_LENGTH; + RecursiveGuard l(get()->x_this); + if (_number < get()->m_seedHashes.size()) + return get()->m_seedHashes[_number]; + h256 ret; + unsigned n = 0; + if (!get()->m_seedHashes.empty()) + { + ret = get()->m_seedHashes.back(); + n = get()->m_seedHashes.size() - 1; + } + cdebug << "Searching for seedHash of epoch " << epoch; + for (; n < epoch; ++n, ret = sha3(ret)) + cdebug << "Epoch" << n << "is" << ret.abridged(); + return ret; +} + ethash_params EthashAux::params(h256 const& _seedHash) { RecursiveGuard l(get()->x_this); unsigned epoch = 0; try { - epoch = get()->m_seedHashes.at(_seedHash); + epoch = get()->m_epochs.at(_seedHash); } catch (...) { - for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = h256(h)) {} + cdebug << "Searching for seedHash " << _seedHash.abridged(); + for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h)) + { + cdebug << "Epoch" << epoch << "is" << h.abridged(); + } if (epoch == 2048) { std::ostringstream error; error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048); throw std::invalid_argument(error.str()); } - get()->m_seedHashes[_seedHash] = epoch; + get()->m_epochs[_seedHash] = epoch; } return params(epoch * ETHASH_EPOCH_LENGTH); } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index aec1089a2..94c2243e0 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -36,6 +36,7 @@ public: using LightType = void const*; using FullType = void const*; + static h256 seedHash(unsigned _number); static ethash_params params(BlockInfo const& _header); static ethash_params params(h256 const& _seedHash); static ethash_params params(unsigned _n); @@ -58,7 +59,8 @@ private: std::map m_lights; std::map m_fulls; - std::map m_seedHashes; + std::map m_epochs; + h256s m_seedHashes; }; } From 76518d519f8559860d2db0618a8e7ae4d5b5d080 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 10:37:11 +0200 Subject: [PATCH 076/108] Marginally better Client async code. --- libethereum/Client.cpp | 14 ++++---------- libethereum/Client.h | 9 ++++----- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 46da3e1f7..cc579ec08 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -571,19 +571,13 @@ void Client::doWork() { // TODO: Use condition variable rather than this rubbish. - Guard l(x_fakeSignalSystemState); - - if (m_syncTransactionQueue) - { - m_syncTransactionQueue = false; + bool t = true; + if (m_syncTransactionQueue.compare_exchange_strong(t, false)) syncTransactionQueue(); - } - if (m_syncBlockQueue) - { - m_syncBlockQueue = false; + t = true; + if (m_syncBlockQueue.compare_exchange_strong(t, false)) syncBlockQueue(); - } checkWatchGarbage(); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16033a11f..289df3fe0 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -249,10 +249,10 @@ private: void syncTransactionQueue(); /// Magically called when m_tq needs syncing. Be nice and don't block. - void onTransactionQueueReady() { Guard l(x_fakeSignalSystemState); m_syncTransactionQueue = true; } + void onTransactionQueueReady() { m_syncTransactionQueue = true; } /// Magically called when m_tq needs syncing. Be nice and don't block. - void onBlockQueueReady() { Guard l(x_fakeSignalSystemState); m_syncBlockQueue = true; } + void onBlockQueueReady() { m_syncBlockQueue = true; } /// Called when the post state has changed (i.e. when more transactions are in it or we're mining on a new block). /// This updates m_miningInfo. @@ -286,9 +286,8 @@ private: ///< When did we last both doing GC on the watches? // TODO!!!!!! REPLACE WITH A PROPER X-THREAD ASIO SIGNAL SYSTEM (could just be condition variables) - mutable Mutex x_fakeSignalSystemState; - bool m_syncTransactionQueue = false; - bool m_syncBlockQueue = false; + std::atomic m_syncTransactionQueue = {false}; + std::atomic m_syncBlockQueue = {false}; }; } From 8f532e81cbfcea2f746297592e963108319e0c52 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 12:43:00 +0200 Subject: [PATCH 077/108] Fix to ethash seedHash caching. --- alethzero/Main.ui | 6 ++++ alethzero/MainWin.cpp | 5 +++ alethzero/MainWin.h | 1 + eth/main.cpp | 41 +++++++++++++++++++++- libdevcore/Guards.h | 71 ++++++++++++++++++++++++++++++++++++++ libethcore/EthashAux.cpp | 33 +++++++++--------- libethcore/EthashAux.h | 2 +- libethcore/Params.cpp | 1 - libethcore/Params.h | 1 - libethereum/BlockQueue.cpp | 12 +++++++ libethereum/BlockQueue.h | 3 ++ libethereum/Client.cpp | 47 ++++++++++++++----------- libethereum/Client.h | 4 ++- libethereum/Farm.h | 6 +++- 14 files changed, 190 insertions(+), 43 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 3f3d1e237..8e48793c9 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -180,6 +180,7 @@ + @@ -1679,6 +1680,11 @@ font-size: 14pt &GPU Mining + + + Retry Unknown Parent Blocks + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2e4478594..a60875ba6 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1752,6 +1752,11 @@ void Main::on_clearPending_triggered() refreshAll(); } +void Main::on_retryUnknown_triggered() +{ + ethereum()->retryUnkonwn(); +} + void Main::on_killBlockchain_triggered() { writeSettings(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index a5c74eeaa..a8579ed01 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -163,6 +163,7 @@ private slots: void on_usePrivate_triggered(); void on_turboMining_triggered(); void on_jitvm_triggered(); + void on_retryUnknown_triggered(); // Debugger void on_debugCurrent_triggered(); diff --git a/eth/main.cpp b/eth/main.cpp index 24bf839aa..461494cef 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,11 +32,12 @@ #include #include #include +#include +#include #include #include #include #include -#include #if ETH_READLINE #include #include @@ -111,6 +112,7 @@ void help() << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -B,--block-fees Set the block fee profit in the reference unit e.g. ยข (Default: 15)." << endl << " -c,--client-name Add a name to your client's version string (default: blank)." << endl + << " -C,--check-pow Check PoW credentials for validity." << endl << " -d,--db-path Load database from path (default: ~/.ethereum " << endl << " /Etherum or Library/Application Support/Ethereum)." << endl << " -D,--create-dag Create the DAG in preparation for mining on given block and exit." << endl @@ -401,6 +403,43 @@ int main(int argc, char** argv) return -1; } } + else if ((arg == "-C" || arg == "--check-pow") && i + 4 < argc) + { + string m; + try + { + BlockInfo bi; + m = boost::to_lower_copy(string(argv[++i])); + h256 powHash(m); + m = boost::to_lower_copy(string(argv[++i])); + h256 seedHash; + if (m.size() == 64 || m.size() == 66) + seedHash = h256(m); + else + seedHash = EthashAux::seedHash(stol(m)); + m = boost::to_lower_copy(string(argv[++i])); + bi.difficulty = u256(m); + auto boundary = bi.boundary(); + m = boost::to_lower_copy(string(argv[++i])); + bi.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bool valid = r.value < boundary; + cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; + cout << r.value << (valid ? " < " : " >= ") << boundary << endl; + cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " with seed as " << seedHash << endl; + if (valid) + cout << "(mixHash = " << r.mixHash << ")" << endl; + cout << "SHA3( light(seed) ) = " << sha3(bytesConstRef((byte const*)EthashAux::light(seedHash), EthashAux::params(seedHash).cache_size)) << endl; + exit(0); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << m << endl; + return -1; + } + } else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) { try diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index f5c64b041..4229428ce 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -38,4 +38,75 @@ using UpgradableGuard = boost::upgrade_lock; using UpgradeGuard = boost::upgrade_to_unique_lock; using WriteGuard = boost::unique_lock; +template +struct GenericGuardBool: GuardType +{ + GenericGuardBool(MutexType& _m): GuardType(_m) {} + bool b = true; +}; +template +struct GenericUnguardBool +{ + GenericUnguardBool(MutexType& _m): m(_m) { m.unlock(); } + ~GenericUnguardBool() { m.lock(); } + bool b = true; + MutexType& m; +}; +template +struct GenericUnguardSharedBool +{ + GenericUnguardSharedBool(MutexType& _m): m(_m) { m.unlock_shared(); } + ~GenericUnguardSharedBool() { m.lock_shared(); } + bool b = true; + MutexType& m; +}; + +/** @brief Simple block guard. + * The expression/block following is guarded though the given mutex. + * Usage: + * @code + * Mutex m; + * unsigned d; + * ... + * ETH_GUARDED(m) d = 1; + * ... + * ETH_GUARDED(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; } + * @endcode + * + * There are several variants of this basic mechanism for different Mutex types and Guards. + * + * There is also the UNGUARD variant which allows an unguarded expression/block to exist within a + * guarded expression. eg: + * + * @code + * Mutex m; + * int d; + * ... + * ETH_GUARDED(m) + * { + * for (auto d = 50; d > 25; --d) + * foo(d); + * ETH_UNGUARDED(m) + * bar(); + * for (; d > 0; --d) + * foo(d); + * } + * @endcode + */ + +#define ETH_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_READ_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_WRITE_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_RECURSIVE_GUARDED(MUTEX) \ + for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_UNGUARDED(MUTEX) \ + for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_READ_UNGUARDED(MUTEX) \ + for (GenericUnguardSharedBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) +#define ETH_WRITE_UNGUARDED(MUTEX) \ + for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false) + } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index fb4c2820d..061af566e 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -67,19 +67,24 @@ h256 EthashAux::seedHash(unsigned _number) { unsigned epoch = _number / ETHASH_EPOCH_LENGTH; RecursiveGuard l(get()->x_this); - if (_number < get()->m_seedHashes.size()) - return get()->m_seedHashes[_number]; - h256 ret; - unsigned n = 0; - if (!get()->m_seedHashes.empty()) + if (epoch >= get()->m_seedHashes.size()) { - ret = get()->m_seedHashes.back(); - n = get()->m_seedHashes.size() - 1; + h256 ret; + unsigned n = 0; + if (!get()->m_seedHashes.empty()) + { + ret = get()->m_seedHashes.back(); + n = get()->m_seedHashes.size() - 1; + } + get()->m_seedHashes.resize(epoch + 1); + cdebug << "Searching for seedHash of epoch " << epoch; + for (; n <= epoch; ++n, ret = sha3(ret)) + { + get()->m_seedHashes[n] = ret; + cdebug << "Epoch" << n << "is" << ret.abridged(); + } } - cdebug << "Searching for seedHash of epoch " << epoch; - for (; n < epoch; ++n, ret = sha3(ret)) - cdebug << "Epoch" << n << "is" << ret.abridged(); - return ret; + return get()->m_seedHashes[epoch]; } ethash_params EthashAux::params(h256 const& _seedHash) @@ -93,17 +98,13 @@ ethash_params EthashAux::params(h256 const& _seedHash) catch (...) { cdebug << "Searching for seedHash " << _seedHash.abridged(); - for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h)) - { - cdebug << "Epoch" << epoch << "is" << h.abridged(); - } + for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {} if (epoch == 2048) { std::ostringstream error; error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048); throw std::invalid_argument(error.str()); } - get()->m_epochs[_seedHash] = epoch; } return params(epoch * ETHASH_EPOCH_LENGTH); } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 94c2243e0..c927a012b 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -41,7 +41,7 @@ public: static ethash_params params(h256 const& _seedHash); static ethash_params params(unsigned _n); static LightType light(BlockInfo const& _header); - static LightType light(h256 const& _header); + static LightType light(h256 const& _seedHash); static bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef()); static bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef()); diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp index 029f8b47a..655c8a78b 100644 --- a/libethcore/Params.cpp +++ b/libethcore/Params.cpp @@ -30,7 +30,6 @@ namespace eth //--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json u256 const c_genesisDifficulty = 131072; u256 const c_maximumExtraDataSize = 1024; -u256 const c_epochDuration = 30000; u256 const c_genesisGasLimit = 3141592; u256 const c_minGasLimit = 125000; u256 const c_gasLimitBoundDivisor = 1024; diff --git a/libethcore/Params.h b/libethcore/Params.h index 46b30e2c3..b957f9737 100644 --- a/libethcore/Params.h +++ b/libethcore/Params.h @@ -37,7 +37,6 @@ extern u256 const c_minimumDifficulty; extern u256 const c_difficultyBoundDivisor; extern u256 const c_durationLimit; extern u256 const c_maximumExtraDataSize; -extern u256 const c_epochDuration; extern u256 const c_stackLimit; extern u256 const c_tierStepGas[8]; ///< Once per operation, for a selection of them. diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index e9dd99cd1..b76e4bed6 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -183,3 +183,15 @@ void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) m_unknown.erase(r.first, r.second); } } + +void BlockQueue::retryAllUnknown() +{ + for (auto it = m_unknown.begin(); it != m_unknown.end(); ++it) + { + m_ready.push_back(it->second.second); + auto newReady = it->second.first; + m_unknownSet.erase(newReady); + m_readySet.insert(newReady); + } + m_unknown.clear(); +} diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index f5cdf7ab5..4a503d114 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -71,6 +71,9 @@ public: /// Notify the queue that the chain has changed and a new block has attained 'ready' status (i.e. is in the chain). void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); } + /// Force a retry of all the blocks with unknown parents. + void retryAllUnknown(); + /// Get information on the items queued. std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index cc579ec08..ea8efd310 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -436,15 +436,12 @@ void Client::syncBlockQueue() { ImportRoute ir; + cwork << "BQ ==> CHAIN ==> STATE"; { WriteGuard l(x_stateDB); - cwork << "BQ ==> CHAIN ==> STATE"; OverlayDB db = m_stateDB; - x_stateDB.unlock(); - - tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); - - x_stateDB.lock(); + ETH_WRITE_UNGUARDED(x_stateDB) + tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100); if (ir.first.empty()) return; m_stateDB = db; @@ -458,7 +455,11 @@ void Client::syncTransactionQueue() cwork << "postSTATE <== TQ"; h256Set changeds; - TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); + TransactionReceipts newPendingReceipts; + + ETH_WRITE_GUARDED(x_stateDB) + newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp); + if (newPendingReceipts.size()) { for (size_t i = 0; i < newPendingReceipts.size(); i++) @@ -512,8 +513,7 @@ void Client::onChainChanged(ImportRoute const& _ir) // RESTART MINING // LOCKS REALLY NEEDED? - { - ReadGuard l(x_stateDB); + ETH_WRITE_GUARDED(x_stateDB) if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) { if (isMining()) @@ -522,11 +522,9 @@ void Client::onChainChanged(ImportRoute const& _ir) m_postMine = m_preMine; changeds.insert(PendingChangedFilter); - x_stateDB.unlock_shared(); - onPostStateChanged(); - x_stateDB.lock_shared(); + ETH_WRITE_UNGUARDED(x_stateDB) + onPostStateChanged(); } - } noteChanged(changeds); } @@ -534,17 +532,24 @@ void Client::onChainChanged(ImportRoute const& _ir) void Client::onPostStateChanged() { cnote << "Post state changed: Restarting mining..."; + if (isMining()) { - WriteGuard l(x_stateDB); - cdebug << "Pre:" << m_preMine.info(); - m_postMine.commitToMine(m_bc); - m_miningInfo = m_postMine.info(); - cdebug << "Pre:" << m_preMine.info(); - cdebug << "Post:" << m_postMine.info(); - cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce); + { + WriteGuard l(x_stateDB); + m_postMine.commitToMine(m_bc); + m_miningInfo = m_postMine.info(); + } + m_farm.setWork(m_miningInfo); } +} - m_farm.setWork(m_miningInfo); +void Client::startMining() +{ + if (m_turboMining) + m_farm.startGPU(); + else + m_farm.startCPU(); + onPostStateChanged(); } void Client::noteChanged(h256Set const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index 289df3fe0..dedb3bcf1 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -169,7 +169,7 @@ public: /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread - void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); onPostStateChanged(); } + void startMining() override; /// Stop mining. /// NOT thread-safe void stopMining() override { m_farm.stop(); } @@ -202,6 +202,8 @@ public: void clearPending(); /// Kills the blockchain. Just for debug use. void killChain(); + /// Retries all blocks with unknown parents. + void retryUnkonwn() { m_bq.retryAllUnknown(); } protected: /// InterfaceStub methods diff --git a/libethereum/Farm.h b/libethereum/Farm.h index afca853ed..26d4b139e 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -92,11 +92,12 @@ public: WriteGuard l(x_minerWork); m_miners.clear(); m_work.reset(); + m_isMining = false; } bool isMining() const { - return !!m_work; + return m_isMining; } /** @@ -165,6 +166,7 @@ private: m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); m_miners.back()->setWork(m_work); } + m_isMining = true; resetTimer(); return true; } @@ -179,6 +181,8 @@ private: WorkPackage m_work; BlockInfo m_header; + std::atomic m_isMining = {false}; + mutable SharedMutex x_progress; mutable MiningProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; From 036214820080b41eac8ded1657b5983bffa18fba Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 12:54:03 +0200 Subject: [PATCH 078/108] Version bump. Minor fix. --- libdevcore/Common.cpp | 2 +- libethereum/Client.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index b6e8e7f93..78b3d9c30 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.7"; +char const* Version = "0.9.8"; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ea8efd310..4f9af91a9 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -332,7 +332,8 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed) void Client::setForceMining(bool _enable) { m_forceMining = _enable; - startMining(); + if (isMining()) + startMining(); } MiningProgress Client::miningProgress() const From 609d650182f177deaf09e311c725eb7f40c6f1c5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 13:30:10 +0200 Subject: [PATCH 079/108] Windows warning fixes. Mac build fixes. --- eth/main.cpp | 2 +- libdevcore/CommonData.h | 4 ++-- libethash/ethash.h | 4 ++-- libethash/io.c | 6 +++--- libethcore/Ethash.cpp | 4 ++-- mix/ContractCallDataEncoder.cpp | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 461494cef..db6acbbca 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -364,7 +364,7 @@ int main(int argc, char** argv) { coinbase = h160(fromHex(argv[++i], WhenError::Throw)); } - catch (BadHexCharacter& _e) + catch (BadHexCharacter&) { cerr << "Bad hex in " << arg << " option: " << argv[i] << endl; return -1; diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 38ccd71f0..93bad71a3 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -116,9 +116,9 @@ inline void toBigEndian(_T _val, _Out& o_out) template inline _T fromBigEndian(_In const& _bytes) { - _T ret = 0; + _T ret = (_T)0; for (auto i: _bytes) - ret = (ret << 8) | (byte)(typename std::make_unsigned::type)i; + ret = (_T)((ret << 8) | (byte)(typename std::make_unsigned::type)i); return ret; } diff --git a/libethash/ethash.h b/libethash/ethash.h index 7594fc835..bc62a29cc 100644 --- a/libethash/ethash.h +++ b/libethash/ethash.h @@ -85,7 +85,7 @@ typedef uint8_t const ethash_seedhash_t[32]; typedef void const* ethash_light_t; static inline ethash_light_t ethash_new_light(ethash_params const* params, ethash_seedhash_t seed) { - void* ret = malloc(params->cache_size); + void* ret = malloc((size_t)params->cache_size); ethash_mkcache(ret, params, seed); return ret; } @@ -98,7 +98,7 @@ static inline void ethash_delete_light(ethash_light_t light) { typedef void const* ethash_full_t; static inline ethash_full_t ethash_new_full(ethash_params const* params, ethash_light_t light) { - void* ret = malloc(params->full_size); + void* ret = malloc((size_t)params->full_size); ethash_compute_full_data(ret, params, light); return ret; } diff --git a/libethash/io.c b/libethash/io.c index 0e935fa59..07387caaf 100644 --- a/libethash/io.c +++ b/libethash/io.c @@ -61,13 +61,13 @@ bool ethash_io_write(char const *dirname, { char info_buffer[DAG_MEMO_BYTESIZE]; // allocate the bytes - uint8_t *temp_data_ptr = malloc(params->full_size); + uint8_t *temp_data_ptr = malloc((size_t)params->full_size); if (!temp_data_ptr) { goto end; } ethash_compute_full_data(temp_data_ptr, params, cache); - if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, params->full_size)) { + if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, (size_t)params->full_size)) { goto fail_free; } @@ -77,7 +77,7 @@ bool ethash_io_write(char const *dirname, } *data = temp_data_ptr; - *data_size = params->full_size; + *data_size = (size_t)params->full_size; return true; fail_free: diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 3dd9d3b60..a777205e9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -48,7 +48,7 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage; +const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); std::string Ethash::name() { @@ -81,7 +81,7 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - return ethash_quick_check_difficulty( + return !!ethash_quick_check_difficulty( _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_header.nonce, _header.mixHash.data(), diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 56aeb1d34..e1f02f631 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -118,7 +118,7 @@ unsigned ContractCallDataEncoder::encodeSingleItem(QString const& _data, Solidit result = bytes(alignSize); toBigEndian((u256)i, result); } - catch (std::exception const& ex) + catch (std::exception const&) { // manage input as a string. QByteArray bytesAr = src.toLocal8Bit(); From 7cd581abc54b8c4f7425b0233beb898c204c1227 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 14:53:19 +0200 Subject: [PATCH 080/108] new way of searching for windows libs --- cmake/EthDependencies.cmake | 6 +++++- cmake/FindCURL.cmake | 19 +++---------------- cmake/FindCryptoPP.cmake | 12 ++---------- cmake/FindJsoncpp.cmake | 11 ++--------- cmake/FindLevelDB.cmake | 17 ++--------------- cmake/FindMHD.cmake | 17 ++--------------- cmake/Findjson_rpc_cpp.cmake | 34 ++++++---------------------------- 7 files changed, 22 insertions(+), 94 deletions(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 9c38b6919..18d61e7a0 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -4,7 +4,11 @@ # by defining this variable, cmake will look for dependencies first in our own repository before looking in system paths like /usr/local/ ... # this must be set to point to the same directory as $ETH_DEPENDENCY_INSTALL_DIR in /extdep directory string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name) -set (ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extdep/install/${_system_name}") +if (CMAKE_CL_64) + set (ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extdep/install/${_system_name}/x64") +else () + set (ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extdep/install/${_system_name}/Win32") +endif() set (CMAKE_PREFIX_PATH ${ETH_DEPENDENCY_INSTALL_DIR}) # setup directory for cmake generated files and include it globally diff --git a/cmake/FindCURL.cmake b/cmake/FindCURL.cmake index 60937c64e..e2f52fe79 100644 --- a/cmake/FindCURL.cmake +++ b/cmake/FindCURL.cmake @@ -16,17 +16,10 @@ find_path( DOC "curl include dir" ) -# if msvc 64 build -# names from cmake's FindCURL -if (CMAKE_CL_64) - set(CURL_NAMES curl_x64 curllib_x64 libcurl_imp_x64 curllib_static_x64 libcurl_x64) -else () - set(CURL_NAMES curl curllib libcurl_imp curllib_static libcurl) -endif() - find_library( CURL_LIBRARY - NAMES ${CURL_NAMES} + # names from cmake's FindCURL + NAMES curl curllib libcurl_imp curllib_static libcurl DOC "curl library" ) @@ -38,15 +31,9 @@ set(CURL_LIBRARIES ${CURL_LIBRARY}) # boost is using the same "hack" as us with "optimized" and "debug" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - if (CMAKE_CL_64) - set(CURL_NAMES_DEBUG curld_x64 libcurld_x64) - else () - set(CURL_NAMES_DEBUG curld libcurld) - endif() - find_library( CURL_LIBRARY_DEBUG - NAMES ${CURL_NAMES_DEBUG} + NAMES curld libcurld DOC "curl debug library" ) diff --git a/cmake/FindCryptoPP.cmake b/cmake/FindCryptoPP.cmake index 90ea4925d..a9e7183c0 100644 --- a/cmake/FindCryptoPP.cmake +++ b/cmake/FindCryptoPP.cmake @@ -53,22 +53,14 @@ FIND_PATH (CRYPTOPP_INCLUDE_DIR PATH_SUFFIXES include DOC "CryptoPP include directory") -if (CMAKE_CL_64) - set(CRYPTOPP_NAMES cryptlib_x64 cryptopp_x64) - set(CRYPTOPP_NAMES_DEBUG cryptlibd_x64 cryptoppd_x64) -else () - set(CRYPTOPP_NAMES cryptlib cryptopp) - set(CRYPTOPP_NAMES_DEBUG cryptlibd cryptoppd) -endif() - FIND_LIBRARY (CRYPTOPP_LIBRARY_DEBUG - NAMES ${CRYPTOPP_NAMES_DEBUG} + NAMES cryptlibd cryptoppd HINTS ${CRYPTOPP_ROOT_DIR} PATH_SUFFIXES lib DOC "CryptoPP debug library") FIND_LIBRARY (CRYPTOPP_LIBRARY_RELEASE - NAMES ${CRYPTOPP_NAMES} + NAMES cryptlib cryptopp HINTS ${CRYPTOPP_ROOT_DIR} PATH_SUFFIXES lib DOC "CryptoPP release library") diff --git a/cmake/FindJsoncpp.cmake b/cmake/FindJsoncpp.cmake index 711ba667c..1c8540bad 100644 --- a/cmake/FindJsoncpp.cmake +++ b/cmake/FindJsoncpp.cmake @@ -17,16 +17,9 @@ find_path( DOC "jsoncpp include dir" ) -# if msvc 64 build -if (CMAKE_CL_64) - set(JSONCPP_NAMES jsoncpp_x64) -else () - set(JSONCPP_NAMES jsoncpp) -endif() - find_library( JSONCPP_LIBRARY - NAMES ${JSONCPP_NAMES} + NAMES jsoncpp DOC "jsoncpp library" ) @@ -46,7 +39,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") find_library( JSONCPP_LIBRARY_DEBUG - NAMES ${JSONCPP_NAMES_DEBUG} + NAMES jsoncppd DOC "jsoncpp debug library" ) diff --git a/cmake/FindLevelDB.cmake b/cmake/FindLevelDB.cmake index 82b1e277e..1c3465665 100644 --- a/cmake/FindLevelDB.cmake +++ b/cmake/FindLevelDB.cmake @@ -16,16 +16,9 @@ find_path( DOC "leveldb include dir" ) -# if msvc 64 build -if (CMAKE_CL_64) - set(LEVELDB_NAMES leveldb_x64) -else () - set(LEVELDB_NAMES leveldb) -endif() - find_library( LEVELDB_LIBRARY - NAMES ${LEVELDB_NAMES} + NAMES leveldb DOC "leveldb library" ) @@ -37,15 +30,9 @@ set(LEVELDB_LIBRARIES ${LEVELDB_LIBRARY}) # boost is using the same "hack" as us with "optimized" and "debug" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - if (CMAKE_CL_64) - set(LEVELDB_NAMES_DEBUG leveldbd_x64) - else () - set(LEVELDB_NAMES_DEBUG leveldbd) - endif() - find_library( LEVELDB_LIBRARY_DEBUG - NAMES ${LEVELDB_NAMES_DEBUG} + NAMES leveldbd DOC "leveldb debug library" ) diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake index 1915b2f19..1e8ba03aa 100644 --- a/cmake/FindMHD.cmake +++ b/cmake/FindMHD.cmake @@ -15,16 +15,9 @@ find_path( DOC "microhttpd include dir" ) -# if msvc 64 build -if (CMAKE_CL_64) - set(MHD_NAMES microhttpd_x64 microhttpd-10_x64 libmicrohttpd_x64 libmicrohttpd-dll_x64) -else () - set(MHD_NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll) -endif() - find_library( MHD_LIBRARY - NAMES ${MHD_NAMES} + NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll DOC "microhttpd library" ) @@ -37,15 +30,9 @@ set(MHD_LIBRARIES ${MHD_LIBRARY}) # official MHD project actually uses _d suffix if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - if (CMAKE_CL_64) - set(MHD_NAMES_DEBUG microhttpd_d_x64 microhttpd-10_d_x64 libmicrohttpd_d_x64 libmicrohttpd-dll_d_x64) - else () - set(MHD_NAMES_DEBUG microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d) - endif() - find_library( MHD_LIBRARY_DEBUG - NAMES ${MHD_NAMES_DEBUG} + NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d DOC "mhd debug library" ) diff --git a/cmake/Findjson_rpc_cpp.cmake b/cmake/Findjson_rpc_cpp.cmake index ca3439717..0bdbe4d5c 100644 --- a/cmake/Findjson_rpc_cpp.cmake +++ b/cmake/Findjson_rpc_cpp.cmake @@ -24,32 +24,21 @@ find_path( DOC "json-rpc-cpp include dir" ) -# if msvc 64 build -if (CMAKE_CL_64) - set(JSON_RPC_CPP_COMMON_NAME jsonrpccpp-common_x64) - set(JSON_RPC_CPP_SERVER_NAME jsonrpccpp-server_x64) - set(JSON_RPC_CPP_CLIENT_NAME jsonrpccpp-client_x64) -else () - set(JSON_RPC_CPP_COMMON_NAME jsonrpccpp-common) - set(JSON_RPC_CPP_SERVER_NAME jsonrpccpp-server) - set(JSON_RPC_CPP_CLIENT_NAME jsonrpccpp-client) -endif() - find_library( JSON_RPC_CPP_COMMON_LIBRARY - NAMES ${JSON_RPC_CPP_COMMON_NAME} + NAMES jsonrpccpp-common DOC "json-rpc-cpp common library" ) find_library( JSON_RPC_CPP_SERVER_LIBRARY - NAMES ${JSON_RPC_CPP_SERVER_NAME} + NAMES jsonrpccpp-server DOC "json-rpc-cpp server library" ) find_library( JSON_RPC_CPP_CLIENT_LIBRARY - NAMES ${JSON_RPC_CPP_CLIENT_NAME} + NAMES jsonrpccpp-client DOC "json-rpc-cpp client library" ) @@ -64,32 +53,21 @@ set (JSON_RPC_CPP_CLIENT_LIBRARIES ${JSON_RPC_CPP_COMMON_LIBRARY} ${JSON_RPC_CPP # boost is using the same "hack" as us with "optimized" and "debug" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # if msvc 64 build - if (CMAKE_CL_64) - set(JSON_RPC_CPP_COMMON_NAME_DEBUG jsonrpccpp-commond_x64) - set(JSON_RPC_CPP_SERVER_NAME_DEBUG jsonrpccpp-serverd_x64) - set(JSON_RPC_CPP_CLIENT_NAME_DEBUG jsonrpccpp-clientd_x64) - else () - set(JSON_RPC_CPP_COMMON_NAME_DEBUG jsonrpccpp-commond) - set(JSON_RPC_CPP_SERVER_NAME_DEBUG jsonrpccpp-serverd) - set(JSON_RPC_CPP_CLIENT_NAME_DEBUG jsonrpccpp-clientd) - endif() - find_library( JSON_RPC_CPP_COMMON_LIBRARY_DEBUG - NAMES ${JSON_RPC_CPP_COMMON_NAME_DEBUG} + NAMES jsonrpccpp-commond DOC "json-rpc-cpp common debug library" ) find_library( JSON_RPC_CPP_SERVER_LIBRARY_DEBUG - NAMES ${JSON_RPC_CPP_SERVER_NAME_DEBUG} + NAMES jsonrpccpp-serverd DOC "json-rpc-cpp server debug library" ) find_library( JSON_RPC_CPP_CLIENT_LIBRARY_DEBUG - NAMES ${JSON_RPC_CPP_CLIENT_NAME_DEBUG} + NAMES jsonrpccpp-clientd DOC "json-rpc-cpp client debug library" ) From 6ae4b03211622ede94c85efdbf0f3b45ac87dc63 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 15:06:26 +0200 Subject: [PATCH 081/108] updated versions of dependencies --- extdep/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extdep/CMakeLists.txt b/extdep/CMakeLists.txt index 8735328eb..8ec381330 100644 --- a/extdep/CMakeLists.txt +++ b/extdep/CMakeLists.txt @@ -34,14 +34,14 @@ if (ETH_COMPILE) # boost include(compile/boost.cmake) else() + eth_download(boost VERSION 1.55.0) + eth_download(cryptopp VERSION 5.6.2) eth_download(curl VERSION 7.4.2) eth_download(jsoncpp VERSION 1.6.2) - eth_download(microhttpd VERSION 0.9.2) eth_download(json-rpc-cpp VERSION 0.5.0) - eth_download(qt VERSION 5.4) - eth_download(leveldb) - eth_download(cryptopp) - eth_download(boost) + eth_download(leveldb VERSION 1.2) + eth_download(microhttpd VERSION 0.9.2) + eth_download(qt VERSION 5.4.1) endif() # will be re-eanbled later From ae9c6626d3ba8c5f11f9c352526ff17f14dbc180 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 15:31:36 +0200 Subject: [PATCH 082/108] depracate '-n'. --- eth/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth/main.cpp b/eth/main.cpp index db6acbbca..5bc6f9911 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -342,6 +342,8 @@ int main(int argc, char** argv) exportTo = exportFrom = argv[++i]; else if ((arg == "-n" || arg == "-u" || arg == "--upnp") && i + 1 < argc) { + if (arg == "-n") + cerr << "-n is DEPRECATED. It will be removed for the Frontier. Use -u instead." << endl; string m = argv[++i]; if (isTrue(m)) upnp = true; From eaa4f43432927cc54349da1c719654e7c1f8acf2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 15:37:03 +0200 Subject: [PATCH 083/108] -DHEADLESS is DEPRECATED!!! --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c90dec46..d40d76ef2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,7 @@ else () endif () # Backwards compatibility if (HEADLESS) + message("*** WARNING: -DHEADLESS=1 option is DEPRECATED! Use -DBUNDLE=minimal or -DGUI=0") set(BUNDLE "minimal") endif () From aa686b1c0f764797e4a65393718ded21881e1deb Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 14 Apr 2015 16:41:21 +0200 Subject: [PATCH 084/108] Test Case for Miner Selection features. --- mix/qml/StateDialog.qml | 17 +++++++++++++++-- mix/qml/StateListModel.qml | 4 +++- mix/test/qml/TestMain.qml | 3 +++ mix/test/qml/js/TestMiner.js | 20 ++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 mix/test/qml/js/TestMiner.js diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index d609808ea..a2f9a09b7 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -22,6 +22,8 @@ Dialog { property alias isDefault: defaultCheckBox.checked property alias model: transactionsModel property alias transactionDialog: transactionDialog + property alias minerComboBox: comboMiner + property alias newAccAction: newAccountAction property int stateIndex property var stateTransactions: [] property var stateAccounts: [] @@ -46,12 +48,11 @@ Dialog { accountsModel.clear(); stateAccounts = []; var miner = 0; - for (var k = 0; k < item.accounts.length; k++) { accountsModel.append(item.accounts[k]); stateAccounts.push(item.accounts[k]); - if (item.accounts[k].name === item.miner.name) + if (item.miner && item.accounts[k].name === item.miner.name) miner = k; } @@ -91,6 +92,7 @@ Dialog { } return item; } + contentItem: Rectangle { color: stateDialogStyle.generic.backgroundColor Rectangle { @@ -138,6 +140,7 @@ Dialog { Button { + id: newAccountButton anchors.top: accountsLabel.bottom anchors.topMargin: 10 iconSource: "qrc:/qml/img/plus.png" @@ -148,10 +151,16 @@ Dialog { id: newAccountAction tooltip: qsTr("Add new Account") onTriggered: + { + add(); + } + + function add() { var account = stateListModel.newAccount("1000000", QEther.Ether); stateAccounts.push(account); accountsModel.append(account); + return account; } } } @@ -194,8 +203,12 @@ Dialog { alertAlreadyUsed.open(); else { + if (stateAccounts[styleData.row].name === comboMiner.currentText) + comboMiner.currentIndex = 0; stateAccounts.splice(styleData.row, 1); accountsModel.remove(styleData.row); + comboMiner.model = stateAccounts; + comboMiner.update(); } } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index fbb384caf..35d106b5f 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -193,7 +193,9 @@ Item { accounts: [] }; - item.accounts.push(newAccount("1000000", QEther.Ether, defaultAccount)); + var account = newAccount("1000000", QEther.Ether, defaultAccount) + item.accounts.push(account); + item.miner = account; //add all stdc contracts for (var i = 0; i < contractLibrary.model.count; i++) { diff --git a/mix/test/qml/TestMain.qml b/mix/test/qml/TestMain.qml index bf449d2dd..69f37f5a4 100644 --- a/mix/test/qml/TestMain.qml +++ b/mix/test/qml/TestMain.qml @@ -4,6 +4,7 @@ import org.ethereum.qml.TestService 1.0 import "../../qml" import "js/TestDebugger.js" as TestDebugger import "js/TestTutorial.js" as TestTutorial +import "js/TestMiner.js" as TestMiner TestCase { @@ -74,5 +75,7 @@ TestCase function test_dbg_transactionWithParameter() { TestDebugger.test_transactionWithParameter(); } function test_dbg_constructorParameters() { TestDebugger.test_constructorParameters(); } function test_dbg_arrayParametersAndStorage() { TestDebugger.test_arrayParametersAndStorage(); } + function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); } + function test_miner_selectMiner() { TestMiner.test_selectMiner(); } } diff --git a/mix/test/qml/js/TestMiner.js b/mix/test/qml/js/TestMiner.js new file mode 100644 index 000000000..a24b0ce19 --- /dev/null +++ b/mix/test/qml/js/TestMiner.js @@ -0,0 +1,20 @@ +function test_getDefaultMiner() +{ + newProject(); + var state = mainApplication.projectModel.stateListModel.get(0); + compare(state.miner.secret, "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074"); +} + +function test_selectMiner() +{ + newProject(); + mainApplication.projectModel.stateListModel.editState(0); + var account = mainApplication.projectModel.stateDialog.newAccAction.add(); + account = mainApplication.projectModel.stateDialog.newAccAction.add(); + mainApplication.projectModel.stateDialog.minerComboBox.currentIndex = 2; + ts.waitForRendering(mainApplication.projectModel.stateDialog.minerComboBox, 3000); + mainApplication.projectModel.stateDialog.acceptAndClose(); + var state = mainApplication.projectModel.stateListModel.get(0); + compare(state.miner.secret, account.secret); +} + From 8d2141fdf8b985f24612ba13f6dfcfd242fa206a Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 14 Apr 2015 16:52:23 +0200 Subject: [PATCH 085/108] fixed bad commit --- mix/test/qml/TestMain.qml | 3 --- 1 file changed, 3 deletions(-) diff --git a/mix/test/qml/TestMain.qml b/mix/test/qml/TestMain.qml index fb0c01adf..d1d962900 100644 --- a/mix/test/qml/TestMain.qml +++ b/mix/test/qml/TestMain.qml @@ -76,11 +76,8 @@ TestCase function test_dbg_transactionWithParameter() { TestDebugger.test_transactionWithParameter(); } function test_dbg_constructorParameters() { TestDebugger.test_constructorParameters(); } function test_dbg_arrayParametersAndStorage() { TestDebugger.test_arrayParametersAndStorage(); } -<<<<<<< HEAD function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); } function test_miner_selectMiner() { TestMiner.test_selectMiner(); } -======= function test_project_contractRename() { TestProject.test_contractRename(); } ->>>>>>> up/develop } From b5e9ab0a6fd5f12af48b76dfc76335b48837c4c0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 19:05:34 +0200 Subject: [PATCH 086/108] GPU/CPU Mining benchmarking. --- CMakeLists.txt | 18 +++- cmake/EthDependencies.cmake | 10 +- cmake/FindCpuid.cmake | 33 +++++++ eth/main.cpp | 157 ++++++++++++++++++++++++++++--- libethash-cl/ethash_cl_miner.cpp | 27 ++++++ libethash-cl/ethash_cl_miner.h | 1 + libethcore/CMakeLists.txt | 7 ++ libethcore/Ethash.cpp | 62 ++++++++++++ libethcore/Ethash.h | 2 + libethcore/Miner.h | 7 +- libethereum/Farm.h | 11 +++ 11 files changed, 316 insertions(+), 19 deletions(-) create mode 100644 cmake/FindCpuid.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d40d76ef2..2641f1bda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,14 @@ function(configureProject) add_definitions(-DETH_GUI) endif() + if (CPUID_FOUND) + add_definitions(-DETH_CPUID) + endif() + + if (CURL_FOUND) + add_definitions(-DETH_CURL) + endif() + add_definitions(-DETH_TRUE) endfunction() @@ -272,8 +280,6 @@ elseif (BUNDLE STREQUAL "user") set(TESTS OFF) endif () -configureProject() - # Default CMAKE_BUILD_TYPE to "Release". set(CMAKE_BUILD_TYPE CACHE STRING "Release") if ("x${CMAKE_BUILD_TYPE}" STREQUAL "x") @@ -290,6 +296,10 @@ if ("x${TARGET_PLATFORM}" STREQUAL "x") endif () endif () +include(EthDependencies) + +configureProject() + message("------------------------------------------------------------------------") message("-- CMake Version ${CMAKE_VERSION}") message("-- CMAKE_BUILD_TYPE Build type ${CMAKE_BUILD_TYPE}") @@ -297,6 +307,8 @@ message("-- TARGET_PLATFORM Target platform ${TARGET_P message("-- BUNDLE Build bundle ${BUNDLE}") message("--------------------------------------------------------------- features") message("-- Chromium support ${ETH_HAVE_WEBENGINE}") +message("-- Hardware identification support ${CPUID_FOUND}") +message("-- HTTP Request support ${CURL_FOUND}") message("-- VMTRACE VM execution tracing ${VMTRACE}") message("-- PROFILING Profiling support ${PROFILING}") message("-- FATDB Full database exploring ${FATDB}") @@ -322,9 +334,7 @@ endif () include(EthCompilerSettings) message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") - # this must be an include, as a function it would mess up with variable scope! -include(EthDependencies) include(EthExecutableHelper) createBuildInfo() diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 61c87efd2..4c6b7841a 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -59,7 +59,6 @@ if (JSONRPC) find_package(MHD) message(" - microhttpd header: ${MHD_INCLUDE_DIRS}") message(" - microhttpd lib : ${MHD_LIBRARIES}") - endif() #JSONRPC # TODO readline package does not yet check for correct version number @@ -86,7 +85,7 @@ endif() # TODO it is also not required in msvc build find_package (Gmp 6.0.0) if (GMP_FOUND) - message(" - gmp Header: ${GMP_INCLUDE_DIRS}") + message(" - gmp header: ${GMP_INCLUDE_DIRS}") message(" - gmp lib : ${GMP_LIBRARIES}") endif() @@ -96,6 +95,13 @@ find_package (CURL) message(" - curl header: ${CURL_INCLUDE_DIRS}") message(" - curl lib : ${CURL_LIBRARIES}") +# cpuid required for eth +find_package (Cpuid) +if (CPUID_FOUND) + message(" - cpuid header: ${CPUID_INCLUDE_DIRS}") + message(" - cpuid lib : ${CPUID_LIBRARIES}") +endif() + # find location of jsonrpcstub find_program(ETH_JSON_RPC_STUB jsonrpcstub) message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}") diff --git a/cmake/FindCpuid.cmake b/cmake/FindCpuid.cmake new file mode 100644 index 000000000..8b590f44b --- /dev/null +++ b/cmake/FindCpuid.cmake @@ -0,0 +1,33 @@ +# Find libcpuid +# +# Find the libcpuid includes and library +# +# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH +# +# This module defines +# CPUID_INCLUDE_DIRS, where to find header, etc. +# CPUID_LIBRARIES, the libraries needed to use cpuid. +# CPUID_FOUND, If false, do not try to use cpuid. + +# only look in default directories +find_path( + CPUID_INCLUDE_DIR + NAMES libcpuid/libcpuid.h + DOC "libcpuid include dir" + ) + +find_library( + CPUID_LIBRARY + NAMES cpuid + DOC "libcpuid library" + ) + +set(CPUID_INCLUDE_DIRS ${CPUID_INCLUDE_DIR}) +set(CPUID_LIBRARIES ${CPUID_LIBRARY}) + +# handle the QUIETLY and REQUIRED arguments and set CPUID_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(cpuid DEFAULT_MSG CPUID_INCLUDE_DIR CPUID_LIBRARY) +mark_as_advanced (CPUID_INCLUDE_DIR CPUID_LIBRARY) + diff --git a/eth/main.cpp b/eth/main.cpp index 5bc6f9911..7da725b6c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -89,7 +89,7 @@ void interactiveHelp() << " send Execute a given transaction with current secret." << endl << " contract Create a new contract with current secret." << endl << " peers List the peers that are connected" << endl -#if ETH_FATDB +#if ETH_FATDB || !ETH_TRUE << " listaccounts List the accounts on the network." << endl << " listcontracts List the contracts on the network." << endl #endif @@ -112,24 +112,31 @@ void help() << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -B,--block-fees Set the block fee profit in the reference unit e.g. ยข (Default: 15)." << endl << " -c,--client-name Add a name to your client's version string (default: blank)." << endl - << " -C,--check-pow Check PoW credentials for validity." << endl + << " -C,--cpu When mining, use the CPU." << endl << " -d,--db-path Load database from path (default: ~/.ethereum " << endl << " /Etherum or Library/Application Support/Ethereum)." << endl + << " --benchmark-warmup Set the duration of warmup for the benchmark tests (default: 15)." << endl + << " --benchmark-trial Set the duration for each trial for the benchmark tests (default: 3)." << endl + << " --benchmark-trials Set the duration of warmup for the benchmark tests (default: 5)." << endl << " -D,--create-dag Create the DAG in preparation for mining on given block and exit." << endl << " -e,--ether-price Set the ether price in the reference unit e.g. ยข (Default: 30.679)." << endl << " -E,--export Export file as a concatenated series of blocks and exit." << endl << " --from Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --to Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --only Equivalent to --export-from n --export-to n." << endl - << " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl + << " -f,--force-mining Mine even when there are no transactions to mine (Default: off)" << endl +#if ETH_JSONRPC || !ETH_TRUE + << " -F,--farm Put into mining farm mode (default GPU with CPU as fallback)." << endl +#endif + << " -G,--gpu When miningm use the GPU." << endl << " -h,--help Show this help message and exit." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl << " -I,--import Import file as a concatenated series of blocks and exit." << endl -#if ETH_JSONRPC +#if ETH_JSONRPC || !ETH_TRUE << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl #endif -#if ETH_EVMJIT +#if ETH_EVMJIT || !ETH_TRUE << " -J,--jit Enable EVM JIT (default: off)." << endl #endif << " -K,--kill First kill the blockchain." << endl @@ -137,17 +144,20 @@ void help() << " -l,--listen Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl << " -u,--public-ip Force public ip to given (default: auto)." << endl << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl - << " -n,-u,--upnp Use upnp for NAT (default: on)." << endl + << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --gpu." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl << " -p,--port Connect to remote port (default: 30303)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl + << " --phone-home When benchmarking, publish results (Default: on)" << endl << " -R,--rebuild First rebuild the blockchain from the existing database." << endl << " -r,--remote Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl << " -S,--temporary-secret Set the secret key for use with send command, for this session only." << endl + << " -u,--upnp Use upnp for NAT (default: on)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl - << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl << " -V,--version Show the version and exit." << endl + << " -w,--check-pow Check PoW credentials for validity." << endl + << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl ; exit(0); } @@ -221,7 +231,9 @@ enum class OperationMode Node, Import, Export, - DAGInit + DAGInit, + Benchmark, + Farm }; enum class Format @@ -231,6 +243,70 @@ enum class Format Human }; +enum class MinerType +{ + CPU, + GPU +}; + +void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) +{ + BlockInfo genesis = CanonBlockChain::genesis(); + genesis.difficulty = 1 << 18; + cdebug << genesis.boundary(); + + GenericFarm f; + f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + + string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + cout << "Benchmarking on platform: " << platformInfo << endl; + + cout << "Preparing DAG..." << endl; + Ethash::prep(genesis); + + genesis.difficulty = u256(1) << 63; + genesis.noteDirty(); + f.setWork(genesis); + if (_m == MinerType::CPU) + f.startCPU(); + else if (_m == MinerType::GPU) + f.startGPU(); + + map results; + uint64_t mean = 0; + uint64_t innerMean = 0; + for (unsigned i = 0; i <= _trials; ++i) + { + if (!i) + cout << "Warming up..." << endl; + else + cout << "Trial " << i << "... " << flush; + this_thread::sleep_for(chrono::seconds(i ? _trialDuration : _warmupDuration)); + + auto mp = f.miningProgress(); + f.resetMiningProgress(); + if (!i) + continue; + auto rate = mp.rate(); + + cout << rate << endl; + results[rate] = mp; + mean += rate; + if (i > 1 && i < 5) + innerMean += rate; + } + f.stop(); + cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl; + cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl; + + (void)_phoneHome; + if (_phoneHome) + { + // TODO: send f.miningInfo() along with f.platformInfo() to Marian. + } + exit(0); +} + int main(int argc, char** argv) { // Init defaults @@ -240,6 +316,9 @@ int main(int argc, char** argv) OperationMode mode = OperationMode::Node; string dbPath; + /// Mining options + MinerType minerType = MinerType::CPU; + /// File name for import/export. string filename; @@ -287,6 +366,12 @@ int main(int argc, char** argv) double etherPrice = 30.679; double blockFees = 15.0; + /// Benchmarking params + bool phoneHome = true; + unsigned benchmarkWarmup = 15; + unsigned benchmarkTrial = 3; + unsigned benchmarkTrials = 5; + string configFile = getDataDir() + "/config.rlp"; bytes b = contents(configFile); if (b.size()) @@ -319,6 +404,21 @@ int main(int argc, char** argv) mode = OperationMode::Export; filename = argv[++i]; } + else if (arg == "-F" || arg == "--farm") + mode = OperationMode::Farm; + else if (arg == "--phone-home" && i + 1 < argc) + { + string m = argv[++i]; + if (isTrue(m)) + phoneHome = true; + else if (isFalse(m)) + phoneHome = false; + else + { + cerr << "Bad " << arg << " option: " << m << endl; + return -1; + } + } else if (arg == "--format" && i + 1 < argc) { string m = argv[++i]; @@ -355,6 +455,33 @@ int main(int argc, char** argv) return -1; } } + else if (arg == "--benchmark-warmup" && i + 1 < argc) + try { + benchmarkWarmup = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } + else if (arg == "--benchmark-trial" && i + 1 < argc) + try { + benchmarkTrial = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } + else if (arg == "--benchmark-trials" && i + 1 < argc) + try { + benchmarkTrials = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill") killChain = WithExisting::Kill; else if (arg == "-B" || arg == "--rebuild") @@ -362,8 +489,7 @@ int main(int argc, char** argv) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) clientName = argv[++i]; else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) - try - { + try { coinbase = h160(fromHex(argv[++i], WhenError::Throw)); } catch (BadHexCharacter&) @@ -376,6 +502,10 @@ int main(int argc, char** argv) cerr << "Bad " << arg << " option: " << argv[i] << endl; return -1; } + else if (arg == "-C" || arg == "--cpu") + minerType = MinerType::CPU; + else if (arg == "-G" || arg == "--gpu") + minerType = MinerType::GPU; else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) sigKey = KeyPair(h256(fromHex(argv[++i]))); else if ((arg == "-S" || arg == "--session-secret") && i + 1 < argc) @@ -405,7 +535,7 @@ int main(int argc, char** argv) return -1; } } - else if ((arg == "-C" || arg == "--check-pow") && i + 4 < argc) + else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc) { string m; try @@ -442,6 +572,8 @@ int main(int argc, char** argv) return -1; } } + else if (arg == "-M" || arg == "--benchmark") + mode = OperationMode::Benchmark; else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc) { try @@ -564,6 +696,9 @@ int main(int argc, char** argv) if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock)) doInitDAG(initDAG); + if (mode == OperationMode::Benchmark) + doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials); + if (!clientName.empty()) clientName += "/"; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 016d8af58..c9a621e29 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -57,6 +57,33 @@ ethash_cl_miner::ethash_cl_miner() { } +std::string ethash_cl_miner::platform_info() +{ + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + debugf("No OpenCL platforms found.\n"); + return std::string(); + } + + // get GPU device of the default platform + std::vector devices; + platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) + { + debugf("No OpenCL devices found.\n"); + return std::string(); + } + + // use default device + unsigned device_num = 0; + cl::Device& device = devices[device_num]; + std::string device_version = device.getInfo(); + + return "{ platform: '" + platforms[0].getInfo() + "', device: '" + device.getInfo() + "', version: '" + device_version + "' }"; +} + void ethash_cl_miner::finish() { if (m_queue()) diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index d3d9f0223..079000f55 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -23,6 +23,7 @@ public: ethash_cl_miner(); bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64); + static std::string platform_info(); void finish(); void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index f562bc948..020480d67 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -11,11 +11,15 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) +if (CPUID_FOUND) + include_directories(${Cpuid_INCLUDE_DIRS}) +endif () set(EXECUTABLE ethcore) file(GLOB HEADERS "*.h") + if(ETH_STATIC) add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) else() @@ -25,6 +29,9 @@ endif() target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) +if (CPUID_FOUND) + target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) +endif () install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index a777205e9..632bc278d 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,10 @@ #if ETH_ETHASHCL || !ETH_TRUE #include #endif +#if ETH_CPUID || !ETH_TRUE +#define HAVE_STDINT_H +#include +#endif #include "BlockInfo.h" #include "EthashAux.h" using namespace std; @@ -142,6 +147,58 @@ void Ethash::CPUMiner::workLoop() } } +static string jsonEncode(map const& _m) +{ + string ret = "{"; + + for (auto const& i: _m) + { + string k = boost::replace_all_copy(boost::replace_all_copy(i.first, "\\", "\\\\"), "'", "\\'"); + string v = boost::replace_all_copy(boost::replace_all_copy(i.second, "\\", "\\\\"), "'", "\\'"); + if (ret.size() > 1) + ret += ", "; + ret += "\"" + k + "\":\"" + v + "\""; + } + + return ret + "}"; +} + +std::string Ethash::CPUMiner::platformInfo() +{ + string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; +#if ETH_CPUID || !ETH_TRUE + if (!cpuid_present()) + return baseline; + struct cpu_raw_data_t raw; + struct cpu_id_t data; + if (cpuid_get_raw_data(&raw) < 0) + return baseline; + if (cpu_identify(&raw, &data) < 0) + return baseline; + map m; + m["vendor"] = data.vendor_str; + m["codename"] = data.cpu_codename; + m["brand"] = data.brand_str; + m["L1 cache"] = toString(data.l1_data_cache); + m["L2 cache"] = toString(data.l2_cache); + m["L3 cache"] = toString(data.l3_cache); + m["cores"] = toString(data.num_cores); + m["threads"] = toString(data.num_logical_cpus); + m["clocknominal"] = toString(cpu_clock_by_os()); + m["clocktested"] = toString(cpu_clock_measure(200, 0)); + /* + printf(" MMX : %s\n", data.flags[CPU_FEATURE_MMX] ? "present" : "absent"); + printf(" MMX-extended: %s\n", data.flags[CPU_FEATURE_MMXEXT] ? "present" : "absent"); + printf(" SSE : %s\n", data.flags[CPU_FEATURE_SSE] ? "present" : "absent"); + printf(" SSE2 : %s\n", data.flags[CPU_FEATURE_SSE2] ? "present" : "absent"); + printf(" 3DNow! : %s\n", data.flags[CPU_FEATURE_3DNOW] ? "present" : "absent"); + */ + return jsonEncode(m); +#else + return baseline; +#endif +} + #if ETH_ETHASHCL || !ETH_TRUE class EthashCLHook: public ethash_cl_miner::search_hook @@ -258,6 +315,11 @@ void Ethash::GPUMiner::pause() stopWorking(); } +std::string Ethash::GPUMiner::platformInfo() +{ + return ethash_cl_miner::platform_info(); +} + #endif } diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 06e6b9e96..0d33d43a8 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -85,6 +85,7 @@ public: CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return std::thread::hardware_concurrency(); } + static std::string platformInfo(); protected: void kickOff() override @@ -109,6 +110,7 @@ public: ~GPUMiner(); static unsigned instances() { return 1; } + static std::string platformInfo(); protected: void kickOff() override; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 51a0ff6f6..71e952d5c 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -42,13 +42,14 @@ struct MiningProgress // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return hashes * 1000 / ms; } }; struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) { - _out << (_p.hashes * 1000 / _p.ms) << "H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << "s"; + _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; } @@ -112,7 +113,9 @@ public: m_hashCount = 0; } - uint64_t hashCount() { return m_hashCount; } + uint64_t hashCount() const { return m_hashCount; } + + void resetHashCount() { m_hashCount = 0; } unsigned index() const { return m_index; } diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 26d4b139e..869925098 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -118,6 +118,17 @@ public: return m_progress; } + /** + * @brief Reset the mining progess counter. + */ + void resetMiningProgress() + { + ETH_READ_GUARDED(x_minerWork) + for (auto const& i: m_miners) + i->resetHashCount(); + resetTimer(); + } + using SolutionFound = std::function; /** From aa6b3c28ccc58f722f6b5c370d1f5ee3b9b6e6cd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 20:59:40 +0200 Subject: [PATCH 087/108] Allow device selection. --- eth/main.cpp | 24 +++++++++++++++++++++--- libethash-cl/ethash_cl_miner.cpp | 11 ++++++++--- libethash-cl/ethash_cl_miner.h | 2 +- libethcore/Ethash.cpp | 4 +++- libethcore/Ethash.h | 4 ++++ 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 7da725b6c..bc7d4875c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -38,14 +38,17 @@ #include #include #include -#if ETH_READLINE +#if ETH_READLINE || !ETH_TRUE #include #include #endif -#if ETH_JSONRPC +#if ETH_JSONRPC || !ETH_TRUE #include #include #endif +#if ETH_CURL || !ETH_TRUE +#include +#endif #include "BuildInfo.h" using namespace std; using namespace dev; @@ -128,7 +131,7 @@ void help() #if ETH_JSONRPC || !ETH_TRUE << " -F,--farm Put into mining farm mode (default GPU with CPU as fallback)." << endl #endif - << " -G,--gpu When miningm use the GPU." << endl + << " -G,--gpu When mining use the GPU." << endl << " -h,--help Show this help message and exit." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl << " -I,--import Import file as a concatenated series of blocks and exit." << endl @@ -146,6 +149,7 @@ void help() << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --gpu." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl + << " --opencl-device When mining use OpenCL device n (default: 0)." << endl << " -p,--port Connect to remote port (default: 30303)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl << " --phone-home When benchmarking, publish results (Default: on)" << endl @@ -302,6 +306,8 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u (void)_phoneHome; if (_phoneHome) { + cout << "Phoning home to find world ranking..." << endl; + // TODO: send f.miningInfo() along with f.platformInfo() to Marian. } exit(0); @@ -318,6 +324,7 @@ int main(int argc, char** argv) /// Mining options MinerType minerType = MinerType::CPU; + unsigned openclDevice = 0; /// File name for import/export. string filename; @@ -406,6 +413,15 @@ int main(int argc, char** argv) } else if (arg == "-F" || arg == "--farm") mode = OperationMode::Farm; + else if (arg == "--opencl-device" && i + 1 < argc) + try { + openclDevice = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; @@ -718,6 +734,8 @@ int main(int argc, char** argv) if (mode == OperationMode::DAGInit) doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0)); + ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); + auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index c9a621e29..56ac44e6b 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -92,7 +92,7 @@ void ethash_cl_miner::finish() } } -bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size) +bool ethash_cl_miner::init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size, unsigned _deviceId) { // store params m_params = params; @@ -119,8 +119,13 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function(_deviceId, devices.size() - 1)]; + for (unsigned n = 0; n < devices.size(); ++n) + { + auto version = devices[n].getInfo(); + auto name = devices[n].getInfo(); + fprintf(stderr, "%s %d: %s (%s)\n", n == _deviceId ? "USING " : " ", n, name.c_str(), version.c_str()); + } std::string device_version = device.getInfo(); fprintf(stderr, "Using device: %s (%s)\n", device.getInfo().c_str(),device_version.c_str()); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 079000f55..c699a2d83 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -22,7 +22,7 @@ public: public: ethash_cl_miner(); - bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64); + bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64, unsigned _deviceId = 0); static std::string platform_info(); void finish(); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 632bc278d..2307da9dc 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -261,6 +261,8 @@ private: Ethash::GPUMiner* m_owner = nullptr; }; +unsigned Ethash::GPUMiner::s_deviceId = 0; + Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), m_hook(new EthashCLHook(this)) @@ -302,7 +304,7 @@ void Ethash::GPUMiner::workLoop() auto p = EthashAux::params(m_minerSeed); auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; - m_miner->init(p, cb, 32); + m_miner->init(p, cb, 32, s_deviceId); } uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 0d33d43a8..077da4460 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -86,6 +86,7 @@ public: static unsigned instances() { return std::thread::hardware_concurrency(); } static std::string platformInfo(); + static void setDefaultDevice(unsigned) {} protected: void kickOff() override @@ -98,6 +99,7 @@ public: private: void workLoop() override; + static unsigned s_deviceId; }; #if ETH_ETHASHCL || !ETH_TRUE @@ -111,6 +113,7 @@ public: static unsigned instances() { return 1; } static std::string platformInfo(); + static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } protected: void kickOff() override; @@ -126,6 +129,7 @@ public: ethash_cl_miner* m_miner = nullptr; h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_deviceId; }; #else using GPUMiner = CPUMiner; From fff8c42240787951b4770a257a43b4b978956391 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 21:02:00 +0200 Subject: [PATCH 088/108] Fix for previous. --- eth/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index bc7d4875c..c88ce1b1b 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -707,6 +707,8 @@ int main(int argc, char** argv) if (sessionSecret) sigKey = KeyPair(sessionSecret); + ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); + // Two codepaths is necessary since named block require database, but numbered // blocks are superuseful to have when database is already open in another process. if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock)) @@ -734,8 +736,6 @@ int main(int argc, char** argv) if (mode == OperationMode::DAGInit) doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0)); - ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); - auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); From 28f2badc38d1b4a06fe355cafbc672a6b7f432a0 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 21:04:48 +0200 Subject: [PATCH 089/108] cleanup in ethashcl --- cmake/EthDependencies.cmake | 6 ++++ eth/CMakeLists.txt | 1 + libethash-cl/CMakeLists.txt | 52 ++++++++-------------------------- libethash-cl/ethash_cl_miner.h | 9 ++++++ libethcore/CMakeLists.txt | 3 +- libethereum/CMakeLists.txt | 1 - 6 files changed, 30 insertions(+), 42 deletions(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 4c6b7841a..4d79d7911 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -102,6 +102,12 @@ if (CPUID_FOUND) message(" - cpuid lib : ${CPUID_LIBRARIES}") endif() +find_package (OpenCL) +if (OpenCL_FOUND) + message(" - opencl header: ${OpenCL_INCLUDE_DIRES}") + message(" - opencl lib : ${OpenCL_LIBRARIES}") +endif() + # find location of jsonrpcstub find_program(ETH_JSON_RPC_STUB jsonrpcstub) message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}") diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index fbc6a8b24..557707f62 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -27,6 +27,7 @@ endif() target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethash) +target_link_libraries(${EXECUTABLE} ethash-cl) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") diff --git a/libethash-cl/CMakeLists.txt b/libethash-cl/CMakeLists.txt index 7b00a22bd..d5f6792e1 100644 --- a/libethash-cl/CMakeLists.txt +++ b/libethash-cl/CMakeLists.txt @@ -1,47 +1,19 @@ -cmake_minimum_required(VERSION 2.8) - -set(LIBRARY ethash-cl) -#set(CMAKE_BUILD_TYPE Release) +set(EXECUTABLE ethash-cl) include(bin2h.cmake) bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl - VARIABLE_NAME ethash_cl_miner_kernel - HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) - -if (NOT MSVC) - # Initialize CXXFLAGS for c++11 - set(CMAKE_CXX_FLAGS "-Wall -std=c++11") - set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") - set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + VARIABLE_NAME ethash_cl_miner_kernel + HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) - # Compiler-specific C++11 activation. - if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)) - message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.") - endif () - elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") - else () - message(FATAL_ERROR "Your C++ compiler does not support C++11.") - endif () -endif() +aux_source_directory(. SRC_LIST) +file(GLOB HEADERS "*.h") -set(OpenCL_FOUND TRUE) -set(OpenCL_INCLUDE_DIRS /usr/include/CL) -set(OpenCL_LIBRARIES -lOpenCL) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${OpenCL_INCLUDE_DIRS}}) +include_directories(..) +add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) +TARGET_LINK_LIBRARIES(${EXECUTABLE} ${OpenCL_LIBRARIES} ethash) -if (NOT OpenCL_FOUND) - find_package(OpenCL) -endif() +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) -if (OpenCL_FOUND) - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -pedantic -fPIC ${CMAKE_CXX_FLAGS}") - include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) - include_directories(..) - add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp) - TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash) -endif() diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 079000f55..2776b7378 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -2,7 +2,16 @@ #define __CL_ENABLE_EXCEPTIONS #define CL_USE_DEPRECATED_OPENCL_2_0_APIS + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#include "cl.hpp" +#pragma clang diagnostic pop +#else #include "cl.hpp" +#endif + #include #include #include diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 020480d67..c425c444d 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -19,7 +19,6 @@ set(EXECUTABLE ethcore) file(GLOB HEADERS "*.h") - if(ETH_STATIC) add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) else() @@ -29,6 +28,8 @@ endif() target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) +target_link_libraries(${EXECUTABLE} ethash-cl) + if (CPUID_FOUND) target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) endif () diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 8822394a3..362713663 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -36,7 +36,6 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} secp256k1) if (ETHASHCL) target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} OpenCL) endif () if (CMAKE_COMPILER_IS_MINGW) From 5d660495f599d03678e7dc8dae1d52652bc721ac Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 21:16:38 +0200 Subject: [PATCH 090/108] Linux, Mac building with OpenCL. --- cmake/CMakeParseArguments.cmake | 161 +++++++++ cmake/FindOpenCL.cmake | 136 ++++++++ cmake/FindPackageHandleStandardArgs.cmake | 382 ++++++++++++++++++++++ cmake/FindPackageMessage.cmake | 57 ++++ eth/main.cpp | 11 + 5 files changed, 747 insertions(+) create mode 100644 cmake/CMakeParseArguments.cmake create mode 100644 cmake/FindOpenCL.cmake create mode 100644 cmake/FindPackageHandleStandardArgs.cmake create mode 100644 cmake/FindPackageMessage.cmake diff --git a/cmake/CMakeParseArguments.cmake b/cmake/CMakeParseArguments.cmake new file mode 100644 index 000000000..8553f38f5 --- /dev/null +++ b/cmake/CMakeParseArguments.cmake @@ -0,0 +1,161 @@ +#.rst: +# CMakeParseArguments +# ------------------- +# +# +# +# CMAKE_PARSE_ARGUMENTS( +# args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions +# for parsing the arguments given to that macro or function. It +# processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any +# value following, like e.g. the OPTIONAL keyword of the install() +# command. +# +# The argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The argument contains all keywords for this +# macro which can be followed by more than one value, like e.g. the +# TARGETS or FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in , and +# a variable composed of the given +# followed by "_" and the name of the respective keyword. These +# variables will then hold the respective value from the argument list. +# For the keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# _UNPARSED_ARGUMENTS, this can be checked afterwards to see +# whether your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments +# as the real install() command: +# +# :: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" +# "${multiValueArgs}" ${ARGN} ) +# ... +# +# +# +# Assume my_install() has been called like this: +# +# :: +# +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# +# +# After the cmake_parse_arguments() call the macro will have set the +# following variables: +# +# :: +# +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# +# +# You can then continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a +# one_value_keyword another recognized keyword follows, this is +# interpreted as the beginning of the new option. E.g. +# my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION +# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. + +#============================================================================= +# Copyright 2010 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach() + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach() + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else() + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif() + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach() + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach() + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction() diff --git a/cmake/FindOpenCL.cmake b/cmake/FindOpenCL.cmake new file mode 100644 index 000000000..4d3ed842c --- /dev/null +++ b/cmake/FindOpenCL.cmake @@ -0,0 +1,136 @@ +#.rst: +# FindOpenCL +# ---------- +# +# Try to find OpenCL +# +# Once done this will define:: +# +# OpenCL_FOUND - True if OpenCL was found +# OpenCL_INCLUDE_DIRS - include directories for OpenCL +# OpenCL_LIBRARIES - link against this library to use OpenCL +# OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2) +# OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation +# OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation +# +# The module will also define two cache variables:: +# +# OpenCL_INCLUDE_DIR - the OpenCL include directory +# OpenCL_LIBRARY - the path to the OpenCL library +# + +#============================================================================= +# Copyright 2014 Matthaeus G. Chajdas +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +function(_FIND_OPENCL_VERSION) + include(CheckSymbolExists) + include(CMakePushCheckState) + set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY}) + + CMAKE_PUSH_CHECK_STATE() + foreach(VERSION "2_0" "1_2" "1_1" "1_0") + set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}") + + if(APPLE) + CHECK_SYMBOL_EXISTS( + CL_VERSION_${VERSION} + "${OpenCL_INCLUDE_DIR}/OpenCL/cl.h" + OPENCL_VERSION_${VERSION}) + else() + CHECK_SYMBOL_EXISTS( + CL_VERSION_${VERSION} + "${OpenCL_INCLUDE_DIR}/CL/cl.h" + OPENCL_VERSION_${VERSION}) + endif() + + if(OPENCL_VERSION_${VERSION}) + string(REPLACE "_" "." VERSION "${VERSION}") + set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE) + string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}") + list(GET version_components 0 major_version) + list(GET version_components 1 minor_version) + set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE) + set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE) + break() + endif() + endforeach() + CMAKE_POP_CHECK_STATE() +endfunction() + +find_path(OpenCL_INCLUDE_DIR + NAMES + CL/cl.h OpenCL/cl.h + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV NVSDKCOMPUTE_ROOT + ENV CUDA_PATH + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + include + OpenCL/common/inc + "AMD APP/include") + +_FIND_OPENCL_VERSION() + +if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86" + lib/x86 + lib/Win32 + OpenCL/common/lib/Win32) + elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86_64" + lib/x86_64 + lib/x64 + OpenCL/common/lib/x64) + endif() +else() + find_library(OpenCL_LIBRARY + NAMES OpenCL) +endif() + +set(OpenCL_LIBRARIES ${OpenCL_LIBRARY}) +set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args( + OpenCL + FOUND_VAR OpenCL_FOUND + REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR + VERSION_VAR OpenCL_VERSION_STRING) + +mark_as_advanced( + OpenCL_INCLUDE_DIR + OpenCL_LIBRARY) diff --git a/cmake/FindPackageHandleStandardArgs.cmake b/cmake/FindPackageHandleStandardArgs.cmake new file mode 100644 index 000000000..6bcf1e788 --- /dev/null +++ b/cmake/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,382 @@ +#.rst: +# FindPackageHandleStandardArgs +# ----------------------------- +# +# +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( ... ) +# +# This function is intended to be used in FindXXX.cmake modules files. +# It handles the REQUIRED, QUIET and version-related arguments to +# find_package(). It also sets the _FOUND variable. The +# package is considered found if all variables ... listed contain +# valid results, e.g. valid filepaths. +# +# There are two modes of this function. The first argument in both +# modes is the name of the Find-module where it is called (in original +# casing). +# +# The first simple mode looks like this: +# +# :: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( +# (DEFAULT_MSG|"Custom failure message") ... ) +# +# If the variables to are all valid, then +# _FOUND will be set to TRUE. If DEFAULT_MSG is given +# as second argument, then the function will generate itself useful +# success and error messages. You can also supply a custom error +# message for the failure case. This is not recommended. +# +# The second mode is more powerful and also supports version checking: +# +# :: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME +# [FOUND_VAR ] +# [REQUIRED_VARS ...] +# [VERSION_VAR ] +# [HANDLE_COMPONENTS] +# [CONFIG_MODE] +# [FAIL_MESSAGE "Custom failure message"] ) +# +# In this mode, the name of the result-variable can be set either to +# either _FOUND or _FOUND using the +# FOUND_VAR option. Other names for the result-variable are not +# allowed. So for a Find-module named FindFooBar.cmake, the two +# possible names are FooBar_FOUND and FOOBAR_FOUND. It is recommended +# to use the original case version. If the FOUND_VAR option is not +# used, the default is _FOUND. +# +# As in the simple mode, if through are all valid, +# _FOUND will be set to TRUE. After REQUIRED_VARS the +# variables which are required for this package are listed. Following +# VERSION_VAR the name of the variable can be specified which holds the +# version of the package which has been found. If this is done, this +# version will be checked against the (potentially) specified required +# version used in the find_package() call. The EXACT keyword is also +# handled. The default messages include information about the required +# version and the version which has been actually found, both if the +# version is ok or not. If the package supports components, use the +# HANDLE_COMPONENTS option to enable handling them. In this case, +# find_package_handle_standard_args() will report which components have +# been found and which are missing, and the _FOUND variable +# will be set to FALSE if any of the required components (i.e. not the +# ones listed after OPTIONAL_COMPONENTS) are missing. Use the option +# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a +# find_package(... NO_MODULE) call. In this case VERSION_VAR will be +# set to _VERSION and the macro will automatically check whether +# the Config module was found. Via FAIL_MESSAGE a custom failure +# message can be specified, if this is not used, the default message +# will be displayed. +# +# Example for mode 1: +# +# :: +# +# find_package_handle_standard_args(LibXml2 DEFAULT_MSG +# LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) +# +# +# +# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and +# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to +# TRUE. If it is not found and REQUIRED was used, it fails with +# FATAL_ERROR, independent whether QUIET was used or not. If it is +# found, success will be reported, including the content of . On +# repeated Cmake runs, the same message won't be printed again. +# +# Example for mode 2: +# +# :: +# +# find_package_handle_standard_args(LibXslt +# FOUND_VAR LibXslt_FOUND +# REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS +# VERSION_VAR LibXslt_VERSION_STRING) +# +# In this case, LibXslt is considered to be found if the variable(s) +# listed after REQUIRED_VAR are all valid, i.e. LibXslt_LIBRARIES and +# LibXslt_INCLUDE_DIRS in this case. The result will then be stored in +# LibXslt_FOUND . Also the version of LibXslt will be checked by using +# the version contained in LibXslt_VERSION_STRING. Since no +# FAIL_MESSAGE is given, the default messages will be printed. +# +# Another example for mode 2: +# +# :: +# +# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) +# find_package_handle_standard_args(Automoc4 CONFIG_MODE) +# +# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4 +# NO_MODULE) and adds an additional search directory for automoc4. Here +# the result will be stored in AUTOMOC4_FOUND. The following +# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper +# success/error message. + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake) + +# internal helper macro +macro(_FPHSA_FAILURE_MESSAGE _msg) + if (${_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "${_msg}") + else () + if (NOT ${_NAME}_FIND_QUIETLY) + message(STATUS "${_msg}") + endif () + endif () +endmacro() + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + if(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + else() + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + if(${_NAME}_CONSIDERED_CONFIGS) + set(configsText "") + list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + math(EXPR configsCount "${configsCount} - 1") + foreach(currentConfigIndex RANGE ${configsCount}) + list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + set(configsText "${configsText} ${filename} (version ${version})\n") + endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") + + else() + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + endif() + endif() +endmacro() + + +function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + +# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in +# new extended or in the "old" mode: + set(options CONFIG_MODE HANDLE_COMPONENTS) + set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR) + set(multiValueArgs REQUIRED_VARS) + set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + if(${INDEX} EQUAL -1) + set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + set(FPHSA_REQUIRED_VARS ${ARGN}) + set(FPHSA_VERSION_VAR) + else() + + CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(FPHSA_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT FPHSA_FAIL_MESSAGE) + set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + endif() + endif() + +# now that we collected all arguments, process them + + if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") + set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + endif() + + # In config-mode, we rely on the variable _CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + if(FPHSA_CONFIG_MODE) + list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + set(FPHSA_VERSION_VAR ${_NAME}_VERSION) + endif() + + if(NOT FPHSA_REQUIRED_VARS) + message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + endif() + + list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + + string(TOUPPER ${_NAME} _NAME_UPPER) + string(TOLOWER ${_NAME} _NAME_LOWER) + + if(FPHSA_FOUND_VAR) + if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$") + set(_FOUND_VAR ${FPHSA_FOUND_VAR}) + else() + message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.") + endif() + else() + set(_FOUND_VAR ${_NAME_UPPER}_FOUND) + endif() + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + set(MISSING_VARS "") + set(DETAILS "") + # check if all passed variables are valid + unset(${_FOUND_VAR}) + foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + if(NOT ${_CURRENT_VAR}) + set(${_FOUND_VAR} FALSE) + set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}") + else() + set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]") + endif() + endforeach() + if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE") + set(${_FOUND_VAR} TRUE) + endif() + + # component handling + unset(FOUND_COMPONENTS_MSG) + unset(MISSING_COMPONENTS_MSG) + + if(FPHSA_HANDLE_COMPONENTS) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(${_NAME}_${comp}_FOUND) + + if(NOT DEFINED FOUND_COMPONENTS_MSG) + set(FOUND_COMPONENTS_MSG "found components: ") + endif() + set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}") + + else() + + if(NOT DEFINED MISSING_COMPONENTS_MSG) + set(MISSING_COMPONENTS_MSG "missing components: ") + endif() + set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}") + + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_FOUND_VAR} FALSE) + set(MISSING_VARS "${MISSING_VARS} ${comp}") + endif() + + endif() + endforeach() + set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]") + endif() + + # version handling: + set(VERSION_MSG "") + set(VERSION_OK TRUE) + set(VERSION ${${FPHSA_VERSION_VAR}}) + + # check with DEFINED here as the requested or found version may be "0" + if (DEFINED ${_NAME}_FIND_VERSION) + if(DEFINED ${FPHSA_VERSION_VAR}) + + if(${_NAME}_FIND_VERSION_EXACT) # exact version required + # count the dots in the version string + string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}") + # add one dot because there is one dot more than there are components + string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS) + if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT) + # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT + # is at most 4 here. Therefore a simple lookup table is used. + if (${_NAME}_FIND_VERSION_COUNT EQUAL 1) + set(_VERSION_REGEX "[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2) + set(_VERSION_REGEX "[^.]*\\.[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3) + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*") + else () + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") + endif () + string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}") + unset(_VERSION_REGEX) + if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD) + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + unset(_VERSION_HEAD) + else () + if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + endif () + unset(_VERSION_DOTS) + + else() # minimum version specified: + if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")") + endif () + endif() + + else() + + # if the package was not found, but a version was given, add that to the output: + if(${_NAME}_FIND_VERSION_EXACT) + set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + else() + set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + endif() + + endif() + else () + if(VERSION) + set(VERSION_MSG "(found version \"${VERSION}\")") + endif() + endif () + + if(VERSION_OK) + set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]") + else() + set(${_FOUND_VAR} FALSE) + endif() + + + # print the result: + if (${_FOUND_VAR}) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else () + + if(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + else() + if(NOT VERSION_OK) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") + else() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}") + endif() + endif() + + endif () + + set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE) + +endfunction() diff --git a/cmake/FindPackageMessage.cmake b/cmake/FindPackageMessage.cmake new file mode 100644 index 000000000..a0349d3db --- /dev/null +++ b/cmake/FindPackageMessage.cmake @@ -0,0 +1,57 @@ +#.rst: +# FindPackageMessage +# ------------------ +# +# +# +# FIND_PACKAGE_MESSAGE( "message for user" "find result details") +# +# This macro is intended to be used in FindXXX.cmake modules files. It +# will print a message once for each unique find result. This is useful +# for telling the user where a package was found. The first argument +# specifies the name (XXX) of the package. The second argument +# specifies the message to display. The third argument lists details +# about the find result so that if they change the message will be +# displayed again. The macro also obeys the QUIET argument to the +# find_package command. +# +# Example: +# +# :: +# +# if(X11_FOUND) +# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" +# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") +# else() +# ... +# endif() + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +function(FIND_PACKAGE_MESSAGE pkg msg details) + # Avoid printing a message repeatedly for the same find result. + if(NOT ${pkg}_FIND_QUIETLY) + string(REPLACE "\n" "" details "${details}") + set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) + if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") + # The message has not yet been printed. + message(STATUS "${msg}") + + # Save the find details in the cache to avoid printing the same + # message again. + set("${DETAILS_VAR}" "${details}" + CACHE INTERNAL "Details about finding ${pkg}") + endif() + endif() +endfunction() diff --git a/eth/main.cpp b/eth/main.cpp index c88ce1b1b..0896823d2 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -313,6 +313,14 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u exit(0); } +void doFarm(MinerType _m) +{ + (void)_m; + // TODO: Set up JSONRPC client: to implement: +// { "name": "eth_getWork", "params": [], "order": [], "returns": [, , ]}, +// { "name": "eth_submitWork", "params": [, ], "order": [], "returns": true}, +} + int main(int argc, char** argv) { // Init defaults @@ -717,6 +725,9 @@ int main(int argc, char** argv) if (mode == OperationMode::Benchmark) doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials); + if (mode == OperationMode::Farm) + doFarm(minerType); + if (!clientName.empty()) clientName += "/"; From 37e0f18129b3a5846df73a53ea0faa03bd69685f Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 21:45:13 +0200 Subject: [PATCH 091/108] ethashcl optional --- libethcore/CMakeLists.txt | 5 ++++- libethereum/CMakeLists.txt | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index c425c444d..6ef7b928c 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -28,7 +28,10 @@ endif() target_link_libraries(${EXECUTABLE} ethash) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} ethash-cl) + +if (ETHASHCL) + target_link_libraries(${EXECUTABLE} ethash-cl) +endif () if (CPUID_FOUND) target_link_libraries(${EXECUTABLE} ${CPUID_LIBRARIES}) diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 362713663..1d0911909 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -34,9 +34,6 @@ target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} secp256k1) -if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) -endif () if (CMAKE_COMPILER_IS_MINGW) target_link_libraries(${EXECUTABLE} ssp shlwapi) From 599f8d1c8047a62ffc343c40969f2a40663e9129 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 21:49:43 +0200 Subject: [PATCH 092/108] eth do not need ethash-cl --- eth/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index 557707f62..fbc6a8b24 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -27,7 +27,6 @@ endif() target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethash) -target_link_libraries(${EXECUTABLE} ethash-cl) if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") From a47ab408dfe7bff8253c009c31ac2bbd6f7eb797 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 22:01:55 +0200 Subject: [PATCH 093/108] fixed typo --- cmake/EthDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 16d5f89fc..2dfb80ac3 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -109,7 +109,7 @@ endif() find_package (OpenCL) if (OpenCL_FOUND) - message(" - opencl header: ${OpenCL_INCLUDE_DIRES}") + message(" - opencl header: ${OpenCL_INCLUDE_DIRS}") message(" - opencl lib : ${OpenCL_LIBRARIES}") endif() From 5fb0acd29b1d63c1c0d76da328cd5ff3cf572ecd Mon Sep 17 00:00:00 2001 From: ethdev zug Date: Tue, 14 Apr 2015 21:21:54 +0100 Subject: [PATCH 094/108] ethashcl on x64 :) --- libethash-cl/CMakeLists.txt | 2 +- libethcore/CMakeLists.txt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libethash-cl/CMakeLists.txt b/libethash-cl/CMakeLists.txt index d5f6792e1..fdc2dad07 100644 --- a/libethash-cl/CMakeLists.txt +++ b/libethash-cl/CMakeLists.txt @@ -9,7 +9,7 @@ aux_source_directory(. SRC_LIST) file(GLOB HEADERS "*.h") include_directories(${CMAKE_CURRENT_BINARY_DIR}) -include_directories(${OpenCL_INCLUDE_DIRS}}) +include_directories(${OpenCL_INCLUDE_DIRS}) include_directories(..) add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) TARGET_LINK_LIBRARIES(${EXECUTABLE} ${OpenCL_LIBRARIES} ethash) diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 6ef7b928c..322ac80ea 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -11,6 +11,11 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) + +if (ETHASHCL) + include_directories(${OpenCL_INCLUDE_DIRS}) +endif () + if (CPUID_FOUND) include_directories(${Cpuid_INCLUDE_DIRS}) endif () From be552419d3c75b4c30fe3a7692c5d8e203591686 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 22:25:44 +0200 Subject: [PATCH 095/108] removed unused lines in FindJsoncpp --- cmake/FindJsoncpp.cmake | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cmake/FindJsoncpp.cmake b/cmake/FindJsoncpp.cmake index 1c8540bad..1dbfc2046 100644 --- a/cmake/FindJsoncpp.cmake +++ b/cmake/FindJsoncpp.cmake @@ -31,12 +31,6 @@ set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY}) # boost is using the same "hack" as us with "optimized" and "debug" if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - if (CMAKE_CL_64) - set(JSONCPP_NAMES_DEBUG jsoncppd_x64) - else () - set(JSONCPP_NAMES_DEBUG jsoncppd) - endif() - find_library( JSONCPP_LIBRARY_DEBUG NAMES jsoncppd From d86b30d9d5967c453396b6ced76cc964160bffbc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 22:43:42 +0200 Subject: [PATCH 096/108] Options cleanup. --- eth/main.cpp | 37 +++++++++++++++++++++++++++--------- libethereum/EthereumHost.cpp | 5 +++-- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 0896823d2..be12e3668 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -114,7 +114,7 @@ void help() << " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -B,--block-fees Set the block fee profit in the reference unit e.g. ยข (Default: 15)." << endl - << " -c,--client-name Add a name to your client's version string (default: blank)." << endl + << " --client-name Add a name to your client's version string (default: blank)." << endl << " -C,--cpu When mining, use the CPU." << endl << " -d,--db-path Load database from path (default: ~/.ethereum " << endl << " /Etherum or Library/Application Support/Ethereum)." << endl @@ -143,21 +143,21 @@ void help() << " -J,--jit Enable EVM JIT (default: off)." << endl #endif << " -K,--kill First kill the blockchain." << endl - << " --listen-ip Listen on the given port for incoming connections (default: 30303)." << endl - << " -l,--listen Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl - << " -u,--public-ip Force public ip to given (default: auto)." << endl + << " --listen Listen on the given port for incoming connections (default: 30303)." << endl + << " --listen-ip (:) Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl + << " --public-ip Force public ip to given (default: auto)." << endl << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --gpu." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl << " --opencl-device When mining use OpenCL device n (default: 0)." << endl - << " -p,--port Connect to remote port (default: 30303)." << endl + << " --port Connect to remote port (default: 30303)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl << " --phone-home When benchmarking, publish results (Default: on)" << endl << " -R,--rebuild First rebuild the blockchain from the existing database." << endl - << " -r,--remote Connect to remote host (default: none)." << endl + << " -r,--remote (:) Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl - << " -S,--temporary-secret Set the secret key for use with send command, for this session only." << endl - << " -u,--upnp Use upnp for NAT (default: on)." << endl + << " -S,--session-secret Set the secret key for use with send command, for this session only." << endl + << " --upnp Use upnp for NAT (default: on)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl << " -V,--version Show the version and exit." << endl << " -w,--check-pow Check PoW credentials for validity." << endl @@ -319,6 +319,9 @@ void doFarm(MinerType _m) // TODO: Set up JSONRPC client: to implement: // { "name": "eth_getWork", "params": [], "order": [], "returns": [, , ]}, // { "name": "eth_submitWork", "params": [, ], "order": [], "returns": true}, + + + exit(0); } int main(int argc, char** argv) @@ -402,13 +405,25 @@ int main(int argc, char** argv) if (arg == "--listen-ip" && i + 1 < argc) listenIP = argv[++i]; else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) + { + if (arg == "-l") + cerr << "-l is DEPRECATED. It will be removed for the Frontier. Use --listen-port instead." << endl; listenPort = (short)atoi(argv[++i]); + } else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc) + { + if (arg == "-u") + cerr << "-u is DEPRECATED. It will be removed for the Frontier. Use --public-ip instead." << endl; publicIP = argv[++i]; + } else if ((arg == "-r" || arg == "--remote") && i + 1 < argc) remoteHost = argv[++i]; else if ((arg == "-p" || arg == "--port") && i + 1 < argc) + { + if (arg == "-p") + cerr << "-p is DEPRECATED. It will be removed for the Frontier. Use --port instead (or place directly as host:port)." << endl; remotePort = (short)atoi(argv[++i]); + } else if ((arg == "-I" || arg == "--import") && i + 1 < argc) { mode = OperationMode::Import; @@ -467,7 +482,7 @@ int main(int argc, char** argv) else if ((arg == "-n" || arg == "-u" || arg == "--upnp") && i + 1 < argc) { if (arg == "-n") - cerr << "-n is DEPRECATED. It will be removed for the Frontier. Use -u instead." << endl; + cerr << "-n is DEPRECATED. It will be removed for the Frontier. Use --upnp instead." << endl; string m = argv[++i]; if (isTrue(m)) upnp = true; @@ -511,7 +526,11 @@ int main(int argc, char** argv) else if (arg == "-B" || arg == "--rebuild") killChain = WithExisting::Verify; else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) + { + if (arg == "-c") + cerr << "-c is DEPRECATED. It will be removed for the Frontier. Use --client-name instead." << endl; clientName = argv[++i]; + } else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) try { coinbase = h160(fromHex(argv[++i], WhenError::Throw)); diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 6b50ddbae..4f0c49146 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -133,9 +133,10 @@ void EthereumHost::noteDoneBlocks(EthereumPeer* _who, bool _clemency) { // Done our chain-get. clog(NetNote) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished."; + clog(NetNote) << "TODO: PUNISH."; - m_banned.insert(_who->session()->id()); // We know who you are! - _who->disable("Peer sent hashes but was unable to provide the blocks."); +// m_banned.insert(_who->session()->id()); // We know who you are! +// _who->disable("Peer sent hashes but was unable to provide the blocks."); } m_man.reset(); } From b8f93a6b37520e3389ddc8afa76c320032fdad26 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 16:47:10 -0400 Subject: [PATCH 097/108] set socketid for logging --- libp2p/Common.h | 2 +- libp2p/Session.cpp | 1 + libp2p/Session.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libp2p/Common.h b/libp2p/Common.h index c9aee9a0e..51938e5f1 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -145,7 +145,7 @@ struct PeerSessionInfo unsigned short port; std::chrono::steady_clock::duration lastPing; std::set caps; - unsigned socket; + unsigned socketId; std::map notes; }; diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 8c5a50750..0ea7c33e2 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -48,6 +48,7 @@ Session::Session(Host* _s, RLPXFrameIO* _io, std::shared_ptr const& _n, Pe { m_peer->m_lastDisconnect = NoDisconnect; m_lastReceived = m_connect = chrono::steady_clock::now(); + m_info.socketId = _io->socket().native_handle(); } Session::~Session() diff --git a/libp2p/Session.h b/libp2p/Session.h index 95053d2a9..be8422c82 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -65,7 +65,7 @@ public: bool isConnected() const { return m_socket.is_open(); } NodeId id() const; - unsigned socketId() const { return m_info.socket; } + unsigned socketId() const { return m_info.socketId; } template std::shared_ptr cap() const { try { return std::static_pointer_cast(m_capabilities.at(std::make_pair(PeerCap::name(), PeerCap::version()))); } catch (...) { return nullptr; } } From 7c826ec051776bb3e91da173ca4b936aa1bfbb2e Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 14 Apr 2015 22:48:43 +0200 Subject: [PATCH 098/108] new way of downloading dependencies on windows --- extdep/getstuff.bat | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 extdep/getstuff.bat diff --git a/extdep/getstuff.bat b/extdep/getstuff.bat new file mode 100644 index 000000000..70cf51264 --- /dev/null +++ b/extdep/getstuff.bat @@ -0,0 +1,31 @@ +REM get stuff! +if not exist download mkdir download +if not exist install mkdir install +if not exist install\windows mkdir install\windows + +set eth_server=https://build.ethdev.com/builds/windows-precompiled + +call :download boost 1.55.0 +call :download cryptopp 5.6.2 +call :download curl 7.4.2 +call :download jsoncpp 1.6.2 +call :download json-rpc-cpp 0.5.0 +call :download leveldb 1.2 +call :download microhttpd 0.9.2 +call :download qt 5.4.1 + +goto :EOF + +:download + +set eth_name=%1 +set eth_version=%2 + +cd download +curl -o %eth_name%-%eth_version%.tar.gz %eth_server%/%eth_name%-%eth_version%.tar.gz +tar -zxvf %eth_name%-%eth_version%.tar.gz +cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows +cd ..\download + +goto :EOF + From f3008621494ec65f665c3557e9a4a045f3585b54 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 22:53:25 +0200 Subject: [PATCH 099/108] Diagnostics for peer ban issues. --- libethereum/DownloadMan.h | 9 +++++++++ libethereum/EthereumHost.cpp | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/libethereum/DownloadMan.h b/libethereum/DownloadMan.h index 1902f3db1..d32d0465c 100644 --- a/libethereum/DownloadMan.h +++ b/libethereum/DownloadMan.h @@ -134,6 +134,15 @@ public: return m_blocksGot.full(); } + h256s remaining() const + { + h256s ret; + ReadGuard l(m_lock); + for (auto i: m_blocksGot.inverted()) + ret.push_back(m_chain[i]); + return ret; + } + h256s chain() const { ReadGuard l(m_lock); return m_chain; } void foreachSub(std::function const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); } unsigned subCount() const { ReadGuard l(x_subs); return m_subs.size(); } diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 4f0c49146..6ef293d5a 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -132,9 +132,9 @@ void EthereumHost::noteDoneBlocks(EthereumPeer* _who, bool _clemency) else { // Done our chain-get. - clog(NetNote) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished."; - clog(NetNote) << "TODO: PUNISH."; - + clog(NetWarn) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished."; + clog(NetWarn) << m_man.remaining(); + clog(NetWarn) << "WOULD BAN."; // m_banned.insert(_who->session()->id()); // We know who you are! // _who->disable("Peer sent hashes but was unable to provide the blocks."); } From 1f31c30df924e180a49f51dff4f86d0bcffb5495 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 16:54:11 -0400 Subject: [PATCH 100/108] rename socketid --- alethzero/MainWin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a60875ba6..d0dab63d3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1027,7 +1027,7 @@ void Main::refreshNetwork() .arg(sessions[i.id] = QString::fromStdString(i.clientVersion)) .arg(QString::fromStdString(toString(i.caps))) .arg(QString::fromStdString(toString(i.notes))) - .arg(i.socket) + .arg(i.socketId) .arg(QString::fromStdString(i.id.abridged()))); auto ns = web3()->nodes(); From 96b6ec70cb2610bac5fe30fffd7aa08d5c127274 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 23:03:15 +0200 Subject: [PATCH 101/108] Version bump - 0.9.9 has no kickban/ --- libdevcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 78b3d9c30..7cdc433f3 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.8"; +char const* Version = "0.9.9"; } From 269bce9eaae4ecce6faa4ccd82facf1c552e08ce Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 23:05:50 +0200 Subject: [PATCH 102/108] AZ fix for socketId. --- alethzero/MainWin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a60875ba6..d0dab63d3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1027,7 +1027,7 @@ void Main::refreshNetwork() .arg(sessions[i.id] = QString::fromStdString(i.clientVersion)) .arg(QString::fromStdString(toString(i.caps))) .arg(QString::fromStdString(toString(i.notes))) - .arg(i.socket) + .arg(i.socketId) .arg(QString::fromStdString(i.id.abridged()))); auto ns = web3()->nodes(); From 09a9e5c2311cf14b5e4f25426e758c0bfe7dca7f Mon Sep 17 00:00:00 2001 From: ethdev zug Date: Tue, 14 Apr 2015 22:04:42 +0100 Subject: [PATCH 103/108] getstuff.bat, fixed #1621 --- extdep/getstuff.bat | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extdep/getstuff.bat b/extdep/getstuff.bat index 70cf51264..e083a97ce 100644 --- a/extdep/getstuff.bat +++ b/extdep/getstuff.bat @@ -22,10 +22,11 @@ set eth_name=%1 set eth_version=%2 cd download -curl -o %eth_name%-%eth_version%.tar.gz %eth_server%/%eth_name%-%eth_version%.tar.gz -tar -zxvf %eth_name%-%eth_version%.tar.gz + +if not exist %eth_name%-%eth_version%.tar.gz curl -o %eth_name%-%eth_version%.tar.gz %eth_server%/%eth_name%-%eth_version%.tar.gz +if not exist %eth_name%-%eth_version% tar -zxvf %eth_name%-%eth_version%.tar.gz cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows + cd ..\download goto :EOF - From 6cad687c3b42280a8a2f8ce50dba7e94a58650b2 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 17:47:00 -0400 Subject: [PATCH 104/108] Fix neighbours timeout to timeout-based on destination nodeid and not nodeid of the query. Update timeout to allow multiple packets. --- libp2p/NodeTable.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 652aec745..447a7f3c9 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -178,7 +178,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrendpoint.udp, _node); p.sign(m_secret); - m_findNodeTimeout.push_back(make_pair(_node, chrono::steady_clock::now())); + m_findNodeTimeout.push_back(make_pair(r->id, chrono::steady_clock::now())); m_socketPointer->send(p); } @@ -459,11 +459,14 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case Neighbours::type: { bool expected = false; + auto now = chrono::steady_clock::now(); m_findNodeTimeout.remove_if([&](NodeIdTimePoint const& t) { - if (t.first == nodeid && chrono::steady_clock::now() - t.second < c_reqTimeout) + if (t.first == nodeid && now - t.second < c_reqTimeout) expected = true; - return t.first == nodeid; + else if (t.first == nodeid) + return true; + return false; }); if (!expected) From 6b172571a711a738490a7bd00311b6eeccd3b9b4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 14 Apr 2015 23:50:46 +0200 Subject: [PATCH 105/108] Phone home :-) --- eth/CMakeLists.txt | 1 + eth/PhoneHome.h | 28 ++++++++++++++++++++++++++++ eth/main.cpp | 20 +++++++++++++++----- eth/phonehome.json | 3 +++ eth/spec.json | 4 ++++ 5 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 eth/PhoneHome.h create mode 100644 eth/phonehome.json create mode 100644 eth/spec.json diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index fbc6a8b24..bd6b8d354 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -22,6 +22,7 @@ if (READLINE_FOUND) endif() if (JSONRPC) + target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() diff --git a/eth/PhoneHome.h b/eth/PhoneHome.h new file mode 100644 index 000000000..ae6091cc2 --- /dev/null +++ b/eth/PhoneHome.h @@ -0,0 +1,28 @@ +/** + * This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY! + */ + +#ifndef JSONRPC_CPP_STUB_PHONEHOME_H_ +#define JSONRPC_CPP_STUB_PHONEHOME_H_ + +#include + +class PhoneHome : public jsonrpc::Client +{ + public: + PhoneHome(jsonrpc::IClientConnector &conn, jsonrpc::clientVersion_t type = jsonrpc::JSONRPC_CLIENT_V2) : jsonrpc::Client(conn, type) {} + + int report_benchmark(const std::string& param1, int param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("report_benchmark",p); + if (result.isInt()) + return result.asInt(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } +}; + +#endif //JSONRPC_CPP_STUB_PHONEHOME_H_ diff --git a/eth/main.cpp b/eth/main.cpp index be12e3668..8eebe3395 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -45,11 +45,10 @@ #if ETH_JSONRPC || !ETH_TRUE #include #include -#endif -#if ETH_CURL || !ETH_TRUE -#include +#include #endif #include "BuildInfo.h" +#include "PhoneHome.h" using namespace std; using namespace dev; using namespace dev::p2p; @@ -304,12 +303,23 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u cout << "inner mean: " << (innerMean / (_trials - 2)) << " H/s" << endl; (void)_phoneHome; +#if ETH_JSONRPC || !ETH_TRUE if (_phoneHome) { cout << "Phoning home to find world ranking..." << endl; - - // TODO: send f.miningInfo() along with f.platformInfo() to Marian. + jsonrpc::HttpClient client("http://192.168.33.39:3000/benchmark"); + PhoneHome rpc(client); + try + { + unsigned ranking = rpc.report_benchmark(platformInfo, innerMean); + cout << "Ranked: " << ranking << " of all benchmarks." << endl; + } + catch (...) + { + cout << "Error phoning home. ET is sad." << endl; + } } +#endif exit(0); } diff --git a/eth/phonehome.json b/eth/phonehome.json new file mode 100644 index 000000000..0bed56d72 --- /dev/null +++ b/eth/phonehome.json @@ -0,0 +1,3 @@ +[ + { "name": "report_benchmark", "params": [ "", 0 ], "order": [], "returns": 0 } +] diff --git a/eth/spec.json b/eth/spec.json new file mode 100644 index 000000000..24f0c163e --- /dev/null +++ b/eth/spec.json @@ -0,0 +1,4 @@ +[ + { "name": "eth_getWork", "params": [], "order": [], "returns": []}, + { "name": "eth_submitWork", "params": ["", ""], "order": [], "returns": true} +] From c80761b684e5d900e6f613322a353831b8f0aa15 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 17:51:11 -0400 Subject: [PATCH 106/108] Ignore interfaces which aren't UP. --- libp2p/Network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index 74bc8bd45..5702fbce7 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -84,7 +84,7 @@ std::set Network::getInterfaceAddresses() for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr || string(ifa->ifa_name) == "lo0") + if (!ifa->ifa_addr || string(ifa->ifa_name) == "lo0" || !(ifa->ifa_flags & IFF_UP)) continue; if (ifa->ifa_addr->sa_family == AF_INET) From 2bb61d80c7b86090e4b07cf0dc47f0578002903e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Apr 2015 00:47:23 +0200 Subject: [PATCH 107/108] RPC-mining. --- eth/Farm.h | 38 +++++++++++++++ eth/{spec.json => farm.json} | 0 eth/main.cpp | 82 +++++++++++++++++++++++++++----- libethash-cl/ethash_cl_miner.cpp | 2 +- libethereum/Farm.h | 15 +++--- 5 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 eth/Farm.h rename eth/{spec.json => farm.json} (100%) diff --git a/eth/Farm.h b/eth/Farm.h new file mode 100644 index 000000000..c061449e3 --- /dev/null +++ b/eth/Farm.h @@ -0,0 +1,38 @@ +/** + * This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY! + */ + +#ifndef JSONRPC_CPP_STUB_FARM_H_ +#define JSONRPC_CPP_STUB_FARM_H_ + +#include + +class Farm : public jsonrpc::Client +{ + public: + Farm(jsonrpc::IClientConnector &conn, jsonrpc::clientVersion_t type = jsonrpc::JSONRPC_CLIENT_V2) : jsonrpc::Client(conn, type) {} + + Json::Value eth_getWork() throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p = Json::nullValue; + Json::Value result = this->CallMethod("eth_getWork",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool eth_submitWork(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("eth_submitWork",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } +}; + +#endif //JSONRPC_CPP_STUB_FARM_H_ diff --git a/eth/spec.json b/eth/farm.json similarity index 100% rename from eth/spec.json rename to eth/farm.json diff --git a/eth/main.cpp b/eth/main.cpp index 8eebe3395..98d98b2ab 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -48,7 +48,10 @@ #include #endif #include "BuildInfo.h" +#if ETH_JSONRPC || !ETH_TRUE #include "PhoneHome.h" +#include "Farm.h" +#endif using namespace std; using namespace dev; using namespace dev::p2p; @@ -117,7 +120,7 @@ void help() << " -C,--cpu When mining, use the CPU." << endl << " -d,--db-path Load database from path (default: ~/.ethereum " << endl << " /Etherum or Library/Application Support/Ethereum)." << endl - << " --benchmark-warmup Set the duration of warmup for the benchmark tests (default: 15)." << endl + << " --benchmark-warmup Set the duration of warmup for the benchmark tests (default: 3)." << endl << " --benchmark-trial Set the duration for each trial for the benchmark tests (default: 3)." << endl << " --benchmark-trials Set the duration of warmup for the benchmark tests (default: 5)." << endl << " -D,--create-dag Create the DAG in preparation for mining on given block and exit." << endl @@ -128,9 +131,10 @@ void help() << " --only Equivalent to --export-from n --export-to n." << endl << " -f,--force-mining Mine even when there are no transactions to mine (Default: off)" << endl #if ETH_JSONRPC || !ETH_TRUE - << " -F,--farm Put into mining farm mode (default GPU with CPU as fallback)." << endl + << " -F,--farm Put into mining farm mode with the work server at URL. Use with -G/--opencl." << endl + << " --farm-recheck Leave n ms between checks for changed work (default: 500)." << endl #endif - << " -G,--gpu When mining use the GPU." << endl + << " -G,--opencl When mining use the GPU via OpenCL." << endl << " -h,--help Show this help message and exit." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl << " -I,--import Import file as a concatenated series of blocks and exit." << endl @@ -146,12 +150,14 @@ void help() << " --listen-ip (:) Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl << " --public-ip Force public ip to given (default: auto)." << endl << " -m,--mining Enable mining, optionally for a specified number of blocks (Default: off)" << endl - << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --gpu." << endl + << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl << " -o,--mode Start a full node or a peer node (Default: full)." << endl - << " --opencl-device When mining use OpenCL device n (default: 0)." << endl + << " --opencl-device When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << " --port Connect to remote port (default: 30303)." << endl << " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl +#if ETH_JSONRPC || !ETH_TRUE << " --phone-home When benchmarking, publish results (Default: on)" << endl +#endif << " -R,--rebuild First rebuild the blockchain from the existing database." << endl << " -r,--remote (:) Connect to remote host (default: none)." << endl << " -s,--secret Set the secret key for use with send command (default: auto)." << endl @@ -323,14 +329,48 @@ void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, u exit(0); } -void doFarm(MinerType _m) +void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod) { (void)_m; - // TODO: Set up JSONRPC client: to implement: -// { "name": "eth_getWork", "params": [], "order": [], "returns": [, , ]}, -// { "name": "eth_submitWork", "params": [, ], "order": [], "returns": true}, + (void)_remote; + (void)_recheckPeriod; +#if ETH_JSONRPC || !ETH_TRUE + jsonrpc::HttpClient client(_remote); + Farm rpc(client); + GenericFarm f; + if (_m == MinerType::CPU) + f.startCPU(); + else if (_m == MinerType::GPU) + f.startGPU(); + + ProofOfWork::WorkPackage current; + while (true) + { + bool completed = false; + ProofOfWork::Solution solution; + f.onSolutionFound([&](ProofOfWork::Solution sol) + { + solution = sol; + return completed = true; + }); + for (unsigned i = 0; !completed; ++i) + { + Json::Value v = rpc.eth_getWork(); + h256 hh(v[0].asString()); + if (hh != current.headerHash) + { + current.headerHash = hh; + current.seedHash = h256(v[1].asString()); + current.boundary = h256(v[2].asString()); + f.setWork(current); + } + this_thread::sleep_for(chrono::milliseconds(_recheckPeriod)); + } + rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(solution.mixHash)); + } +#endif exit(0); } @@ -396,10 +436,14 @@ int main(int argc, char** argv) /// Benchmarking params bool phoneHome = true; - unsigned benchmarkWarmup = 15; + unsigned benchmarkWarmup = 3; unsigned benchmarkTrial = 3; unsigned benchmarkTrials = 5; + /// Farm params + string farmURL = "http://127.0.0.1:8080"; + unsigned farmRecheckPeriod = 500; + string configFile = getDataDir() + "/config.rlp"; bytes b = contents(configFile); if (b.size()) @@ -444,8 +488,20 @@ int main(int argc, char** argv) mode = OperationMode::Export; filename = argv[++i]; } - else if (arg == "-F" || arg == "--farm") + else if ((arg == "-F" || arg == "--farm") && i + 1 < argc) + { mode = OperationMode::Farm; + farmURL = argv[++i]; + } + else if (arg == "--farm-recheck" && i + 1 < argc) + try { + farmRecheckPeriod = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "--opencl-device" && i + 1 < argc) try { openclDevice = stol(argv[++i]); @@ -557,7 +613,7 @@ int main(int argc, char** argv) } else if (arg == "-C" || arg == "--cpu") minerType = MinerType::CPU; - else if (arg == "-G" || arg == "--gpu") + else if (arg == "-G" || arg == "--opencl") minerType = MinerType::GPU; else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) sigKey = KeyPair(h256(fromHex(argv[++i]))); @@ -755,7 +811,7 @@ int main(int argc, char** argv) doBenchmark(minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials); if (mode == OperationMode::Farm) - doFarm(minerType); + doFarm(minerType, farmURL, farmRecheckPeriod); if (!clientName.empty()) clientName += "/"; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 56ac44e6b..172123439 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -81,7 +81,7 @@ std::string ethash_cl_miner::platform_info() cl::Device& device = devices[device_num]; std::string device_version = device.getInfo(); - return "{ platform: '" + platforms[0].getInfo() + "', device: '" + device.getInfo() + "', version: '" + device_version + "' }"; + return "{ \"platform\": \"" + platforms[0].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }"; } void ethash_cl_miner::finish() diff --git a/libethereum/Farm.h b/libethereum/Farm.h index 869925098..6263faf1b 100644 --- a/libethereum/Farm.h +++ b/libethereum/Farm.h @@ -59,14 +59,18 @@ public: * @brief Sets the current mining mission. * @param _bi The block (header) we wish to be mining. */ - void setWork(BlockInfo const& _bi) + void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } + + /** + * @brief Sets the current mining mission. + * @param _wp The work package we wish to be mining. + */ + void setWork(WorkPackage const& _wp) { WriteGuard l(x_minerWork); - m_header = _bi; - auto p = PoW::package(m_header); - if (p.headerHash == m_work.headerHash) + if (_wp.headerHash == m_work.headerHash) return; - m_work = p; + m_work = _wp; for (auto const& m: m_miners) m->setWork(m_work); resetTimer(); @@ -190,7 +194,6 @@ private: mutable SharedMutex x_minerWork; std::vector> m_miners; WorkPackage m_work; - BlockInfo m_header; std::atomic m_isMining = {false}; From 003fb51e06e9f9642773ac28519d088290e0aafb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Apr 2015 10:41:41 +0200 Subject: [PATCH 108/108] Fixes #1608 --- alethzero/MainWin.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index d0dab63d3..0de197a64 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -890,12 +890,16 @@ void Main::on_usePrivate_triggered() { m_privateChain = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0))); if (m_privateChain.isEmpty()) - ui->usePrivate->setChecked(false); + { + if (ui->usePrivate->isChecked()) + ui->usePrivate->setChecked(false); + else + // was cancelled. + return; + } } else - { m_privateChain.clear(); - } on_killBlockchain_triggered(); }