fcoin/test/net-test.js
2019-05-24 17:58:25 -07:00

832 lines
23 KiB
JavaScript

/* eslint-env mocha */
/* eslint prefer-arrow-callback: "off" */
'use strict';
const assert = require('./util/assert');
const common = require('./util/common');
const {BloomFilter} = require('bfilter');
const {nonce} = require('../lib/net/common');
const Framer = require('../lib/net/framer');
const packets = require('../lib/net/packets');
const NetAddress = require('../lib/net/netaddress');
const {CompactBlock, TXRequest, TXResponse} = require('../lib/net/bip152');
const InvItem = require('../lib/primitives/invitem');
const Headers = require('../lib/primitives/headers');
const Network = require('../lib/protocol/network');
// Block test vectors
const block300025 = common.readBlock('block300025');
// Merkle block test vectors
const merkle300025 = common.readMerkle('merkle300025');
// Small SegWit block test vector
const block482683 = common.readBlock('block482683');
describe('Net', function() {
describe('Packets', function() {
it('version', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'version');
assert.equal(pkt.type, packets.types.VERSION);
assert.equal(pkt.version, 70012);
assert.equal(pkt.services, 10);
assert.equal(pkt.time, 1558405603);
assert.equal(pkt.remote.host, '127.0.0.1');
assert.equal(pkt.remote.port, 8334);
assert.equal(pkt.local.host, '127.0.0.1');
assert.equal(pkt.local.port, 8335);
assert.bufferEqual(pkt.nonce, Buffer.alloc(8, 0x00));
assert.equal(pkt.agent, 'bcoin');
assert.equal(pkt.height, 500000);
assert.equal(pkt.noRelay, true);
};
let pkt = new packets.VersionPacket({
version: 70012,
services: 10,
time: 1558405603,
remote: {
host: '127.0.0.1',
port: 8334
},
local: {
host: '127.0.0.1',
port: 8335
},
nonce: Buffer.alloc(8, 0x00),
agent: 'bcoin',
height: 500000,
noRelay: true
});
check(pkt);
pkt = packets.VersionPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('verack', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'verack');
assert.equal(pkt.type, packets.types.VERACK);
};
let pkt = new packets.VerackPacket();
check(pkt);
pkt = packets.VerackPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('ping', () => {
const check = (pkt, nonce) => {
assert.equal(pkt.cmd, 'ping');
assert.equal(pkt.type, packets.types.PING);
if (nonce)
assert.bufferEqual(pkt.nonce, Buffer.alloc(8, 0x01));
};
let pkt = new packets.PingPacket(Buffer.alloc(8, 0x01));
check(pkt, true);
pkt = packets.PingPacket.fromRaw(pkt.toRaw());
check(pkt, true);
pkt = new packets.PingPacket();
check(pkt, false);
pkt = packets.PingPacket.fromRaw(pkt.toRaw());
check(pkt, false);
});
it('pong', () => {
const check = (pkt, nonce) => {
assert.equal(pkt.cmd, 'pong');
assert.equal(pkt.type, packets.types.PONG);
if (nonce)
assert.bufferEqual(pkt.nonce, Buffer.alloc(8, 0x01));
else {
assert.bufferEqual(pkt.nonce, Buffer.alloc(8, 0x00));
}
};
let pkt = new packets.PongPacket(Buffer.alloc(8, 0x01));
check(pkt, true);
pkt = packets.PongPacket.fromRaw(pkt.toRaw());
check(pkt, true);
pkt = new packets.PongPacket();
check(pkt, false);
pkt = packets.PongPacket.fromRaw(pkt.toRaw());
check(pkt, false);
});
it('getaddr', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'getaddr');
assert.equal(pkt.type, packets.types.GETADDR);
};
let pkt = new packets.GetAddrPacket();
check(pkt);
pkt = packets.GetAddrPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('addr', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'addr');
assert.equal(pkt.type, packets.types.ADDR);
let addr = pkt.items[0];
assert.equal(addr.host, '127.0.0.2');
assert.equal(addr.port, 8334);
assert.equal(addr.services, 101);
assert.equal(addr.time, 1558405603);
addr = pkt.items[1];
assert.equal(addr.host, '127.0.0.3');
assert.equal(addr.port, 8333);
assert.equal(addr.services, 102);
assert.equal(addr.time, 1558405602);
};
const items = [
new NetAddress({
host: '127.0.0.2',
port: 8334,
services: 101,
time: 1558405603
}),
new NetAddress({
host: '127.0.0.3',
port: 8333,
services: 102,
time: 1558405602
})
];
let pkt = new packets.AddrPacket(items);
check(pkt);
pkt = packets.AddrPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('inv', () => {
const check = (pkt, many) => {
assert.equal(pkt.cmd, 'inv');
assert.equal(pkt.type, packets.types.INV);
let item = pkt.items[0];
assert.equal(item.type, 1);
assert.bufferEqual(item.hash, Buffer.alloc(32, 0x01));
item = pkt.items[1];
assert.equal(item.type, 1);
assert.bufferEqual(item.hash, Buffer.alloc(32, 0x02));
if (many) {
for (let i = 2; i < 254; i++) {
item = pkt.items[i];
assert.equal(item.type, 1);
assert.bufferEqual(item.hash, Buffer.alloc(32, 0x03));
}
}
};
const items = [
new InvItem(InvItem.types.TX, Buffer.alloc(32, 0x01)),
new InvItem(InvItem.types.TX, Buffer.alloc(32, 0x02))
];
let pkt = new packets.InvPacket(items);
check(pkt, false);
pkt = packets.InvPacket.fromRaw(pkt.toRaw());
check(pkt, false);
while (items.length < 254)
items.push(new InvItem(InvItem.types.TX, Buffer.alloc(32, 0x03)));
pkt = new packets.InvPacket(items);
check(pkt, true);
pkt = packets.InvPacket.fromRaw(pkt.toRaw());
check(pkt, true);
});
it('getdata', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'getdata');
assert.equal(pkt.type, packets.types.GETDATA);
let item = pkt.items[0];
assert.equal(item.type, 1);
assert.bufferEqual(item.hash, Buffer.alloc(32, 0x01));
item = pkt.items[1];
assert.equal(item.type, 1);
assert.bufferEqual(item.hash, Buffer.alloc(32, 0x02));
};
const items = [
new InvItem(InvItem.types.TX, Buffer.alloc(32, 0x01)),
new InvItem(InvItem.types.TX, Buffer.alloc(32, 0x02))
];
let pkt = new packets.GetDataPacket(items);
check(pkt);
pkt = packets.GetDataPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('notfound', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'notfound');
assert.equal(pkt.type, packets.types.NOTFOUND);
let item = pkt.items[0];
assert.equal(item.type, 1);
assert.bufferEqual(item.hash, Buffer.alloc(32, 0x01));
item = pkt.items[1];
assert.equal(item.type, 1);
assert.bufferEqual(item.hash, Buffer.alloc(32, 0x02));
};
const items = [
new InvItem(InvItem.types.TX, Buffer.alloc(32, 0x01)),
new InvItem(InvItem.types.TX, Buffer.alloc(32, 0x02))
];
let pkt = new packets.NotFoundPacket(items);
check(pkt);
pkt = packets.NotFoundPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('getblocks', () => {
const check = (pkt, values) => {
assert.equal(pkt.cmd, 'getblocks');
assert.equal(pkt.type, packets.types.GETBLOCKS);
if (values) {
assert.equal(pkt.locator.length, 2);
assert.bufferEqual(pkt.locator[0], Buffer.alloc(32, 0x01));
assert.bufferEqual(pkt.locator[1], Buffer.alloc(32, 0x02));
assert.bufferEqual(pkt.stop, Buffer.alloc(32, 0x03));
} else {
assert.equal(pkt.locator.length, 0);
assert.strictEqual(pkt.stop, null);
}
};
const locator = [
Buffer.alloc(32, 0x01),
Buffer.alloc(32, 0x02)
];
const stop = Buffer.alloc(32, 0x03);
let pkt = new packets.GetBlocksPacket(locator, stop);
check(pkt, true);
pkt = packets.GetBlocksPacket.fromRaw(pkt.toRaw());
check(pkt, true);
pkt = new packets.GetBlocksPacket();
check(pkt, false);
pkt = packets.GetBlocksPacket.fromRaw(pkt.toRaw());
check(pkt, false);
});
it('getheaders', () => {
const check = (pkt, values) => {
assert.equal(pkt.cmd, 'getheaders');
assert.equal(pkt.type, packets.types.GETHEADERS);
if (values) {
assert.equal(pkt.locator.length, 2);
assert.bufferEqual(pkt.locator[0], Buffer.alloc(32, 0x01));
assert.bufferEqual(pkt.locator[1], Buffer.alloc(32, 0x02));
assert.bufferEqual(pkt.stop, Buffer.alloc(32, 0x03));
} else {
assert.equal(pkt.locator.length, 0);
assert.strictEqual(pkt.stop, null);
}
};
const locator = [
Buffer.alloc(32, 0x01),
Buffer.alloc(32, 0x02)
];
const stop = Buffer.alloc(32, 0x03);
let pkt = new packets.GetHeadersPacket(locator, stop);
check(pkt, true);
pkt = packets.GetHeadersPacket.fromRaw(pkt.toRaw());
check(pkt, true);
pkt = new packets.GetHeadersPacket();
check(pkt, false);
pkt = packets.GetHeadersPacket.fromRaw(pkt.toRaw());
check(pkt, false);
});
it('headers', () => {
const check = (pkt, values, many) => {
assert.equal(pkt.cmd, 'headers');
assert.equal(pkt.type, packets.types.HEADERS);
assert.equal(pkt.items[0].version, 1);
assert.bufferEqual(pkt.items[0].prevBlock, Buffer.alloc(32, 0x01));
assert.bufferEqual(pkt.items[0].merkleRoot, Buffer.alloc(32, 0x02));
assert.equal(pkt.items[0].time, 1558405603);
assert.equal(pkt.items[0].bits, 403014710);
assert.equal(pkt.items[0].nonce, 101);
assert.equal(pkt.items[1].version, 2);
assert.bufferEqual(pkt.items[1].prevBlock, Buffer.alloc(32, 0x02));
assert.bufferEqual(pkt.items[1].merkleRoot, Buffer.alloc(32, 0x03));
assert.equal(pkt.items[1].time, 1558405604);
assert.equal(pkt.items[1].bits, 403014711);
assert.equal(pkt.items[1].nonce, 102);
if (many) {
for (let i = 2; i < 254; i++) {
const item = pkt.items[i];
assert.equal(item.version, 3);
assert.bufferEqual(pkt.items[1].prevBlock, Buffer.alloc(32, 0x04));
assert.bufferEqual(pkt.items[1].merkleRoot, Buffer.alloc(32, 0x05));
assert.equal(pkt.items[1].time, 1558405605);
assert.equal(pkt.items[1].bits, 403014712);
assert.equal(pkt.items[1].nonce, 103);
}
}
};
const items = [
new Headers({
version: 1,
prevBlock: Buffer.alloc(32, 0x01),
merkleRoot: Buffer.alloc(32, 0x02),
time: 1558405603,
bits: 403014710,
nonce: 101
}),
new Headers({
version: 2,
prevBlock: Buffer.alloc(32, 0x02),
merkleRoot: Buffer.alloc(32, 0x03),
time: 1558405604,
bits: 403014711,
nonce: 102
})
];
let pkt = new packets.HeadersPacket(items);
check(pkt, false);
pkt = packets.HeadersPacket.fromRaw(pkt.toRaw());
check(pkt, false);
while (items.length < 254) {
items.push(new Headers({
version: 3,
prevBlock: Buffer.alloc(32, 0x04),
merkleRoot: Buffer.alloc(32, 0x05),
time: 1558405605,
bits: 403014712,
nonce: 103
}));
}
pkt = new packets.HeadersPacket(items);
check(pkt, true);
pkt = packets.HeadersPacket.fromRaw(pkt.toRaw());
check(pkt, true);
});
it('sendheaders', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'sendheaders');
assert.equal(pkt.type, packets.types.SENDHEADERS);
};
let pkt = new packets.SendHeadersPacket();
check(pkt);
pkt = packets.SendHeadersPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('block', () => {
const [block] = block300025.getBlock();
const [witnessBlock] = block482683.getBlock();
const check = (pkt, witness, read) => {
assert.equal(pkt.cmd, 'block');
assert.equal(pkt.type, packets.types.BLOCK);
if (witness) {
assert.bufferEqual(pkt.block.hash(), witnessBlock.hash());
if (!read)
assert.equal(pkt.witness, true);
} else {
assert.bufferEqual(pkt.block.hash(), block.hash());
assert.equal(pkt.witness, false);
}
};
let pkt = new packets.BlockPacket(block, false);
check(pkt, false);
pkt = packets.BlockPacket.fromRaw(pkt.toRaw());
check(pkt, false);
pkt = new packets.BlockPacket(witnessBlock, true);
check(pkt, true);
pkt = packets.BlockPacket.fromRaw(pkt.toRaw());
check(pkt, true, true);
});
it('tx', () => {
const [block] = block482683.getBlock();
const tx = block.txs[9];
const witnessTx = block.txs[10];
const check = (pkt, witness, read) => {
assert.equal(pkt.cmd, 'tx');
assert.equal(pkt.type, packets.types.TX);
if (witness) {
assert.bufferEqual(pkt.tx.hash(), witnessTx.hash());
if (!read)
assert.equal(pkt.witness, true);
} else {
assert.bufferEqual(pkt.tx.hash(), tx.hash());
assert.equal(pkt.witness, false);
}
};
let pkt = new packets.TXPacket(tx, false);
check(pkt, false);
pkt = packets.TXPacket.fromRaw(pkt.toRaw());
check(pkt, false);
pkt = new packets.TXPacket(witnessTx, true);
check(pkt, true);
pkt = packets.TXPacket.fromRaw(pkt.toRaw());
check(pkt, true, true);
});
it('reject', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'reject');
assert.equal(pkt.type, packets.types.REJECT);
assert.equal(pkt.code, 1);
assert.equal(pkt.reason, 'test-reason');
assert.equal(pkt.message, 'block');
assert.equal(pkt.getCode(), 'malformed');
assert.bufferEqual(pkt.hash, Buffer.alloc(32, 0x01));
};
let pkt = new packets.RejectPacket({
message: 'block',
code: 1,
reason: 'test-reason',
hash: Buffer.alloc(32, 0x01)
});
check(pkt);
pkt = packets.RejectPacket.fromRaw(pkt.toRaw());
check(pkt);
pkt = packets.RejectPacket.fromReason(
'malformed',
'test-reason',
'block',
Buffer.alloc(32, 0x01)
);
check(pkt);
pkt = packets.RejectPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('mempool', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'mempool');
assert.equal(pkt.type, packets.types.MEMPOOL);
};
let pkt = new packets.MempoolPacket();
check(pkt);
pkt = packets.MempoolPacket.fromRaw(pkt.toRaw());
});
it('filterload', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'filterload');
assert.equal(pkt.type, packets.types.FILTERLOAD);
assert.equal(pkt.filter.test(Buffer.alloc(32, 0x01)), true);
};
const filter = BloomFilter.fromRate(
20000, 0.001, BloomFilter.flags.ALL);
filter.add(Buffer.alloc(32, 0x01));
let pkt = new packets.FilterLoadPacket(filter);
check(pkt);
pkt = packets.FilterLoadPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('filteradd', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'filteradd');
assert.equal(pkt.type, packets.types.FILTERADD);
assert.bufferEqual(pkt.data, Buffer.alloc(32, 0x02));
};
let pkt = new packets.FilterAddPacket(Buffer.alloc(32, 0x02));
check(pkt);
pkt = packets.FilterAddPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('filterclear', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'filterclear');
assert.equal(pkt.type, packets.types.FILTERCLEAR);
};
let pkt = new packets.FilterClearPacket();
check(pkt);
pkt = packets.FilterClearPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('merkleblock', () => {
const [block] = merkle300025.getBlock();
const check = (pkt) => {
assert.equal(pkt.cmd, 'merkleblock');
assert.equal(pkt.type, packets.types.MERKLEBLOCK);
assert.bufferEqual(pkt.block.hash(), block.hash());
};
let pkt = new packets.MerkleBlockPacket(block);
check(pkt);
pkt = packets.MerkleBlockPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('feefilter', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'feefilter');
assert.equal(pkt.type, packets.types.FEEFILTER);
assert.equal(pkt.rate, 120000);
};
let pkt = new packets.FeeFilterPacket(120000);
check(pkt);
pkt = packets.FeeFilterPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('sendcmpct', () => {
const check = (pkt, mode, version) => {
assert.equal(pkt.cmd, 'sendcmpct');
assert.equal(pkt.type, packets.types.SENDCMPCT);
assert.equal(pkt.mode, mode);
assert.equal(pkt.version, version);
};
let pkt = new packets.SendCmpctPacket();
check(pkt, 0, 1);
pkt = packets.SendCmpctPacket.fromRaw(pkt.toRaw());
check(pkt, 0, 1);
pkt = new packets.SendCmpctPacket(1, 2);
check(pkt, 1, 2);
pkt = packets.SendCmpctPacket.fromRaw(pkt.toRaw());
check(pkt, 1, 2);
});
it('cmpctblock', () => {
const [block] = block300025.getBlock();
const [witnessBlock] = block482683.getBlock();
const check = (pkt, witness, read) => {
assert.equal(pkt.cmd, 'cmpctblock');
assert.equal(pkt.type, packets.types.CMPCTBLOCK);
if (witness) {
assert.bufferEqual(pkt.block.hash(), witnessBlock.hash());
if (!read)
assert.equal(pkt.witness, true);
} else {
assert.bufferEqual(pkt.block.hash(), block.hash());
assert.equal(pkt.witness, false);
}
};
const compact = CompactBlock.fromBlock(block);
let pkt = new packets.CmpctBlockPacket(compact);
check(pkt, false);
pkt = packets.CmpctBlockPacket.fromRaw(pkt.toRaw());
check(pkt, false);
const witnessCompact = CompactBlock.fromBlock(witnessBlock);
pkt = new packets.CmpctBlockPacket(witnessCompact, true);
check(pkt, true);
pkt = packets.CmpctBlockPacket.fromRaw(pkt.toRaw());
check(pkt, true, true);
});
it('getblocktxn', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'getblocktxn');
assert.equal(pkt.type, packets.types.GETBLOCKTXN);
assert.bufferEqual(pkt.request.hash, Buffer.alloc(32, 0x01));
assert.deepEqual(pkt.request.indexes, [2, 3, 5, 7, 11]);
};
const request = new TXRequest({
hash: Buffer.alloc(32, 0x01),
indexes: [2, 3, 5, 7, 11]
});
let pkt = new packets.GetBlockTxnPacket(request);
check(pkt);
pkt = packets.GetBlockTxnPacket.fromRaw(pkt.toRaw());
check(pkt);
});
it('blocktxn', () => {
const [block] = block482683.getBlock();
const tx = block.txs[9];
const witnessTx = block.txs[10];
const check = (pkt, witness, read) => {
assert.equal(pkt.cmd, 'blocktxn');
assert.equal(pkt.type, packets.types.BLOCKTXN);
assert.bufferEqual(pkt.response.hash, Buffer.alloc(32, 0x01));
if (witness) {
assert.bufferEqual(pkt.response.txs[0].hash(), witnessTx.hash());
if (!read)
assert.equal(pkt.witness, true);
} else {
assert.bufferEqual(pkt.response.txs[0].hash(), tx.hash());
assert.equal(pkt.witness, false);
}
};
const response = new TXResponse({
hash: Buffer.alloc(32, 0x01),
txs: [tx]
});
let pkt = new packets.BlockTxnPacket(response);
check(pkt, false);
pkt = packets.BlockTxnPacket.fromRaw(pkt.toRaw());
check(pkt, false);
const witnessResponse = new TXResponse({
hash: Buffer.alloc(32, 0x01),
txs: [witnessTx]
});
pkt = new packets.BlockTxnPacket(witnessResponse, true);
check(pkt, true);
pkt = packets.BlockTxnPacket.fromRaw(pkt.toRaw());
check(pkt, true, true);
});
it('unknown', () => {
const check = (pkt) => {
assert.equal(pkt.cmd, 'cmd');
assert.equal(pkt.type, packets.types.UNKNOWN);
};
let pkt = new packets.UnknownPacket('cmd', Buffer.alloc(12, 0x01));
check(pkt);
pkt = packets.UnknownPacket.fromRaw('cmd', pkt.toRaw());
check(pkt);
});
});
describe('Framer', function() {
it('will construct with network (primary)', () => {
const framer = new Framer();
assert.strictEqual(framer.network, Network.get('main'));
});
it('will construct with network (custom)', () => {
const framer = new Framer('regtest');
assert.strictEqual(framer.network, Network.get('regtest'));
});
it('throw with long command', () => {
const framer = new Framer('regtest');
let err = null;
try {
framer.packet('abcdefghijklm', Buffer.alloc(2, 0x00));
} catch (e) {
err = e;
}
assert(err);
assert(err.type, 'AssertionError');
});
it('will frame payload with header', () => {
const framer = new Framer('regtest');
const pkt = framer.packet('cmd', Buffer.alloc(2, 0x00));
const magic = pkt.slice(0, 4);
assert.bufferEqual(magic, Buffer.from('fabfb5da', 'hex'));
const cmd = pkt.slice(4, 16);
const cmdbuf = Buffer.from('636d64000000000000000000', 'hex');
assert.bufferEqual(cmd, cmdbuf);
const length = pkt.slice(16, 20);
assert.bufferEqual(length, Buffer.from('02000000', 'hex'));
const checksum = pkt.slice(20, 24);
assert.bufferEqual(checksum, Buffer.from('407feb4a', 'hex'));
const payload = pkt.slice(24, 26);
assert.bufferEqual(payload, Buffer.from('0000', 'hex'));
});
it('will frame payload with header (w/ checksum)', () => {
const framer = new Framer('regtest');
const payload = Buffer.alloc(2, 0x00);
const checksum = Buffer.alloc(4, 0x00);
const pkt = framer.packet('cmd', payload, checksum);
assert.bufferEqual(pkt.slice(20, 24), Buffer.from('00000000', 'hex'));
});
});
describe('Common', function() {
it('will give nonce', async () => {
const n = nonce();
assert(Buffer.isBuffer(n));
assert.equal(n.length, 8);
});
});
});