8000 Add comments to aec_block_generator by richcarl · Pull Request #4529 · aeternity/aeternity · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add comments to aec_block_generator #4529

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

Merged
merged 1 commit into from
Jan 21, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 48 additions & 7 deletions apps/aecore/src/aec_block_generator.erl
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
%%%=============================================================================
%%% @copyright 2018, Aeternity Anstalt
%%% @doc
%%% Module that handle candidate block generation.
%%% Server for collecting transactions into microblocks
%%% @end
%%%=============================================================================
-module(aec_block_generator).

%% The server builds one microbolock at a time, starting with transactions
%% already in the transaction pool. It also subscribes to events about new
%% transactions, adding them to the current microblock as they arrive,
%% avoiding having to query the pool again.
%%
%% When the chain top changes, the current microblock candidate is
%% discarded and a new candidate microblock is started.
%%
%% When a candidate is ready, this fact is published as a `candidate_block`
%% event, and the `get_candidate()` API function can be used to fetch the
%% current candidate (see the `aec_conductor` module). There is however no
%% guarantee that the candidate has not been discarded in the meantime.
%%
%% A single worker process is used for doing the heavy work in the
%% background, for better responsiveness.

%% API
-export([start_link/0, stop/0]).

Expand Down Expand Up @@ -91,13 +107,13 @@ handle_cast(start_generation, State) ->
{noreply, do_start_generation(State)};
handle_cast({worker_done, Pid, {candidate, Candidate, CandidateState}},
State = #state{ worker = {Pid, _} }) ->
%% Only publish non-empty micro-blocks
%% Only publish non-empty microblocks
case aec_blocks:txs(Candidate) of
[] ->
lager:debug("New empty microblock candidate generated, and discarded", []),
lager:debug("Empty microblock candidate prepared", []),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discarded was the important bit here, I don't like it being removed from the message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to find a wording that made sense. It's not discarded, just not published, and stays in the state ready to be filled when there are incoming tx events. Any better suggestion?

ok;
_ ->
epoch_mining:info("New microblock candidate generated", []),
epoch_mining:info("New microblock candidate ready", []),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not an improvement?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it's getting published as being ready to fetch. Tried to make it contrast with the alternative message above

publish_candidate(Candidate)
end,
State1 = finish_worker(State),
Expand Down Expand Up @@ -149,6 +165,7 @@ code_change(_OldVsn, State, _Extra) ->

%% -- Local functions --------------------------------------------------------

%% When server is told to start generation
do_start_generation(S = #state{ generating = false }) ->
S1 = start_worker(S),
S1#state{ generating = true };
Expand All @@ -158,25 +175,30 @@ do_start_generation(S = #state{ candidate = Candidate }) ->
|| Candidate /= undefined andalso aec_blocks:txs(Candidate) /= [] ],
S.

%% When server is told to stop generation
do_stop_generation(S = #state{ generating = true }) ->
S1 = stop_worker(S),
S1#state{ generating = false };
do_stop_generation(S) ->
S.

%% When a new transaction arrives, either cache it until the current worker
%% has finished, or start a new worker to add it right away.
add_new_tx(S = #state{ worker = Worker }, Tx) ->
case Worker of
undefined -> start_worker_txs(S, [Tx]);
{_WPid, _WRef} -> S#state{ new_txs = [Tx | S#state.new_txs] }
end.

%% Terminate current worker and start a new one
%% (used when the top has changed)
preempt_generation(S, #{ block_hash := NewTop }) ->
S1 = stop_worker(S),
start_worker_block(S1, NewTop).

stop_worker(S = #state{ worker = {WPid, WRef} }) ->
erlang:demonitor(WRef, [flush]),
erlang:exit(WPid, finished),
erlang:exit(WPid, finished), % kill worker process
lager:debug("stopped worker ~p", [WPid]),
S#state{ worker = undefined };
stop_worker(S) ->
Expand All @@ -190,34 +212,50 @@ worker_failed(Reason, S) ->
S1 = finish_worker(S),
start_worker(S1).

%% Update server side bookkeeping when worker is already terminated
finish_worker(S = #state{ worker = {_WPid, WRef} }) ->
erlang:demonitor(WRef, [flush]),
S#state{ worker = undefined }.

%% Creates a fresh microblock candidate on the current top block (used when
%% generation goes from stopped to started)
start_worker(S) ->
case aec_chain:top_block() of
undefined -> S;
Block -> start_worker_block(S, Block)
end.

%% Creates a fresh microblock candidate by querying the transaction pool.
%% Used when the top has changed; there must be no current worker running.
%% Discards and clears the new_tx cache and sets the current candidate to
%% `undefined` so any previously existing candidate can no longer be
%% fetched.
start_worker_block(S = #state{ worker = undefined }, BlockOrBlockHash) ->
{Pid, Ref} = spawn_monitor(fun() -> create_block_candidate(BlockOrBlockHash) end),
lager:debug("Worker ~p created", [Pid]),
S#state{ worker = {Pid, Ref}, new_txs = [], candidate = undefined }.

%% Starts a worker to add transactions from the new_tx cache to the current
%% candidate and clear the new_tx cache. There must be no current worker
%% running. The worker will get the current candidate microblock, returning
%% the updated candidate when done.
start_worker_txs(S = #state{ worker = undefined, candidate = Candidate
, candidate_state = CState }, Txs) ->
, candidate_state = CState }, Txs)
when Candidate =/= undefined ->
{Pid, Ref} = spawn_monitor(fun() -> update_block_candidate(Candidate, CState, Txs) end),
lager:debug("Worker ~p created", [Pid]),
S#state{ worker = {Pid, Ref}, new_txs = [] }.

%% Used when the worker has finished but we may have cached transactions
%% and if so start a new worker to handle them
maybe_start_worker_txs(S) ->
case S#state.new_txs of
[] -> S;
Txs -> start_worker_txs(S, Txs)
end.

%% Generate block candidate
%% Worker: generate a fresh microblock candidate, taking transactions
%% from the transaction pool
create_block_candidate(BlockOrBlockHash) ->
case aec_block_micro_candidate:create(BlockOrBlockHash) of
{ok, NewBlock, NewBlockInfo} ->
Expand All @@ -227,6 +265,7 @@ create_block_candidate(BlockOrBlockHash) ->
end,
ok.

%% Worker: take a microblock candidate and update it, adding transactions
update_block_candidate(Block, BlockInfo, Txs) ->
case aec_block_micro_candidate:update(Block, Txs, BlockInfo) of
{ok, NewBlock, NewBlockInfo} ->
Expand All @@ -235,9 +274,11 @@ update_block_candidate(Block, BlockInfo, Txs) ->
failed_attempt(Reason)
end.

%% Report error and terminate worker
failed_attempt(Reason) ->
gen_server:cast(?MODULE, {worker_done, self(), {failed, Reason}}).

%% Report new candidate microblock and terminate worker
new_candidate(NewBlock, NewBlockInfo) ->
gen_server:cast(?MODULE, {worker_done, self(), {candidate, NewBlock, NewBlockInfo}}).

Expand Down
0