test: fix tx tests.

This commit is contained in:
Christopher Jeffrey 2016-12-10 07:43:54 -08:00
parent 4484a11ede
commit bf2e7d1486
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 400 additions and 551 deletions

View File

@ -706,7 +706,7 @@ Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) {
} }
// Make sure the miner isn't trying to conjure more coins. // Make sure the miner isn't trying to conjure more coins.
if (block.getClaimed() > block.getReward(view, this.network)) { if (block.getClaimed() > block.getReward(view, height, this.network)) {
throw new VerifyError(block, throw new VerifyError(block,
'invalid', 'invalid',
'bad-cb-amount', 'bad-cb-amount',

View File

@ -400,8 +400,6 @@ ChainEntry.prototype.rhash = function() {
*/ */
ChainEntry.prototype.fromBlock = function fromBlock(block, prev) { ChainEntry.prototype.fromBlock = function fromBlock(block, prev) {
assert(block.height !== -1);
this.hash = block.hash('hex'); this.hash = block.hash('hex');
this.version = block.version; this.version = block.version;
this.prevBlock = block.prevBlock; this.prevBlock = block.prevBlock;
@ -409,9 +407,8 @@ ChainEntry.prototype.fromBlock = function fromBlock(block, prev) {
this.ts = block.ts; this.ts = block.ts;
this.bits = block.bits; this.bits = block.bits;
this.nonce = block.nonce; this.nonce = block.nonce;
this.height = block.height; this.height = prev ? prev.height + 1: 0;
this.chainwork = this.getChainwork(prev); this.chainwork = this.getChainwork(prev);
return this; return this;
}; };

View File

@ -539,11 +539,13 @@ Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
* @returns {Amount} reward * @returns {Amount} reward
*/ */
Block.prototype.getReward = function getReward(view, network) { Block.prototype.getReward = function getReward(view, height, network) {
var i, tx, reward, fee; var i, tx, reward, fee;
assert(typeof height === 'number');
network = Network.get(network); network = Network.get(network);
reward = btcutils.getReward(this.height, network.halvingInterval); reward = btcutils.getReward(height, network.halvingInterval);
for (i = 1; i < this.txs.length; i++) { for (i = 1; i < this.txs.length; i++) {
tx = this.txs[i]; tx = this.txs[i];

View File

@ -1,27 +1,29 @@
'use strict'; 'use strict';
var BN = require('bn.js'); var assert = require('assert');
var bcoin = require('../').set('main'); var fs = require('fs');
var util = bcoin.util; var util = require('../lib/utils/util');
var btcutils = require('../lib/btc/utils'); var btcutils = require('../lib/btc/utils');
var crypto = require('../lib/crypto/crypto'); var crypto = require('../lib/crypto/crypto');
var Bloom = require('../lib/utils/bloom'); var Bloom = require('../lib/utils/bloom');
var Block = require('../lib/primitives/block');
var Headers = require('../lib/primitives/headers');
var MerkleBlock = require('../lib/primitives/merkleblock');
var TX = require('../lib/primitives/tx');
var CoinView = require('../lib/blockchain/coinview'); var CoinView = require('../lib/blockchain/coinview');
var Coin = require('../lib/primitives/coin'); var Coin = require('../lib/primitives/coin');
var constants = bcoin.constants; var constants = require('../lib/protocol/constants');
var network = bcoin.networks;
var assert = require('assert');
var block300025 = require('./data/block300025.json');
var fs = require('fs');
var cmpct = fs.readFileSync(__dirname + '/data/compactblock.hex', 'utf8').trim().split('\n');
var bip152 = require('../lib/net/bip152'); var bip152 = require('../lib/net/bip152');
var block300025 = require('./data/block300025.json');
var cmpct = fs.readFileSync(__dirname + '/data/compactblock.hex', 'utf8').trim().split('\n');
var cmpct2 = fs.readFileSync(__dirname + '/data/cmpct2', 'utf8').trim(); var cmpct2 = fs.readFileSync(__dirname + '/data/cmpct2', 'utf8').trim();
var cmpct2block = fs.readFileSync(__dirname + '/data/cmpct2.bin'); var cmpct2block = fs.readFileSync(__dirname + '/data/cmpct2.bin');
bcoin.cache();
describe('Block', function() { describe('Block', function() {
var mblock = bcoin.merkleblock({ var mblock, raw, block, raw2;
mblock = new MerkleBlock({
version: 2, version: 2,
prevBlock: 'd1831d4411bdfda89d9d8c842b541beafd1437fc560dbe5c0000000000000000', prevBlock: 'd1831d4411bdfda89d9d8c842b541beafd1437fc560dbe5c0000000000000000',
merkleRoot: '28bec1d35af480ba3884553d72694f6ba6c163a5c081d7e6edaec15f373f19af', merkleRoot: '28bec1d35af480ba3884553d72694f6ba6c163a5c081d7e6edaec15f373f19af',
@ -43,10 +45,9 @@ describe('Block', function() {
], ],
flags: new Buffer([245, 122, 0]) flags: new Buffer([245, 122, 0])
}); });
var raw = mblock.toRaw().toString('hex'); raw = mblock.toRaw().toString('hex');
var block;
var raw2 = '02000000d1831d4411bdfda89d9d8c842b541beafd1437fc560dbe5c0' raw2 = '02000000d1831d4411bdfda89d9d8c842b541beafd1437fc560dbe5c0'
+ '00000000000000028bec1d35af480ba3884553d72694f6ba6c163a5c081d7e6edaec' + '00000000000000028bec1d35af480ba3884553d72694f6ba6c163a5c081d7e6edaec'
+ '15f373f19af62ef6d536c890019d0b4bf46cd0100000a7d22e53bce1bbb3294d1a39' + '15f373f19af62ef6d536c890019d0b4bf46cd0100000a7d22e53bce1bbb3294d1a39'
+ '6c5acc45bdcc8f192cb492f0d9f55421fd4c62de19d6d585fdaf3737b9a54aaee1dd' + '6c5acc45bdcc8f192cb492f0d9f55421fd4c62de19d6d585fdaf3737b9a54aaee1dd'
@ -60,7 +61,7 @@ describe('Block', function() {
+ '056c6d56433825657ba32afe269819f01993bd77baba86379043168c94845d32370e' + '056c6d56433825657ba32afe269819f01993bd77baba86379043168c94845d32370e'
+ '5356203f57a00'; + '5356203f57a00';
var mblock = bcoin.merkleblock.fromRaw(raw2, 'hex'); mblock = MerkleBlock.fromRaw(raw2, 'hex');
this.timeout(10000); this.timeout(10000);
@ -80,26 +81,26 @@ describe('Block', function() {
}); });
it('should decode/encode with parser/framer', function() { it('should decode/encode with parser/framer', function() {
var b = bcoin.merkleblock.fromRaw(raw, 'hex'); var b = MerkleBlock.fromRaw(raw, 'hex');
assert.equal(b.toRaw().toString('hex'), raw); assert.equal(b.toRaw().toString('hex'), raw);
assert.equal(raw, raw2); assert.equal(raw, raw2);
}); });
it('should be verifiable', function() { it('should be verifiable', function() {
var b = bcoin.merkleblock.fromRaw(raw, 'hex'); var b = MerkleBlock.fromRaw(raw, 'hex');
assert(b.verify()); assert(b.verify());
}); });
it('should be serialized and deserialized and still verify', function() { it('should be serialized and deserialized and still verify', function() {
var raw = mblock.toRaw(); var raw = mblock.toRaw();
var b = bcoin.merkleblock.fromRaw(raw); var b = MerkleBlock.fromRaw(raw);
assert.deepEqual(b.toRaw(), raw); assert.deepEqual(b.toRaw(), raw);
assert(b.verify()); assert(b.verify());
}); });
it('should be jsonified and unjsonified and still verify', function() { it('should be jsonified and unjsonified and still verify', function() {
var raw = mblock.toJSON(); var raw = mblock.toJSON();
var b = bcoin.merkleblock.fromJSON(raw); var b = MerkleBlock.fromJSON(raw);
assert.deepEqual(b.toJSON(), raw); assert.deepEqual(b.toJSON(), raw);
assert(b.verify()); assert(b.verify());
}); });
@ -123,7 +124,7 @@ describe('Block', function() {
}); });
it('should parse JSON', function() { it('should parse JSON', function() {
block = bcoin.block.fromJSON(block300025); block = Block.fromJSON(block300025);
assert.equal(block.hash('hex'), assert.equal(block.hash('hex'),
'8cc72c02a958de5a8b35a23bb7e3bced8bf840cc0a4e1c820000000000000000'); '8cc72c02a958de5a8b35a23bb7e3bced8bf840cc0a4e1c820000000000000000');
assert.equal(block.rhash(), assert.equal(block.rhash(),
@ -132,53 +133,66 @@ describe('Block', function() {
}); });
it('should create a merkle block', function() { it('should create a merkle block', function() {
var filter = Bloom.fromRate(1000, 0.01, constants.filterFlags.NONE); var filter, item1, item2, mblock2;
var item1 = '8e7445bbb8abd4b3174d80fa4c409fea6b94d96b';
var item2 = '047b00000078da0dca3b0ec2300c00d0ab4466ed10' filter = Bloom.fromRate(1000, 0.01, constants.filterFlags.NONE);
item1 = '8e7445bbb8abd4b3174d80fa4c409fea6b94d96b';
item2 = '047b00000078da0dca3b0ec2300c00d0ab4466ed10'
+ 'e763272c6c9ca052972c69e3884a9022084215e2eef' + 'e763272c6c9ca052972c69e3884a9022084215e2eef'
+ '0e6f781656b5d5a87231cd4349e534b6dea55ad4ff55e'; + '0e6f781656b5d5a87231cd4349e534b6dea55ad4ff55e';
filter.add(item1, 'hex'); filter.add(item1, 'hex');
filter.add(item2, 'hex'); filter.add(item2, 'hex');
var mblock2 = bcoin.merkleblock.fromBlock(block, filter);
mblock2 = MerkleBlock.fromBlock(block, filter);
assert(mblock2.verifyPartial()); assert(mblock2.verifyPartial());
assert.deepEqual(mblock2.toRaw(), mblock.toRaw()); assert.deepEqual(mblock2.toRaw(), mblock.toRaw());
}); });
it('should verify a historical block', function() { it('should verify a historical block', function() {
var view = new CoinView(); var view = new CoinView();
for (var i = 1; i < block300025.txs.length; i++) { var height = block300025.height;
var tx = block300025.txs[i]; var i, j, tx, input, coin, flags;
for (var j = 0; j < tx.inputs.length; j++) {
var input = tx.inputs[j]; for (i = 1; i < block300025.txs.length; i++) {
var coin = Coin.fromJSON(input.coin); tx = block300025.txs[i];
for (j = 0; j < tx.inputs.length; j++) {
input = tx.inputs[j];
coin = Coin.fromJSON(input.coin);
view.addCoin(coin); view.addCoin(coin);
} }
} }
assert(block.verify()); assert(block.verify());
assert(block.txs[0].isCoinbase()); assert(block.txs[0].isCoinbase());
assert(block.txs[0].isSane()); assert(block.txs[0].isSane());
assert(!block.hasWitness()); assert(!block.hasWitness());
assert.equal(block.getWeight(), 1136924); assert.equal(block.getWeight(), 1136924);
var flags = constants.flags.VERIFY_P2SH | constants.flags.VERIFY_DERSIG;
for (var i = 1; i < block.txs.length; i++) { flags = constants.flags.VERIFY_P2SH | constants.flags.VERIFY_DERSIG;
var tx = block.txs[i];
for (i = 1; i < block.txs.length; i++) {
tx = block.txs[i];
assert(tx.isSane()); assert(tx.isSane());
assert(tx.checkInputs(view, block300025.height)); assert(tx.checkInputs(view, block300025.height));
assert(tx.verify(view, flags)); assert(tx.verify(view, flags));
assert(!tx.hasWitness()); assert(!tx.hasWitness());
view.addTX(tx, block300025.height); view.addTX(tx, height);
} }
assert.equal(block.getReward(view), 2507773345);
assert.equal(block.getReward(view), block.txs[0].outputs[0].value); assert.equal(block.getReward(view, height), 2507773345);
assert.equal(block.getReward(view, height), block.txs[0].outputs[0].value);
}); });
it('should fail with a bad merkle root', function() { it('should fail with a bad merkle root', function() {
var block2 = new bcoin.block(block); var block2 = new Block(block);
var ret = {};
block2.hash(); block2.hash();
block2.merkleRoot = constants.NULL_HASH; block2.merkleRoot = constants.NULL_HASH;
block2._valid = null; block2._valid = null;
block2._validHeaders = null; block2._validHeaders = null;
var ret = {};
assert(!block2.verify(ret)); assert(!block2.verify(ret));
assert.equal(ret.reason, 'bad-txnmrklroot'); assert.equal(ret.reason, 'bad-txnmrklroot');
block2._valid = null; block2._valid = null;
@ -189,10 +203,10 @@ describe('Block', function() {
}); });
it('should fail on merkle block with a bad merkle root', function() { it('should fail on merkle block with a bad merkle root', function() {
var mblock2 = new bcoin.merkleblock(mblock); var mblock2 = new MerkleBlock(mblock);
var ret = {};
mblock2.hash(); mblock2.hash();
mblock2.merkleRoot = constants.NULL_HASH; mblock2.merkleRoot = constants.NULL_HASH;
var ret = {};
assert(!mblock2.verify(ret)); assert(!mblock2.verify(ret));
assert.equal(ret.reason, 'bad-txnmrklroot'); assert.equal(ret.reason, 'bad-txnmrklroot');
mblock2._valid = null; mblock2._valid = null;
@ -204,10 +218,10 @@ describe('Block', function() {
}); });
it('should fail with a low target', function() { it('should fail with a low target', function() {
var block2 = new bcoin.block(block); var block2 = new Block(block);
var ret = {};
block2.hash(); block2.hash();
block2.bits = 403014710; block2.bits = 403014710;
var ret = {};
assert(!block2.verify(ret)); assert(!block2.verify(ret));
assert.equal(ret.reason, 'high-hash'); assert.equal(ret.reason, 'high-hash');
block2._valid = null; block2._valid = null;
@ -218,83 +232,90 @@ describe('Block', function() {
}); });
it('should fail on duplicate txs', function() { it('should fail on duplicate txs', function() {
var block2 = new bcoin.block(block); var block2 = new Block(block);
block2.txs.push(block2.txs[block2.txs.length - 1]);
var ret = {}; var ret = {};
block2.txs.push(block2.txs[block2.txs.length - 1]);
assert(!block2.verify(ret)); assert(!block2.verify(ret));
assert.equal(ret.reason, 'bad-txns-duplicate'); assert.equal(ret.reason, 'bad-txns-duplicate');
}); });
it('should verify with headers', function() { it('should verify with headers', function() {
var headers = new bcoin.headers(block); var headers = new Headers(block);
assert(headers.verify()); assert(headers.verify());
}); });
it('should handle compact block', function(cb) { it('should handle compact block', function(cb) {
var cblock = bip152.CompactBlock.fromRaw(cmpct[0], 'hex'); var cblock = bip152.CompactBlock.fromRaw(cmpct[0], 'hex');
var block = bcoin.block.fromRaw(cmpct[1], 'hex'); var block = Block.fromRaw(cmpct[1], 'hex');
var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce); var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce);
var map = {}; var map = {};
var i, tx, mempool, result;
assert.equal(cblock.toRaw().toString('hex'), cmpct[0]); assert.equal(cblock.toRaw().toString('hex'), cmpct[0]);
assert.equal(cblock2.toRaw().toString('hex'), cmpct[0]); assert.equal(cblock2.toRaw().toString('hex'), cmpct[0]);
for (var i = 0; i < block.txs.length; i++) { for (i = 0; i < block.txs.length; i++) {
var tx = block.txs[i]; tx = block.txs[i];
map[tx.hash('hex')] = tx; map[tx.hash('hex')] = tx;
} }
var fakeMempool = { mempool = {
getSnapshot: function(callback) { getSnapshot: function() {
return Object.keys(map); return Object.keys(map);
}, },
getTX: function(hash, callback) { getTX: function(hash) {
return map[hash]; return map[hash];
} }
}; };
assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291); assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291);
var result = cblock.fillMempool(false, fakeMempool); result = cblock.fillMempool(false, mempool);
assert(result); assert(result);
for (var i = 0; i < cblock.available.length; i++)
for (i = 0; i < cblock.available.length; i++)
assert(cblock.available[i]); assert(cblock.available[i]);
assert.equal(cblock.toBlock().toRaw().toString('hex'), block.toRaw().toString('hex'));
assert.equal(
cblock.toBlock().toRaw().toString('hex'),
block.toRaw().toString('hex'));
cb(); cb();
}); });
it('should handle half-full compact block', function(cb) { it('should handle half-full compact block', function(cb) {
var cblock = bip152.CompactBlock.fromRaw(cmpct[0], 'hex'); var cblock = bip152.CompactBlock.fromRaw(cmpct[0], 'hex');
var block = bcoin.block.fromRaw(cmpct[1], 'hex'); var block = Block.fromRaw(cmpct[1], 'hex');
var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce); var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce);
var map = {}; var map = {};
var i, tx, mid, keys, mempool, result, req, res;
assert.equal(cblock.toRaw().toString('hex'), cmpct[0]); assert.equal(cblock.toRaw().toString('hex'), cmpct[0]);
assert.equal(cblock2.toRaw().toString('hex'), cmpct[0]); assert.equal(cblock2.toRaw().toString('hex'), cmpct[0]);
for (var i = 0; i < block.txs.length; i++) { for (i = 0; i < block.txs.length; i++) {
var tx = block.txs[i]; tx = block.txs[i];
map[tx.hash('hex')] = tx; map[tx.hash('hex')] = tx;
} }
var mid = block.txs.length >>> 1; mid = block.txs.length >>> 1;
var keys = Object.keys(map).slice(0, mid); keys = Object.keys(map).slice(0, mid);
var fakeMempool = { mempool = {
getSnapshot: function(callback) { getSnapshot: function() {
return keys; return keys;
}, },
getTX: function(hash, callback) { getTX: function(hash) {
return map[hash]; return map[hash];
} }
}; };
assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291); assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291);
var result = cblock.fillMempool(false, fakeMempool); result = cblock.fillMempool(false, mempool);
assert(!result); assert(!result);
var req = cblock.toRequest(); req = cblock.toRequest();
assert.equal(req.hash, cblock.hash('hex')); assert.equal(req.hash, cblock.hash('hex'));
assert.deepEqual(req.indexes, [5, 6, 7, 8, 9]); assert.deepEqual(req.indexes, [5, 6, 7, 8, 9]);
@ -302,102 +323,107 @@ describe('Block', function() {
assert.equal(req.hash, cblock.hash('hex')); assert.equal(req.hash, cblock.hash('hex'));
assert.deepEqual(req.indexes, [5, 6, 7, 8, 9]); assert.deepEqual(req.indexes, [5, 6, 7, 8, 9]);
var res = bip152.TXResponse.fromBlock(block, req); res = bip152.TXResponse.fromBlock(block, req);
res = bip152.TXResponse.fromRaw(res.toRaw()); res = bip152.TXResponse.fromRaw(res.toRaw());
var result = cblock.fillMissing(res); result = cblock.fillMissing(res);
assert(result); assert(result);
for (var i = 0; i < cblock.available.length; i++) for (i = 0; i < cblock.available.length; i++)
assert(cblock.available[i]); assert(cblock.available[i]);
assert.equal(cblock.toBlock().toRaw().toString('hex'), block.toRaw().toString('hex')); assert.equal(
cblock.toBlock().toRaw().toString('hex'),
block.toRaw().toString('hex'));
cb(); cb();
}); });
it('should handle compact block', function(cb) { it('should handle compact block', function(cb) {
var cblock = bip152.CompactBlock.fromRaw(cmpct2, 'hex'); var cblock = bip152.CompactBlock.fromRaw(cmpct2, 'hex');
var block = bcoin.block.fromRaw(cmpct2block); var block = Block.fromRaw(cmpct2block);
var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce); var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce);
var map = {}; var map = {};
var i, tx, result, mempool;
assert.equal(cblock.toRaw().toString('hex'), cmpct2); assert.equal(cblock.toRaw().toString('hex'), cmpct2);
assert.equal(cblock2.toRaw().toString('hex'), cmpct2); assert.equal(cblock2.toRaw().toString('hex'), cmpct2);
for (var i = 0; i < block.txs.length; i++) { for (i = 0; i < block.txs.length; i++) {
var tx = block.txs[i]; tx = block.txs[i];
map[tx.hash('hex')] = tx; map[tx.hash('hex')] = tx;
} }
var fakeMempool = { mempool = {
getSnapshot: function(callback) { getSnapshot: function() {
return Object.keys(map); return Object.keys(map);
}, },
getTX: function(hash, callback) { getTX: function(hash) {
return map[hash]; return map[hash];
} }
}; };
//assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291); result = cblock.fillMempool(false, mempool);
var result = cblock.fillMempool(false, fakeMempool);
assert(result); assert(result);
for (var i = 0; i < cblock.available.length; i++)
for (i = 0; i < cblock.available.length; i++)
assert(cblock.available[i]); assert(cblock.available[i]);
assert.equal(cblock.toBlock().toRaw().toString('hex'), block.toRaw().toString('hex'));
assert.equal(
cblock.toBlock().toRaw().toString('hex'),
block.toRaw().toString('hex'));
cb(); cb();
}); });
it('should handle half-full compact block', function(cb) { it('should handle half-full compact block', function(cb) {
var cblock = bip152.CompactBlock.fromRaw(cmpct2, 'hex'); var cblock = bip152.CompactBlock.fromRaw(cmpct2, 'hex');
var block = bcoin.block.fromRaw(cmpct2block); var block = Block.fromRaw(cmpct2block);
var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce); var cblock2 = bip152.CompactBlock.fromBlock(block, false, cblock.keyNonce);
var map = {}; var map = {};
var i, tx, mid, keys, mempool, result, req, res;
assert.equal(cblock.toRaw().toString('hex'), cmpct2); assert.equal(cblock.toRaw().toString('hex'), cmpct2);
assert.equal(cblock2.toRaw().toString('hex'), cmpct2); assert.equal(cblock2.toRaw().toString('hex'), cmpct2);
for (var i = 0; i < block.txs.length; i++) { for (i = 0; i < block.txs.length; i++) {
var tx = block.txs[i]; tx = block.txs[i];
map[tx.hash('hex')] = tx; map[tx.hash('hex')] = tx;
} }
var mid = block.txs.length >>> 1; mid = block.txs.length >>> 1;
var keys = Object.keys(map).slice(0, mid); keys = Object.keys(map).slice(0, mid);
var fakeMempool = { mempool = {
getSnapshot: function(callback) { getSnapshot: function() {
return keys; return keys;
}, },
getTX: function(hash, callback) { getTX: function(hash) {
return map[hash]; return map[hash];
} }
}; };
//assert.equal(cblock.sid(block.txs[1].hash()), 125673511480291); result = cblock.fillMempool(false, mempool);
var result = cblock.fillMempool(false, fakeMempool);
assert(!result); assert(!result);
var req = cblock.toRequest(); req = cblock.toRequest();
assert.equal(req.hash, cblock.hash('hex')); assert.equal(req.hash, cblock.hash('hex'));
//assert.deepEqual(req.indexes, [5, 6, 7, 8, 9]);
req = bip152.TXRequest.fromRaw(req.toRaw()); req = bip152.TXRequest.fromRaw(req.toRaw());
assert.equal(req.hash, cblock.hash('hex')); assert.equal(req.hash, cblock.hash('hex'));
//assert.deepEqual(req.indexes, [5, 6, 7, 8, 9]);
var res = bip152.TXResponse.fromBlock(block, req); res = bip152.TXResponse.fromBlock(block, req);
res = bip152.TXResponse.fromRaw(res.toRaw()); res = bip152.TXResponse.fromRaw(res.toRaw());
var result = cblock.fillMissing(res); result = cblock.fillMissing(res);
assert(result); assert(result);
for (var i = 0; i < cblock.available.length; i++) for (i = 0; i < cblock.available.length; i++)
assert(cblock.available[i]); assert(cblock.available[i]);
assert.equal(cblock.toBlock().toRaw().toString('hex'), block.toRaw().toString('hex')); assert.equal(
cblock.toBlock().toRaw().toString('hex'),
block.toRaw().toString('hex'));
cb(); cb();
}); });

View File

@ -1,25 +1,41 @@
'use strict'; 'use strict';
var bcoin = require('../').set('main');
var assert = require('assert'); var assert = require('assert');
var Script = bcoin.script; var Script = require('../lib/script/script');
var Stack = bcoin.stack; var Witness = require('../lib/script/witness');
var util = bcoin.util; var Stack = require('../lib/script/stack');
var TX = require('../lib/primitives/tx');
var util = require('../lib/utils/util');
var crypto = require('../lib/crypto/crypto'); var crypto = require('../lib/crypto/crypto');
var constants = bcoin.constants; var constants = require('../lib/protocol/constants');
var opcodes = bcoin.constants.opcodes; var opcodes = constants.opcodes;
var scripts = require('./data/script_tests'); var scripts = require('./data/script_tests');
var BN = require('bn.js');
function success(res, stack) {
if (!res)
return false;
if (stack.length === 0)
return false;
if (!Script.bool(stack.top(-1)))
return false;
return true;
}
describe('Script', function() { describe('Script', function() {
it('should encode/decode script', function() { it('should encode/decode script', function() {
var src = '20' var src, decoded, dst;
src = '20'
+ '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f' + '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'
+ '20' + '20'
+ '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f' + '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f'
+ 'ac'; + 'ac';
var decoded = bcoin.script(new Buffer(src, 'hex')); decoded = Script.fromRaw(src, 'hex');
assert.equal(decoded.code.length, 3); assert.equal(decoded.code.length, 3);
assert.equal(decoded.code[0].data.toString('hex'), assert.equal(decoded.code[0].data.toString('hex'),
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'); '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');
@ -27,33 +43,36 @@ describe('Script', function() {
'101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f'); '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f');
assert.equal(decoded.code[2].value, opcodes.OP_CHECKSIG); assert.equal(decoded.code[2].value, opcodes.OP_CHECKSIG);
var dst = decoded.toRaw(); dst = decoded.toRaw();
assert.equal(dst.toString('hex'), src); assert.equal(dst.toString('hex'), src);
}); });
it('should encode/decode numbers', function() { it('should encode/decode numbers', function() {
var script = [0, 0x51, 0x52, 0x60]; var script = [0, 0x51, 0x52, 0x60];
var encoded = bcoin.script.fromArray(script).raw; var encoded = Script.fromArray(script).raw;
var decoded = bcoin.script(encoded).toArray(); var decoded = Script(encoded).toArray();
assert.deepEqual(decoded, script); assert.deepEqual(decoded, script);
}); });
it('should recognize a P2SH output', function() { it('should recognize a P2SH output', function() {
var hex = 'a91419a7d869032368fd1f1e26e5e73a4ad0e474960e87'; var hex = 'a91419a7d869032368fd1f1e26e5e73a4ad0e474960e87';
var decoded = bcoin.script.fromRaw(hex, 'hex'); var decoded = Script.fromRaw(hex, 'hex');
assert(decoded.isScripthash()); assert(decoded.isScripthash());
}); });
it('should recognize a Null Data output', function() { it('should recognize a Null Data output', function() {
var hex = '6a28590c080112220a1b353930632e6f7267282a5f' var hex = '6a28590c080112220a1b353930632e6f7267282a5f'
+ '5e294f7665726c6179404f7261636c65103b1a010c'; + '5e294f7665726c6179404f7261636c65103b1a010c';
var decoded = bcoin.script.fromRaw(hex, 'hex'); var decoded = Script.fromRaw(hex, 'hex');
assert(decoded.isNulldata()); assert(decoded.isNulldata());
}); });
it('should handle if statements correctly', function() { it('should handle if statements correctly', function() {
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); var input, output, stack, res;
var prevOutScript = new Script([
input = new Script([opcodes.OP_1, opcodes.OP_2]);
output = new Script([
opcodes.OP_2, opcodes.OP_2,
opcodes.OP_EQUAL, opcodes.OP_EQUAL,
opcodes.OP_IF, opcodes.OP_IF,
@ -63,14 +82,18 @@ describe('Script', function() {
opcodes.OP_ENDIF, opcodes.OP_ENDIF,
opcodes.OP_5 opcodes.OP_5
]); ]);
var stack = new Stack();
inputScript.execute(stack); stack = new Stack();
var res = prevOutScript.execute(stack);
input.execute(stack);
res = output.execute(stack);
assert(res); assert(res);
assert.deepEqual(stack.items, [[1], [3], [5]]); assert.deepEqual(stack.items, [[1], [3], [5]]);
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); input = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([ output = new Script([
opcodes.OP_9, opcodes.OP_9,
opcodes.OP_EQUAL, opcodes.OP_EQUAL,
opcodes.OP_IF, opcodes.OP_IF,
@ -80,14 +103,16 @@ describe('Script', function() {
opcodes.OP_ENDIF, opcodes.OP_ENDIF,
opcodes.OP_5 opcodes.OP_5
]); ]);
var stack = new Stack();
inputScript.execute(stack); stack = new Stack();
var res = prevOutScript.execute(stack); input.execute(stack);
res = output.execute(stack);
assert(res); assert(res);
assert.deepEqual(stack.items, [[1], [4], [5]]); assert.deepEqual(stack.items, [[1], [4], [5]]);
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); input = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([ output = new Script([
opcodes.OP_2, opcodes.OP_2,
opcodes.OP_EQUAL, opcodes.OP_EQUAL,
opcodes.OP_IF, opcodes.OP_IF,
@ -95,14 +120,17 @@ describe('Script', function() {
opcodes.OP_ENDIF, opcodes.OP_ENDIF,
opcodes.OP_5 opcodes.OP_5
]); ]);
var stack = new Stack();
inputScript.execute(stack); stack = new Stack();
var res = prevOutScript.execute(stack);
input.execute(stack);
res = output.execute(stack);
assert(res); assert(res);
assert.deepEqual(stack.items, [[1], [3], [5]]); assert.deepEqual(stack.items, [[1], [3], [5]]);
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); input = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([ output = new Script([
opcodes.OP_9, opcodes.OP_9,
opcodes.OP_EQUAL, opcodes.OP_EQUAL,
opcodes.OP_IF, opcodes.OP_IF,
@ -110,14 +138,16 @@ describe('Script', function() {
opcodes.OP_ENDIF, opcodes.OP_ENDIF,
opcodes.OP_5 opcodes.OP_5
]); ]);
var stack = new Stack();
inputScript.execute(stack); stack = new Stack();
var res = prevOutScript.execute(stack); input.execute(stack);
res = output.execute(stack);
assert(res); assert(res);
assert.deepEqual(stack.items, [[1], [5]]); assert.deepEqual(stack.items, [[1], [5]]);
var inputScript = new Script([opcodes.OP_1, opcodes.OP_2]); input = new Script([opcodes.OP_1, opcodes.OP_2]);
var prevOutScript = new Script([ output = new Script([
opcodes.OP_9, opcodes.OP_9,
opcodes.OP_EQUAL, opcodes.OP_EQUAL,
opcodes.OP_NOTIF, opcodes.OP_NOTIF,
@ -125,138 +155,66 @@ describe('Script', function() {
opcodes.OP_ENDIF, opcodes.OP_ENDIF,
opcodes.OP_5 opcodes.OP_5
]); ]);
var stack = new Stack(); stack = new Stack();
inputScript.execute(stack); input.execute(stack);
var res = prevOutScript.execute(stack);
res = output.execute(stack);
assert(res); assert(res);
assert.deepEqual(stack.items, [[1], [3], [5]]); assert.deepEqual(stack.items, [[1], [3], [5]]);
}); });
function success(res, stack) {
if (!res)
return false;
if (stack.length === 0)
return false;
if (!bcoin.script.bool(stack.pop()))
return false;
return true;
}
/*
it('should handle bad size pushes correctly.', function() {
var err;
var stack = new bcoin.stack();
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA1'
);
assert(util.equal(s.raw, new Buffer('51764c', 'hex')));
delete s.raw;
assert(util.equal(s.encode(), new Buffer('51764c', 'hex')));
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA2 0x01'
);
assert(util.equal(s.raw, new Buffer('51764d01', 'hex')));
delete s.raw;
assert(util.equal(s.encode(), new Buffer('51764d01', 'hex')));
err = null;
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA4 0x0001'
);
assert(util.equal(s.raw, new Buffer('51764e0001', 'hex')));
delete s.raw;
assert(util.equal(s.encode(), new Buffer('51764e0001', 'hex')));
err = null;
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA1 0x02 0x01'
);
assert(util.equal(s.raw, new Buffer('51764c0201', 'hex')));
delete s.raw;
assert(util.equal(s.encode(), new Buffer('51764c0201', 'hex')));
err = null;
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA2 0x0200 0x01'
);
assert(util.equal(s.raw, new Buffer('51764d020001', 'hex')));
delete s.raw;
assert(util.equal(s.encode(), new Buffer('51764d020001', 'hex')));
err = null;
try {
s.execute(stack);
} catch (e) {
err = e;
}
assert(err);
assert(err.code === 'BAD_OPCODE');
});
*/
it('should handle CScriptNums correctly', function() { it('should handle CScriptNums correctly', function() {
var s = new bcoin.script([ var s1, s2, stack;
s1 = new Script([
new Buffer([0xff, 0xff, 0xff, 0x7f]), new Buffer([0xff, 0xff, 0xff, 0x7f]),
opcodes.OP_NEGATE, opcodes.OP_NEGATE,
opcodes.OP_DUP, opcodes.OP_DUP,
opcodes.OP_ADD opcodes.OP_ADD
]); ]);
var s2 = new bcoin.script([
s2 = new Script([
new Buffer([0xfe, 0xff, 0xff, 0xff, 0x80]), new Buffer([0xfe, 0xff, 0xff, 0xff, 0x80]),
opcodes.OP_EQUAL opcodes.OP_EQUAL
]); ]);
var stack = new bcoin.stack();
assert(s.execute(stack)); stack = new Stack();
assert(s1.execute(stack));
assert(success(s2.execute(stack), stack)); assert(success(s2.execute(stack), stack));
}); });
it('should handle CScriptNums correctly', function() { it('should handle CScriptNums correctly', function() {
var s = new bcoin.script([ var s1, s2, stack;
s1 = new Script([
opcodes.OP_11, opcodes.OP_11,
opcodes.OP_10, opcodes.OP_10,
opcodes.OP_1, opcodes.OP_1,
opcodes.OP_ADD opcodes.OP_ADD
]); ]);
var s2 = new bcoin.script([
s2 = new Script([
opcodes.OP_NUMNOTEQUAL, opcodes.OP_NUMNOTEQUAL,
opcodes.OP_NOT opcodes.OP_NOT
]); ]);
var stack = new bcoin.stack();
assert(s.execute(stack)); stack = new Stack();
assert(s1.execute(stack));
assert(success(s2.execute(stack), stack)); assert(success(s2.execute(stack), stack));
}); });
it('should handle OP_ROLL correctly', function() { it('should handle OP_ROLL correctly', function() {
var s = new bcoin.script([ var s1, s2, stack;
s1 = new Script([
new Buffer([0x16]), new Buffer([0x16]),
new Buffer([0x15]), new Buffer([0x15]),
new Buffer([0x14]) new Buffer([0x14])
]); ]);
var s2 = new bcoin.script([
s2 = new Script([
opcodes.OP_0, opcodes.OP_0,
opcodes.OP_ROLL, opcodes.OP_ROLL,
new Buffer([0x14]), new Buffer([0x14]),
@ -265,13 +223,14 @@ describe('Script', function() {
opcodes.OP_2, opcodes.OP_2,
opcodes.OP_EQUAL opcodes.OP_EQUAL
]); ]);
var stack = new bcoin.stack();
assert(s.execute(stack)); stack = new Stack();
assert(s1.execute(stack));
assert(success(s2.execute(stack), stack)); assert(success(s2.execute(stack), stack));
}); });
scripts.forEach(function(data) { scripts.forEach(function(data) {
// ["Format is: [[wit...]?, scriptSig, scriptPubKey, flags, expected_scripterror, ... comments]"],
var witness = Array.isArray(data[0]) ? data.shift() : []; var witness = Array.isArray(data[0]) ? data.shift() : [];
var input = data[0] ? data[0].trim() : data[0] || ''; var input = data[0] ? data[0].trim() : data[0] || '';
var output = data[1] ? data[1].trim() : data[1] || ''; var output = data[1] ? data[1].trim() : data[1] || '';
@ -293,9 +252,9 @@ describe('Script', function() {
if (witness.length !== 0) if (witness.length !== 0)
amount = witness.pop() * 100000000; amount = witness.pop() * 100000000;
witness = bcoin.witness.fromString(witness); witness = Witness.fromString(witness);
input = bcoin.script.fromString(input); input = Script.fromString(input);
output = bcoin.script.fromString(output); output = Script.fromString(output);
for (i = 0; i < flags.length; i++) { for (i = 0; i < flags.length; i++) {
name = 'VERIFY_' + flags[i]; name = 'VERIFY_' + flags[i];
@ -311,7 +270,7 @@ describe('Script', function() {
var prev, tx, err, res; var prev, tx, err, res;
// Funding transaction. // Funding transaction.
prev = bcoin.tx({ prev = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [{ inputs: [{
@ -319,8 +278,8 @@ describe('Script', function() {
hash: constants.NULL_HASH, hash: constants.NULL_HASH,
index: 0xffffffff index: 0xffffffff
}, },
script: [bcoin.script.array(0), bcoin.script.array(0)], script: [Script.array(0), Script.array(0)],
witness: new bcoin.witness(), witness: new Witness(),
sequence: 0xffffffff sequence: 0xffffffff
}], }],
outputs: [{ outputs: [{
@ -331,7 +290,7 @@ describe('Script', function() {
}); });
// Spending transaction. // Spending transaction.
tx = bcoin.tx({ tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [{ inputs: [{
@ -344,7 +303,7 @@ describe('Script', function() {
sequence: 0xffffffff sequence: 0xffffffff
}], }],
outputs: [{ outputs: [{
script: new bcoin.script(), script: new Script(),
value: amount value: amount
}], }],
locktime: 0 locktime: 0
@ -392,158 +351,4 @@ describe('Script', function() {
}); });
}); });
}); });
/*
it('should execute FindAndDelete correctly', function() {
var s, d, expect;
function del(s) {
s.mutable = true;
return s;
}
s = bcoin.script.fromString('OP_1 OP_2');
del(s);
d = new bcoin.script();
expect = s.clone();
assert.equal(s.findAndDelete(d.encode()), 0);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromString('OP_1 OP_2 OP_3');
del(s);
d = bcoin.script.fromString('OP_2');
del(d);
expect = bcoin.script.fromString('OP_1 OP_3');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromString('OP_3 OP_1 OP_3 OP_3 OP_4 OP_3');
del(s);
d = bcoin.script.fromString('OP_3');
del(d);
expect = bcoin.script.fromString('OP_1 OP_4');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 4);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('0302ff03', 'hex');
del(d);
expect = new bcoin.script();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('0302ff03', 'hex');
del(d);
expect = new bcoin.script();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 2);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('02', 'hex');
del(d);
expect = s.clone();
del(expect);
//assert.equal(s.findAndDelete(d.encode()), 0);
s.findAndDelete(d.encode());
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('ff', 'hex');
del(d);
expect = s.clone();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 0);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0302ff030302ff03', 'hex');
del(s);
d = bcoin.script.fromRaw('03', 'hex');
del(d);
expect = new bcoin.script([new Buffer([0xff, 0x03]), new Buffer([0xff, 0x03])]);
del(expect);
assert.equal(s.findAndDelete(d.encode()), 2);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('02feed5169', 'hex');
del(s);
d = bcoin.script.fromRaw('feed51', 'hex');
del(d);
expect = s.clone();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 0);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('02feed5169', 'hex');
del(s);
d = bcoin.script.fromRaw('02feed51', 'hex');
del(d);
expect = bcoin.script.fromRaw('69', 'hex');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('516902feed5169', 'hex');
del(s);
d = bcoin.script.fromRaw('feed51', 'hex');
del(d);
expect = s.clone();
del(expect);
assert.equal(s.findAndDelete(d.encode()), 0);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('516902feed5169', 'hex');
del(s);
d = bcoin.script.fromRaw('02feed51', 'hex');
del(d);
expect = bcoin.script.fromRaw('516969', 'hex');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromString('OP_0 OP_0 OP_1 OP_1');
del(s);
d = bcoin.script.fromString('OP_0 OP_1');
del(d);
expect = bcoin.script.fromString('OP_0 OP_1');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromString('OP_0 OP_0 OP_1 OP_0 OP_1 OP_1');
del(s);
d = bcoin.script.fromString('OP_0 OP_1');
del(d);
expect = bcoin.script.fromString('OP_0 OP_1');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 2);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0003feed', 'hex');
del(s);
d = bcoin.script.fromRaw('03feed', 'hex');
del(d);
expect = bcoin.script.fromRaw('00', 'hex');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
s = bcoin.script.fromRaw('0003feed', 'hex');
del(s);
d = bcoin.script.fromRaw('00', 'hex');
del(d);
expect = bcoin.script.fromRaw('03feed', 'hex');
del(expect);
assert.equal(s.findAndDelete(d.encode()), 1);
assert.deepEqual(s.encode(), expect.encode());
});
*/
}); });

View File

@ -1,18 +1,22 @@
'use strict'; 'use strict';
var BN = require('bn.js'); var fs = require('fs');
var bcoin = require('../').set('main');
var assert = require('assert'); var assert = require('assert');
var util = bcoin.util; var util = require('../lib/utils/util');
var encoding = require('../lib/utils/encoding'); var encoding = require('../lib/utils/encoding');
var crypto = require('../lib/crypto/crypto'); var crypto = require('../lib/crypto/crypto');
var constants = bcoin.constants; var constants = require('../lib/protocol/constants');
var opcodes = bcoin.constants.opcodes; var Network = require('../lib/protocol/network');
var TX = require('../lib/primitives/tx');
var Block = require('../lib/primitives/block');
var Coin = require('../lib/primitives/coin');
var Output = require('../lib/primitives/output');
var Script = require('../lib/script/script');
var CoinView = require('../lib/blockchain/coinview');
var valid = require('./data/tx_valid.json'); var valid = require('./data/tx_valid.json');
var invalid = require('./data/tx_invalid.json'); var invalid = require('./data/tx_invalid.json');
var sighash = require('./data/sighash.json'); var sighash = require('./data/sighash.json');
var fs = require('fs');
var CoinView = require('../lib/blockchain/coinview');
var tx1 = parseTX('data/tx1.hex'); var tx1 = parseTX('data/tx1.hex');
var tx2 = parseTX('data/tx2.hex'); var tx2 = parseTX('data/tx2.hex');
var tx3 = parseTX('data/tx3.hex'); var tx3 = parseTX('data/tx3.hex');
@ -24,13 +28,13 @@ function parseTX(file) {
var data = fs.readFileSync(__dirname + '/' + file, 'utf8'); var data = fs.readFileSync(__dirname + '/' + file, 'utf8');
var parts = data.trim().split(/\n+/); var parts = data.trim().split(/\n+/);
var raw = parts[0]; var raw = parts[0];
var tx = bcoin.tx.fromRaw(raw.trim(), 'hex'); var tx = TX.fromRaw(raw.trim(), 'hex');
var view = new CoinView(); var view = new CoinView();
var i, prev; var i, prev;
for (i = 1; i < parts.length; i++) { for (i = 1; i < parts.length; i++) {
raw = parts[i]; raw = parts[i];
prev = bcoin.tx.fromRaw(raw.trim(), 'hex'); prev = TX.fromRaw(raw.trim(), 'hex');
view.addTX(prev, -1); view.addTX(prev, -1);
} }
@ -56,6 +60,56 @@ function clearCache(tx, nocache) {
tx._hashOutputs = null; tx._hashOutputs = null;
} }
function parseTest(data) {
var coins = data[0];
var tx = TX.fromRaw(data[1], 'hex');
var flags = data[2] ? data[2].trim().split(/,\s*/) : [];
var view = new CoinView();
var flag = 0;
var i, name, coin;
for (i = 0; i < flags.length; i++) {
name = 'VERIFY_' + flags[i];
assert(constants.flags[name] != null, 'Unknown flag.');
flag |= constants.flags[name];
}
flags = flag;
coins.forEach(function(data) {
var hash = data[0];
var index = data[1];
var script = Script.fromString(data[2]);
var value = data[3];
var coin;
coin = new Coin({
version: 1,
height: -1,
coinbase: false,
hash: util.revHex(hash),
index: index,
script: script,
value: value != null ? parseInt(value, 10) : 0
});
if (index !== -1)
view.addCoin(coin);
});
coin = view.getOutput(tx.inputs[0]);
return {
tx: tx,
flags: flags,
view: view,
comments: coin
? util.inspectify(coin.script, false)
: 'coinbase',
data: data
};
}
describe('TX', function() { describe('TX', function() {
var raw = '010000000125393c67cd4f581456dd0805fa8e9db3abdf90dbe1d4b53e28' + var raw = '010000000125393c67cd4f581456dd0805fa8e9db3abdf90dbe1d4b53e28' +
'6490f35d22b6f2010000006b483045022100f4fa5ced20d2dbd2f905809d' + '6490f35d22b6f2010000006b483045022100f4fa5ced20d2dbd2f905809d' +
@ -98,14 +152,14 @@ describe('TX', function() {
var suffix = nocache ? ' without cache' : ' with cache'; var suffix = nocache ? ' without cache' : ' with cache';
it('should decode/encode with parser/framer' + suffix, function() { it('should decode/encode with parser/framer' + suffix, function() {
var tx = bcoin.tx.fromRaw(raw, 'hex'); var tx = TX.fromRaw(raw, 'hex');
clearCache(tx, nocache); clearCache(tx, nocache);
assert.equal(tx.toRaw().toString('hex'), raw); assert.equal(tx.toRaw().toString('hex'), raw);
}); });
it('should be verifiable' + suffix, function() { it('should be verifiable' + suffix, function() {
var tx = bcoin.tx.fromRaw(raw, 'hex'); var tx = TX.fromRaw(raw, 'hex');
var p = bcoin.tx.fromRaw(inp, 'hex'); var p = TX.fromRaw(inp, 'hex');
var view = new CoinView(); var view = new CoinView();
view.addTX(p, -1); view.addTX(p, -1);
@ -163,63 +217,14 @@ describe('TX', function() {
raw2 = wtx.tx.toRaw(); raw2 = wtx.tx.toRaw();
assert.deepEqual(raw1, raw2); assert.deepEqual(raw1, raw2);
wtx2 = bcoin.tx.fromRaw(raw2); wtx2 = TX.fromRaw(raw2);
clearCache(wtx2, nocache); clearCache(wtx2, nocache);
assert.equal(wtx.tx.hash('hex'), wtx2.hash('hex')); assert.equal(wtx.tx.hash('hex'), wtx2.hash('hex'));
assert.equal(wtx.tx.witnessHash('hex'), wtx2.witnessHash('hex')); assert.equal(wtx.tx.witnessHash('hex'), wtx2.witnessHash('hex'));
}); });
function parseTest(data) {
var coins = data[0];
var tx = bcoin.tx.fromRaw(data[1], 'hex');
var flags = data[2] ? data[2].trim().split(/,\s*/) : [];
var view = new CoinView();
var flag = 0;
var i, name;
for (i = 0; i < flags.length; i++) {
name = 'VERIFY_' + flags[i];
assert(constants.flags[name] != null, 'Unknown flag.');
flag |= constants.flags[name];
}
flags = flag;
coins.forEach(function(data) {
var hash = data[0];
var index = data[1];
var script = bcoin.script.fromString(data[2]);
var value = data[3];
var coin;
coin = new bcoin.coin({
version: 1,
height: -1,
coinbase: false,
hash: util.revHex(hash),
index: index,
script: script,
value: value != null ? parseInt(value, 10) : 0
});
if (index !== -1)
view.addCoin(coin);
});
return {
tx: tx,
flags: flags,
view: view,
comments: tx.hasCoins(view)
? util.inspectify(view.getOutput(tx.inputs[0]).script, false)
: 'coinbase',
data: data
};
}
[[valid, true], [invalid, false]].forEach(function(test) { [[valid, true], [invalid, false]].forEach(function(test) {
// ["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
var arr = test[0]; var arr = test[0];
var valid = test[1]; var valid = test[1];
var comment = ''; var comment = '';
@ -296,15 +301,13 @@ describe('TX', function() {
sighash.forEach(function(data) { sighash.forEach(function(data) {
var tx, script, index, type, expected, hexType; var tx, script, index, type, expected, hexType;
// ["raw_transaction, script, input_index, hashType, signature_hash (result)"],
if (data.length === 1) if (data.length === 1)
return; return;
tx = bcoin.tx.fromRaw(data[0], 'hex'); tx = TX.fromRaw(data[0], 'hex');
clearCache(tx, nocache); clearCache(tx, nocache);
script = bcoin.script.fromRaw(data[1], 'hex'); script = Script.fromRaw(data[1], 'hex');
index = data[2]; index = data[2];
type = data[3]; type = data[3];
@ -327,33 +330,25 @@ describe('TX', function() {
}); });
}); });
function createInput(value) { function createInput(value, view) {
var hash = crypto.randomBytes(32).toString('hex'); var hash = crypto.randomBytes(32).toString('hex');
var output = new Output();
output.value = value;
view.addOutput(hash, 0, output);
return { return {
prevout: { prevout: {
hash: hash, hash: hash,
index: 0 index: 0
}, }
coin: {
version: 1,
height: 0,
value: value,
script: [],
coinbase: false,
hash: hash,
index: 0
},
script: [],
witness: [],
sequence: 0xffffffff
}; };
} }
it('should fail on >51 bit coin values', function() { it('should fail on >51 bit coin values', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(constants.MAX_MONEY + 1)], inputs: [createInput(constants.MAX_MONEY + 1, view)],
outputs: [{ outputs: [{
script: [], script: [],
value: constants.MAX_MONEY value: constants.MAX_MONEY
@ -361,14 +356,15 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should handle 51 bit coin values', function() { it('should handle 51 bit coin values', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(constants.MAX_MONEY)], inputs: [createInput(constants.MAX_MONEY, view)],
outputs: [{ outputs: [{
script: [], script: [],
value: constants.MAX_MONEY value: constants.MAX_MONEY
@ -376,14 +372,15 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(tx.checkInputs(view, 0)); assert.ok(tx.checkInputs(view, 0));
}); });
it('should fail on >51 bit output values', function() { it('should fail on >51 bit output values', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(constants.MAX_MONEY)], inputs: [createInput(constants.MAX_MONEY, view)],
outputs: [{ outputs: [{
script: [], script: [],
value: constants.MAX_MONEY + 1 value: constants.MAX_MONEY + 1
@ -391,14 +388,15 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(!tx.isSane()); assert.ok(!tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should handle 51 bit output values', function() { it('should handle 51 bit output values', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(constants.MAX_MONEY)], inputs: [createInput(constants.MAX_MONEY, view)],
outputs: [{ outputs: [{
script: [], script: [],
value: constants.MAX_MONEY value: constants.MAX_MONEY
@ -406,14 +404,15 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(tx.checkInputs(view, 0)); assert.ok(tx.checkInputs(view, 0));
}); });
it('should fail on >51 bit fees', function() { it('should fail on >51 bit fees', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(constants.MAX_MONEY + 1)], inputs: [createInput(constants.MAX_MONEY + 1, view)],
outputs: [{ outputs: [{
script: [], script: [],
value: 0 value: 0
@ -421,17 +420,18 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on >51 bit values from multiple', function() { it('should fail on >51 bit values from multiple', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [ inputs: [
createInput(Math.floor(constants.MAX_MONEY / 2)), createInput(Math.floor(constants.MAX_MONEY / 2), view),
createInput(Math.floor(constants.MAX_MONEY / 2)), createInput(Math.floor(constants.MAX_MONEY / 2), view),
createInput(Math.floor(constants.MAX_MONEY / 2)) createInput(Math.floor(constants.MAX_MONEY / 2), view)
], ],
outputs: [{ outputs: [{
script: [], script: [],
@ -440,14 +440,15 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on >51 bit output values from multiple', function() { it('should fail on >51 bit output values from multiple', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(constants.MAX_MONEY)], inputs: [createInput(constants.MAX_MONEY, view)],
outputs: [ outputs: [
{ {
script: [], script: [],
@ -465,17 +466,18 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(!tx.isSane()); assert.ok(!tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on >51 bit fees from multiple', function() { it('should fail on >51 bit fees from multiple', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [ inputs: [
createInput(Math.floor(constants.MAX_MONEY / 2)), createInput(Math.floor(constants.MAX_MONEY / 2), view),
createInput(Math.floor(constants.MAX_MONEY / 2)), createInput(Math.floor(constants.MAX_MONEY / 2), view),
createInput(Math.floor(constants.MAX_MONEY / 2)) createInput(Math.floor(constants.MAX_MONEY / 2), view)
], ],
outputs: [{ outputs: [{
script: [], script: [],
@ -484,18 +486,21 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on >51 bit fees from multiple txs', function() { it('should fail on >51 bit fees from multiple txs', function() {
var data = util.merge({}, bcoin.network.get().genesis, { height: 0 }); var view = new CoinView();
var block = new bcoin.block(data); var genesis = Network.get().genesis;
for (var i = 0; i < 3; i++) { var block = new Block(genesis);
var tx = bcoin.tx({ var i, tx;
for (i = 0; i < 3; i++) {
tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [ inputs: [
createInput(Math.floor(constants.MAX_MONEY / 2)) createInput(Math.floor(constants.MAX_MONEY / 2), view)
], ],
outputs: [{ outputs: [{
script: [], script: [],
@ -503,17 +508,22 @@ describe('TX', function() {
}], }],
locktime: 0 locktime: 0
}); });
block.txs.push(tx); block.txs.push(tx);
} }
// assert.equal(block.getReward(), -1);
assert.equal(block.getReward(view, 0), -1);
}); });
it('should fail to parse >53 bit values', function() { it('should fail to parse >53 bit values', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx, raw;
tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [ inputs: [
createInput(Math.floor(constants.MAX_MONEY / 2)) createInput(Math.floor(constants.MAX_MONEY / 2), view)
], ],
outputs: [{ outputs: [{
script: [], script: [],
@ -521,27 +531,30 @@ describe('TX', function() {
}], }],
locktime: 0 locktime: 0
}); });
var raw = tx.toRaw();
raw = tx.toRaw();
assert(encoding.readU64(raw, 47) === 0xdeadbeef); assert(encoding.readU64(raw, 47) === 0xdeadbeef);
raw[54] = 0x7f; raw[54] = 0x7f;
assert.throws(function() { assert.throws(function() {
bcoin.tx.fromRaw(raw); TX.fromRaw(raw);
}); });
tx._raw = null; tx._raw = null;
tx.outputs[0].value = 0; tx.outputs[0].value = 0;
var raw = tx.toRaw();
raw = tx.toRaw();
assert(encoding.readU64(raw, 47) === 0x00); assert(encoding.readU64(raw, 47) === 0x00);
raw[54] = 0x80; raw[54] = 0x80;
assert.throws(function() { assert.throws(function() {
bcoin.tx.fromRaw(raw); TX.fromRaw(raw);
}); });
}); });
it('should fail on 53 bit coin values', function() { it('should fail on 53 bit coin values', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(util.MAX_SAFE_INTEGER)], inputs: [createInput(util.MAX_SAFE_INTEGER, view)],
outputs: [{ outputs: [{
script: [], script: [],
value: constants.MAX_MONEY value: constants.MAX_MONEY
@ -549,14 +562,15 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on 53 bit output values', function() { it('should fail on 53 bit output values', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(constants.MAX_MONEY)], inputs: [createInput(constants.MAX_MONEY, view)],
outputs: [{ outputs: [{
script: [], script: [],
value: util.MAX_SAFE_INTEGER value: util.MAX_SAFE_INTEGER
@ -564,14 +578,15 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(!tx.isSane()); assert.ok(!tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on 53 bit fees', function() { it('should fail on 53 bit fees', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(util.MAX_SAFE_INTEGER)], inputs: [createInput(util.MAX_SAFE_INTEGER, view)],
outputs: [{ outputs: [{
script: [], script: [],
value: 0 value: 0
@ -579,18 +594,19 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
[util.MAX_SAFE_ADDITION, util.MAX_SAFE_INTEGER].forEach(function(MAX) { [util.MAX_SAFE_ADDITION, util.MAX_SAFE_INTEGER].forEach(function(MAX) {
it('should fail on >53 bit values from multiple', function() { it('should fail on >53 bit values from multiple', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [ inputs: [
createInput(MAX), createInput(MAX, view),
createInput(MAX), createInput(MAX, view),
createInput(MAX) createInput(MAX, view)
], ],
outputs: [{ outputs: [{
script: [], script: [],
@ -599,14 +615,15 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on >53 bit output values from multiple', function() { it('should fail on >53 bit output values from multiple', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [createInput(constants.MAX_MONEY)], inputs: [createInput(constants.MAX_MONEY, view)],
outputs: [ outputs: [
{ {
script: [], script: [],
@ -624,17 +641,18 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(!tx.isSane()); assert.ok(!tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on >53 bit fees from multiple', function() { it('should fail on >53 bit fees from multiple', function() {
var tx = bcoin.tx({ var view = new CoinView();
var tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [ inputs: [
createInput(MAX), createInput(MAX, view),
createInput(MAX), createInput(MAX, view),
createInput(MAX) createInput(MAX, view)
], ],
outputs: [{ outputs: [{
script: [], script: [],
@ -643,20 +661,21 @@ describe('TX', function() {
locktime: 0 locktime: 0
}); });
assert.ok(tx.isSane()); assert.ok(tx.isSane());
// assert.ok(!tx.checkInputs(view, 0)); assert.ok(!tx.checkInputs(view, 0));
}); });
it('should fail on >53 bit fees from multiple txs', function() { it('should fail on >53 bit fees from multiple txs', function() {
var genesis = bcoin.network.get().genesis; var view = new CoinView();
var block = new bcoin.block(genesis); var genesis = Network.get().genesis;
var block = new Block(genesis);
var i, tx; var i, tx;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
tx = bcoin.tx({ tx = new TX({
version: 1, version: 1,
flag: 1, flag: 1,
inputs: [ inputs: [
createInput(MAX) createInput(MAX, view)
], ],
outputs: [{ outputs: [{
script: [], script: [],
@ -667,7 +686,7 @@ describe('TX', function() {
block.txs.push(tx); block.txs.push(tx);
} }
// assert.equal(block.getReward(view), -1); assert.equal(block.getReward(view, 0), -1);
}); });
}); });
}); });