From 91cbad347cfee5d4a62d0588ad39d14e6fff9b47 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 17 May 2022 21:22:41 +0000 Subject: [PATCH] Boolean output spend status when indexing disabled --- client/nginx/bitfeed.conf.template | 7 -- .../src/components/TransactionOverlay.svelte | 17 +++- client/src/utils/search.js | 10 +- server/lib/bitcoin_rpc.ex | 2 +- server/lib/mempool.ex | 6 +- server/lib/protocol/transaction.ex | 2 +- server/lib/server.ex | 2 +- server/lib/spend_index.ex | 99 ++++++++++++++++--- 8 files changed, 116 insertions(+), 29 deletions(-) diff --git a/client/nginx/bitfeed.conf.template b/client/nginx/bitfeed.conf.template index 352cf1f..974de8f 100644 --- a/client/nginx/bitfeed.conf.template +++ b/client/nginx/bitfeed.conf.template @@ -5,8 +5,6 @@ map $sent_http_content_type $expires { application/javascript max; } -proxy_cache_path /var/cache/nginx/bitfeed levels=1:2 keys_zone=bitfeed:10m max_size=500m inactive=1w use_temp_path=off; - server { listen 80; @@ -20,11 +18,6 @@ server { } location /api { - proxy_cache bitfeed; - proxy_cache_revalidate on; - proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; - proxy_cache_background_update on; - proxy_cache_lock on; proxy_pass http://wsmonobackend; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; diff --git a/client/src/components/TransactionOverlay.svelte b/client/src/components/TransactionOverlay.svelte index 055d2fe..27972d2 100644 --- a/client/src/components/TransactionOverlay.svelte +++ b/client/src/components/TransactionOverlay.svelte @@ -515,6 +515,15 @@ async function goToBlock(e) { animation-iteration-count: infinite; } } + + &.disabled { + cursor: normal; + opacity: 0.5; + .chevron .outline { + stroke-opacity: 1; + fill-opacity: 1; + } + } } } @@ -748,8 +757,14 @@ async function goToBlock(e) { + {:else if spends[output.index] == true} + + + + + {:else if spends[output.index]} - goToSpend(e, spends[output.index])} class="put-link" in:fade|local={{ duration: 200 }}> + goToSpend(e, spends[output.index])} title="spent" class="put-link" in:fade|local={{ duration: 200 }}> diff --git a/client/src/utils/search.js b/client/src/utils/search.js index cdeb781..e300e9a 100644 --- a/client/src/utils/search.js +++ b/client/src/utils/search.js @@ -190,9 +190,13 @@ async function fetchSpends (txid) { const result = await response.json() return result.map(output => { if (output) { - return { - txid: output[0], - vin: output[1], + if (output === true) { + return true + } else { + return { + txid: output[0], + vin: output[1], + } } } else { return null diff --git a/server/lib/bitcoin_rpc.ex b/server/lib/bitcoin_rpc.ex index ed164d1..af8b3cc 100644 --- a/server/lib/bitcoin_rpc.ex +++ b/server/lib/bitcoin_rpc.ex @@ -175,7 +175,7 @@ defmodule BitcoinStream.RPC do end defp do_batch_request(method, batch_params, host, port, creds) do - case Jason.encode(Enum.map(batch_params, fn [params, id] -> %{method: method, params: [params], id: id} end)) do + case Jason.encode(Enum.map(batch_params, fn [params, id] -> %{method: method, params: params, id: id} end)) do {:ok, body} -> async_request(body, host, port, creds) diff --git a/server/lib/mempool.ex b/server/lib/mempool.ex index 633c03e..928bf4e 100644 --- a/server/lib/mempool.ex +++ b/server/lib/mempool.ex @@ -397,7 +397,7 @@ defmodule BitcoinStream.Mempool do defp sync_batch(pid, batch) do - with batch_params <- Enum.map(batch, fn txid -> [txid, txid] end), + with batch_params <- Enum.map(batch, fn txid -> [[txid], txid] end), {:ok, 200, txs} <- RPC.batch_request(:rpc, "getrawtransaction", batch_params, true), failures <- Enum.filter(txs, fn %{"error" => error} -> error != nil end), successes <- Enum.filter(txs, fn %{"error" => error} -> error == nil end) do @@ -411,7 +411,7 @@ defmodule BitcoinStream.Mempool do end); case length(failures) do count when count > 0 -> - IO.puts("failures: #{length(failures)}") + Logger.info("Failed to sync #{length(failures)} transactions") _ -> false end @@ -435,7 +435,7 @@ defmodule BitcoinStream.Mempool do defp sync_mempool_txns(pid, [next_chunk | rest], count) do case sync_batch(pid, next_chunk) do {:ok, batch_count} -> - IO.puts("synced #{batch_count + count} mempool transactions"); + Logger.info("synced #{batch_count + count} mempool transactions"); sync_mempool_txns(pid, rest, batch_count + count) _ -> diff --git a/server/lib/protocol/transaction.ex b/server/lib/protocol/transaction.ex index 20b817e..74bf5ed 100644 --- a/server/lib/protocol/transaction.ex +++ b/server/lib/protocol/transaction.ex @@ -125,7 +125,7 @@ defmodule BitcoinStream.Protocol.Transaction do end defp inflate_batch(batch, fail_fast) do - with batch_params <- Enum.map(batch, fn input -> [input.prev_txid, input.prev_txid <> "#{input.prev_vout}"] end), + with batch_params <- Enum.map(batch, fn input -> [[input.prev_txid], input.prev_txid <> "#{input.prev_vout}"] end), batch_map <- Enum.into(batch, %{}, fn p -> {p.prev_txid <> "#{p.prev_vout}", p} end), {:ok, 200, txs} <- RPC.batch_request(:rpc, "getrawtransaction", batch_params, fail_fast), successes <- Enum.filter(txs, fn %{"error" => error} -> error == nil end), diff --git a/server/lib/server.ex b/server/lib/server.ex index e5fc49f..98da156 100644 --- a/server/lib/server.ex +++ b/server/lib/server.ex @@ -13,7 +13,7 @@ defmodule BitcoinStream.Server do { rpc_pool_size, "" } = Integer.parse(System.get_env("RPC_POOL_SIZE") || "16"); log_level = System.get_env("LOG_LEVEL"); btc_host = System.get_env("BITCOIN_HOST"); - indexed = Mix.target == "public"; + indexed = System.get_env("TARGET") == "public"; case log_level do "debug" -> diff --git a/server/lib/spend_index.ex b/server/lib/spend_index.ex index 632dd41..1d540dc 100644 --- a/server/lib/spend_index.ex +++ b/server/lib/spend_index.ex @@ -57,7 +57,7 @@ defmodule BitcoinStream.Index.Spend do @impl true def handle_call({:get_tx_spends, txid}, _from, [dbref, indexed, done]) do - case get_transaction_spends(dbref, txid, (indexed)) do + case get_transaction_spends(dbref, txid, indexed) do {:ok, spends} -> {:reply, {:ok, spends}, [dbref, indexed, done]} @@ -297,12 +297,81 @@ defmodule BitcoinStream.Index.Spend do end end + defp batch_spend_status(txid, batch) do + with batch_params <- Enum.map(batch, fn index -> [[txid, index, true], index] end), + {:ok, 200, txouts} <- RPC.batch_request(:rpc, "gettxout", batch_params, false), + utxos <- Enum.map(txouts, fn txout -> + case txout do + %{"error" => nil, "id" => index, "result" => nil} -> + { index, true } + + %{"error" => nil, "id" => index, "result" => result} -> + { index, false } + + %{"error" => error, "id" => index } -> + { index, false } + end + end), + utxoMap <- Enum.into(Enum.filter(utxos, fn utxo -> + case utxo do + { _index, false } -> + false + + { _index, true } -> + true + + _ -> false + end + end), %{}) + do + {:ok, utxoMap} + else + _ -> + :error + end + end + + defp get_spend_status(_txid, [], results) do + results + end + + defp get_spend_status(txid, [next_batch | rest], results) do + case batch_spend_status(txid, next_batch) do + {:ok, result} -> + get_spend_status(txid, rest, Map.merge(results, result)) + + _ -> :err + end + end + + defp get_spend_status(txid, numOutputs) do + index_list = Enum.to_list(0..(numOutputs - 1)) + spend_map = get_spend_status(txid, Enum.chunk_every(index_list, 100), %{}); + Enum.map(index_list, fn index -> + case Map.get(spend_map, index) do + true -> true + + _ -> false + end + end) + end + + defp get_spend_status(txid) do + with {:ok, 200, hextx} <- RPC.request(:rpc, "getrawtransaction", [txid]), + rawtx <- Base.decode16!(hextx, case: :lower), + {:ok, tx } <- BitcoinTx.decode(rawtx) do + get_spend_status(txid, length(tx.outputs)) + else + _ -> [] + end + end + defp get_chain_spends(dbref, binary_txid, use_index) do - case (if use_index do :rocksdb.get(dbref, binary_txid, []) else :not_found end) do + case (if use_index do :rocksdb.get(dbref, binary_txid, []) else :unindexed end) do {:ok, spends} -> spends - :not_found -> + :unindexed -> # uninitialized, try to construct on-the-fly from RPC data txid = Base.encode16(binary_txid); with {:ok, 200, hextx} <- RPC.request(:rpc, "getrawtransaction", [txid]), @@ -339,23 +408,29 @@ defmodule BitcoinStream.Index.Spend do end defp get_transaction_spends(dbref, txid, use_index) do - binary_txid = Base.decode16!(txid, [case: :lower]); - chain_spends = get_chain_spends(dbref, binary_txid, use_index); - spend_list = unpack_spends(chain_spends); - spend_list = add_mempool_spends(txid, spend_list); - {:ok, spend_list} + if (use_index) do + binary_txid = Base.decode16!(txid, [case: :lower]); + chain_spends = get_chain_spends(dbref, binary_txid, use_index); + spend_list = unpack_spends(chain_spends); + spend_list = add_mempool_spends(txid, spend_list); + {:ok, spend_list} + else + spend_list = get_spend_status(txid); + spend_list = add_mempool_spends(txid, spend_list); + {:ok, spend_list} + end end defp add_mempool_spends(_txid, _index, [], added) do Enum.reverse(added) end - defp add_mempool_spends(txid, index, [false | rest], added) do + defp add_mempool_spends(txid, index, [spend | rest], added) when is_boolean(spend) do case :ets.lookup(:spend_cache, [txid, index]) do [] -> - add_mempool_spends(txid, index + 1, rest, [false | added]) - - [{[_index, _txid], spend}] -> add_mempool_spends(txid, index + 1, rest, [spend | added]) + + [{[_index, _txid], mempool_spend}] -> + add_mempool_spends(txid, index + 1, rest, [mempool_spend | added]) end end defp add_mempool_spends(txid, index, [spend | rest], added) do