metamask源码学习-controllers-network
https://github.com/MetaMask/metamask-extension/tree/master/app/scripts/controllers/network
metamask-extension/app/scripts/controllers/network/network.js
const assert = require('assert') const EventEmitter = require('events') const createMetamaskProvider = require('web3-provider-engine/zero.js') const SubproviderFromProvider = require('web3-provider-engine/subproviders/provider.js') const createInfuraProvider = require('eth-json-rpc-infura/src/createProvider') const ObservableStore = require('obs-store')//ObservableStore是一个内存中的同步存储,只存储一个值,用于订阅更新。详细看https://github.com/MetaMask/obs-store const ComposedStore = require('obs-store/lib/composed') const extend = require('xtend') const EthQuery = require('eth-query') const createEventEmitterProxy = require('../../lib/events-proxy.js') const log = require('loglevel') const urlUtil = require('url') const {//这就是我们在metamask中看见的五种网络 ROPSTEN, RINKEBY, KOVAN, MAINNET, LOCALHOST, } = require('./enums') const LOCALHOST_RPC_URL = 'http://localhost:8545' //本地网络设置的host:port信息 const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] //infura支持的网络的类型有这四种 const env = process.env.METAMASK_ENV //process是nodejs中的一个全局变量,metamask-extension/package.json进行METAMASK_ENV设置,设置为test const METAMASK_DEBUG = process.env.METAMASK_DEBUG //如果之前没有设置则为false,这是在调用网页的时候进行设置的window.METAMASK_DEBUG = true const testMode = (METAMASK_DEBUG || env === 'test') //如果满足其中之一则说明使用的是测试模式 const defaultProviderConfig = { type: testMode ? RINKEBY : MAINNET,//如果是测试模式,则自动设置为RINKEBY,否则为MAINNET } module.exports = class NetworkController extends EventEmitter { constructor (opts = {}) {//如果没有opts传入,则默认为{} super() // parse options const providerConfig = opts.provider || defaultProviderConfig // create stores this.providerStore = new ObservableStore(providerConfig)//即上面的provider,到底是default的RINKEBY或MAINNET还是用户自己传进来的provider this.networkStore = new ObservableStore('loading') //network处于加载状态 this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore }) //即将两个store组合起来 // create event emitter proxy this._proxy = createEventEmitterProxy() this.on('networkDidChange', this.lookupNetwork) } initializeProvider (_providerParams) { //初始化provider this._baseProviderParams = _providerParams const { type, rpcTarget } = this.providerStore.getState() //得到此时provider的状态,type即ROPSTEN, RINKEBY, KOVAN, MAINNET四种之一,rpcTarget即连接的网络信息 this._configureProvider({ type, rpcTarget }) //配置provider,rpcTarget即比如http://localhost:8545 this._proxy.on('block', this._logBlock.bind(this)) this._proxy.on('error', this.verifyNetwork.bind(this)) this.ethQuery = new EthQuery(this._proxy) this.lookupNetwork() return this._proxy } verifyNetwork () { // Check network when restoring connectivity: if (this.isNetworkLoading()) this.lookupNetwork() } getNetworkState () { return this.networkStore.getState() } setNetworkState (network) { return this.networkStore.putState(network) } isNetworkLoading () { return this.getNetworkState() === 'loading' } lookupNetwork () { // Prevent firing when provider is not defined. if (!this.ethQuery || !this.ethQuery.sendAsync) { return log.warn('NetworkController - lookupNetwork aborted due to missing ethQuery') } this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { if (err) return this.setNetworkState('loading') log.info('web3.getNetwork returned ' + network) this.setNetworkState(network) }) } setRpcTarget (rpcTarget) { const providerConfig = { type: 'rpc', rpcTarget, } this.providerConfig = providerConfig } async setProviderType (type) { assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`) assert(INFURA_PROVIDER_TYPES.includes(type) || type === LOCALHOST, `NetworkController - Unknown rpc type "${type}"`) const providerConfig = { type } this.providerConfig = providerConfig } resetConnection () { this.providerConfig = this.getProviderConfig() } set providerConfig (providerConfig) { this.providerStore.updateState(providerConfig) this._switchNetwork(providerConfig) } getProviderConfig () { return this.providerStore.getState() } // // Private // _switchNetwork (opts) { this.setNetworkState('loading') this._configureProvider(opts) this.emit('networkDidChange') } _configureProvider (opts) { const { type, rpcTarget } = opts // infura type-based endpoints const isInfura = INFURA_PROVIDER_TYPES.includes(type)//type即infura中支持的那四种网络的类型ROPSTEN, RINKEBY, KOVAN, MAINNET,metamask的这四种网络的provider都是使用了infura if (isInfura) {//是就调用infura配置this._configureInfuraProvider(opts) // other type-based rpc endpoints } else if (type === LOCALHOST) {//否则就查看它是否使用了本地的8545接口,如ganache this._configureStandardProvider({ rpcUrl: LOCALHOST_RPC_URL }) // url-based rpc endpoints } else if (type === 'rpc') {//或者是自己设置的其他区块链接口 this._configureStandardProvider({ rpcUrl: rpcTarget }) } else { throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)//没有连接到这样的接口时报错 } } _configureInfuraProvider ({ type }) { log.info('_configureInfuraProvider', type) const infuraProvider = createInfuraProvider({ network: type }) const infuraSubprovider = new SubproviderFromProvider(infuraProvider) const providerParams = extend(this._baseProviderParams, { engineParams: { pollingInterval: 8000, blockTrackerProvider: infuraProvider, }, dataSubprovider: infuraSubprovider, }) const provider = createMetamaskProvider(providerParams) this._setProvider(provider) } _configureStandardProvider ({ rpcUrl }) { // urlUtil handles malformed urls rpcUrl = urlUtil.parse(rpcUrl).format() const providerParams = extend(this._baseProviderParams, { rpcUrl, engineParams: { pollingInterval: 8000, }, }) const provider = createMetamaskProvider(providerParams) this._setProvider(provider) } _setProvider (provider) { // collect old block tracker events const oldProvider = this._provider let blockTrackerHandlers if (oldProvider) { // capture old block handlers blockTrackerHandlers = oldProvider._blockTracker.proxyEventHandlers // tear down oldProvider.removeAllListeners() oldProvider.stop() } // override block tracler provider._blockTracker = createEventEmitterProxy(provider._blockTracker, blockTrackerHandlers) // set as new provider this._provider = provider this._proxy.setTarget(provider) } _logBlock (block) { log.info(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`) this.verifyNetwork() } }
metamask-extension/app/scripts/controllers/network/enums.js
有关网络的配置信息
const ROPSTEN = 'ropsten' const RINKEBY = 'rinkeby' const KOVAN = 'kovan' const MAINNET = 'mainnet' const LOCALHOST = 'localhost'
//各个网络的networkId值 const MAINNET_CODE = 1 const ROPSTEN_CODE = 3 const RINKEYBY_CODE = 4 const KOVAN_CODE = 42
//各个网络在metamask上的显示名字 const ROPSTEN_DISPLAY_NAME = 'Ropsten' const RINKEBY_DISPLAY_NAME = 'Rinkeby' const KOVAN_DISPLAY_NAME = 'Kovan' const MAINNET_DISPLAY_NAME = 'Main Ethereum Network' module.exports = { ROPSTEN, RINKEBY, KOVAN, MAINNET, LOCALHOST, MAINNET_CODE, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, ROPSTEN_DISPLAY_NAME, RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, }