Merge branch 'master' into nymkappa/order-isp
This commit is contained in:
		
						commit
						7e873e6637
					
				| @ -171,52 +171,58 @@ Helpful link: https://gist.github.com/System-Glitch/cb4e87bf1ae3fec9925725bb3ebe | |||||||
| 
 | 
 | ||||||
| Run bitcoind on regtest: | Run bitcoind on regtest: | ||||||
|    ``` |    ``` | ||||||
|    bitcoind -regtest -rpcport=8332 |    bitcoind -regtest | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| Create a new wallet, if needed: | Create a new wallet, if needed: | ||||||
|    ``` |    ``` | ||||||
|    bitcoin-cli -regtest -rpcport=8332 createwallet test |    bitcoin-cli -regtest createwallet test | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| Load wallet (this command may take a while if you have lot of UTXOs): | Load wallet (this command may take a while if you have lot of UTXOs): | ||||||
|    ``` |    ``` | ||||||
|    bitcoin-cli -regtest -rpcport=8332 loadwallet test |    bitcoin-cli -regtest loadwallet test | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| Get a new address: | Get a new address: | ||||||
|    ``` |    ``` | ||||||
|    address=$(./src/bitcoin-cli -regtest -rpcport=8332 getnewaddress) |    address=$(bitcoin-cli -regtest getnewaddress) | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| Mine blocks to the previously generated address. You need at least 101 blocks before you can spend. This will take some time to execute (~1 min): | Mine blocks to the previously generated address. You need at least 101 blocks before you can spend. This will take some time to execute (~1 min): | ||||||
|    ``` |    ``` | ||||||
|    bitcoin-cli -regtest -rpcport=8332 generatetoaddress 101 $address |    bitcoin-cli -regtest generatetoaddress 101 $address | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| Send 0.1 BTC at 5 sat/vB to another address: | Send 0.1 BTC at 5 sat/vB to another address: | ||||||
|    ``` |    ``` | ||||||
|    ./src/bitcoin-cli -named -regtest -rpcport=8332 sendtoaddress address=$(./src/bitcoin-cli -regtest -rpcport=8332 getnewaddress) amount=0.1 fee_rate=5 |    bitcoin-cli -named -regtest sendtoaddress address=$(bitcoin-cli -regtest getnewaddress) amount=0.1 fee_rate=5 | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| See more example of `sendtoaddress`: | See more example of `sendtoaddress`: | ||||||
|    ``` |    ``` | ||||||
|    ./src/bitcoin-cli sendtoaddress # will print the help |    bitcoin-cli sendtoaddress # will print the help | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| Mini script to generate transactions with random TX fee-rate (between 1 to 100 sat/vB). It's slow so don't expect to use this to test mempool spam, except if you let it run for a long time, or maybe with multiple regtest nodes connected to each other. | Mini script to generate random network activity (random TX count with random tx fee-rate). It's slow so don't expect to use this to test mempool spam, except if you let it run for a long time, or maybe with multiple regtest nodes connected to each other. | ||||||
|    ``` |    ``` | ||||||
|    #!/bin/bash |    #!/bin/bash | ||||||
|    address=$(./src/bitcoin-cli -regtest -rpcport=8332 getnewaddress) |    address=$(bitcoin-cli -regtest getnewaddress) | ||||||
|  |    bitcoin-cli -regtest generatetoaddress 101 $address | ||||||
|    for i in {1..1000000} |    for i in {1..1000000} | ||||||
|    do |    do | ||||||
|      ./src/bitcoin-cli -regtest -rpcport=8332 -named sendtoaddress address=$address amount=0.01 fee_rate=$(jot -r 1  1 100) |       for y in $(seq 1 "$(jot -r 1 1 1000)") | ||||||
|  |       do | ||||||
|  |          bitcoin-cli -regtest -named sendtoaddress address=$address amount=0.01 fee_rate=$(jot -r 1 1 100) | ||||||
|  |       done | ||||||
|  |       bitcoin-cli -regtest generatetoaddress 1 $address | ||||||
|  |       sleep 5 | ||||||
|    done |    done | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| Generate block at regular interval (every 10 seconds in this example): | Generate block at regular interval (every 10 seconds in this example): | ||||||
|    ``` |    ``` | ||||||
|    watch -n 10 "./src/bitcoin-cli -regtest -rpcport=8332 generatetoaddress 1 $address" |    watch -n 10 "bitcoin-cli -regtest generatetoaddress 1 $address" | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
| ### Mining pools update | ### Mining pools update | ||||||
|  | |||||||
| @ -11,19 +11,33 @@ import { Common } from './common'; | |||||||
| class DiskCache { | class DiskCache { | ||||||
|   private cacheSchemaVersion = 3; |   private cacheSchemaVersion = 3; | ||||||
| 
 | 
 | ||||||
|  |   private static TMP_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/tmp-cache.json'; | ||||||
|  |   private static TMP_FILE_NAMES = config.MEMPOOL.CACHE_DIR + '/tmp-cache{number}.json'; | ||||||
|   private static FILE_NAME = config.MEMPOOL.CACHE_DIR + '/cache.json'; |   private static FILE_NAME = config.MEMPOOL.CACHE_DIR + '/cache.json'; | ||||||
|   private static FILE_NAMES = config.MEMPOOL.CACHE_DIR + '/cache{number}.json'; |   private static FILE_NAMES = config.MEMPOOL.CACHE_DIR + '/cache{number}.json'; | ||||||
|   private static CHUNK_FILES = 25; |   private static CHUNK_FILES = 25; | ||||||
|   private isWritingCache = false; |   private isWritingCache = false; | ||||||
| 
 | 
 | ||||||
|   constructor() { } |   constructor() { | ||||||
|  |     if (!cluster.isMaster) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     process.on('SIGINT', (e) => { | ||||||
|  |       this.saveCacheToDiskSync(); | ||||||
|  |       process.exit(2); | ||||||
|  |     }); | ||||||
|  |     process.on('SIGTERM', (e) => { | ||||||
|  |       this.saveCacheToDiskSync(); | ||||||
|  |       process.exit(2); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   async $saveCacheToDisk(): Promise<void> { |   async $saveCacheToDisk(): Promise<void> { | ||||||
|     if (!cluster.isPrimary) { |     if (!cluster.isPrimary) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     if (this.isWritingCache) { |     if (this.isWritingCache) { | ||||||
|       logger.debug('Saving cache already in progress. Skipping.') |       logger.debug('Saving cache already in progress. Skipping.'); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     try { |     try { | ||||||
| @ -61,7 +75,56 @@ class DiskCache { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   wipeCache() { |   saveCacheToDiskSync(): void { | ||||||
|  |     if (!cluster.isPrimary) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if (this.isWritingCache) { | ||||||
|  |       logger.debug('Saving cache already in progress. Skipping.'); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     try { | ||||||
|  |       logger.debug('Writing mempool and blocks data to disk cache (sync)...'); | ||||||
|  |       this.isWritingCache = true; | ||||||
|  | 
 | ||||||
|  |       const mempool = memPool.getMempool(); | ||||||
|  |       const mempoolArray: TransactionExtended[] = []; | ||||||
|  |       for (const tx in mempool) { | ||||||
|  |         mempoolArray.push(mempool[tx]); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       Common.shuffleArray(mempoolArray); | ||||||
|  | 
 | ||||||
|  |       const chunkSize = Math.floor(mempoolArray.length / DiskCache.CHUNK_FILES); | ||||||
|  | 
 | ||||||
|  |       fs.writeFileSync(DiskCache.TMP_FILE_NAME, JSON.stringify({ | ||||||
|  |         cacheSchemaVersion: this.cacheSchemaVersion, | ||||||
|  |         blocks: blocks.getBlocks(), | ||||||
|  |         blockSummaries: blocks.getBlockSummaries(), | ||||||
|  |         mempool: {}, | ||||||
|  |         mempoolArray: mempoolArray.splice(0, chunkSize), | ||||||
|  |       }), { flag: 'w' }); | ||||||
|  |       for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { | ||||||
|  |         fs.writeFileSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({ | ||||||
|  |           mempool: {}, | ||||||
|  |           mempoolArray: mempoolArray.splice(0, chunkSize), | ||||||
|  |         }), { flag: 'w' }); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       fs.renameSync(DiskCache.TMP_FILE_NAME, DiskCache.FILE_NAME); | ||||||
|  |       for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { | ||||||
|  |         fs.renameSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), DiskCache.FILE_NAMES.replace('{number}', i.toString())); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       logger.debug('Mempool and blocks data saved to disk cache'); | ||||||
|  |       this.isWritingCache = false; | ||||||
|  |     } catch (e) { | ||||||
|  |       logger.warn('Error writing to cache file: ' + (e instanceof Error ? e.message : e)); | ||||||
|  |       this.isWritingCache = false; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   wipeCache(): void { | ||||||
|     logger.notice(`Wiping nodejs backend cache/cache*.json files`); |     logger.notice(`Wiping nodejs backend cache/cache*.json files`); | ||||||
|     try { |     try { | ||||||
|       fs.unlinkSync(DiskCache.FILE_NAME); |       fs.unlinkSync(DiskCache.FILE_NAME); | ||||||
| @ -83,7 +146,7 @@ class DiskCache { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   loadMempoolCache() { |   loadMempoolCache(): void { | ||||||
|     if (!fs.existsSync(DiskCache.FILE_NAME)) { |     if (!fs.existsSync(DiskCache.FILE_NAME)) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -107,7 +107,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|           this.blocks.unshift(block); |           this.blocks.unshift(block); | ||||||
|           this.blocks = this.blocks.slice(0, this.dynamicBlocksAmount); |           this.blocks = this.blocks.slice(0, this.dynamicBlocksAmount); | ||||||
| 
 | 
 | ||||||
|           if (txConfirmed) { |           if (txConfirmed && this.height === block.height) { | ||||||
|             this.markHeight = block.height; |             this.markHeight = block.height; | ||||||
|             this.moveArrowToPosition(true, true); |             this.moveArrowToPosition(true, true); | ||||||
|           } else { |           } else { | ||||||
|  | |||||||
| @ -53,3 +53,8 @@ form { | |||||||
|   margin-top: 1px; |   margin-top: 1px; | ||||||
|   margin-right: 2px; |   margin-right: 2px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | input:focus { | ||||||
|  |   box-shadow: none; | ||||||
|  |   border-color: #1b1f2c; | ||||||
|  | } | ||||||
|  | |||||||
| @ -488,7 +488,7 @@ | |||||||
|           <div class="effective-fee-container"> |           <div class="effective-fee-container"> | ||||||
|             {{ tx.effectiveFeePerVsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span> |             {{ tx.effectiveFeePerVsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span> | ||||||
|             <ng-template [ngIf]="tx.status.confirmed"> |             <ng-template [ngIf]="tx.status.confirmed"> | ||||||
|               <app-tx-fee-rating class="d-none d-lg-inline ml-2" *ngIf="tx.fee" [tx]="tx"></app-tx-fee-rating> |               <app-tx-fee-rating class="ml-2 mr-2" *ngIf="tx.fee || tx.effectiveFeePerVsize" [tx]="tx"></app-tx-fee-rating> | ||||||
|             </ng-template> |             </ng-template> | ||||||
|           </div> |           </div> | ||||||
|           <button type="button" class="btn btn-outline-info btn-sm btn-small-height float-right" (click)="showCpfpDetails = !showCpfpDetails">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon></button> |           <button type="button" class="btn btn-outline-info btn-sm btn-small-height float-right" (click)="showCpfpDetails = !showCpfpDetails">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon></button> | ||||||
|  | |||||||
| @ -347,7 +347,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|     this.blocksSubscription = this.stateService.blocks$.subscribe(([block, txConfirmed]) => { |     this.blocksSubscription = this.stateService.blocks$.subscribe(([block, txConfirmed]) => { | ||||||
|       this.latestBlock = block; |       this.latestBlock = block; | ||||||
| 
 | 
 | ||||||
|       if (txConfirmed && this.tx) { |       if (txConfirmed && this.tx && !this.tx.status.confirmed) { | ||||||
|         this.tx.status = { |         this.tx.status = { | ||||||
|           confirmed: true, |           confirmed: true, | ||||||
|           block_height: block.height, |           block_height: block.height, | ||||||
| @ -496,7 +496,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|   @HostListener('window:resize', ['$event']) |   @HostListener('window:resize', ['$event']) | ||||||
|   setGraphSize(): void { |   setGraphSize(): void { | ||||||
|     if (this.graphContainer) { |     if (this.graphContainer) { | ||||||
|  |       setTimeout(() => { | ||||||
|         this.graphWidth = this.graphContainer.nativeElement.clientWidth; |         this.graphWidth = this.graphContainer.nativeElement.clientWidth; | ||||||
|  |       }, 1); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -208,8 +208,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { | |||||||
|     this.outputs = this.initLines('out', voutWithFee, totalValue, this.maxStrands); |     this.outputs = this.initLines('out', voutWithFee, totalValue, this.maxStrands); | ||||||
| 
 | 
 | ||||||
|     this.middle = { |     this.middle = { | ||||||
|       path: `M ${(this.width / 2) - this.midWidth} ${(this.height / 2) + 0.5} L ${(this.width / 2) + this.midWidth} ${(this.height / 2) + 0.5}`, |       path: `M ${(this.width / 2) - this.midWidth} ${(this.height / 2) + 0.25} L ${(this.width / 2) + this.midWidth} ${(this.height / 2) + 0.25}`, | ||||||
|       style: `stroke-width: ${this.combinedWeight + 1}; stroke: ${this.gradient[1]}` |       style: `stroke-width: ${this.combinedWeight + 0.5}; stroke: ${this.gradient[1]}` | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     this.hasLine = this.inputs.reduce((line, put) => line || !put.zeroValue, false) |     this.hasLine = this.inputs.reduce((line, put) => line || !put.zeroValue, false) | ||||||
| @ -266,7 +266,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { | |||||||
|     const lineParams = weights.map((w, i) => { |     const lineParams = weights.map((w, i) => { | ||||||
|       return { |       return { | ||||||
|         weight: w, |         weight: w, | ||||||
|         thickness: xputs[i].value === 0 ? this.zeroValueThickness : Math.max(this.minWeight - 1, w) + 1, |         thickness: xputs[i].value === 0 ? this.zeroValueThickness : Math.min(this.combinedWeight + 0.5, Math.max(this.minWeight - 1, w) + 1), | ||||||
|         offset: 0, |         offset: 0, | ||||||
|         innerY: 0, |         innerY: 0, | ||||||
|         outerY: 0, |         outerY: 0, | ||||||
| @ -278,7 +278,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { | |||||||
| 
 | 
 | ||||||
|     // bounds of the middle segment
 |     // bounds of the middle segment
 | ||||||
|     const innerTop = (this.height / 2) - (this.combinedWeight / 2); |     const innerTop = (this.height / 2) - (this.combinedWeight / 2); | ||||||
|     const innerBottom = innerTop + this.combinedWeight; |     const innerBottom = innerTop + this.combinedWeight + 0.5; | ||||||
|     // tracks the visual bottom of the endpoints of the previous line
 |     // tracks the visual bottom of the endpoints of the previous line
 | ||||||
|     let lastOuter = 0; |     let lastOuter = 0; | ||||||
|     let lastInner = innerTop; |     let lastInner = innerTop; | ||||||
| @ -303,7 +303,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { | |||||||
| 
 | 
 | ||||||
|       // set the vertical position of the (center of the) outer side of the line
 |       // set the vertical position of the (center of the) outer side of the line
 | ||||||
|       line.outerY = lastOuter + (line.thickness / 2); |       line.outerY = lastOuter + (line.thickness / 2); | ||||||
|       line.innerY = Math.min(innerBottom + (line.thickness / 2), Math.max(innerTop + (line.thickness / 2), lastInner + (line.weight / 2))); |       line.innerY = Math.min(innerBottom - (line.thickness / 2), Math.max(innerTop + (line.thickness / 2), lastInner + (line.weight / 2))); | ||||||
| 
 | 
 | ||||||
|       // special case to center single input/outputs
 |       // special case to center single input/outputs
 | ||||||
|       if (xputs.length === 1) { |       if (xputs.length === 1) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user