Skip to content

Commit da4a0d0

Browse files
test: integration test now use real-world data to test and demonstrates improvement
Signed-off-by: theanmolsharma <anmolsharma0234@gmail.com>
1 parent 876fd40 commit da4a0d0

File tree

2 files changed

+25109
-98
lines changed

2 files changed

+25109
-98
lines changed

test/coinselector-test.js

Lines changed: 107 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ const assert = require('bsert');
77
const {CoinSelector, CoinPointer} = require('../lib/wallet/coinselector');
88
const TX = require('../lib/primitives/tx');
99
const random = require('bcrypto/lib/random');
10-
const Address = require('../lib/primitives/address');
11-
const consensus = require('../lib/protocol/consensus');
12-
const FullNode = require('../lib/node/fullnode');
13-
const plugin = require('../lib/wallet/plugin');
14-
const {testdir, rimraf, forValue} = require('./util/common');
15-
16-
describe('Coin Selector', function() {
10+
const WorkerPool = require('../lib/workers/workerpool');
11+
const WalletDB = require('../lib/wallet/walletdb');
12+
const Amount = require('../lib/btc/amount');
13+
const hash256 = require('bcrypto/lib/hash256');
14+
const data = require('./data/bustabit-2019-2020-tiny-hot-wallet.json');
15+
const MTX = require('../lib/primitives/mtx');
16+
const Input = require('../lib/primitives/input');
17+
const Outpoint = require('../lib/primitives/outpoint');
18+
19+
describe('Coin Selector', function () {
1720
function build(values) {
1821
const pointers = [];
1922
for (let i = 0; i < values.length; i++) {
@@ -30,18 +33,18 @@ describe('Coin Selector', function() {
3033
const costOfChange = 345; // this is cost of producing and spending a change output
3134

3235
const targetSet1 = [221000, 220000, 215000, 214000, 211000, 208000, 206000, 203000, 201000,
33-
195000, 186000, 178000, 166000, 160000, 155000, 152000, 146000, 139000, 119000,
34-
116000, 110000, 109000, 108000, 106000, 105000, 101000, 98000, 96000, 90000,
35-
85000, 82000, 81000, 80000, 78000, 71000, 67000, 66000, 63000, 55000, 53000,
36-
51000, 45000, 44000, 41000, 38000, 36000, 23000, 19000, 16000, 11000, 6000];
36+
195000, 186000, 178000, 166000, 160000, 155000, 152000, 146000, 139000, 119000,
37+
116000, 110000, 109000, 108000, 106000, 105000, 101000, 98000, 96000, 90000,
38+
85000, 82000, 81000, 80000, 78000, 71000, 67000, 66000, 63000, 55000, 53000,
39+
51000, 45000, 44000, 41000, 38000, 36000, 23000, 19000, 16000, 11000, 6000];
3740

3841
const targetSet2 = [150000, 130000, 101000, 50000, 15000, 13000, 5000, 3000];
3942

4043
const targetSet3 = [219000, 217000, 213000, 212000, 211000, 205000, 202000, 201000, 190000,
41-
185000, 183000, 182000, 181000, 170000, 155000, 153000, 152000, 151000, 130000,
42-
120000, 110000, 105000, 103000, 102000, 101000];
44+
185000, 183000, 182000, 181000, 170000, 155000, 153000, 152000, 151000, 130000,
45+
120000, 110000, 105000, 103000, 102000, 101000];
4346

44-
describe('Branch and Bound Selection', function() {
47+
describe('Branch and Bound Selection', function () {
4548
// try to select single UTXOs
4649
for (const value of values) {
4750
it(`should select target=${value} using Branch and Bound`, () => {
@@ -114,7 +117,7 @@ describe('Coin Selector', function() {
114117
}
115118
});
116119

117-
describe('Lowest Larger Selection', function() {
120+
describe('Lowest Larger Selection', function () {
118121
// try selecting a single UTXO
119122
for (const value of values) {
120123
it(`should select target=${value} using Lowest Larger`, () => {
@@ -181,7 +184,7 @@ describe('Coin Selector', function() {
181184
});
182185
});
183186

184-
describe('Single Random Draw Selection', function() {
187+
describe('Single Random Draw Selection', function () {
185188
it('should be able to fund all values in range 1 to 221000 using Single Random Draw', () => {
186189
for (let target = 1; target <= 221000; target++) {
187190
const selection = selector.selectSRD(target);
@@ -197,100 +200,106 @@ describe('Coin Selector', function() {
197200
});
198201
});
199202

200-
describe('Integration', function () {
201-
this.timeout(30000);
203+
const workers = new WorkerPool({
204+
enabled: true,
205+
size: 2
206+
});
202207

203-
const prefix = testdir('coinselection');
204-
const node = new FullNode({
205-
prefix,
206-
network: 'regtest'
207-
});
208-
node.use(plugin);
209-
const {wdb} = node.plugins.walletdb;
210-
let miner, minerAddr;
211-
let alice, bob;
208+
const wdb = new WalletDB({workers});
209+
210+
function fromU32(num) {
211+
const data = Buffer.allocUnsafe(4);
212+
data.writeUInt32LE(num, 0, true);
213+
return data;
214+
}
215+
216+
function nextBlock(wdb) {
217+
return fakeBlock(wdb.state.height + 1);
218+
}
219+
220+
function fakeBlock(height) {
221+
const prev = hash256.digest(fromU32((height - 1) >>> 0));
222+
const hash = hash256.digest(fromU32(height >>> 0));
223+
const root = hash256.digest(fromU32((height | 0x80000000) >>> 0));
224+
225+
return {
226+
hash: hash,
227+
prevBlock: prev,
228+
merkleRoot: root,
229+
time: 500000000 + (height * (10 * 60)),
230+
bits: 0,
231+
nonce: 0,
232+
height: height
233+
};
234+
}
235+
236+
function dummyInput() {
237+
const hash = random.randomBytes(32);
238+
return Input.fromOutpoint(new Outpoint(hash, 0));
239+
}
212240

213-
const actualCoinbaseMaturity = consensus.COINBASE_MATURITY;
241+
describe('Integration', function () {
242+
this.timeout(1000000);
214243

215244
before(async () => {
216-
consensus.COINBASE_MATURITY = 0;
217-
await node.open();
218-
219-
miner = await wdb.create();
220-
minerAddr = await miner.receiveAddress();
221-
222-
alice = await wdb.create();
223-
bob = await wdb.create();
245+
await wdb.open();
246+
await workers.open();
224247
});
225248

226-
after(async () => {
227-
await node.close();
228-
await rimraf(prefix);
229-
consensus.COINBASE_MATURITY = actualCoinbaseMaturity;
230-
});
249+
let oldBalance, newBalance, oldCoins, newCoins;
231250

232-
it('should fund miner', async () => {
233-
const blocks = 1500;
234-
await node.rpc.mineBlocks(blocks, minerAddr);
235-
await forValue(node.chain, 'height', blocks);
236-
await forValue(wdb, 'height', node.chain.height);
251+
after(async () => {
252+
console.log('Amount saved in fees :', newBalance - oldBalance);
253+
console.log('Coins in UTXO pool using old selection :', oldCoins);
254+
console.log('Coins in UTXO pool using new selection :', newCoins);
255+
await wdb.close();
256+
await workers.close();
237257
});
238258

239-
{
240-
let value = 100000;
241-
for (let b = 0; b < 10; b++) {
242-
it(`should fund test wallet with range of coins: block ${b}`, async () => {
243-
// 10 blocks with 100 transactions each
244-
// exponentially increasing coin sizes starting at 0.00001 BTC
245-
for (let t = 0; t < 100; t++) {
246-
let address = await alice.receiveAddress();
247-
await miner.send({
248-
outputs: [{value, address}],
249-
useSelectEstimate: true
250-
});
251-
address = await bob.receiveAddress();
252-
await miner.send({
259+
for (const useSelectEstimate of [true, false]) {
260+
it('should send transactions using old selection', async () => {
261+
const alice = await wdb.create();
262+
const bob = await wdb.create();
263+
264+
for (const payment of data) {
265+
let value = Amount.value(payment.value);
266+
const rate = Amount.value(payment.rate);
267+
268+
// remove dust outputs
269+
if (Math.abs(value) < 500)
270+
continue;
271+
272+
let tx;
273+
274+
if (value > 0) {
275+
// send to Alice's wallet
276+
const t1 = new MTX();
277+
t1.addInput(dummyInput());
278+
t1.addOutput(await alice.receiveAddress(), value);
279+
tx = t1.toTX();
280+
} else {
281+
// send from Alice's wallet
282+
const address = await bob.receiveAddress();
283+
value = -value;
284+
tx = await alice.send({
253285
outputs: [{value, address}],
254-
useSelectEstimate: true
286+
rate,
287+
useSelectEstimate
255288
});
256-
value = parseInt(value * 1.01);
257289
}
258-
await node.rpc.mineBlocks(1, minerAddr);
259-
await forValue(wdb, 'height', node.chain.height);
260-
});
261-
}
262-
}
263-
264-
{
265-
const values = [];
266-
let v = 10000;
267290

268-
for (let i = 0; i < 140; i++) {
269-
values.push(v);
270-
v = parseInt(v * 1.1);
271-
}
272-
const rate = 10000;
273-
for (let i = 0; i < 140; i++) {
274-
it(`should comapre old and new coin selectors: ${values[i]} : iteration: ${i + 1}`, async () => {
275-
const address = Address.fromProgram(0, random.randomBytes(20));
276-
277-
const value = values[i];
278-
const old = await alice.send({
279-
outputs: [{value, address}],
280-
useSelectEstimate: true,
281-
rate
282-
});
283-
284-
const bnb = await bob.send({
285-
outputs: [{value, address}],
286-
rate
287-
});
288-
289-
const oldSize = old.getVirtualSize();
290-
const newSize = bnb.getVirtualSize();
291-
292-
assert(oldSize >= newSize || oldSize + 5 > newSize);
293-
});
294-
}
291+
// confirm tx
292+
await wdb.addBlock(nextBlock(wdb), [tx]);
293+
}
294+
// check balance after simulation
295+
const balance = await alice.getBalance();
296+
if (useSelectEstimate) {
297+
oldBalance = balance.unconfirmed;
298+
oldCoins = balance.coin;
299+
} else {
300+
newBalance = balance.unconfirmed;
301+
newCoins = balance.coin;
302+
}
303+
});
295304
}
296305
});

0 commit comments

Comments
 (0)