115 lines
3.3 KiB
PHP
115 lines
3.3 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Mod\Explorer\Controllers;
|
||
|
|
|
||
|
|
use Illuminate\Http\JsonResponse;
|
||
|
|
use Illuminate\Routing\Controller;
|
||
|
|
use Mod\Chain\Services\DaemonRpc;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Block explorer API — JSON responses for chain data.
|
||
|
|
*
|
||
|
|
* GET /v1/explorer/info — chain info
|
||
|
|
* GET /v1/explorer/block/{id} — block by height or hash
|
||
|
|
* GET /v1/explorer/tx/{hash} — transaction details
|
||
|
|
* GET /v1/explorer/aliases — all aliases
|
||
|
|
* GET /v1/explorer/alias/{name} — single alias
|
||
|
|
* GET /v1/explorer/search/{q} — search
|
||
|
|
* GET /v1/explorer/stats — chain statistics
|
||
|
|
*/
|
||
|
|
class ExplorerApiController extends Controller
|
||
|
|
{
|
||
|
|
public function __construct(
|
||
|
|
private readonly DaemonRpc $rpc,
|
||
|
|
) {}
|
||
|
|
|
||
|
|
public function info(): JsonResponse
|
||
|
|
{
|
||
|
|
return response()->json($this->rpc->getInfo());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function block(string $id): JsonResponse
|
||
|
|
{
|
||
|
|
$block = is_numeric($id)
|
||
|
|
? $this->rpc->getBlockByHeight((int) $id)
|
||
|
|
: $this->rpc->getBlockByHash($id);
|
||
|
|
|
||
|
|
return response()->json($block);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function transaction(string $hash): JsonResponse
|
||
|
|
{
|
||
|
|
return response()->json($this->rpc->getTransaction($hash));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function aliases(): JsonResponse
|
||
|
|
{
|
||
|
|
$result = $this->rpc->getAllAliases();
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'aliases' => $result['aliases'] ?? [],
|
||
|
|
'count' => count($result['aliases'] ?? []),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function alias(string $name): JsonResponse
|
||
|
|
{
|
||
|
|
$alias = $this->rpc->getAliasByName($name);
|
||
|
|
|
||
|
|
if (! $alias) {
|
||
|
|
return response()->json(['error' => 'Alias not found'], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
return response()->json($alias);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function search(string $query): JsonResponse
|
||
|
|
{
|
||
|
|
if (is_numeric($query)) {
|
||
|
|
return response()->json([
|
||
|
|
'type' => 'block',
|
||
|
|
'data' => $this->rpc->getBlockByHeight((int) $query),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (strlen($query) === 64 && ctype_xdigit($query)) {
|
||
|
|
$block = $this->rpc->getBlockByHash($query);
|
||
|
|
if (! empty($block['block_header'])) {
|
||
|
|
return response()->json(['type' => 'block', 'data' => $block]);
|
||
|
|
}
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'type' => 'transaction',
|
||
|
|
'data' => $this->rpc->getTransaction($query),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
$alias = $this->rpc->getAliasByName($query);
|
||
|
|
if ($alias) {
|
||
|
|
return response()->json(['type' => 'alias', 'data' => $alias]);
|
||
|
|
}
|
||
|
|
|
||
|
|
return response()->json(['error' => 'Not found'], 404);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function stats(): JsonResponse
|
||
|
|
{
|
||
|
|
$info = $this->rpc->getInfo();
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'height' => $info['height'] ?? 0,
|
||
|
|
'difficulty' => [
|
||
|
|
'pow' => $info['pow_difficulty'] ?? 0,
|
||
|
|
'pos' => $info['pos_difficulty'] ?? '0',
|
||
|
|
],
|
||
|
|
'hashrate' => $info['current_network_hashrate_350'] ?? 0,
|
||
|
|
'aliases' => $info['alias_count'] ?? 0,
|
||
|
|
'transactions' => $info['tx_count'] ?? 0,
|
||
|
|
'supply' => ($info['height'] ?? 0) + 10000000, // premine + block rewards
|
||
|
|
'network' => config('chain.network'),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
}
|