zoukankan      html  css  js  c++  java
  • 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, }
  • 相关阅读:
    boost lexical_cast 字符串数字间的字面转换(学习笔记)
    Smoke Testing
    深入浅出InfoPath——手工绑定托管代码
    深入浅出InfoPath——操作InfoPath元素
    深入浅出SharePoint2010——附录:常用术语对照
    CAML语法必备
    深入浅出SharePoint ——2010 新特性之搜索
    BVT测试
    Windows 7的71个运行命令列表
    深入浅出InfoPath——如何在项目中引用GAC中的dll文件
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/9720062.html
Copyright © 2011-2022 走看看