Skip to content
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

[wip] feat: add monitor overflow to develop branch #958

Draft
wants to merge 28 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1660e19
initial app changes
alexbarnsley Sep 12, 2024
62bc9af
update resources
alexbarnsley Sep 12, 2024
84ffbad
initial test updates
alexbarnsley Sep 12, 2024
1d99762
style: resolve style guide violations
alexbarnsley Sep 12, 2024
d4f78ab
scrub
alexbarnsley Sep 18, 2024
1224b03
move delegate tracker functionality into separate method
alexbarnsley Sep 18, 2024
c4c564a
adjustments
alexbarnsley Sep 18, 2024
d33bc72
Merge branch 'feat/add-monitor-overflow-to-develop-branch' of github.…
alexbarnsley Sep 18, 2024
5d7cbe7
style: resolve style guide violations
alexbarnsley Sep 18, 2024
b7a676b
test
alexbarnsley Sep 18, 2024
29c9273
Merge branch 'feat/add-monitor-overflow-to-develop-branch' of github.…
alexbarnsley Sep 18, 2024
238c463
wip - debugging
alexbarnsley Sep 19, 2024
13a75be
style: resolve style guide violations
alexbarnsley Sep 19, 2024
563376e
wip
alexbarnsley Sep 30, 2024
870cd7a
fix time to forge
alexbarnsley Sep 30, 2024
a3e8548
style: resolve style guide violations
alexbarnsley Sep 30, 2024
179e079
convert core timestamp to unix
alexbarnsley Sep 30, 2024
64981f3
wip
alexbarnsley Sep 30, 2024
1bdaac6
test wip
alexbarnsley Sep 30, 2024
51982b8
Merge branch 'feat/add-monitor-overflow-to-develop-branch' of github.…
alexbarnsley Sep 30, 2024
a1e60c4
style: resolve style guide violations
alexbarnsley Sep 30, 2024
9ab2445
improvements to frontend
alexbarnsley Oct 1, 2024
a1bc54d
wip - copied tests from mainsail branch
alexbarnsley Oct 1, 2024
1b85111
Merge branch 'feat/add-monitor-overflow-to-develop-branch' of github.…
alexbarnsley Oct 1, 2024
a1b0ae3
style: resolve style guide violations
alexbarnsley Oct 1, 2024
1a5df30
wip
alexbarnsley Oct 2, 2024
483d2bd
Merge branch 'feat/add-monitor-overflow-to-develop-branch' of github.…
alexbarnsley Oct 2, 2024
334050f
style: resolve style guide violations
alexbarnsley Oct 2, 2024
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
57 changes: 56 additions & 1 deletion app/DTO/Slot.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public function __construct(
private array $lastBlock,
private string $status,
private Collection $roundBlockCount,
private int $roundNumber
private int $roundNumber,
private int $secondsUntilForge,
) {
$this->currentRoundBlocks = $this->roundBlockCount
->get($this->publicKey, 0);
Expand All @@ -49,6 +50,11 @@ public function forgingAt(): Carbon
return $this->forgingAt;
}

public function secondsUntilForge(): int
{
return $this->secondsUntilForge;
}

public function lastBlock(): array
{
return $this->lastBlock;
Expand Down Expand Up @@ -96,6 +102,16 @@ public function missedCount(): int
return (new WalletCache())->getMissedBlocks($this->publicKey);
}

/**
* Get how many blocks the forger has forged in the current round.
*
* @return int
*/
public function currentRoundBlocks(): int
{
return $this->currentRoundBlocks;
}

public function isDone(): bool
{
return $this->status === 'done';
Expand Down Expand Up @@ -129,6 +145,45 @@ public function isWaiting(): bool
return false;
}

/**
* Clone the slot with the given overridden properties.
*
* @param string|null $publicKey
* @param int|null $order
* @param WalletViewModel|null $wallet
* @param Carbon|null $forgingAt
* @param array|null $lastBlock
* @param string|null $status
* @param Collection|null $roundBlockCount
* @param int|null $roundNumber
* @param int|null $secondsUntilForge
*
* @return Slot
*/
public function clone(
?string $publicKey = null,
?int $order = null,
?WalletViewModel $wallet = null,
?Carbon $forgingAt = null,
?array $lastBlock = null,
?string $status = null,
?Collection $roundBlockCount = null,
?int $roundNumber = null,
?int $secondsUntilForge = null,
): self {
return new self(
publicKey: $publicKey ?? $this->publicKey,
order: $order ?? $this->order,
wallet: $wallet ?? $this->wallet,
forgingAt: $forgingAt ?? $this->forgingAt,
lastBlock: $lastBlock ?? $this->lastBlock,
status: $status ?? $this->status,
roundBlockCount: $roundBlockCount ?? $this->roundBlockCount,
roundNumber: $roundNumber ?? $this->roundNumber,
secondsUntilForge: $secondsUntilForge ?? $this->secondsUntilForge,
);
}

private function getLastHeight(): int
{
return Arr::get($this->lastBlock, 'height', 0);
Expand Down
87 changes: 66 additions & 21 deletions app/Http/Livewire/Concerns/DelegateData.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,48 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

trait DelegateData
{
private function cacheLastBlocks(array $delegates): void
private function cacheTtl(): int
{
$ttl = (int) ceil(Network::blockTime() / 2);
return (int) ceil(Network::blockTime() / 2);
}

Cache::remember('monitor:last-blocks', $ttl, function () use ($delegates): void {
private function cacheLastBlocks(array $delegates): void
{
Cache::remember('monitor:last-blocks', $this->cacheTtl(), function () use ($delegates): bool {
$blocks = Block::query()
->orderBy('height', 'desc')
->limit(Network::delegateCount() * 2)
->get();

$lastBlockIds = DB::connection('explorer')
->table('wallets')
->whereIn('public_key', $delegates)
->select([
'public_key',
'last_block_id' => function ($query) {
$query->select('id')
->from('blocks')
->whereColumn('generator_public_key', 'public_key')
->orderBy('height', 'desc')
->limit(1);
},
]);

/** @var Collection $lastBlocks */
$lastBlocks = Block::whereIn('id', $lastBlockIds->pluck('last_block_id'))
->get()
->groupBy('generator_public_key');

foreach ($delegates as $delegate) {
$block = $blocks->firstWhere('generator_public_key', $delegate);

// The delegate hasn't forged in some rounds.
if (is_null($block)) {
$block = Block::query()
->where('generator_public_key', $delegate)
->orderBy('height', 'desc')
->limit(1)
if (is_null($block) && $lastBlocks->has($delegate)) {
$block = $lastBlocks->get($delegate)
->first();
}

Expand All @@ -50,32 +70,56 @@ private function cacheLastBlocks(array $delegates): void
(new WalletCache())->setLastBlock($delegate, [
'id' => $block->id,
'height' => $block->height->toNumber(),
'timestamp' => Timestamp::fromGenesis($block->timestamp)->unix(),
'timestamp' => $block->timestamp,
'generator_public_key' => $block->generator_public_key,
]);
}

return true;

// foreach ($delegates as $delegate) {
// $block = $blocks->firstWhere('generator_public_key', $delegate);

// // The delegate hasn't forged in some rounds.
// if (is_null($block)) {
// $block = Block::query()
// ->where('generator_public_key', $delegate)
// ->orderBy('height', 'desc')
// ->limit(1)
// ->first();
// }

// // The delegate has never forged.
// if (is_null($block)) {
// continue;
// }

// (new WalletCache())->setLastBlock($delegate, [
// 'id' => $block->id,
// 'height' => $block->height->toNumber(),
// 'timestamp' => Timestamp::fromGenesis($block->timestamp)->unix(),
// 'generator_public_key' => $block->generator_public_key,
// ]);
// }

// return true;
});
}

private function getBlocksByRange(array $publicKeys, array $heightRange): Collection
{
$key = 'monitor:last-blocks:'.md5(implode(',', $publicKeys)).':'.$heightRange[0].'-'.$heightRange[1];
$ttl = (int) ceil(Network::blockTime() / 2);

return Cache::remember($key, $ttl, function () use ($publicKeys, $heightRange) {
return Block::query()
->whereIn('generator_public_key', $publicKeys)
->whereBetween('height', $heightRange)
->orderBy('height', 'asc')
->get();
});
return Block::query()
->whereIn('generator_public_key', $publicKeys)
->whereBetween('height', $heightRange)
->orderBy('height', 'asc')
->get();
}

private function hasRoundStarted(int $height): bool
{
return Cache::remember(
'delegate:round:'.$height,
Network::blockTime() / 2,
$this->cacheTtl(),
fn () => Block::where('height', $height)->exists()
);
}
Expand Down Expand Up @@ -121,7 +165,8 @@ private function fetchDelegates(): array
lastBlock: (new WalletCache())->getLastBlock($delegate['publicKey']),
status: $delegate['status'],
roundBlockCount: $roundBlockCount,
roundNumber: $roundNumber
roundNumber: $roundNumber,
secondsUntilForge: $delegate['time'],
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,28 @@

declare(strict_types=1);

namespace App\Http\Livewire;
namespace App\Http\Livewire\Delegates\Concerns;

use App\Actions\CacheNetworkHeight;
use App\DTO\Slot;
use App\Enums\DelegateForgingStatus;
use App\Facades\Network;
use App\Http\Livewire\Concerns\DeferLoading;
use App\Http\Livewire\Concerns\DelegateData;
use App\Models\Block;
use App\Models\Wallet;
use App\Services\Cache\MonitorCache;
use App\Services\Cache\WalletCache;
use App\Services\Monitor\Monitor;
use App\ViewModels\ViewModelFactory;
use App\ViewModels\WalletViewModel;
use Illuminate\View\View;
use Livewire\Component;

final class DelegateDataBoxes extends Component
trait HandlesMonitorDataBoxes
{
use DeferLoading;
use DelegateData;

/** @var mixed */
protected $listeners = [
'echo:blocks,NewBlock' => 'pollStatistics',
];

private array $delegates = [];

private array $statistics = [];

public function render(): View
{
$this->delegates = $this->fetchDelegates();

return view('livewire.delegate-data-boxes', [
'height' => CacheNetworkHeight::execute(),
'statistics' => $this->statistics,
]);
}

public function componentIsReady(): void
{
$this->setIsReady();

$this->pollStatistics();
$this->pollData();
}

public function pollStatistics(): void
Expand Down Expand Up @@ -111,9 +86,12 @@ public function getBlockCount(): string

public function getNextDelegate(): ? WalletViewModel
{
$this->delegates = $this->fetchDelegates();
$delegates = [
...$this->delegates,
...$this->overflowDelegates,
];

return (new MonitorCache())->setNextDelegate(fn () => optional($this->getSlotsByStatus($this->delegates, 'pending'))->wallet());
return (new MonitorCache())->setNextDelegate(fn () => optional($this->getSlotsByStatus($delegates, 'pending'))->wallet());
}

private function getSlotsByStatus(array $slots, string $status): ?Slot
Expand Down
Loading
Loading