From 835eca0a6c9e0ff4dae33c5c94e5a6cb719d9295 Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Wed, 1 Jul 2026 11:09:18 +0800 Subject: [PATCH] feat(internal/ethapi): add block timestamp to eth_getTransactionByHash #33709 --- internal/ethapi/api.go | 12 ++++++++---- internal/ethapi/api_test.go | 16 ++++++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 12dc3f122bd8..a297559f7bb9 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1543,6 +1543,7 @@ func (api *BlockChainAPI) rpcOutputBlockSigners(b *types.Block, ctx context.Cont type RPCTransaction struct { BlockHash *common.Hash `json:"blockHash"` BlockNumber *hexutil.Big `json:"blockNumber"` + BlockTimestamp *hexutil.Uint64 `json:"blockTimestamp"` From common.Address `json:"from"` Gas hexutil.Uint64 `json:"gas"` GasPrice *hexutil.Big `json:"gasPrice"` @@ -1566,7 +1567,7 @@ type RPCTransaction struct { // newRPCTransaction returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). -func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { +func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber)) from, _ := types.Sender(signer, tx) v, r, s := tx.RawSignatureValues() @@ -1587,6 +1588,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber if blockHash != (common.Hash{}) { result.BlockHash = &blockHash result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.BlockTimestamp = (*hexutil.Uint64)(&blockTime) result.TransactionIndex = (*hexutil.Uint64)(&index) } @@ -1655,12 +1657,14 @@ func newRPCPendingTransaction(tx *types.Transaction, current *types.Header, conf var ( baseFee *big.Int blockNumber = uint64(0) + blockTime = uint64(0) ) if current != nil { baseFee = eip1559.CalcBaseFee(config, current) blockNumber = current.Number.Uint64() + blockTime = current.Time } - return newRPCTransaction(tx, common.Hash{}, blockNumber, 0, baseFee, config) + return newRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config) } // newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. @@ -1669,7 +1673,7 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *param if index >= uint64(len(txs)) { return nil } - return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee(), config) + return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config) } // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. @@ -1917,7 +1921,7 @@ func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H if err != nil { return nil, err } - return newRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee, s.b.ChainConfig()), nil + return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil } // No finalized transaction, try to retrieve it from the pool if tx := s.b.GetPoolTransaction(hash); tx != nil { diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 75b8502da842..317b9f94adb2 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -178,6 +178,7 @@ func TestRPCMarshalBlock(t *testing.T) { { "blockHash":"0x2cb4e4b5b5be5a2520377e87e8d7d2cf83fc0783fa6518d67b9606d3c5317b50", "blockNumber":"0x64", + "blockTimestamp":"0x0", "from":"0x0000000000000000000000000000000000000000", "gas":"0x457", "gasPrice":"0x2b67", @@ -198,6 +199,7 @@ func TestRPCMarshalBlock(t *testing.T) { { "blockHash":"0x2cb4e4b5b5be5a2520377e87e8d7d2cf83fc0783fa6518d67b9606d3c5317b50", "blockNumber":"0x64", + "blockTimestamp":"0x0", "from":"0x0000000000000000000000000000000000000000", "gas":"0x457", "gasPrice":"0x2b67", @@ -216,6 +218,7 @@ func TestRPCMarshalBlock(t *testing.T) { { "blockHash":"0x2cb4e4b5b5be5a2520377e87e8d7d2cf83fc0783fa6518d67b9606d3c5317b50", "blockNumber":"0x64", + "blockTimestamp":"0x0", "from":"0x0000000000000000000000000000000000000000", "gas":"0x457", "gasPrice":"0x2b67", @@ -236,6 +239,7 @@ func TestRPCMarshalBlock(t *testing.T) { { "blockHash":"0x2cb4e4b5b5be5a2520377e87e8d7d2cf83fc0783fa6518d67b9606d3c5317b50", "blockNumber":"0x64", + "blockTimestamp":"0x0", "from":"0x0000000000000000000000000000000000000000", "gas":"0x457", "gasPrice":"0x2b67", @@ -618,7 +622,7 @@ func TestTransaction_RoundTripRpcJSON(t *testing.T) { tx, err := types.SignNewTx(key, signer, txdata) require.NoErrorf(t, err, "test %d: signing failed", i) - rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, nil, config) + rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config) data, err := json.Marshal(rpcTx) require.NoErrorf(t, err, "test %d: rpc marshal failed", i) @@ -2153,7 +2157,7 @@ func TestNewRPCTransactionLegacyMined(t *testing.T) { require.NoError(t, err) blockHash := common.HexToHash("0x1234") - rpcTx := newRPCTransaction(tx, blockHash, 99, 1, big.NewInt(10), config) + rpcTx := newRPCTransaction(tx, blockHash, 99, 0, 1, big.NewInt(10), config) require.NotNil(t, rpcTx) require.NotNil(t, rpcTx.BlockHash) require.Equal(t, blockHash, *rpcTx.BlockHash) @@ -2185,7 +2189,7 @@ func TestNewRPCTransactionLegacyPending(t *testing.T) { }) require.NoError(t, err) - rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, nil, config) + rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config) require.NotNil(t, rpcTx) require.Nil(t, rpcTx.BlockHash) require.Nil(t, rpcTx.BlockNumber) @@ -2216,7 +2220,7 @@ func TestNewRPCTransactionDynamicPending(t *testing.T) { }) require.NoError(t, err) - rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, big.NewInt(10), config) + rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, big.NewInt(10), config) require.NotNil(t, rpcTx) require.Nil(t, rpcTx.BlockHash) require.Nil(t, rpcTx.BlockNumber) @@ -2249,7 +2253,7 @@ func TestNewRPCTransactionAccessListPending(t *testing.T) { }) require.NoError(t, err) - rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, nil, config) + rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config) require.NotNil(t, rpcTx) require.EqualValues(t, types.AccessListTxType, rpcTx.Type) require.Equal(t, (*hexutil.Big)(tx.GasPrice()), rpcTx.GasPrice) @@ -2282,7 +2286,7 @@ func TestNewRPCTransactionDynamicMinedFeeCapClamp(t *testing.T) { require.NoError(t, err) blockHash := common.HexToHash("0x5678") - rpcTx := newRPCTransaction(tx, blockHash, 1200, 0, big.NewInt(20), config) + rpcTx := newRPCTransaction(tx, blockHash, 1200, 0, 0, big.NewInt(20), config) require.NotNil(t, rpcTx) require.NotNil(t, rpcTx.BlockHash) require.Equal(t, blockHash, *rpcTx.BlockHash)