Skip to content

Commit

Permalink
worker_should_not_be_executed_while_replicating_a_transaction_from_se…
Browse files Browse the repository at this point in the history
…lf_repair_
  • Loading branch information
apoorv-2204 authored and Neylix committed Jan 30, 2023
1 parent 3b8b8b1 commit 083d1a4
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 51 deletions.
4 changes: 2 additions & 2 deletions lib/archethic/contracts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ defmodule Archethic.Contracts do
@doc """
Load transaction into the Smart Contract context leveraging the interpreter
"""
@spec load_transaction(Transaction.t()) :: :ok
defdelegate load_transaction(tx), to: Loader
@spec load_transaction(Transaction.t(), list()) :: :ok
defdelegate load_transaction(tx, opts \\ []), to: Loader

@spec accept_new_contract?(Transaction.t() | nil, Transaction.t(), DateTime.t()) :: boolean()
def accept_new_contract?(nil, _, _), do: true
Expand Down
93 changes: 53 additions & 40 deletions lib/archethic/contracts/loader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ defmodule Archethic.Contracts.Loader do
_ -> true
end)
|> Stream.map(fn {:ok, tx} -> tx end)
|> Stream.each(&load_transaction(&1, true))
|> Stream.each(&load_transaction(&1, from_db: true))
|> Stream.run()

{:ok, []}
Expand All @@ -43,18 +43,24 @@ defmodule Archethic.Contracts.Loader do
@doc """
Load the smart contracts based on transaction involving smart contract code
"""
@spec load_transaction(Transaction.t()) :: :ok
def load_transaction(_tx, from_db \\ false)

def load_transaction(
tx = %Transaction{
address: address,
type: type,
data: %TransactionData{code: code}
},
_from_db
)
when code != "" do
@spec load_transaction(Transaction.t(), list()) :: :ok
def load_transaction(tx, opts \\ []) do
from_db = Keyword.get(opts, :from_db, false)
from_self_repair = Keyword.get(opts, :from_self_repair, false)

do_load_transaction(tx, from_db, from_self_repair)
end

defp do_load_transaction(
tx = %Transaction{
address: address,
type: type,
data: %TransactionData{code: code}
},
_from_db,
_from_self_repair
)
when code != "" do
stop_contract(Transaction.previous_address(tx))

%Contract{triggers: triggers} = Contracts.parse!(code)
Expand All @@ -77,25 +83,31 @@ defmodule Archethic.Contracts.Loader do
end
end

def load_transaction(
tx = %Transaction{
address: tx_address,
type: tx_type,
validation_stamp: %ValidationStamp{
timestamp: tx_timestamp,
recipients: recipients,
protocol_version: protocol_version
}
},
false
)
when recipients != [] do
defp do_load_transaction(
tx = %Transaction{
address: tx_address,
type: tx_type,
validation_stamp: %ValidationStamp{
timestamp: tx_timestamp,
recipients: recipients,
protocol_version: protocol_version
}
},
_from_db = false,
from_self_repair?
)
when recipients != [] do
Enum.each(recipients, fn contract_address ->
Logger.info("Execute transaction on contract #{Base.encode16(contract_address)}",
transaction_address: Base.encode16(tx_address),
transaction_type: tx_type
)

unless from_self_repair? do
# execute asynchronously the contract
Worker.execute(contract_address, tx)
end

TransactionLookup.add_contract_transaction(
contract_address,
tx_address,
Expand All @@ -112,19 +124,20 @@ defmodule Archethic.Contracts.Loader do
end)
end

def load_transaction(
%Transaction{
address: address,
type: type,
validation_stamp: %ValidationStamp{
recipients: recipients,
timestamp: timestamp,
protocol_version: protocol_version
}
},
true
)
when recipients != [] do
defp do_load_transaction(
%Transaction{
address: address,
type: type,
validation_stamp: %ValidationStamp{
recipients: recipients,
timestamp: timestamp,
protocol_version: protocol_version
}
},
_from_db = true,
false
)
when recipients != [] do
Enum.each(
recipients,
&TransactionLookup.add_contract_transaction(&1, address, timestamp, protocol_version)
Expand All @@ -136,7 +149,7 @@ defmodule Archethic.Contracts.Loader do
)
end

def load_transaction(_tx, _), do: :ok
defp do_load_transaction(_tx, _, _), do: :ok

@doc """
Termine a contract execution
Expand Down
17 changes: 9 additions & 8 deletions lib/archethic/replication.ex
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ defmodule Archethic.Replication do
type: type,
validation_stamp: %ValidationStamp{timestamp: timestamp}
},
download_nodes \\ P2P.authorized_and_available_nodes()
download_nodes \\ P2P.authorized_and_available_nodes(),
self_repair? \\ false
) do
start_time = System.monotonic_time()

Expand All @@ -155,13 +156,13 @@ defmodule Archethic.Replication do
|> Election.chain_storage_nodes(download_nodes)
|> Utils.key_in_node_list?(Crypto.first_node_public_key())

if storage_node?, do: ingest_transaction(tx, false)
if storage_node?, do: ingest_transaction(tx, false, self_repair?)
end)
|> Stream.run()

TransactionChain.write_transaction(tx)

:ok = ingest_transaction(tx, false)
:ok = ingest_transaction(tx, false, self_repair?)

Logger.info("Replication finished",
transaction_address: Base.encode16(address),
Expand Down Expand Up @@ -202,7 +203,7 @@ defmodule Archethic.Replication do
) do
case validate_transaction(tx, self_repair?, download_nodes) do
:ok ->
sync_transaction_chain(tx, download_nodes)
sync_transaction_chain(tx, download_nodes, self_repair?)

{:error, reason} ->
Logger.warning("Invalid transaction for replication - #{inspect(reason)}",
Expand Down Expand Up @@ -247,7 +248,7 @@ defmodule Archethic.Replication do
case TransactionValidator.validate(tx, self_repair?) do
:ok ->
:ok = TransactionChain.write_transaction(tx, :io)
ingest_transaction(tx, true)
ingest_transaction(tx, true, self_repair?)

Logger.info("Replication finished",
transaction_address: Base.encode16(address),
Expand Down Expand Up @@ -564,14 +565,14 @@ defmodule Archethic.Replication do
- Transactions with smart contract deploy instances of them or can put in pending state waiting approval signatures
- Code approval transactions may trigger the TestNets deployments or hot-reloads
"""
@spec ingest_transaction(Transaction.t(), boolean()) :: :ok
def ingest_transaction(tx = %Transaction{}, io_transaction?) do
@spec ingest_transaction(Transaction.t(), boolean(), boolean()) :: :ok
def ingest_transaction(tx = %Transaction{}, io_transaction?, self_repair?) do
TransactionChain.load_transaction(tx)
Crypto.load_transaction(tx)
P2P.load_transaction(tx)
SharedSecrets.load_transaction(tx)
Account.load_transaction(tx, io_transaction?)
Contracts.load_transaction(tx)
Contracts.load_transaction(tx, from_self_repair: self_repair?)
OracleChain.load_transaction(tx)
Reward.load_transaction(tx)
:ok
Expand Down
2 changes: 1 addition & 1 deletion test/archethic/bootstrap_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ defmodule Archethic.BootstrapTest do

validated_tx = %{tx | validation_stamp: stamp}
:ok = TransactionChain.write_transaction(validated_tx)
:ok = Replication.ingest_transaction(validated_tx, false)
:ok = Replication.ingest_transaction(validated_tx, false, false)

{:ok, %Ok{}}

Expand Down

0 comments on commit 083d1a4

Please sign in to comment.