Skip to content

Commit 00d6b77

Browse files
authored
feat(jsonrpc): implement eth_getBlockReceipts (#6379)
1 parent 456b4eb commit 00d6b77

File tree

5 files changed

+390
-136
lines changed

5 files changed

+390
-136
lines changed

framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,14 @@ TransactionResult getTransactionByBlockNumberAndIndex(String blockNumOrTag, Stri
146146
})
147147
TransactionReceipt getTransactionReceipt(String txid) throws JsonRpcInvalidParamsException;
148148

149+
@JsonRpcMethod("eth_getBlockReceipts")
150+
@JsonRpcErrors({
151+
@JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"),
152+
@JsonRpcError(exception = JsonRpcInternalException.class, code = -32000, data = "{}")
153+
})
154+
List<TransactionReceipt> getBlockReceipts(String blockNumOrTag)
155+
throws JsonRpcInvalidParamsException, JsonRpcInternalException;
156+
149157
@JsonRpcMethod("eth_call")
150158
@JsonRpcErrors({
151159
@JsonRpcError(exception = JsonRpcInvalidRequestException.class, code = -32600, data = "{}"),

framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.google.protobuf.GeneratedMessageV3;
1616
import java.io.Closeable;
1717
import java.io.IOException;
18+
import java.util.ArrayList;
1819
import java.util.Arrays;
1920
import java.util.HashMap;
2021
import java.util.Iterator;
@@ -37,6 +38,7 @@
3738
import org.tron.api.GrpcAPI.Return;
3839
import org.tron.api.GrpcAPI.Return.response_code;
3940
import org.tron.api.GrpcAPI.TransactionExtention;
41+
import org.tron.api.GrpcAPI.TransactionInfoList;
4042
import org.tron.common.crypto.Hash;
4143
import org.tron.common.es.ExecutorServiceManager;
4244
import org.tron.common.logsfilter.ContractEventParser;
@@ -75,12 +77,14 @@
7577
import org.tron.core.services.jsonrpc.types.BuildArguments;
7678
import org.tron.core.services.jsonrpc.types.CallArguments;
7779
import org.tron.core.services.jsonrpc.types.TransactionReceipt;
80+
import org.tron.core.services.jsonrpc.types.TransactionReceipt.TransactionContext;
7881
import org.tron.core.services.jsonrpc.types.TransactionResult;
7982
import org.tron.core.store.StorageRowStore;
8083
import org.tron.core.vm.program.Storage;
8184
import org.tron.program.Version;
8285
import org.tron.protos.Protocol.Account;
8386
import org.tron.protos.Protocol.Block;
87+
import org.tron.protos.Protocol.ResourceReceipt;
8488
import org.tron.protos.Protocol.Transaction;
8589
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
8690
import org.tron.protos.Protocol.Transaction.Result.code;
@@ -93,6 +97,7 @@
9397
import org.tron.protos.contract.SmartContractOuterClass.SmartContractDataWrapper;
9498
import org.tron.protos.contract.SmartContractOuterClass.TriggerSmartContract;
9599

100+
96101
@Slf4j(topic = "API")
97102
@Component
98103
public class TronJsonRpcImpl implements TronJsonRpc, Closeable {
@@ -767,6 +772,13 @@ public TransactionResult getTransactionByBlockNumberAndIndex(String blockNumOrTa
767772
return getTransactionByBlockAndIndex(block, index);
768773
}
769774

775+
/**
776+
* Get a transaction receipt by transaction hash
777+
*
778+
* @param txId the transaction hash in hex format (with or without 0x prefix)
779+
* @return TransactionReceipt object for the specified transaction, or null if not found
780+
* @throws JsonRpcInvalidParamsException if the transaction hash format is invalid
781+
*/
770782
@Override
771783
public TransactionReceipt getTransactionReceipt(String txId)
772784
throws JsonRpcInvalidParamsException {
@@ -781,7 +793,116 @@ public TransactionReceipt getTransactionReceipt(String txId)
781793
return null;
782794
}
783795

784-
return new TransactionReceipt(block, transactionInfo, wallet);
796+
BlockCapsule blockCapsule = new BlockCapsule(block);
797+
long blockNum = blockCapsule.getNum();
798+
TransactionInfoList transactionInfoList = wallet.getTransactionInfoByBlockNum(blockNum);
799+
long energyFee = wallet.getEnergyFee(blockCapsule.getTimeStamp());
800+
801+
// Find transaction context
802+
TransactionReceipt.TransactionContext context
803+
= findTransactionContext(transactionInfoList,
804+
transactionInfo.getId());
805+
806+
if (context == null) {
807+
return null; // Transaction not found in block
808+
}
809+
810+
return new TransactionReceipt(blockCapsule, transactionInfo, context, energyFee);
811+
}
812+
813+
/**
814+
* Finds transaction context for a specific transaction ID within the block
815+
* Calculates cumulative gas and log count up to the target transaction
816+
* @param infoList the transactionInfo list for the block
817+
* @param txId the transaction ID
818+
* @return TransactionContext containing index and cumulative values, or null if not found
819+
*/
820+
private TransactionContext findTransactionContext(TransactionInfoList infoList,
821+
ByteString txId) {
822+
823+
long cumulativeGas = 0;
824+
long cumulativeLogCount = 0;
825+
826+
for (int index = 0; index < infoList.getTransactionInfoCount(); index++) {
827+
TransactionInfo info = infoList.getTransactionInfo(index);
828+
ResourceReceipt resourceReceipt = info.getReceipt();
829+
830+
if (info.getId().equals(txId)) {
831+
return new TransactionContext(index, cumulativeGas, cumulativeLogCount);
832+
} else {
833+
cumulativeGas += resourceReceipt.getEnergyUsageTotal();
834+
cumulativeLogCount += info.getLogCount();
835+
}
836+
}
837+
return null;
838+
}
839+
840+
/**
841+
* Get all transaction receipts for a specific block
842+
* @param blockNumOrTag the block number or tag (latest, earliest, pending, finalized)
843+
* @return List of TransactionReceipt objects for all transactions in the block,
844+
* null if block not found
845+
* @throws JsonRpcInvalidParamsException if the parameter format is invalid
846+
* @throws JsonRpcInternalException if there's an internal error
847+
*/
848+
@Override
849+
public List<TransactionReceipt> getBlockReceipts(String blockNumOrTag)
850+
throws JsonRpcInvalidParamsException, JsonRpcInternalException {
851+
Block block = wallet.getByJsonBlockId(blockNumOrTag);
852+
if (block == null) {
853+
return null;
854+
}
855+
856+
BlockCapsule blockCapsule = new BlockCapsule(block);
857+
long blockNum = blockCapsule.getNum();
858+
TransactionInfoList transactionInfoList = wallet.getTransactionInfoByBlockNum(blockNum);
859+
860+
//energy price at the block timestamp
861+
long energyFee = wallet.getEnergyFee(blockCapsule.getTimeStamp());
862+
863+
// Validate transaction list size consistency
864+
int transactionSizeInBlock = blockCapsule.getTransactions().size();
865+
if (transactionSizeInBlock != transactionInfoList.getTransactionInfoCount()) {
866+
throw new JsonRpcInternalException(
867+
String.format("TransactionList size mismatch: "
868+
+ "block has %d transactions, but transactionInfoList has %d",
869+
transactionSizeInBlock, transactionInfoList.getTransactionInfoCount()));
870+
}
871+
872+
return getTransactionReceiptsFromBlock(blockCapsule, transactionInfoList, energyFee);
873+
}
874+
875+
/**
876+
* Get all TransactionReceipts from a block
877+
* This method processes all transactions in the block
878+
* and creates receipts with cumulative gas calculations
879+
* @param blockCapsule the block containing transactions
880+
* @param transactionInfoList the transaction info list for the block
881+
* @param energyFee the energy price at the block timestamp
882+
* @return List of TransactionReceipt objects for all transactions in the block
883+
*/
884+
private List<TransactionReceipt> getTransactionReceiptsFromBlock(BlockCapsule blockCapsule,
885+
TransactionInfoList transactionInfoList, long energyFee) {
886+
887+
List<TransactionReceipt> receipts = new ArrayList<>();
888+
long cumulativeGas = 0;
889+
long cumulativeLogCount = 0;
890+
891+
for (int index = 0; index < transactionInfoList.getTransactionInfoCount(); index++) {
892+
TransactionInfo info = transactionInfoList.getTransactionInfo(index);
893+
ResourceReceipt resourceReceipt = info.getReceipt();
894+
895+
TransactionReceipt.TransactionContext context = new TransactionContext(
896+
index, cumulativeGas, cumulativeLogCount);
897+
898+
// Use the constructor with pre-calculated context
899+
TransactionReceipt receipt = new TransactionReceipt(blockCapsule, info, context, energyFee);
900+
receipts.add(receipt);
901+
902+
cumulativeGas += resourceReceipt.getEnergyUsageTotal();
903+
cumulativeLogCount += info.getLogCount();
904+
}
905+
return receipts;
785906
}
786907

787908
@Override

0 commit comments

Comments
 (0)