better system to prevent DOSing.
This commit is contained in:
parent
a2c08d9692
commit
47af5987ae
@ -489,7 +489,7 @@ Block.prototype.verifyContext = function verifyContext() {
|
||||
};
|
||||
|
||||
Block.prototype.isGenesis = function isGenesis() {
|
||||
return this.hash('hex') === utils.toHex(network.genesis._hash);
|
||||
return this.hash('hex') === network.genesis.hash;
|
||||
};
|
||||
|
||||
Block.prototype.getHeight = function getHeight() {
|
||||
|
||||
@ -56,9 +56,9 @@ function Chain(options) {
|
||||
network: network.type,
|
||||
entries: [
|
||||
{
|
||||
hash: utils.toHex(network.genesis._hash),
|
||||
hash: network.genesis.hash,
|
||||
version: network.genesis.version,
|
||||
prevBlock: utils.toHex(network.genesis.prevBlock),
|
||||
prevBlock: network.genesis.prevBlock,
|
||||
ts: network.genesis.ts,
|
||||
bits: network.genesis.bits,
|
||||
height: 0
|
||||
@ -302,9 +302,8 @@ Chain.prototype.add = function add(block, peer) {
|
||||
code = Chain.codes.invalid;
|
||||
this.emit('invalid', {
|
||||
height: prevHeight + 1,
|
||||
hash: hash,
|
||||
peer: peer
|
||||
});
|
||||
hash: hash
|
||||
}, peer);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -322,9 +321,8 @@ Chain.prototype.add = function add(block, peer) {
|
||||
height: -1,
|
||||
expected: this.orphan.map[prevHash].hash('hex'),
|
||||
received: hash,
|
||||
checkpoint: null,
|
||||
peer: peer
|
||||
});
|
||||
checkpoint: null
|
||||
}, peer);
|
||||
code = Chain.codes.forked;
|
||||
break;
|
||||
}
|
||||
@ -383,9 +381,8 @@ Chain.prototype.add = function add(block, peer) {
|
||||
height: prevHeight + 1,
|
||||
expected: tip.hash,
|
||||
received: hash,
|
||||
checkpoint: null,
|
||||
peer: peer
|
||||
});
|
||||
checkpoint: null
|
||||
}, peer);
|
||||
code = Chain.codes.forked;
|
||||
break;
|
||||
}
|
||||
@ -397,9 +394,8 @@ Chain.prototype.add = function add(block, peer) {
|
||||
code = Chain.codes.invalid;
|
||||
this.emit('invalid', {
|
||||
height: prevHeight + 1,
|
||||
hash: hash,
|
||||
peer: peer
|
||||
});
|
||||
hash: hash
|
||||
}, peer);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -422,8 +418,7 @@ Chain.prototype.add = function add(block, peer) {
|
||||
height: entry.height,
|
||||
expected: network.checkpoints[entry.height],
|
||||
received: entry.hash,
|
||||
checkpoint: true,
|
||||
peer: peer
|
||||
checkpoint: true
|
||||
});
|
||||
break;
|
||||
}
|
||||
@ -483,17 +478,14 @@ Chain.prototype.add = function add(block, peer) {
|
||||
return total;
|
||||
};
|
||||
|
||||
Chain.prototype.has = function has(hash, cb) {
|
||||
if (this.loading) {
|
||||
this.once('load', function() {
|
||||
this.has(hash, noIndex, cb);
|
||||
});
|
||||
return;
|
||||
}
|
||||
Chain.prototype.has = function has(hash) {
|
||||
if (this.hasBlock(hash))
|
||||
return true;
|
||||
|
||||
cb = utils.asyncify(cb);
|
||||
if (this.hasOrphan(hash))
|
||||
return true;
|
||||
|
||||
return cb(this.hasBlock(hash) || this.hasOrphan(hash));
|
||||
return false;
|
||||
};
|
||||
|
||||
Chain.prototype.byHeight = function byHeight(height) {
|
||||
|
||||
@ -113,7 +113,7 @@ Peer.prototype._init = function init() {
|
||||
|
||||
this.socket.once('error', function(err) {
|
||||
self._error(err);
|
||||
self.emit('misbehave');
|
||||
self.pool.misbehaving(self, 100);
|
||||
});
|
||||
|
||||
this.socket.once('close', function() {
|
||||
@ -134,7 +134,7 @@ Peer.prototype._init = function init() {
|
||||
// Something is wrong here.
|
||||
// Ignore this peer.
|
||||
self.destroy();
|
||||
self.emit('misbehave');
|
||||
self.pool.misbehaving(self, 100);
|
||||
});
|
||||
|
||||
if (this.pool.options.fullNode) {
|
||||
@ -156,7 +156,7 @@ Peer.prototype._init = function init() {
|
||||
if (err) {
|
||||
self._error(err);
|
||||
self.destroy();
|
||||
self.emit('misbehave');
|
||||
self.pool.misbehaving(self, 100);
|
||||
return;
|
||||
}
|
||||
self.ack = true;
|
||||
|
||||
@ -12,6 +12,7 @@ var bcoin = require('../bcoin');
|
||||
var utils = bcoin.utils;
|
||||
var assert = utils.assert;
|
||||
var network = bcoin.protocol.network;
|
||||
var constants = bcoin.protocol.constants;
|
||||
|
||||
/**
|
||||
* Pool
|
||||
@ -40,9 +41,6 @@ function Pool(options) {
|
||||
|
||||
this.originalSeeds = (options.seeds || network.seeds).map(utils.parseHost);
|
||||
this.setSeeds([]);
|
||||
this._priorityTries = {};
|
||||
this._regularTries = {};
|
||||
this._misbehaving = {};
|
||||
|
||||
this.storage = this.options.storage;
|
||||
this.destroyed = false;
|
||||
@ -112,13 +110,21 @@ function Pool(options) {
|
||||
// Peers that are loading block ids
|
||||
load: null,
|
||||
// All peers
|
||||
all: []
|
||||
all: [],
|
||||
// Misbehaving hosts
|
||||
misbehaving: {},
|
||||
// Attempts at using seed peers
|
||||
tries: {
|
||||
priority: {},
|
||||
regular: {}
|
||||
}
|
||||
};
|
||||
|
||||
this.block = {
|
||||
bestHeight: 0,
|
||||
bestHash: null,
|
||||
type: this.options.fullNode ? 'block' : 'filtered'
|
||||
type: this.options.fullNode ? 'block' : 'filtered',
|
||||
invalid: {}
|
||||
};
|
||||
|
||||
this.request = {
|
||||
@ -179,36 +185,36 @@ Pool.prototype._init = function _init() {
|
||||
self.emit('block', block, peer);
|
||||
});
|
||||
|
||||
this.chain.on('fork', function(data) {
|
||||
this.chain.on('fork', function(data, peer) {
|
||||
self.emit('debug',
|
||||
'Fork at height %d: expected=%s received=%s checkpoint=%s peer=%s',
|
||||
data.height,
|
||||
utils.revHex(data.expected),
|
||||
utils.revHex(data.received),
|
||||
data.checkpoint,
|
||||
data.peer ? data.peer.host : ''
|
||||
peer ? peer.host : ''
|
||||
);
|
||||
|
||||
if (!data.peer)
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
data.peer.destroy();
|
||||
self.misbehaving(peer, 100);
|
||||
});
|
||||
|
||||
this.chain.on('invalid', function(data) {
|
||||
this.chain.on('invalid', function(data, peer) {
|
||||
self.emit('debug',
|
||||
'Invalid block at height: %d: hash=%s peer=%s',
|
||||
data.height,
|
||||
utils.revHex(data.hash),
|
||||
data.peer ? data.peer.host : ''
|
||||
peer ? peer.host : ''
|
||||
);
|
||||
|
||||
if (!data.peer)
|
||||
self.block.invalid[data.hash] = true;
|
||||
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
// We should technically use a ban score
|
||||
// here instead of killing the peer.
|
||||
data.peer.destroy();
|
||||
self.misbehaving(peer, 100);
|
||||
});
|
||||
|
||||
this.options.wallets.forEach(function(w) {
|
||||
@ -536,10 +542,12 @@ Pool.prototype._handleInv = function _handleInv(hashes, peer) {
|
||||
|
||||
Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
||||
var self = this;
|
||||
var requested, hasPrev;
|
||||
|
||||
var requested = this._response(block);
|
||||
// Fulfill our request.
|
||||
requested = this._response(block);
|
||||
|
||||
// Emulate bip37 - emit all the "watched" txs
|
||||
// Emulate BIP37: emit all the filtered transactions.
|
||||
if (this.options.fullNode && this.listeners('watched').length > 0) {
|
||||
block.txs.forEach(function(tx) {
|
||||
if (self.isWatched(tx))
|
||||
@ -547,21 +555,39 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
||||
});
|
||||
}
|
||||
|
||||
// Ignore if we already have
|
||||
if (this.chain.has(block)) {
|
||||
this.emit('debug', 'Already have block %s (%s)', block.height, peer.host);
|
||||
// Ensure the block was not invalid last time.
|
||||
// Someone might be sending us bad blocks to DoS us.
|
||||
if (this.block.invalid[block.hash('hex')]) {
|
||||
this.misbehaving(peer, 100);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the block is valid
|
||||
// Ensure this is not a continuation
|
||||
// of an invalid chain.
|
||||
if (this.block.invalid[block.prevBlock]) {
|
||||
this.misbehaving(peer, 100);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore if we already have.
|
||||
if (this.chain.has(block)) {
|
||||
this.emit('debug', 'Already have block %s (%s)', block.height, peer.host);
|
||||
this.misbehaving(peer, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the block is valid.
|
||||
if (!block.verify()) {
|
||||
this.emit('debug',
|
||||
'Block verification failed for %s (%s)',
|
||||
block.rhash, peer.host);
|
||||
this.block.invalid[block.hash('hex')] = true;
|
||||
this.misbehaving(peer, 100);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Someone is sending us blocks without us requesting them.
|
||||
// Someone is sending us blocks without
|
||||
// us requesting them.
|
||||
if (!requested) {
|
||||
this.emit('debug',
|
||||
'Recieved unrequested block: %s (%s)',
|
||||
@ -571,19 +597,40 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
||||
// Resolve orphan chain
|
||||
if (!this.options.headers) {
|
||||
if (!this.chain.hasBlock(block.prevBlock)) {
|
||||
// Special case for genesis block.
|
||||
if (block.isGenesis())
|
||||
return false;
|
||||
|
||||
// Make sure the peer doesn't send us
|
||||
// more than 100 orphans every 3 minutes.
|
||||
if (this.orphaning(peer)) {
|
||||
this.misbehaving(peer, 100);
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: If we were to emit new orphans here, we
|
||||
// would not need to store full blocks as orphans.
|
||||
// However, the listener would not be able to see
|
||||
// the height until later.
|
||||
if (this._addIndex(block, peer))
|
||||
this.emit('pool block', block, peer);
|
||||
|
||||
this.peers.load.loadBlocks(
|
||||
this.chain.locatorHashes(),
|
||||
this.chain.getOrphanRoot(block)
|
||||
);
|
||||
|
||||
this.emit('debug', 'Handled orphan %s (%s)', block.rhash, peer.host);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!this.chain.hasBlock(block.prevBlock)) {
|
||||
if (!this.options.multiplePeers) {
|
||||
if (this.misbehaving(peer, 10))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add to index and emit/save
|
||||
@ -688,10 +735,6 @@ Pool.prototype._createPeer = function _createPeer(backoff, priority) {
|
||||
self.emit.apply(self, ['debug'].concat(args));
|
||||
});
|
||||
|
||||
peer.once('misbehave', function() {
|
||||
self._misbehaving[peer.host] = true;
|
||||
});
|
||||
|
||||
peer.on('reject', function(payload) {
|
||||
var data = utils.revHex(utils.toHex(payload.data));
|
||||
|
||||
@ -1203,37 +1246,31 @@ Pool.prototype.search = function search(id, range, e) {
|
||||
};
|
||||
|
||||
Pool.prototype._request = function _request(type, hash, options, cb) {
|
||||
var self = this;
|
||||
|
||||
// Optional `force`
|
||||
if (typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
hash = utils.toHex(hash);
|
||||
|
||||
if (this.request.map[hash])
|
||||
return this.request.map[hash].addCallback(cb);
|
||||
|
||||
function next(has) {
|
||||
if (has)
|
||||
return;
|
||||
|
||||
if (self.destroyed)
|
||||
return;
|
||||
|
||||
var req = new LoadRequest(self, type, hash, cb);
|
||||
req.add(options.noQueue);
|
||||
}
|
||||
|
||||
// Block should be not in chain, or be requested
|
||||
// Do not use with headers-first
|
||||
if (!options.force && (type === 'block' || type === 'filtered'))
|
||||
return this.chain.has(hash, next);
|
||||
if (!options.force && (type === 'block' || type === 'filtered')) {
|
||||
if (this.chain.has(hash))
|
||||
return;
|
||||
}
|
||||
|
||||
return next(false);
|
||||
if (this.destroyed)
|
||||
return;
|
||||
|
||||
var req = new LoadRequest(this, type, hash, cb);
|
||||
req.add(options.noQueue);
|
||||
};
|
||||
|
||||
Pool.prototype._response = function _response(entity) {
|
||||
@ -1498,7 +1535,10 @@ Pool.prototype.usableSeed = function usableSeed(priority, connecting) {
|
||||
var i, addr;
|
||||
var original = this.originalSeeds;
|
||||
var seeds = this.seeds;
|
||||
var tries = priority ? this._priorityTries : this._regularTries;
|
||||
var tries = this.peers.tries.regular;
|
||||
|
||||
if (priority)
|
||||
tries = this.peers.tries.priority;
|
||||
|
||||
// Hang back if we don't have a loader peer yet.
|
||||
if (!connecting && !priority && (!this.peers.load || !this.peers.load.socket))
|
||||
@ -1516,7 +1556,7 @@ Pool.prototype.usableSeed = function usableSeed(priority, connecting) {
|
||||
assert(addr.host);
|
||||
if (this.getPeer(addr))
|
||||
continue;
|
||||
if (this._misbehaving[addr.host])
|
||||
if (this.isMisbehaving(addr.host))
|
||||
continue;
|
||||
if (tries[addr.host])
|
||||
continue;
|
||||
@ -1533,7 +1573,7 @@ Pool.prototype.usableSeed = function usableSeed(priority, connecting) {
|
||||
assert(addr.host);
|
||||
if (this.peers.load && this.getPeer(addr) === this.peers.load)
|
||||
continue;
|
||||
if (this._misbehaving[addr.host])
|
||||
if (this.isMisbehaving(addr.host))
|
||||
continue;
|
||||
if (tries[addr.host])
|
||||
continue;
|
||||
@ -1549,7 +1589,7 @@ Pool.prototype.usableSeed = function usableSeed(priority, connecting) {
|
||||
assert(addr.host);
|
||||
if (this.getPeer(addr))
|
||||
continue;
|
||||
if (this._misbehaving[addr.host])
|
||||
if (this.isMisbehaving(addr.host))
|
||||
continue;
|
||||
return addr;
|
||||
}
|
||||
@ -1562,7 +1602,7 @@ Pool.prototype.usableSeed = function usableSeed(priority, connecting) {
|
||||
assert(addr.host);
|
||||
if (this.peers.load && this.getPeer(addr) === this.peers.load)
|
||||
continue;
|
||||
if (this._misbehaving[addr.host])
|
||||
if (this.isMisbehaving(addr.host))
|
||||
continue;
|
||||
return addr;
|
||||
}
|
||||
@ -1622,6 +1662,64 @@ Pool.prototype.removeSeed = function removeSeed(seed) {
|
||||
return true;
|
||||
};
|
||||
|
||||
Pool.prototype.orphaning = function orphaning(peer) {
|
||||
if (!peer._orphanTime)
|
||||
peer._orphanTime = utils.now();
|
||||
|
||||
if (!peer._orphans)
|
||||
peer._orphans = 0;
|
||||
|
||||
if (utils.now() > peer._orphanTime + 3 * 60) {
|
||||
peer._orphans = 0;
|
||||
peer._orphanTime = utils.now();
|
||||
}
|
||||
|
||||
peer._orphans += 1;
|
||||
|
||||
if (peer._orphans > 100)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Pool.prototype.misbehaving = function misbehaving(peer, dos) {
|
||||
if (!peer._banscore)
|
||||
peer._banscore = 0;
|
||||
|
||||
peer._banscore += dos;
|
||||
|
||||
if (peer._banscore >= constants.banScore) {
|
||||
this.peers.misbehaving[peer.host] = utils.now();
|
||||
this.emit('debug', 'Ban threshold exceeded for %s', peer.host);
|
||||
peer.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Pool.prototype.isMisbehaving = function isMisbehaving(host) {
|
||||
var peer, time;
|
||||
|
||||
if (host.host)
|
||||
host = host.host;
|
||||
|
||||
time = this.peers.misbehaving[host];
|
||||
|
||||
if (time) {
|
||||
if (utils.now() > time + constants.banTime) {
|
||||
delete this.peers.misbehaving[host];
|
||||
peer = this.getPeer(host);
|
||||
if (peer)
|
||||
peer._banscore = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Pool.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
v: 1,
|
||||
|
||||
@ -262,3 +262,6 @@ exports.userAgent = '/bcoin:' + exports.userVersion + '/';
|
||||
exports.coin = new bn(10000000).muln(10);
|
||||
exports.cent = new bn(1000000);
|
||||
exports.maxMoney = new bn(21000000).mul(exports.coin);
|
||||
|
||||
exports.banTime = 24 * 60 * 60;
|
||||
exports.banScore = 100;
|
||||
|
||||
@ -88,18 +88,17 @@ main.halvingInterval = 210000;
|
||||
// http://blockexplorer.com/rawblock/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
|
||||
main.genesis = {
|
||||
version: 1,
|
||||
_hash: utils.toArray(
|
||||
'000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f',
|
||||
'hex'
|
||||
).reverse(),
|
||||
prevBlock: [ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
hash: utils.revHex(
|
||||
'000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'
|
||||
),
|
||||
prevBlock: utils.toHex(
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0 ],
|
||||
merkleRoot: utils.toArray(
|
||||
'4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
|
||||
'hex'
|
||||
).reverse(),
|
||||
0, 0, 0, 0, 0, 0, 0, 0 ]),
|
||||
merkleRoot: utils.revHex(
|
||||
'4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'
|
||||
),
|
||||
ts: 1231006505,
|
||||
bits: 0x1d00ffff,
|
||||
nonce: 2083236893
|
||||
@ -113,9 +112,9 @@ main.preload = {
|
||||
network: main.type,
|
||||
entries: [
|
||||
{
|
||||
hash: utils.toHex(main.genesis._hash),
|
||||
hash: main.genesis.hash,
|
||||
version: main.genesis.version,
|
||||
prevBlock: utils.toHex(main.genesis.prevBlock),
|
||||
prevBlock: main.genesis.prevBlock,
|
||||
ts: main.genesis.ts,
|
||||
bits: main.genesis.bits,
|
||||
height: 0
|
||||
@ -203,18 +202,17 @@ testnet.halvingInterval = 210000;
|
||||
// http://blockexplorer.com/testnet/rawblock/000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943
|
||||
testnet.genesis = {
|
||||
version: 1,
|
||||
_hash: utils.toArray(
|
||||
'000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943',
|
||||
'hex'
|
||||
).reverse(),
|
||||
prevBlock: [ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
hash: utils.revHex(
|
||||
'000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943'
|
||||
),
|
||||
prevBlock: utils.toHex(
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0 ],
|
||||
merkleRoot: utils.toArray(
|
||||
'4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
|
||||
'hex'
|
||||
).reverse(),
|
||||
0, 0, 0, 0, 0, 0, 0, 0 ]),
|
||||
merkleRoot: utils.revHex(
|
||||
'4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'
|
||||
),
|
||||
ts: 1296688602,
|
||||
bits: 0x1d00ffff,
|
||||
nonce: 414098458
|
||||
@ -228,9 +226,9 @@ testnet.preload = {
|
||||
network: testnet.type,
|
||||
entries: [
|
||||
{
|
||||
hash: utils.toHex(testnet.genesis._hash),
|
||||
hash: testnet.genesis.hash,
|
||||
version: testnet.genesis.version,
|
||||
prevBlock: utils.toHex(testnet.genesis.prevBlock),
|
||||
prevBlock: testnet.genesis.prevBlock,
|
||||
ts: testnet.genesis.ts,
|
||||
bits: testnet.genesis.bits,
|
||||
height: 0
|
||||
@ -300,18 +298,17 @@ regtest.halvingInterval = 150;
|
||||
|
||||
regtest.genesis = {
|
||||
version: 1,
|
||||
_hash: utils.toArray(
|
||||
'0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206',
|
||||
'hex'
|
||||
).reverse(),
|
||||
prevBlock: [ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
hash: utils.revHex(
|
||||
'0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206'
|
||||
),
|
||||
prevBlock: utils.toHex(
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0 ],
|
||||
merkleRoot: utils.toArray(
|
||||
'4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
|
||||
'hex'
|
||||
).reverse(),
|
||||
0, 0, 0, 0, 0, 0, 0, 0 ]),
|
||||
merkleRoot: utils.revHex(
|
||||
'4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'
|
||||
),
|
||||
ts: 1296688602,
|
||||
bits: 0x207fffff,
|
||||
nonce: 2
|
||||
@ -325,9 +322,9 @@ regtest.preload = {
|
||||
network: regtest.type,
|
||||
entries: [
|
||||
{
|
||||
hash: utils.toHex(regtest.genesis._hash),
|
||||
hash: regtest.genesis.hash,
|
||||
version: regtest.genesis.version,
|
||||
prevBlock: utils.toHex(regtest.genesis.prevBlock),
|
||||
prevBlock: regtest.genesis.prevBlock,
|
||||
ts: regtest.genesis.ts,
|
||||
bits: regtest.genesis.bits,
|
||||
height: 0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user