block: rename some more methods. refactor bip152 ptx vector.

This commit is contained in:
Christopher Jeffrey 2017-07-25 01:06:55 -07:00
parent 7ed36ec2ba
commit 8c212d797f
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
9 changed files with 112 additions and 120 deletions

View File

@ -1334,7 +1334,7 @@ Chain.prototype.connect = async function connect(prev, block, flags) {
// validated, and connected. Hopefully the
// deserialized blocks get cleaned up by the
// GC quickly.
if (block.memory) {
if (block.isMemory()) {
try {
block = block.toBlock();
} catch (e) {
@ -1342,7 +1342,8 @@ Chain.prototype.connect = async function connect(prev, block, flags) {
throw new VerifyError(block,
'malformed',
'error parsing message',
10);
10,
true);
}
}

View File

@ -921,7 +921,7 @@ RPC.prototype.verifyTXOutProof = async function verifyTXOutProof(args, help) {
let valid = new Validator([args]);
let data = valid.buf(0);
let out = [];
let block, entry;
let block, entry, tree;
if (help || args.length !== 1)
throw new RPCError(errs.MISC_ERROR, 'verifytxoutproof "proof"');
@ -939,7 +939,9 @@ RPC.prototype.verifyTXOutProof = async function verifyTXOutProof(args, help) {
if (!entry)
throw new RPCError(errs.MISC_ERROR, 'Block not found in chain.');
for (let hash of block.tree.matches)
tree = block.getTree();
for (let hash of tree.matches)
out.push(util.revHex(hash));
return out;

View File

@ -124,12 +124,7 @@ CompactBlock.prototype.fromRaw = function fromRaw(data) {
let br = new BufferReader(data);
let count;
this.version = br.readU32();
this.prevBlock = br.readHash('hex');
this.merkleRoot = br.readHash('hex');
this.ts = br.readU32();
this.bits = br.readU32();
this.nonce = br.readU32();
this.readHead(br);
this.keyNonce = br.readBytes(8);
this.sipKey = this.getKey();
@ -154,7 +149,7 @@ CompactBlock.prototype.fromRaw = function fromRaw(data) {
tx = TX.fromReader(br);
this.ptx.push(new PrefilledTX(index, tx));
this.ptx.push([index, tx]);
}
return this;
@ -238,12 +233,13 @@ CompactBlock.prototype.getSize = function getSize(witness) {
size += this.ids.length * 6;
size += encoding.sizeVarint(this.ptx.length);
for (let ptx of this.ptx) {
size += encoding.sizeVarint(ptx.index);
for (let [index, tx] of this.ptx) {
size += encoding.sizeVarint(index);
if (witness)
size += ptx.tx.getSize();
size += tx.getSize();
else
size += ptx.tx.getBaseSize();
size += tx.getBaseSize();
}
return size;
@ -273,12 +269,13 @@ CompactBlock.prototype.writeRaw = function writeRaw(bw, witness) {
bw.writeVarint(this.ptx.length);
for (let ptx of this.ptx) {
bw.writeVarint(ptx.index);
for (let [index, tx] of this.ptx) {
bw.writeVarint(index);
if (witness)
ptx.tx.toWriter(bw);
tx.toWriter(bw);
else
ptx.tx.toNormalWriter(bw);
tx.toNormalWriter(bw);
}
return bw;
@ -302,13 +299,14 @@ CompactBlock.prototype.toRequest = function toRequest() {
*/
CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) {
let have = {};
let have;
if (this.count === this.totalTX)
return true;
for (let entry of mempool.map.values()) {
let tx = entry.tx;
have = new Set();
for (let {tx} of mempool.map.values()) {
let hash = tx.hash();
let id, index;
@ -321,7 +319,7 @@ CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) {
if (index == null)
continue;
if (have[index]) {
if (have.has(index)) {
// Siphash collision, just request it.
this.available[index] = null;
this.count--;
@ -329,7 +327,7 @@ CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) {
}
this.available[index] = tx;
have[index] = true;
have.add(index);
this.count++;
// We actually may have a siphash collision
@ -417,7 +415,7 @@ CompactBlock.prototype.init = function init() {
if (this.totalTX > consensus.MAX_BLOCK_SIZE / 10)
throw new Error('Compact block too big.');
// Custom limit to avoid hashdos:
// Custom limit to avoid a hashdos.
// Min valid tx size: (4 + 1 + 41 + 1 + 9 + 4) = 60
// Min block header size: 81
// Max number of transactions: (1000000 - 81) / 60 = 16665
@ -429,33 +427,25 @@ CompactBlock.prototype.init = function init() {
this.available.push(null);
for (let i = 0; i < this.ptx.length; i++) {
let ptx = this.ptx[i];
assert(ptx);
last += ptx.index + 1;
let [index, tx] = this.ptx[i];
last += index + 1;
assert(last <= 0xffff);
assert(last <= this.ids.length + i);
this.available[last] = ptx.tx;
this.available[last] = tx;
this.count++;
}
for (let i = 0; i < this.ids.length; i++) {
let id;
let id = this.ids[i];
while (this.available[i + offset])
offset++;
id = this.ids[i];
// Fails on siphash collision
// Fails on siphash collision.
if (this.idMap.has(id))
return false;
this.idMap.set(id, i + offset);
// We're supposed to fail here if there's
// more than 12 hash collisions, but we
// don't have lowlevel access to our hash
// table. Hopefully we don't get hashdos'd.
}
return true;
@ -526,7 +516,7 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) {
this.ids.push(id);
}
this.ptx.push(new PrefilledTX(0, block.txs[0]));
this.ptx.push([0, block.txs[0]]);
return this;
};
@ -964,20 +954,6 @@ TXResponse.prototype.frameRaw = function frameRaw(witness) {
return this.writeRaw(new StaticWriter(size), witness).render();
};
/**
* Represents a prefilled TX.
* @constructor
* @param {Number} index
* @param {TX} tx
* @property {Number} index
* @property {TX} tx
*/
function PrefilledTX(index, tx) {
this.index = index;
this.tx = tx;
}
/*
* Expose
*/

View File

@ -2687,6 +2687,7 @@ Pool.prototype._handleMerkleBlock = async function handleMerkleBlock(peer, packe
let block = packet.block;
let hash = block.hash('hex');
let flags = chainCommon.flags.VERIFY_NONE;
let tree;
if (!this.syncing)
return;
@ -2724,14 +2725,16 @@ Pool.prototype._handleMerkleBlock = async function handleMerkleBlock(peer, packe
return;
}
if (block.tree.matches.length === 0) {
tree = block.getTree();
if (tree.matches.length === 0) {
await this._addBlock(peer, block, flags);
return;
}
peer.merkleBlock = block;
peer.merkleTime = util.ms();
peer.merkleMatches = block.tree.matches.length;
peer.merkleMatches = tree.matches.length;
peer.merkleMap = new Set();
};

View File

@ -29,8 +29,6 @@ const consensus = require('../protocol/consensus');
* @property {Number} ts - Timestamp.
* @property {Number} bits
* @property {Number} nonce
* @property {TX[]} txs - Transaction vector.
* @property {ReversedHash} rhash - Reversed block hash (uint256le).
*/
function AbstractBlock() {
@ -44,24 +42,12 @@ function AbstractBlock() {
this.bits = 0;
this.nonce = 0;
this.txs = null;
this.mutable = false;
this._hash = null;
this._hhash = null;
this._size = -1;
this._witness = -1;
}
/**
* Memory flag.
* @const {Boolean}
* @default
* @memberof AbstractBlock#
*/
AbstractBlock.prototype.memory = false;
/**
* Inject properties from options object.
* @private
@ -116,33 +102,29 @@ AbstractBlock.prototype.parseJSON = function parseJSON(json) {
};
/**
* Clear any cached values (abstract).
* @param {Boolean?} all - Clear transactions.
* Test whether the block is a memblock.
* @returns {Boolean}
*/
AbstractBlock.prototype._refresh = function refresh(all) {
AbstractBlock.prototype.isMemory = function isMemory() {
return false;
};
/**
* Clear any cached values (abstract).
*/
AbstractBlock.prototype._refresh = function refresh() {
this._hash = null;
this._hhash = null;
this._size = -1;
this._witness = -1;
if (!all)
return;
if (!this.txs)
return;
for (let tx of this.txs)
tx.refresh();
};
/**
* Clear any cached values.
* @param {Boolean?} all - Clear transactions.
*/
AbstractBlock.prototype.refresh = function refresh(all) {
return this._refresh(all);
AbstractBlock.prototype.refresh = function refresh() {
return this._refresh();
};
/**
@ -182,6 +164,16 @@ AbstractBlock.prototype.toHead = function toHead() {
return this.writeHead(new StaticWriter(80)).render();
};
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
AbstractBlock.prototype.fromHead = function fromHead(data) {
return this.readHead(new BufferReader(data));
};
/**
* Serialize the block headers.
* @param {BufferWriter} bw
@ -202,7 +194,7 @@ AbstractBlock.prototype.writeHead = function writeHead(bw) {
* @param {BufferReader} br
*/
AbstractBlock.prototype.parseHead = function parseHead(br) {
AbstractBlock.prototype.readHead = function readHead(br) {
this.version = br.readU32();
this.prevBlock = br.readHash('hex');
this.merkleRoot = br.readHash('hex');

View File

@ -79,8 +79,17 @@ Block.fromOptions = function fromOptions(options) {
*/
Block.prototype.refresh = function refresh(all) {
this._refresh();
this._raw = null;
this._refresh(all);
this._size = -1;
this._witness = -1;
if (!all)
return;
for (let tx of this.txs)
tx.refresh();
};
/**
@ -644,7 +653,7 @@ Block.prototype.fromReader = function fromReader(br) {
br.start();
this.parseHead(br);
this.readHead(br);
count = br.readVarint();

View File

@ -80,7 +80,7 @@ Headers.prototype.toRaw = function toRaw() {
*/
Headers.prototype.fromReader = function fromReader(br) {
this.parseHead(br);
this.readHead(br);
br.readVarint();
return this;
};
@ -118,17 +118,6 @@ Headers.fromRaw = function fromRaw(data, enc) {
return new Headers().fromRaw(data);
};
/**
* Inject properties from serialized data.
* TODO: MOVE.
* @private
* @param {Buffer} data
*/
Headers.prototype.fromHead = function fromHead(data) {
return this.parseHead(new BufferReader(data));
};
/**
* Instantiate headers from serialized data.
* @param {Buffer} data
@ -149,8 +138,15 @@ Headers.fromHead = function fromHead(data, enc) {
*/
Headers.fromEntry = function fromEntry(entry) {
let headers = new Headers(entry);
let headers = new Headers();
headers.version = entry.version;
headers.prevBlock = entry.prevBlock;
headers.merkleRoot = entry.merkleRoot;
headers.ts = entry.ts;
headers.bits = entry.bits;
headers.nonce = entry.nonce;
headers._hash = Buffer.from(entry.hash, 'hex');
headers._hhash = entry.hash;
return headers;
};

View File

@ -40,19 +40,21 @@ function MemBlock() {
if (!(this instanceof MemBlock))
return new MemBlock();
AbstractBlock.call(this);
this._raw = DUMMY;
}
util.inherits(MemBlock, AbstractBlock);
/**
* Memory flag.
* @const {Boolean}
* @default
* @memberof MemBlock#
* Test whether the block is a memblock.
* @returns {Boolean}
*/
MemBlock.prototype.memory = true;
MemBlock.prototype.isMemory = function isMemory() {
return true;
};
/**
* Serialize the block headers.
@ -144,7 +146,7 @@ MemBlock.prototype.parseCoinbaseHeight = function parseCoinbaseHeight() {
MemBlock.prototype.fromRaw = function fromRaw(data) {
let br = new BufferReader(data, true);
this.parseHead(br);
this.readHead(br);
this._raw = br.data;

View File

@ -32,12 +32,12 @@ function MerkleBlock(options) {
AbstractBlock.call(this);
this.txs = [];
this.hashes = [];
this.flags = DUMMY;
this.totalTX = 0;
this.tree = null;
this.txs = [];
this._tree = null;
if (options)
this.fromOptions(options);
@ -63,15 +63,20 @@ MerkleBlock.prototype.fromOptions = function fromOptions(options) {
for (let hash of options.hashes) {
if (typeof hash === 'string')
hash = Buffer.from(hash, 'hex');
assert(Buffer.isBuffer(hash));
this.hashes.push(hash);
}
}
if (options.flags)
if (options.flags) {
assert(Buffer.isBuffer(options.flags));
this.flags = options.flags;
}
if (options.totalTX != null)
if (options.totalTX != null) {
assert(util.isUInt32(options.totalTX));
this.totalTX = options.totalTX;
}
return this;
};
@ -92,8 +97,14 @@ MerkleBlock.fromOptions = function fromOptions(data) {
*/
MerkleBlock.prototype.refresh = function refresh(all) {
this.tree = null;
this._refresh(all);
this._refresh();
this._tree = null;
if (!all)
return;
for (let tx of this.txs)
tx.refresh();
};
/**
@ -161,7 +172,7 @@ MerkleBlock.prototype.checkBody = function checkBody() {
if (tree.root !== this.merkleRoot)
return [false, 'bad-txnmrklroot', 100];
return [true, 'valid', 100];
return [true, 'valid', 0];
};
/**
@ -171,14 +182,14 @@ MerkleBlock.prototype.checkBody = function checkBody() {
*/
MerkleBlock.prototype.getTree = function getTree() {
if (!this.tree) {
if (!this._tree) {
try {
this.tree = this.extractTree();
this._tree = this.extractTree();
} catch (e) {
this.tree = new PartialTree();
this._tree = new PartialTree();
}
}
return this.tree;
return this._tree;
};
/**
@ -380,7 +391,7 @@ MerkleBlock.prototype.toRaw = function toRaw() {
MerkleBlock.prototype.fromReader = function fromReader(br) {
let count;
this.parseHead(br);
this.readHead(br);
this.totalTX = br.readU32();