diff --git a/lib/archethic/mining/pending_transaction_validation.ex b/lib/archethic/mining/pending_transaction_validation.ex index 7485aa8929..2f503162d1 100644 --- a/lib/archethic/mining/pending_transaction_validation.ex +++ b/lib/archethic/mining/pending_transaction_validation.ex @@ -28,6 +28,7 @@ defmodule Archethic.Mining.PendingTransactionValidation do TransactionData, TransactionData.Ledger, TransactionData.Ownership, + TransactionData.UCOLedger, TransactionData.TokenLedger, TransactionSummary } @@ -243,6 +244,47 @@ defmodule Archethic.Mining.PendingTransactionValidation do end end + defp do_accept_transaction( + %Transaction{ + type: :transfer, + data: %TransactionData{ + ledger: %Ledger{ + uco: %UCOLedger{transfers: uco_transfers}, + token: %TokenLedger{transfers: token_transfers} + }, + recipients: recipients + } + }, + _ + ) do + if length(uco_transfers) > 0 or length(token_transfers) > 0 or length(recipients) > 0 do + :ok + else + {:error, + "Transfer's transaction requires some recipients for ledger or smart contract calls"} + end + end + + defp do_accept_transaction( + %Transaction{ + type: :hosting, + data: %TransactionData{content: content} + }, + _ + ) do + with {:ok, json} <- Jason.decode(content), + :ok <- check_aeweb_format(json) do + :ok + else + :error -> + {:error, "Invalid AEWeb transaction"} + + {:error, reason} -> + Logger.debug("Invalid AEWeb format #{inspect(reason)}") + {:error, "Invalid AEWeb transaction"} + end + end + defp do_accept_transaction( tx = %Transaction{ type: :node_rewards, @@ -762,4 +804,37 @@ defmodule Archethic.Mining.PendingTransactionValidation do {:error, :invalid_ip} end end + + defp check_aeweb_format(json) do + ref_schema = + :archethic + |> Application.app_dir("priv/json-schemas/aeweb_ref.json") + |> File.read!() + |> Jason.decode!() + |> ExJsonSchema.Schema.resolve() + + file_schema = + :archethic + |> Application.app_dir("priv/json-schemas/aeweb_file.json") + |> File.read!() + |> Jason.decode!() + |> ExJsonSchema.Schema.resolve() + + case ExJsonSchema.Validator.validate(ref_schema, json) do + :ok -> + :ok + + {:error, [{"Required properties aewebVersion, metadata were not present.", _}]} -> + case ExJsonSchema.Validator.validate(file_schema, json) do + :ok -> + :ok + + {:error, error_file} -> + {:error, error_file} + end + + {:error, error_ref} -> + {:error, error_ref} + end + end end diff --git a/test/archethic/mining/pending_transaction_validation_test.exs b/test/archethic/mining/pending_transaction_validation_test.exs index 9fffd12080..f8413345b8 100644 --- a/test/archethic/mining/pending_transaction_validation_test.exs +++ b/test/archethic/mining/pending_transaction_validation_test.exs @@ -20,6 +20,9 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do alias Archethic.TransactionChain.Transaction alias Archethic.TransactionChain.TransactionData + alias Archethic.TransactionChain.TransactionData.Ledger + alias Archethic.TransactionChain.TransactionData.UCOLedger + alias Archethic.TransactionChain.TransactionData.UCOLedger.Transfer alias Archethic.TransactionChain.TransactionData.Ownership alias Archethic.SharedSecrets @@ -490,6 +493,13 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do Transaction.new( :transfer, %TransactionData{ + ledger: %Ledger{ + uco: %UCOLedger{ + transfers: [ + %Transfer{to: :crypto.strong_rand_bytes(32), amount: 100_000} + ] + } + }, code: """ condition inherit: [ content: "hello" @@ -724,5 +734,40 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do assert {:error, "Invalid node rewards trigger time"} = PendingTransactionValidation.validate(tx, ~U[2022-01-01 00:00:03Z]) end + + test "should return :ok when we deploy a aeweb ref transaction" do + tx = + Transaction.new(:hosting, %TransactionData{ + content: + Jason.encode!(%{ + "aewebVersion" => 1, + "metadata" => %{ + "index.html" => %{ + "encoding" => "gzip", + "addresses" => [ + Crypto.derive_keypair("seed", 0) + |> elem(0) + |> Crypto.derive_address() + |> Base.encode16() + ] + } + } + }) + }) + + assert :ok = PendingTransactionValidation.validate(tx, DateTime.utc_now()) + end + + test "should return :ok when we deploy a aeweb file transaction" do + tx = + Transaction.new(:hosting, %TransactionData{ + content: + Jason.encode!(%{ + "index.html" => Base.url_encode64(:crypto.strong_rand_bytes(1000)) + }) + }) + + assert :ok = PendingTransactionValidation.validate(tx, DateTime.utc_now()) + end end end