Merge branch 'master' into nymkappa/duplicate-block

This commit is contained in:
wiz 2023-03-11 15:15:56 +09:00 committed by GitHub
commit 35a05a420d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 100 additions and 24 deletions

View File

@ -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

View File

@ -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;
} }

View File

@ -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 {

View File

@ -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;
}

View File

@ -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>

View File

@ -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) {
this.graphWidth = this.graphContainer.nativeElement.clientWidth; setTimeout(() => {
this.graphWidth = this.graphContainer.nativeElement.clientWidth;
}, 1);
} }
} }

View File

@ -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) {