Terminus v0.1.1 Terminus View Source
Terminus allows you to crawl and subscribe to Bitcoin transaction events and download binary data from transactions, using a combination of Bitbus and Bitsocket, and BitFS.
Terminus provides a single unified interface for querying Planaria corp APIs
in a highly performant manner. Each request is a GenStage
process, enabling
you to create powerful concurrent data flows. Terminus may well be the most
powerful way of querying Bitcoin in the Universe!
APIs
Terminus can be used to interface with the following Planaria Corp APIs.
Bitbus
- crawl filtered subsets of confirmed Bitcoin transactions in blocks.Bitsocket
- subscribe to a live, filterable stream of realtime transaction events.BitFS
- fetch raw binary data chunks (over 512kb) indexed from all Bitcoin transactions.
Authentication
Both Bitbus and Bitsocket require a token to authenticate requests. (The Bitsocket
listen
API currently doesn't require a token but that is likely to change).
Currently tokens are free with no usage limits. (Also likely to change)
Where a token is given as a tuple pair in the format, {app, key}
, Terminus
will fetch the token at runtime using Application.get_env(app, key)
.callback()
iex> Terminus.Omni.find(txid, token: {:my_app, :planaria_token})
{:ok, %{...}}
Query language
Both Bitbus and Bitsocket use the same MongoDB-like query language, known as
Bitquery. Terminus fully supports both
the TXO (Transaction Object) and BOB (Bitcoin OP_RETURN Bytecode) schemas, and
allows the optional use of shorthand queries (just the q
value).
iex> Terminus.Bitbus.fetch!(%{
...> find: %{ "out.s2" => "1LtyME6b5AnMopQrBPLk4FGN8UBuhxKqrn" },
...> sort: %{ "blk.i": -1 },
...> project: %{ "tx.h": 1 },
...> limit: 5
...> }, token: token)
[
%{"tx" => %{"h" => "fca7bdd7658613418c54872212811cf4c5b4f8ee16864eaf70cb1393fb0df6ca"}},
%{"tx" => %{"h" => "79ae3ca23d1067b9ab45aba7e8ff4de1943e383e9a33e562d5ffd8489f388c93"}},
%{"tx" => %{"h" => "5526989417f28da5e0c99b58863db58c1faf8862ac9325dc415ad4b11605c1b1"}},
%{"tx" => %{"h" => "0bac587681360f961dbccba4c49a5c8f1b6f0bef61fe8501a28dcfe981a920b5"}},
%{"tx" => %{"h" => "fa13a8f0f5688f761b2f34949bb35fa5d6fd14cb3d49c2c1617363b6984df162"}}
]
Using Terminus
Terminus can be used as a simple API client, or a turbo-charged, concurrent multi-stream Bitcoin scraper on steroids. You decide.
The following modules are the primary ways of using Terminus.
Terminus.Bitbus
- functions for crawling and query confirmed Bitcoin transactions.Terminus.Bitsocket
- query mempool transactions and listen to realtime transaction events.Terminus.BitFS
- fetch binary data blobs embedded in Bitcoin transactions.Terminus.Omni
- conveniently fetch confirmed and mempool transactions together.Terminus.Planaria
- run Bitcoin scraper processes under your application's supervision tree.
Streams
Most Terminus functions return a streaming Enumerable.t/0
allowing you to
compose data processing pipelines and operations.
iex> Terminus.Bitbus.crawl!(query, token: token)
...> |> Stream.map(&Terminus.BitFS.scan_tx/1)
...> |> Stream.each(&save_to_db/1)
...> |> Stream.run
:ok
Omni
Sometimes it's necessary to query both confirmed and confirmed transaction
simultaneously. This is where Terminus.Omni
comes in, effectively replicating
the functionality of legacy Planaria APIs and returning returning results from
Bitbus and Bitsocket in one call.
iex> Terminus.Omni.fetch(query, token: token)
{:ok, %{
c: [...], # collection of confirmed tx
u: [...] # collection of mempool tx
}}
You can also easily find a single transaction by its txid
irrespective of whether it is confirmed or not.
iex> Terminus.Omni.find(txid, token: token)
{:ok, %{
"tx" => %{"h" => "fca7bdd7658613418c54872212811cf4c5b4f8ee16864eaf70cb1393fb0df6ca"},
...
}}
Planaria
Using Terminus.Planaria
inside a module allows you to simply recreate
Planaria-like state machine functionality.
Planarias can be started under your app's supervision tree, allowing multiple Planaria processes to run concurrently.
defmodule TwetchScraper do
@query %{
"find" => %{
"out.s2": "19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut",
"out.s25": "twetch"
}
}
use Terminus.Planaria, token: {:my_app, :planaria_token},
from: 600000,
query: @query
def handle_data(:block, txns) do
# Handle confirmed transactions
end
def handle_data(:mempool, txns) do
# Handle unconfirmed transactions
end
end
Concurrency
Under the hood, each Terminus request is a GenStage
producer process, and
the bare pid
can be returned. This allows you to take full
advantage of Elixir's concurrency, by either using with your own GenStage
consumers or using a tool like Flow
to create powerful concurrent pipelines.
# One stream of transactions will be distributed across eight concurrent
# processes for mapping and saving the data.
iex> {:ok, pid} = Terminus.Bitbus.crawl(query, token: token, stage: true)
iex> Flow.from_stages([pid], stages: 8)
...> |> Flow.map(&Terminus.BitFS.scan_tx/1)
...> |> Flow.map(&save_to_db/1)
...> |> Flow.run
:ok
Link to this section Summary
Types
BitFS URI scheme.
Bitcoin data query language.
On-data callback function.
Hex-encoded transaction ID.