Fix blocks tracking: reset recent blocks array on network change
This commit is contained in:
parent
5a1aff9315
commit
3e148a750c
|
@ -13,6 +13,8 @@ const createLocalhostClient = require('./createLocalhostClient')
|
|||
const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy')
|
||||
const ethNetProps = require('eth-net-props')
|
||||
const parse = require('url-parse')
|
||||
const extend = require('extend')
|
||||
const networks = { networkList: {} }
|
||||
|
||||
const {
|
||||
ROPSTEN,
|
||||
|
@ -41,8 +43,21 @@ const env = process.env.METAMASK_ENV
|
|||
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
|
||||
const testMode = (METAMASK_DEBUG || env === 'test')
|
||||
|
||||
let defaultProviderConfigType
|
||||
if (process.env.IN_TEST === 'true') {
|
||||
defaultProviderConfigType = LOCALHOST
|
||||
} else if (testMode) {
|
||||
defaultProviderConfigType = POA_SOKOL
|
||||
} else {
|
||||
defaultProviderConfigType = POA
|
||||
}
|
||||
|
||||
const defaultProviderConfig = {
|
||||
type: testMode ? POA_SOKOL : POA,
|
||||
type: defaultProviderConfigType,
|
||||
}
|
||||
|
||||
const defaultNetworkConfig = {
|
||||
ticker: 'POA',
|
||||
}
|
||||
|
||||
module.exports = class NetworkController extends EventEmitter {
|
||||
|
@ -55,7 +70,8 @@ module.exports = class NetworkController extends EventEmitter {
|
|||
// create stores
|
||||
this.providerStore = new ObservableStore(providerConfig)
|
||||
this.networkStore = new ObservableStore('loading')
|
||||
this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore })
|
||||
this.networkConfig = new ObservableStore(defaultNetworkConfig)
|
||||
this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore, settings: this.networkConfig })
|
||||
this.on('networkDidChange', this.lookupNetwork)
|
||||
// provider and block tracker
|
||||
this._provider = null
|
||||
|
@ -67,8 +83,8 @@ module.exports = class NetworkController extends EventEmitter {
|
|||
|
||||
initializeProvider (providerParams) {
|
||||
this._baseProviderParams = providerParams
|
||||
const { type, rpcTarget } = this.providerStore.getState()
|
||||
this._configureProvider({ type, rpcTarget })
|
||||
const { type, rpcTarget, chainId, ticker, nickname } = this.providerStore.getState()
|
||||
this._configureProvider({ type, rpcTarget, chainId, ticker, nickname })
|
||||
this.lookupNetwork()
|
||||
}
|
||||
|
||||
|
@ -88,7 +104,20 @@ module.exports = class NetworkController extends EventEmitter {
|
|||
return this.networkStore.getState()
|
||||
}
|
||||
|
||||
setNetworkState (network) {
|
||||
getNetworkConfig () {
|
||||
return this.networkConfig.getState()
|
||||
}
|
||||
|
||||
setNetworkState (network, type) {
|
||||
if (network === 'loading') {
|
||||
return this.networkStore.putState(network)
|
||||
}
|
||||
|
||||
// type must be defined
|
||||
if (!type) {
|
||||
return
|
||||
}
|
||||
network = networks.networkList[type] && networks.networkList[type].chainId ? networks.networkList[type].chainId : network
|
||||
return this.networkStore.putState(network)
|
||||
}
|
||||
|
||||
|
@ -97,33 +126,43 @@ module.exports = class NetworkController extends EventEmitter {
|
|||
}
|
||||
|
||||
lookupNetwork () {
|
||||
const { type, rpcTarget } = this.providerStore.getState()
|
||||
// Prevent firing when provider is not defined.
|
||||
if (!this._provider) {
|
||||
return log.warn('NetworkController - lookupNetwork aborted due to missing provider')
|
||||
}
|
||||
const { type, rpcTarget } = this.providerStore.getState()
|
||||
const ethQuery = new EthQuery(this._provider)
|
||||
const initialNetwork = this.getNetworkState()
|
||||
ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
|
||||
if (err) return this.setNetworkState('loading')
|
||||
const targetHost = parse(rpcTarget, true).host
|
||||
const classicHost = parse(ethNetProps.RPCEndpoints(CLASSIC_CODE)[0], true).host
|
||||
if (type === CLASSIC || targetHost === classicHost) {
|
||||
network = CLASSIC_CODE.toString()
|
||||
} // workaround to avoid Mainnet and Classic are having the same network ID
|
||||
log.info('web3.getNetwork returned ' + network)
|
||||
this.setNetworkState(network)
|
||||
const currentNetwork = this.getNetworkState()
|
||||
if (initialNetwork === currentNetwork) {
|
||||
if (err) {
|
||||
return this.setNetworkState('loading')
|
||||
}
|
||||
log.info('web3.getNetwork returned ' + network)
|
||||
this.setNetworkState(network, type)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setRpcTarget (rpcTarget) {
|
||||
setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '', rpcPrefs) {
|
||||
const providerConfig = {
|
||||
type: 'rpc',
|
||||
rpcTarget,
|
||||
chainId,
|
||||
ticker,
|
||||
nickname,
|
||||
rpcPrefs,
|
||||
}
|
||||
this.providerConfig = providerConfig
|
||||
}
|
||||
|
||||
async setProviderType (type) {
|
||||
async setProviderType (type, rpcTarget = '', ticker = 'ETH', nickname = '') {
|
||||
assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`)
|
||||
assert(INFURA_PROVIDER_TYPES.includes(type) ||
|
||||
type === LOCALHOST ||
|
||||
|
@ -135,7 +174,7 @@ module.exports = class NetworkController extends EventEmitter {
|
|||
type === RSK ||
|
||||
type === RSK_TESTNET
|
||||
, `NetworkController - Unknown rpc type "${type}"`)
|
||||
const providerConfig = { type }
|
||||
const providerConfig = { type, rpcTarget, ticker, nickname }
|
||||
this.providerConfig = providerConfig
|
||||
}
|
||||
|
||||
|
@ -159,35 +198,35 @@ module.exports = class NetworkController extends EventEmitter {
|
|||
_switchNetwork (opts) {
|
||||
this.setNetworkState('loading')
|
||||
this._configureProvider(opts)
|
||||
this.emit('networkDidChange')
|
||||
this.emit('networkDidChange', opts.type)
|
||||
}
|
||||
|
||||
_configureProvider (opts) {
|
||||
const { type, rpcTarget } = opts
|
||||
const { type, rpcTarget, chainId, ticker, nickname } = opts
|
||||
// infura type-based endpoints
|
||||
const isInfura = INFURA_PROVIDER_TYPES.includes(type)
|
||||
if (isInfura) {
|
||||
this._configureInfuraProvider(opts)
|
||||
// other type-based rpc endpoints
|
||||
} else if (type === POA) {
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(POA_CODE)[0] })
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(POA_CODE)[0], chainId, ticker, nickname })
|
||||
} else if (type === DAI) {
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(DAI_CODE)[0] })
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(DAI_CODE)[0], chainId, ticker, nickname })
|
||||
} else if (type === POA_SOKOL) {
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(POA_SOKOL_CODE)[0] })
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(POA_SOKOL_CODE)[0], chainId, ticker, nickname })
|
||||
} else if (type === GOERLI_TESTNET) {
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(GOERLI_TESTNET_CODE)[0] })
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(GOERLI_TESTNET_CODE)[0], chainId, ticker, nickname })
|
||||
} else if (type === CLASSIC) {
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(CLASSIC_CODE)[0] })
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(CLASSIC_CODE)[0], chainId, ticker, nickname })
|
||||
} else if (type === RSK) {
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(RSK_CODE)[0] })
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(RSK_CODE)[0], chainId, ticker, nickname })
|
||||
} else if (type === RSK_TESTNET) {
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(RSK_TESTNET_CODE)[0] })
|
||||
this._configureStandardProvider({ rpcUrl: ethNetProps.RPCEndpoints(RSK_TESTNET_CODE)[0], chainId, ticker, nickname })
|
||||
} else if (type === LOCALHOST) {
|
||||
this._configureLocalhostProvider()
|
||||
// url-based rpc endpoints
|
||||
} else if (type === 'rpc') {
|
||||
this._configureStandardProvider({ rpcUrl: rpcTarget })
|
||||
this._configureStandardProvider({ rpcUrl: rpcTarget, chainId, ticker, nickname })
|
||||
} else {
|
||||
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
|
||||
}
|
||||
|
@ -197,6 +236,11 @@ module.exports = class NetworkController extends EventEmitter {
|
|||
log.info('NetworkController - configureInfuraProvider', type)
|
||||
const networkClient = createInfuraClient({ network: type })
|
||||
this._setNetworkClient(networkClient)
|
||||
// setup networkConfig
|
||||
var settings = {
|
||||
ticker: 'ETH',
|
||||
}
|
||||
this.networkConfig.putState(settings)
|
||||
}
|
||||
|
||||
_configureLocalhostProvider () {
|
||||
|
@ -205,9 +249,22 @@ module.exports = class NetworkController extends EventEmitter {
|
|||
this._setNetworkClient(networkClient)
|
||||
}
|
||||
|
||||
_configureStandardProvider ({ rpcUrl }) {
|
||||
_configureStandardProvider ({ rpcUrl, chainId, ticker, nickname }) {
|
||||
log.info('NetworkController - configureStandardProvider', rpcUrl)
|
||||
const networkClient = createJsonRpcClient({ rpcUrl })
|
||||
// hack to add a 'rpc' network with chainId
|
||||
networks.networkList['rpc'] = {
|
||||
chainId: chainId,
|
||||
rpcUrl,
|
||||
ticker: ticker || 'ETH',
|
||||
nickname,
|
||||
}
|
||||
// setup networkConfig
|
||||
var settings = {
|
||||
network: chainId,
|
||||
}
|
||||
settings = extend(settings, networks.networkList['rpc'])
|
||||
this.networkConfig.putState(settings)
|
||||
this._setNetworkClient(networkClient)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ const extend = require('xtend')
|
|||
const EthQuery = require('eth-query')
|
||||
const log = require('loglevel')
|
||||
const pify = require('pify')
|
||||
const { isKnownProvider, ifRSKByProviderType } = require('../../../old-ui/app/util')
|
||||
|
||||
|
||||
class RecentBlocksController {
|
||||
|
||||
|
@ -24,26 +26,58 @@ class RecentBlocksController {
|
|||
*
|
||||
*/
|
||||
constructor (opts = {}) {
|
||||
const { blockTracker, provider } = opts
|
||||
const { blockTracker, provider, networkController } = opts
|
||||
const { type } = networkController.getProviderConfig()
|
||||
this.blockTracker = blockTracker
|
||||
this.ethQuery = new EthQuery(provider)
|
||||
this.historyLength = opts.historyLength || 40
|
||||
this.setHistoryLength(type, opts)
|
||||
|
||||
const initState = extend({
|
||||
recentBlocks: [],
|
||||
}, opts.initState)
|
||||
this.store = new ObservableStore(initState)
|
||||
|
||||
this.blockTracker.on('latest', async (newBlockNumberHex) => {
|
||||
const blockListner = async (newBlockNumberHex) => {
|
||||
try {
|
||||
await this.processBlock(newBlockNumberHex)
|
||||
} catch (err) {
|
||||
log.error(err)
|
||||
}
|
||||
}
|
||||
let isListening = false
|
||||
|
||||
if (!isKnownProvider(type) && type !== 'loading') {
|
||||
this.blockTracker.on('latest', blockListner)
|
||||
isListening = true
|
||||
}
|
||||
networkController.on('networkDidChange', (newType) => {
|
||||
this.setHistoryLength(newType, opts)
|
||||
this.resetState()
|
||||
this.backfill()
|
||||
if (isKnownProvider(newType) && isListening) {
|
||||
this.blockTracker.removeListener('latest', blockListner)
|
||||
} else if (
|
||||
!isKnownProvider(type) &&
|
||||
type !== 'loading' &&
|
||||
!isListening
|
||||
) {
|
||||
this.blockTracker.on('latest', blockListner)
|
||||
}
|
||||
})
|
||||
this.backfill()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets historyLength param
|
||||
*
|
||||
*/
|
||||
setHistoryLength (type, opts) {
|
||||
if (ifRSKByProviderType(type)) {
|
||||
this.historyLength = 1
|
||||
} else {
|
||||
this.historyLength = opts.historyLength || 40
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets store.recentBlocks to an empty array
|
||||
*
|
||||
|
|
|
@ -130,6 +130,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||
this.recentBlocksController = new RecentBlocksController({
|
||||
blockTracker: this.blockTracker,
|
||||
provider: this.provider,
|
||||
networkController: this.networkController,
|
||||
})
|
||||
|
||||
// account tracker watches balances, nonces, and any code at their address.
|
||||
|
|
|
@ -6,6 +6,18 @@ const {
|
|||
DAI_CODE,
|
||||
RSK_CODE,
|
||||
RSK_TESTNET_CODE,
|
||||
ROPSTEN,
|
||||
RINKEBY,
|
||||
KOVAN,
|
||||
MAINNET,
|
||||
LOCALHOST,
|
||||
POA_SOKOL,
|
||||
POA,
|
||||
DAI,
|
||||
GOERLI_TESTNET,
|
||||
CLASSIC,
|
||||
RSK,
|
||||
RSK_TESTNET,
|
||||
} = require('../../app/scripts/controllers/network/enums')
|
||||
|
||||
var valueTable = {
|
||||
|
@ -54,9 +66,12 @@ module.exports = {
|
|||
ifHardwareAcc,
|
||||
getAllKeyRingsAccounts,
|
||||
ifRSK,
|
||||
ifRSKByProviderType,
|
||||
ifPOA,
|
||||
toChecksumAddress,
|
||||
isValidChecksumAddress,
|
||||
isInfuraProvider,
|
||||
isKnownProvider,
|
||||
}
|
||||
|
||||
function valuesFor (obj) {
|
||||
|
@ -391,6 +406,11 @@ function ifRSK (network) {
|
|||
return numericNet === RSK_CODE || numericNet === RSK_TESTNET_CODE
|
||||
}
|
||||
|
||||
function ifRSKByProviderType (type) {
|
||||
if (!type) return false
|
||||
return type === RSK || type === RSK_TESTNET
|
||||
}
|
||||
|
||||
function ifPOA (network) {
|
||||
if (!network) return false
|
||||
const numericNet = isNaN(network) ? network : parseInt(network)
|
||||
|
@ -424,3 +444,21 @@ function toChecksumAddress (network, address, chainId = null) {
|
|||
function isValidChecksumAddress (network, address) {
|
||||
return isValidAddress(address, network) && toChecksumAddress(network, address) === address
|
||||
}
|
||||
|
||||
function isInfuraProvider (type) {
|
||||
const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET]
|
||||
return INFURA_PROVIDER_TYPES.includes(type)
|
||||
}
|
||||
|
||||
function isKnownProvider (type) {
|
||||
const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET]
|
||||
return INFURA_PROVIDER_TYPES.includes(type) ||
|
||||
type === LOCALHOST ||
|
||||
type === POA_SOKOL ||
|
||||
type === POA ||
|
||||
type === DAI ||
|
||||
type === GOERLI_TESTNET ||
|
||||
type === CLASSIC ||
|
||||
type === RSK ||
|
||||
type === RSK_TESTNET
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ describe('# Network Controller', function () {
|
|||
|
||||
describe('#setNetworkState', function () {
|
||||
it('should update the network', function () {
|
||||
networkController.setNetworkState(1)
|
||||
networkController.setNetworkState(1, 'mainnet')
|
||||
const networkState = networkController.getNetworkState()
|
||||
assert.equal(networkState, 1, 'network is 1')
|
||||
})
|
||||
|
|
|
@ -14,9 +14,12 @@ const {
|
|||
normalizeNumberToWei,
|
||||
isHex,
|
||||
ifRSK,
|
||||
ifRSKByProviderType,
|
||||
ifPOA,
|
||||
toChecksumAddress,
|
||||
isValidChecksumAddress,
|
||||
isInfuraProvider,
|
||||
isKnownProvider,
|
||||
} = require('../../../../old-ui/app/util')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
let ethInWei = '1'
|
||||
|
@ -347,6 +350,18 @@ describe('normalizing values', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('#ifRSKByProviderType', function () {
|
||||
it('checks if this is RSK chain based on provider type', function () {
|
||||
var result1 = ifRSKByProviderType('rsk')
|
||||
assert(result1)
|
||||
var result2 = ifRSKByProviderType('rsk_testnet')
|
||||
assert(result2)
|
||||
var result3 = ifRSKByProviderType('mainnet')
|
||||
assert(!result3)
|
||||
var result4 = ifRSKByProviderType()
|
||||
assert(!result4)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#ifPOA', function () {
|
||||
it('checks if this is POA chain', function () {
|
||||
|
@ -388,4 +403,48 @@ describe('normalizing values', function () {
|
|||
assert(resultNotRSK)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#isInfuraProvider', function () {
|
||||
it('checks, that the given provider is Infura provider', function () {
|
||||
var resultKovan = isInfuraProvider('kovan')
|
||||
assert(resultKovan)
|
||||
var resultRopsten = isInfuraProvider('ropsten')
|
||||
assert(resultRopsten)
|
||||
var resultRinkeby = isInfuraProvider('rinkeby')
|
||||
assert(resultRinkeby)
|
||||
var resultMainnet = isInfuraProvider('mainnet')
|
||||
assert(resultMainnet)
|
||||
var resultGoerli = !isInfuraProvider('goerli_testnet')
|
||||
assert(resultGoerli)
|
||||
var resultSokol = !isInfuraProvider('sokol')
|
||||
assert(resultSokol)
|
||||
var resultClassic = !isInfuraProvider('classic')
|
||||
assert(resultClassic)
|
||||
var resultRSK = !isInfuraProvider('rsk')
|
||||
assert(resultRSK)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#isKnownProvider', function () {
|
||||
it('checks, that the given provider is Infura provider', function () {
|
||||
var resultKovan = isKnownProvider('kovan')
|
||||
assert(resultKovan)
|
||||
var resultRopsten = isKnownProvider('ropsten')
|
||||
assert(resultRopsten)
|
||||
var resultRinkeby = isKnownProvider('rinkeby')
|
||||
assert(resultRinkeby)
|
||||
var resultMainnet = isKnownProvider('mainnet')
|
||||
assert(resultMainnet)
|
||||
var resultGoerli = isKnownProvider('goerli_testnet')
|
||||
assert(resultGoerli)
|
||||
var resultSokol = isKnownProvider('sokol')
|
||||
assert(resultSokol)
|
||||
var resultClassic = isKnownProvider('classic')
|
||||
assert(resultClassic)
|
||||
var resultRSK = isKnownProvider('rsk')
|
||||
assert(resultRSK)
|
||||
var resultUnknown = !isKnownProvider('unknown_network')
|
||||
assert(resultUnknown)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue