diff --git a/client/package.json b/client/package.json index 2d268fb..211e9d4 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "bitfeed-client", - "version": "2.3.1", + "version": "2.3.2", "scripts": { "build": "rollup -c", "dev": "rollup -c -w", diff --git a/client/src/components/BlockInfo.svelte b/client/src/components/BlockInfo.svelte index 9625d98..a7ddce2 100644 --- a/client/src/components/BlockInfo.svelte +++ b/client/src/components/BlockInfo.svelte @@ -359,7 +359,7 @@
 
- Avg fee rate + avg fee rate {#if block.fees != null} { formatFee(block.avgFeerate) } sats/vbyte {:else} diff --git a/client/src/components/TransactionOverlay.svelte b/client/src/components/TransactionOverlay.svelte index b5db8ff..bf0a028 100644 --- a/client/src/components/TransactionOverlay.svelte +++ b/client/src/components/TransactionOverlay.svelte @@ -91,7 +91,7 @@ function expandAddresses(items, truncate) { }) if (truncate && items.length > 100) { const remainingCount = items.length - 100 - const remainingValue = items.slice(100).reduce((acc, item) => { return acc + item.value }, 0) + const remainingValue = items.slice(100).reduce((acc, item) => { return acc + (item.value || 0) }, 0) expanded.push({ address: `+ ${remainingCount} more`, value: remainingValue, @@ -173,36 +173,32 @@ function calcSankeyLines(inputs, outputs, fee, value, totalHeight, svgWidth, flo let maxXOffset = 0 const inLines = inputs.map((input, index) => { - if (input.value == null) { - return { line: [], weight: 0, index, total: inputs.length, in: true } - } else { - const weight = (input.value / total) * flowWeight - const height = ((index + 0.5) * rowHeight) - const step = (weight / 2) - const line = [] - const yOffset = 0.5 + const weight = ((input.value || 0) / total) * flowWeight + const height = ((index + 0.5) * rowHeight) + const step = (weight / 2) + const line = [] + const yOffset = 0.5 - line.push({ x: triangleWidth, y: height }) - line.push({ x: triangleWidth + (0.25 * svgWidth), y: height }) - line.push({ x: 0.425 * svgWidth, y: mergeOffset + cumThick + step + yOffset }) - line.push({ x: (0.5 * svgWidth) + 1, y: mergeOffset + cumThick + step + yOffset }) + line.push({ x: triangleWidth, y: height }) + line.push({ x: triangleWidth + (0.25 * svgWidth), y: height }) + line.push({ x: 0.425 * svgWidth, y: mergeOffset + cumThick + step + yOffset }) + line.push({ x: (0.5 * svgWidth) + 1, y: mergeOffset + cumThick + step + yOffset }) - const dy = line[1].y - line[2].y - const dx = line[2].x - line[1].x - const miterOffset = getMiterOffset(weight, dy, dx) - xOffset += miterOffset - line[1].x += xOffset - line[2].x += xOffset - xOffset += miterOffset - maxXOffset = Math.max(xOffset, maxXOffset) + const dy = line[1].y - line[2].y + const dx = line[2].x - line[1].x + const miterOffset = getMiterOffset(weight, dy, dx) + xOffset += miterOffset + line[1].x += xOffset + line[2].x += xOffset + xOffset += miterOffset + maxXOffset = Math.max(xOffset, maxXOffset) - // inLines.push({ line, weight }) - // inLines.push({ line: [{x: line[1].x + miterOffset, y: line[1].y - (weight / 2)}, {x: line[2].x + miterOffset, y: line[2].y - (weight / 2)}], weight: 1}) + // inLines.push({ line, weight }) + // inLines.push({ line: [{x: line[1].x + miterOffset, y: line[1].y - (weight / 2)}, {x: line[2].x + miterOffset, y: line[2].y - (weight / 2)}], weight: 1}) - cumThick += weight + cumThick += weight - return { line, weight, index, total: inputs.length, in: true } - } + return { line, weight, index, total: inputs.length, in: true } }) inLines.forEach(line => { if (line.line.length) { diff --git a/client/src/components/TxInfo.svelte b/client/src/components/TxInfo.svelte index ca95f85..e6d5f7e 100644 --- a/client/src/components/TxInfo.svelte +++ b/client/src/components/TxInfo.svelte @@ -166,6 +166,9 @@ function highlight () { {#if !tx.coinbase && tx.fee != null }

Fee rate: { numberFormat.format(tx.feerate.toFixed(2)) } sats/vbyte

Fee: { numberFormat.format(tx.fee) } sats

+ {:else if !tx.coinbase && tx.fee == null} +

Fee rate: unavailable

+

Fee: unavailable

{/if}

Total value: { formatBTC(tx.value) } diff --git a/client/src/controllers/TxController.js b/client/src/controllers/TxController.js index 2cb6b3f..4f796bd 100644 --- a/client/src/controllers/TxController.js +++ b/client/src/controllers/TxController.js @@ -417,7 +417,7 @@ export default class TxController { this.selectedTx = selected selectedTx.set(selected) if (sameTx && selected) { - if (!selected.is_inflated) { + if (!selected.is_inflated || selected.is_partial) { loading.increment() await searchTx(selected.id) loading.decrement() diff --git a/client/src/models/BitcoinTx.js b/client/src/models/BitcoinTx.js index 5a340bb..340916e 100644 --- a/client/src/models/BitcoinTx.js +++ b/client/src/models/BitcoinTx.js @@ -49,10 +49,11 @@ export default class BitcoinTx { this.view = new TxView(this) } - mergeData ({ version, inflated, preview, id, value, fee, vbytes, numInputs, inputs, outputs, time, block }, isCoinbase=false) { + mergeData ({ version, inflated, partial, preview, id, value, fee, vbytes, numInputs, inputs, outputs, time, block }, isCoinbase=false) { this.setData({ version, inflated: this.is_inflated || inflated, + partial: this.is_partial && partial, preview: this.is_preview && preview, id, value, @@ -66,9 +67,10 @@ export default class BitcoinTx { }) } - setData ({ version, inflated, preview, id, value, fee, vbytes, numInputs, inputs, outputs, time, block }, isCoinbase=false) { + setData ({ version, inflated, partial, preview, id, value, fee, vbytes, numInputs, inputs, outputs, time, block }, isCoinbase=false) { this.version = version this.is_inflated = !!inflated + this.is_partial = !!partial this.is_preview = !!preview this.id = id this.pixelPosition = { x: 0, y: 0, r: 0} @@ -92,7 +94,7 @@ export default class BitcoinTx { // is a coinbase transaction? this.isCoinbase = isCoinbase - if (this.isCoinbase || this.fee == null || this.fee < 0) { + if (this.isCoinbase || this.fee == null || this.fee < 0 || this.is_partial) { this.fee = null this.feerate = null } diff --git a/server/lib/mempool.ex b/server/lib/mempool.ex index 928bf4e..8faade9 100644 --- a/server/lib/mempool.ex +++ b/server/lib/mempool.ex @@ -433,18 +433,20 @@ defmodule BitcoinStream.Mempool do end defp sync_mempool_txns(pid, [next_chunk | rest], count) do + :timer.sleep(250); case sync_batch(pid, next_chunk) do {:ok, batch_count} -> Logger.info("synced #{batch_count + count} mempool transactions"); sync_mempool_txns(pid, rest, batch_count + count) _ -> - :failed + Logger.info("Failed to sync #{length(next_chunk)} mempool transactions"); + sync_mempool_txns(pid, rest, count) end end def sync_mempool_txns(pid, txns) do - sync_mempool_txns(pid, Enum.chunk_every(txns, 100), 0) + sync_mempool_txns(pid, Enum.chunk_every(txns, 50), 0) end diff --git a/server/lib/protocol/transaction.ex b/server/lib/protocol/transaction.ex index a21d33c..914f066 100644 --- a/server/lib/protocol/transaction.ex +++ b/server/lib/protocol/transaction.ex @@ -21,6 +21,7 @@ defmodule BitcoinStream.Protocol.Transaction do defstruct [ :version, :inflated, + :partial, :vbytes, :inputs, :outputs, @@ -99,6 +100,7 @@ defmodule BitcoinStream.Protocol.Transaction do %__MODULE__{ version: txn.version, inflated: false, + partial: true, vbytes: txn.vbytes, inputs: inputs, outputs: txn.outputs, @@ -163,27 +165,35 @@ defmodule BitcoinStream.Protocol.Transaction do :error end - defp inflate_inputs([], inflated, total, _fail_fast) do + defp inflate_inputs([], inflated, total, _fail_fast, false) do {:ok, inflated, total} end - defp inflate_inputs([next_chunk | rest], inflated, total, fail_fast) do - case inflate_batch(next_chunk, fail_fast) do - {:ok, inflated_chunk, chunk_total} -> - inflate_inputs(rest, inflated ++ inflated_chunk, total + chunk_total, fail_fast) - _ -> - {:failed, inflated ++ next_chunk ++ rest, 0} + defp inflate_inputs([], inflated, total, _fail_fast, true) do + {:failed, inflated, 0} + end + + defp inflate_inputs([next_chunk | rest], inflated, total, fail_fast, failed) do + if (failed) do + inflate_inputs(rest, inflated ++ next_chunk, total, fail_fast, true) + else + case inflate_batch(next_chunk, fail_fast) do + {:ok, inflated_chunk, chunk_total} -> + inflate_inputs(rest, inflated ++ inflated_chunk, total + chunk_total, fail_fast, false) + _ -> + inflate_inputs(rest, inflated ++ next_chunk, total, fail_fast, true) + end end end - def inflate_inputs([], nil, _fail_fast) do + def inflate_inputs([], nil, _fail_fast, _failed) do { :failed, nil, 0 } end # Retrieves cached inputs if available, # otherwise inflates inputs in batches of up to 100 def inflate_inputs(_txid, inputs, fail_fast) do - inflate_inputs(Enum.chunk_every(inputs, 100), [], 0, fail_fast) + inflate_inputs(Enum.chunk_every(inputs, 50), [], 0, fail_fast, false) end end diff --git a/server/mix.exs b/server/mix.exs index 0a2e071..23bec32 100644 --- a/server/mix.exs +++ b/server/mix.exs @@ -4,7 +4,7 @@ defmodule BitcoinStream.MixProject do def project do [ app: :bitcoin_stream, - version: "2.3.1", + version: "2.3.2", elixir: "~> 1.10", start_permanent: Mix.env() == :prod, deps: deps(),