diff --git a/apps/arweave/src/ar_block_cache.erl b/apps/arweave/src/ar_block_cache.erl index 8c9cefe64..17034498c 100644 --- a/apps/arweave/src/ar_block_cache.erl +++ b/apps/arweave/src/ar_block_cache.erl @@ -7,7 +7,8 @@ mark_tip/2, get/2, get_earliest_not_validated_from_longest_chain/1, get_longest_chain_cache/1, get_block_and_status/2, remove/2, get_checkpoint_block/1, prune/2, - get_by_solution_hash/5, is_known_solution_hash/2]). + get_by_solution_hash/5, is_known_solution_hash/2, + get_siblings/2, get_fork_blocks/2]). -include_lib("arweave/include/ar.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -21,10 +22,6 @@ %% validated: block is validated but does not belong to the tip fork %% not_validated: block is not validated yet %% none: null status --type validation_status() :: on_chain | validated | not_validated | none. --type nonce_limiter_validation_status() :: nonce_limiter_validated | - awaiting_nonce_limiter_validation. --type block_status() :: validation_status() | {not_validated, nonce_limiter_validation_status()}. %% @doc ETS table: block_cache %% {block, BlockHash} => {#block{}, block_status(), Timestamp, set(Children)} @@ -306,8 +303,8 @@ get_block_and_status(Tab, H) -> case ets:lookup(Tab, {block, H}) of [] -> not_found; - [{_, {B, Status, _Timestamp, _Children}}] -> - {B, Status} + [{_, {B, Status, Timestamp, _Children}}] -> + {B, {Status, Timestamp}} end. %% @doc Mark the given block as the tip block. Mark the previous blocks as on-chain. @@ -432,6 +429,33 @@ get_by_solution_hash(Tab, SolutionH, H, CDiff, PrevCDiff, [H2 | L], _B) -> get_by_solution_hash(Tab, SolutionH, H, CDiff, PrevCDiff, L, B2) end. +%% @doc Return the list of siblings of the given block, if any. +get_siblings(Tab, B) -> + H = B#block.indep_hash, + PrevH = B#block.previous_block, + case ets:lookup(Tab, {block, PrevH}) of + [] -> + []; + [{_, {_B, _Status, _CurrentTimestamp, Children}}] -> + sets:fold( + fun(SibH, Acc) -> + case SibH of + H -> + Acc; + _ -> + case ets:lookup(Tab, {block, SibH}) of + [] -> + Acc; + [{_, {Sib, _, _, _}}] -> + [Sib | Acc] + end + end + end, + [], + Children + ) + end. + %%%=================================================================== %%% Private functions. %%%=================================================================== @@ -1013,6 +1037,7 @@ block_cache_test() -> assert_tip(block_id(B1)), assert_max_cdiff({0, block_id(B1)}), assert_is_valid_fork(true, on_chain, B1), + ?assertEqual([], get_siblings(bcache_test, B1)), %% Re-adding B1 shouldn't change anything - i.e. nothing should be updated because the %% block is already on chain @@ -1056,6 +1081,7 @@ block_cache_test() -> assert_max_cdiff({1, block_id(B2)}), assert_is_valid_fork(true, on_chain, B1), assert_is_valid_fork(true, not_validated, B2), + ?assertEqual([], get_siblings(bcache_test, B2)), %% Add a TXID to B2, but still don't mark as validated %% @@ -1113,6 +1139,8 @@ block_cache_test() -> assert_is_valid_fork(true, on_chain, B1), assert_is_valid_fork(true, not_validated, B2), assert_is_valid_fork(true, not_validated, B1_2), + ?assertEqual([B2], get_siblings(bcache_test, B1_2)), + ?assertEqual([B1_2], get_siblings(bcache_test, B2)), %% Even though B2 is marked as a tip, it is still lower difficulty than B1_2 so will %% not be included in the longest chain @@ -1243,7 +1271,8 @@ block_cache_test() -> %% \ / %% 0 B1/on_chain add_validated(bcache_test, B2_2), - ?assertEqual({B2_2, validated}, get_block_and_status(bcache_test, B2_2#block.indep_hash)), + ?assertMatch({B2_2, {validated, _}}, + get_block_and_status(bcache_test, B2_2#block.indep_hash)), ?assertMatch({B2_3, [B2_2, B2], {{not_validated, ExpectedStatus}, _}}, get_earliest_not_validated_from_longest_chain(bcache_test)), assert_longest_chain([B2_2, B2, B1], 1), @@ -1281,6 +1310,9 @@ block_cache_test() -> assert_is_valid_fork(true, validated, B2_2), assert_is_valid_fork(true, not_validated, B2_3), assert_is_valid_fork(true, on_chain, B3), + ?assertEqual([B2_2], get_siblings(bcache_test, B3)), + ?assertEqual([B3], get_siblings(bcache_test, B2_2)), + ?assertEqual([B2], get_siblings(bcache_test, B1_2)), %% B3->B2->B1 fork is still heaviest %% @@ -1346,6 +1378,8 @@ block_cache_test() -> assert_is_valid_fork(true, not_validated, B2_3), assert_is_valid_fork(true, validated, B3), assert_is_valid_fork(true, not_validated, B4), + ?assertEqual([], get_siblings(bcache_test, B2_3)), + ?assertEqual([], get_siblings(bcache_test, B4)), %% Height Block/Status %% @@ -1494,8 +1528,9 @@ block_cache_test() -> %% 0 B11/on_chain mark_nonce_limiter_validated(bcache_test, crypto:strong_rand_bytes(48)), mark_nonce_limiter_validated(bcache_test, block_id(B13)), - ?assertEqual({B13, on_chain}, get_block_and_status(bcache_test, block_id(B13))), - ?assertMatch({B14, {not_validated, awaiting_nonce_limiter_validation}}, + ?assertMatch({B13, {on_chain, _}}, + get_block_and_status(bcache_test, block_id(B13))), + ?assertMatch({B14, {{not_validated, awaiting_nonce_limiter_validation}, _}}, get_block_and_status(bcache_test, block_id(B14))), assert_longest_chain([B13, B11], 0), assert_tip(block_id(B13)), @@ -1512,7 +1547,7 @@ block_cache_test() -> %% 1 B12/not_validated B13/on_chain %% \ / %% 0 B11/on_chain - ?assertMatch({B14, {not_validated, awaiting_nonce_limiter_validation}}, + ?assertMatch({B14, {{not_validated, awaiting_nonce_limiter_validation}, _}}, get_block_and_status(bcache_test, block_id(B14))), ?assertMatch({B14, [B13], {{not_validated, awaiting_nonce_limiter_validation}, _}}, get_earliest_not_validated_from_longest_chain(bcache_test)), @@ -1532,7 +1567,7 @@ block_cache_test() -> %% \ / %% 0 B11/on_chain mark_nonce_limiter_validated(bcache_test, block_id(B14)), - ?assertMatch({B14, {not_validated, nonce_limiter_validated}}, + ?assertMatch({B14, {{not_validated, nonce_limiter_validated}, _}}, get_block_and_status(bcache_test, block_id(B14))), ?assertMatch({B14, [B13], {{not_validated, nonce_limiter_validated}, _}}, get_earliest_not_validated_from_longest_chain(bcache_test)), @@ -1578,7 +1613,7 @@ block_cache_test() -> add_validated(bcache_test, B14), ?assertMatch({B15, [B14, B13], {{not_validated, awaiting_nonce_limiter_validation}, _}}, get_earliest_not_validated_from_longest_chain(bcache_test)), - ?assertMatch({B14, validated}, get_block_and_status(bcache_test, block_id(B14))), + ?assertMatch({B14, {validated, _}}, get_block_and_status(bcache_test, block_id(B14))), assert_longest_chain([B14, B13, B11], 1), assert_tip(block_id(B13)), assert_max_cdiff({3, block_id(B15)}), @@ -1626,7 +1661,7 @@ block_cache_test() -> mark_nonce_limiter_validated(bcache_test, block_id(B16)), ?assertMatch({B15, [B14, B13], {{not_validated, awaiting_nonce_limiter_validation}, _}}, get_earliest_not_validated_from_longest_chain(bcache_test)), - ?assertMatch({B16, {not_validated, nonce_limiter_validated}}, + ?assertMatch({B16, {{not_validated, nonce_limiter_validated}, _}}, get_block_and_status(bcache_test, block_id(B16))), assert_longest_chain([B14, B13, B11], 1), assert_tip(block_id(B13)), @@ -1650,7 +1685,7 @@ block_cache_test() -> %% \ / %% 0 B11/on_chain mark_tip(bcache_test, block_id(B14)), - ?assertEqual({B14, on_chain}, get_block_and_status(bcache_test, block_id(B14))), + ?assertMatch({B14, {on_chain, _}}, get_block_and_status(bcache_test, block_id(B14))), ?assertMatch({B15, [B14], {{not_validated, awaiting_nonce_limiter_validation}, _}}, get_earliest_not_validated_from_longest_chain(bcache_test)), assert_longest_chain([B14, B13, B11], 0), diff --git a/apps/arweave/src/ar_http_iface_middleware.erl b/apps/arweave/src/ar_http_iface_middleware.erl index b9bbf3d31..1200ae116 100644 --- a/apps/arweave/src/ar_http_iface_middleware.erl +++ b/apps/arweave/src/ar_http_iface_middleware.erl @@ -836,7 +836,7 @@ handle(<<"GET">>, [<<"reward_history">>, EncodedBH], Req, _Pid) -> {ok, BH} -> Fork_2_6 = ar_fork:height_2_6(), case ar_block_cache:get_block_and_status(block_cache, BH) of - {#block{ height = Height, reward_history = RewardHistory }, Status} + {#block{ height = Height, reward_history = RewardHistory }, {Status, _}} when (Status == on_chain orelse Status == validated), Height >= Fork_2_6 -> {200, #{}, ar_serialize:reward_history_to_binary(RewardHistory), @@ -859,7 +859,7 @@ handle(<<"GET">>, [<<"block_time_history">>, EncodedBH], Req, _Pid) -> Fork_2_7 = ar_fork:height_2_7(), case ar_block_cache:get_block_and_status(block_cache, BH) of {#block{ height = Height, - block_time_history = BlockTimeHistory }, Status} + block_time_history = BlockTimeHistory }, {Status, _}} when (Status == on_chain orelse Status == validated), Height >= Fork_2_7 -> {200, #{}, ar_serialize:block_time_history_to_binary( diff --git a/apps/arweave/src/ar_node.erl b/apps/arweave/src/ar_node.erl index 12340dd44..e88cc1337 100644 --- a/apps/arweave/src/ar_node.erl +++ b/apps/arweave/src/ar_node.erl @@ -241,7 +241,7 @@ get_partition_upper_bound(BI) -> get_recent_partition_upper_bound_by_prev_h(H, Diff) -> case ar_block_cache:get_block_and_status(block_cache, H) of - {_B, on_chain} -> + {_B, {on_chain, _}} -> [{_, BI}] = ets:lookup(node_state, recent_block_index), Genesis = length(BI) =< ?SEARCH_SPACE_UPPER_BOUND_DEPTH, get_recent_partition_upper_bound_by_prev_h(H, Diff, BI, Genesis); diff --git a/apps/arweave/src/ar_node_worker.erl b/apps/arweave/src/ar_node_worker.erl index 27e6f00a2..3fc3726a3 100644 --- a/apps/arweave/src/ar_node_worker.erl +++ b/apps/arweave/src/ar_node_worker.erl @@ -165,7 +165,9 @@ init([]) -> tags => [], blocks_missing_txs => sets:new(), missing_txs_lookup_processes => #{}, - task_queue => gb_sets:new() + task_queue => gb_sets:new(), + solution_cache => #{}, + solution_cache_records => queue:new() }}. get_block_index_at_state(BI, Config) -> @@ -467,7 +469,9 @@ handle_info({event, miner, {found_solution, miner, _Solution, _PoACache, _PoA2Ca #{ automine := false, miner_2_6 := undefined } = State) -> {noreply, State}; handle_info({event, miner, {found_solution, Source, Solution, PoACache, PoA2Cache}}, State) -> - handle_found_solution({Source, Solution, PoACache, PoA2Cache}, State); + [{_, PrevH}] = ets:lookup(node_state, current), + PrevB = ar_block_cache:get(block_cache, PrevH), + handle_found_solution({Source, Solution, PoACache, PoA2Cache}, PrevB, State); handle_info({event, miner, _}, State) -> {noreply, State}; @@ -631,7 +635,7 @@ handle_task({cache_missing_txs, BH, TXs}, State) -> not_found -> %% The block should have been pruned while we were fetching the missing txs. {noreply, State}; - {B, {not_validated, _}} -> + {B, {{not_validated, _}, _}} -> case ar_block_cache:get(block_cache, B#block.previous_block) of not_found -> ok; @@ -753,25 +757,108 @@ get_max_block_size([{_BH, PrevWeaveSize, _TXRoot} | BI], WeaveSize, Max) -> apply_block(State) -> case ar_block_cache:get_earliest_not_validated_from_longest_chain(block_cache) of not_found -> - %% Nothing to do - we are at the longest known chain already. + maybe_rebase(State); + Args -> + %% Cancel the pending rebase, if there is one. + State2 = State#{ pending_rebase => false }, + apply_block(Args, State2) + end. + +apply_block({B, [PrevB | _PrevBlocks], {{not_validated, awaiting_nonce_limiter_validation}, + _Timestamp}}, State) -> + H = B#block.indep_hash, + case maps:get({nonce_limiter_validation_scheduled, H}, State, false) of + true -> + %% Waiting until the nonce limiter chain is validated. + {noreply, State}; + false -> + ?LOG_DEBUG([{event, schedule_nonce_limiter_validation}, + {block, ar_util:encode(B#block.indep_hash)}]), + request_nonce_limiter_validation(B, PrevB), + {noreply, State#{ {nonce_limiter_validation_scheduled, H} => true }} + end; +apply_block({B, PrevBlocks, {{not_validated, nonce_limiter_validated}, Timestamp}}, State) -> + apply_block(B, PrevBlocks, Timestamp, State). + +maybe_rebase(#{ pending_rebase := {PrevH, H} } = State) -> + case ar_block_cache:get_block_and_status(block_cache, PrevH) of + not_found -> {noreply, State}; - {B, [PrevB | _PrevBlocks], {{not_validated, awaiting_nonce_limiter_validation}, - _Timestamp}} -> - H = B#block.indep_hash, - case maps:get({nonce_limiter_validation_scheduled, H}, State, false) of - true -> - %% Waiting until the nonce limiter chain is validated. + {PrevB, {validated, _}} -> + case get_cached_solution(H, State) of + not_found -> + ?LOG_WARNING([{event, failed_to_find_cached_solution_for_rebasing}, + {h, ar_util:encode(H)}, + {prev_h, ar_util:encode(PrevH)}]), {noreply, State}; - false -> - ?LOG_DEBUG([{event, schedule_nonce_limiter_validation}, - {block, ar_util:encode(B#block.indep_hash)}]), - request_nonce_limiter_validation(B, PrevB), - {noreply, State#{ {nonce_limiter_validation_scheduled, H} => true }} + Args -> + SolutionH = (element(2, Args))#mining_solution.solution_hash, + ?LOG_INFO([{event, rebasing_block}, + {h, ar_util:encode(H)}, + {prev_h, ar_util:encode(PrevH)}, + {solution_h, ar_util:encode(SolutionH)}, + {expected_new_height, PrevB#block.height + 1}]), + handle_found_solution(Args, PrevB, State) + end; + {B, {Status, Timestamp}} -> + PrevBlocks = ar_block_cache:get_fork_blocks(block_cache, B), + Args = {B, PrevBlocks, {Status, Timestamp}}, + apply_block(Args, State) + end; +maybe_rebase(State) -> + [{_, H}] = ets:lookup(node_state, current), + B = ar_block_cache:get(block_cache, H), + {ok, Config} = application:get_env(arweave, config), + case B#block.reward_addr == Config#config.mining_addr of + false -> + {noreply, State}; + true -> + case ar_block_cache:get_siblings(block_cache, B) of + [] -> + {noreply, State}; + Siblings -> + maybe_rebase(B, Siblings, State) + end + end. + +maybe_rebase(_B, [], State) -> + {noreply, State}; +maybe_rebase(B, [Sib | Siblings], State) -> + #block{ nonce_limiter_info = Info, cumulative_diff = CDiff } = B, + #block{ nonce_limiter_info = SibInfo, cumulative_diff = SibCDiff } = Sib, + StepNumber = Info#nonce_limiter_info.global_step_number, + SibStepNumber = SibInfo#nonce_limiter_info.global_step_number, + case {CDiff == SibCDiff, StepNumber > SibStepNumber, + Sib#block.reward_addr == B#block.reward_addr} of + {true, true, false} -> + %% See if the solution is cached to avoid wasting time. + case get_cached_solution(B#block.indep_hash, State) of + not_found -> + maybe_rebase(B, Siblings, State); + _Args -> + rebase(B, Sib, State) end; - {B, PrevBlocks, {{not_validated, nonce_limiter_validated}, Timestamp}} -> - apply_block(B, PrevBlocks, Timestamp, State) + _ -> + maybe_rebase(B, Siblings, State) + end. + +rebase(B, PrevB, State) -> + H = B#block.indep_hash, + PrevH = PrevB#block.indep_hash, + gen_server:cast(?MODULE, apply_block), + PrevBlocks = ar_block_cache:get_fork_blocks(block_cache, PrevB), + {_, {Status, Timestamp}} = ar_block_cache:get_block_and_status(block_cache, PrevH), + State2 = State#{ pending_rebase => {PrevH, H} }, + case Status of + validated -> + {noreply, State2}; + _ -> + apply_block({PrevB, PrevBlocks, {Status, Timestamp}}, State2) end. +get_cached_solution(H, State) -> + maps:get(H, maps:get(solution_cache, State), not_found). + apply_block(B, PrevBlocks, Timestamp, State) -> #{ blocks_missing_txs := BlocksMissingTXs } = State, case sets:is_element(B#block.indep_hash, BlocksMissingTXs) of @@ -964,8 +1051,11 @@ pack_block_with_transactions(B, PrevB) -> [ar_wallet:to_address({?DEFAULT_KEY_TYPE, element(1, Proof)}) | Addresses2] end, Accounts = ar_wallets:get(PrevB#block.wallet_list, Addresses3), - [{_, BlockAnchors}] = ets:lookup(node_state, block_anchors), - [{_, RecentTXMap}] = ets:lookup(node_state, recent_txs_map), + [{block_txs_pairs, BlockTXPairs}] = ets:lookup(node_state, block_txs_pairs), + PrevBlocks = ar_block_cache:get_fork_blocks(block_cache, B), + BlockTXPairs2 = update_block_txs_pairs(B, PrevBlocks, BlockTXPairs), + BlockTXPairs3 = tl(BlockTXPairs2), + {BlockAnchors, RecentTXMap} = get_block_anchors_and_recent_txs_map(BlockTXPairs3), ValidTXs = ar_tx_replay_pool:pick_txs_to_mine({BlockAnchors, RecentTXMap, Height - 1, RedenominationHeight, Rate, PricePerGiBMinute, KryderPlusRateMultiplier, PrevDenomination, B#block.timestamp, Accounts, TXs}), @@ -1651,7 +1741,7 @@ dump_mempool(TXs, MempoolSize) -> ?LOG_ERROR([{event, failed_to_dump_mempool}, {reason, Reason}]) end. -handle_found_solution(Args, State) -> +handle_found_solution(Args, PrevB, State) -> {Source, Solution, PoACache, PoA2Cache} = Args, #mining_solution{ last_step_checkpoints = LastStepCheckpoints, @@ -1673,8 +1763,9 @@ handle_found_solution(Args, State) -> } = Solution, MerkleRebaseThreshold = ?MERKLE_REBASE_SUPPORT_THRESHOLD, - [{_, PrevH}] = ets:lookup(node_state, current), - [{_, PrevTimestamp}] = ets:lookup(node_state, timestamp), + #block{ indep_hash = PrevH, timestamp = PrevTimestamp, + wallet_list = WalletList, + nonce_limiter_info = PrevNonceLimiterInfo } = PrevB, Now = os:system_time(second), MaxDeviation = ar_block:get_max_timestamp_deviation(), Timestamp = @@ -1690,15 +1781,13 @@ handle_found_solution(Args, State) -> Now end, - [{wallet_list, WalletList}] = ets:lookup(node_state, wallet_list), IsBanned = ar_node_utils:is_account_banned(MiningAddress, ar_wallets:get(WalletList, MiningAddress)), %% Check the solution is ahead of the previous solution on the timeline. - [{_, TipNonceLimiterInfo}] = ets:lookup(node_state, nonce_limiter_info), NonceLimiterInfo = #nonce_limiter_info{ global_step_number = StepNumber, output = NonceLimiterOutput, - prev_output = TipNonceLimiterInfo#nonce_limiter_info.output }, + prev_output = PrevNonceLimiterInfo#nonce_limiter_info.output }, PassesTimelineCheck = case IsBanned of true -> @@ -1707,7 +1796,7 @@ handle_found_solution(Args, State) -> {false, address_banned}; false -> case ar_nonce_limiter:is_ahead_on_the_timeline(NonceLimiterInfo, - TipNonceLimiterInfo) of + PrevNonceLimiterInfo) of false -> ar_events:send(solution, {stale, #{ source => Source }}), {false, timeline}; @@ -1719,7 +1808,7 @@ handle_found_solution(Args, State) -> %% Check solution seed. #nonce_limiter_info{ next_seed = PrevNextSeed, next_vdf_difficulty = PrevNextVDFDifficulty, - global_step_number = PrevStepNumber } = TipNonceLimiterInfo, + global_step_number = PrevStepNumber } = PrevNonceLimiterInfo, PrevIntervalNumber = PrevStepNumber div ?NONCE_LIMITER_RESET_FREQUENCY, PassesSeedCheck = case PassesTimelineCheck of @@ -1737,7 +1826,11 @@ handle_found_solution(Args, State) -> end, %% Check solution difficulty - DiffPair = {_PoA1Diff, Diff} = get_current_diff(Timestamp), + PrevDiffPair = ar_difficulty:diff_pair(PrevB), + LastRetarget = PrevB#block.last_retarget, + PrevTS = PrevB#block.timestamp, + DiffPair = {_PoA1Diff, Diff} = ar_retarget:maybe_retarget(PrevB#block.height + 1, + PrevDiffPair, Timestamp, LastRetarget, PrevTS), PassesDiffCheck = case PassesSeedCheck of {false, Reason2} -> @@ -1776,7 +1869,6 @@ handle_found_solution(Args, State) -> end end, - PrevB = ar_block_cache:get(block_cache, PrevH), CorrectRebaseThreshold = case PassesKeyCheck of {false, Reason4} -> @@ -1831,7 +1923,7 @@ handle_found_solution(Args, State) -> [_, PrevStepOutput | _] -> PrevStepOutput; _ -> - TipNonceLimiterInfo#nonce_limiter_info.output + PrevNonceLimiterInfo#nonce_limiter_info.output end, PrevOutput2 = ar_nonce_limiter:maybe_add_entropy( PrevOutput, PrevStepNumber, StepNumber, PrevNextSeed), @@ -1930,7 +2022,7 @@ handle_found_solution(Args, State) -> end}]), ar_block_cache:add(block_cache, B), ar_events:send(solution, {accepted, #{ indep_hash => H, source => Source }}), - apply_block(State); + apply_block(update_solution_cache(H, Args, State)); _Steps -> ar_events:send(solution, {rejected, #{ reason => bad_vdf, source => Source }}), @@ -1942,3 +2034,27 @@ handle_found_solution(Args, State) -> {output, ar_util:encode(NonceLimiterOutput)}]), {noreply, State} end. + +update_solution_cache(H, Args, State) -> + %% Maintain a cache of mining solutions for potential reuse in rebasing. + %% + %% - We only want to cache 5 solutions at max. + %% - If we exceed 5, we remove the oldest one from the solution_cache. + %% - solution_cache_records is only used to track which solution is oldest. + #{ solution_cache := Map, solution_cache_records := Q } = State, + case maps:is_key(H, Map) of + true -> + State; + false -> + Q2 = queue:in(H, Q), + Map2 = maps:put(H, Args, Map), + {Map3, Q3} = + case queue:len(Q2) > 5 of + true -> + {{value, H2}, Q4} = queue:out(Q2), + {maps:remove(H2, Map2), Q4}; + false -> + {Map2, Q2} + end, + State#{ solution_cache => Map3, solution_cache_records => Q3 } + end. diff --git a/apps/arweave/src/ar_watchdog.erl b/apps/arweave/src/ar_watchdog.erl index ee7d2a609..1c74c489c 100644 --- a/apps/arweave/src/ar_watchdog.erl +++ b/apps/arweave/src/ar_watchdog.erl @@ -35,7 +35,7 @@ mined_block(BH, Height, PrevH) -> gen_server:cast(?MODULE, {mined_block, BH, Height, PrevH}). is_mined_block(Block) -> - gen_server:call(?MODULE, {is_mined_block, Block#block.indep_hash}). + gen_server:call(?MODULE, {is_mined_block, Block#block.indep_hash}, infinity). %%-------------------------------------------------------------------- %% @doc diff --git a/apps/arweave/test/ar_coordinated_mining_tests.erl b/apps/arweave/test/ar_coordinated_mining_tests.erl index 49fa56985..387fd57c0 100644 --- a/apps/arweave/test/ar_coordinated_mining_tests.erl +++ b/apps/arweave/test/ar_coordinated_mining_tests.erl @@ -61,7 +61,9 @@ test_single_node_two_chunk_coordinated_mining() -> test_coordinated_mining_retarget() -> %% Assert that a difficulty retarget is handled correctly. - [Node1, Node2, _ExitNode, ValidatorNode] = ar_test_node:start_coordinated(2), + [Node1, Node2, ExitNode, ValidatorNode] = ar_test_node:start_coordinated(2), + ?debugFmt("~nnode1: ~p~nnode2: ~p~nexit node: ~p~nvalidator: ~p~n", + [Node1, Node2, ExitNode, ValidatorNode]), lists:foreach( fun(Height) -> mine_in_parallel([Node1, Node2], ValidatorNode, Height)