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的RINKEBYMAINNET还是用户自己传进来的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的状态,typeROPSTEN, 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, }

 

posted @ 2018-09-29 16:44  慢行厚积  阅读(1035)  评论(0编辑  收藏  举报