Skip to content

Commit

Permalink
Add graphql queries to get oracle data (#532)
Browse files Browse the repository at this point in the history
Provide a live feed with subscription and query for the latest or by time.
  • Loading branch information
Samuel committed Aug 24, 2022
1 parent db6383b commit b82bc91
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 9 deletions.
9 changes: 8 additions & 1 deletion lib/archethic/oracle_chain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,21 @@ defmodule Archethic.OracleChain do
@spec get_uco_price(DateTime.t()) :: list({binary(), float()})
def get_uco_price(date = %DateTime{}) do
case MemTable.get_oracle_data("uco", date) do
{:ok, prices} ->
{:ok, prices, _} ->
Enum.map(prices, fn {pair, price} -> {String.to_existing_atom(pair), price} end)

_ ->
[eur: 0.05, usd: 0.07]
end
end

@doc """
Get the oracle data by date for a given service
"""
@spec get_oracle_data(binary(), DateTime.t()) ::
{:ok, map(), DateTime.t()} | {:error, :not_found}
defdelegate get_oracle_data(service, date), to: MemTable

def config_change(changed_conf) do
changed_conf
|> Keyword.get(Scheduler)
Expand Down
13 changes: 7 additions & 6 deletions lib/archethic/oracle_chain/mem_table.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ defmodule Archethic.OracleChain.MemTable do
iex> MemTable.add_oracle_data("uco", %{ "eur" => 0.02 }, ~U[2021-06-04 10:00:00Z])
iex> MemTable.add_oracle_data("uco", %{ "eur" => 0.04 }, ~U[2021-06-04 15:00:00Z])
iex> MemTable.get_oracle_data("uco", ~U[2021-06-04 10:10:00Z])
{:ok, %{ "eur" => 0.02 }}
{:ok, %{ "eur" => 0.02 }, ~U[2021-06-04 10:00:00Z]}
iex> MemTable.get_oracle_data("uco", ~U[2021-06-04 20:10:40Z])
{:ok, %{ "eur" => 0.04 }}
{:ok, %{ "eur" => 0.04 }, ~U[2021-06-04 15:00:00Z]}
"""
@spec get_oracle_data(any(), DateTime.t()) :: {:ok, map()} | {:error, :not_found}
@spec get_oracle_data(any(), DateTime.t()) ::
{:ok, data :: map(), oracle_datetime :: DateTime.t()} | {:error, :not_found}
def get_oracle_data(type, date = %DateTime{}) do
timestamp =
date
Expand All @@ -70,13 +71,13 @@ defmodule Archethic.OracleChain.MemTable do
:"$end_of_table" ->
{:error, :not_found}

key ->
key = {time, _} ->
[{_, data}] = :ets.lookup(:archethic_oracle, key)
{:ok, data}
{:ok, data, DateTime.from_unix!(time)}
end

[{_, data}] ->
{:ok, data}
{:ok, data, date}
end
end
end
10 changes: 10 additions & 0 deletions lib/archethic/oracle_chain/mem_table_loader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ defmodule Archethic.OracleChain.MemTableLoader do

content
|> Jason.decode!()
|> tap(fn data ->
Absinthe.Subscription.publish(
ArchethicWeb.Endpoint,
%{
services: data,
timestamp: timestamp
},
oracle_update: "oracle-topic"
)
end)
|> Enum.each(fn {service, data} ->
MemTable.add_oracle_data(service, data, timestamp)
end)
Expand Down
45 changes: 45 additions & 0 deletions lib/archethic_web/graphql_schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule ArchethicWeb.GraphQLSchema do
alias __MODULE__.PageType
alias __MODULE__.TransactionAttestation
alias __MODULE__.TransactionError
alias __MODULE__.OracleData

import_types(HexType)
import_types(DateTimeType)
Expand All @@ -21,6 +22,7 @@ defmodule ArchethicWeb.GraphQLSchema do
import_types(TransactionAttestation)
import_types(TransactionError)
import_types(PageType)
import_types(OracleData)

query do
@desc """
Expand Down Expand Up @@ -128,6 +130,22 @@ defmodule ArchethicWeb.GraphQLSchema do
{:ok, Resolver.network_transactions(type, page)}
end)
end

field :oracle_data, :oracle_data do
arg(:timestamp, :timestamp)

resolve(fn args, _ ->
datetime = Map.get(args, :timestamp, DateTime.utc_now())

case Archethic.OracleChain.get_oracle_data("uco", datetime) do
{:ok, %{"eur" => eur, "usd" => usd}, datetime} ->
{:ok, %{services: %{uco: %{eur: eur, usd: usd}}, timestamp: datetime}}

{:error, :not_found} ->
{:error, "Not data found at this date"}
end
end)
end
end

subscription do
Expand All @@ -142,12 +160,39 @@ defmodule ArchethicWeb.GraphQLSchema do
end)
end

@desc """
Subscribe to be notified when a transaction is on error
"""
field :transaction_error, :transaction_error do
arg(:address, non_null(:address))

config(fn args, _info ->
{:ok, topic: args.address}
end)
end

@desc """
Subscribe to be notified when a new oracle data is stored
"""
field :oracle_update, :oracle_data do
config(fn _args, _info ->
{:ok, topic: "oracle-topic"}
end)

resolve(fn %{timestamp: timestamp, services: %{"uco" => %{"eur" => eur, "usd" => usd}}},
_,
_ ->
{:ok,
%{
timestamp: timestamp,
services: %{
uco: %{
eur: eur,
usd: usd
}
}
}}
end)
end
end
end
17 changes: 17 additions & 0 deletions lib/archethic_web/graphql_schema/datetime_type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,22 @@ defmodule ArchethicWeb.GraphQLSchema.DateTimeType do
"""
scalar :timestamp do
serialize(&DateTime.to_unix/1)
parse(&parse_datetime/1)
end

defp parse_datetime(%Absinthe.Blueprint.Input.String{value: value}) do
with {timestamp, ""} <- Integer.parse(value),
{:ok, datetime} <- DateTime.from_unix(timestamp) do
{:ok, datetime}
else
_ ->
:error
end
end

defp parse_datetime(%Absinthe.Blueprint.Input.Integer{value: value}) do
DateTime.from_unix(value)
end

defp parse_datetime(_), do: :error
end
22 changes: 22 additions & 0 deletions lib/archethic_web/graphql_schema/oracle_data.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule ArchethicWeb.GraphQLSchema.OracleData do
@moduledoc false

use Absinthe.Schema.Notation

@desc """
[OracleData] represents an oracle data.
"""
object :oracle_data do
field(:services, :oracle_services)
field(:timestamp, :timestamp)
end

object :oracle_services do
field(:uco, :uco_data)
end

object :uco_data do
field(:usd, :float)
field(:eur, :float)
end
end
4 changes: 2 additions & 2 deletions test/archethic/oracle_chain/mem_table_loader_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ defmodule Archethic.OracleChain.MemTableLoaderTest do
}
})

assert {:ok, %{"eur" => 0.02}} = MemTable.get_oracle_data("uco", DateTime.utc_now())
assert {:ok, %{"eur" => 0.02}, _} = MemTable.get_oracle_data("uco", DateTime.utc_now())
end

test "should load an oracle summary transaction and the related changes" do
Expand All @@ -42,7 +42,7 @@ defmodule Archethic.OracleChain.MemTableLoaderTest do
}
})

assert {:ok, %{"eur" => 0.07}} =
assert {:ok, %{"eur" => 0.07}, _} =
MemTable.get_oracle_data("uco", DateTime.from_unix!(1_614_677_925))
end
end
Expand Down

0 comments on commit b82bc91

Please sign in to comment.