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