Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add eth_getBlockReceipts #1156

Merged
7 changes: 7 additions & 0 deletions client/rpc-core/src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ pub trait EthApi {
number: BlockNumber,
) -> RpcResult<Option<U256>>;

/// Returns the receipts of a block by number or hash.
#[method(name = "eth_getBlockReceipts")]
async fn block_transaction_receipts(
&self,
number: BlockNumber,
) -> RpcResult<Vec<Option<Receipt>>>;
boundless-forest marked this conversation as resolved.
Show resolved Hide resolved

/// Returns the number of uncles in a block with given hash.
#[method(name = "eth_getUncleCountByBlockHash")]
fn block_uncles_count_by_hash(&self, hash: H256) -> RpcResult<U256>;
Expand Down
41 changes: 40 additions & 1 deletion client/rpc/src/eth/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ where
C: ProvideRuntimeApi<B>,
C::Api: EthereumRuntimeRPCApi<B>,
C: HeaderBackend<B> + StorageProvider<B, BE> + 'static,
BE: Backend<B>,
BE: Backend<B> + 'static,
A: ChainApi<Block = B> + 'static,
{
pub async fn block_by_hash(&self, hash: H256, full: bool) -> RpcResult<Option<RichBlock>> {
Expand Down Expand Up @@ -267,6 +267,45 @@ where
}
}

pub async fn block_transaction_receipts(
&self,
number: BlockNumber,
) -> RpcResult<Vec<Option<Receipt>>> {
let id = match frontier_backend_client::native_block_id::<B, C>(
self.client.as_ref(),
self.backend.as_ref(),
Some(number),
)
.await?
{
Some(id) => id,
None => return Ok(vec![]),
};

let substrate_hash = self
.client
.expect_block_hash_from_id(&id)
.map_err(|_| internal_err(format!("Expect block number from id: {}", id)))?;
let schema = fc_storage::onchain_storage_schema(self.client.as_ref(), substrate_hash);
let block = self
.overrides
.schemas
.get(&schema)
.unwrap_or(&self.overrides.fallback)
.current_block(substrate_hash);

let transaction_hashes = match block {
Some(block) => block.transactions.iter().map(|tx| tx.hash()).collect(),
None => vec![],
};
let mut receipts = Vec::new();
for hash in transaction_hashes {
receipts.push(self.transaction_receipt(hash).await?);
}

Ok(receipts)
}

pub fn block_uncles_count_by_hash(&self, _: H256) -> RpcResult<U256> {
Ok(U256::zero())
}
Expand Down
7 changes: 7 additions & 0 deletions client/rpc/src/eth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@ where
self.block_transaction_count_by_number(number).await
}

async fn block_transaction_receipts(
&self,
number: BlockNumber,
) -> RpcResult<Vec<Option<Receipt>>> {
self.block_transaction_receipts(number).await
}

fn block_uncles_count_by_hash(&self, hash: H256) -> RpcResult<U256> {
self.block_uncles_count_by_hash(hash)
}
Expand Down
70 changes: 69 additions & 1 deletion ts-tests/tests/test-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ describeWithFrontier("Frontier RPC (Pending Block)", (context) => {
nonce = nonce + 100;
await sendTransaction();

// do not seal, get pendign block
// do not seal, get pending block
let pending_transactions = [];
{
const pending = (await customRequest(context.web3, "eth_getBlockByNumber", ["pending", false])).result;
Expand All @@ -195,3 +195,71 @@ describeWithFrontier("Frontier RPC (Pending Block)", (context) => {
expect(pending_transactions).to.be.deep.eq(latest_block.transactions);
});
});

describeWithFrontier("Frontier RPC (BlockReceipts)", (context) => {
const TEST_ACCOUNT = "0x1111111111111111111111111111111111111111";
const N = 5;

it("should return empty if block without transaction", async function () {
await createAndFinalizeBlock(context.web3);
expect(await context.web3.eth.getBlockNumber()).to.equal(1);

let result = await customRequest(context.web3, "eth_getBlockReceipts", [
await context.web3.eth.getBlockNumber(),
]);
expect(result.result.length).to.be.eq(0);
});

it("should return multiple receipts", async function () {
var nonce = 0;
let sendTransaction = async () => {
const tx = await context.web3.eth.accounts.signTransaction(
{
from: GENESIS_ACCOUNT,
to: TEST_ACCOUNT,
value: "0x200", // Must be higher than ExistentialDeposit
gasPrice: "0x3B9ACA00",
gas: "0x100000",
nonce: nonce,
},
GENESIS_ACCOUNT_PRIVATE_KEY
);
nonce = nonce + 1;
return (await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction])).result;
};

// block 1 send 5 transactions
for (var _ of Array(N)) {
await sendTransaction();
}
await createAndFinalizeBlock(context.web3);
expect(await context.web3.eth.getBlockNumber()).to.equal(2);

let result = await customRequest(context.web3, "eth_getBlockReceipts", [2]);
expect(result.result.length).to.be.eq(N);
});

it("should support block number, tag and hash", async function () {
let block_number = await context.web3.eth.getBlockNumber();

// block number
expect((await customRequest(context.web3, "eth_getBlockReceipts", [block_number])).result.length).to.be.eq(N);
// block hash
let block = await context.web3.eth.getBlock(block_number);
expect(
(
await customRequest(context.web3, "eth_getBlockReceipts", [
{
blockHash: block.hash,
requireCanonical: true,
},
])
).result.length
).to.be.eq(N);
// block tags
expect((await customRequest(context.web3, "eth_getBlockReceipts", ["earliest"])).result.length).to.be.eq(0);
expect((await customRequest(context.web3, "eth_getBlockReceipts", ["pending"])).result.length).to.be.eq(0);
expect((await customRequest(context.web3, "eth_getBlockReceipts", ["finalized"])).result.length).to.be.eq(N);
expect((await customRequest(context.web3, "eth_getBlockReceipts", ["latest"])).result.length).to.be.eq(N);
});
});
Loading