diff --git a/public/config.json b/public/config.json index 5573731..1db5aa7 100644 --- a/public/config.json +++ b/public/config.json @@ -1,4 +1,4 @@ { - "erigonURL": "ws://localhost:8545", + "erigonURL": "http://localhost:8545", "assetsURLPrefix": "http://localhost:3001" } \ No newline at end of file diff --git a/src/Block.tsx b/src/Block.tsx index a515036..298ef01 100644 --- a/src/Block.tsx +++ b/src/Block.tsx @@ -83,7 +83,7 @@ const Block: React.FC = () => { className="bg-link-blue bg-opacity-10 text-link-blue hover:bg-opacity-100 hover:text-white rounded-lg px-2 py-1 text-xs" to={blockTxsURL(block.number)} > - {block.transactions.length} transactions + {block.transactionCount} transactions {" "} in this block diff --git a/src/BlockTransactions.tsx b/src/BlockTransactions.tsx index 2ce687b..4835fd3 100644 --- a/src/BlockTransactions.tsx +++ b/src/BlockTransactions.tsx @@ -1,17 +1,13 @@ -import React, { useEffect, useState, useMemo, useContext } from "react"; +import React, { useMemo, useContext } from "react"; import { useParams, useLocation } from "react-router"; import { ethers } from "ethers"; import queryString from "query-string"; import StandardFrame from "./StandardFrame"; import BlockTransactionHeader from "./block/BlockTransactionHeader"; import BlockTransactionResults from "./block/BlockTransactionResults"; -import { - InternalOperation, - OperationType, - ProcessedTransaction, -} from "./types"; import { PAGE_SIZE } from "./params"; import { RuntimeContext } from "./useRuntime"; +import { useBlockTransactions } from "./useErigonHooks"; type BlockParams = { blockNumber: string; @@ -38,87 +34,12 @@ const BlockTransactions: React.FC = () => { [params.blockNumber] ); - const [txs, setTxs] = useState(); - useEffect(() => { - if (!provider) { - return; - } - - const readBlock = async () => { - const [_block, _receipts] = await Promise.all([ - provider.getBlockWithTransactions(blockNumber.toNumber()), - provider.send("eth_getBlockReceipts", [blockNumber.toNumber()]), - ]); - document.title = `Block #${_block.number} Transactions | Otterscan`; - - const responses = _block.transactions - .map((t, i): ProcessedTransaction => { - return { - blockNumber: blockNumber.toNumber(), - timestamp: _block.timestamp, - miner: _block.miner, - idx: i, - hash: t.hash, - from: t.from, - to: t.to, - createdContractAddress: _receipts[i].contractAddress, - value: t.value, - fee: - t.type !== 2 - ? provider.formatter - .bigNumber(_receipts[i].gasUsed) - .mul(t.gasPrice!) - : provider.formatter - .bigNumber(_receipts[i].gasUsed) - .mul(t.maxPriorityFeePerGas!.add(_block.baseFeePerGas!)), - gasPrice: - t.type !== 2 - ? t.gasPrice! - : t.maxPriorityFeePerGas!.add(_block.baseFeePerGas!), - data: t.data, - status: provider.formatter.number(_receipts[i].status), - }; - }) - .reverse(); - setTxs(responses); - - const internalChecks = await Promise.all( - responses.map(async (res) => { - const r: InternalOperation[] = await provider.send( - "ots_getInternalOperations", - [res.hash] - ); - for (const op of r) { - if (op.type !== OperationType.TRANSFER) { - continue; - } - if ( - res.miner && - (res.miner === ethers.utils.getAddress(op.from) || - res.miner === ethers.utils.getAddress(op.to)) - ) { - return true; - } - } - return false; - }) - ); - const processedResponses = responses.map((r, i): ProcessedTransaction => { - return { ...r, internalMinerInteraction: internalChecks[i] }; - }); - setTxs(processedResponses); - }; - readBlock(); - }, [provider, blockNumber]); - - const page = useMemo(() => { - if (!txs) { - return undefined; - } - const pageStart = (pageNumber - 1) * PAGE_SIZE; - return txs.slice(pageStart, pageStart + PAGE_SIZE); - }, [txs, pageNumber]); - const total = useMemo(() => txs?.length ?? 0, [txs]); + const [totalTxs, txs] = useBlockTransactions( + provider, + blockNumber.toNumber(), + pageNumber - 1, + PAGE_SIZE + ); document.title = `Block #${blockNumber} Txns | Otterscan`; @@ -126,8 +47,8 @@ const BlockTransactions: React.FC = () => { diff --git a/src/nodeFunctions.ts b/src/nodeFunctions.ts index d160dac..29bd5d5 100644 --- a/src/nodeFunctions.ts +++ b/src/nodeFunctions.ts @@ -1,12 +1,12 @@ import { ethers } from "ethers"; -import { TransactionData, InternalOperation } from "./types"; +import { InternalOperation } from "./types"; export const getInternalOperations = async ( provider: ethers.providers.JsonRpcProvider, - txData: TransactionData + txHash: string ) => { const rawTransfers = await provider.send("ots_getInternalOperations", [ - txData.transactionHash, + txHash, ]); const _transfers: InternalOperation[] = []; diff --git a/src/special/london/Blocks.tsx b/src/special/london/Blocks.tsx index 7dc5f9a..441aa05 100644 --- a/src/special/london/Blocks.tsx +++ b/src/special/london/Blocks.tsx @@ -61,7 +61,7 @@ type BlocksProps = { const Blocks: React.FC = ({ latestBlock, targetBlockNumber }) => { const { provider } = useContext(RuntimeContext); - const [blocks, setBlock] = useState([]); + const [blocks, setBlocks] = useState([]); const [now, setNow] = useState(Date.now()); const addBlock = useCallback( @@ -77,7 +77,7 @@ const Blocks: React.FC = ({ latestBlock, targetBlockNumber }) => { const extBlock = await readBlock(provider, blockNumber.toString()); setNow(Date.now()); - setBlock((_blocks) => { + setBlocks((_blocks) => { if (_blocks.length > 0 && blockNumber === _blocks[0].number) { return _blocks; } diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 69e40fe..2946df5 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -130,7 +130,7 @@ const Details: React.FC = ({ )} - {internalOps && ( + {internalOps && internalOps.length > 0 && (
{internalOps.map((op, i) => ( { let blockPromise: Promise; if (ethers.utils.isHexString(blockNumberOrHash, 32)) { + // TODO: fix blockPromise = provider.send("eth_getBlockByHash", [ blockNumberOrHash, false, ]); } else { - blockPromise = provider.send("eth_getBlockByNumber", [ - blockNumberOrHash, - false, - ]); + blockPromise = provider.send("ots_getBlockDetails", [blockNumberOrHash]); } - const [_rawBlock, _rawIssuance, _rawReceipts] = await Promise.all([ - blockPromise, - provider.send("erigon_issuance", [blockNumberOrHash]), - provider.send("eth_getBlockReceipts", [blockNumberOrHash]), - ]); - const receipts = (_rawReceipts as any[]).map((r) => - provider.formatter.receipt(r) - ); - const fees = receipts.reduce( - (acc, r) => acc.add(r.effectiveGasPrice.mul(r.gasUsed)), - BigNumber.from(0) - ); - const _block = provider.formatter.block(_rawBlock); + const _rawBlock = await blockPromise; + const _block = provider.formatter.block(_rawBlock.block); + const _rawIssuance = _rawBlock.issuance; + const fees = provider.formatter.bigNumber(_rawBlock.totalFees); + const extBlock: ExtendedBlock = { blockReward: provider.formatter.bigNumber(_rawIssuance.blockReward ?? 0), unclesReward: provider.formatter.bigNumber(_rawIssuance.uncleReward ?? 0), feeReward: fees, - size: provider.formatter.number(_rawBlock.size), - sha3Uncles: _rawBlock.sha3Uncles, - stateRoot: _rawBlock.stateRoot, - totalDifficulty: provider.formatter.bigNumber(_rawBlock.totalDifficulty), + size: provider.formatter.number(_rawBlock.block.size), + sha3Uncles: _rawBlock.block.sha3Uncles, + stateRoot: _rawBlock.block.stateRoot, + totalDifficulty: provider.formatter.bigNumber( + _rawBlock.block.totalDifficulty + ), + transactionCount: provider.formatter.number( + _rawBlock.block.transactionCount + ), ..._block, }; return extBlock; }; +export const useBlockTransactions = ( + provider: ethers.providers.JsonRpcProvider | undefined, + blockNumber: number, + pageNumber: number, + pageSize: number +): [number | undefined, ProcessedTransaction[] | undefined] => { + const [totalTxs, setTotalTxs] = useState(); + const [txs, setTxs] = useState(); + + useEffect(() => { + if (!provider) { + return; + } + + const readBlock = async () => { + const result = await provider.send("ots_getBlockTransactions", [ + blockNumber, + pageNumber, + pageSize, + ]); + const _block = provider.formatter.blockWithTransactions( + result.fullblock + ) as unknown as BlockWithTransactions; + const _receipts = result.receipts; + + const rawTxs = _block.transactions + .map( + (t, i): ProcessedTransaction => ({ + blockNumber: blockNumber, + timestamp: _block.timestamp, + miner: _block.miner, + idx: i, + hash: t.hash, + from: t.from, + to: t.to, + createdContractAddress: _receipts[i].contractAddress, + value: t.value, + fee: + t.type !== 2 + ? provider.formatter + .bigNumber(_receipts[i].gasUsed) + .mul(t.gasPrice!) + : provider.formatter + .bigNumber(_receipts[i].gasUsed) + .mul(t.maxPriorityFeePerGas!.add(_block.baseFeePerGas!)), + gasPrice: + t.type !== 2 + ? t.gasPrice! + : t.maxPriorityFeePerGas!.add(_block.baseFeePerGas!), + data: t.data, + status: provider.formatter.number(_receipts[i].status), + }) + ) + .reverse(); + setTxs(rawTxs); + setTotalTxs(result.fullblock.transactionCount); + + const checkTouchMinerAddr = await Promise.all( + rawTxs.map(async (res) => { + const ops = await getInternalOperations(provider, res.hash); + return ( + ops.findIndex( + (op) => + op.type === OperationType.TRANSFER && + res.miner !== undefined && + res.miner === ethers.utils.getAddress(op.to) + ) !== -1 + ); + }) + ); + const processedTxs = rawTxs.map( + (r, i): ProcessedTransaction => ({ + ...r, + internalMinerInteraction: checkTouchMinerAddr[i], + }) + ); + setTxs(processedTxs); + }; + readBlock(); + }, [provider, blockNumber, pageNumber, pageSize]); + + return [totalTxs, txs]; +}; + export const useBlockData = ( provider: ethers.providers.JsonRpcProvider | undefined, blockNumberOrHash: string @@ -96,12 +179,12 @@ export const useTxData = ( return; } - const readBlock = async () => { + const readTxData = async () => { const [_response, _receipt] = await Promise.all([ provider.getTransaction(txhash), provider.getTransactionReceipt(txhash), ]); - const _block = await provider.getBlock(_receipt.blockNumber); + const _block = await readBlock(provider, _receipt.blockNumber.toString()); document.title = `Transaction ${_response.hash} | Otterscan`; // Extract token transfers @@ -149,7 +232,7 @@ export const useTxData = ( status: _receipt.status === 1, blockNumber: _receipt.blockNumber, transactionIndex: _receipt.transactionIndex, - blockTransactionCount: _block.transactions.length, + blockTransactionCount: _block.transactionCount, confirmations: _receipt.confirmations, timestamp: _block.timestamp, miner: _block.miner, @@ -172,7 +255,7 @@ export const useTxData = ( logs: _receipt.logs, }); }; - readBlock(); + readTxData(); }, [provider, txhash]); return txData; @@ -190,7 +273,10 @@ export const useInternalOperations = ( return; } - const _transfers = await getInternalOperations(provider, txData); + const _transfers = await getInternalOperations( + provider, + txData.transactionHash + ); for (const t of _transfers) { t.from = provider.formatter.address(t.from); t.to = provider.formatter.address(t.to);