query tx by fork

This commit is contained in:
David Rusu 2026-02-16 23:46:08 +04:00
parent e6821bdbb4
commit e2b61db480
4 changed files with 21 additions and 8 deletions

View File

@ -41,11 +41,11 @@ async def stream(
return NDJsonStreamingResponse(ndjson_transactions_stream)
async def get(request: NBERequest, transaction_hash: str) -> Response:
async def get(request: NBERequest, transaction_hash: str, fork: int = Query(...)) -> Response:
if not transaction_hash:
return Response(status_code=NOT_FOUND)
transaction_hash = dehexify(transaction_hash)
transaction = await request.app.state.transaction_repository.get_by_hash(transaction_hash)
transaction = await request.app.state.transaction_repository.get_by_hash(transaction_hash, fork=fork)
return transaction.map(
lambda _transaction: JSONResponse(TransactionRead.from_transaction(_transaction).model_dump(mode="json"))
).unwrap_or_else(lambda: Response(status_code=NOT_FOUND))

View File

@ -51,12 +51,16 @@ class TransactionRepository:
else:
return Empty()
async def get_by_hash(self, transaction_hash: bytes) -> Option[Transaction]:
statement = select(Transaction).where(Transaction.hash == transaction_hash)
async def get_by_hash(self, transaction_hash: bytes, *, fork: int) -> Option[Transaction]:
statement = (
select(Transaction)
.join(Block, Transaction.block_id == Block.id)
.where(Transaction.hash == transaction_hash, Block.fork == fork)
)
with self.client.session() as session:
result: Result[Transaction] = session.exec(statement)
if (transaction := result.one_or_none()) is not None:
if (transaction := result.first()) is not None:
return Some(transaction)
else:
return Empty()

View File

@ -8,7 +8,8 @@ const encodeHash = (hash) => encodeURIComponent(String(hash));
const HEALTH_ENDPOINT = joinUrl(API_PREFIX, 'health/stream');
const TRANSACTION_DETAIL_BY_HASH = (hash) => joinUrl(API_PREFIX, 'transactions', encodeHash(hash));
const TRANSACTION_DETAIL_BY_HASH = (hash, fork) =>
`${joinUrl(API_PREFIX, 'transactions', encodeHash(hash))}?fork=${encodeURIComponent(fork)}`;
const TRANSACTIONS_STREAM = joinUrl(API_PREFIX, 'transactions/stream');
const FORK_CHOICE = joinUrl(API_PREFIX, 'fork-choice');

View File

@ -3,6 +3,7 @@ import { h, Fragment } from 'preact';
import { useEffect, useMemo, useState } from 'preact/hooks';
import { API, PAGE, BASE_PATH } from '../lib/api.js';
import { shortenHex } from '../lib/utils.js';
import { subscribeFork } from '../lib/fork.js';
// ————— helpers —————
const isNumber = (v) => typeof v === 'number' && !Number.isNaN(v);
@ -485,6 +486,11 @@ export default function TransactionDetail({ parameters }) {
const [tx, setTx] = useState(null);
const [err, setErr] = useState(null); // { kind: 'invalid'|'not-found'|'network', msg: string }
const [fork, setFork] = useState(null);
useEffect(() => {
return subscribeFork((newFork) => setFork(newFork));
}, []);
const pageTitle = useMemo(() => `Transaction ${shortenHex(transactionHash)}`, [transactionHash]);
useEffect(() => {
@ -500,12 +506,14 @@ export default function TransactionDetail({ parameters }) {
return;
}
if (fork == null) return;
let alive = true;
const controller = new AbortController();
(async () => {
try {
const res = await fetch(API.TRANSACTION_DETAIL_BY_HASH(transactionHash), {
const res = await fetch(API.TRANSACTION_DETAIL_BY_HASH(transactionHash, fork), {
cache: 'no-cache',
signal: controller.signal,
});
@ -527,7 +535,7 @@ export default function TransactionDetail({ parameters }) {
alive = false;
controller.abort();
};
}, [transactionHash, isValidHash]);
}, [transactionHash, isValidHash, fork]);
return h(
'main',