Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API to get last oracle value #532

Merged
1 commit merged into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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