mirror of
https://github.com/Retropex/bitfeed.git
synced 2025-05-12 19:20:46 +02:00
111 lines
3.1 KiB
Elixir
111 lines
3.1 KiB
Elixir
Application.ensure_all_started(:hackney)
|
|
|
|
defmodule BitcoinStream.Mempool do
|
|
@moduledoc """
|
|
Agent for retrieving and maintaining mempool info (primarily tx count)
|
|
"""
|
|
use Agent
|
|
|
|
@doc """
|
|
Start a new mempool tracker,
|
|
connecting to a bitcoin node at RPC `host:port` for ground truth data
|
|
"""
|
|
def start_link(opts) do
|
|
{port, opts} = Keyword.pop(opts, :port);
|
|
{host, opts} = Keyword.pop(opts, :host);
|
|
IO.puts("Starting mempool agent on #{host} port #{port}");
|
|
case Agent.start_link(fn -> %{count: 0, host: host, port: port} end, opts) do
|
|
{:ok, pid} ->
|
|
sync(pid);
|
|
{:ok, pid}
|
|
|
|
result -> result
|
|
end
|
|
end
|
|
|
|
def getHost(pid) do
|
|
Agent.get(pid, &Map.get(&1, :host))
|
|
end
|
|
|
|
def getPort(pid) do
|
|
Agent.get(pid, &Map.get(&1, :port))
|
|
end
|
|
|
|
def set(pid, n) do
|
|
Agent.update(pid, &Map.update(&1, :count, 0, fn(_) -> n end))
|
|
end
|
|
|
|
def get(pid) do
|
|
Agent.get(pid, &Map.get(&1, :count))
|
|
end
|
|
|
|
def increment(pid) do
|
|
Agent.update(pid, &Map.update(&1, :count, 0, fn(x) -> x + 1 end))
|
|
end
|
|
|
|
def decrement(pid) do
|
|
Agent.update(pid, &Map.update(&1, :count, 0, fn(x) -> x - 1 end))
|
|
end
|
|
|
|
def add(pid, n) do
|
|
Agent.update(pid, &Map.update(&1, :count, 0, fn(x) -> x + n end))
|
|
end
|
|
|
|
def subtract(pid, n) do
|
|
Agent.update(pid, &Map.update(&1, :count, 0, fn(x) -> x - n end))
|
|
end
|
|
|
|
def sync(pid) do
|
|
host = getHost(pid);
|
|
port = getPort(pid);
|
|
IO.puts("Syncing mempool with bitcoin node on #{host} port #{port}");
|
|
with { user, pw } <- rpc_creds(),
|
|
{:ok, rpc_request} <- Jason.encode(%{method: "getmempoolinfo", params: [], request_id: 0}),
|
|
{:ok, 200, _headers, body_ref} <- :hackney.request(:post, "http://#{host}:#{port}", [{"content-type", "application/json"}], rpc_request, [basic_auth: { user, pw }]),
|
|
{:ok, body} <- :hackney.body(body_ref),
|
|
{:ok, %{"result" => info}} <- Jason.decode(body),
|
|
%{"size" => pool_size} <- info do
|
|
IO.puts("Synced pool: size = #{pool_size}");
|
|
set(pid, pool_size)
|
|
else
|
|
{:error, reason} ->
|
|
IO.puts("Pool sync failed");
|
|
IO.inspect(reason)
|
|
:error
|
|
err ->
|
|
IO.puts("Pool sync failed: (unknown reason)");
|
|
IO.inspect(err);
|
|
:error
|
|
end
|
|
end
|
|
|
|
defp rpc_creds() do
|
|
cookie_path = System.get_env("BITCOIN_RPC_COOKIE");
|
|
rpc_user = System.get_env("BITCOIN_RPC_USER");
|
|
rpc_pw = System.get_env("BITCOIN_RPC_PASS");
|
|
cond do
|
|
(rpc_user != nil && rpc_pw != nil)
|
|
-> { rpc_user, rpc_pw }
|
|
(cookie_path != nil)
|
|
->
|
|
IO.puts("loading bitcoin rpc cookie at #{cookie_path}");
|
|
with {:ok, cookie} <- File.read(cookie_path),
|
|
[ user, pw ] <- String.split(cookie, ":") do
|
|
{ user, pw }
|
|
else
|
|
{:error, reason} ->
|
|
IO.puts("Failed to load bitcoin rpc cookie");
|
|
IO.inspect(reason)
|
|
:error
|
|
err ->
|
|
IO.puts("Failed to load bitcoin rpc cookie: (unknown reason)");
|
|
IO.inspect(err);
|
|
:error
|
|
end
|
|
true ->
|
|
IO.puts("Missing bitcoin rpc credentials");
|
|
:error
|
|
end
|
|
end
|
|
end
|