当前位置 : 主页 > 大数据 > 区块链 >

MetaMask/provider-engine-3-test

来源:互联网 收集:自由互联 发布时间:2021-06-22
通过看其test的代码去好好看看它是怎么使用的 1. provider-engine / test / basic.js const test = require( ‘ tape ‘ ) const ProviderEngine = require( ‘ ../index.js ‘ ) const PassthroughProvider = require( ‘ ./util/pa

通过看其test的代码去好好看看它是怎么使用的

1.

provider-engine/test/basic.js

const test = require(tape)
const ProviderEngine = require(../index.js)
const PassthroughProvider = require(./util/passthrough.js)
const FixtureProvider = require(../subproviders/fixture.js)
const TestBlockProvider = require(./util/block.js)
const createPayload = require(../util/create-payload.js)
const injectMetrics = require(./util/inject-metrics)


test(fallthrough test, function(t){
  t.plan(8)

  // handle nothing
  var providerA = injectMetrics(new PassthroughProvider())
  // handle "test_rpc"
  var providerB = injectMetrics(new FixtureProvider({ //写入了能够处理的方法test_rpc
    test_rpc: true,
  }))
  // handle block requests
  var providerC = injectMetrics(new TestBlockProvider())

  var engine = new ProviderEngine()
  engine.addProvider(providerA)
  engine.addProvider(providerB)
  engine.addProvider(providerC)

  engine.start()
  engine.sendAsync(createPayload({ method: test_rpc }), function(err, response){//当要访问test_rpc时,就会按照subprovider被添加进engine的顺序一个个去查看能不能被处理
    t.ifError(err, did not error) //下面是根据返回的信息去分析处理的过程
    t.ok(response, has response)

    t.equal(providerA.getWitnessed(test_rpc).length, 1, providerA did see "test_rpc") //首先是先去访问providerA,将test_rpc的访问添加进payloadsWitnessed
    t.equal(providerA.getHandled(test_rpc).length, 0, providerA did NOT handle "test_rpc") //因为它不能处理这个方法,所以payloadsHandled中没有它

    t.equal(providerB.getWitnessed(test_rpc).length, 1, providerB did see "test_rpc")//然后是去访问providerB,将test_rpc的访问添加进payloadsWitnessed
    t.equal(providerB.getHandled(test_rpc).length, 1, providerB did handle "test_rpc")//因为它能处理这个方法,所以payloadsHandled中有它

    t.equal(providerC.getWitnessed(test_rpc).length, 0, providerC did NOT see "test_rpc")//因为providerB上面已经成功处理这个方法了,不会再next(),所以providerC的
    t.equal(providerC.getHandled(test_rpc).length, 0, providerC did NOT handle "test_rpc")//payloadsWitnessedpayloadsHandled都没有它

    engine.stop()
    t.end()
  })

})

 

injectMetrics= require(./util/inject-metrics):添加两个记录指标payloadsWitnessed={method:[payload1,payload2,...]}(记录要被运行的method及其不同时候传进来的payload)和payloadsHandled={}(记录已经处理的method及其handle)。并且给了两个获得method的payload数组的方法:getWitnessed(method)和getHandled(method)
PassthroughProvider和TestBlockProvider都是继承了FixtureProvider的

返回结果:

# fallthrough test
ok 1 did not error
ok 2 has response
ok 3 providerA did see "test_rpc"
ok 4 providerA did NOT handle "test_rpc"
ok 5 providerB did see "test_rpc"
ok 6 providerB did handle "test_rpc"
ok 7 providerC did NOT see "test_rpc"
ok 8 providerC did NOT handle "test_rpc"

 

2.

provider-engine/test/cache-utils.js

const test = require(tape)
const cacheUtils = require(../util/rpc-cache-utils)

test(cacheIdentifierForPayload for latest block, function (t) {
  const payload1 = {id: 1, jsonrpc: 2.0, params: [latest, false], method: eth_getBlockByNumber}
  const payload2 = {id: 2, jsonrpc: 2.0, params: [0x0, false], method: eth_getBlockByNumber}
  const cacheId1 = cacheUtils.cacheIdentifierForPayload(payload1, { includeBlockRef: true })//返回eth_getBlockByNumber:[latest‘, false]
  const cacheId2 = cacheUtils.cacheIdentifierForPayload(payload2, { includeBlockRef: true })//返回eth_getBlockByNumber:[0x0‘, false]

  t.notEqual(cacheId1, cacheId2, cacheIds are unique)
  t.end()
})

test(blockTagForPayload for different methods, function (t) {
  const payloads = [
    {jsonrpc: 2.0, method: eth_getBalance, params: [0x407d73d8a49eeb85d32cf465507dd71d507100c1, 0x1234], id: 1},
    {jsonrpc: 2.0, method: eth_getCode, params: [0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b, 0x1234], id: 1},
    {jsonrpc: 2.0, method: eth_getTransactionCount, params: [0x407d73d8a49eeb85d32cf465507dd71d507100c1,0x1234], id: 1},
    {jsonrpc: 2.0, method: eth_getStorageAt, params: [0x295a70b2de5e3953354a6a8344e616ed314d7251, 0x0, 0x1234], id: 1},
    {jsonrpc: 2.0, method: eth_call, params: [{to: 0x295a70b2de5e3953354a6a8344e616ed314d7251}, 0x1234], id: 1},
    {jsonrpc: 2.0, method: eth_estimateGas, params: [{to: 0x295a70b2de5e3953354a6a8344e616ed314d7251}, 0x1234], id: 1},
    {jsonrpc: 2.0, method: eth_getBlockByNumber, params: [0x1234, true], id: 1},
  ]


  payloads.forEach(function (payload) {
    const blockTag = cacheUtils.blockTagForPayload(payload)
    t.isEqual(blockTag, 0x1234, block tag for  + payload.method +  is correct)//上面的payload都能够正确地得到blockTag的值为0x1234
  })

  t.end()
})

provider-engine/util/rpc-cache-utils.js

const stringify = require(json-stable-stringify)

module.exports = {
  cacheIdentifierForPayload: cacheIdentifierForPayload, //6 根据传入的opts.includeBlockRef(params是否需要blockTag参数),来得到payload.params,返回payload.methodpayload.params
  canCache: canCache, //2 分类后类型不为‘never‘的都能够cache
  blockTagForPayload: blockTagForPayload,//5 得到payload.params中的blockTag参数
  paramsWithoutBlockTag: paramsWithoutBlockTag,//4 返回去掉blockTag参数payload.params
  blockTagParamIndex: blockTagParamIndex, //3 得到blockTag参数在payload.params的下标位置
  cacheTypeForPayload: cacheTypeForPayload,//1 根据payload中的method来对需要对其进行cache存储的操作进行分类,有得方法的内容需要永久存储,有的甚至不需存储(never)
}

function cacheIdentifierForPayload(payload, opts = {}){
  if (!canCache(payload)) return null
  const { includeBlockRef } = opts
  const params = includeBlockRef ? payload.params : paramsWithoutBlockTag(payload)
  return payload.method + : + stringify(params)
}

function canCache(payload){
  return cacheTypeForPayload(payload) !== never
}

function blockTagForPayload(payload){
  var index = blockTagParamIndex(payload);

  // Block tag param not passed.
  if (index >= payload.params.length) {
    return null;
  }

  return payload.params[index];
}

function paramsWithoutBlockTag(payload){
  var index = blockTagParamIndex(payload);

  // Block tag param not passed.
  if (index >= payload.params.length) {
    return payload.params;
  }

  // eth_getBlockByNumber has the block tag first, then the optional includeTx? param
  if (payload.method === eth_getBlockByNumber) {
    return payload.params.slice(1);
  }

  return payload.params.slice(0,index);
}

function blockTagParamIndex(payload){
  switch(payload.method) {
    // blockTag is third param
    case eth_getStorageAt:
      return 2
    // blockTag is second param
    case eth_getBalance:
    case eth_getCode:
    case eth_getTransactionCount:
    case eth_call:
    case eth_estimateGas:
      return 1
    // blockTag is first param
    case eth_getBlockByNumber:
      return 0
    // there is no blockTag
    default:
      return undefined
  }
}

function cacheTypeForPayload(payload) {
  switch (payload.method) {
    // cache permanently
    case web3_clientVersion:
    case web3_sha3:
    case eth_protocolVersion:
    case eth_getBlockTransactionCountByHash:
    case eth_getUncleCountByBlockHash:
    case eth_getCode:
    case eth_getBlockByHash:
    case eth_getTransactionByHash:
    case eth_getTransactionByBlockHashAndIndex:
    case eth_getTransactionReceipt:
    case eth_getUncleByBlockHashAndIndex:
    case eth_getCompilers:
    case eth_compileLLL:
    case eth_compileSolidity:
    case eth_compileSerpent:
    case shh_version:
      return perma

    // cache until fork
    case eth_getBlockByNumber:
    case eth_getBlockTransactionCountByNumber:
    case eth_getUncleCountByBlockNumber:
    case eth_getTransactionByBlockNumberAndIndex:
    case eth_getUncleByBlockNumberAndIndex:
      return fork

    // cache for block
    case eth_gasPrice:
    case eth_blockNumber:
    case eth_getBalance:
    case eth_getStorageAt:
    case eth_getTransactionCount:
    case eth_call:
    case eth_estimateGas:
    case eth_getFilterLogs:
    case eth_getLogs:
    case net_peerCount:
      return block

    // never cache
    case net_version:
    case net_peerCount:
    case net_listening:
    case eth_syncing:
    case eth_sign:
    case eth_coinbase:
    case eth_mining:
    case eth_hashrate:
    case eth_accounts:
    case eth_sendTransaction:
    case eth_sendRawTransaction:
    case eth_newFilter:
    case eth_newBlockFilter:
    case eth_newPendingTransactionFilter:
    case eth_uninstallFilter:
    case eth_getFilterChanges:
    case eth_getWork:
    case eth_submitWork:
    case eth_submitHashrate:
    case db_putString:
    case db_getString:
    case db_putHex:
    case db_getHex:
    case shh_post:
    case shh_newIdentity:
    case shh_hasIdentity:
    case shh_newGroup:
    case shh_addToGroup:
    case shh_newFilter:
    case shh_uninstallFilter:
    case shh_getFilterChanges:
    case shh_getMessages:
      return never
  }
}

返回:

# cacheIdentifierForPayload for latest block
ok 9 cacheIds are unique
# blockTagForPayload for different methods
ok 10 block tag for eth_getBalance is correct
ok 11 block tag for eth_getCode is correct
ok 12 block tag for eth_getTransactionCount is correct
ok 13 block tag for eth_getStorageAt is correct
ok 14 block tag for eth_call is correct
ok 15 block tag for eth_estimateGas is correct
ok 16 block tag for eth_getBlockByNumber is correct

 

 

3.

provider-engine/test/cache.js

const test = require(tape)
const ProviderEngine = require(../index.js)
const FixtureProvider = require(../subproviders/fixture.js)
const CacheProvider = require(../subproviders/cache.js)
const TestBlockProvider = require(./util/block.js)
const createPayload = require(../util/create-payload.js)
const injectMetrics = require(./util/inject-metrics)

// skip cache

cacheTest(skipCache - true, {
  method: eth_getBalance,
  skipCache: true,
}, false)

cacheTest(skipCache - false, {
  method: eth_getBalance,
  skipCache: false,
}, true)

// block tags

cacheTest(getBalance + undefined blockTag, {
  method: eth_getBalance,
  params: [0x1234],
}, true)

cacheTest(getBalance + latest blockTag, {
  method: eth_getBalance,
  params: [0x1234, latest],
}, true)

cacheTest(getBalance + pending blockTag, {
  method: eth_getBalance,
  params: [0x1234, pending],
}, false)

// tx by hash

cacheTest(getTransactionByHash for transaction that doesn\‘t exist, {
  method: eth_getTransactionByHash,
  params: [0x00000000000000000000000000000000000000000000000000deadbeefcafe00],
}, false)

cacheTest(getTransactionByHash for transaction that\‘s pending, {
  method: eth_getTransactionByHash,
  params: [0x00000000000000000000000000000000000000000000000000deadbeefcafe01],
}, false)

cacheTest(getTransactionByHash for mined transaction, {
  method: eth_getTransactionByHash,
  params: [0x00000000000000000000000000000000000000000000000000deadbeefcafe02],
}, true)

// code

cacheTest(getCode for latest block, then for earliest block, should not return cached response on second request, [{
  method: eth_getCode,
  params: [0x1234, latest],
}, {
  method: eth_getCode,
  params: [0x1234, earliest],
}], false)

cacheTest(getCode for a specific block, then for the one before it, should not return cached response on second request, [{
  method: eth_getCode,
  params: [0x1234, 0x3],
}, {
  method: eth_getCode,
  params: [0x1234, 0x2],
}], false)

cacheTest(getCode for a specific block, then the one after it, should return cached response on second request, [{
  method: eth_getCode,
  params: [0x1234, 0x2],
}, {
  method: eth_getCode,
  params: [0x1234, 0x3],
}], true)

cacheTest(getCode for an unspecified block, then for the latest, should return cached response on second request, [{
  method: eth_getCode,
  params: [0x1234],
}, {
  method: eth_getCode,
  params: [0x1234, latest],
}], true)

// blocks

cacheTest(getBlockForNumber for latest then block 0, [{
  method: eth_getBlockByNumber,
  params: [latest],
}, {
  method: eth_getBlockByNumber,
  params: [0x0],
}], false)

cacheTest(getBlockForNumber for latest then block 1, [{
  method: eth_getBlockByNumber,
  params: [latest],
}, {
  method: eth_getBlockByNumber,
  params: [0x1],
}], false)

cacheTest(getBlockForNumber for 0 then block 1, [{
  method: eth_getBlockByNumber,
  params: [0x0],
}, {
  method: eth_getBlockByNumber,
  params: [0x1],
}], false)

cacheTest(getBlockForNumber for block 0, [{
  method: eth_getBlockByNumber,
  params: [0x0],
}, {
  method: eth_getBlockByNumber,
  params: [0x0],
}], true)

cacheTest(getBlockForNumber for block 1, [{
  method: eth_getBlockByNumber,
  params: [0x1],
}, {
  method: eth_getBlockByNumber,
  params: [0x1],
}], true)

// storage

cacheTest(getStorageAt for same block should cache, [{
  method: eth_getStorageAt,
  params: [0x295a70b2de5e3953354a6a8344e616ed314d7251, 0x0, 0x1234],
}, {
  method: eth_getStorageAt,
  params: [0x295a70b2de5e3953354a6a8344e616ed314d7251, 0x0, 0x1234],
}], true)

cacheTest(getStorageAt for different block should not cache, [{
  method: eth_getStorageAt,
  params: [0x295a70b2de5e3953354a6a8344e616ed314d7251, 0x0, 0x1234],
}, {
  method: eth_getStorageAt,
  params: [0x295a70b2de5e3953354a6a8344e616ed314d7251, 0x0, 0x4321],
}], false)


// test helper for caching
// 1. Sets up caching and data provider
// 2. Performs first request
// 3. Performs second request
// 4. checks if cache hit or missed

function cacheTest(label, payloads, shouldHitCacheOnSecondRequest){//就是如果连着两次访问就触发cacheProvider进行存储该method
  if (!Array.isArray(payloads)) {
    payloads = [payloads, payloads]//为了连着两次请求该payloads
  }

  test(cache - +label, function(t){
    t.plan(12)

    // cache layer
    var cacheProvider = injectMetrics(new CacheProvider())
    // handle balance
    var dataProvider = injectMetrics(new FixtureProvider({
      eth_getBalance: 0xdeadbeef,
      eth_getCode: 6060604052600560005560408060156000396000f3606060405260e060020a60003504633fa4f245811460245780635524107714602c575b005b603660005481565b6004356000556022565b6060908152602090f3,
      eth_getTransactionByHash: function(payload, next, end) {
        // represents a pending tx
        if (payload.params[0] === 0x00000000000000000000000000000000000000000000000000deadbeefcafe00) {
          end(null, null)
        } else if (payload.params[0] === 0x00000000000000000000000000000000000000000000000000deadbeefcafe01) {
          end(null, {
            hash: 0x00000000000000000000000000000000000000000000000000deadbeefcafe01,
            nonce: 0xd,
            blockHash: null,
            blockNumber: null,
            transactionIndex: null,
            from: 0xb1cc05ab12928297911695b55ee78c1188f8ef91,
            to: 0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98,
            value: 0xddb66b2addf4800,
            gas: 0x5622,
            gasPrice: 0xba43b7400,
            input: 0x,
          })
        } else {
          end(null, {
            hash: payload.params[0],
            nonce: 0xd,
            blockHash: 0x1,
            blockNumber: 0x1,
            transactionIndex: 0x0,
            from: 0xb1cc05ab12928297911695b55ee78c1188f8ef91,
            to: 0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98,
            value: 0xddb66b2addf4800,
            gas: 0x5622,
            gasPrice: 0xba43b7400,
            input: 0x,
          })
        }
      },
      eth_getStorageAt: 0x00000000000000000000000000000000000000000000000000000000deadbeef,
    }))
    // handle dummy block
    var blockProvider = injectMetrics(new TestBlockProvider())

    var engine = new ProviderEngine()
    engine.addProvider(cacheProvider)
    engine.addProvider(dataProvider)
    engine.addProvider(blockProvider)

    // run polling until first block
    engine.start()
    engine.once(block, () => {//监听到第一个block生成时进入
      // stop polling
      engine.stop()//然后停止拉取block
      // clear subprovider metrics ,然后清空所有subprovider的payloadWitnessed和payloadHandled
      cacheProvider.clearMetrics()
      dataProvider.clearMetrics()
      blockProvider.clearMetrics()

      // determine which provider will handle the request,决定处理该payload的是哪一个subprovider
      const isBlockTest = (payloads[0].method === eth_getBlockByNumber)
      const handlingProvider = isBlockTest ? blockProvider : dataProvider

      // begin cache test
      cacheCheck(t, engine, cacheProvider, handlingProvider, payloads, function(err, response) {
        t.end()
      })
    })

    function cacheCheck(t, engine, cacheProvider, handlingProvider, payloads, cb) {
      var method = payloads[0].method
      requestTwice(payloads, function(err, response){
        // first request
        t.ifError(err || response.error && response.error.message, did not error)
        t.ok(response, has response)

        t.equal(cacheProvider.getWitnessed(method).length, 1, cacheProvider did see "+method+")
        t.equal(cacheProvider.getHandled(method).length, 0, cacheProvider did NOT handle "+method+")//第一次cache不能够handle这个方法

        t.equal(handlingProvider.getWitnessed(method).length, 1, handlingProvider did see "+method+")
        t.equal(handlingProvider.getHandled(method).length, 1, handlingProvider did handle "+method+")

      }, function(err, response){
        // second request
        t.ifError(err || response.error && response.error.message, did not error)
        t.ok(response, has response)

        if (shouldHitCacheOnSecondRequest) {//如果设置shouldHitCacheOnSecondRequest为true,则之前第一次的时候就会写入cache,这样第二次的时候就能够从cache处运行
          t.equal(cacheProvider.getWitnessed(method).length, 2, cacheProvider did see "+method+")
          t.equal(cacheProvider.getHandled(method).length, 1, cacheProvider did handle "+method+")

          t.equal(handlingProvider.getWitnessed(method).length, 1, handlingProvider did NOT see "+method+")//这样就不会轮到handlingProvider了
          t.equal(handlingProvider.getHandled(method).length, 1, handlingProvider did NOT handle "+method+")
        } else {
          t.equal(cacheProvider.getWitnessed(method).length, 2, cacheProvider did see "+method+")
          t.equal(cacheProvider.getHandled(method).length, 0, cacheProvider did not handle "+method+")

          t.equal(handlingProvider.getWitnessed(method).length, 2, handlingProvider did NOT see "+method+")
          t.equal(handlingProvider.getHandled(method).length, 2, handlingProvider did NOT handle "+method+")
        }

        cb()
      })
    }

    function requestTwice(payloads, afterFirst, afterSecond){//就是这个method请求第一次的时候,回调afterFirst函数,请求第二次的时候回调afterSecond
      engine.sendAsync(createPayload(payloads[0]), function(err, result){
        afterFirst(err, result)
        engine.sendAsync(createPayload(payloads[1]), afterSecond)
      })
    }

  })

}

 

 

4.

provider-engine/subproviders/filters.js

module.exports = FilterSubprovider

// handles the following RPC methods:
//   eth_newBlockFilter
//   eth_newPendingTransactionFilter
//   eth_newFilter
//   eth_getFilterChanges
//   eth_uninstallFilter
//   eth_getFilterLogs

 

5.

provider-engine/subproviders/nonce-tracker.js

// handles the following RPC methods:
//   eth_getTransactionCount (pending only)
// observes the following RPC methods:
//   eth_sendRawTransaction

 

provider-engine/test/nonce.js

const test = require(tape)
const Transaction = require(ethereumjs-tx)
const ethUtil = require(ethereumjs-util)
const ProviderEngine = require(../index.js)
const FixtureProvider = require(../subproviders/fixture.js)
const NonceTracker = require(../subproviders/nonce-tracker.js)
const HookedWalletProvider = require(../subproviders/hooked-wallet.js)
const TestBlockProvider = require(./util/block.js)
const createPayload = require(../util/create-payload.js)
const injectMetrics = require(./util/inject-metrics)


test(basic nonce tracking, function(t){
  t.plan(11)

  var privateKey = new Buffer(cccd8f4d88de61f92f3747e4a9604a0395e6ad5138add4bec4a2ddf231ee24f9, hex)
  var address = new Buffer(1234362ef32bcd26d3dd18ca749378213625ba0b, hex)
  var addressHex = 0x+address.toString(hex)
  
  // sign all tx‘s
  var providerA = injectMetrics(new HookedWalletProvider({
    signTransaction: function(txParams, cb){
      var tx = new Transaction(txParams)
      tx.sign(privateKey)
      var rawTx = 0x+tx.serialize().toString(hex)
      cb(null, rawTx)
    },
  }))

  // handle nonce requests
  var providerB = injectMetrics(new NonceTracker())
  // handle all bottom requests
  var providerC = injectMetrics(new FixtureProvider({
    eth_gasPrice: 0x1234,
    eth_getTransactionCount: 0x00,
    eth_sendRawTransaction: function(payload, next, done){
      var rawTx = ethUtil.toBuffer(payload.params[0])
      var tx = new Transaction(rawTx)
      var hash = 0x+tx.hash().toString(hex)
      done(null, hash)
    },
  }))
  // handle block requests
  var providerD = injectMetrics(new TestBlockProvider())

  var engine = new ProviderEngine()
  engine.addProvider(providerA)
  engine.addProvider(providerB)
  engine.addProvider(providerC)
  engine.addProvider(providerD)

  var txPayload = {
    method: eth_sendTransaction,//需要调用eth_getTransactionCounteth_sendRawTransaction
    params: [{
      from: addressHex,
      to: addressHex,
      value: 0x01,
      gas: 0x1234567890,
    }]
  }

  engine.start()
  engine.sendAsync(createPayload(txPayload), function(err, response){
    t.ifError(err, did not error)
    t.ok(response, has response)

    // tx nonce
    t.equal(providerB.getWitnessed(eth_getTransactionCount).length, 1, providerB did see "eth_getTransactionCount")
    t.equal(providerB.getHandled(eth_getTransactionCount).length, 0, providerB did NOT handle "eth_getTransactionCount")//因为nonceProvider只handle类型为pending的
    t.equal(providerC.getWitnessed(eth_getTransactionCount).length, 1, providerC did see "eth_getTransactionCount")
    t.equal(providerC.getHandled(eth_getTransactionCount).length, 1, providerC did handle "eth_getTransactionCount")//所以一直next()到providerC才被执行
    // send raw tx
    t.equal(providerC.getWitnessed(eth_sendRawTransaction).length, 1, providerC did see "eth_sendRawTransaction")
    t.equal(providerC.getHandled(eth_sendRawTransaction).length, 1, providerC did handle "eth_sendRawTransaction")

    engine.sendAsync(createPayload({
      method: eth_getTransactionCount,
      params: [addressHex, pending],
    }), function(err, response){
      t.ifError(err, did not error)
      t.ok(response, has response)

      // tx nonce did increment
      t.equal(response.result, 0x01, the provider gives the correct pending nonce)

      engine.stop()
      t.end()

    })

  })

})

 

 

6.

provider-engine/subproviders/subscriptions.js

相当于web3的subscribe

 

7.

provider-engine/test/wallet.js

const test = require(tape)
const Transaction = require(ethereumjs-tx)
const ethUtil = require(ethereumjs-util)
const ProviderEngine = require(../index.js)
const FixtureProvider = require(../subproviders/fixture.js)
const NonceTracker = require(../subproviders/nonce-tracker.js)
const HookedWalletProvider = require(../subproviders/hooked-wallet.js)
const HookedWalletTxProvider = require(../subproviders/hooked-wallet-ethtx.js)
const TestBlockProvider = require(./util/block.js)
const createPayload = require(../util/create-payload.js)
const injectMetrics = require(./util/inject-metrics)


test(tx sig, function(t){
  t.plan(12)

  var privateKey = new Buffer(cccd8f4d88de61f92f3747e4a9604a0395e6ad5138add4bec4a2ddf231ee24f9, hex)
  var address = new Buffer(1234362ef32bcd26d3dd18ca749378213625ba0b, hex)
  var addressHex = 0x+address.toString(hex)

  // sign all tx‘s
  var providerA = injectMetrics(new HookedWalletProvider({
    getAccounts: function(cb){
      cb(null, [addressHex])
    },
    signTransaction: function(txParams, cb){
      var tx = new Transaction(txParams)
      tx.sign(privateKey)
      var rawTx = 0x+tx.serialize().toString(hex)
      cb(null, rawTx)
    },
  }))

  // handle nonce requests
  var providerB = injectMetrics(new NonceTracker())
  // handle all bottom requests
  var providerC = injectMetrics(new FixtureProvider({
    eth_gasPrice: 0x1234,
    eth_getTransactionCount: 0x00,
    eth_sendRawTransaction: function(payload, next, done){
      var rawTx = ethUtil.toBuffer(payload.params[0])
      var tx = new Transaction(rawTx)
      var hash = 0x+tx.hash().toString(hex)
      done(null, hash)
    },
  }))
  // handle block requests
  var providerD = injectMetrics(new TestBlockProvider())

  var engine = new ProviderEngine()
  engine.addProvider(providerA)
  engine.addProvider(providerB)
  engine.addProvider(providerC)
  engine.addProvider(providerD)

  var txPayload = {
    method: eth_sendTransaction,//会调用signTransaction/eth_getTransactionCount/eth_gasPrice/eth_sendRawTransaction
    params: [{
      from: addressHex,
      to: addressHex,
      value: 0x01,
      gas: 0x1234567890,
    }]
  }

  engine.start()
  engine.sendAsync(createPayload(txPayload), function(err, response){
    t.ifError(err, did not error)
    t.ok(response, has response)

    // intial tx request
    t.equal(providerA.getWitnessed(eth_sendTransaction).length, 1, providerA did see "signTransaction")
    t.equal(providerA.getHandled(eth_sendTransaction).length, 1, providerA did handle "signTransaction")

    // tx nonce
    t.equal(providerB.getWitnessed(eth_getTransactionCount).length, 1, providerB did see "eth_getTransactionCount")
    t.equal(providerB.getHandled(eth_getTransactionCount).length, 0, providerB did NOT handle "eth_getTransactionCount")//不在nonceProvider处handle是因为它只处理pending的
    t.equal(providerC.getWitnessed(eth_getTransactionCount).length, 1, providerC did see "eth_getTransactionCount")
    t.equal(providerC.getHandled(eth_getTransactionCount).length, 1, providerC did handle "eth_getTransactionCount")

    // gas price
    t.equal(providerC.getWitnessed(eth_gasPrice).length, 1, providerB did see "eth_gasPrice")
    t.equal(providerC.getHandled(eth_gasPrice).length, 1, providerB did handle "eth_gasPrice")

    // send raw tx
    t.equal(providerC.getWitnessed(eth_sendRawTransaction).length, 1, providerC did see "eth_sendRawTransaction")
    t.equal(providerC.getHandled(eth_sendRawTransaction).length, 1, providerC did handle "eth_sendRawTransaction")

    engine.stop()
    t.end()
  })

})

 

provider-engine/subproviders/hooked-wallet.js

// handles the following RPC methods:
//   eth_coinbase
//   eth_accounts
//   eth_sendTransaction
//   eth_sign
//   eth_signTypedData
//   personal_sign
//   personal_ecRecover
//   parity_postTransaction
//   parity_checkRequest
//   parity_defaultAccount

//
// Tx Signature Flow,交易签名需要做的事情
//
// handleRequest: eth_sendTransaction
//   validateTransaction (basic validity check)
//     validateSender (checks that sender is in accounts)
//   processTransaction (sign tx and submit to network)
//     approveTransaction (UI approval hook)
//     checkApproval
//     finalizeAndSubmitTx (tx signing)
//       nonceLock.take (bottle neck to ensure atomic nonce)
//         fillInTxExtras (set fallback gasPrice, nonce, etc)
//         signTransaction (perform the signature)
//         publishTransaction (publish signed tx to network)
//
网友评论