Packages
elixium_core
0.2.13
0.6.3
0.6.2
0.6.1
0.6.0
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.1
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.4
0.1.3
The core package for the Elixium blockchain, containing all the modules needed to run the chain
Current section
Files
Jump to
Current section
Files
lib/store/utxo.ex
defmodule Elixium.Store.Utxo do
use Elixium.Store
require IEx
@moduledoc """
Provides an interface for interacting with the UTXOs stored in level db
"""
@store_dir ".utxo"
@ets_name :utxo
@type utxo() :: %{
txoid: String.t(),
addr: String.t(),
amount: number,
signature: String.t() | none()
}
def initialize do
initialize(@store_dir)
:ets.new(@ets_name, [:ordered_set, :public, :named_table])
end
@doc """
Add a utxo to leveldb, indexing it by its txoid
"""
@spec add_utxo(utxo()) :: :ok | {:error, any}
def add_utxo(utxo) do
transact @store_dir do
&Exleveldb.put(&1, String.to_atom(utxo.txoid), :erlang.term_to_binary(utxo))
end
:ets.insert(@ets_name, {utxo.txoid, utxo.addr, utxo})
end
@spec remove_utxo(String.t()) :: :ok | {:error, any}
def remove_utxo(txoid) do
transact @store_dir do
&Exleveldb.delete(&1, String.to_atom(txoid))
end
:ets.delete(@ets_name, txoid)
end
@doc """
Retrieve a UTXO by its txoid
"""
@spec retrieve_utxo(String.t()) :: map
def retrieve_utxo(txoid) do
case :ets.lookup(@ets_name, txoid) do
[] ->
transact @store_dir do
fn ref ->
{:ok, utxo} = Exleveldb.get(ref, String.to_atom(txoid))
:erlang.binary_to_term(utxo)
end
end
[{_txoid, _addr, utxo}] -> utxo
end
end
@doc """
Check if a UTXO is currently in the pool
"""
@spec in_pool?(utxo()) :: true | false
def in_pool?(%{txoid: txoid}), do: retrieve_utxo(txoid) != []
@spec retrieve_all_utxos :: list(utxo())
def retrieve_all_utxos do
# It might be better to get from ets here, but there might be the issue
# that ets wont have an UTXO that the store does, causing a block to be
# invalidated somewhere down the line even if the inputs are all valid.
transact @store_dir do
&Exleveldb.map(&1, fn {_, utxo} -> :erlang.binary_to_term(utxo) end)
end
end
@spec update_with_transactions(list) :: :ok | {:error, any}
def update_with_transactions(transactions) do
transact @store_dir do
fn ref ->
remove =
transactions
|> Enum.flat_map(& &1.inputs)
|> Enum.map(&{:delete, &1.txoid})
add =
transactions
|> Enum.flat_map(& &1.outputs)
|> Enum.map(&{:put, &1.txoid, :erlang.term_to_binary(&1)})
Exleveldb.write(ref, Enum.concat(remove, add))
transactions
|> Enum.flat_map(& &1.inputs)
|> Enum.each(&(:ets.delete(@ets_name, &1.txoid)))
transactions
|> Enum.flat_map(& &1.outputs)
|> Enum.each(&(:ets.insert(@ets_name, {&1.txoid, &1.addr, &1})))
end
end
end
@doc """
Return a list of UTXOs that a given address (public key) can use as inputs
"""
@spec find_by_address(String.t()) :: list(utxo())
def find_by_address(public_key) do
case :ets.match(@ets_name, {'_', public_key, '$1'}) do
[] -> do_find_by_address_from_store(public_key)
utxos -> utxos
end
end
defp do_find_by_address_from_store(public_key) do
transact @store_dir do
fn ref ->
ref
|> Exleveldb.map(fn {_, utxo} -> :erlang.binary_to_term(utxo) end)
|> Enum.filter(&(&1.addr == public_key))
end
end
end
end