wallet: add by height indexes for credits.
This commit is contained in:
parent
3c94eb369d
commit
b8ce31e9d8
4 changed files with 229 additions and 106 deletions
|
|
@ -162,8 +162,10 @@ exports.txdb = {
|
|||
s: bdb.key('s', ['hash256', 'uint32']),
|
||||
|
||||
// Coin Selector
|
||||
// by value + account
|
||||
// by account + value
|
||||
SV: bdb.key('SV', ['uint32', 'uint64', 'hash256', 'uint32']),
|
||||
// by account + height
|
||||
SH: bdb.key('SH', ['uint32', 'uint32', 'hash256', 'uint32']),
|
||||
|
||||
// Transaction
|
||||
t: bdb.key('t', ['hash256']),
|
||||
|
|
|
|||
|
|
@ -202,14 +202,25 @@ class TXDB {
|
|||
* @param {Batch} b
|
||||
* @param {Credit} credit
|
||||
* @param {Path} path
|
||||
* @param {Number?} oldHeight
|
||||
*/
|
||||
|
||||
indexCSCredit(b, credit, path) {
|
||||
indexCSCredit(b, credit, path, oldHeight) {
|
||||
const {coin} = credit;
|
||||
|
||||
// index coin by value + account.
|
||||
b.put(layout.SV.encode(
|
||||
path.account, coin.value, coin.hash, coin.index), null);
|
||||
|
||||
const height = coin.height === -1 ? UNCONFIRMED_HEIGHT : coin.height;
|
||||
b.put(layout.SH.encode(
|
||||
path.account, height, coin.hash, coin.index), null);
|
||||
|
||||
if (oldHeight != null) {
|
||||
const height = oldHeight === -1 ? UNCONFIRMED_HEIGHT : oldHeight;
|
||||
b.del(layout.SH.encode(
|
||||
path.account, height, coin.hash, coin.index));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -222,8 +233,12 @@ class TXDB {
|
|||
unindexCSCredit(b, credit, path) {
|
||||
const {coin} = credit;
|
||||
|
||||
// Remove coin by value + account.
|
||||
// Remove coin by account + value.
|
||||
b.del(layout.SV.encode(path.account, coin.value, coin.hash, coin.index));
|
||||
|
||||
// Remove coin by account + height
|
||||
const height = coin.height === -1 ? UNCONFIRMED_HEIGHT : coin.height;
|
||||
b.del(layout.SH.encode(path.account, height, coin.hash, coin.index));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1192,7 +1207,7 @@ class TXDB {
|
|||
}
|
||||
|
||||
await this.saveCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path, null);
|
||||
await this.watchOpensEarly(b, output);
|
||||
}
|
||||
|
||||
|
|
@ -1429,7 +1444,7 @@ class TXDB {
|
|||
credit.coin.height = height;
|
||||
|
||||
await this.saveCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path, -1);
|
||||
}
|
||||
|
||||
// Handle names.
|
||||
|
|
@ -1554,7 +1569,7 @@ class TXDB {
|
|||
|
||||
credit.spent = false;
|
||||
await this.saveCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1818,7 +1833,7 @@ class TXDB {
|
|||
credit.spent = true;
|
||||
own = true;
|
||||
await this.saveCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1870,6 +1885,7 @@ class TXDB {
|
|||
|
||||
// Update coin height and confirmed
|
||||
// balance. Save once again.
|
||||
const oldHeight = credit.coin.height;
|
||||
credit.coin.height = -1;
|
||||
|
||||
// If the coin was not discovered now, it means
|
||||
|
|
@ -1882,7 +1898,7 @@ class TXDB {
|
|||
}
|
||||
|
||||
await this.saveCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path);
|
||||
this.indexCSCredit(b, credit, path, oldHeight);
|
||||
}
|
||||
|
||||
// Unconfirm will also index OPENs as the transaction is now part of the
|
||||
|
|
@ -3815,6 +3831,58 @@ class TXDB {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get credits iterator sorted by height.
|
||||
* @param {Number} acct
|
||||
* @param {Object} [options]
|
||||
* @param {Number} [options.minHeight=0]
|
||||
* @param {Number} [options.maxHeight=UNCONFIRMED_HEIGHT]
|
||||
* @param {Number} [options.limit=-1]
|
||||
* @param {Boolean} [options.reverse=false]
|
||||
* @returns {AsyncGenerator<Credit>}
|
||||
*/
|
||||
|
||||
async *getAccountCreditIterByHeight(acct, options = {}) {
|
||||
assert(typeof acct === 'number');
|
||||
assert(acct >= 0);
|
||||
assert(options && typeof options === 'object');
|
||||
|
||||
let minHeight = 0;
|
||||
let maxHeight = UNCONFIRMED_HEIGHT;
|
||||
|
||||
if (options.minHeight != null) {
|
||||
assert(typeof options.minHeight === 'number');
|
||||
minHeight = options.minHeight;
|
||||
}
|
||||
|
||||
if (options.maxHeight != null) {
|
||||
assert(typeof options.maxHeight === 'number');
|
||||
maxHeight = options.maxHeight;
|
||||
}
|
||||
|
||||
assert(minHeight <= maxHeight);
|
||||
|
||||
const min = layout.SH.min(acct, minHeight);
|
||||
const max = layout.SH.max(acct, maxHeight);
|
||||
|
||||
const iter = this.bucket.iterator({
|
||||
gte: min,
|
||||
lte: max,
|
||||
limit: options.limit,
|
||||
reverse: options.reverse,
|
||||
keys: true,
|
||||
values: false
|
||||
});
|
||||
|
||||
for await (const {key} of iter) {
|
||||
const [,, hash, index] = layout.SH.decode(key);
|
||||
const credit = await this.getCredit(hash, index);
|
||||
|
||||
assert(credit);
|
||||
yield credit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a coin viewpoint.
|
||||
* @param {TX} tx
|
||||
|
|
|
|||
|
|
@ -5163,6 +5163,21 @@ class Wallet extends EventEmitter {
|
|||
return this.txdb.getAccountCreditIterByValue(acct, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get credits iterator sorted by height.
|
||||
* @param {Number} acct
|
||||
* @param {Object} [options]
|
||||
* @param {Number} [options.minHeight=0]
|
||||
* @param {Number} [options.maxHeight=UNCONFIRMED_HEIGHT]
|
||||
* @param {Number} [options.limit=-1]
|
||||
* @param {Boolean} [options.reverse=false]
|
||||
* @returns {AsyncGenerator<Credit>}
|
||||
*/
|
||||
|
||||
getAccountCreditIterByHeight(acct, options = {}) {
|
||||
return this.txdb.getAccountCreditIterByHeight(acct, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "smart" coins.
|
||||
* @param {(String|Number)?} acct
|
||||
|
|
|
|||
|
|
@ -44,7 +44,13 @@ describe('Wallet Coin Selection', function() {
|
|||
wallet = null;
|
||||
};
|
||||
|
||||
describe('Coin Selection Indexes', function() {
|
||||
const indexes = [
|
||||
'value',
|
||||
'height'
|
||||
];
|
||||
|
||||
for (const indexType of indexes) {
|
||||
describe(`Coin Selection Indexes (${indexType})`, function() {
|
||||
const TX_OPTIONS = [
|
||||
{ value: 2e6, address: primutils.randomP2PKAddress() },
|
||||
// address will be generated using wallet.
|
||||
|
|
@ -57,33 +63,36 @@ describe('Wallet Coin Selection', function() {
|
|||
const TOTAL_COINS = 4;
|
||||
const TOTAL_FUNDS = 1e6 + 2e6 + 3e6 + 4e6;
|
||||
|
||||
let isSorted, getIterMethodName;
|
||||
|
||||
before(() => {
|
||||
switch (indexType) {
|
||||
case 'value':
|
||||
isSorted = isSortedByValue;
|
||||
getIterMethodName = 'getAccountCreditIterByValue';
|
||||
break;
|
||||
case 'height':
|
||||
isSorted = isSortedByHeight;
|
||||
getIterMethodName = 'getAccountCreditIterByHeight';
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid index type.');
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(beforeFn);
|
||||
afterEach(afterFn);
|
||||
|
||||
/**
|
||||
* @param {Credit[]} credits
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
const isSortedByValue = (credit) => {
|
||||
for (let i = 1; i < credit.length; i++) {
|
||||
if (credit[i].value > credit[i - 1].value)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
it('should index unconfirmed tx output', async () => {
|
||||
const txs = await createInboundTXs(wallet, TX_OPTIONS, false);
|
||||
await wallet.wdb.addTX(txs[0]);
|
||||
|
||||
const iter = wallet.getAccountCreditIterByValue(0);
|
||||
const creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
const iter = wallet[getIterMethodName](0);
|
||||
const credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, -1);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
|
@ -100,12 +109,12 @@ describe('Wallet Coin Selection', function() {
|
|||
await wdb.addTX(spendAll.toTX());
|
||||
|
||||
// We still have the coin, even thought it is flagged: .spent = true
|
||||
const iter = wallet.getAccountCreditIterByValue(0);
|
||||
const creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
const iter = wallet[getIterMethodName](0);
|
||||
const credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, curBlock(wdb).height);
|
||||
assert.strictEqual(credit.spent, true);
|
||||
}
|
||||
|
|
@ -115,12 +124,12 @@ describe('Wallet Coin Selection', function() {
|
|||
await fundWallet(wallet, TX_OPTIONS, false);
|
||||
const currentBlock = curBlock(wdb);
|
||||
|
||||
const iter = wallet.getAccountCreditIterByValue(0);
|
||||
const creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
const iter = wallet[getIterMethodName](0);
|
||||
const credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, currentBlock.height);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
|
@ -135,33 +144,33 @@ describe('Wallet Coin Selection', function() {
|
|||
outputs: [{ value: TOTAL_FUNDS, address: primutils.randomP2PKAddress() }]
|
||||
});
|
||||
|
||||
let iter = wallet.getAccountCreditIterByValue(0);
|
||||
let creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
let iter = wallet[getIterMethodName](0);
|
||||
let credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, currentBlock.height);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
||||
await wdb.addBlock(nextBlock(wdb), [spendAll.toTX()]);
|
||||
|
||||
iter = wallet.getAccountCreditIterByValue(0);
|
||||
creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, 0);
|
||||
iter = wallet[getIterMethodName](0);
|
||||
credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, 0);
|
||||
});
|
||||
|
||||
it('should index confirm tx output', async () => {
|
||||
const txs = await createInboundTXs(wallet, TX_OPTIONS, false);
|
||||
await wdb.addTX(txs[0]);
|
||||
|
||||
let iter = wallet.getAccountCreditIterByValue(0);
|
||||
let creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
let iter = wallet[getIterMethodName](0);
|
||||
let credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, -1);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
|
@ -169,12 +178,12 @@ describe('Wallet Coin Selection', function() {
|
|||
await wdb.addBlock(nextBlock(wdb), txs);
|
||||
const currentBlock = curBlock(wdb);
|
||||
|
||||
iter = wallet.getAccountCreditIterByValue(0);
|
||||
creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
iter = wallet[getIterMethodName](0);
|
||||
credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, currentBlock.height);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
|
@ -192,21 +201,21 @@ describe('Wallet Coin Selection', function() {
|
|||
|
||||
await wdb.addTX(spendAllTX);
|
||||
|
||||
let iter = wallet.getAccountCreditIterByValue(0);
|
||||
let creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
let iter = wallet[getIterMethodName](0);
|
||||
let credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, currentBlock.height);
|
||||
assert.strictEqual(credit.spent, true);
|
||||
}
|
||||
|
||||
await wdb.addBlock(nextBlock(wdb), [spendAllTX]);
|
||||
|
||||
iter = wallet.getAccountCreditIterByValue(0);
|
||||
creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, 0);
|
||||
iter = wallet[getIterMethodName](0);
|
||||
credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, 0);
|
||||
});
|
||||
|
||||
it('should index disconnect tx output', async () => {
|
||||
|
|
@ -214,12 +223,12 @@ describe('Wallet Coin Selection', function() {
|
|||
|
||||
const currentBlock = curBlock(wdb);
|
||||
|
||||
let iter = wallet.getAccountCreditIterByValue(0);
|
||||
let creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
let iter = wallet[getIterMethodName](0);
|
||||
let credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, currentBlock.height);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
|
@ -228,12 +237,12 @@ describe('Wallet Coin Selection', function() {
|
|||
await wdb.removeBlock(currentBlock);
|
||||
|
||||
// Only thing that must change is the HEIGHT.
|
||||
iter = wallet.getAccountCreditIterByValue(0);
|
||||
creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
iter = wallet[getIterMethodName](0);
|
||||
credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, -1);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
|
@ -251,18 +260,18 @@ describe('Wallet Coin Selection', function() {
|
|||
const spendAllTX = spendAll.toTX();
|
||||
await wdb.addBlock(nextBlock(wdb), [spendAllTX]);
|
||||
|
||||
let iter = wallet.getAccountCreditIterByValue(0);
|
||||
let creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, 0);
|
||||
let iter = wallet[getIterMethodName](0);
|
||||
let credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, 0);
|
||||
|
||||
await wdb.removeBlock(curBlock(wdb));
|
||||
|
||||
iter = wallet.getAccountCreditIterByValue(0);
|
||||
creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
iter = wallet[getIterMethodName](0);
|
||||
credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, createCoinHeight);
|
||||
assert.strictEqual(credit.spent, true);
|
||||
}
|
||||
|
|
@ -272,12 +281,12 @@ describe('Wallet Coin Selection', function() {
|
|||
const txs = await createInboundTXs(wallet, TX_OPTIONS, false);
|
||||
await wdb.addTX(txs[0]);
|
||||
|
||||
let iter = wallet.getAccountCreditIterByValue(0);
|
||||
let creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
let iter = wallet[getIterMethodName](0);
|
||||
let credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, -1);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
|
@ -289,9 +298,9 @@ describe('Wallet Coin Selection', function() {
|
|||
|
||||
await wdb.addBlock(nextBlock(wdb), [mtx.toTX()]);
|
||||
|
||||
iter = wallet.getAccountCreditIterByValue(0);
|
||||
creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, 0);
|
||||
iter = wallet[getIterMethodName](0);
|
||||
credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, 0);
|
||||
});
|
||||
|
||||
it('should index erase tx input', async () => {
|
||||
|
|
@ -305,12 +314,12 @@ describe('Wallet Coin Selection', function() {
|
|||
|
||||
await wdb.addTX(spendAll.toTX());
|
||||
|
||||
let iter = wallet.getAccountCreditIterByValue(0);
|
||||
let creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
let iter = wallet[getIterMethodName](0);
|
||||
let credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, -1);
|
||||
assert.strictEqual(credit.spent, true);
|
||||
}
|
||||
|
|
@ -322,9 +331,9 @@ describe('Wallet Coin Selection', function() {
|
|||
|
||||
await wdb.addBlock(nextBlock(wdb), [mtx.toTX()]);
|
||||
|
||||
iter = wallet.getAccountCreditIterByValue(0);
|
||||
creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, 0);
|
||||
iter = wallet[getIterMethodName](0);
|
||||
credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, 0);
|
||||
});
|
||||
|
||||
it('should index erase (block) tx output', async () => {
|
||||
|
|
@ -336,23 +345,24 @@ describe('Wallet Coin Selection', function() {
|
|||
|
||||
const currentBlock = curBlock(wdb);
|
||||
|
||||
let iter = wallet.getAccountCreditIterByValue(0);
|
||||
let creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, TOTAL_COINS);
|
||||
assert(isSortedByValue(creditsByValue), 'Credits not sorted.');
|
||||
let iter = wallet[getIterMethodName](0);
|
||||
let credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, TOTAL_COINS);
|
||||
assert(isSorted(credits), 'Credits not sorted.');
|
||||
|
||||
for (const credit of creditsByValue) {
|
||||
for (const credit of credits) {
|
||||
assert.strictEqual(credit.coin.height, currentBlock.height);
|
||||
assert.strictEqual(credit.spent, false);
|
||||
}
|
||||
|
||||
await wdb.removeBlock(currentBlock);
|
||||
|
||||
iter = wallet.getAccountCreditIterByValue(0);
|
||||
creditsByValue = await collectIter(iter);
|
||||
assert.strictEqual(creditsByValue.length, 0);
|
||||
iter = wallet[getIterMethodName](0);
|
||||
credits = await collectIter(iter);
|
||||
assert.strictEqual(credits.length, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Selection types', function() {
|
||||
beforeEach(beforeFn);
|
||||
|
|
@ -652,3 +662,31 @@ async function collectIter(iter) {
|
|||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Credit[]} credits
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
function isSortedByValue(credits) {
|
||||
for (let i = 1; i < credits.length; i++) {
|
||||
if (credits[i].value > credits[i - 1].value)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Credit[]} credits
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
function isSortedByHeight(credits) {
|
||||
for (let i = 1; i < credits.length; i++) {
|
||||
if (credits[i].coin.height > credits[i - 1].coin.height)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue