https://github.com/ethereumjs/ethereumjs-blockchain/tree/master/test

'use strict'

const test = require('tape')
const Blockchain = require('..')
const Block = require('ethereumjs-block')
const Common = require('ethereumjs-common')
const async = require('async')
const ethUtil = require('ethereumjs-util')
const level = require('level-mem')
const testData = require('./testdata.json')
const BN = require('bn.js')
const rlp = ethUtil.rlp test('blockchain test', function (t) {
t.plan()
var blockchain = new Blockchain()//还没有区块头
var genesisBlock
var blocks = []
var forkHeader
blockchain.validate = false //不进行区块验证
async.series([ function (done) {
blockchain.getHead(function (err, head) {//返回指定迭代区块头,这里没有设置name,则name = 'vm'
if (err) return done(err)
t.ok(true, 'should not crash on getting head of a blockchain without a genesis') //因为这个区块链还没有区块头,所以是得不到区块头信息的
done()
})
},
function initialization (done) {
const common = new Common('ropsten')
t.throws(function () { new Blockchain({ chain: 'ropsten', common: common }) }, /not allowed!$/, 'should throw on initialization with chain and common parameter') // eslint-disable-line const bc0 = new Blockchain({ chain: 'ropsten' }) //两条链是相同的,所以得到的区块头是相同的
const bc1 = new Blockchain({ common: common })
async.parallel([
(cb) => bc0.getHead(cb),
(cb) => bc1.getHead(cb)
], (err, heads) => {
if (err) return done(err)
t.equals(heads[].hash().toString('hex'), common.genesis().hash.slice(), 'correct genesis hash')
t.equals(heads[].hash().toString('hex'), heads[].hash().toString('hex'), 'genesis blocks match')
done()
})
},
function alternateConstructors (done) {
var db = level()
var blockchain = new Blockchain(db)
t.equals(db, blockchain.db, 'support constructor with db parameter')
blockchain = new Blockchain({detailsDb: db, blockDb: db})//弃用的参数,detailsDb会被忽略
t.equals(db, blockchain.db, 'support blockDb and detailsDb params')
t.notOk(blockchain.detailsDb, 'ignore detailsDb param')
done()
},
function addgenesis (done) {
genesisBlock = new Block()
genesisBlock.setGenesisParams() //设置初始区块
blockchain.putGenesis(genesisBlock, function (err) {//将该初始区块添加到区块链上
if (err) return done(err)
t.equals(genesisBlock.hash().toString('hex'), blockchain.meta.genesis.toString('hex'), 'genesis block hash should be correct')
blocks.push(genesisBlock)
done()
})
},
function invalidGenesis (done) {
var badBlock = new Block() //该区块其实不是初始区块,但是我通过将其badBlock.header.number更改成空数组buffer来假装初始区块
badBlock.header.number = Buffer.from([])
blockchain.validate = true //进行区块验证
blockchain.putBlock(badBlock, function (err) { //然后将这个区块添加进区块链中
t.ok(err, 'should not validate a block incorrectly flagged as genesis') //会失败,因为区块验证过程中会发现它不是初始区块
blockchain.validate = false
done()
}, false)
},
function addBlocks (done) { //即从blockNumber = 1添加到blockNumber = 10结束
function addNextBlock (blockNumber) {
var block = new Block()
block.header.number = ethUtil.toBuffer(blockNumber)
block.header.difficulty = '0xfffffff'
block.header.parentHash = blocks[blockNumber - ].hash()
blockchain.putBlock(block, function (err) {
if (err) return done(err) blocks.push(block) if (blocks.length === ) {
t.ok(true, 'added 10 blocks')
done()
} else {
addNextBlock(blockNumber + )
}
})
}
addNextBlock()
},
function getBlockByNumber (done) { //通过blocknumber得到block
blockchain.getBlock(, function (err, block) {
if (err) return done(err)
t.equals(block.hash().toString('hex'), blocks[].hash().toString('hex'), 'should get block by number')
done()
})
},
function getBlockByHash (done) {//通过blockhash得到block
blockchain.getBlock(genesisBlock.hash(), function (err, block) {
if (err) return done(err)
t.equals(block.hash().toString('hex'), genesisBlock.hash().toString('hex'), 'should get block by hash')
done()
})
},
function getBlocks1 (done) {
// start: genesisHash, max: 5, skip: 0, reverse: false,正向从初始区块开始获取最多5个区块,跳过第一个区块(即初始区块)
blockchain.getBlocks(genesisBlock.hash(), , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 5 blocks')
t.ok(isConsecutive(blocks), 'blocks should be consecutive')//是连续的区块
done()
})
},
function getBlocks2 (done) {
// start: genesisHash, max: 5, skip: 1, reverse: false
blockchain.getBlocks(genesisBlock.hash(), , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 5 blocks')
t.ok(!isConsecutive(blocks), 'blocks should not be consecutive') //因为跳过了第二个区块,所以得到的区块就不连续了
done()
})
},
function getBlocks3 (done) {
// start: genesisHash, max: 5, skip: 2, reverse: false
blockchain.getBlocks(genesisBlock.hash(), , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 4 blocks')
t.ok(!isConsecutive(blocks), 'blocks should not be consecutive')
done()
})
},
function getBlocks4 (done) {
// start: genesisHash, max: 12, skip: 0, reverse: false
blockchain.getBlocks(genesisBlock.hash(), , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 10 blocks')
t.ok(isConsecutive(blocks), 'blocks should be consecutive')
done()
})
},
function getBlocks5 (done) {
// start: 0, max: 5, skip: 0, reverse: false
blockchain.getBlocks(, , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 5 blocks')
t.ok(isConsecutive(blocks), 'blocks should be consecutive')
done()
})
},
function getBlocks6 (done) {
// start: 0, max: 5, skip: 1, reverse: false
blockchain.getBlocks(, , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 5 blocks')
t.ok(!isConsecutive(blocks), 'blocks should not be consecutive')
done()
})
},
function getBlocks7 (done) {
// start: 0, max: 5, skip: 2, reverse: false
blockchain.getBlocks(, , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 4 blocks')
t.ok(!isConsecutive(blocks), 'blocks should not be consecutive')
done()
})
},
function getBlocks8 (done) {
// start: 0, max: 12, skip: 0, reverse: false
blockchain.getBlocks(, , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 10 blocks')
t.ok(isConsecutive(blocks), 'blocks should be consecutive')
done()
})
},
function getBlocks9 (done) {
// start: 1, max: 5, skip: 0, reverse: false
blockchain.getBlocks(, , , false, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 5 blocks')
t.ok(isConsecutive(blocks), 'blocks should be consecutive')
done()
})
},
function getBlocks10 (done) {
// start: 5, max: 5, skip: 0, reverse: true ,从第六个区块开始反向获取最多5个区块,跳过第一个区块
blockchain.getBlocks(, , , true, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 5 blocks')
t.ok(isConsecutive(blocks.reverse()), 'blocks should be consecutive')
done()
})
},
function getBlocks11 (done) {
// start: 5, max: 10, skip: 0, reverse: true
blockchain.getBlocks(, , , true, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 6 blocks')
t.ok(isConsecutive(blocks.reverse()), 'blocks should be consecutive')
done()
})
},
function getBlocks12 (done) {
// start: 5, max: 10, skip: 0, reverse: true
blockchain.getBlocks(, , , true, function (err, blocks) {
if (err) return done(err)
t.equals(blocks.length, , 'should get 3 blocks')
t.ok(!isConsecutive(blocks.reverse()), 'blocks should not be consecutive')
done()
})
},
function selectNeededHashes (done) {
var neededHash = Buffer.from('abcdef', 'hex')
blockchain.selectNeededHashes([//即这三个hash值表示的区块只有neededHash不在区块链上,所以最后得到的数组结果中有的是是neededHash这个hash,表示需要的区块
blocks[].hash(),
blocks[].hash(),
neededHash
], (err, hashes) => {
if (err) return done(err)
t.equals(hashes[].toString('hex'), neededHash.toString('hex'), 'should find needed hash')
done()
})
},
function iterateBlocks (done) {//迭代从blocknumber = 0 到 9这十个之前加到区块链上的区块,他们的区块hash是相同的,所以符合迭代的if条件,直至i=9才结束
var i =
blockchain.iterator('test', function (block, reorg, cb) {
if (block.hash().equals(blocks[i + ].hash())) i++
cb()
}, function () {
t.equals(i, , 'should iterate through 9 blocks')
done()
})
},
function iterateError (done) {
blockchain.iterator('error', function (block, reorg, cb) {//就是一开始迭代就返回错误
cb(new Error('iterator func error'))
}, function (err) { //然后就会触发回调函数,err则为上面返回的错误
t.ok(err, 'should catch iterator func error')
t.equal(err.message, 'iterator func error', 'should return correct error')
done()
})
},
function iterateEmpty (done) {
var blockchain = new Blockchain()
blockchain.validate = false //不验证区块
blockchain.iterator('test', function () { //这个没有返回错误就结束了
t.ok(false, 'should not call iterator function')
done()
}, function (err) {//所以回调函数的err为null
t.error(err, 'should not return error')
t.ok(true, 'should finish iterating')
done()
})
},
function getMeta (done) { //得到区块链的元数据的方法
t.equals(blockchain.meta.rawHead.toString('hex'), blocks[].hash().toString('hex'), 'should get meta.rawHead')
t.equals(blockchain.meta.genesis.toString('hex'), genesisBlock.hash().toString('hex'), 'should get meta.genesis')
t.ok(blockchain.meta.heads['test'], 'should get meta.heads')
done()
},
function addForkHeaderAndResetStaleHeads (done) {
forkHeader = new Block.Header()
forkHeader.number = ethUtil.toBuffer()//新得到的区块索引是9
forkHeader.difficulty = '0xffffffff'
forkHeader.parentHash = blocks[].hash()
blockchain._heads['staletest'] = blockchain._headHeader
blockchain.putHeader(forkHeader, function (err) {//添加区块头,这里的回调中没有返回保存的header!!!!,即(err,header)后面测试header其值为
// [ undefined,
// undefined,
// [ undefined, undefined ],
// undefined,
// [ undefined, undefined ],
// undefined ]
t.equals(blockchain._heads['staletest'].toString('hex'), blocks[].hash().toString('hex'), 'should update stale head')//blockchain._heads['staletest']是旧的blockchain._headHeader的值,等于blocks[8].hash().toString('hex')
t.equals(blockchain._headBlock.toString('hex'), blocks[].hash().toString('hex'), 'should update stale headBlock')//因为只添加了区块头,没有添加区块,所以现在的blockchain._headBlock.toString('hex')等于blocks[8].hash().toString('hex')
// t.notOk(err, 'should add new block in fork') //err为null,没出错,接下来就是应该添加新的区块到分支上,光添加区块头是不够的
done()
})
},
function delForkHeader (done) {
blockchain.delBlock(forkHeader.hash(), (err) => {//forkHeader.hash()等于区块hash,即上面添加的区块头,删除指定的区块
t.ok(!err, 'should delete fork block') //即err = null
t.equals(blockchain._headHeader.toString('hex'), blocks[].hash().toString('hex'), 'should reset headHeader')//因为成功将上面添加的区块头删除了,所以现在的blockchain._headHeader == blocks[8].hash()
t.equals(blockchain._headBlock.toString('hex'), blocks[].hash().toString('hex'), 'should not change headBlock') //因为blocks[8]是有区块的,所以这两个值是相等的
done()
})
},
function delBlocks (done) {
function delNextBlock (number, cb) {
var block = blocks[number]
blockchain.delBlock(block.hash(), (err) => {
if (err) return cb(err)
if (number > ) {
return delNextBlock(--number, cb)
}
cb()
})
}
delNextBlock(, (err) => {//从blocknumber = 9的区块删到6,然后是5的区块变成了头
t.ok(!err, 'should delete blocks in canonical chain')
t.equals(blockchain._headHeader.toString('hex'), blocks[].hash().toString('hex'), 'should have block 5 as head')
done()
})
},
function delBlockAndChildren (done) {
blockchain.delBlock(blocks[].hash(), (err) => {//当你直接删除blocknumber = 1的区块时,意味着将其后面的子区块都删除了,所以此时的区块头为初始区块
t.ok(!err, 'should delete block and children')
t.equals(blockchain._headHeader.toString('hex'), genesisBlock.hash().toString('hex'), 'should have genesis as head')
done()
})
},
function putBlocks (done) {
blockchain.putBlocks(blocks.slice(), (err) => {
t.ok(!err, 'should put multiple blocks at once')
done()
})
},
function getHeads (done) {
createTestDB((err, db, genesis) => {
if (err) return done(err)
var blockchain = new Blockchain({db: db})
blockchain.getHead((err, head) => {
if (err) return done(err)
t.equals(head.hash().toString('hex'), genesis.hash().toString('hex'), 'should get head')
t.equals(blockchain._heads['head0'].toString('hex'), 'abcd', 'should get state root heads')
done()
})
})
},
function validate (done) {//会对添加进的区块进行验证
var blockchain = new Blockchain({validate: true})
var genesisBlock = new Block()
genesisBlock.setGenesisParams()
blockchain.putGenesis(genesisBlock, function (err) {
t.notOk(err, 'should validate genesisBlock')
var invalidBlock = new Block()
blockchain.putBlock(invalidBlock, function (err) {
t.ok(err, 'should not validate an invalid block')
done()
})
})
},
function addBlockWithBody (done) {//使用rlp值来添加区块
var blockchain = new Blockchain({validate: false})
var genesisBlock = new Block(Buffer.from(testData.genesisRLP.slice(), 'hex'))//slice(2)即去掉'0x'
blockchain.putGenesis(genesisBlock, function (err) {
if (err) return done(err)
var block = new Block(Buffer.from(testData.blocks[].rlp.slice(), 'hex'))
blockchain.putBlock(block, function (err) {
if (err) return done(err)
t.notOk(err, 'should add block with a body')
done()
})
})
},
function uncachedDbOps (done) {
createTestDB((err, db, genesis) => {
if (err) return done(err)
var blockchain = new Blockchain({db: db})
async.series([
cb => blockchain._hashToNumber(genesisBlock.hash(), (err, number) => {
t.equals(number.toString(), '', 'should perform _hashToNumber correctly')
cb(err)
}),
cb => blockchain._numberToHash(new BN(), (err, hash) => {
t.equals(genesisBlock.hash().toString('hex'), hash.toString('hex'), 'should perform _numberToHash correctly')
cb(err)
}),
cb => blockchain._getTd(genesisBlock.hash(), new BN(), (err, td) => {
t.equals(td.toBuffer().toString('hex'), genesis.header.difficulty.toString('hex'), 'should perform _getTd correctly')
cb(err)
})
], done)
})
},
function saveHeads (done) {
var db = level()
var blockchain = new Blockchain({db: db, validate: false})
var header = new Block.Header()
header.number = ethUtil.toBuffer()
header.difficulty = '0xfffffff'
header.parentHash = blocks[].hash()
blockchain.putHeader(header, (err) => {
if (err) return done(err)
blockchain = new Blockchain({db: db, validate: false})
async.series([
(cb) => blockchain.getLatestHeader((err, latest) => {//得到最新的区块头
if (err) return done(err)
t.equals(latest.hash().toString('hex'), header.hash().toString('hex'), 'should save headHeader')
cb()
}),
(cb) => blockchain.getLatestBlock((err, latest) => {//得到最新的区块
if (err) return done(err)
t.equals(latest.hash().toString('hex'), blocks[].hash().toString('hex'), 'should save headBlock')
cb()
})
], done)
})
},
function immutableCachedObjects (done) {
var blockchain = new Blockchain({validate: false})
// clone blocks[1]
var testBlock = new Block(rlp.decode(rlp.encode(blocks[].raw)))
var cachedHash
async.series([
(cb) => blockchain.putBlock(testBlock, (err) => {
if (err) return done(err)
cachedHash = testBlock.hash()
cb()
}),
(cb) => {
// change testBlock's extraData in order to modify its hash
testBlock.header.extraData = Buffer.from([]) //改变testBlock的extraData的数据,这将导致其hash值变化,但是它的变化并没有改变存储的区块中的值,说明存储对象是不可变的
blockchain.getBlock(, (err, block) => {
if (err) return done(err)
t.equals(cachedHash.toString('hex'), block.hash().toString('hex'), 'should not modify cached objects')
cb()
})
}
], done)
},
function getLatest (done) {
var blockchain = new Blockchain({validate: false})
var headers = [new Block.Header(), new Block.Header()] headers[].number = ethUtil.toBuffer()
headers[].difficulty = '0xfffffff'
headers[].parentHash = blocks[].hash() headers[].number = ethUtil.toBuffer()
headers[].difficulty = '0xfffffff'
headers[].parentHash = headers[].hash() async.series([
// first, add some headers and make sure the latest block remains the same
(cb) => blockchain.putHeaders(headers, (err) => {
if (err) return cb(err)
async.series([
(cb) => blockchain.getLatestHeader((err, header) => {
if (err) return done(err)
t.equals(header.hash().toString('hex'), headers[].hash().toString('hex'), 'should update latest header')
cb()
}),
(cb) => blockchain.getLatestBlock((err, block) => {
if (err) return done(err)
t.equals(block.hash().toString('hex'), blocks[].hash().toString('hex'), 'should not change latest block')//此时header为1,block为0,说明下面应该添加区块1
cb()
})
], cb)
}),
// then, add a full block and make sure the latest header remains the same
(cb) => blockchain.putBlock(blocks[], (err) => {//所以这里就添加区块1
if (err) return cb(err)
async.series([
(cb) => blockchain.getLatestHeader((err, header) => {
if (err) return done(err)
t.equals(header.hash().toString('hex'), headers[].hash().toString('hex'), 'should not change latest header')
cb()
}),
(cb) => blockchain.getLatestBlock((err, block) => {
if (err) return done(err)
t.equals(block.hash().toString('hex'), blocks[].hash().toString('hex'), 'should update latest block')//然后最新的区块就变成了区块1
cb()
})
], cb)
})
], done)
},
function mismatchedChains (done) {
var common = new Common('rinkeby')
var blockchain = new Blockchain({common: common, validate: false})
var blocks = [
new Block(null, {common: common}),
new Block(null, {chain: 'rinkeby'}),
new Block(null, {chain: 'ropsten'})//连接的chain不同,这个区块添加的过程会导致Chain mismatch的错误
] blocks[].setGenesisParams() blocks[].header.number =
blocks[].header.parentHash = blocks[].hash() blocks[].header.number =
blocks[].header.parentHash = blocks[].hash() async.eachOfSeries(blocks, (block, i, cb) => {
if (i === ) {
blockchain.putGenesis(block, cb)
} else {
blockchain.putBlock(block, (err) => {
if (i === ) {
t.ok(err.message.match('Chain mismatch'), 'should return chain mismatch error')//当new Block(null, {chain: 'ropsten'}区块添加时会报错
} else {
t.error(err, 'should not return mismatch error')
}
cb()
})
}
})
}
], function (err) {
if (err) {
t.ok(false, err)
} else {
t.ok(true, 'no errors')
}
})
}) function isConsecutive (blocks) {
var isConsecutive = true
blocks.some(function (block, index) {
if (index === ) return false
if (Buffer.compare(block.header.parentHash, blocks[index - ].hash()) !== ) {
isConsecutive = false
return true
}
})
return isConsecutive
} function createTestDB (cb) {
var genesis = new Block()
genesis.setGenesisParams()
var db = level()
db.batch([{
type: 'put',
key: Buffer.from('6800000000000000006e', 'hex'),
keyEncoding: 'binary',
valueEncoding: 'binary',
value: genesis.hash()
}, {
type: 'put',
key: Buffer.from('48d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3', 'hex'),
keyEncoding: 'binary',
valueEncoding: 'binary',
value: Buffer.from('', 'hex')
}, {
type: 'put',
key: 'LastHeader',
keyEncoding: 'binary',
valueEncoding: 'binary',
value: genesis.hash()
}, {
type: 'put',
key: 'LastBlock',
keyEncoding: 'binary',
valueEncoding: 'binary',
value: genesis.hash()
}, {
type: 'put',
key: Buffer.from('680000000000000000d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3', 'hex'),
keyEncoding: 'binary',
valueEncoding: 'binary',
value: ethUtil.rlp.encode(genesis.header.raw)
}, {
type: 'put',
key: Buffer.from('680000000000000000d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa374', 'hex'),
keyEncoding: 'binary',
valueEncoding: 'binary',
value: ethUtil.rlp.encode(new BN().toBuffer())
}, {
type: 'put',
key: Buffer.from('620000000000000000d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3', 'hex'),
keyEncoding: 'binary',
valueEncoding: 'binary',
value: ethUtil.rlp.encode(genesis.serialize(false).slice())
}, {
type: 'put',
key: 'heads',
valueEncoding: 'json',
value: { 'head0': { 'type': 'Buffer', 'data': [, ] } }
}], (err) => {
cb(err, db, genesis)
})
}

运行:

npm run test

返回:

userdeMBP:ethereumjs-blockchain-master user$ npm run test

> ethereumjs-blockchain@3.3. test /Users/user/ethereumjs-blockchain-master
> tape ./test/index.js TAP version
# blockchain test
ok should not crash on getting head of a blockchain without a genesis
ok should throw on initialization with chain and common parameter
ok correct genesis hash
ok genesis blocks match
ok support constructor with db parameter
ok support blockDb and detailsDb params
ok ignore detailsDb param
ok genesis block hash should be correct
ok should not validate a block incorrectly flagged as genesis
ok added blocks
ok should get block by number
ok should get block by hash
ok should get blocks
ok blocks should be consecutive
ok should get blocks
ok blocks should not be consecutive
ok should get blocks
ok blocks should not be consecutive
ok should get blocks
ok blocks should be consecutive
ok should get blocks
ok blocks should be consecutive
ok should get blocks
ok blocks should not be consecutive
ok should get blocks
ok blocks should not be consecutive
ok should get blocks
ok blocks should be consecutive
ok should get blocks
ok blocks should be consecutive
ok should get blocks
ok blocks should be consecutive
ok should get blocks
ok blocks should be consecutive
ok should get blocks
ok blocks should not be consecutive
ok should find needed hash
ok should iterate through blocks
ok should catch iterator func error
ok should return correct error
ok should not return error
ok should finish iterating
ok should get meta.rawHead
ok should get meta.genesis
ok should get meta.heads
ok should update stale head
ok should update stale headBlock
ok should add new block in fork
ok should delete fork block
ok should reset headHeader
ok should not change headBlock
ok should delete blocks in canonical chain
ok should have block as head
ok should delete block and children
ok should have genesis as head
ok should put multiple blocks at once
ok should get head
ok should get state root heads
ok should validate genesisBlock
ok should not validate an invalid block
ok should add block with a body
ok should perform _hashToNumber correctly
ok should perform _numberToHash correctly
ok should perform _getTd correctly
ok should save headHeader
ok should save headBlock
ok should not modify cached objects
ok should update latest header
ok should not change latest block
ok should not change latest header
ok should update latest block
ok should not return mismatch error
ok should return chain mismatch error ..
# tests
# pass # ok

ethereumjs/ethereumjs-blockchain-2-test的更多相关文章

  1. ethereumjs/ethereumjs-vm-2-API文档

    https://github.com/ethereumjs/ethereumjs-vm/blob/master/docs/index.md vm.runBlockchain Processes blo ...

  2. ethereumjs/ethereumjs-vm-4-tests

    根据代码发现还要了解的模块有: ethereumjs/merkle-patricia-tree -对应数据存储的数据结构 ethereumjs-blockchain —— 区块链 ethereumjs ...

  3. ethereumjs/ethereumjs-block-2-api

    https://github.com/ethereumjs/ethereumjs-block/blob/master/docs/index.md 详细的调用代码可见本博客的ethereumjs/eth ...

  4. ethereumjs/ethereumjs-blockchain-1-简介和API

    https://github.com/ethereumjs/ethereumjs-blockchain SYNOPSIS概要 A module to store and interact with b ...

  5. ethereumjs/ethereumjs-util

    ethereumjs/ethereumjs-util Most of the string manipulation methods are provided by ethjs-util 更多的字符串 ...

  6. ethereumjs/ethereumjs-wallet

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

  7. ethereumjs/ethereumjs-tx

    https://github.com/ethereumjs/ethereumjs-tx A simple module for creating, manipulating and signing e ...

  8. ethereumjs/ethereumjs-icap

    https://github.com/ethereumjs/ethereumjs-icap ethereumjs-icap 安装: npm install ethereumjs-icap --save ...

  9. ethereumjs/ethereumjs-common-1-简介

    为了了解ethereumjs/ethereumjs-block-3-代码的使用需要了解的一个模块 https://github.com/ethereumjs/ethereumjs-common Com ...

随机推荐

  1. 微信小程序二维码识别

    目前市场上二维码识别的软件或者网站越来越多,可是真正方便,无广告的却少之很少. 于是,自己突发奇想做了一个微信二维码识别的小程序. 包含功能: 1.识别二维码 ①普通二维码 ②条形码 ③只是复制解析出 ...

  2. Oracle数据库采用数据泵方式导入导出数据

    特别说明:Oralce的数据泵导入导出技术只能用在数据库服务器上,在只有客户端的机器上是无法使用数据泵技术的. 1.创建备份文件目录  mkdir d:\dmp 2.在Oralce中注册该目录,将目录 ...

  3. MySql:局域网和权限用户管理

    MySql 5.6(XP)/5.7(win7) 添加用户和设置局域访问权限操作.请在 http://sourceforge.net/  下载MySql Control Center(不是安装版本). ...

  4. 51Nod 算法马拉松23 开黑记

    惨啊……虽然开了半天黑,但是还是被dalao们踩了…… 第二次开黑,还是被卡在rank20了,我好菜啊……= = 写一写比赛经过吧…… 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是 ...

  5. 02:奇数单增序列 个人博客doubleq.win

    个人博客doubleq.win 02:奇数单增序列 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 给定一个长度为N(不大于500)的正整数序列,请将其中的所 ...

  6. 鼠标事件-拖拽2(不能拖出指定对象的div)

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  7. 131.003 数据预处理之Dummy Variable & One-Hot Encoding

    @(131 - Machine Learning | 机器学习) Demo 直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制 {sex:{male, female}}​ ...

  8. Appium元素定位(uiautomatorviewer)

    一.uiautomatorviewer元素定位 1.adroid-sdk的安装目录tools下有1个自带的工具uiautomatorviewer,打开后,如下所示: 点击后,如图所示: 步骤: a.链 ...

  9. Springmvc和Mybatis中常用的注解

    使用注解来构造IoC容器 用注解来向Spring容器注册Bean.需要在applicationContext.xml中注册<context:component-scan base-package ...

  10. RoCE、softRoCE与iWRAP

    RoCE - RDMA over Converged Ethernet 以太网在全球互联的广域网中毫无异议的老大,但在高带宽.低延时的专有网络领域却明显混不开.伴随网络融合概念兴起,IETF发布了DC ...