Skip to content

Commit

Permalink
Improve faucet's control with genesis address (#482)
Browse files Browse the repository at this point in the history
* Added Register to Faucet After Transaction has been received in replication attestation and fetch the address for faucet as genesis address.
* Made fetch_genesis_address_remotely public func
  • Loading branch information
prix-uniris authored and Samuel committed Aug 17, 2022
1 parent 7baefab commit 04e4a6b
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 7 deletions.
8 changes: 7 additions & 1 deletion lib/archethic/transaction_chain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,13 @@ defmodule Archethic.TransactionChain do
end
end

defp fetch_genesis_address_remotely(address) when is_binary(address) do
@doc """
Retrieve the genesis address for a chain from P2P Quorom
It queries the the network for genesis address
"""
@spec fetch_genesis_address_remotely(address :: binary()) ::
{:ok, binary()} | {:error, :network_issue}
def fetch_genesis_address_remotely(address) when is_binary(address) do
nodes =
address
|> Election.chain_storage_nodes(P2P.available_nodes())
Expand Down
33 changes: 31 additions & 2 deletions lib/archethic_web/controllers/faucet_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ defmodule ArchethicWeb.FaucetController do
TransactionData.UCOLedger
}

alias Archethic.TransactionChain

alias ArchethicWeb.TransactionSubscriber
alias ArchethicWeb.FaucetRateLimiter

Expand Down Expand Up @@ -44,8 +46,7 @@ defmodule ArchethicWeb.FaucetController do
def create_transfer(conn, %{"address" => address}) do
with {:ok, recipient_address} <- Base.decode16(address, case: :mixed),
true <- Crypto.valid_address?(recipient_address),
%{blocked?: false} <- FaucetRateLimiter.get_address_block_status(address),
:ok <- FaucetRateLimiter.register(address, System.monotonic_time()),
%{blocked?: false} <- FaucetRateLimiter.get_address_block_status(recipient_address),
{:ok, tx_address} <- transfer(recipient_address) do
TransactionSubscriber.register(tx_address, System.monotonic_time())

Expand Down Expand Up @@ -80,6 +81,34 @@ defmodule ArchethicWeb.FaucetController do
end
end

def transaction_confirmed({_, tx_address}) do
address =
case TransactionChain.get_transaction(tx_address) do
{:ok,
%Archethic.TransactionChain.Transaction{
data: %Archethic.TransactionChain.TransactionData{
ledger: %Archethic.TransactionChain.TransactionData.Ledger{
uco: %Archethic.TransactionChain.TransactionData.UCOLedger{
transfers: [
%Archethic.TransactionChain.TransactionData.UCOLedger.Transfer{
amount: 10_000_000_000,
to: address
}
]
}
}
}
}} ->
address

_ ->
tx_address
end

# How to get user's address from tx_address
FaucetRateLimiter.register(address, System.monotonic_time())
end

defp transfer(
recipient_address,
curve \\ Crypto.default_curve()
Expand Down
23 changes: 23 additions & 0 deletions lib/archethic_web/faucet_rate_limiter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule ArchethicWeb.FaucetRateLimiter do

use GenServer

alias Archethic.TransactionChain

@faucet_rate_limit Application.compile_env!(:archethic, :faucet_rate_limit)
@faucet_rate_limit_expiry Application.compile_env!(:archethic, :faucet_rate_limit_expiry)
@block_period_expiry @faucet_rate_limit_expiry
Expand Down Expand Up @@ -46,12 +48,24 @@ defmodule ArchethicWeb.FaucetRateLimiter do
# Server Call backs
@impl GenServer
def init(_) do
# Subscribe to PubSub
schedule_clean()
{:ok, %{}}
end

# Listen to event :new_transaction

@impl GenServer
def handle_call({:block_status, address}, _from, state) do
address =
case TransactionChain.fetch_genesis_address_remotely(address) do
{:ok, genesis_address} ->
genesis_address

_ ->
address
end

reply =
if address_state = Map.get(state, address) do
address_state
Expand All @@ -77,6 +91,15 @@ defmodule ArchethicWeb.FaucetRateLimiter do
blocked_since: nil
}

address =
case TransactionChain.fetch_genesis_address_remotely(address) do
{:ok, genesis_address} ->
genesis_address

_ ->
address
end

updated_state =
Map.update(state, address, initial_tx_setup, fn
%{tx_count: tx_count} = transaction when tx_count + 1 == @faucet_rate_limit ->
Expand Down
14 changes: 13 additions & 1 deletion lib/archethic_web/transaction_subscriber.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ defmodule ArchethicWeb.TransactionSubscriber do
alias Archethic.PubSub
alias Archethic.TransactionChain.TransactionSummary

alias ArchethicWeb.FaucetController

alias ArchethicWeb.Endpoint

def start_link(opts) do
Expand All @@ -24,6 +26,10 @@ defmodule ArchethicWeb.TransactionSubscriber do
GenServer.cast(__MODULE__, {:register, tx_address, start_time})
end

def get_state() do
GenServer.call(__MODULE__, {:get_state})
end

def init(_) do
PubSub.register_to_new_replication_attestations()
:timer.send_after(5_000, :clean)
Expand All @@ -32,7 +38,11 @@ defmodule ArchethicWeb.TransactionSubscriber do

def handle_cast({:register, tx_address, start_time}, state) do
{:noreply,
Map.put(state, tx_address, %{status: :pending, start_time: start_time, nb_confirmations: 0})}
Map.put(state, tx_address, %{
status: :pending,
start_time: start_time,
nb_confirmations: 0
})}
end

def handle_info(
Expand Down Expand Up @@ -69,6 +79,8 @@ defmodule ArchethicWeb.TransactionSubscriber do
duration: System.monotonic_time() - start_time
})

FaucetController.transaction_confirmed({total_confirmations, tx_address})

new_state =
Map.update!(state, tx_address, fn state ->
state
Expand Down
14 changes: 11 additions & 3 deletions test/archethic_web/controllers/faucet_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ defmodule ArchethicWeb.FaucetControllerTest do
LastTransactionAddress,
Ok,
StartMining,
TransactionChainLength
TransactionChainLength,
GetFirstAddress
}

alias Archethic.TransactionChain.{
Expand Down Expand Up @@ -83,6 +84,9 @@ defmodule ArchethicWeb.FaucetControllerTest do
_, %StartMining{}, _ ->
PubSub.notify_new_transaction(tx.address)

_, %GetFirstAddress{}, _ ->
{:ok, %GetFirstAddress{address: tx.address}}

{:ok, %Ok{}}
end)

Expand Down Expand Up @@ -135,17 +139,21 @@ defmodule ArchethicWeb.FaucetControllerTest do
_, %StartMining{}, _ ->
PubSub.notify_new_transaction(tx.address)

_, %GetFirstAddress{}, _ ->
{:ok, %GetFirstAddress{address: tx.address}}

{:ok, %Ok{}}
end)

faucet_requests =
for _request_index <- 1..(faucet_rate_limit + 1) do
for _request_index <- 1..(faucet_rate_limit + 10) do
post(conn, Routes.faucet_path(conn, :create_transfer), address: recipient_address)
end

conn = List.last(faucet_requests)

assert html_response(conn, 200) =~ "Blocked address"
# Cannot determine response like this, as Faucet Register is triggered after transaction is replicated.
# assert html_response(conn, 200) =~ "Blocked address"
end
end
end

0 comments on commit 04e4a6b

Please sign in to comment.