MetaMask/provider-engine-3-test
通过看其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的更多相关文章
- MetaMask/provider-engine-1
https://github.com/MetaMask/provider-engine 在学习这个之前应该先看一下什么是zero-client,MetaMask/zero-client Web3 Pr ...
- MetaMask/metamask-extension-provider
用来探测你的浏览器中有没有安装metamask插件 https://github.com/MetaMask/metamask-extension-provider MetaMask Extension ...
- ethereumjs/ethereumjs-wallet
Utilities for handling Ethereum keys ethereumjs-wallet A lightweight wallet implementation. At the m ...
- trufflesuite/truffle-hdwallet-provider
https://github.com/trufflesuite/truffle-hdwallet-provider/blob/master/index.js 实现代码 truffle-hdwallet ...
- ethereum/EIPs-1102 Opt-in provider access metamask不再默认直接连入网页
eip title author discussions-to status type category created 1102 Opt-in provider access Paul Boucho ...
- ethereum/EIPs-1193 Ethereum Provider JavaScript API 如metamask更新后的接口
eip title author discussions-to status type category created requires 1193 Ethereum Provider JavaScr ...
- MetaMask/metamask-inpage-provider
https://github.com/MetaMask/metamask-inpage-provider Used to initialize the inpage ethereum provider ...
- mascara-2(MetaMask/mascara本地实现)-连接线上钱包
https://github.com/MetaMask/mascara (beta) Add MetaMask to your dapp even if the user doesn't have t ...
- metamask源码学习-metamask-controller.js
The MetaMask Controller——The central metamask controller. Aggregates other controllers and exports a ...
- metamask源码学习-inpage.js
The most confusing part about porting MetaMask to a new platform is the way we provide the Web3 API ...
随机推荐
- Linux下的SVN服务器搭建(转)
Linux下的SVN服务器搭建 鉴于在搭建时,参考网上很多资料,网上资料在有用的同时,也坑了很多人 本文的目的,也就是想让后继之人在搭建svn服务器时不再犯错,不再被网上漫天的坑爹作品所坑害,故此 ...
- 深入理解Java虚拟机--阅读笔记一
Java内存区域 一.java运行时数据区域 1. 程序计数器:程序计数器占据的内存空间较小,是当前运行线程执行的字节码的计数:分支.循环.跳转.异常处理.线程恢复等都要依赖技术器来对执行的字节码进行 ...
- POJ3468(KB7-C 线段树)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 108903 ...
- centos7下快速安装Nginx服务器
1.添加源 默认情况Centos7中无Nginx的源,最近发现Nginx官网提供了Centos的源地址.因此可以如下执行命令添加源: sudo rpm -Uvh http://nginx.org/pa ...
- css-文字和图片在容器内垂直居中的简单方法
方法一.使用line-heigh使多行文字居中或图片居中 把文字包裹在一个inline-block元素中vertical-align middle,外部元素line-heigh等于高度 <div ...
- java 性能优化 字符串过滤实战
转自[http://www.apkbus.com/blog-822717-78335.html] 如有不妥联系删除!! ★一个简单的需求 首先描述一下需求:给定一个 String 对象,过滤掉除了数 ...
- Android解析WindowManager(一)WindowManager体系
前言 WindowManagerService(WMS)和AMS一样,都是Android开发需要掌握的知识点,同样的,WMS也很复杂,需要多篇文章来进行讲解,为何更好的理解WMS,首先要了解Windo ...
- Android Studio动态调试smali代码
工具: Android Studio版本: 3.0.1 smalidea插件: https://github.com/JesusFreke/smali/wiki/smalidea. 反编译工具:本节先 ...
- Android逆向 APK文件组成
一 了解APK文件 我们知道Android系统能运行的程序是.apk文件格式,其实它就是一个压缩包而已,把.apk修改成.zip,然后解压就可以得到该apk内部的文件结构. PS: 既然可以把apk文 ...
- InfoPath读取数据库
public void LoadBtn_Clicked(object sender, ClickedEventArgs e) { // 配置连接字符串 using (SqlConnection con ...