You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
670 lines
20 KiB
670 lines
20 KiB
extends layout
|
|
|
|
block headContent
|
|
title Block Analysis ##{result.getblock.height.toLocaleString()}, #{result.getblock.hash}
|
|
|
|
block content
|
|
h1.h3 Block Analysis
|
|
small.text-monospace(style="width: 100%;") ##{result.getblock.height.toLocaleString()}
|
|
br
|
|
small.text-monospace.word-wrap(style="width: 100%;") #{result.getblock.hash}
|
|
hr
|
|
|
|
div.mb-2
|
|
if (result.getblock)
|
|
a.btn.btn-sm.btn-primary.mb-1(href=("/block/" + result.getblock.hash)) « Block Details:
|
|
span.text-monospace ##{result.getblock.height.toLocaleString()}
|
|
|
|
div.row
|
|
- var sumTableLabelClass = (result.blockstats != null ? "summary-split-table-label" : "summary-table-label");
|
|
- var sumTableValueClass = (result.blockstats != null ? "summary-split-table-content" : "summary-table-content");
|
|
|
|
div.mb-3.col
|
|
div.card.shadow-sm(style="height: 100%;")
|
|
div.card-body.px-2.px-md-3
|
|
h3.h6.mb-0 Summary
|
|
hr
|
|
|
|
div.clearfix
|
|
div.row
|
|
div.summary-table-label Date
|
|
div.summary-table-content.text-monospace
|
|
- var timestampHuman = result.getblock.time;
|
|
include includes/timestamp-human.pug
|
|
small.ml-1 utc
|
|
|
|
- var timeAgoTime = result.getblock.time;
|
|
span.text-muted.ml-2 (
|
|
include includes/time-ago-text.pug
|
|
span ago)
|
|
|
|
if (result.getblock.weight)
|
|
div.row
|
|
div.summary-table-label Weight
|
|
div.summary-table-content.text-monospace
|
|
span #{result.getblock.weight.toLocaleString()}
|
|
small wu
|
|
|
|
span.text-muted (#{new Decimal(100 * result.getblock.weight / coinConfig.maxBlockWeight).toDecimalPlaces(2)}% full)
|
|
|
|
else
|
|
div.row
|
|
div.summary-table-label Size
|
|
div.summary-table-content.text-monospace #{result.getblock.size.toLocaleString()}
|
|
small B
|
|
|
|
div.row
|
|
div.summary-table-label Transactions
|
|
div.summary-table-content.text-monospace #{result.getblock.tx.length.toLocaleString()}
|
|
|
|
div.row
|
|
div.summary-table-label Confirmations
|
|
div.summary-table-content.text-monospace
|
|
if (result.getblock.confirmations < 6)
|
|
span.font-weight-bold.text-warning #{result.getblock.confirmations.toLocaleString()}
|
|
a(data-toggle="tooltip", title="Fewer than 6 confirmations is generally considered 'unsettled' for high-value transactions. The applicability of this guidance may vary.")
|
|
i.fas.fa-unlock-alt
|
|
else
|
|
span.font-weight-bold.text-success #{result.getblock.confirmations.toLocaleString()}
|
|
a(data-toggle="tooltip", title="6 confirmations is generally considered 'settled'. High-value transactions may require more; low-value transactions may require less.")
|
|
i.fas.fa-lock
|
|
|
|
div#progress-wrapper.mb-huge
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h4.h6 Loading transactions:
|
|
span(id="progress-text")
|
|
div.progress.mt-2(id="progress-bar", style="height: 7px;")
|
|
div.progress-bar(id="data-progress", role="progressbar", aria-valuenow="0", aria-valuemin="0" ,aria-valuemax="100")
|
|
|
|
|
|
div#main-content(style="display: none;")
|
|
div.row
|
|
div.col-xl-4
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Top Value Transactions
|
|
hr
|
|
|
|
div.table-responsive
|
|
table.table.table-striped.mb-0
|
|
thead
|
|
tr
|
|
th.data-header Transaction
|
|
th.data-header.text-right Output Value
|
|
|
|
tbody(id="tbody-top-value-tx")
|
|
tr.text-monospace.row-prototype(style="display: none;")
|
|
td.data-tx-link
|
|
td.text-right.data-tx-value
|
|
|
|
div.col-xl-4
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Top Fee Transactions
|
|
hr
|
|
|
|
div.table-responsive
|
|
table.table.table-striped.mb-0
|
|
thead
|
|
tr
|
|
th.data-header Transaction
|
|
th.data-header.text-right Fee
|
|
|
|
tbody(id="tbody-top-fee-tx")
|
|
tr.text-monospace.row-prototype(style="display: none;")
|
|
td.data-tx-link
|
|
td.text-right.data-tx-value
|
|
|
|
div.col-xl-4
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Top Size Transactions
|
|
hr
|
|
|
|
div.table-responsive
|
|
table.table.table-striped.mb-0
|
|
thead
|
|
tr
|
|
th.data-header Transaction
|
|
th.data-header.text-right Size
|
|
|
|
tbody(id="tbody-top-size-tx")
|
|
tr.text-monospace.row-prototype(style="display: none;")
|
|
td.data-tx-link
|
|
td.text-right.data-tx-value
|
|
|
|
div.col-lg-6.mb-3
|
|
div.card.shadow-sm(style="height: 100%;")
|
|
div.card-body
|
|
h3.h6.mb-0 Input Types
|
|
hr
|
|
|
|
table.table.table-striped.mb-0
|
|
tbody(id="tbody-input-types")
|
|
tr.text-monospace.row-prototype(style="display: none;")
|
|
td
|
|
small.data-tag.bg-dark.data-type
|
|
|
|
td.data-count
|
|
|
|
div.col-lg-6.mb-3
|
|
div.card.shadow-sm(style="height: 100%;")
|
|
div.card-body
|
|
h3.h6.mb-0 Output Types
|
|
hr
|
|
|
|
table.table.table-striped.mb-0
|
|
tbody(id="tbody-output-types")
|
|
tr.text-monospace.row-prototype(style="display: none;")
|
|
td
|
|
small.data-tag.bg-dark.data-type
|
|
|
|
td.data-count
|
|
|
|
div.row
|
|
div.col-lg-6
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Transaction Value
|
|
hr
|
|
|
|
canvas(id="graph-tx-value")
|
|
|
|
div.col-lg-6
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Transaction Value Distribution
|
|
hr
|
|
|
|
canvas(id="chart-tx-value-distribution")
|
|
|
|
div.col-lg-6
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Transaction Fee
|
|
hr
|
|
|
|
canvas(id="graph-tx-fee")
|
|
|
|
div.col-lg-6
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Transaction Fee Distribution
|
|
hr
|
|
|
|
canvas(id="chart-tx-fee-distribution")
|
|
|
|
div.col-lg-6
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Transaction Size
|
|
hr
|
|
|
|
canvas(id="graph-tx-size")
|
|
|
|
div.col-lg-6
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Transaction Size Distribution
|
|
hr
|
|
|
|
canvas(id="chart-tx-size-distribution")
|
|
|
|
div.col-lg-6
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Transaction Input Count
|
|
hr
|
|
|
|
canvas(id="graph-tx-inputs")
|
|
|
|
div.col-lg-6
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body
|
|
h3.h6.mb-0 Transaction Output Count
|
|
hr
|
|
|
|
canvas(id="graph-tx-outputs")
|
|
|
|
|
|
|
|
block endOfBody
|
|
- var txidChunkSize = 10;
|
|
|
|
script(src="/js/chart.bundle.min.js", integrity="sha384-qgOtiGNaHh9fVWUnRjyHlV39rfbDcvPPkEzL1RHvsHKbuqUqM6uybNuVnghY2z4/")
|
|
script(src='/js/decimal.js')
|
|
script.
|
|
var txidChunkSize = !{txidChunkSize};
|
|
var txidChunks = !{JSON.stringify(utils.splitArrayIntoChunks(result.getblock.tx, txidChunkSize))};
|
|
var blockHeight = !{result.getblock.height};
|
|
var satsMultiplier = !{coinConfig.baseCurrencyUnit.multiplier};
|
|
var vByteSizes = false;
|
|
|
|
$(document).ready(function() {
|
|
loadTransactions(txidChunks, txidChunkSize, txidChunks.length * txidChunkSize);
|
|
});
|
|
|
|
function loadTransactions(txidChunks, chunkSize, count) {
|
|
var chunkStrs = [];
|
|
|
|
for (var i = 0; i < txidChunks.length; i++) {
|
|
var txidChunk = txidChunks[i];
|
|
|
|
var chunkStr = "";
|
|
|
|
for (var j = 0; j < txidChunk.length; j++) {
|
|
if (j > 0) {
|
|
chunkStr += ",";
|
|
}
|
|
|
|
chunkStr += txidChunk[j];
|
|
}
|
|
|
|
chunkStrs.push(chunkStr);
|
|
}
|
|
|
|
//alert(JSON.stringify(chunks));
|
|
|
|
var results = [];
|
|
|
|
var statusCallback = function(chunkIndexDone, chunkCount) {
|
|
//console.log("Done: " + Math.min(((chunkIndexDone + 1) * chunkSize), count) + " of " + count);
|
|
|
|
var wPercent = `${parseInt(100 * (chunkIndexDone + 1) / parseFloat(chunkCount))}%`;
|
|
|
|
$("#data-progress").css("width", wPercent);
|
|
$("#progress-text").text(`${Math.min(((chunkIndexDone + 1) * chunkSize), count).toLocaleString()} of ${count.toLocaleString()} (${wPercent})`);
|
|
};
|
|
|
|
var finishedCallback = function() {
|
|
var summary = summarizeData(results);
|
|
|
|
fillTopValueTxTable(summary);
|
|
fillTopFeeTxTable(summary);
|
|
fillTopSizeTxTable(summary);
|
|
|
|
fillInputOutputTypesTable(summary);
|
|
|
|
createGraph("graph-tx-value", summary.txValueGraphData, "Value");
|
|
createGraph("graph-tx-fee", summary.txFeeGraphData, "Fee");
|
|
createGraph("graph-tx-inputs", summary.txInputCountGraphData, "Input Count");
|
|
createGraph("graph-tx-outputs", summary.txOutputCountGraphData, "Output Count");
|
|
createGraph("graph-tx-size", summary.txSizeGraphData, "Size");
|
|
|
|
createChart("chart-tx-value-distribution", summary.valueDistribution, summary.valueDistributionLabels);
|
|
createChart("chart-tx-fee-distribution", summary.feeDistribution, summary.feeDistributionLabels);
|
|
createChart("chart-tx-size-distribution", summary.sizeDistribution, summary.sizeDistributionLabels);
|
|
|
|
//$(".abc").text(JSON.stringify(summary));
|
|
|
|
$("#main-content").show();
|
|
$("#progress-wrapper").hide();
|
|
};
|
|
|
|
getTxData(results, chunkStrs, 0, statusCallback, finishedCallback);
|
|
}
|
|
|
|
function fillTopValueTxTable(data) {
|
|
var count = Math.min(10, data.topValueTxs.length);
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
var item = data.topValueTxs[i];
|
|
|
|
var row = $("#tbody-top-value-tx .row-prototype").clone();
|
|
|
|
row.removeClass("row-prototype");
|
|
|
|
row.find(".data-tx-link").html(`<a href='/tx/${item.txid}'>${item.txid.substring(0, 14)}<span class='d-inline d-xl-none'>${item.txid.substring(14, 32)}</span><span class='d-none d-xxl-inline'>${item.txid.substring(14, 30)}</span>…</a>`);
|
|
row.find(".data-tx-value").text(item.value);
|
|
|
|
updateCurrencyValue(row.find(".data-tx-value"), item.value);
|
|
|
|
row.show();
|
|
|
|
$("#tbody-top-value-tx").append(row);
|
|
}
|
|
}
|
|
|
|
function fillTopFeeTxTable(data) {
|
|
var count = Math.min(10, data.topFeeTxs.length);
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
var item = data.topFeeTxs[i];
|
|
|
|
var row = $("#tbody-top-fee-tx .row-prototype").clone();
|
|
|
|
row.removeClass("row-prototype");
|
|
|
|
row.find(".data-tx-link").html(`<a href='/tx/${item.txid}'>${item.txid.substring(0, 14)}<span class='d-inline d-xl-none'>${item.txid.substring(14, 32)}</span><span class='d-none d-xxl-inline'>${item.txid.substring(14, 30)}</span>…</a>`);
|
|
row.find(".data-tx-value").text(item.value);
|
|
|
|
updateCurrencyValue(row.find(".data-tx-value"), item.value);
|
|
|
|
row.show();
|
|
|
|
$("#tbody-top-fee-tx").append(row);
|
|
}
|
|
}
|
|
|
|
function fillTopSizeTxTable(data) {
|
|
var count = Math.min(10, data.topSizeTxs.length);
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
var item = data.topSizeTxs[i];
|
|
|
|
var row = $("#tbody-top-size-tx .row-prototype").clone();
|
|
|
|
row.removeClass("row-prototype");
|
|
|
|
row.find(".data-tx-link").html(`<a href='/tx/${item.txid}'>${item.txid.substring(0, 14)}<span class='d-inline d-xl-none'>${item.txid.substring(14, 32)}</span><span class='d-none d-xxl-inline'>${item.txid.substring(14, 30)}</span>…</a>`);
|
|
row.find(".data-tx-value").html(`<span>${parseInt(item.value).toLocaleString()} <small>${vByteSizes ? "v" : ""}B</small></span>`);
|
|
|
|
row.show();
|
|
|
|
$("#tbody-top-size-tx").append(row);
|
|
}
|
|
}
|
|
|
|
function fillInputOutputTypesTable(data) {
|
|
var sortedInputs = [];
|
|
for (var key in data.inputTypeCounts) {
|
|
if (data.inputTypeCounts.hasOwnProperty(key)) {
|
|
sortedInputs.push({type:key, count:data.inputTypeCounts[key]});
|
|
}
|
|
}
|
|
|
|
var sortedOutputs = [];
|
|
for (var key in data.outputTypeCounts) {
|
|
if (data.outputTypeCounts.hasOwnProperty(key)) {
|
|
sortedOutputs.push({type:key, count:data.outputTypeCounts[key]});
|
|
}
|
|
}
|
|
|
|
sortedInputs.sort(function(a, b) {
|
|
return b.count - a.count;
|
|
});
|
|
|
|
sortedOutputs.sort(function(a, b) {
|
|
return b.count - a.count;
|
|
});
|
|
|
|
for (var i = 0; i < sortedInputs.length; i++) {
|
|
var item = sortedInputs[i];
|
|
|
|
var row = $("#tbody-input-types .row-prototype").clone();
|
|
|
|
row.removeClass("row-prototype");
|
|
|
|
if (i == 0) {
|
|
row.addClass("table-borderless");
|
|
}
|
|
|
|
// span(title=`Output Type: ${utils.outputTypeName(inputTypeKey)}`, data-toggle="tooltip") #{utils.outputTypeAbbreviation(inputTypeKey)}
|
|
row.find(".data-type").html(`<span title='Type: ${item.type}' data-toggle='tooltip'>${item.type}</span>`);
|
|
row.find(".data-count").text(item.count.toLocaleString());
|
|
|
|
row.show();
|
|
|
|
$("#tbody-input-types").append(row);
|
|
}
|
|
|
|
for (var i = 0; i < sortedOutputs.length; i++) {
|
|
var item = sortedOutputs[i];
|
|
|
|
var row = $("#tbody-output-types .row-prototype").clone();
|
|
|
|
row.removeClass("row-prototype");
|
|
|
|
if (i == 0) {
|
|
row.addClass("table-borderless");
|
|
}
|
|
|
|
// span(title=`Output Type: ${utils.outputTypeName(inputTypeKey)}`, data-toggle="tooltip") #{utils.outputTypeAbbreviation(inputTypeKey)}
|
|
row.find(".data-type").html(`<span title='Type: ${item.type}' data-toggle='tooltip'>${item.type}</span>`);
|
|
row.find(".data-count").text(item.count.toLocaleString());
|
|
|
|
row.show();
|
|
|
|
$("#tbody-output-types").append(row);
|
|
}
|
|
}
|
|
|
|
function createGraph(graphId, data, yLabelStr) {
|
|
var ctx = document.getElementById(graphId).getContext('2d');
|
|
var graph = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
datasets: [{
|
|
borderColor: '#007bff',
|
|
borderWidth: 2,
|
|
backgroundColor: 'rgba(0,0,0,0)',
|
|
data: data,
|
|
pointRadius: 1
|
|
}]
|
|
},
|
|
options: {
|
|
legend: { display: false },
|
|
scales: {
|
|
xAxes: [{
|
|
type: 'linear',
|
|
position: 'bottom',
|
|
scaleLabel: {
|
|
display: true,
|
|
labelString: 'Index in Block'
|
|
},
|
|
//ticks: {
|
|
// stepSize: 100,
|
|
//}
|
|
}],
|
|
yAxes: [{
|
|
scaleLabel: {
|
|
display: true,
|
|
labelString: yLabelStr
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function createChart(chartId, data, labels) {
|
|
var bgColors = [];
|
|
|
|
for (var i = 0; i < labels.length; i++) {
|
|
bgColors.push(`hsl(${(333 * i / labels.length)}, 100%, 50%)`);
|
|
}
|
|
|
|
var ctx1 = document.getElementById(chartId).getContext('2d');
|
|
var chart = new Chart(ctx1, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
data: data,
|
|
backgroundColor: bgColors
|
|
}]
|
|
},
|
|
options: {
|
|
legend: {
|
|
display: false
|
|
},
|
|
scales: {
|
|
yAxes: [{
|
|
ticks: {
|
|
beginAtZero:true
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function getTxData(results, chunks, chunkIndex, statusCallback, finishedCallback) {
|
|
if (chunkIndex > chunks.length - 1) {
|
|
finishedCallback();
|
|
|
|
return;
|
|
}
|
|
|
|
var url = `/api/block-tx-summaries/${blockHeight}/${chunks[chunkIndex]}`;
|
|
|
|
//console.log(url);
|
|
|
|
$.ajax({
|
|
url: url
|
|
|
|
}).done(function(result) {
|
|
for (var i = 0; i < result.length; i++) {
|
|
results.push(result[i]);
|
|
}
|
|
|
|
statusCallback(chunkIndex, chunks.length);
|
|
|
|
getTxData(results, chunks, chunkIndex + 1, statusCallback, finishedCallback);
|
|
});
|
|
}
|
|
|
|
function summarizeData(txResults) {
|
|
var analysis = {};
|
|
|
|
analysis.inputTypeCounts = {};
|
|
analysis.outputTypeCounts = {};
|
|
|
|
analysis.txValues = [];
|
|
analysis.txValueGraphData = [];
|
|
|
|
analysis.txFees = [];
|
|
analysis.txFeeGraphData = [];
|
|
|
|
analysis.txSizes = [];
|
|
analysis.txSizeGraphData = [];
|
|
analysis.txInputCountGraphData = [];
|
|
analysis.txOutputCountGraphData = [];
|
|
|
|
for (var i = 0; i < txResults.length; i++) {
|
|
var txSummary = txResults[i];
|
|
|
|
//console.log(JSON.stringify(txSummary));
|
|
|
|
for (var j = 0; j < txSummary.vout.length; j++) {
|
|
var vout = txSummary.vout[j];
|
|
var outputType = vout.type;
|
|
|
|
if (!analysis.outputTypeCounts[outputType]) {
|
|
analysis.outputTypeCounts[outputType] = 0;
|
|
}
|
|
|
|
analysis.outputTypeCounts[outputType]++;
|
|
}
|
|
|
|
if (txSummary.vsize) {
|
|
vByteSizes = true;
|
|
}
|
|
|
|
analysis.txValues.push({txid:txSummary.txid, value:new Decimal(txSummary.totalOutput)});
|
|
analysis.txValueGraphData.push({x:i, y:new Decimal(txSummary.totalOutput).toNumber()});
|
|
|
|
analysis.txFees.push({txid:txSummary.txid, value:new Decimal(txSummary.totalFee)});
|
|
analysis.txFeeGraphData.push({x:i, y:new Decimal(txSummary.totalFee).toNumber()});
|
|
|
|
analysis.txSizes.push({txid:txSummary.txid, value:new Decimal(txSummary.vsize ? txSummary.vsize : txSummary.size)});
|
|
analysis.txSizeGraphData.push({x:i, y:(txSummary.vsize ? txSummary.vsize : txSummary.size)});
|
|
|
|
analysis.txInputCountGraphData.push({x:i, y:txSummary.vin.length});
|
|
analysis.txOutputCountGraphData.push({x:i, y:txSummary.vout.length});
|
|
|
|
if (!txSummary.coinbase) {
|
|
for (var j = 0; j < txSummary.vin.length; j++) {
|
|
var vin = txSummary.vin[j];
|
|
|
|
var inputType = vin.type;
|
|
|
|
if (!analysis.inputTypeCounts[inputType]) {
|
|
analysis.inputTypeCounts[inputType] = 0;
|
|
}
|
|
|
|
analysis.inputTypeCounts[inputType]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
analysis.txValues.sort(function(a, b) {
|
|
return b.value.cmp(a.value);
|
|
});
|
|
|
|
analysis.txFees.sort(function(a, b) {
|
|
return b.value.cmp(a.value);
|
|
});
|
|
|
|
analysis.txSizes.sort(function(a, b) {
|
|
return b.value.cmp(a.value);
|
|
});
|
|
|
|
analysis.topValueTxs = analysis.txValues.slice(0, Math.min(100, analysis.txValues.length));
|
|
analysis.topFeeTxs = analysis.txFees.slice(0, Math.min(100, analysis.txFees.length));
|
|
analysis.topSizeTxs = analysis.txSizes.slice(0, Math.min(100, analysis.txSizes.length));
|
|
|
|
var topValue = new Decimal(analysis.txValues[parseInt(analysis.txValues.length * 0.1)].value).times(satsMultiplier);
|
|
var topFee = new Decimal(analysis.txFees[parseInt(analysis.txFees.length * 0.1)].value).times(satsMultiplier);
|
|
var topSize = new Decimal(analysis.txSizes[parseInt(analysis.txSizes.length * 0.1)].value);
|
|
|
|
var topValueSats = parseInt(topValue);
|
|
var topFeeSats = parseInt(topFee);
|
|
|
|
var distributionBucketCount = 25;
|
|
|
|
analysis.valueDistribution = [];
|
|
analysis.valueDistributionLabels = [];
|
|
|
|
analysis.feeDistribution = [];
|
|
analysis.feeDistributionLabels = [];
|
|
|
|
analysis.sizeDistribution = [];
|
|
analysis.sizeDistributionLabels = [];
|
|
|
|
for (var i = 0; i < distributionBucketCount; i++) {
|
|
analysis.valueDistribution.push(0);
|
|
analysis.valueDistributionLabels.push(`[${new Decimal(i * topValueSats / distributionBucketCount).dividedBy(satsMultiplier).toDP(3)} - ${new Decimal((i + 1) * topValueSats / distributionBucketCount).dividedBy(satsMultiplier).toDP(3)})`);
|
|
|
|
analysis.feeDistribution.push(0);
|
|
analysis.feeDistributionLabels.push(`[${new Decimal(i * topFeeSats / distributionBucketCount).toDP(0)} - ${new Decimal((i + 1) * topFeeSats / distributionBucketCount).toDP(0)})`);
|
|
|
|
analysis.sizeDistribution.push(0);
|
|
analysis.sizeDistributionLabels.push(`[${new Decimal(i * topSize / distributionBucketCount).toDP(0)} - ${new Decimal((i + 1) * topSize / distributionBucketCount).toDP(0)})`);
|
|
}
|
|
|
|
analysis.valueDistributionLabels[distributionBucketCount - 1] = `${new Decimal(topValueSats).dividedBy(satsMultiplier).toDP(3)}+`;
|
|
analysis.feeDistributionLabels[distributionBucketCount - 1] = `${topFeeSats}+`;
|
|
analysis.sizeDistributionLabels[distributionBucketCount - 1] = `${topSize}+`;
|
|
|
|
for (var i = 0; i < txResults.length; i++) {
|
|
var txSummary = txResults[i];
|
|
|
|
var valueSats = new Decimal(txSummary.totalOutput).times(satsMultiplier);
|
|
var feeSats = new Decimal(txSummary.totalFee).times(satsMultiplier);
|
|
var size = new Decimal(txSummary.vsize ? txSummary.vsize : txSummary.size);
|
|
|
|
var valueBucket = parseInt(distributionBucketCount * valueSats / topValueSats);
|
|
if (valueBucket >= distributionBucketCount) {
|
|
valueBucket = distributionBucketCount - 1;
|
|
}
|
|
|
|
var feeBucket = parseInt(distributionBucketCount * feeSats / topFeeSats);
|
|
if (feeBucket >= distributionBucketCount) {
|
|
feeBucket = distributionBucketCount - 1;
|
|
}
|
|
|
|
var sizeBucket = parseInt(distributionBucketCount * size / topSize);
|
|
if (sizeBucket >= distributionBucketCount) {
|
|
sizeBucket = distributionBucketCount - 1;
|
|
}
|
|
|
|
analysis.valueDistribution[valueBucket]++;
|
|
analysis.feeDistribution[feeBucket]++;
|
|
analysis.sizeDistribution[sizeBucket]++;
|
|
}
|
|
|
|
return analysis;
|
|
}
|
|
|
|
|