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 fn in SC lib to get genesis address in smart contract #268

Merged
11 commits merged into from
Apr 29, 2022
16 changes: 16 additions & 0 deletions lib/archethic/contracts/interpreter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,14 @@ defmodule ArchEthic.Contracts.Interpreter do
when scope != :root,
do: {node, acc}

# Whitelist the get_genesis_address/1 function in condition
defp prewalk(
This conversation was marked as resolved.
Show resolved Hide resolved
node = {{:atom, "get_genesis_address"}, _, [_address]},
acc = {:ok, %{scope: :condition}}
) do
{node, acc}
end

# Whitelist the regex_match?/1 function in the condition
defp prewalk(
node = {{:atom, "regex_match?"}, _, [_search]},
Expand Down Expand Up @@ -631,6 +639,14 @@ defmodule ArchEthic.Contracts.Interpreter do
defp prewalk(node = {{:atom, "size"}, _, []}, acc = {:ok, %{scope: :condition}}),
do: {node, acc}

# Whitelist the get_genesis_address/1 function in actions
defp prewalk(
node = {{:atom, "get_genesis_address"}, _, [_address]},
acc = {:ok, %{scope: :actions}}
) do
{node, acc}
end

# Whitelist the used of functions in the actions
defp prewalk(node = {{:atom, fun_name}, _, _}, {:ok, acc = %{scope: :actions}})
when fun_name in @transaction_statements_functions_names,
Expand Down
30 changes: 28 additions & 2 deletions lib/archethic/contracts/interpreter/library.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ defmodule ArchEthic.Contracts.Interpreter.Library do
@moduledoc false

alias ArchEthic.Crypto
alias ArchEthic.P2P
alias ArchEthic.P2P.Message.GetFirstAddress
alias ArchEthic.P2P.Message.FirstAddress
alias ArchEthic.Election

@doc """
Match a regex expression
Expand Down Expand Up @@ -79,12 +83,12 @@ defmodule ArchEthic.Contracts.Interpreter.Library do
end

@doc ~S"""
Match a json path expression
Match a json path expression

## Examples

iex> Library.json_path_match?("{\"1622541930\":{\"uco\":{\"eur\":0.176922,\"usd\":0.21642}}}", "$.*.uco.usd")
true
true
"""
@spec json_path_match?(binary(), binary()) :: boolean()
def json_path_match?(text, path) when is_binary(text) and is_binary(path) do
Expand Down Expand Up @@ -149,4 +153,26 @@ defmodule ArchEthic.Contracts.Interpreter.Library do
def size(binary) when is_binary(binary), do: byte_size(binary)
def size(list) when is_list(list), do: length(list)
def size(map) when is_map(map), do: map_size(map)

@doc """
Get the genesis address of the chain

"""
@spec get_genesis_address(binary()) ::
binary()
def get_genesis_address(address) do
address = Base.decode16!(address)
This conversation was marked as resolved.
Show resolved Hide resolved
nodes = Election.chain_storage_nodes(address, P2P.available_nodes())
{:ok, address} = download_first_address(nodes, address)
address
end

defp download_first_address([node | rest], address) do
case P2P.send_message(node, %GetFirstAddress{address: address}) do
{:ok, %FirstAddress{address: address}} -> {:ok, address}
{:error, _} -> download_first_address(rest, address)
end
end

defp download_first_address([], _address), do: {:error, :network_issue}
end
32 changes: 32 additions & 0 deletions lib/archethic/p2p/message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ defmodule ArchEthic.P2P.Message do
alias __MODULE__.EncryptedStorageNonce
alias __MODULE__.Error
alias __MODULE__.FirstPublicKey
alias __MODULE__.FirstAddress
alias __MODULE__.GetFirstAddress
alias __MODULE__.GetBalance
alias __MODULE__.GetBeaconSummaries
alias __MODULE__.GetBeaconSummary
Expand Down Expand Up @@ -114,6 +116,7 @@ defmodule ArchEthic.P2P.Message do
| BeaconUpdate.t()
| TransactionSummary.t()
| ReplicationAttestation.t()
| GetFirstAddress.t()

@type response ::
Ok.t()
Expand All @@ -135,6 +138,7 @@ defmodule ArchEthic.P2P.Message do
| Error.t()
| Summary.t()
| BeaconSummaryList.t()
| FirstAddress.t()

@doc """
Extract the Message Struct name
Expand Down Expand Up @@ -332,6 +336,14 @@ defmodule ArchEthic.P2P.Message do
<<30::8, ReplicationAttestation.serialize(attestation)::binary>>
end

def encode(%GetFirstAddress{address: address}) do
<<31::8, address::binary>>
end

def encode(%FirstAddress{address: address}) do
<<235::8, address::binary>>
end

def encode(%BeaconUpdate{transaction_attestations: transaction_attestations}) do
transaction_attestations_bin =
transaction_attestations
Expand Down Expand Up @@ -740,6 +752,16 @@ defmodule ArchEthic.P2P.Message do
ReplicationAttestation.deserialize(rest)
end

def decode(<<31::8, rest::bitstring>>) do
{address, rest} = Utils.deserialize_address(rest)
{%GetFirstAddress{address: address}, rest}
end

def decode(<<235::8, rest::bitstring>>) do
{address, rest} = Utils.deserialize_address(rest)
{%FirstAddress{address: address}, rest}
end

def decode(<<236::8, nb_transaction_attestations::16, rest::bitstring>>) do
{transaction_attestations, rest} =
Utils.deserialize_transaction_attestations(rest, nb_transaction_attestations, [])
Expand Down Expand Up @@ -1176,6 +1198,16 @@ defmodule ArchEthic.P2P.Message do
end
end

def process(%GetFirstAddress{address: address}) do
case TransactionChain.get_first_transaction(address, [:address]) do
{:ok, %Transaction{address: address}} ->
%FirstAddress{address: address}

{:error, :transaction_not_exits} ->
%NotFound{}
end
end

def process(%GetLastTransactionAddress{address: address, timestamp: timestamp}) do
address = TransactionChain.get_last_address(address, timestamp)
%LastTransactionAddress{address: address}
Expand Down
11 changes: 11 additions & 0 deletions lib/archethic/p2p/message/first_address.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule ArchEthic.P2P.Message.FirstAddress do
@moduledoc """
Represents a message to first address from the transaction chain
"""
@enforce_keys [:address]
defstruct [:address]

@type t :: %__MODULE__{
address: binary()
}
end
12 changes: 12 additions & 0 deletions lib/archethic/p2p/message/get_first_address.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule ArchEthic.P2P.Message.GetFirstAddress do
@moduledoc """
Represents a message to request the first address from a transaction chain
"""

@enforce_keys [:address]
defstruct [:address]

@type t() :: %__MODULE__{
address: binary()
}
end
2 changes: 1 addition & 1 deletion test/archethic/contracts/interpreter/library_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule ArchEthic.Contracts.Interpreter.LibraryTest do
use ExUnit.Case
use ArchEthicCase

alias ArchEthic.Contracts.Interpreter.Library

Expand Down