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
8 changes: 8 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
31 changes: 29 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.FirstPublicKey
alias ArchEthic.P2P.Message.GetFirstPublicKey
alias ArchEthic.P2P.Message.NotFound

@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,27 @@ 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() | {:error, :network_issue} | {:error, :enoaddress}
def get_genesis_address(address) do
address = Base.decode16!(address)
This conversation was marked as resolved.
Show resolved Hide resolved

with [node | _rest] <- P2P.available_nodes(),
public_key_request <- %GetFirstPublicKey{address: address},
{:ok, %FirstPublicKey{public_key: key}} <- P2P.send_message(node, public_key_request) do
{pub, _priv} = Crypto.derive_keypair(key, 0)
This conversation was marked as resolved.
Show resolved Hide resolved
Crypto.derive_address(pub)
else
[] ->
{:error, :network_issue}

{:ok, %NotFound{}} ->
This conversation was marked as resolved.
Show resolved Hide resolved
{:error, :enoaddress}
end
end
end
56 changes: 55 additions & 1 deletion test/archethic/contracts/interpreter/library_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,61 @@
defmodule ArchEthic.Contracts.Interpreter.LibraryTest do
use ExUnit.Case
use ArchEthicCase

alias ArchEthic.Contracts.Interpreter.Library
alias ArchEthic.Crypto
alias ArchEthic.P2P
alias ArchEthic.P2P.Node
alias ArchEthic.P2P.Message.NotFound
alias ArchEthic.P2P.Message.FirstPublicKey

doctest Library

import Mox

describe "get_genesis_address/1" do
setup do
key = <<0::16, :crypto.strong_rand_bytes(32)::binary>>

P2P.add_and_connect_node(%Node{
ip: {127, 0, 0, 1},
port: 3000,
first_public_key: key,
last_public_key: key,
available?: true,
geo_patch: "AAA",
network_patch: "AAA",
authorized?: true,
authorization_date: DateTime.utc_now()
})

{:ok, [key: key]}
end

test "with empty node list" do
MockClient
|> expect(:send_message, fn _, _, _ -> [] end)

address = :crypto.strong_rand_bytes(34) |> Base.encode16()
assert {:error, :network_issue} == Library.get_genesis_address(address)
end

test "with NotFound node list" do
MockClient
|> expect(:send_message, fn _, _, _ -> {:ok, %NotFound{}} end)

address = :crypto.strong_rand_bytes(34) |> Base.encode16()
assert {:error, :enoaddress} == Library.get_genesis_address(address)
end

test "with FirstPublicKey returned", %{key: key} do
{pub, _priv} = Crypto.derive_keypair(key, 0)
genesis_address = Crypto.derive_address(pub)

MockClient
|> expect(:send_message, fn _, _, _ -> {:ok, %FirstPublicKey{public_key: key}} end)

address = :crypto.strong_rand_bytes(34) |> Base.encode16()
assert genesis_address == Library.get_genesis_address(address)
end
end
end