mirror of
https://github.com/Retropex/bitfeed.git
synced 2025-05-13 03:30:47 +02:00
Boolean output spend status when indexing disabled
This commit is contained in:
parent
b689b3dd55
commit
91cbad347c
@ -5,8 +5,6 @@ map $sent_http_content_type $expires {
|
|||||||
application/javascript max;
|
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 {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
|
|
||||||
@ -20,11 +18,6 @@ server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
location /api {
|
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_pass http://wsmonobackend;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
@ -515,6 +515,15 @@ async function goToBlock(e) {
|
|||||||
animation-iteration-count: infinite;
|
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) {
|
|||||||
<path d="M 107.628,257.54 327.095,38.078 404,114.989 261.506,257.483 404,399.978 327.086,476.89 Z" class="outline" />
|
<path d="M 107.628,257.54 327.095,38.078 404,114.989 261.506,257.483 404,399.978 327.086,476.89 Z" class="outline" />
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
|
{:else if spends[output.index] == true}
|
||||||
|
<span class="put-link disabled" in:fade|local={{ duration: 200 }} title="spent">
|
||||||
|
<svg class="chevron right" height="1.2em" width="1.2em" viewBox="0 0 512 512">
|
||||||
|
<path d="M 107.628,257.54 327.095,38.078 404,114.989 261.506,257.483 404,399.978 327.086,476.89 Z" class="outline" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
{:else if spends[output.index]}
|
{:else if spends[output.index]}
|
||||||
<a href="/tx/{spends[output.index].vin}:{spends[output.index].txid}" on:click={(e) => goToSpend(e, spends[output.index])} class="put-link" in:fade|local={{ duration: 200 }}>
|
<a href="/tx/{spends[output.index].vin}:{spends[output.index].txid}" on:click={(e) => goToSpend(e, spends[output.index])} title="spent" class="put-link" in:fade|local={{ duration: 200 }}>
|
||||||
<svg class="chevron right" height="1.2em" width="1.2em" viewBox="0 0 512 512">
|
<svg class="chevron right" height="1.2em" width="1.2em" viewBox="0 0 512 512">
|
||||||
<path d="M 107.628,257.54 327.095,38.078 404,114.989 261.506,257.483 404,399.978 327.086,476.89 Z" class="outline" />
|
<path d="M 107.628,257.54 327.095,38.078 404,114.989 261.506,257.483 404,399.978 327.086,476.89 Z" class="outline" />
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -190,10 +190,14 @@ async function fetchSpends (txid) {
|
|||||||
const result = await response.json()
|
const result = await response.json()
|
||||||
return result.map(output => {
|
return result.map(output => {
|
||||||
if (output) {
|
if (output) {
|
||||||
|
if (output === true) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
return {
|
return {
|
||||||
txid: output[0],
|
txid: output[0],
|
||||||
vin: output[1],
|
vin: output[1],
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ defmodule BitcoinStream.RPC do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp do_batch_request(method, batch_params, host, port, creds) do
|
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} ->
|
{:ok, body} ->
|
||||||
async_request(body, host, port, creds)
|
async_request(body, host, port, creds)
|
||||||
|
|
||||||
|
@ -397,7 +397,7 @@ defmodule BitcoinStream.Mempool do
|
|||||||
|
|
||||||
|
|
||||||
defp sync_batch(pid, batch) 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),
|
{:ok, 200, txs} <- RPC.batch_request(:rpc, "getrawtransaction", batch_params, true),
|
||||||
failures <- Enum.filter(txs, fn %{"error" => error} -> error != nil end),
|
failures <- Enum.filter(txs, fn %{"error" => error} -> error != nil end),
|
||||||
successes <- Enum.filter(txs, fn %{"error" => error} -> error == nil end) do
|
successes <- Enum.filter(txs, fn %{"error" => error} -> error == nil end) do
|
||||||
@ -411,7 +411,7 @@ defmodule BitcoinStream.Mempool do
|
|||||||
end);
|
end);
|
||||||
case length(failures) do
|
case length(failures) do
|
||||||
count when count > 0 ->
|
count when count > 0 ->
|
||||||
IO.puts("failures: #{length(failures)}")
|
Logger.info("Failed to sync #{length(failures)} transactions")
|
||||||
|
|
||||||
_ -> false
|
_ -> false
|
||||||
end
|
end
|
||||||
@ -435,7 +435,7 @@ defmodule BitcoinStream.Mempool do
|
|||||||
defp sync_mempool_txns(pid, [next_chunk | rest], count) do
|
defp sync_mempool_txns(pid, [next_chunk | rest], count) do
|
||||||
case sync_batch(pid, next_chunk) do
|
case sync_batch(pid, next_chunk) do
|
||||||
{:ok, batch_count} ->
|
{: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)
|
sync_mempool_txns(pid, rest, batch_count + count)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -125,7 +125,7 @@ defmodule BitcoinStream.Protocol.Transaction do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp inflate_batch(batch, fail_fast) do
|
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),
|
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),
|
{:ok, 200, txs} <- RPC.batch_request(:rpc, "getrawtransaction", batch_params, fail_fast),
|
||||||
successes <- Enum.filter(txs, fn %{"error" => error} -> error == nil end),
|
successes <- Enum.filter(txs, fn %{"error" => error} -> error == nil end),
|
||||||
|
@ -13,7 +13,7 @@ defmodule BitcoinStream.Server do
|
|||||||
{ rpc_pool_size, "" } = Integer.parse(System.get_env("RPC_POOL_SIZE") || "16");
|
{ rpc_pool_size, "" } = Integer.parse(System.get_env("RPC_POOL_SIZE") || "16");
|
||||||
log_level = System.get_env("LOG_LEVEL");
|
log_level = System.get_env("LOG_LEVEL");
|
||||||
btc_host = System.get_env("BITCOIN_HOST");
|
btc_host = System.get_env("BITCOIN_HOST");
|
||||||
indexed = Mix.target == "public";
|
indexed = System.get_env("TARGET") == "public";
|
||||||
|
|
||||||
case log_level do
|
case log_level do
|
||||||
"debug" ->
|
"debug" ->
|
||||||
|
@ -57,7 +57,7 @@ defmodule BitcoinStream.Index.Spend do
|
|||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_call({:get_tx_spends, txid}, _from, [dbref, indexed, done]) do
|
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} ->
|
{:ok, spends} ->
|
||||||
{:reply, {:ok, spends}, [dbref, indexed, done]}
|
{:reply, {:ok, spends}, [dbref, indexed, done]}
|
||||||
|
|
||||||
@ -297,12 +297,81 @@ defmodule BitcoinStream.Index.Spend do
|
|||||||
end
|
end
|
||||||
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
|
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} ->
|
{:ok, spends} ->
|
||||||
spends
|
spends
|
||||||
|
|
||||||
:not_found ->
|
:unindexed ->
|
||||||
# uninitialized, try to construct on-the-fly from RPC data
|
# uninitialized, try to construct on-the-fly from RPC data
|
||||||
txid = Base.encode16(binary_txid);
|
txid = Base.encode16(binary_txid);
|
||||||
with {:ok, 200, hextx} <- RPC.request(:rpc, "getrawtransaction", [txid]),
|
with {:ok, 200, hextx} <- RPC.request(:rpc, "getrawtransaction", [txid]),
|
||||||
@ -339,23 +408,29 @@ defmodule BitcoinStream.Index.Spend do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp get_transaction_spends(dbref, txid, use_index) do
|
defp get_transaction_spends(dbref, txid, use_index) do
|
||||||
|
if (use_index) do
|
||||||
binary_txid = Base.decode16!(txid, [case: :lower]);
|
binary_txid = Base.decode16!(txid, [case: :lower]);
|
||||||
chain_spends = get_chain_spends(dbref, binary_txid, use_index);
|
chain_spends = get_chain_spends(dbref, binary_txid, use_index);
|
||||||
spend_list = unpack_spends(chain_spends);
|
spend_list = unpack_spends(chain_spends);
|
||||||
spend_list = add_mempool_spends(txid, spend_list);
|
spend_list = add_mempool_spends(txid, spend_list);
|
||||||
{:ok, 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
|
end
|
||||||
|
|
||||||
defp add_mempool_spends(_txid, _index, [], added) do
|
defp add_mempool_spends(_txid, _index, [], added) do
|
||||||
Enum.reverse(added)
|
Enum.reverse(added)
|
||||||
end
|
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
|
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])
|
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
|
||||||
end
|
end
|
||||||
defp add_mempool_spends(txid, index, [spend | rest], added) do
|
defp add_mempool_spends(txid, index, [spend | rest], added) do
|
||||||
|
Loading…
Reference in New Issue
Block a user