test: improve addrindex tests
- Vectors for p2wsh and p2sh. - Edge case for witness program. - Improve determinism by not comparing mtime. - Various edge and error cases.
This commit is contained in:
parent
69e9844f82
commit
b4be8574e5
@ -138,8 +138,7 @@ class AddrIndexer extends Indexer {
|
|||||||
const hash = tx.hash();
|
const hash = tx.hash();
|
||||||
const count = new Count(height, i);
|
const count = new Count(height, i);
|
||||||
|
|
||||||
this.put(layout.C.encode(height, i), hash);
|
let hasAddress = false;
|
||||||
this.put(layout.c.encode(hash), count.toRaw());
|
|
||||||
|
|
||||||
for (const addr of tx.getAddresses(view)) {
|
for (const addr of tx.getAddresses(view)) {
|
||||||
const prefix = addr.getPrefix();
|
const prefix = addr.getPrefix();
|
||||||
@ -150,6 +149,13 @@ class AddrIndexer extends Indexer {
|
|||||||
const addrHash = addr.getHash();
|
const addrHash = addr.getHash();
|
||||||
|
|
||||||
this.put(layout.A.encode(prefix, addrHash, height, i), null);
|
this.put(layout.A.encode(prefix, addrHash, height, i), null);
|
||||||
|
|
||||||
|
hasAddress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAddress) {
|
||||||
|
this.put(layout.C.encode(height, i), hash);
|
||||||
|
this.put(layout.c.encode(hash), count.toRaw());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,8 +175,7 @@ class AddrIndexer extends Indexer {
|
|||||||
const tx = block.txs[i];
|
const tx = block.txs[i];
|
||||||
const hash = tx.hash();
|
const hash = tx.hash();
|
||||||
|
|
||||||
this.del(layout.C.encode(height, i));
|
let hasAddress = false;
|
||||||
this.del(layout.c.encode(hash));
|
|
||||||
|
|
||||||
for (const addr of tx.getAddresses(view)) {
|
for (const addr of tx.getAddresses(view)) {
|
||||||
const prefix = addr.getPrefix();
|
const prefix = addr.getPrefix();
|
||||||
@ -181,6 +186,13 @@ class AddrIndexer extends Indexer {
|
|||||||
const addrHash = addr.getHash();
|
const addrHash = addr.getHash();
|
||||||
|
|
||||||
this.del(layout.A.encode(prefix, addrHash, height, i));
|
this.del(layout.A.encode(prefix, addrHash, height, i));
|
||||||
|
|
||||||
|
hasAddress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAddress) {
|
||||||
|
this.del(layout.C.encode(height, i));
|
||||||
|
this.del(layout.c.encode(hash));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,13 +234,19 @@ class AddrIndexer extends Indexer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Determine if the hash -> height + index mapping exists.
|
||||||
const hasAfter = (after && await this.db.has(layout.c.encode(after)));
|
const hasAfter = (after && await this.db.has(layout.c.encode(after)));
|
||||||
const skip = (after && !hasAfter && !reverse);
|
|
||||||
|
|
||||||
|
// Check to see if results should be skipped because
|
||||||
|
// the after hash is expected to be within a following
|
||||||
|
// mempool query.
|
||||||
|
const skip = (after && !hasAfter && !reverse);
|
||||||
if (skip)
|
if (skip)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
if (after && hasAfter) {
|
if (after && hasAfter) {
|
||||||
|
// Give results starting from after
|
||||||
|
// the tx hash for the address.
|
||||||
const raw = await this.db.get(layout.c.encode(after));
|
const raw = await this.db.get(layout.c.encode(after));
|
||||||
const count = Count.fromRaw(raw);
|
const count = Count.fromRaw(raw);
|
||||||
const {height, index} = count;
|
const {height, index} = count;
|
||||||
@ -241,6 +259,8 @@ class AddrIndexer extends Indexer {
|
|||||||
opts.lt = layout.A.max(prefix, hash, height, index);
|
opts.lt = layout.A.max(prefix, hash, height, index);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Give earliest or latest results
|
||||||
|
// for the address.
|
||||||
opts.gte = layout.A.min(prefix, hash);
|
opts.gte = layout.A.min(prefix, hash);
|
||||||
opts.lte = layout.A.max(prefix, hash);
|
opts.lte = layout.A.max(prefix, hash);
|
||||||
}
|
}
|
||||||
|
|||||||
235
lib/mempool/addrindexer.js
Normal file
235
lib/mempool/addrindexer.js
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/*!
|
||||||
|
* mempool.js - mempool for bcoin
|
||||||
|
* Copyright (c) 2018-2019, the bcoin developers (MIT License).
|
||||||
|
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
|
||||||
|
* https://github.com/bcoin-org/bcoin
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const assert = require('bsert');
|
||||||
|
const {BufferMap} = require('buffer-map');
|
||||||
|
const TXMeta = require('../primitives/txmeta');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address Indexer
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AddrIndexer {
|
||||||
|
/**
|
||||||
|
* Create TX address index.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Map of addr->entries.
|
||||||
|
this.index = new BufferMap();
|
||||||
|
|
||||||
|
// Map of txid->addrs.
|
||||||
|
this.map = new BufferMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.index.clear();
|
||||||
|
this.map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
getKey(addr) {
|
||||||
|
const prefix = addr.getPrefix();
|
||||||
|
|
||||||
|
if (prefix < 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
const raw = Buffer.allocUnsafe(1);
|
||||||
|
raw.writeUInt8(prefix);
|
||||||
|
|
||||||
|
return Buffer.concat([raw, addr.getHash()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get transactions by address.
|
||||||
|
* @param {Address} addr
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {Number} options.limit
|
||||||
|
* @param {Number} options.reverse
|
||||||
|
* @param {Buffer} options.after
|
||||||
|
*/
|
||||||
|
|
||||||
|
get(addr, options = {}) {
|
||||||
|
const values = this.getEntries(addr, options);
|
||||||
|
|
||||||
|
const out = [];
|
||||||
|
|
||||||
|
for (const entry of values)
|
||||||
|
out.push(entry.tx);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get transaction meta by address.
|
||||||
|
* @param {Address} addr
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {Number} options.limit
|
||||||
|
* @param {Number} options.reverse
|
||||||
|
* @param {Buffer} options.after
|
||||||
|
*/
|
||||||
|
|
||||||
|
getMeta(addr, options = {}) {
|
||||||
|
const values = this.getEntries(addr, options);
|
||||||
|
|
||||||
|
const out = [];
|
||||||
|
|
||||||
|
for (const entry of values) {
|
||||||
|
const meta = TXMeta.fromTX(entry.tx);
|
||||||
|
meta.mtime = entry.time;
|
||||||
|
out.push(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get entries by address.
|
||||||
|
* @param {Address} addr
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {Number} options.limit
|
||||||
|
* @param {Number} options.reverse
|
||||||
|
* @param {Buffer} options.after
|
||||||
|
*/
|
||||||
|
|
||||||
|
getEntries(addr, options = {}) {
|
||||||
|
const {limit, reverse, after} = options;
|
||||||
|
const key = this.getKey(addr);
|
||||||
|
|
||||||
|
if (!key)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
const items = this.index.get(key);
|
||||||
|
|
||||||
|
if (!items)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
let values = [];
|
||||||
|
|
||||||
|
// Check to see if results should be skipped because
|
||||||
|
// the after hash is expected to be within a following
|
||||||
|
// confirmed query.
|
||||||
|
const skip = (after && !items.has(after) && reverse);
|
||||||
|
|
||||||
|
if (skip)
|
||||||
|
return values;
|
||||||
|
|
||||||
|
if (after && items.has(after)) {
|
||||||
|
// Give results starting from after
|
||||||
|
// the tx hash for the address.
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
for (const k of items.keys()) {
|
||||||
|
if (k.compare(after) === 0)
|
||||||
|
break;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
values = Array.from(items.values());
|
||||||
|
|
||||||
|
let start = index + 1;
|
||||||
|
let end = values.length;
|
||||||
|
|
||||||
|
if (end - start > limit)
|
||||||
|
end = start + limit;
|
||||||
|
|
||||||
|
if (reverse) {
|
||||||
|
start = 0;
|
||||||
|
end = index;
|
||||||
|
|
||||||
|
if (end > limit)
|
||||||
|
start = end - limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
values = values.slice(start, end);
|
||||||
|
} else {
|
||||||
|
// Give earliest or latest results
|
||||||
|
// for the address.
|
||||||
|
values = Array.from(items.values());
|
||||||
|
|
||||||
|
if (values.length > limit) {
|
||||||
|
let start = 0;
|
||||||
|
let end = limit;
|
||||||
|
|
||||||
|
if (reverse) {
|
||||||
|
start = values.length - limit;
|
||||||
|
end = values.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
values = values.slice(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
values.reverse();
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(entry, view) {
|
||||||
|
const tx = entry.tx;
|
||||||
|
const hash = tx.hash();
|
||||||
|
const addrs = tx.getAddresses(view);
|
||||||
|
|
||||||
|
if (addrs.length === 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const addr of addrs) {
|
||||||
|
const key = this.getKey(addr);
|
||||||
|
|
||||||
|
if (!key)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let items = this.index.get(key);
|
||||||
|
|
||||||
|
if (!items) {
|
||||||
|
items = new BufferMap();
|
||||||
|
this.index.set(key, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!items.has(hash));
|
||||||
|
items.set(hash, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.map.set(hash, addrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(hash) {
|
||||||
|
const addrs = this.map.get(hash);
|
||||||
|
|
||||||
|
if (!addrs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const addr of addrs) {
|
||||||
|
const key = this.getKey(addr);
|
||||||
|
|
||||||
|
if (!key)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const items = this.index.get(key);
|
||||||
|
|
||||||
|
assert(items);
|
||||||
|
assert(items.has(hash));
|
||||||
|
|
||||||
|
items.delete(hash);
|
||||||
|
|
||||||
|
if (items.size === 0)
|
||||||
|
this.index.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.map.delete(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expose
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = AddrIndexer;
|
||||||
@ -27,6 +27,7 @@ const TXMeta = require('../primitives/txmeta');
|
|||||||
const MempoolEntry = require('./mempoolentry');
|
const MempoolEntry = require('./mempoolentry');
|
||||||
const Network = require('../protocol/network');
|
const Network = require('../protocol/network');
|
||||||
const layout = require('./layout');
|
const layout = require('./layout');
|
||||||
|
const AddrIndexer = require('./addrindexer');
|
||||||
const Fees = require('./fees');
|
const Fees = require('./fees');
|
||||||
const CoinView = require('../coins/coinview');
|
const CoinView = require('../coins/coinview');
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ class Mempool extends EventEmitter {
|
|||||||
this.spents = new BufferMap();
|
this.spents = new BufferMap();
|
||||||
this.rejects = new RollingFilter(120000, 0.000001);
|
this.rejects = new RollingFilter(120000, 0.000001);
|
||||||
|
|
||||||
this.addrindex = new AddrIndex();
|
this.addrindex = new AddrIndexer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2118,216 +2119,6 @@ class MempoolOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Address Index
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
|
|
||||||
class AddrIndex {
|
|
||||||
/**
|
|
||||||
* Create TX address index.
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
// Map of addr->entries.
|
|
||||||
this.index = new BufferMap();
|
|
||||||
|
|
||||||
// Map of txid->addrs.
|
|
||||||
this.map = new BufferMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.index.clear();
|
|
||||||
this.map.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
getKey(addr) {
|
|
||||||
const prefix = addr.getPrefix();
|
|
||||||
|
|
||||||
if (prefix < 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
const raw = Buffer.allocUnsafe(1);
|
|
||||||
raw.writeUInt8(prefix);
|
|
||||||
|
|
||||||
return Buffer.concat([raw, addr.getHash()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get transactions by address.
|
|
||||||
* @param {Address} addr
|
|
||||||
* @param {Object} options
|
|
||||||
* @param {Number} options.limit
|
|
||||||
* @param {Number} options.reverse
|
|
||||||
* @param {Buffer} options.after
|
|
||||||
*/
|
|
||||||
|
|
||||||
get(addr, options = {}) {
|
|
||||||
const values = this.getEntries(addr, options);
|
|
||||||
|
|
||||||
const out = [];
|
|
||||||
|
|
||||||
for (const entry of values)
|
|
||||||
out.push(entry.tx);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get transaction meta by address.
|
|
||||||
* @param {Address} addr
|
|
||||||
* @param {Object} options
|
|
||||||
* @param {Number} options.limit
|
|
||||||
* @param {Number} options.reverse
|
|
||||||
* @param {Buffer} options.after
|
|
||||||
*/
|
|
||||||
|
|
||||||
getMeta(addr, options = {}) {
|
|
||||||
const values = this.getEntries(addr, options);
|
|
||||||
|
|
||||||
const out = [];
|
|
||||||
|
|
||||||
for (const entry of values) {
|
|
||||||
const meta = TXMeta.fromTX(entry.tx);
|
|
||||||
meta.mtime = entry.time;
|
|
||||||
out.push(meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get entries by address.
|
|
||||||
* @param {Address} addr
|
|
||||||
* @param {Object} options
|
|
||||||
* @param {Number} options.limit
|
|
||||||
* @param {Number} options.reverse
|
|
||||||
* @param {Buffer} options.after
|
|
||||||
*/
|
|
||||||
|
|
||||||
getEntries(addr, options = {}) {
|
|
||||||
const {limit, reverse, after} = options;
|
|
||||||
const key = this.getKey(addr);
|
|
||||||
|
|
||||||
if (!key)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
const items = this.index.get(key);
|
|
||||||
|
|
||||||
if (!items)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
let values = [];
|
|
||||||
|
|
||||||
const skip = (after && !items.has(after) && reverse);
|
|
||||||
|
|
||||||
if (skip)
|
|
||||||
return values;
|
|
||||||
|
|
||||||
if (after && items.has(after)) {
|
|
||||||
let index = 0;
|
|
||||||
|
|
||||||
for (const k of items.keys()) {
|
|
||||||
if (k.compare(after) === 0)
|
|
||||||
break;
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
values = Array.from(items.values());
|
|
||||||
|
|
||||||
let start = index + 1;
|
|
||||||
let end = values.length;
|
|
||||||
|
|
||||||
if (end - start > limit)
|
|
||||||
end = start + limit;
|
|
||||||
|
|
||||||
if (reverse) {
|
|
||||||
start = 0;
|
|
||||||
end = index;
|
|
||||||
|
|
||||||
if (end - start > limit)
|
|
||||||
start = end - limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
values = values.slice(start, end);
|
|
||||||
} else {
|
|
||||||
values = Array.from(items.values());
|
|
||||||
|
|
||||||
if (values.length > limit) {
|
|
||||||
let start = 0;
|
|
||||||
let end = limit;
|
|
||||||
|
|
||||||
if (reverse) {
|
|
||||||
start = values.length - limit;
|
|
||||||
end = values.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
values = values.slice(start, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reverse)
|
|
||||||
values.reverse();
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
insert(entry, view) {
|
|
||||||
const tx = entry.tx;
|
|
||||||
const hash = tx.hash();
|
|
||||||
const addrs = tx.getAddresses(view);
|
|
||||||
|
|
||||||
if (addrs.length === 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (const addr of addrs) {
|
|
||||||
const key = this.getKey(addr);
|
|
||||||
|
|
||||||
if (!key)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let items = this.index.get(key);
|
|
||||||
|
|
||||||
if (!items) {
|
|
||||||
items = new BufferMap();
|
|
||||||
this.index.set(key, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(!items.has(hash));
|
|
||||||
items.set(hash, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.map.set(hash, addrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(hash) {
|
|
||||||
const addrs = this.map.get(hash);
|
|
||||||
|
|
||||||
if (!addrs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (const addr of addrs) {
|
|
||||||
const key = this.getKey(addr);
|
|
||||||
|
|
||||||
if (!key)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const items = this.index.get(key);
|
|
||||||
|
|
||||||
assert(items);
|
|
||||||
assert(items.has(hash));
|
|
||||||
|
|
||||||
items.delete(hash);
|
|
||||||
|
|
||||||
if (items.size === 0)
|
|
||||||
this.index.delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.map.delete(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Orphan
|
* Orphan
|
||||||
* @ignore
|
* @ignore
|
||||||
|
|||||||
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
const assert = require('./util/assert');
|
const assert = require('./util/assert');
|
||||||
const reorg = require('./util/reorg');
|
const reorg = require('./util/reorg');
|
||||||
|
const Script = require('../lib/script/script');
|
||||||
|
const Opcode = require('../lib/script/opcode');
|
||||||
|
const Address = require('../lib/primitives/address');
|
||||||
const Chain = require('../lib/blockchain/chain');
|
const Chain = require('../lib/blockchain/chain');
|
||||||
const WorkerPool = require('../lib/workers/workerpool');
|
const WorkerPool = require('../lib/workers/workerpool');
|
||||||
const Miner = require('../lib/mining/miner');
|
const Miner = require('../lib/mining/miner');
|
||||||
@ -18,6 +21,34 @@ const network = Network.get('regtest');
|
|||||||
const {NodeClient, WalletClient} = require('bclient');
|
const {NodeClient, WalletClient} = require('bclient');
|
||||||
const {forValue} = require('./util/common');
|
const {forValue} = require('./util/common');
|
||||||
|
|
||||||
|
const vectors = [
|
||||||
|
// Secret for the public key vectors:
|
||||||
|
// cVDJUtDjdaM25yNVVDLLX3hcHUfth4c7tY3rSc4hy9e8ibtCuj6G
|
||||||
|
{
|
||||||
|
addr: 'bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h',
|
||||||
|
amount: 19.99,
|
||||||
|
label: 'p2wpkh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addr: 'muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi',
|
||||||
|
amount: 1.99,
|
||||||
|
label: 'p2pkh'
|
||||||
|
},
|
||||||
|
// Secrets for 1 of 2 multisig vectors:
|
||||||
|
// cVDJUtDjdaM25yNVVDLLX3hcHUfth4c7tY3rSc4hy9e8ibtCuj6G
|
||||||
|
// 93KCDD4LdP4BDTNBXrvKUCVES2jo9dAKKvhyWpNEMstuxDauHty
|
||||||
|
{
|
||||||
|
addr: 'bcrt1q2nj8e2nhmsa4hl9qw3xas7l5n2547h5uhlj47nc3pqfxaeq5rtjs9g328g',
|
||||||
|
amount: 0.99,
|
||||||
|
label: 'p2wsh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addr: '2Muy8nSQaMsMFAZwPyiXSEMTVFJv9iYuhwT',
|
||||||
|
amount: 0.11,
|
||||||
|
label: 'p2sh'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const workers = new WorkerPool({
|
const workers = new WorkerPool({
|
||||||
enabled: true
|
enabled: true
|
||||||
});
|
});
|
||||||
@ -79,7 +110,89 @@ describe('Indexer', function() {
|
|||||||
await addrindexer.close();
|
await addrindexer.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('index 10 blocks', function() {
|
describe('Unit', function() {
|
||||||
|
it('should not index transaction w/ invalid address', async () => {
|
||||||
|
const indexer = new AddrIndexer({
|
||||||
|
blocks: {},
|
||||||
|
chain: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ops = [];
|
||||||
|
|
||||||
|
indexer.put = (key, value) => ops.push([key, value]);
|
||||||
|
indexer.del = (key, value) => ops.push([key, value]);
|
||||||
|
|
||||||
|
// Create a witness program version 1 with
|
||||||
|
// 40 byte data push.
|
||||||
|
const script = new Script();
|
||||||
|
script.push(Opcode.fromSmall(1));
|
||||||
|
script.push(Opcode.fromData(Buffer.alloc(40)));
|
||||||
|
script.compile();
|
||||||
|
const addr = Address.fromScript(script);
|
||||||
|
|
||||||
|
const tx = {
|
||||||
|
getAddresses: () => [addr],
|
||||||
|
hash: () => Buffer.alloc(32)
|
||||||
|
};
|
||||||
|
|
||||||
|
const entry = {height: 323549};
|
||||||
|
const block = {txs: [tx]};
|
||||||
|
const view = {};
|
||||||
|
|
||||||
|
indexer.indexBlock(entry, block, view);
|
||||||
|
indexer.unindexBlock(entry, block, view);
|
||||||
|
|
||||||
|
assert.equal(ops.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should index transaction w/ valid address', async () => {
|
||||||
|
const indexer = new AddrIndexer({
|
||||||
|
blocks: {},
|
||||||
|
chain: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ops = [];
|
||||||
|
|
||||||
|
indexer.put = (key, value) => ops.push([key, value]);
|
||||||
|
indexer.del = (key, value) => ops.push([key, value]);
|
||||||
|
|
||||||
|
// Create a witness program version 0 with
|
||||||
|
// 20 byte data push.
|
||||||
|
const script = new Script();
|
||||||
|
script.push(Opcode.fromSmall(0));
|
||||||
|
script.push(Opcode.fromData(Buffer.alloc(20)));
|
||||||
|
script.compile();
|
||||||
|
const addr = Address.fromScript(script);
|
||||||
|
|
||||||
|
const tx = {
|
||||||
|
getAddresses: () => [addr],
|
||||||
|
hash: () => Buffer.alloc(32)
|
||||||
|
};
|
||||||
|
|
||||||
|
const entry = {height: 323549};
|
||||||
|
const block = {txs: [tx]};
|
||||||
|
const view = {};
|
||||||
|
|
||||||
|
indexer.indexBlock(entry, block, view);
|
||||||
|
indexer.unindexBlock(entry, block, view);
|
||||||
|
|
||||||
|
assert.equal(ops.length, 6);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error with limits', async () => {
|
||||||
|
const indexer = new AddrIndexer({
|
||||||
|
blocks: {},
|
||||||
|
chain: {},
|
||||||
|
maxTxs: 10
|
||||||
|
});
|
||||||
|
|
||||||
|
await assert.asyncThrows(async () => {
|
||||||
|
await indexer.getHashesByAddress(vectors[0].addr, {limit: 11});
|
||||||
|
}, 'Limit above max');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Index 10 blocks', function() {
|
||||||
let addr = null;
|
let addr = null;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@ -189,7 +302,7 @@ describe('Indexer', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('rescan and reorg', function() {
|
describe('Rescan and reorg', function() {
|
||||||
it('should rescan and reindex 10 missed blocks', async () => {
|
it('should rescan and reindex 10 missed blocks', async () => {
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
const block = await cpu.mineBlock();
|
const block = await cpu.mineBlock();
|
||||||
@ -226,26 +339,11 @@ describe('Indexer', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('http', function() {
|
describe('HTTP', function() {
|
||||||
this.timeout(120000);
|
this.timeout(120000);
|
||||||
|
|
||||||
let node, nclient, wclient = null;
|
let node, nclient, wclient = null;
|
||||||
|
|
||||||
const vectors = [
|
|
||||||
// Secret for the vectors:
|
|
||||||
// cVDJUtDjdaM25yNVVDLLX3hcHUfth4c7tY3rSc4hy9e8ibtCuj6G
|
|
||||||
{
|
|
||||||
addr: 'bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h',
|
|
||||||
amount: 19.99,
|
|
||||||
label: 'p2wpkh'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
addr: 'muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi',
|
|
||||||
amount: 1.99,
|
|
||||||
label: 'p2pkh'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const confirmed = [];
|
const confirmed = [];
|
||||||
const unconfirmed = [];
|
const unconfirmed = [];
|
||||||
|
|
||||||
@ -255,6 +353,15 @@ describe('Indexer', function() {
|
|||||||
wallet: 49333
|
wallet: 49333
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function sanitize(txs) {
|
||||||
|
return txs.map((tx) => {
|
||||||
|
// Remove mtime from the results for deep
|
||||||
|
// comparisons as it can be variable.
|
||||||
|
delete tx.mtime;
|
||||||
|
return tx;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
this.timeout(120000);
|
this.timeout(120000);
|
||||||
|
|
||||||
@ -326,7 +433,7 @@ describe('Indexer', function() {
|
|||||||
await forValue(node.chain, 'height', 160);
|
await forValue(node.chain, 'height', 160);
|
||||||
|
|
||||||
// Send unconfirmed to the vector addresses.
|
// Send unconfirmed to the vector addresses.
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
for (const v of vectors) {
|
for (const v of vectors) {
|
||||||
const txid = await wclient.execute(
|
const txid = await wclient.execute(
|
||||||
'sendtoaddress', [v.addr, v.amount]);
|
'sendtoaddress', [v.addr, v.amount]);
|
||||||
@ -335,7 +442,7 @@ describe('Indexer', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await forValue(node.mempool.map, 'size', 6);
|
await forValue(node.mempool.map, 'size', 20);
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
@ -345,20 +452,20 @@ describe('Indexer', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const v of vectors) {
|
for (const v of vectors) {
|
||||||
it(`txs by ${v.label} address`, async () => {
|
it(`txs by ${v.label} addr`, async () => {
|
||||||
const res = await nclient.request(
|
const res = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`, {});
|
'GET', `/tx/address/${v.addr}`, {});
|
||||||
|
|
||||||
assert.equal(res.length, 13);
|
assert.equal(res.length, 15);
|
||||||
|
|
||||||
for (let i = 0; i < 10; i++)
|
for (let i = 0; i < 10; i++)
|
||||||
assert(confirmed.includes(res[i].hash));
|
assert(confirmed.includes(res[i].hash));
|
||||||
|
|
||||||
for (let i = 10; i < 13; i++)
|
for (let i = 10; i < 15; i++)
|
||||||
assert(unconfirmed.includes(res[i].hash));
|
assert(unconfirmed.includes(res[i].hash));
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`txs by ${v.label} address (limit)`, async () => {
|
it(`txs by ${v.label} addr (limit)`, async () => {
|
||||||
const res = await nclient.request(
|
const res = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`, {limit: 3});
|
'GET', `/tx/address/${v.addr}`, {limit: 3});
|
||||||
|
|
||||||
@ -368,7 +475,7 @@ describe('Indexer', function() {
|
|||||||
assert(confirmed.includes(tx.hash));
|
assert(confirmed.includes(tx.hash));
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`txs by ${v.label} address (limit w/ unconf)`, async () => {
|
it(`txs by ${v.label} addr (limit w/ unconf)`, async () => {
|
||||||
const res = await nclient.request(
|
const res = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`, {limit: 11});
|
'GET', `/tx/address/${v.addr}`, {limit: 11});
|
||||||
|
|
||||||
@ -381,21 +488,21 @@ describe('Indexer', function() {
|
|||||||
assert(unconfirmed.includes(res[i].hash));
|
assert(unconfirmed.includes(res[i].hash));
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`txs by ${v.label} address (reverse)`, async () => {
|
it(`txs by ${v.label} addr (reverse)`, async () => {
|
||||||
const asc = await nclient.request(
|
const asc = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`, {reverse: false});
|
'GET', `/tx/address/${v.addr}`, {reverse: false});
|
||||||
|
|
||||||
assert.equal(asc.length, 13);
|
assert.equal(asc.length, 15);
|
||||||
|
|
||||||
const dsc = await nclient.request(
|
const dsc = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`, {reverse: true});
|
'GET', `/tx/address/${v.addr}`, {reverse: true});
|
||||||
|
|
||||||
assert.equal(asc.length, 13);
|
assert.equal(dsc.length, 15);
|
||||||
|
|
||||||
for (let i = 0; i < 10; i++)
|
for (let i = 0; i < 10; i++)
|
||||||
assert(confirmed.includes(asc[i].hash));
|
assert(confirmed.includes(asc[i].hash));
|
||||||
|
|
||||||
for (let i = 10; i < 13; i++)
|
for (let i = 10; i < 15; i++)
|
||||||
assert(unconfirmed.includes(asc[i].hash));
|
assert(unconfirmed.includes(asc[i].hash));
|
||||||
|
|
||||||
// Check the the results are reverse
|
// Check the the results are reverse
|
||||||
@ -407,11 +514,16 @@ describe('Indexer', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`txs by ${v.label} address (after)`, async () => {
|
it(`txs by ${v.label} addr (after)`, async () => {
|
||||||
const one = await nclient.request(
|
const one = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`, {limit: 3});
|
'GET', `/tx/address/${v.addr}`, {limit: 3});
|
||||||
assert.strictEqual(one.length, 3);
|
assert.strictEqual(one.length, 3);
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++)
|
||||||
|
assert(confirmed.includes(one[i].hash));
|
||||||
|
|
||||||
|
// The after hash is within the
|
||||||
|
// confirmed transactions.
|
||||||
const hash = one[2].hash;
|
const hash = one[2].hash;
|
||||||
|
|
||||||
const two = await nclient.request(
|
const two = await nclient.request(
|
||||||
@ -422,10 +534,10 @@ describe('Indexer', function() {
|
|||||||
'GET', `/tx/address/${v.addr}`, {limit: 6});
|
'GET', `/tx/address/${v.addr}`, {limit: 6});
|
||||||
assert.strictEqual(one.length, 3);
|
assert.strictEqual(one.length, 3);
|
||||||
|
|
||||||
assert.deepEqual(one.concat(two), all);
|
assert.deepEqual(sanitize(one.concat(two)), sanitize(all));
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`txs by ${v.label} address (after w/ unconf)`, async () => {
|
it(`txs by ${v.label} addr (after w/ unconf)`, async () => {
|
||||||
const one = await nclient.request(
|
const one = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`, {limit: 11});
|
'GET', `/tx/address/${v.addr}`, {limit: 11});
|
||||||
assert.strictEqual(one.length, 11);
|
assert.strictEqual(one.length, 11);
|
||||||
@ -449,24 +561,113 @@ describe('Indexer', function() {
|
|||||||
'GET', `/tx/address/${v.addr}`, {limit: 12});
|
'GET', `/tx/address/${v.addr}`, {limit: 12});
|
||||||
assert.strictEqual(all.length, 12);
|
assert.strictEqual(all.length, 12);
|
||||||
|
|
||||||
assert.deepEqual(one.concat(two), all);
|
assert.deepEqual(sanitize(one.concat(two)), sanitize(all));
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`txs by ${v.label} address (after, reverse)`, async () => {
|
it(`txs by ${v.label} addr (after w/ unconf 2)`, async () => {
|
||||||
|
const one = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`, {limit: 12});
|
||||||
|
assert.strictEqual(one.length, 12);
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++)
|
||||||
|
assert(confirmed.includes(one[i].hash));
|
||||||
|
|
||||||
|
for (let i = 10; i < 12; i++)
|
||||||
|
assert(unconfirmed.includes(one[i].hash));
|
||||||
|
|
||||||
|
const hash = one[11].hash;
|
||||||
|
|
||||||
|
const two = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`, {after: hash, limit: 10});
|
||||||
|
assert.strictEqual(two.length, 3);
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++)
|
||||||
|
assert(unconfirmed.includes(two[i].hash));
|
||||||
|
|
||||||
|
const all = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`, {limit: 100});
|
||||||
|
assert.strictEqual(all.length, 15);
|
||||||
|
|
||||||
|
assert.deepEqual(sanitize(one.concat(two)), sanitize(all));
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`txs by ${v.label} addr (after w/ unconf 3)`, async () => {
|
||||||
|
const one = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`, {limit: 13});
|
||||||
|
assert.strictEqual(one.length, 13);
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++)
|
||||||
|
assert(confirmed.includes(one[i].hash));
|
||||||
|
|
||||||
|
for (let i = 10; i < 13; i++)
|
||||||
|
assert(unconfirmed.includes(one[i].hash));
|
||||||
|
|
||||||
|
const hash = one[12].hash;
|
||||||
|
|
||||||
|
const two = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`, {after: hash, limit: 1});
|
||||||
|
assert.strictEqual(two.length, 1);
|
||||||
|
assert(unconfirmed.includes(two[0].hash));
|
||||||
|
|
||||||
|
const all = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`, {limit: 14});
|
||||||
|
assert.strictEqual(all.length, 14);
|
||||||
|
|
||||||
|
assert.deepEqual(sanitize(one.concat(two)), sanitize(all));
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`txs by ${v.label} addr (after, reverse)`, async () => {
|
||||||
|
const one = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`,
|
||||||
|
{limit: 8, reverse: true});
|
||||||
|
|
||||||
|
assert.strictEqual(one.length, 8);
|
||||||
|
|
||||||
|
for (let i = 0; i < 5; i++)
|
||||||
|
assert(unconfirmed.includes(one[i].hash));
|
||||||
|
|
||||||
|
for (let i = 5; i < 8; i++)
|
||||||
|
assert(confirmed.includes(one[i].hash));
|
||||||
|
|
||||||
|
// The after hash is within the
|
||||||
|
// confirmed transactions.
|
||||||
|
const hash = one[7].hash;
|
||||||
|
|
||||||
|
const two = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`,
|
||||||
|
{after: hash, limit: 3, reverse: true});
|
||||||
|
|
||||||
|
assert.strictEqual(two.length, 3);
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++)
|
||||||
|
assert(confirmed.includes(two[i].hash));
|
||||||
|
|
||||||
|
const all = await nclient.request(
|
||||||
|
'GET', `/tx/address/${v.addr}`,
|
||||||
|
{limit: 11, reverse: true});
|
||||||
|
|
||||||
|
assert.strictEqual(all.length, 11);
|
||||||
|
|
||||||
|
for (let i = 0; i < 5; i++)
|
||||||
|
assert(unconfirmed.includes(all[i].hash));
|
||||||
|
|
||||||
|
for (let i = 5; i < 11; i++)
|
||||||
|
assert(confirmed.includes(all[i].hash));
|
||||||
|
|
||||||
|
assert.deepEqual(sanitize(one.concat(two)), sanitize(all));
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`txs by ${v.label} addr (after, reverse w/ unconf)`, async () => {
|
||||||
const one = await nclient.request(
|
const one = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`,
|
'GET', `/tx/address/${v.addr}`,
|
||||||
{limit: 5, reverse: true});
|
{limit: 5, reverse: true});
|
||||||
|
|
||||||
assert.strictEqual(one.length, 5);
|
assert.strictEqual(one.length, 5);
|
||||||
|
for (let i = 0; i < 5; i++)
|
||||||
for (let i = 0; i < 3; i++)
|
|
||||||
assert(unconfirmed.includes(one[i].hash));
|
assert(unconfirmed.includes(one[i].hash));
|
||||||
|
|
||||||
for (let i = 3; i < 5; i++)
|
|
||||||
assert(confirmed.includes(one[i].hash));
|
|
||||||
|
|
||||||
// The after hash is within the
|
// The after hash is within the
|
||||||
// confirmed transactions.
|
// unconfirmed transactions.
|
||||||
const hash = one[4].hash;
|
const hash = one[4].hash;
|
||||||
|
|
||||||
const two = await nclient.request(
|
const two = await nclient.request(
|
||||||
@ -474,6 +675,7 @@ describe('Indexer', function() {
|
|||||||
{after: hash, limit: 3, reverse: true});
|
{after: hash, limit: 3, reverse: true});
|
||||||
|
|
||||||
assert.strictEqual(two.length, 3);
|
assert.strictEqual(two.length, 3);
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++)
|
for (let i = 0; i < 3; i++)
|
||||||
assert(confirmed.includes(two[i].hash));
|
assert(confirmed.includes(two[i].hash));
|
||||||
|
|
||||||
@ -483,16 +685,16 @@ describe('Indexer', function() {
|
|||||||
|
|
||||||
assert.strictEqual(all.length, 8);
|
assert.strictEqual(all.length, 8);
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++)
|
for (let i = 0; i < 5; i++)
|
||||||
assert(unconfirmed.includes(all[i].hash));
|
assert(unconfirmed.includes(all[i].hash));
|
||||||
|
|
||||||
for (let i = 3; i < 8; i++)
|
for (let i = 5; i < 8; i++)
|
||||||
assert(confirmed.includes(all[i].hash));
|
assert(confirmed.includes(all[i].hash));
|
||||||
|
|
||||||
assert.deepEqual(one.concat(two), all);
|
assert.deepEqual(sanitize(one.concat(two)), sanitize(all));
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`txs by ${v.label} address (after, reverse w/ unconf)`, async () => {
|
it(`txs by ${v.label} addr (after, reverse w/ unconf 2)`, async () => {
|
||||||
const one = await nclient.request(
|
const one = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`,
|
'GET', `/tx/address/${v.addr}`,
|
||||||
{limit: 3, reverse: true});
|
{limit: 3, reverse: true});
|
||||||
@ -501,32 +703,49 @@ describe('Indexer', function() {
|
|||||||
for (let i = 0; i < 3; i++)
|
for (let i = 0; i < 3; i++)
|
||||||
assert(unconfirmed.includes(one[i].hash));
|
assert(unconfirmed.includes(one[i].hash));
|
||||||
|
|
||||||
// The after hash is within the
|
|
||||||
// unconfirmed transactions.
|
|
||||||
const hash = one[2].hash;
|
const hash = one[2].hash;
|
||||||
|
|
||||||
const two = await nclient.request(
|
const two = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`,
|
'GET', `/tx/address/${v.addr}`,
|
||||||
{after: hash, limit: 3, reverse: true});
|
{after: hash, limit: 1, reverse: true});
|
||||||
|
|
||||||
assert.strictEqual(two.length, 3);
|
assert.strictEqual(two.length, 1);
|
||||||
for (let i = 0; i < 3; i++)
|
assert(unconfirmed.includes(two[0].hash));
|
||||||
assert(confirmed.includes(two[i].hash));
|
|
||||||
|
|
||||||
const all = await nclient.request(
|
const all = await nclient.request(
|
||||||
'GET', `/tx/address/${v.addr}`,
|
'GET', `/tx/address/${v.addr}`,
|
||||||
{limit: 6, reverse: true});
|
{limit: 4, reverse: true});
|
||||||
|
|
||||||
assert.strictEqual(all.length, 6);
|
assert.strictEqual(all.length, 4);
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++)
|
for (let i = 0; i < 4; i++)
|
||||||
assert(unconfirmed.includes(all[i].hash));
|
assert(unconfirmed.includes(all[i].hash));
|
||||||
|
|
||||||
for (let i = 3; i < 6; i++)
|
assert.deepEqual(sanitize(one.concat(two)), sanitize(all));
|
||||||
assert(confirmed.includes(all[i].hash));
|
|
||||||
|
|
||||||
assert.deepEqual(one.concat(two), all);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe('Errors', function() {
|
||||||
|
it('will give error if limit is exceeded', async () => {
|
||||||
|
await assert.asyncThrows(async () => {
|
||||||
|
await nclient.request(
|
||||||
|
'GET', `/tx/address/${vectors[0].addr}`, {limit: 101});
|
||||||
|
}, 'Limit above max');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will give error with invalid after hash', async () => {
|
||||||
|
await assert.asyncThrows(async () => {
|
||||||
|
await nclient.request(
|
||||||
|
'GET', `/tx/address/${vectors[0].addr}`, {after: 'deadbeef'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will give error with invalid reverse', async () => {
|
||||||
|
await assert.asyncThrows(async () => {
|
||||||
|
await nclient.request(
|
||||||
|
'GET', `/tx/address/${vectors[0].addr}`, {reverse: 'sure'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,6 +9,7 @@ const common = require('../lib/blockchain/common');
|
|||||||
const Block = require('../lib/primitives/block');
|
const Block = require('../lib/primitives/block');
|
||||||
const MempoolEntry = require('../lib/mempool/mempoolentry');
|
const MempoolEntry = require('../lib/mempool/mempoolentry');
|
||||||
const Mempool = require('../lib/mempool/mempool');
|
const Mempool = require('../lib/mempool/mempool');
|
||||||
|
const AddrIndexer = require('../lib/mempool/addrindexer');
|
||||||
const WorkerPool = require('../lib/workers/workerpool');
|
const WorkerPool = require('../lib/workers/workerpool');
|
||||||
const Chain = require('../lib/blockchain/chain');
|
const Chain = require('../lib/blockchain/chain');
|
||||||
const MTX = require('../lib/primitives/mtx');
|
const MTX = require('../lib/primitives/mtx');
|
||||||
@ -18,6 +19,7 @@ const Address = require('../lib/primitives/address');
|
|||||||
const Outpoint = require('../lib/primitives/outpoint');
|
const Outpoint = require('../lib/primitives/outpoint');
|
||||||
const Input = require('../lib/primitives/input');
|
const Input = require('../lib/primitives/input');
|
||||||
const Script = require('../lib/script/script');
|
const Script = require('../lib/script/script');
|
||||||
|
const Opcode = require('../lib/script/opcode');
|
||||||
const opcodes = Script.opcodes;
|
const opcodes = Script.opcodes;
|
||||||
const Witness = require('../lib/script/witness');
|
const Witness = require('../lib/script/witness');
|
||||||
const MemWallet = require('./util/memwallet');
|
const MemWallet = require('./util/memwallet');
|
||||||
@ -780,6 +782,40 @@ describe('Mempool', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('AddrIndexer', function () {
|
||||||
|
it('will not get key for witness program v1', function() {
|
||||||
|
const addrindex = new AddrIndexer();
|
||||||
|
|
||||||
|
// Create a witness program version 1 with
|
||||||
|
// 40 byte data push.
|
||||||
|
const script = new Script();
|
||||||
|
script.push(Opcode.fromSmall(1));
|
||||||
|
script.push(Opcode.fromData(Buffer.alloc(40)));
|
||||||
|
script.compile();
|
||||||
|
const addr = Address.fromScript(script);
|
||||||
|
|
||||||
|
const key = addrindex.getKey(addr);
|
||||||
|
|
||||||
|
assert.strictEqual(key, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will get key for witness program v0', function() {
|
||||||
|
const addrindex = new AddrIndexer();
|
||||||
|
|
||||||
|
// Create a witness program version 0 with
|
||||||
|
// 32 byte data push.
|
||||||
|
const script = new Script();
|
||||||
|
script.push(Opcode.fromSmall(0));
|
||||||
|
script.push(Opcode.fromData(Buffer.alloc(32)));
|
||||||
|
script.compile();
|
||||||
|
const addr = Address.fromScript(script);
|
||||||
|
|
||||||
|
const key = addrindex.getKey(addr);
|
||||||
|
|
||||||
|
assert.bufferEqual(key, Buffer.from('0a' + '00'.repeat(32), 'hex'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Mempool persistent cache', function () {
|
describe('Mempool persistent cache', function () {
|
||||||
const workers = new WorkerPool({
|
const workers = new WorkerPool({
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@ -115,8 +115,11 @@ assert.asyncThrows = async function asyncThrows(func, expectedError) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e;
|
err = e;
|
||||||
}
|
}
|
||||||
const re = new RegExp('^' + expectedError);
|
assert(err, 'Expected error.');
|
||||||
assert(re.test(err.message));
|
if (expectedError) {
|
||||||
|
const re = new RegExp('^' + expectedError);
|
||||||
|
assert(re.test(err.message), err.message);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function _isString(value, message, stackStartFunction) {
|
function _isString(value, message, stackStartFunction) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user