• MetaMask/eth-block-tracker


    https://github.com/MetaMask/eth-block-tracker

    A JS module for keeping track of the latest Ethereum block by polling an ethereum provider.

    通过拉取以太坊的provider来跟踪最新的以太坊区块

    eth-block-tracker

    This module walks the Ethereum blockchain, keeping track of the latest block. It uses a web3 provider as a data source and will continuously poll for the next block.

    这个模块沿着以太坊区块链去跟踪最新的区块。它使用web3 provider作为其数据源,并不停地从最新的区块中拉取数据

    const HttpProvider = require('ethjs-provider-http')
    const PollingBlockTracker = require('eth-block-tracker')
    
    const provider = new HttpProvider('https://mainnet.infura.io')//设置provider
    const blockTracker = new PollingBlockTracker({ provider })
    blockTracker.on('latest', console.log)
     

    methods

    new PollingBlockTracker({ provider, pollingInterval, retryTimeout, keepEventLoopActive })

    creates a new block tracker with provider as a data source and pollingInterval (ms) timeout between polling for the latest block. If an Error is encountered when fetching blocks, it will wait retryTimeout (ms) before attempting again. If keepEventLoopActive is false, in Node.js it will unref the polling timeout, allowing the process to exit during the polling interval. defaults to true, meaning the process will be kept alive.

    创建了一个指定provider数据源的区块追踪器,并在pollingInterval的间隔时间内拉取最新区块。当获取区块的时候如果出现了错误,那么她就会等待retryTimeout (ms)再重新获取。如果keepEventLoopActive是false,在nodejs中它会取消轮询超时,即在拉取的间隔中允许进程退出。默认是true,意味着进程始终保持活跃

    getCurrentBlock()

    synchronous returns the current block. may be null.

    同步等到当前的区块

    console.log(blockTracker.getCurrentBlock())
    async getLatestBlock()

    Asynchronously returns the latest block. if not immediately available, it will fetch one.

    异步得到最新区块

    async checkForLatestBlock()

    Tells the block tracker to ask for a new block immediately, in addition to its normal polling interval. Useful if you received a hint of a new block (e.g. via tx.blockNumber from getTransactionByHash). Will resolve to the new latest block when its done polling.

    要求区块追踪器马上去取新的区块,除非现在正处于正常的polling间隔。如果你收到了新的区块的暗示时这个功能就十分有用(via tx.blockNumber from getTransactionByHash)。当其拉取完后,将释放最新的区块

    EVENTS

    latest

    The latest event is emitted for whenever a new latest block is detected. This may mean skipping blocks if there were two created since the last polling period.

    blockTracker.on('latest', (newBlock) => console.log(newBlock))

    当新的区块被检测到时,这个事件就会被触发。如果在上一个拉取周期中生成了两个区块,那么将会跳过,不会触发事件

    sync

    The sync event is emitted the same as "latest" but includes the previous block.

    blockTracker.on('sync', ({ newBlock, oldBlock }) => console.log(newBlock, oldBlock))

    它跟"latest"是相同的,不同在与它还返回了之前的一个区块

    error

    The error event means an error occurred while polling for the latest block.

    blockTracker.on('error', (err) => console.error(err))

    当拉取最新的区块的时候出现错误时触发

    代码:

    eth-block-tracker/package.json

      "main": "src/polling.js",
      "scripts": {
        "test": "npm run build && node test/index.js",
        "prepublish": "npm run build",
        "build": "mkdir -p ./dist && npm run bundle",
        "bundle": "babel src -d dist/es5/ && npm run bundle-polling && npm run bundle-base",
        "bundle-polling": "browserify -s PollingBlockTracker -e src/polling.js -t [ babelify --presets [ es2015 ] ] > dist/PollingBlockTracker.js",
        "bundle-base": "browserify -s BaseBlockTracker -e src/base.js -t [ babelify --presets [ es2015 ] ] > dist/BaseBlockTracker.js"
      },

    eth-block-tracker/example.js

    const createInfuraProvider = require('eth-json-rpc-infura/src/createProvider')
    const PollingBlockTracker = require('./src/polling')
    
    
    const provider = createInfuraProvider({ network: 'mainnet' })//使用infura的mainnet网生成provider
    const blockTracker = new PollingBlockTracker({ provider }) //生成blockTracker
    
    blockTracker.on('sync', ({ newBlock, oldBlock }) => {//监听sync事件
      if (oldBlock) {
        console.log(`sync #${Number(oldBlock)} -> #${Number(newBlock)}`)
      } else {
        console.log(`first sync #${Number(newBlock)}`)
      }
    })

    eth-block-tracker/src/polling.js

    const EthQuery = require('eth-query')
    const EventEmitter = require('events')
    const pify = require('pify')
    const BaseBlockTracker = require('./base')
    
    const sec = 1000
    const min = 60 * sec
    
    class PollingBlockTracker extends BaseBlockTracker {//1 继承自BaseBlockTracker
    
      constructor(opts = {}) {
        // parse + validate args
        if (!opts.provider) throw new Error('PollingBlockTracker - no provider specified.')//2 必须要传入provider
        const pollingInterval = opts.pollingInterval || 20 * sec //3 设置poll间隔时间
        const retryTimeout = opts.retryTimeout || pollingInterval / 10 //4 设置出错后的重试时间
        const keepEventLoopActive = opts.keepEventLoopActive !== undefined ? opts.keepEventLoopActive : true //5进程是否保持活跃
        // BaseBlockTracker constructor
        super(Object.assign({//6 将opts复制到前一个参数数组中,并作为BaseBlockTracker参数传给其构造函数
          blockResetDuration: pollingInterval,
        }, opts))
        // config,配置相应的信息
        this._provider = opts.provider 
        this._pollingInterval = pollingInterval
        this._retryTimeout = retryTimeout
        this._keepEventLoopActive = keepEventLoopActive
        // util
        this._query = new EthQuery(this._provider)
      }
    
      //
      // public
      //
      //公有函数
      // trigger block polling
      async checkForLatestBlock() {
        await this._updateLatestBlock()
        return await this.getLatestBlock() //调用BaseBlockTracker的函数getLatestBlock
      }
    
      //
      // private
      //
     //下面为私有函数
      _start() {
        this._performSync().catch(err => this.emit('error', err))
      }
    
      async _performSync () {
        while (this._isRunning) {
          try {
            await this._updateLatestBlock()
            await timeout(this._pollingInterval, !this._keepEventLoopActive)
          } catch (err) {
            const newErr = new Error(`PollingBlockTracker - encountered an error while attempting to update latest block:
    ${err.stack}`)
            try {
              this.emit('error', newErr)
            } catch (emitErr) {
              console.error(newErr)
            }
            await timeout(this._retryTimeout, !this._keepEventLoopActive)
          }
        }
      }
    
      async _updateLatestBlock () {
        // fetch + set latest block
        const latestBlock = await this._fetchLatestBlock()
        this._newPotentialLatest(latestBlock)
      }
    
      async _fetchLatestBlock () {
        return await pify(this._query.blockNumber).call(this._query)
      }
    
    }
    
    module.exports = PollingBlockTracker
    
    function timeout (duration, unref) {
      return new Promise(resolve => {
        const timoutRef = setTimeout(resolve, duration)
        // don't keep process open
        if (timoutRef.unref && unref) {
          timoutRef.unref()
        }
      })
    }

    eth-block-tracker/src/base.js

    const EthQuery = require('eth-query')
    const pify = require('pify')
    const SafeEventEmitter = require('safe-event-emitter')
    
    const sec = 1000
    
    const calculateSum = (accumulator, currentValue) => accumulator + currentValue
    const blockTrackerEvents = ['sync', 'latest']
    
    class BaseBlockTracker extends SafeEventEmitter {
    
      //
      // public
      //
    
      constructor(opts = {}) {//6
        super()
        // config
        this._blockResetDuration = opts.blockResetDuration || 20 * sec //拉取的间隔时间
        // state
        this._blockResetTimeout
        this._currentBlock = null
        this._isRunning = false
        // bind functions for internal use
        this._onNewListener = this._onNewListener.bind(this)
        this._onRemoveListener = this._onRemoveListener.bind(this)
        this._resetCurrentBlock = this._resetCurrentBlock.bind(this)
        // listen for handler changes
        this._setupInternalEvents()
      }
    
      isRunning() {
        return this._isRunning
      }
    
      getCurrentBlock () {
        return this._currentBlock
      }
    
      async getLatestBlock () {
        // return if available
        if (this._currentBlock) return this._currentBlock
        // wait for a new latest block
        const latestBlock = await new Promise(resolve => this.once('latest', resolve))
        // return newly set current block
        return latestBlock
      }
    
      // dont allow module consumer to remove our internal event listeners
      removeAllListeners(eventName) {
        // perform default behavior, preserve fn arity
        if (eventName) {
          super.removeAllListeners(eventName)
        } else {
          super.removeAllListeners()
        }
        // re-add internal events
        this._setupInternalEvents()
        // trigger stop check just in case
        this._onRemoveListener()
      }
    
      //
      // to be implemented in subclass
      //
    
      _start () {
        // default behavior is noop
      }
    
      _end () {
        // default behavior is noop
      }
    
      //
      // private
      //
    
      _setupInternalEvents () {
        // first remove listeners for idempotence
        this.removeListener('newListener', this._onNewListener)
        this.removeListener('removeListener', this._onRemoveListener)
        // then add them
        this.on('newListener', this._onNewListener)
        this.on('removeListener', this._onRemoveListener)
      }
    
      _onNewListener (eventName, handler) {
        // `newListener` is called *before* the listener is added
        if (!blockTrackerEvents.includes(eventName)) return
        this._maybeStart()
      }
    
      _onRemoveListener (eventName, handler) {
        // `removeListener` is called *after* the listener is removed
        if (this._getBlockTrackerEventCount() > 0) return
        this._maybeEnd()
      }
    
      _maybeStart () {
        if (this._isRunning) return
        this._isRunning = true
        // cancel setting latest block to stale
        this._cancelBlockResetTimeout()
        this._start()
      }
    
      _maybeEnd () {
        if (!this._isRunning) return
        this._isRunning = false
        this._setupBlockResetTimeout()
        this._end()
      }
    
      _getBlockTrackerEventCount () {
        return blockTrackerEvents
          .map(eventName => this.listenerCount(eventName))
          .reduce(calculateSum)
      }
    
      _newPotentialLatest (newBlock) {
        const currentBlock = this._currentBlock
        // only update if blok number is higher
        if (currentBlock && (hexToInt(newBlock) <= hexToInt(currentBlock))) return
        this._setCurrentBlock(newBlock)
      }
    
      _setCurrentBlock (newBlock) {
        const oldBlock = this._currentBlock
        this._currentBlock = newBlock
        this.emit('latest', newBlock)
        this.emit('sync', { oldBlock, newBlock })
      }
    
      _setupBlockResetTimeout() {
        // clear any existing timeout
        this._cancelBlockResetTimeout()
        // clear latest block when stale
        this._blockResetTimeout = setTimeout(this._resetCurrentBlock, this._blockResetDuration)
        // nodejs - dont hold process open
        if (this._blockResetTimeout.unref) {
          this._blockResetTimeout.unref()
        }
      }
    
      _cancelBlockResetTimeout() {
        clearTimeout(this._blockResetTimeout)
      }
    
      _resetCurrentBlock  () {
        this._currentBlock = null
      }
    
    }
    
    module.exports = BaseBlockTracker
    
    function hexToInt(hexInt) {
      return Number.parseInt(hexInt, 16)
    }
     
  • 相关阅读:
    Linux vi/vim
    Linux 磁盘管理
    Linux 用户和用户组管理
    Linux 文件与目录管理
    Linux 文件基本属性
    Linux 远程登录
    Linux 忘记密码解决方法
    Linux 系统目录结构
    Linux 系统启动过程
    linux -- su和sudo命令的区别
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/9956546.html
Copyright © 2020-2023  润新知