block: rename some more methods. refactor bip152 ptx vector.
This commit is contained in:
parent
7ed36ec2ba
commit
8c212d797f
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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();
|
||||
};
|
||||
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user