feat: add transaction hash search to blockchain explorer and cleanup settlement storage

Blockchain Explorer:
- Add transaction hash search support (64-char hex pattern validation)
- Fetch and display transaction details in modal (hash, type, from/to, amount, fee, block)
- Fix regex escape sequence in block height validation
- Update search placeholder text to mention both search types
- Add blank lines between function definitions for PEP 8 compliance

Settlement Storage:
- Add timedelta import for future
This commit is contained in:
oib
2026-02-17 14:34:12 +01:00
parent 31d3d70836
commit 421191ccaf
34 changed files with 2176 additions and 5660 deletions

View File

@@ -299,13 +299,67 @@ HTML_TEMPLATE = """
if (!query) return;
// Try block height first
if (/^\\d+$/.test(query)) {
if (/^\d+$/.test(query)) {
showBlockDetails(parseInt(query));
return;
}
// TODO: Add transaction hash search
alert('Search by block height is currently supported');
// Try transaction hash search (hex string, 64 chars)
if (/^[a-fA-F0-9]{64}$/.test(query)) {
try {
const tx = await fetch(`/api/transactions/${query}`).then(r => {
if (!r.ok) throw new Error('Transaction not found');
return r.json();
});
// Show transaction details - reuse block modal
const modal = document.getElementById('block-modal');
const details = document.getElementById('block-details');
details.innerHTML = `
<div class="space-y-6">
<div>
<h3 class="text-lg font-semibold mb-2">Transaction</h3>
<div class="bg-gray-50 rounded p-4 space-y-2">
<div class="flex justify-between">
<span class="text-gray-600">Hash:</span>
<span class="font-mono text-sm">${tx.hash || '-'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Type:</span>
<span>${tx.type || '-'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">From:</span>
<span class="font-mono text-sm">${tx.from || '-'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">To:</span>
<span class="font-mono text-sm">${tx.to || '-'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Amount:</span>
<span>${tx.amount || '0'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Fee:</span>
<span>${tx.fee || '0'}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Block:</span>
<span>${tx.block_height || '-'}</span>
</div>
</div>
</div>
</div>
`;
modal.classList.remove('hidden');
return;
} catch (e) {
alert('Transaction not found');
return;
}
}
alert('Search by block height or transaction hash (64 char hex) is supported');
}
// Format timestamp
@@ -321,6 +375,7 @@ HTML_TEMPLATE = """
</html>
"""
async def get_chain_head() -> Dict[str, Any]:
"""Get the current chain head"""
try:
@@ -332,6 +387,7 @@ async def get_chain_head() -> Dict[str, Any]:
print(f"Error getting chain head: {e}")
return {}
async def get_block(height: int) -> Dict[str, Any]:
"""Get a specific block by height"""
try:
@@ -343,21 +399,25 @@ async def get_block(height: int) -> Dict[str, Any]:
print(f"Error getting block {height}: {e}")
return {}
@app.get("/", response_class=HTMLResponse)
async def root():
"""Serve the explorer UI"""
return HTML_TEMPLATE.format(node_url=BLOCKCHAIN_RPC_URL)
@app.get("/api/chain/head")
async def api_chain_head():
"""API endpoint for chain head"""
return await get_chain_head()
@app.get("/api/blocks/{height}")
async def api_block(height: int):
"""API endpoint for block data"""
return await get_block(height)
@app.get("/health")
async def health():
"""Health check endpoint"""
@@ -365,8 +425,9 @@ async def health():
return {
"status": "ok" if head else "error",
"node_url": BLOCKCHAIN_RPC_URL,
"chain_height": head.get("height", 0)
"chain_height": head.get("height", 0),
}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=3000)