Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multinet phase01 #7149

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions app/scripts/controllers/network/createInfuraClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ const BlockTracker = require('eth-block-tracker')
module.exports = createInfuraClient

function createInfuraClient ({ network, onRequest }) {
const net = network.split(':')[1]
const infuraMiddleware = mergeMiddleware([
createRequestHookMiddleware(onRequest),
createInfuraMiddleware({ network, maxAttempts: 5, source: 'metamask' }),
createInfuraMiddleware({ net, maxAttempts: 5, source: 'metamask' }),
])
const infuraProvider = providerFromMiddleware(infuraMiddleware)
const blockTracker = new BlockTracker({ provider: infuraProvider })
Expand All @@ -36,23 +37,23 @@ function createNetworkAndChainIdMiddleware ({ network }) {
let netId

switch (network) {
case 'mainnet':
case 'infura#eth:mainnet':
netId = '1'
chainId = '0x01'
break
case 'ropsten':
case 'infura#eth:ropsten':
netId = '3'
chainId = '0x03'
break
case 'rinkeby':
case 'infura#eth:rinkeby':
netId = '4'
chainId = '0x04'
break
case 'kovan':
case 'infura#eth:kovan':
netId = '42'
chainId = '0x2a'
break
case 'goerli':
case 'infura#eth:goerli':
netId = '5'
chainId = '0x05'
break
Expand Down
63 changes: 57 additions & 6 deletions app/scripts/controllers/network/enums.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,79 @@
const ROPSTEN = 'ropsten'
const RINKEBY = 'rinkeby'
const KOVAN = 'kovan'
const MAINNET = 'mainnet'
const LOCALHOST = 'localhost'
const GOERLI = 'goerli'
// types
// provider#protocall:network-name/transport
const ROPSTEN = 'infura#eth:ropsten'
const RINKEBY = 'infura#eth:rinkeby'
const KOVAN = 'infura#eth:kovan'
const MAINNET = 'infura#eth:mainnet'
const LOCALHOST = 'default#eth:localhost'
const GOERLI = 'infura#eth:goerli'
const CUSTOM_RPC = 'custom#eth:rpc'

// chain id
const MAINNET_CODE = 1
const ROPSTEN_CODE = 3
const RINKEBY_CODE = 4
const KOVAN_CODE = 42
const GOERLI_CODE = 5

// default names
const ROPSTEN_DISPLAY_NAME = 'Ropsten'
const RINKEBY_DISPLAY_NAME = 'Rinkeby'
const KOVAN_DISPLAY_NAME = 'Kovan'
const MAINNET_DISPLAY_NAME = 'Main Ethereum Network'
const GOERLI_DISPLAY_NAME = 'Goerli'

const DEFAULT_LIST = [
{
type: ROPSTEN,
custom: {
chainId: ROPSTEN_CODE,
ticker: 'ETH',
},
},
{
type: RINKEBY,
custom: {
chainId: RINKEBY_CODE,
ticker: 'ETH',
},
},
{
type: KOVAN,
custom: {
chainId: KOVAN_CODE,
ticker: 'ETH',
},
},
{
type: MAINNET,
custom: {
chainId: MAINNET_CODE,
ticker: 'ETH',
},
},
{
type: LOCALHOST,
custom: {
ticker: 'ETH',
},
},
{
type: GOERLI,
custom: {
ticker: 'ETH',
chainId: GOERLI_CODE,
},
},
]

module.exports = {
ROPSTEN,
RINKEBY,
KOVAN,
MAINNET,
LOCALHOST,
GOERLI,
CUSTOM_RPC,
MAINNET_CODE,
ROPSTEN_CODE,
RINKEBY_CODE,
Expand All @@ -34,4 +84,5 @@ module.exports = {
KOVAN_DISPLAY_NAME,
MAINNET_DISPLAY_NAME,
GOERLI_DISPLAY_NAME,
DEFAULT_LIST,
}
252 changes: 250 additions & 2 deletions app/scripts/controllers/network/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,250 @@
const NetworkController = require('./network')
module.exports = NetworkController
const EventEmitter = require('events')
const ObservableStore = require('obs-store')
const Network = require('./network')
const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy')
const { isInfura } = require('./util')

const env = process.env.METAMASK_ENV
const METAMASK_DEBUG = process.env.METAMASK_DEBUG

const enums = require('./enums')

let defaultProviderConfigType
if (process.env.IN_TEST === 'true') {
defaultProviderConfigType = enums.LOCALHOST
} else if (METAMASK_DEBUG || env === 'test') {
defaultProviderConfigType = enums.RINKEBY
} else {
defaultProviderConfigType = enums.MAINNET
}

const defaultNetwork = defaultProviderConfigType

module.exports = class NetworkController extends EventEmitter {
constructor (opts = {}) {
super()
const {
networkConfigs = enums.DEFAULT_LIST,
selectedNetworkConfig = enums.DEFAULT_LIST.find((net) => net.type === defaultNetwork),
} = opts
this.store = new ObservableStore({
networkConfigs,
selectedNetworkConfig,
provider: selectedNetworkConfig,
})

this.networkStore = new ObservableStore('loading')
this.providerStore = new ObservableStore(selectedNetworkConfig)
this.networkStore.subscribe((netId) => {
if (netId === 'loading') return
try {
this.providerStore.putState(this.selectedNetworkConfig)
this.providerStore.updateState({ provider: this.selectedNetworkConfig })
} catch (e) {
// what do i do here when log.error can blow up?
}
})


this.networkConfigs = networkConfigs
this.selectedNetworkConfig = selectedNetworkConfig

// provider and block tracker
this._provider = null
this._blockTracker = null
// provider and block tracker proxies - because the network changes
this._providerProxy = createSwappableProxy({})
const nullBlockTracker = new EventEmitter()
nullBlockTracker.getCurrentBlock = () => null
nullBlockTracker.getLatestBlock = () => null
this._blockTrackerProxy = createEventEmitterProxy(nullBlockTracker, { eventFilter: 'skipInternal' })

}

getNetworkConfig () {
return this.selectedNetworkConfig
}

lookupNetwork () {
return this.selectedNetwork.networkStore.getState()
}

isNetworkLoading () {
if (this.selectedNetwork) return this.selectedNetwork.networkStore.getState() === 'loading'
else return true
}

initializeProvider (baseOpts) {
if (this._initialized) return
this._baseOpts = baseOpts
this.networks = this.networkConfigs.reduce((networks, config) => {
const key = config.type === enums.CUSTOM_RPC ? config.rpcUrl : config.type
const opts = {
baseOpts,
rpcUrl: config.rpcUrl,
type: config.type,
chainId: config.custom.chainId,
}

if (isInfura(key)) {
if (key === this.selectedNetworkConfig.type) opts.initialize = true
const network = config.type.split(':')[1]
opts.onRequest = (req) => this.emit('rpc-req', { network, req })
} else {
if (key === this.selectedNetworkConfig.rpcUrl) opts.initialize = true
}


// note to future self fix this


networks[key] = new Network(opts)
if (opts.initialize) {
networks[key].ready.then(({ provider, blockTracker, chainId }) => {
this._setProviderAndBlockTracker({ provider, blockTracker })
this.setNetworkState(chainId)
})
this.selectedNetwork = networks[key]
}
return networks
}, {})
this._initialized = true
}

// return the selected network config

getProviderConfig () {
return this.selectedNetworkConfig
}

// return the proxies so the references will always be good
getProviderAndBlockTracker () {
const provider = this._providerProxy
const blockTracker = this._blockTrackerProxy
return { provider, blockTracker }
}

addNetwork (opts) {
const config = {
type: enums.CUSTOM_RPC,
...opts,
custom: {ticker: 'ETH', ...opts.custom},
}

this.networkConfigs.push(config)
this.networks[config.rpcUrl] = new Network({
rpcUrl: config.rpcUrl,
type: config.type,
chainId: config.custom.chainId,
baseOpts: this._baseOpts,
})
}

removeNetwork (url) {
// remove from config list
this.networkConfigs = this.networkConfig.reduce((list, config) => {
if (config.rpcUrl !== url) list.push(config)
return list
}, [])
this.networks[url].stop()
// stop and remove from network list
delete this.networks[url]
}

setProviderType (type) {
this.setNetworkState('loading')
const network = this.networks[type]
if (!network) throw new Error('NetworkController - network does not exist')
const { provider, blockTracker } = network
if (!network.initialized) {
network.initializeProvider(this._baseOpts)
network.ready.then(({provider, blockTracker}) => {
this._setProviderAndBlockTracker({ provider, blockTracker })
})
} else {
this._setProviderAndBlockTracker({ provider, blockTracker })
}
this.setNetworkState(network.getNetworkState())
this.selectedNetwork = network
this.selectedNetworkConfig = network.providerConfig
this.store.updateState({settings: network.providerConfig})
}

setNetworkState (netId) {
this.store.updateState({network: netId})
return this.networkStore.putState(netId)
}

getNetworkState () {
return this.networkStore.getState()
}


async setNetwork ({rpcUrl, type}) {
const network = this.networks[rpcUrl || type] || {}
const { provider, blockTracker } = network
if (!network.initialized) {
network.initializeProvider(this._baseOpts)
network.ready.then(({provider, blockTracker}) => {
this._setProviderAndBlockTracker({ provider, blockTracker })
})
} else {
this._setProviderAndBlockTracker({ provider, blockTracker })
}
this.selectedNetwork = network
this.selectedNetworkConfig = network.providerConfig
this.store.updateState({provider: network.providerConfig})
}


/**
* updates custom RPC details
*
* @param {string} url The RPC url to add to frequentRpcList.
* @param {number} chainId Optional chainId of the selected network.
* @param {string} ticker Optional ticker symbol of the selected network.
* @param {string} nickname Optional nickname of the selected network.
* @returns {Promise<array>} Promise resolving to updated frequentRpcList.
*
*/

async updateRpc (newRpcConfig) {
const index = this.networkConfigs.findIndex((config) => {
return config.rpcUrl === newRpcConfig.rpcUrl
})
if (index > -1) {
const config = this.networkConfigs[index]
this.networkConfigs[index] = {
...config,
...newRpcConfig,
custom: {
...config.custom,
...newRpcConfig.custom,
},
}

this.store.updateState({ networkConfigs: this.networkConfigs })
} else {
this.addNetwork(newRpcConfig)
}

return this.networkConfigs
}

resetConnection () {
this.selectedNetworkConfig = this.getProviderConfig()
}
//
// Private
//

_setProviderAndBlockTracker ({ provider, blockTracker }) {
// update or intialize proxies
this._providerProxy.setTarget(provider)
this._blockTrackerProxy.setTarget(blockTracker)
// set new provider and blockTracker
this._provider = provider
this._blockTracker = blockTracker
}

}
Loading