From 59cd60b266ebec20e441b8508671a579630b9870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 10 Feb 2016 11:56:15 +0200 Subject: [PATCH] eth, eth/downloader, jsre: surface state sync progress through the API --- eth/api.go | 30 ++-- eth/downloader/api.go | 7 +- eth/downloader/downloader.go | 14 +- eth/downloader/downloader_test.go | 32 ++--- jsre/ethereum_js.go | 218 +++++++++++++++--------------- 5 files changed, 159 insertions(+), 142 deletions(-) diff --git a/eth/api.go b/eth/api.go index 09ae0c468a..3c01e2c11c 100644 --- a/eth/api.go +++ b/eth/api.go @@ -152,21 +152,27 @@ func (s *PublicEthereumAPI) Hashrate() *rpc.HexNumber { } // Syncing returns false in case the node is currently not synching with the network. It can be up to date or has not -// yet received the latest block headers from its pears. In case it is synchronizing an object with 3 properties is -// returned: +// yet received the latest block headers from its pears. In case it is synchronizing: // - startingBlock: block number this node started to synchronise from -// - currentBlock: block number this node is currently importing -// - highestBlock: block number of the highest block header this node has received from peers +// - currentBlock: block number this node is currently importing +// - highestBlock: block number of the highest block header this node has received from peers +// - pulledStates: number of state entries processed until now +// - knownStates: number of known state entries that still need to be pulled func (s *PublicEthereumAPI) Syncing() (interface{}, error) { - origin, current, height := s.e.Downloader().Progress() - if current < height { - return map[string]interface{}{ - "startingBlock": rpc.NewHexNumber(origin), - "currentBlock": rpc.NewHexNumber(current), - "highestBlock": rpc.NewHexNumber(height), - }, nil + origin, current, height, pulled, known := s.e.Downloader().Progress() + + // Return not syncing if the synchronisation already completed + if current >= height { + return false, nil } - return false, nil + // Otherwise gather the block sync stats + return map[string]interface{}{ + "startingBlock": rpc.NewHexNumber(origin), + "currentBlock": rpc.NewHexNumber(current), + "highestBlock": rpc.NewHexNumber(height), + "pulledStates": rpc.NewHexNumber(pulled), + "knownStates": rpc.NewHexNumber(known), + }, nil } // PublicMinerAPI provides an API to control the miner. diff --git a/eth/downloader/api.go b/eth/downloader/api.go index cc79e669f0..6df911fee0 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -36,6 +36,8 @@ type Progress struct { Origin uint64 `json:"startingBlock"` Current uint64 `json:"currentBlock"` Height uint64 `json:"highestBlock"` + Pulled uint64 `json:"pulledStates"` + Known uint64 `json:"knownStates"` } // SyncingResult provides information about the current synchronisation status for this node. @@ -44,7 +46,7 @@ type SyncingResult struct { Status Progress `json:"status"` } -// Syncing provides information when this nodes starts synchronising with the Ethereumn network and when it's finished. +// Syncing provides information when this nodes starts synchronising with the Ethereum network and when it's finished. func (s *PublicDownloaderAPI) Syncing() (rpc.Subscription, error) { sub := s.d.mux.Subscribe(StartEvent{}, DoneEvent{}, FailedEvent{}) @@ -52,13 +54,12 @@ func (s *PublicDownloaderAPI) Syncing() (rpc.Subscription, error) { switch event.(type) { case StartEvent: result := &SyncingResult{Syncing: true} - result.Status.Origin, result.Status.Current, result.Status.Height = s.d.Progress() + result.Status.Origin, result.Status.Current, result.Status.Height, result.Status.Pulled, result.Status.Known = s.d.Progress() return result case DoneEvent, FailedEvent: return false } return nil } - return rpc.NewSubscriptionWithOutputFormat(sub, output), nil } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 698b99f8bc..6dad6a2cd6 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -196,7 +196,15 @@ func New(stateDb ethdb.Database, mux *event.TypeMux, hasHeader headerCheckFn, ha // Progress retrieves the synchronisation boundaries, specifically the origin // block where synchronisation started at (may have failed/suspended); the block // or header sync is currently at; and the latest known block which the sync targets. -func (d *Downloader) Progress() (uint64, uint64, uint64) { +// +// In addition, during the state download phase of fast synchonisation the number +// of processed and the total number of known states are also returned. Otherwise +// these are zero. +func (d *Downloader) Progress() (uint64, uint64, uint64, uint64, uint64) { + // Fetch the pending state count outside of the lock to prevent unforeseen deadlocks + pendingStates := uint64(d.queue.PendingNodeData()) + + // Lock the current stats and return the progress d.syncStatsLock.RLock() defer d.syncStatsLock.RUnlock() @@ -209,7 +217,7 @@ func (d *Downloader) Progress() (uint64, uint64, uint64) { case LightSync: current = d.headHeader().Number.Uint64() } - return d.syncStatsChainOrigin, current, d.syncStatsChainHeight + return d.syncStatsChainOrigin, current, d.syncStatsChainHeight, d.syncStatsStateDone, d.syncStatsStateDone + pendingStates } // Synchronising returns whether the downloader is currently retrieving blocks. @@ -296,7 +304,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode default: } } - // Reset and ephemeral sync statistics + // Reset any ephemeral sync statistics d.syncStatsLock.Lock() d.syncStatsStateTotal = 0 d.syncStatsStateDone = 0 diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 418243b208..993190c38c 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -1301,7 +1301,7 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) { <-progress } // Retrieve the sync progress and ensure they are zero (pristine sync) - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 { t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, 0) } // Synchronise half the blocks and check initial progress @@ -1316,7 +1316,7 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) { } }() <-starting - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks/2+1) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks/2+1) { t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, targetBlocks/2+1) } progress <- struct{}{} @@ -1333,14 +1333,14 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) { } }() <-starting - if origin, current, latest := tester.downloader.Progress(); origin != uint64(targetBlocks/2+1) || current != uint64(targetBlocks/2+1) || latest != uint64(targetBlocks) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != uint64(targetBlocks/2+1) || current != uint64(targetBlocks/2+1) || latest != uint64(targetBlocks) { t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, targetBlocks/2+1, targetBlocks/2+1, targetBlocks) } progress <- struct{}{} pending.Wait() // Check final progress after successful sync - if origin, current, latest := tester.downloader.Progress(); origin != uint64(targetBlocks/2+1) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != uint64(targetBlocks/2+1) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) { t.Fatalf("Final progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, targetBlocks/2+1, targetBlocks, targetBlocks) } } @@ -1373,7 +1373,7 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) { <-progress } // Retrieve the sync progress and ensure they are zero (pristine sync) - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 { t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, 0) } // Synchronise with one of the forks and check progress @@ -1388,7 +1388,7 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) { } }() <-starting - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(len(hashesA)-1) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(len(hashesA)-1) { t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, len(hashesA)-1) } progress <- struct{}{} @@ -1408,14 +1408,14 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) { } }() <-starting - if origin, current, latest := tester.downloader.Progress(); origin != uint64(common) || current != uint64(len(hashesA)-1) || latest != uint64(len(hashesB)-1) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != uint64(common) || current != uint64(len(hashesA)-1) || latest != uint64(len(hashesB)-1) { t.Fatalf("Forking progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, common, len(hashesA)-1, len(hashesB)-1) } progress <- struct{}{} pending.Wait() // Check final progress after successful sync - if origin, current, latest := tester.downloader.Progress(); origin != uint64(common) || current != uint64(len(hashesB)-1) || latest != uint64(len(hashesB)-1) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != uint64(common) || current != uint64(len(hashesB)-1) || latest != uint64(len(hashesB)-1) { t.Fatalf("Final progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, common, len(hashesB)-1, len(hashesB)-1) } } @@ -1448,7 +1448,7 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) { <-progress } // Retrieve the sync progress and ensure they are zero (pristine sync) - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 { t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, 0) } // Attempt a full sync with a faulty peer @@ -1468,7 +1468,7 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) { } }() <-starting - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks) { t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, targetBlocks) } progress <- struct{}{} @@ -1485,14 +1485,14 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) { } }() <-starting - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current > uint64(targetBlocks/2) || latest != uint64(targetBlocks) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current > uint64(targetBlocks/2) || latest != uint64(targetBlocks) { t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/0-%v/%v", origin, current, latest, 0, targetBlocks/2, targetBlocks) } progress <- struct{}{} pending.Wait() // Check final progress after successful sync - if origin, current, latest := tester.downloader.Progress(); origin > uint64(targetBlocks/2) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin > uint64(targetBlocks/2) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) { t.Fatalf("Final progress mismatch: have %v/%v/%v, want 0-%v/%v/%v", origin, current, latest, targetBlocks/2, targetBlocks, targetBlocks) } } @@ -1524,7 +1524,7 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) { <-progress } // Retrieve the sync progress and ensure they are zero (pristine sync) - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != 0 { t.Fatalf("Pristine progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, 0) } // Create and sync with an attacker that promises a higher chain than available @@ -1545,7 +1545,7 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) { } }() <-starting - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks+3) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current != 0 || latest != uint64(targetBlocks+3) { t.Fatalf("Initial progress mismatch: have %v/%v/%v, want %v/%v/%v", origin, current, latest, 0, 0, targetBlocks+3) } progress <- struct{}{} @@ -1562,14 +1562,14 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) { } }() <-starting - if origin, current, latest := tester.downloader.Progress(); origin != 0 || current > uint64(targetBlocks) || latest != uint64(targetBlocks) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin != 0 || current > uint64(targetBlocks) || latest != uint64(targetBlocks) { t.Fatalf("Completing progress mismatch: have %v/%v/%v, want %v/0-%v/%v", origin, current, latest, 0, targetBlocks, targetBlocks) } progress <- struct{}{} pending.Wait() // Check final progress after successful sync - if origin, current, latest := tester.downloader.Progress(); origin > uint64(targetBlocks) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) { + if origin, current, latest, _, _ := tester.downloader.Progress(); origin > uint64(targetBlocks) || current != uint64(targetBlocks) || latest != uint64(targetBlocks) { t.Fatalf("Final progress mismatch: have %v/%v/%v, want 0-%v/%v/%v", origin, current, latest, targetBlocks, targetBlocks, targetBlocks) } } diff --git a/jsre/ethereum_js.go b/jsre/ethereum_js.go index 94e4fde82e..6d56750362 100644 --- a/jsre/ethereum_js.go +++ b/jsre/ethereum_js.go @@ -653,7 +653,7 @@ module.exports = SolidityTypeBytes; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file coder.js * @author Marek Kotewicz * @date 2015 @@ -683,7 +683,7 @@ var SolidityCoder = function (types) { * * @method _requireType * @param {String} type - * @returns {SolidityType} + * @returns {SolidityType} * @throws {Error} throws if no matching type is found */ SolidityCoder.prototype._requireType = function (type) { @@ -731,7 +731,7 @@ SolidityCoder.prototype.encodeParams = function (types, params) { return acc + roundedStaticPartLength; }, 0); - var result = this.encodeMultiWithOffset(types, solidityTypes, encodeds, dynamicOffset); + var result = this.encodeMultiWithOffset(types, solidityTypes, encodeds, dynamicOffset); return result; }; @@ -756,7 +756,7 @@ SolidityCoder.prototype.encodeMultiWithOffset = function (types, solidityTypes, // TODO: figure out nested arrays }); - + types.forEach(function (type, i) { if (isDynamic(i)) { var e = self.encodeWithOffset(types[i], solidityTypes[i], encodeds[i], dynamicOffset); @@ -776,7 +776,7 @@ SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded var nestedName = solidityType.nestedName(type); var nestedStaticPartLength = solidityType.staticPartLength(nestedName); var result = encoded[0]; - + (function () { var previousLength = 2; // in int if (solidityType.isDynamicArray(nestedName)) { @@ -786,7 +786,7 @@ SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded } } })(); - + // first element is length, skip it (function () { for (var i = 0; i < encoded.length - 1; i++) { @@ -797,7 +797,7 @@ SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded return result; })(); - + } else if (solidityType.isStaticArray(type)) { return (function () { var nestedName = solidityType.nestedName(type); @@ -810,7 +810,7 @@ SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded var previousLength = 0; // in int for (var i = 0; i < encoded.length; i++) { // calculate length of previous item - previousLength += +(encoded[i - 1] || [])[0] || 0; + previousLength += +(encoded[i - 1] || [])[0] || 0; result += f.formatInputInt(offset + i * nestedStaticPartLength + previousLength * 32).encode(); } })(); @@ -853,7 +853,7 @@ SolidityCoder.prototype.decodeParam = function (type, bytes) { SolidityCoder.prototype.decodeParams = function (types, bytes) { var solidityTypes = this.getSolidityTypes(types); var offsets = this.getOffsets(types, solidityTypes); - + return solidityTypes.map(function (solidityType, index) { return solidityType.decode(bytes, offsets[index], types[index], index); }); @@ -863,16 +863,16 @@ SolidityCoder.prototype.getOffsets = function (types, solidityTypes) { var lengths = solidityTypes.map(function (solidityType, index) { return solidityType.staticPartLength(types[index]); }); - + for (var i = 1; i < lengths.length; i++) { // sum with length of previous element - lengths[i] += lengths[i - 1]; + lengths[i] += lengths[i - 1]; } return lengths.map(function (length, index) { // remove the current length, so the length is sum of previous elements var staticPartLength = solidityTypes[index].staticPartLength(types[index]); - return length - staticPartLength; + return length - staticPartLength; }); }; @@ -942,7 +942,7 @@ module.exports = SolidityTypeDynamicBytes; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file formatters.js * @author Marek Kotewicz * @date 2015 @@ -1086,7 +1086,7 @@ var formatOutputUInt = function (param) { * @returns {BigNumber} input bytes formatted to real */ var formatOutputReal = function (param) { - return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128)); + return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128)); }; /** @@ -1097,7 +1097,7 @@ var formatOutputReal = function (param) { * @returns {BigNumber} input bytes formatted to ureal */ var formatOutputUReal = function (param) { - return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128)); + return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128)); }; /** @@ -1232,7 +1232,7 @@ module.exports = SolidityTypeInt; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file param.js * @author Marek Kotewicz * @date 2015 @@ -1251,7 +1251,7 @@ var SolidityParam = function (value, offset) { /** * This method should be used to get length of params's dynamic part - * + * * @method dynamicPartLength * @returns {Number} length of dynamic part (in bytes) */ @@ -1279,7 +1279,7 @@ SolidityParam.prototype.withOffset = function (offset) { * @param {SolidityParam} result of combination */ SolidityParam.prototype.combine = function (param) { - return new SolidityParam(this.value + param.value); + return new SolidityParam(this.value + param.value); }; /** @@ -1311,8 +1311,8 @@ SolidityParam.prototype.offsetAsBytes = function () { */ SolidityParam.prototype.staticPart = function () { if (!this.isDynamic()) { - return this.value; - } + return this.value; + } return this.offsetAsBytes(); }; @@ -1344,7 +1344,7 @@ SolidityParam.prototype.encode = function () { * @returns {String} */ SolidityParam.encodeList = function (params) { - + // updating offsets var totalOffset = params.length * 32; var offsetParams = params.map(function (param) { @@ -1470,13 +1470,13 @@ SolidityType.prototype.staticPartLength = function (name) { /** * Should be used to determine if type is dynamic array - * eg: + * eg: * "type[]" => true * "type[4]" => false * * @method isDynamicArray * @param {String} name - * @return {Bool} true if the type is dynamic array + * @return {Bool} true if the type is dynamic array */ SolidityType.prototype.isDynamicArray = function (name) { var nestedTypes = this.nestedTypes(name); @@ -1485,13 +1485,13 @@ SolidityType.prototype.isDynamicArray = function (name) { /** * Should be used to determine if type is static array - * eg: + * eg: * "type[]" => false * "type[4]" => true * * @method isStaticArray * @param {String} name - * @return {Bool} true if the type is static array + * @return {Bool} true if the type is static array */ SolidityType.prototype.isStaticArray = function (name) { var nestedTypes = this.nestedTypes(name); @@ -1500,7 +1500,7 @@ SolidityType.prototype.isStaticArray = function (name) { /** * Should return length of static array - * eg. + * eg. * "int[32]" => 32 * "int256[14]" => 14 * "int[2][3]" => 3 @@ -1575,7 +1575,7 @@ SolidityType.prototype.nestedTypes = function (name) { * Should be used to encode the value * * @method encode - * @param {Object} value + * @param {Object} value * @param {String} name * @return {String} encoded value */ @@ -1589,7 +1589,7 @@ SolidityType.prototype.encode = function (value, name) { var result = []; result.push(f.formatInputInt(length).encode()); - + value.forEach(function (v) { result.push(self.encode(v, nestedName)); }); @@ -1665,12 +1665,12 @@ SolidityType.prototype.decode = function (bytes, offset, name) { return result; })(); } else if (this.isDynamicType(name)) { - + return (function () { var dynamicOffset = parseInt('0x' + bytes.substr(offset * 2, 64)); // in bytes var length = parseInt('0x' + bytes.substr(dynamicOffset * 2, 64)); // in bytes var roundedLength = Math.floor((length + 31) / 32); // in int - + return self._outputFormatter(new SolidityParam(bytes.substr(dynamicOffset * 2, ( 1 + roundedLength) * 64), 0)); })(); } @@ -1793,13 +1793,13 @@ if (typeof XMLHttpRequest === 'undefined') { /** * Utils - * + * * @module utils */ /** * Utility functions - * + * * @class [utils] config * @constructor */ @@ -1866,7 +1866,7 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file sha3.js * @author Marek Kotewicz * @date 2015 @@ -2444,7 +2444,7 @@ module.exports={ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file web3.js * @authors: * Jeffrey Wilcke @@ -2584,7 +2584,7 @@ module.exports = Web3; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file allevents.js * @author Marek Kotewicz * @date 2014 @@ -2674,7 +2674,7 @@ module.exports = AllSolidityEvents; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file batch.js * @author Marek Kotewicz * @date 2015 @@ -2719,7 +2719,7 @@ Batch.prototype.execute = function () { requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result)); } }); - }); + }); }; module.exports = Batch; @@ -2742,7 +2742,7 @@ module.exports = Batch; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file contract.js * @author Marek Kotewicz * @date 2014 @@ -2804,7 +2804,7 @@ var addEventsToContract = function (contract) { var All = new AllEvents(contract._eth._requestManager, events, contract.address); All.attachToContract(contract); - + events.map(function (json) { return new SolidityEvent(contract._eth._requestManager, json, contract.address); }).forEach(function (e) { @@ -2832,7 +2832,7 @@ var checkForContractAddress = function(contract, callback){ // stop watching after 50 blocks (timeout) if (count > 50) { - + filter.stopWatching(); callbackFired = true; @@ -2852,7 +2852,7 @@ var checkForContractAddress = function(contract, callback){ if(callbackFired || !code) return; - + filter.stopWatching(); callbackFired = true; @@ -2910,7 +2910,7 @@ var ContractFactory = function (eth, abi) { /** * Should be called to create new contract on a blockchain - * + * * @method new * @param {Any} contract constructor param1 (optional) * @param {Any} contract constructor param2 (optional) @@ -2976,14 +2976,14 @@ ContractFactory.prototype.new = function () { ContractFactory.prototype.at = function (address, callback) { var contract = new Contract(this.eth, this.abi, address); - // this functions are not part of prototype, + // this functions are not part of prototype, // because we dont want to spoil the interface addFunctionsToContract(contract); addEventsToContract(contract); - + if (callback) { callback(null, contract); - } + } return contract; }; @@ -3041,7 +3041,7 @@ module.exports = ContractFactory; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file errors.js * @author Marek Kotewicz * @date 2015 @@ -3081,7 +3081,7 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file event.js * @author Marek Kotewicz * @date 2014 @@ -3152,7 +3152,7 @@ SolidityEvent.prototype.signature = function () { /** * Should be used to encode indexed params and options to one final object - * + * * @method encode * @param {Object} indexed * @param {Object} options @@ -3183,7 +3183,7 @@ SolidityEvent.prototype.encode = function (indexed, options) { if (value === undefined || value === null) { return null; } - + if (utils.isArray(value)) { return value.map(function (v) { return '0x' + coder.encodeParam(i.type, v); @@ -3205,17 +3205,17 @@ SolidityEvent.prototype.encode = function (indexed, options) { * @return {Object} result object with decoded indexed && not indexed params */ SolidityEvent.prototype.decode = function (data) { - + data.data = data.data || ''; data.topics = data.topics || []; var argTopics = this._anonymous ? data.topics : data.topics.slice(1); var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(""); - var indexedParams = coder.decodeParams(this.types(true), indexedData); + var indexedParams = coder.decodeParams(this.types(true), indexedData); var notIndexedData = data.data.slice(2); var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData); - + var result = formatters.outputLogFormatter(data); result.event = this.displayName(); result.address = data.address; @@ -3250,7 +3250,7 @@ SolidityEvent.prototype.execute = function (indexed, options, callback) { indexed = {}; } } - + var o = this.encode(indexed, options); var formatter = this.decode.bind(this); return new Filter(this._requestManager, o, watches.eth(), formatter, callback); @@ -3311,7 +3311,7 @@ var extend = function (web3) { } }; - ex.formatters = formatters; + ex.formatters = formatters; ex.utils = utils; ex.Method = Method; ex.Property = Property; @@ -3380,7 +3380,7 @@ var getOptions = function (options) { if (utils.isString(options)) { return options; - } + } options = options || {}; @@ -3396,8 +3396,8 @@ var getOptions = function (options) { to: options.to, address: options.address, fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock), - toBlock: formatters.inputBlockNumberFormatter(options.toBlock) - }; + toBlock: formatters.inputBlockNumberFormatter(options.toBlock) + }; }; /** @@ -3405,7 +3405,7 @@ Adds the callback and sets up the methods, to iterate over the results. @method getLogsAtStart @param {Object} self -@param {funciton} +@param {funciton} */ var getLogsAtStart = function(self, callback){ // call getFilterLogs for the first watch callback start @@ -3573,7 +3573,7 @@ module.exports = Filter; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file formatters.js * @author Marek Kotewicz * @author Fabian Vogelsteller @@ -3640,7 +3640,7 @@ var inputCallFormatter = function (options){ options[key] = utils.fromDecimal(options[key]); }); - return options; + return options; }; /** @@ -3665,12 +3665,12 @@ var inputTransactionFormatter = function (options){ options[key] = utils.fromDecimal(options[key]); }); - return options; + return options; }; /** * Formats the output of a transaction to its proper values - * + * * @method outputTransactionFormatter * @param {Object} tx * @returns {Object} @@ -3689,7 +3689,7 @@ var outputTransactionFormatter = function (tx){ /** * Formats the output of a transaction receipt to its proper values - * + * * @method outputTransactionReceiptFormatter * @param {Object} receipt * @returns {Object} @@ -3715,7 +3715,7 @@ var outputTransactionReceiptFormatter = function (receipt){ * Formats the output of a block to its proper values * * @method outputBlockFormatter - * @param {Object} block + * @param {Object} block * @returns {Object} */ var outputBlockFormatter = function(block) { @@ -3743,7 +3743,7 @@ var outputBlockFormatter = function(block) { /** * Formats the output of a log - * + * * @method outputLogFormatter * @param {Object} log object * @returns {Object} log @@ -3784,7 +3784,7 @@ var inputPostFormatter = function(post) { return (topic.indexOf('0x') === 0) ? topic : utils.fromUtf8(topic); }); - return post; + return post; }; /** @@ -3836,6 +3836,8 @@ var outputSyncingFormatter = function(result) { result.startingBlock = utils.toDecimal(result.startingBlock); result.currentBlock = utils.toDecimal(result.currentBlock); result.highestBlock = utils.toDecimal(result.highestBlock); + result.pulledStates = utils.toDecimal(result.pulledStates); + result.knownStates = utils.toDecimal(result.knownStates); return result; }; @@ -3971,8 +3973,8 @@ SolidityFunction.prototype.call = function () { if (!callback) { var output = this._eth.call(payload, defaultBlock); return this.unpackOutput(output); - } - + } + var self = this; this._eth.call(payload, defaultBlock, function (error, output) { callback(error, self.unpackOutput(output)); @@ -4057,11 +4059,11 @@ SolidityFunction.prototype.request = function () { var callback = this.extractCallback(args); var payload = this.toPayload(args); var format = this.unpackOutput.bind(this); - + return { method: this._constant ? 'eth_call' : 'eth_sendTransaction', callback: callback, - params: [payload], + params: [payload], format: format }; }; @@ -4193,7 +4195,7 @@ HttpProvider.prototype.send = function (payload) { try { result = JSON.parse(result); } catch(e) { - throw errors.InvalidResponse(request.responseText); + throw errors.InvalidResponse(request.responseText); } return result; @@ -4207,7 +4209,7 @@ HttpProvider.prototype.send = function (payload) { * @param {Function} callback triggered on end with (err, result) */ HttpProvider.prototype.sendAsync = function (payload, callback) { - var request = this.prepareRequest(true); + var request = this.prepareRequest(true); request.onreadystatechange = function() { if (request.readyState === 4) { @@ -4217,13 +4219,13 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { try { result = JSON.parse(result); } catch(e) { - error = errors.InvalidResponse(request.responseText); + error = errors.InvalidResponse(request.responseText); } callback(error, result); } }; - + try { request.send(JSON.stringify(payload)); } catch(error) { @@ -4271,7 +4273,7 @@ module.exports = HttpProvider; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file iban.js * @author Marek Kotewicz * @date 2015 @@ -4471,7 +4473,7 @@ Iban.prototype.address = function () { var base36 = this._iban.substr(4); var asBn = new BigNumber(base36, 36); return padLeft(asBn.toString(16), 20); - } + } return ''; }; @@ -4516,7 +4518,7 @@ var IpcProvider = function (path, net) { var _this = this; this.responseCallbacks = {}; this.path = path; - + this.connection = net.connect({path: this.path}); this.connection.on('error', function(e){ @@ -4526,7 +4528,7 @@ var IpcProvider = function (path, net) { this.connection.on('end', function(){ _this._timeout(); - }); + }); // LISTEN FOR CONNECTION RESPONSES @@ -4565,7 +4567,7 @@ Will parse the response and make an array out of it. IpcProvider.prototype._parseResponse = function(data) { var _this = this, returnValues = []; - + // DE-CHUNKER var dechunkedData = data .replace(/\}\{/g,'}|--|{') // }{ @@ -4669,7 +4671,7 @@ IpcProvider.prototype.send = function (payload) { try { result = JSON.parse(data); } catch(e) { - throw errors.InvalidResponse(data); + throw errors.InvalidResponse(data); } return result; @@ -4850,7 +4852,7 @@ Method.prototype.extractCallback = function (args) { /** * Should be called to check if the number of arguments is correct - * + * * @method validateArgs * @param {Array} arguments * @throws {Error} if it is not @@ -4863,7 +4865,7 @@ Method.prototype.validateArgs = function (args) { /** * Should be called to format input args of method - * + * * @method formatInput * @param {Array} * @return {Array} @@ -4917,7 +4919,7 @@ Method.prototype.attachToObject = function (obj) { obj[name[0]] = obj[name[0]] || {}; obj[name[0]][name[1]] = func; } else { - obj[name[0]] = func; + obj[name[0]] = func; } }; @@ -4981,8 +4983,8 @@ var DB = function (web3) { this._requestManager = web3._requestManager; var self = this; - - methods().forEach(function(method) { + + methods().forEach(function(method) { method.attachToObject(self); method.setRequestManager(web3._requestManager); }); @@ -5084,12 +5086,12 @@ function Eth(web3) { var self = this; - methods().forEach(function(method) { + methods().forEach(function(method) { method.attachToObject(self); method.setRequestManager(self._requestManager); }); - properties().forEach(function(p) { + properties().forEach(function(p) { p.attachToObject(self); p.setRequestManager(self._requestManager); }); @@ -5388,7 +5390,7 @@ var Net = function (web3) { var self = this; - properties().forEach(function(p) { + properties().forEach(function(p) { p.attachToObject(self); p.setRequestManager(web3._requestManager); }); @@ -5444,7 +5446,7 @@ var Shh = function (web3) { var self = this; - methods().forEach(function(method) { + methods().forEach(function(method) { method.attachToObject(self); method.setRequestManager(self._requestManager); }); @@ -5454,11 +5456,11 @@ Shh.prototype.filter = function (fil, callback) { return new Filter(this._requestManager, fil, watches.shh(), formatters.outputPostFormatter, callback); }; -var methods = function () { +var methods = function () { var post = new Method({ - name: 'post', - call: 'shh_post', + name: 'post', + call: 'shh_post', params: 1, inputFormatter: [formatters.inputPostFormatter] }); @@ -5632,7 +5634,7 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file namereg.js * @author Marek Kotewicz * @date 2015 @@ -5697,7 +5699,7 @@ Property.prototype.setRequestManager = function (rm) { /** * Should be called to format input args of method - * + * * @method formatInput * @param {Array} * @return {Array} @@ -5733,7 +5735,7 @@ Property.prototype.extractCallback = function (args) { /** * Should attach function to method - * + * * @method attachToObject * @param {Object} * @param {Function} @@ -5766,7 +5768,7 @@ Property.prototype.buildGet = function () { return function get() { return property.formatOutput(property.requestManager.send({ method: property.getter - })); + })); }; }; @@ -5820,7 +5822,7 @@ module.exports = Property; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file requestmanager.js * @author Jeffrey Wilcke * @author Marek Kotewicz @@ -5887,7 +5889,7 @@ RequestManager.prototype.sendAsync = function (data, callback) { if (err) { return callback(err); } - + if (!Jsonrpc.getInstance().isValidResponse(result)) { return callback(errors.InvalidResponse(result)); } @@ -5920,7 +5922,7 @@ RequestManager.prototype.sendBatch = function (data, callback) { } callback(err, results); - }); + }); }; /** @@ -6024,7 +6026,7 @@ RequestManager.prototype.poll = function () { } var payload = Jsonrpc.getInstance().toBatchPayload(pollsData); - + // map the request id to they poll id var pollsIdMap = {}; payload.forEach(function(load, index){ @@ -6054,7 +6056,7 @@ RequestManager.prototype.poll = function () { } else return false; }).filter(function (result) { - return !!result; + return !!result; }).filter(function (result) { var valid = Jsonrpc.getInstance().isValidResponse(result); if (!valid) { @@ -6129,16 +6131,16 @@ var pollSyncing = function(self) { self.callbacks.forEach(function (callback) { if (self.lastSyncState !== sync) { - + // call the callback with true first so the app can stop anything, before receiving the sync data if(!self.lastSyncState && utils.isObject(sync)) callback(null, true); - + // call on the next CPU cycle, so the actions of the sync stop can be processes first setTimeout(function() { callback(null, sync); }, 0); - + self.lastSyncState = sync; } }); @@ -6193,7 +6195,7 @@ module.exports = IsSyncing; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file transfer.js * @author Marek Kotewicz * @date 2015 @@ -6212,7 +6214,7 @@ var exchangeAbi = require('../contracts/SmartExchange.json'); * @param {Function} callback, callback */ var transfer = function (eth, from, to, value, callback) { - var iban = new Iban(to); + var iban = new Iban(to); if (!iban.isValid()) { throw new Error('invalid iban address'); } @@ -6220,7 +6222,7 @@ var transfer = function (eth, from, to, value, callback) { if (iban.isDirect()) { return transferToAddress(eth, from, iban.address(), value, callback); } - + if (!callback) { var address = eth.icapNamereg().addr(iban.institution()); return deposit(eth, from, address, value, iban.client()); @@ -6229,7 +6231,7 @@ var transfer = function (eth, from, to, value, callback) { eth.icapNamereg().addr(iban.institution(), function (err, address) { return deposit(eth, from, address, value, iban.client(), callback); }); - + }; /**