通过看其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() // 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, , 'providerA did see "test_rpc"') //首先是先去访问providerA,将test_rpc的访问添加进payloadsWitnessed
t.equal(providerA.getHandled('test_rpc').length, , 'providerA did NOT handle "test_rpc"') //因为它不能处理这个方法,所以payloadsHandled中没有它 t.equal(providerB.getWitnessed('test_rpc').length, , 'providerB did see "test_rpc"')//然后是去访问providerB,将test_rpc的访问添加进payloadsWitnessed
t.equal(providerB.getHandled('test_rpc').length, , 'providerB did handle "test_rpc"')//因为它能处理这个方法,所以payloadsHandled中有它 t.equal(providerC.getWitnessed('test_rpc').length, , 'providerC did NOT see "test_rpc"')//因为providerB上面已经成功处理这个方法了,不会再next(),所以providerC的
t.equal(providerC.getHandled('test_rpc').length, , 'providerC did NOT handle "test_rpc"')//payloadsWitnessed和payloadsHandled都没有它 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 did not error
ok has response
ok providerA did see "test_rpc"
ok providerA did NOT handle "test_rpc"
ok providerB did see "test_rpc"
ok providerB did handle "test_rpc"
ok providerC did NOT see "test_rpc"
ok 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: , jsonrpc: '2.0', params: ['latest', false], method: 'eth_getBlockByNumber'}
const payload2 = {id: , 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: },
{jsonrpc: '2.0', method: 'eth_getCode', params: ['0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b', '0x1234'], id: },
{jsonrpc: '2.0', method: 'eth_getTransactionCount', params: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1','0x1234'], id: },
{jsonrpc: '2.0', method: 'eth_getStorageAt', params: ['0x295a70b2de5e3953354a6a8344e616ed314d7251', '0x0', '0x1234'], id: },
{jsonrpc: '2.0', method: 'eth_call', params: [{to: '0x295a70b2de5e3953354a6a8344e616ed314d7251'}, '0x1234'], id: },
{jsonrpc: '2.0', method: 'eth_estimateGas', params: [{to: '0x295a70b2de5e3953354a6a8344e616ed314d7251'}, '0x1234'], id: },
{jsonrpc: '2.0', method: 'eth_getBlockByNumber', params: ['0x1234', true], id: },
] 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.method:payload.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();
} return payload.params.slice(,index);
} function blockTagParamIndex(payload){
switch(payload.method) {
// blockTag is third param
case 'eth_getStorageAt':
return
// blockTag is second param
case 'eth_getBalance':
case 'eth_getCode':
case 'eth_getTransactionCount':
case 'eth_call':
case 'eth_estimateGas':
return
// blockTag is first param
case 'eth_getBlockByNumber':
return
// 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 cacheIds are unique
# blockTagForPayload for different methods
ok block tag for eth_getBalance is correct
ok block tag for eth_getCode is correct
ok block tag for eth_getTransactionCount is correct
ok block tag for eth_getStorageAt is correct
ok block tag for eth_call is correct
ok block tag for eth_estimateGas is correct
ok 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() // 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[] === '0x00000000000000000000000000000000000000000000000000deadbeefcafe00') {
end(null, null)
} else if (payload.params[] === '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[],
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[].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[].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, , 'cacheProvider did see "'+method+'"')
t.equal(cacheProvider.getHandled(method).length, , 'cacheProvider did NOT handle "'+method+'"')//第一次cache不能够handle这个方法 t.equal(handlingProvider.getWitnessed(method).length, , 'handlingProvider did see "'+method+'"')
t.equal(handlingProvider.getHandled(method).length, , '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, , 'cacheProvider did see "'+method+'"')
t.equal(cacheProvider.getHandled(method).length, , 'cacheProvider did handle "'+method+'"') t.equal(handlingProvider.getWitnessed(method).length, , 'handlingProvider did NOT see "'+method+'"')//这样就不会轮到handlingProvider了
t.equal(handlingProvider.getHandled(method).length, , 'handlingProvider did NOT handle "'+method+'"')
} else {
t.equal(cacheProvider.getWitnessed(method).length, , 'cacheProvider did see "'+method+'"')
t.equal(cacheProvider.getHandled(method).length, , 'cacheProvider did not handle "'+method+'"') t.equal(handlingProvider.getWitnessed(method).length, , 'handlingProvider did NOT see "'+method+'"')
t.equal(handlingProvider.getHandled(method).length, , 'handlingProvider did NOT handle "'+method+'"')
} cb()
})
} function requestTwice(payloads, afterFirst, afterSecond){//就是这个method请求第一次的时候,回调afterFirst函数,请求第二次的时候回调afterSecond
engine.sendAsync(createPayload(payloads[]), function(err, result){
afterFirst(err, result)
engine.sendAsync(createPayload(payloads[]), 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() 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[])
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_getTransactionCount和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') // tx nonce
t.equal(providerB.getWitnessed('eth_getTransactionCount').length, , 'providerB did see "eth_getTransactionCount"')
t.equal(providerB.getHandled('eth_getTransactionCount').length, , 'providerB did NOT handle "eth_getTransactionCount"')//因为nonceProvider只handle类型为pending的
t.equal(providerC.getWitnessed('eth_getTransactionCount').length, , 'providerC did see "eth_getTransactionCount"')
t.equal(providerC.getHandled('eth_getTransactionCount').length, , 'providerC did handle "eth_getTransactionCount"')//所以一直next()到providerC才被执行
// send raw tx
t.equal(providerC.getWitnessed('eth_sendRawTransaction').length, , 'providerC did see "eth_sendRawTransaction"')
t.equal(providerC.getHandled('eth_sendRawTransaction').length, , '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() 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[])
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, , 'providerA did see "signTransaction"')
t.equal(providerA.getHandled('eth_sendTransaction').length, , 'providerA did handle "signTransaction"') // tx nonce
t.equal(providerB.getWitnessed('eth_getTransactionCount').length, , 'providerB did see "eth_getTransactionCount"')
t.equal(providerB.getHandled('eth_getTransactionCount').length, , 'providerB did NOT handle "eth_getTransactionCount"')//不在nonceProvider处handle是因为它只处理pending的
t.equal(providerC.getWitnessed('eth_getTransactionCount').length, , 'providerC did see "eth_getTransactionCount"')
t.equal(providerC.getHandled('eth_getTransactionCount').length, , 'providerC did handle "eth_getTransactionCount"') // gas price
t.equal(providerC.getWitnessed('eth_gasPrice').length, , 'providerB did see "eth_gasPrice"')
t.equal(providerC.getHandled('eth_gasPrice').length, , 'providerB did handle "eth_gasPrice"') // send raw tx
t.equal(providerC.getWitnessed('eth_sendRawTransaction').length, , 'providerC did see "eth_sendRawTransaction"')
t.equal(providerC.getHandled('eth_sendRawTransaction').length, , '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)
//

MetaMask/provider-engine-3-test的更多相关文章

  1. MetaMask/provider-engine-1

    https://github.com/MetaMask/provider-engine 在学习这个之前应该先看一下什么是zero-client,MetaMask/zero-client Web3 Pr ...

  2. MetaMask/metamask-extension-provider

    用来探测你的浏览器中有没有安装metamask插件 https://github.com/MetaMask/metamask-extension-provider MetaMask Extension ...

  3. ethereumjs/ethereumjs-wallet

    Utilities for handling Ethereum keys ethereumjs-wallet A lightweight wallet implementation. At the m ...

  4. trufflesuite/truffle-hdwallet-provider

    https://github.com/trufflesuite/truffle-hdwallet-provider/blob/master/index.js 实现代码 truffle-hdwallet ...

  5. ethereum/EIPs-1102 Opt-in provider access metamask不再默认直接连入网页

    eip title author discussions-to status type category created 1102 Opt-in provider access Paul Boucho ...

  6. ethereum/EIPs-1193 Ethereum Provider JavaScript API 如metamask更新后的接口

    eip title author discussions-to status type category created requires 1193 Ethereum Provider JavaScr ...

  7. MetaMask/metamask-inpage-provider

    https://github.com/MetaMask/metamask-inpage-provider Used to initialize the inpage ethereum provider ...

  8. mascara-2(MetaMask/mascara本地实现)-连接线上钱包

    https://github.com/MetaMask/mascara (beta) Add MetaMask to your dapp even if the user doesn't have t ...

  9. metamask源码学习-metamask-controller.js

    The MetaMask Controller——The central metamask controller. Aggregates other controllers and exports a ...

  10. metamask源码学习-inpage.js

    The most confusing part about porting MetaMask to a new platform is the way we provide the Web3 API ...

随机推荐

  1. [android] 新闻客户端实现左侧导航点击切换

    设置主布局文件,为根布局设置一个id,作为内容区 给ListView的条目设置点击事件,setOnItemClickListener()方法,参数:上下文 当前的Fragment实现OnItemCli ...

  2. 桥接模式(Bridge)

    1.概念 桥接模式将抽象部分与它的实现部分分离,使它们都可以独立地变化,属于结构性模式的一种. 2.模式结构 Abstraction(抽象类):定义抽象接口,拥有一个Implementor类型的对象引 ...

  3. js实现分享到QQ

    js代码 <script src="http://connect.qq.com/widget/loader/loader.js" widget="shareqq&q ...

  4. 【代码笔记】iOS-SDWebImage的使用

    一,工程图. 二,代码. RootViewController.m #import "RootViewController.h" //加入头文件 #import "UII ...

  5. 记录搭建Odoo框架

    一.获取 Odoo 源码 Odoo 是一个开源项目,我们可以轻松的在 Github 上找到它的源码.本次中使用的是 12.0 版本的 Odoo,所以在拉取代码时选择 12.0 的分支.确保拉取的速度, ...

  6. TensorFlow Saver 保存最佳模型 tf.train.Saver Save Best Model

      TensorFlow Saver 保存最佳模型 tf.train.Saver Save Best Model Checkmate is designed to be a simple drop-i ...

  7. Randoop介绍、安装及环境变量配置

    大体来说,开发人员开发源程序,测试人员找bug,中间人产品经理. 黑盒测试:(不看代码) 白盒测试: 1.基于覆盖:语句.分支(if.for.真假).方法 结构:顺序.分支(T or F,做出选择). ...

  8. 安卓基础之Activity的生命周期

    Activity的生命周期 onCreate 在Activity被创建时调用 onDesdroty 在Activity销毁时调用 onRestart 在Activity重新打开时调用 onStart ...

  9. JSP源码、改写Servlet为JSP、查看转译成为Servlet的文件、JSP字符编码设置

    概述 在Servlet中编写HTML太麻烦了,应该使用JSP.JSP中可以直接编写HTML,使用指示.声明.脚本(scriptlet)等元素来堆砌各种功能,但JSP最后还是会被容器转译为Servlet ...

  10. java基础(十一) 枚举类型

    枚举类型Enum的简介 1.什么是枚举类型 枚举类型: 就是由一组具有名的值的有限集合组成新的类型.(即新的类). 好像还是不懂,别急,咱们先来看一下 为什么要引入枚举类型 在没有引入枚举类型前,当我 ...