Merge branch 'feature/refactor-rpc' into develop

This commit is contained in:
Willian Mitsuda 2021-08-03 19:07:22 -03:00
commit a2d9fcb035
7 changed files with 130 additions and 123 deletions

View File

@ -1,4 +1,4 @@
{
"erigonURL": "ws://localhost:8545",
"erigonURL": "http://localhost:8545",
"assetsURLPrefix": "http://localhost:3001"
}

View File

@ -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
</NavLink>{" "}
in this block
</InfoRow>

View File

@ -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<ProcessedTransaction[]>();
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]
const [totalTxs, txs] = useBlockTransactions(
provider,
blockNumber.toNumber(),
pageNumber - 1,
PAGE_SIZE
);
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]);
document.title = `Block #${blockNumber} Txns | Otterscan`;
@ -126,8 +47,8 @@ const BlockTransactions: React.FC = () => {
<StandardFrame>
<BlockTransactionHeader blockTag={blockNumber.toNumber()} />
<BlockTransactionResults
page={page}
total={total}
page={txs}
total={totalTxs ?? 0}
pageNumber={pageNumber}
/>
</StandardFrame>

View File

@ -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[] = [];

View File

@ -61,7 +61,7 @@ type BlocksProps = {
const Blocks: React.FC<BlocksProps> = ({ latestBlock, targetBlockNumber }) => {
const { provider } = useContext(RuntimeContext);
const [blocks, setBlock] = useState<ExtendedBlock[]>([]);
const [blocks, setBlocks] = useState<ExtendedBlock[]>([]);
const [now, setNow] = useState<number>(Date.now());
const addBlock = useCallback(
@ -77,7 +77,7 @@ const Blocks: React.FC<BlocksProps> = ({ 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;
}

View File

@ -130,7 +130,7 @@ const Details: React.FC<DetailsProps> = ({
<Copy value={txData.createdContractAddress!} />
</div>
)}
{internalOps && (
{internalOps && internalOps.length > 0 && (
<div className="mt-2 space-y-1">
{internalOps.map((op, i) => (
<InternalTransactionOperation

View File

@ -1,11 +1,14 @@
import { useState, useEffect } from "react";
import { ethers, BigNumber } from "ethers";
import { BlockWithTransactions } from "@ethersproject/abstract-provider";
import { getInternalOperations } from "./nodeFunctions";
import {
TokenMetas,
TokenTransfer,
TransactionData,
InternalOperation,
ProcessedTransaction,
OperationType,
} from "./types";
import erc20 from "./erc20.json";
@ -20,6 +23,7 @@ export interface ExtendedBlock extends ethers.providers.Block {
sha3Uncles: string;
stateRoot: string;
totalDifficulty: BigNumber;
transactionCount: number;
}
export const readBlock = async (
@ -28,43 +32,122 @@ export const readBlock = async (
) => {
let blockPromise: Promise<any>;
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<number>();
const [txs, setTxs] = useState<ProcessedTransaction[]>();
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);