From 5a751d9ba7783384e195c634df75cf5b6e9d00ba Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 12 Aug 2017 18:08:43 -0700 Subject: [PATCH] test: add some new functions to test/util/common. --- bench/buffer.js | 2 +- bench/coins.js | 2 +- bench/tx.js | 6 +- scripts/dump.js | 2 +- test/block-test.js | 8 +- test/coins-test.js | 2 +- test/protocol-test.js | 21 +++-- test/tx-test.js | 14 ++-- test/util/common.js | 174 +++++++++++++++++++++++++++++++++++++++--- 9 files changed, 194 insertions(+), 37 deletions(-) diff --git a/bench/buffer.js b/bench/buffer.js index 5c9ea92f2..f85660927 100644 --- a/bench/buffer.js +++ b/bench/buffer.js @@ -5,7 +5,7 @@ const StaticWriter = require('../lib/utils/staticwriter'); const common = require('../test/util/common'); const bench = require('./bench'); -const {tx} = common.parseTX('data/tx5.hex'); +const {tx} = common.parseTX('tx5'); { const end = bench('serialize (static-writer)'); diff --git a/bench/coins.js b/bench/coins.js index 27e8ea0ed..08c35b2c2 100644 --- a/bench/coins.js +++ b/bench/coins.js @@ -4,7 +4,7 @@ const Coins = require('../lib/coins/coins'); const common = require('../test/util/common'); const bench = require('./bench'); -const {tx} = common.parseTX('data/tx5.hex'); +const {tx} = common.parseTX('tx5'); const coins = Coins.fromTX(tx, 1); const raw = coins.toRaw(); diff --git a/bench/tx.js b/bench/tx.js index 1d1d01183..2d25e8d19 100644 --- a/bench/tx.js +++ b/bench/tx.js @@ -19,11 +19,11 @@ const undo = common.parseUndo(undoRaw); const btx = { tx: block.txs[397], - view: common.applyUndo(block, undo) + view: common.applyBlockUndo(block, undo) }; -const tx3 = common.parseTX('data/tx3.hex'); -const tx5 = common.parseTX('data/tx5.hex'); +const tx3 = common.parseTX('tx3'); +const tx5 = common.parseTX('tx5'); const raw = tx5.tx.toRaw(); { diff --git a/scripts/dump.js b/scripts/dump.js index 4ebfd53a6..460e1c449 100644 --- a/scripts/dump.js +++ b/scripts/dump.js @@ -7,7 +7,7 @@ const common = require('../test/util/common'); const SNAPSHOT = `${__dirname}/../dump.heapsnapshot`; -const {tx, view} = common.parseTX('data/tx4.hex'); +const {tx, view} = common.parseTX('tx4'); const coins = Coins.fromTX(tx, 0); const entry = MempoolEntry.fromTX(tx, view, 1000000); diff --git a/test/block-test.js b/test/block-test.js index 8a12acc56..93c88617f 100644 --- a/test/block-test.js +++ b/test/block-test.js @@ -139,7 +139,7 @@ describe('Block', function() { it('should verify a historical block', () => { const block = Block.fromRaw(block300025); const undo = common.parseUndo(undo300025); - const view = common.applyUndo(block, undo); + const view = common.applyBlockUndo(block, undo); const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG; const height = 300025; @@ -361,7 +361,7 @@ describe('Block', function() { it('should count sigops for block 928927 (testnet)', () => { const block = Block.fromRaw(block928927); const undo = common.parseUndo(undo928927); - const view = common.applyUndo(block, undo); + const view = common.applyBlockUndo(block, undo); const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_WITNESS; let sigops = 0; @@ -375,7 +375,7 @@ describe('Block', function() { it('should count sigops for block 928828 (testnet)', () => { const block = Block.fromRaw(block928828); const undo = common.parseUndo(undo928828); - const view = common.applyUndo(block, undo); + const view = common.applyBlockUndo(block, undo); const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_WITNESS; let sigops = 0; @@ -389,7 +389,7 @@ describe('Block', function() { it('should count sigops for block 1087400 (testnet)', () => { const block = Block.fromRaw(block1087400); const undo = common.parseUndo(undo1087400); - const view = common.applyUndo(block, undo); + const view = common.applyBlockUndo(block, undo); const flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_WITNESS; let sigops = 0; diff --git a/test/coins-test.js b/test/coins-test.js index c787e53bc..46119350f 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -13,7 +13,7 @@ const StaticWriter = require('../lib/utils/staticwriter'); const BufferReader = require('../lib/utils/reader'); const {parseTX} = require('./util/common'); -const data = parseTX('data/tx1.hex'); +const data = parseTX('tx1'); const tx1 = data.tx; function reserialize(coin) { diff --git a/test/protocol-test.js b/test/protocol-test.js index f316cdf15..9d3ed70d8 100644 --- a/test/protocol-test.js +++ b/test/protocol-test.js @@ -15,8 +15,8 @@ const packets = require('../lib/net/packets'); const common = require('./util/common'); const network = Network.get('main'); -const tx8 = common.parseTX('data/tx8.hex'); -const tx9 = common.parseTX('data/tx9.hex'); +const tx8 = common.parseTX('tx8'); +const tx9 = common.parseTX('tx9'); describe('Protocol', function() { const pkg = require('../lib/pkg'); @@ -28,15 +28,20 @@ describe('Protocol', function() { framer = new Framer(); }); - function packetTest(command, payload, test) { - it(`should encode/decode ${command}`, (cb) => { - const ver = Buffer.from(framer.packet(command, payload.toRaw())); + function packetTest(cmd, payload, test) { + it(`should encode/decode ${cmd}`, (cb) => { parser.once('packet', (packet) => { - assert.strictEqual(packet.cmd, command); - test(packet); + try { + assert.strictEqual(packet.cmd, cmd); + test(packet); + } catch (e) { + cb(e); + return; + } cb(); }); - parser.feed(ver); + const raw = framer.packet(cmd, payload.toRaw()); + parser.feed(raw); }); } diff --git a/test/tx-test.js b/test/tx-test.js index b6af5a147..70bd046fe 100644 --- a/test/tx-test.js +++ b/test/tx-test.js @@ -23,13 +23,13 @@ const validTests = require('./data/tx-valid.json'); const invalidTests = require('./data/tx-invalid.json'); const sighashTests = require('./data/sighash-tests.json'); -const tx1 = common.parseTX('data/tx1.hex'); -const tx2 = common.parseTX('data/tx2.hex'); -const tx3 = common.parseTX('data/tx3.hex'); -const tx4 = common.parseTX('data/tx4.hex'); -const tx5 = common.parseTX('data/tx5.hex'); -const tx6 = common.parseTX('data/tx6.hex'); -const tx7 = common.parseTX('data/tx7.hex'); +const tx1 = common.parseTX('tx1'); +const tx2 = common.parseTX('tx2'); +const tx3 = common.parseTX('tx3'); +const tx4 = common.parseTX('tx4'); +const tx5 = common.parseTX('tx5'); +const tx6 = common.parseTX('tx6'); +const tx7 = common.parseTX('tx7'); const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; const MAX_SAFE_ADDITION = 0xfffffffffffff; diff --git a/test/util/common.js b/test/util/common.js index 483728679..8636b4426 100644 --- a/test/util/common.js +++ b/test/util/common.js @@ -2,22 +2,26 @@ const assert = require('assert'); const fs = require('../../lib/utils/fs'); +const Block = require('../../lib/primitives/block'); +const MerkleBlock = require('../../lib/primitives/merkleblock'); +const {CompactBlock} = require('../../lib/net/bip152'); const TX = require('../../lib/primitives/tx'); const Output = require('../../lib/primitives/output'); const CoinView = require('../../lib/coins/coinview'); const BufferReader = require('../../lib/utils/reader'); +const BufferWriter = require('../../lib/utils/writer'); -exports.parseTX = function parseTX(file) { - const data = fs.readFileSync(`${__dirname}/../${file}`, 'utf8'); - const parts = data.trim().split(/\n+/); - const raw = parts[0]; - const tx = TX.fromRaw(raw.trim(), 'hex'); +exports.parseTX = function parseTX(name) { + const data = fs.readFileSync(`${__dirname}/../data/${name}.hex`, 'utf8'); + const parts = data.trim().split('\n'); + const raw = Buffer.from(parts[0], 'hex'); + const tx = TX.fromRaw(raw); const view = new CoinView(); const txs = [tx]; for (let i = 1; i < parts.length; i++) { - const raw = parts[i]; - const prev = TX.fromRaw(raw.trim(), 'hex'); + const raw = Buffer.from(parts[i], 'hex'); + const prev = TX.fromRaw(raw); view.addTX(prev, -1); txs.push(prev); } @@ -29,19 +33,87 @@ exports.parseTX = function parseTX(file) { }; }; +exports.readBlock = function readBlock(name) { + const height = name.substring(5); + const blockFile = `${__dirname}/../data/block${height}.raw`; + + if (!fs.existsSync(blockFile)) { + const raw = fs.readFileSync(`${__dirname}/../data/${name}.raw`); + const block = Block.fromRaw(raw); + const view = new CoinView(); + return { raw, block, view }; + } + + const raw = fs.readFileSync(blockFile); + const block = Block.fromRaw(raw); + + const undoFile = `${__dirname}/../data/undo${height}.raw`; + + if (!fs.existsSync(undoFile)) { + const view = new CoinView(); + return { raw, block, view }; + } + + const undoRaw = fs.readFileSync(undoFile); + const undo = exports.parseUndo(undoRaw); + const view = exports.applyBlockUndo(block, undo); + + return { raw, block, view }; +}; + +exports.readMerkle = function readMerkle(name) { + const raw = fs.readFileSync(`${__dirname}/../data/${name}.raw`); + const block = MerkleBlock.fromRaw(raw); + return { raw, block }; +}; + +exports.readCompact = function readCompact(name) { + const raw = fs.readFileSync(`${__dirname}/../data/${name}.raw`); + const block = CompactBlock.fromRaw(raw); + return { raw, block }; +}; + +exports.readTX = function readTX(name) { + const index = name.substring(2); + const txFile = `${__dirname}/../data/tx${index}.raw`; + + if (!fs.existsSync(txFile)) { + const raw = fs.readFileSync(`${__dirname}/../data/${name}.raw`); + const tx = TX.fromRaw(raw); + const view = new CoinView(); + return { raw, tx, view }; + } + + const raw = fs.readFileSync(txFile); + const tx = TX.fromRaw(raw); + + const undoFile = `${__dirname}/../data/utx${index}.raw`; + + if (!fs.existsSync(undoFile)) { + const view = new CoinView(); + return { raw, tx, view }; + } + + const undoRaw = fs.readFileSync(undoFile); + const undo = exports.parseUndo(undoRaw); + const view = exports.applyTXUndo(tx, undo); + + return { raw, tx, view }; +}; + exports.parseUndo = function parseUndo(data) { const br = new BufferReader(data); - const undo = []; + const items = []; while (br.left()) { const output = Output.fromReader(br); - undo.push(output); + items.push(output); } - return undo; + return items; }; -exports.applyUndo = function applyUndo(block, undo) { +exports.applyBlockUndo = function applyBlockUndo(block, undo) { const view = new CoinView(); let i = 0; @@ -57,3 +129,83 @@ exports.applyUndo = function applyUndo(block, undo) { return view; }; + +exports.applyTXUndo = function applyTXUndo(tx, undo) { + const view = new CoinView(); + let i = 0; + + for (const {prevout} of tx.inputs) + view.addOutput(prevout, undo[i++]); + + assert(i === undo.length, 'Undo coins data inconsistency.'); + + return view; +}; + +exports.makeBlockUndo = function makeBlockUndo(block, view) { + const items = []; + + for (const tx of block.txs) { + if (tx.isCoinbase()) + continue; + + for (const {prevout} of tx.inputs) { + const coin = view.getOutput(prevout); + assert(coin); + items.push(coin); + } + } + + return items; +}; + +exports.makeTXUndo = function makeTXUndo(tx, view) { + const items = []; + + for (const {prevout} of tx.inputs) { + const coin = view.getOutput(prevout); + assert(coin); + items.push(coin); + } + + return items; +}; + +exports.serializeUndo = function serializeUndo(items) { + const bw = new BufferWriter(); + + for (const item of items) { + bw.writeI64(item.value); + bw.writeVarBytes(item.script.toRaw()); + } + + return bw.render(); +}; + +exports.writeBlock = function writeBlock(name, block, view) { + const height = name.substring(5); + + fs.writeFileSync(`${__dirname}/../data/block${height}.raw`, block.toRaw()); + + if (!view) + return; + + const undo = exports.makeBlockUndo(block, view); + const undoRaw = exports.serializeUndo(undo); + + fs.writeFileSync(`${__dirname}/../data/undo${height}.raw`, undoRaw); +}; + +exports.writeTX = function writeTX(name, tx, view) { + const index = name.substring(2); + + fs.writeFileSync(`${__dirname}/../data/tx${index}.raw`, tx.toRaw()); + + if (!view) + return; + + const undo = exports.makeTXUndo(tx, view); + const undoRaw = exports.serializeUndo(undo); + + fs.writeFileSync(`${__dirname}/../data/utx${index}.raw`, undoRaw); +};