@@ -7,13 +7,16 @@ const assert = require('bsert');
77const { CoinSelector, CoinPointer} = require ( '../lib/wallet/coinselector' ) ;
88const TX = require ( '../lib/primitives/tx' ) ;
99const 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