Fix slow balances (#6471)
* Update token updates
* Update token info fetching
* Update logger
* Minor fixes to updates and notifications for balances
* Use Pubsub
* Fix timeout.
* Use pubsub for status.
* Fix signer subscription.
* Process tokens in chunks.
* Fix tokens loaded by chunks
* Linting
* Dispatch tokens asap
* Fix chunks processing.
* Better filter options
* Parallel log fetching.
* Fix signer polling.
* Fix initial block query.
* Token balances updates : the right(er) way
* Better tokens info fetching
* Fixes in token data fetching
* Only fetch what's needed (tokens)
* Fix linting issues
* Revert "Transaction permissioning (#6441)"
This reverts commit eed0e8b03a.
* Revert "Revert "Transaction permissioning (#6441)""
This reverts commit 8f96415e58dde652e5828706eb2639d43416f448.
* Update wasm-tests.
* Fixing balances fetching
* Fix requests tracking in UI
* Fix request watching
* Update the Logger
* PR Grumbles Fixes
* PR Grumbles fixes
* Linting...
This commit is contained in:
committed by
Gav Wood
parent
ee14a3fb31
commit
f1a050366f
@@ -71,10 +71,15 @@ export default class Api extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
get isPubSub () {
|
||||
return !!this._pubsub;
|
||||
}
|
||||
|
||||
get pubsub () {
|
||||
if (!this._pubsub) {
|
||||
if (!this.isPubSub) {
|
||||
throw Error('Pubsub is only available with a subscribing-supported transport injected!');
|
||||
}
|
||||
|
||||
return this._pubsub;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export default class Eth extends PubsubBase {
|
||||
}
|
||||
|
||||
newHeads (callback) {
|
||||
return this.addListener('eth', 'newHeads', callback);
|
||||
return this.addListener('eth', 'newHeads', callback, null);
|
||||
}
|
||||
|
||||
logs (callback) {
|
||||
|
||||
@@ -267,7 +267,7 @@ export default class Parity extends PubsubBase {
|
||||
|
||||
// parity accounts API (only secure API or configured to be exposed)
|
||||
allAccountsInfo (callback) {
|
||||
return this._addListener(this._api, 'parity_allAccountsInfo', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_allAccountsInfo', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outAccountInfo(data));
|
||||
@@ -275,7 +275,7 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
getDappAddresses (callback, dappId) {
|
||||
return this._addListener(this._api, 'parity_getDappAddresses', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_getDappAddresses', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outAddresses(data));
|
||||
@@ -283,7 +283,7 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
getDappDefaultAddress (callback, dappId) {
|
||||
return this._addListener(this._api, 'parity_getDappDefaultAddress', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_getDappDefaultAddress', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outAddress(data));
|
||||
@@ -291,7 +291,7 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
getNewDappsAddresses (callback) {
|
||||
return this._addListener(this._api, 'parity_getDappDefaultAddress', (error, addresses) => {
|
||||
return this.addListener(this._api, 'parity_getDappDefaultAddress', (error, addresses) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, addresses ? addresses.map(outAddress) : null);
|
||||
@@ -299,7 +299,7 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
getNewDappsDefaultAddress (callback) {
|
||||
return this._addListener(this._api, 'parity_getNewDappsDefaultAddress', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_getNewDappsDefaultAddress', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outAddress(data));
|
||||
@@ -307,7 +307,7 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
listRecentDapps (callback) {
|
||||
return this._addListener(this._api, 'parity_listRecentDapps', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_listRecentDapps', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outRecentDapps(data));
|
||||
@@ -315,7 +315,7 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
listGethAccounts (callback) {
|
||||
return this._addListener(this._api, 'parity_listGethAccounts', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_listGethAccounts', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outAddresses(data));
|
||||
@@ -323,15 +323,15 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
listVaults (callback) {
|
||||
return this._addListener(this._api, 'parity_listVaults', callback);
|
||||
return this.addListener(this._api, 'parity_listVaults', callback);
|
||||
}
|
||||
|
||||
listOpenedVaults (callback) {
|
||||
return this._addListener(this._api, 'parity_listOpenedVaults', callback);
|
||||
return this.addListener(this._api, 'parity_listOpenedVaults', callback);
|
||||
}
|
||||
|
||||
getVaultMeta (callback, vaultName) {
|
||||
return this._addListener(this._api, 'parity_getVaultMeta', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_getVaultMeta', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outVaultMeta(data));
|
||||
@@ -339,7 +339,7 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
deriveAddressHash (callback, address, password, hash, shouldSave) {
|
||||
return this._addListener(this._api, 'parity_deriveAddressHash', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_deriveAddressHash', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outAddress(data));
|
||||
@@ -347,10 +347,18 @@ export default class Parity extends PubsubBase {
|
||||
}
|
||||
|
||||
deriveAddressIndex (callback, address, password, index, shouldSave) {
|
||||
return this._addListener(this._api, 'parity_deriveAddressIndex', (error, data) => {
|
||||
return this.addListener(this._api, 'parity_deriveAddressIndex', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, outAddress(data));
|
||||
}, [inAddress(address), password, inDeriveIndex(index), !!shouldSave]);
|
||||
}
|
||||
|
||||
nodeHealth (callback) {
|
||||
return this.addListener(this._api, 'parity_nodeHealth', (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import Eth from './eth';
|
||||
import Parity from './parity';
|
||||
import Signer from './signer';
|
||||
import Net from './net';
|
||||
|
||||
import { isFunction } from '../util/types';
|
||||
@@ -29,6 +30,7 @@ export default class Pubsub {
|
||||
this._eth = new Eth(transport);
|
||||
this._net = new Net(transport);
|
||||
this._parity = new Parity(transport);
|
||||
this._signer = new Signer(transport);
|
||||
}
|
||||
|
||||
get net () {
|
||||
@@ -43,8 +45,35 @@ export default class Pubsub {
|
||||
return this._parity;
|
||||
}
|
||||
|
||||
get signer () {
|
||||
return this._signer;
|
||||
}
|
||||
|
||||
unsubscribe (subscriptionIds) {
|
||||
// subscriptions are namespace independent. Thus we can simply removeListener from any.
|
||||
return this._parity.removeListener(subscriptionIds);
|
||||
}
|
||||
|
||||
subscribeAndGetResult (f, callback) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let isFirst = true;
|
||||
let onSubscription = (error, data) => {
|
||||
const p1 = error ? Promise.reject(error) : Promise.resolve(data);
|
||||
const p2 = p1.then(callback);
|
||||
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
p2
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
f.call(this, onSubscription).catch(reject);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,12 @@ export default class PubsubBase {
|
||||
this._transport = transport;
|
||||
}
|
||||
|
||||
addListener (module, eventName, callback, eventParams) {
|
||||
return eventParams
|
||||
? this._transport.subscribe(module, callback, eventName, eventParams)
|
||||
: this._transport.subscribe(module, callback, eventName, []);
|
||||
// this._transport.subscribe(module, callback, eventName); After Patch from tomac is merged to master! => eth_subscribe does not support empty array as params
|
||||
addListener (module, eventName, callback, eventParams = []) {
|
||||
if (eventName) {
|
||||
return this._transport.subscribe(module, callback, eventParams ? [eventName, eventParams] : [eventName]);
|
||||
}
|
||||
|
||||
return this._transport.subscribe(module, callback, eventParams);
|
||||
}
|
||||
|
||||
removeListener (subscriptionIds) {
|
||||
|
||||
16
js/src/api/pubsub/signer/index.js
Normal file
16
js/src/api/pubsub/signer/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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.
|
||||
|
||||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
export default from './signer';
|
||||
37
js/src/api/pubsub/signer/signer.js
Normal file
37
js/src/api/pubsub/signer/signer.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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.
|
||||
|
||||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
import PubsubBase from '../pubsubBase';
|
||||
|
||||
import { outSignerRequest } from '../../format/output';
|
||||
|
||||
export default class Net extends PubsubBase {
|
||||
constructor (transport) {
|
||||
super(transport);
|
||||
this._api = {
|
||||
subscribe: 'signer_subscribePending',
|
||||
unsubscribe: 'signer_unsubscribePending',
|
||||
subscription: 'signer_pending'
|
||||
};
|
||||
}
|
||||
|
||||
pendingRequests (callback) {
|
||||
return this.addListener(this._api, null, (error, data) => {
|
||||
error
|
||||
? callback(error)
|
||||
: callback(null, data.map(outSignerRequest));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,15 @@ export default class Parity {
|
||||
.execute('parity_addReservedPeer', enode);
|
||||
}
|
||||
|
||||
call (requests, blockNumber = 'latest') {
|
||||
return this._transport
|
||||
.execute(
|
||||
'parity_call',
|
||||
requests.map((options) => inOptions(options)),
|
||||
inBlockNumber(blockNumber)
|
||||
);
|
||||
}
|
||||
|
||||
chainStatus () {
|
||||
return this._transport
|
||||
.execute('parity_chainStatus')
|
||||
|
||||
@@ -24,6 +24,13 @@ export default class Eth {
|
||||
|
||||
this._lastBlock = new BigNumber(-1);
|
||||
this._pollTimerId = null;
|
||||
|
||||
// Try to restart subscription if transport is closed
|
||||
this._api.transport.on('close', () => {
|
||||
if (this.isStarted) {
|
||||
this.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get isStarted () {
|
||||
@@ -33,31 +40,56 @@ export default class Eth {
|
||||
start () {
|
||||
this._started = true;
|
||||
|
||||
return this._blockNumber();
|
||||
if (this._api.isPubSub) {
|
||||
return Promise.all([
|
||||
this._pollBlockNumber(false),
|
||||
this._api.pubsub
|
||||
.subscribeAndGetResult(
|
||||
callback => this._api.pubsub.eth.newHeads(callback),
|
||||
() => {
|
||||
return this._api.eth
|
||||
.blockNumber()
|
||||
.then(blockNumber => {
|
||||
this.updateBlock(blockNumber);
|
||||
return blockNumber;
|
||||
});
|
||||
}
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
// fallback to polling
|
||||
return this._pollBlockNumber(true);
|
||||
}
|
||||
|
||||
_blockNumber = () => {
|
||||
const nextTimeout = (timeout = 1000) => {
|
||||
this._pollTimerId = setTimeout(() => {
|
||||
this._blockNumber();
|
||||
}, timeout);
|
||||
_pollBlockNumber = (doTimeout) => {
|
||||
const nextTimeout = (timeout = 1000, forceTimeout = doTimeout) => {
|
||||
if (forceTimeout) {
|
||||
this._pollTimerId = setTimeout(() => {
|
||||
this._pollBlockNumber(doTimeout);
|
||||
}, timeout);
|
||||
}
|
||||
};
|
||||
|
||||
if (!this._api.transport.isConnected) {
|
||||
nextTimeout(500);
|
||||
nextTimeout(500, true);
|
||||
return;
|
||||
}
|
||||
|
||||
return this._api.eth
|
||||
.blockNumber()
|
||||
.then((blockNumber) => {
|
||||
if (!blockNumber.eq(this._lastBlock)) {
|
||||
this._lastBlock = blockNumber;
|
||||
this._updateSubscriptions('eth_blockNumber', null, blockNumber);
|
||||
}
|
||||
this.updateBlock(blockNumber);
|
||||
|
||||
nextTimeout();
|
||||
})
|
||||
.catch(() => nextTimeout());
|
||||
}
|
||||
|
||||
updateBlock (blockNumber) {
|
||||
if (!blockNumber.eq(this._lastBlock)) {
|
||||
this._lastBlock = blockNumber;
|
||||
this._updateSubscriptions('eth_blockNumber', null, blockNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ function stubApi (blockNumber) {
|
||||
return {
|
||||
_calls,
|
||||
transport: {
|
||||
isConnected: true
|
||||
isConnected: true,
|
||||
on: () => {}
|
||||
},
|
||||
eth: {
|
||||
blockNumber: () => {
|
||||
|
||||
@@ -23,6 +23,13 @@ export default class Personal {
|
||||
|
||||
this._lastDefaultAccount = '0x0';
|
||||
this._pollTimerId = null;
|
||||
|
||||
// Try to restart subscription if transport is closed
|
||||
this._api.transport.on('close', () => {
|
||||
if (this.isStarted) {
|
||||
this.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get isStarted () {
|
||||
@@ -32,20 +39,42 @@ export default class Personal {
|
||||
start () {
|
||||
this._started = true;
|
||||
|
||||
let defaultAccount = null;
|
||||
|
||||
if (this._api.isPubSub) {
|
||||
defaultAccount = this._api.pubsub
|
||||
.subscribeAndGetResult(
|
||||
callback => this._api.pubsub.parity.defaultAccount(callback),
|
||||
(defaultAccount) => {
|
||||
this.updateDefaultAccount(defaultAccount);
|
||||
return defaultAccount;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
defaultAccount = this._defaultAccount();
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
this._defaultAccount(),
|
||||
defaultAccount,
|
||||
this._listAccounts(),
|
||||
this._accountsInfo(),
|
||||
this._loggingSubscribe()
|
||||
]);
|
||||
}
|
||||
|
||||
updateDefaultAccount (defaultAccount) {
|
||||
if (this._lastDefaultAccount !== defaultAccount) {
|
||||
this._lastDefaultAccount = defaultAccount;
|
||||
this._updateSubscriptions('parity_defaultAccount', null, defaultAccount);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Because of the different API instances, the "wait for valid changes" approach
|
||||
// doesn't work. Since the defaultAccount is critical to operation, we poll in exactly
|
||||
// same way we do in ../eth (ala eth_blockNumber) and update. This should be moved
|
||||
// to pub-sub as it becomes available
|
||||
_defaultAccount = (timerDisabled = false) => {
|
||||
const nextTimeout = (timeout = 1000) => {
|
||||
const nextTimeout = (timeout = 3000) => {
|
||||
if (!timerDisabled) {
|
||||
this._pollTimerId = setTimeout(() => {
|
||||
this._defaultAccount();
|
||||
@@ -61,11 +90,7 @@ export default class Personal {
|
||||
return this._api.parity
|
||||
.defaultAccount()
|
||||
.then((defaultAccount) => {
|
||||
if (this._lastDefaultAccount !== defaultAccount) {
|
||||
this._lastDefaultAccount = defaultAccount;
|
||||
this._updateSubscriptions('parity_defaultAccount', null, defaultAccount);
|
||||
}
|
||||
|
||||
this.updateDefaultAccount(defaultAccount);
|
||||
nextTimeout();
|
||||
})
|
||||
.catch(() => nextTimeout());
|
||||
|
||||
@@ -22,6 +22,13 @@ export default class Signer {
|
||||
this._api = api;
|
||||
this._updateSubscriptions = updateSubscriptions;
|
||||
this._started = false;
|
||||
|
||||
// Try to restart subscription if transport is closed
|
||||
this._api.transport.on('close', () => {
|
||||
if (this.isStarted) {
|
||||
this.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get isStarted () {
|
||||
@@ -31,30 +38,50 @@ export default class Signer {
|
||||
start () {
|
||||
this._started = true;
|
||||
|
||||
if (this._api.isPubSub) {
|
||||
const subscription = this._api.pubsub
|
||||
.subscribeAndGetResult(
|
||||
callback => this._api.pubsub.signer.pendingRequests(callback),
|
||||
requests => {
|
||||
this.updateSubscriptions(requests);
|
||||
return requests;
|
||||
}
|
||||
);
|
||||
|
||||
return Promise.all([
|
||||
this._listRequests(false),
|
||||
subscription
|
||||
]);
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
this._listRequests(true),
|
||||
this._loggingSubscribe()
|
||||
]);
|
||||
}
|
||||
|
||||
updateSubscriptions (requests) {
|
||||
return this._updateSubscriptions('signer_requestsToConfirm', null, requests);
|
||||
}
|
||||
|
||||
_listRequests = (doTimeout) => {
|
||||
const nextTimeout = (timeout = 1000) => {
|
||||
if (doTimeout) {
|
||||
const nextTimeout = (timeout = 1000, forceTimeout = doTimeout) => {
|
||||
if (forceTimeout) {
|
||||
setTimeout(() => {
|
||||
this._listRequests(true);
|
||||
this._listRequests(doTimeout);
|
||||
}, timeout);
|
||||
}
|
||||
};
|
||||
|
||||
if (!this._api.transport.isConnected) {
|
||||
nextTimeout(500);
|
||||
nextTimeout(500, true);
|
||||
return;
|
||||
}
|
||||
|
||||
return this._api.signer
|
||||
.requestsToConfirm()
|
||||
.then((requests) => {
|
||||
this._updateSubscriptions('signer_requestsToConfirm', null, requests);
|
||||
this.updateSubscriptions(requests);
|
||||
nextTimeout();
|
||||
})
|
||||
.catch(() => nextTimeout());
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import EventEmitter from 'eventemitter3';
|
||||
|
||||
import { Logging } from '../subscriptions';
|
||||
import logger from './logger';
|
||||
|
||||
const LOGGER_ENABLED = process.env.NODE_ENV !== 'production';
|
||||
|
||||
export default class JsonRpcBase extends EventEmitter {
|
||||
constructor () {
|
||||
@@ -75,6 +79,14 @@ export default class JsonRpcBase extends EventEmitter {
|
||||
}
|
||||
|
||||
execute (method, ...params) {
|
||||
let start;
|
||||
let logId;
|
||||
|
||||
if (LOGGER_ENABLED) {
|
||||
start = Date.now();
|
||||
logId = logger.log({ method, params });
|
||||
}
|
||||
|
||||
return this._middlewareList.then((middlewareList) => {
|
||||
for (const middleware of middlewareList) {
|
||||
const res = middleware.handle(method, params);
|
||||
@@ -93,7 +105,18 @@ export default class JsonRpcBase extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
return this._execute(method, params);
|
||||
const result = this._execute(method, params);
|
||||
|
||||
if (!LOGGER_ENABLED) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result
|
||||
.then((result) => {
|
||||
logger.set(logId, { result, time: Date.now() - start });
|
||||
|
||||
return result;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
150
js/src/api/transport/logger.js
Normal file
150
js/src/api/transport/logger.js
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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.
|
||||
|
||||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import MethodDecodingStore from '~/ui/MethodDecoding/methodDecodingStore';
|
||||
|
||||
const LOGGER_ENABLED = process.env.NODE_ENV !== 'production';
|
||||
|
||||
let logger;
|
||||
|
||||
if (LOGGER_ENABLED) {
|
||||
class Logger {
|
||||
_logs = {};
|
||||
_id = 0;
|
||||
|
||||
log ({ method, params }) {
|
||||
const logId = this._id++;
|
||||
|
||||
this._logs[logId] = { method, params, date: Date.now() };
|
||||
return logId;
|
||||
}
|
||||
|
||||
set (logId, data) {
|
||||
this._logs[logId] = {
|
||||
...this._logs[logId],
|
||||
...data
|
||||
};
|
||||
}
|
||||
|
||||
static sorter (logA, logB) {
|
||||
return logA.date - logB.date;
|
||||
}
|
||||
|
||||
get calls () {
|
||||
const calls = this.methods['eth_call'] || [];
|
||||
const decoding = MethodDecodingStore.get(window.secureApi);
|
||||
const contracts = {};
|
||||
|
||||
const progress = Math.round(calls.length / 20);
|
||||
|
||||
return calls
|
||||
.reduce((promise, call, index) => {
|
||||
const { data, to } = call.params[0];
|
||||
|
||||
contracts[to] = contracts[to] || [];
|
||||
|
||||
return promise
|
||||
.then(() => decoding.lookup(null, { data, to }))
|
||||
.then((lookup) => {
|
||||
if (!lookup.name) {
|
||||
contracts[to].push(data);
|
||||
return;
|
||||
}
|
||||
|
||||
const inputs = lookup.inputs.map((input) => {
|
||||
if (/bytes/.test(input.type)) {
|
||||
return '0x' + input.value.map((v) => v.toString(16).padStart(2, 0)).join('');
|
||||
}
|
||||
|
||||
return input.value;
|
||||
});
|
||||
|
||||
const called = `${lookup.name}(${inputs.join(', ')})`;
|
||||
|
||||
contracts[to].push(called);
|
||||
|
||||
if (index % progress === 0) {
|
||||
console.warn(`progress: ${Math.round(100 * index / calls.length)}%`);
|
||||
}
|
||||
});
|
||||
}, Promise.resolve())
|
||||
.then(() => {
|
||||
return Object.keys(contracts)
|
||||
.map((address) => {
|
||||
const count = contracts[address].length;
|
||||
|
||||
return {
|
||||
count,
|
||||
calls: contracts[address],
|
||||
to: address
|
||||
};
|
||||
})
|
||||
.sort((cA, cB) => cB.count - cA.count);
|
||||
});
|
||||
}
|
||||
|
||||
get logs () {
|
||||
return Object.values(this._logs).sort(Logger.sorter);
|
||||
}
|
||||
|
||||
get methods () {
|
||||
return this.logs.reduce((methods, log) => {
|
||||
methods[log.method] = methods[log.method] || [];
|
||||
methods[log.method].push(log);
|
||||
return methods;
|
||||
}, {});
|
||||
}
|
||||
|
||||
get stats () {
|
||||
const logs = this.logs;
|
||||
const methods = this.methods;
|
||||
|
||||
const start = logs[0].date;
|
||||
const end = logs[logs.length - 1].date;
|
||||
|
||||
// Duration in seconds
|
||||
const duration = (end - start) / 1000;
|
||||
const speed = logs.length / duration;
|
||||
|
||||
const sortedMethods = Object.keys(methods)
|
||||
.map((method) => {
|
||||
const methodLogs = methods[method].sort(Logger.sorter);
|
||||
const methodSpeed = methodLogs.length / duration;
|
||||
|
||||
return {
|
||||
speed: methodSpeed,
|
||||
count: methodLogs.length,
|
||||
logs: methodLogs,
|
||||
method
|
||||
};
|
||||
})
|
||||
.sort((mA, mB) => mB.count - mA.count);
|
||||
|
||||
return {
|
||||
methods: sortedMethods,
|
||||
speed
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
logger = new Logger();
|
||||
|
||||
if (window) {
|
||||
window._logger = logger;
|
||||
}
|
||||
}
|
||||
|
||||
export default logger;
|
||||
@@ -29,7 +29,7 @@ export default class Ws extends JsonRpcBase {
|
||||
this._url = url;
|
||||
this._token = token;
|
||||
this._messages = {};
|
||||
this._subscriptions = { 'eth_subscription': [], 'parity_subscription': [], 'shh_subscription': [] };
|
||||
this._subscriptions = {};
|
||||
this._sessionHash = null;
|
||||
|
||||
this._connecting = false;
|
||||
@@ -209,6 +209,7 @@ export default class Ws extends JsonRpcBase {
|
||||
// initial pubsub ACK
|
||||
if (id && msg.subscription) {
|
||||
// save subscription to map subId -> messageId
|
||||
this._subscriptions[msg.subscription] = this._subscriptions[msg.subscription] || {};
|
||||
this._subscriptions[msg.subscription][res] = id;
|
||||
// resolve promise with messageId because subId's can collide (eth/parity)
|
||||
msg.resolve(id);
|
||||
@@ -223,7 +224,7 @@ export default class Ws extends JsonRpcBase {
|
||||
}
|
||||
|
||||
// pubsub format
|
||||
if (method.includes('subscription')) {
|
||||
if (this._subscriptions[method]) {
|
||||
const messageId = this._messages[this._subscriptions[method][params.subscription]];
|
||||
|
||||
if (messageId) {
|
||||
@@ -302,6 +303,16 @@ export default class Ws extends JsonRpcBase {
|
||||
}
|
||||
|
||||
_methodsFromApi (api) {
|
||||
if (api.subscription) {
|
||||
const { subscribe, unsubscribe, subscription } = api;
|
||||
|
||||
return {
|
||||
method: subscribe,
|
||||
uMethod: unsubscribe,
|
||||
subscription
|
||||
};
|
||||
}
|
||||
|
||||
const method = `${api}_subscribe`;
|
||||
const uMethod = `${api}_unsubscribe`;
|
||||
const subscription = `${api}_subscription`;
|
||||
@@ -309,7 +320,7 @@ export default class Ws extends JsonRpcBase {
|
||||
return { method, uMethod, subscription };
|
||||
}
|
||||
|
||||
subscribe (api, callback, ...params) {
|
||||
subscribe (api, callback, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = this.id;
|
||||
const { method, uMethod, subscription } = this._methodsFromApi(api);
|
||||
|
||||
Reference in New Issue
Block a user