1
- use ethereum_types:: { H256 , U256 } ;
2
- use reth_rpc_types:: { Block , BlockTransactions } ;
1
+ use ethereum_types:: { H256 , U256 , U64 } ;
2
+ use reth_rpc_types:: { Block , BlockTransactions , Parity , Signature , Transaction as RethTransaction } ;
3
3
use tokio:: sync:: mpsc;
4
4
5
5
use ethportal_api:: types:: execution:: block_body:: BlockBody ;
6
+ use ethportal_api:: types:: execution:: transaction:: Transaction ;
6
7
use ethportal_api:: types:: jsonrpc:: request:: HistoryJsonRpcRequest ;
8
+ use ethportal_api:: utils:: rethtypes:: { ethtype_u64_to_uint256, u256_to_uint256} ;
7
9
use ethportal_api:: EthApiServer ;
8
10
use trin_validation:: constants:: CHAIN_ID ;
9
11
10
- use crate :: errors:: RpcServeError ;
11
12
use crate :: fetch:: { find_block_body_by_hash, find_header_by_hash} ;
12
13
use crate :: jsonrpsee:: core:: { async_trait, RpcResult } ;
13
14
@@ -21,6 +22,126 @@ impl EthApi {
21
22
}
22
23
}
23
24
25
+ fn rpc_transaction (
26
+ transaction : Transaction ,
27
+ block_hash : H256 ,
28
+ block_number : u64 ,
29
+ transaction_index : usize ,
30
+ ) -> RethTransaction {
31
+ // Fields not extractable from the transaction itself
32
+ let block_hash = block_hash. as_fixed_bytes ( ) . into ( ) ;
33
+ let block_number = U256 :: from ( block_number) ;
34
+ let transaction_index = Some ( U256 :: from ( transaction_index) ) ;
35
+
36
+ // Fields calculated on the full transaction envelope
37
+ let hash = transaction. hash ( ) . as_fixed_bytes ( ) . into ( ) ;
38
+ let type_id = match transaction. type_id ( ) {
39
+ 0 => None ,
40
+ n => Some ( U64 :: from ( n) ) ,
41
+ } ;
42
+ // TODO: generate 'from' address from signature
43
+ let from = None ;
44
+
45
+ // Fields internal to the transaction, sometimes varying by transaction type
46
+ let (
47
+ nonce,
48
+ gas_price,
49
+ gas,
50
+ to,
51
+ value,
52
+ input,
53
+ v,
54
+ r,
55
+ s,
56
+ max_fee_per_gas,
57
+ max_priority_fee_per_gas,
58
+ access_list,
59
+ y_parity,
60
+ ) = match transaction {
61
+ Transaction :: Legacy ( tx) => (
62
+ tx. nonce ,
63
+ Some ( tx. gas_price ) ,
64
+ tx. gas ,
65
+ tx. to ,
66
+ tx. value ,
67
+ tx. data ,
68
+ tx. v ,
69
+ tx. r ,
70
+ tx. s ,
71
+ None ,
72
+ None ,
73
+ None ,
74
+ None ,
75
+ ) ,
76
+ Transaction :: AccessList ( tx) => (
77
+ tx. nonce ,
78
+ Some ( tx. gas_price ) ,
79
+ tx. gas ,
80
+ tx. to ,
81
+ tx. value ,
82
+ tx. data ,
83
+ tx. y_parity ,
84
+ tx. r ,
85
+ tx. s ,
86
+ None ,
87
+ None ,
88
+ Some ( tx. access_list ) ,
89
+ Some ( tx. y_parity ) ,
90
+ ) ,
91
+ Transaction :: EIP1559 ( tx) => (
92
+ tx. nonce ,
93
+ None ,
94
+ tx. gas ,
95
+ tx. to ,
96
+ tx. value ,
97
+ tx. data ,
98
+ tx. y_parity ,
99
+ tx. r ,
100
+ tx. s ,
101
+ Some ( tx. max_fee_per_gas ) ,
102
+ Some ( tx. max_priority_fee_per_gas ) ,
103
+ Some ( tx. access_list ) ,
104
+ Some ( tx. y_parity ) ,
105
+ ) ,
106
+ } ;
107
+
108
+ // Convert types
109
+ let ( gas, value) = ( u256_to_uint256 ( gas) , u256_to_uint256 ( value) ) ;
110
+ let signature = Some ( Signature {
111
+ r : u256_to_uint256 ( r) ,
112
+ s : u256_to_uint256 ( s) ,
113
+ v : ethtype_u64_to_uint256 ( v) ,
114
+ y_parity : y_parity. map ( |y| Parity ( !y. is_zero ( ) ) ) ,
115
+ } ) ;
116
+
117
+ // Fields that are hardcoded, for now
118
+ let max_fee_per_blob_gas = None ;
119
+ let chain_id = Some ( CHAIN_ID . into ( ) ) ;
120
+ let blob_versioned_hashes = vec ! [ ] ;
121
+
122
+ RethTransaction {
123
+ hash,
124
+ nonce,
125
+ block_hash,
126
+ block_number,
127
+ transaction_index,
128
+ from,
129
+ to,
130
+ value,
131
+ gas_price,
132
+ gas,
133
+ max_fee_per_gas,
134
+ max_priority_fee_per_gas,
135
+ max_fee_per_blob_gas,
136
+ input,
137
+ signature,
138
+ chain_id,
139
+ blob_versioned_hashes,
140
+ access_list,
141
+ transaction_type,
142
+ }
143
+ }
144
+
24
145
#[ async_trait]
25
146
impl EthApiServer for EthApi {
26
147
async fn chain_id ( & self ) -> RpcResult < U256 > {
@@ -32,26 +153,29 @@ impl EthApiServer for EthApi {
32
153
block_hash : H256 ,
33
154
hydrated_transactions : bool ,
34
155
) -> RpcResult < Block > {
35
- if hydrated_transactions {
36
- return Err ( RpcServeError :: Message (
37
- "replying with all transaction bodies is not supported yet" . into ( ) ,
38
- )
39
- . into ( ) ) ;
40
- }
41
-
42
156
let header = find_header_by_hash ( & self . network , block_hash) . await ?;
43
157
let body = find_block_body_by_hash ( & self . network , block_hash) . await ?;
44
158
let transactions = match body {
45
159
BlockBody :: Legacy ( body) => body. txs ,
46
160
BlockBody :: Merge ( body) => body. txs ,
47
161
BlockBody :: Shanghai ( body) => body. txs ,
48
162
} ;
49
- let transactions = BlockTransactions :: Hashes (
50
- transactions
51
- . into_iter ( )
52
- . map ( |tx| tx. hash ( ) . as_fixed_bytes ( ) . into ( ) )
53
- . collect ( ) ,
54
- ) ;
163
+ let transactions = if hydrated_transactions {
164
+ BlockTransactions :: Full (
165
+ transactions
166
+ . into_iter ( )
167
+ . enumerate ( )
168
+ . map ( |( idx, tx) | rpc_transaction ( tx, block_hash, header. number , idx) )
169
+ . collect ( ) ,
170
+ )
171
+ } else {
172
+ BlockTransactions :: Hashes (
173
+ transactions
174
+ . into_iter ( )
175
+ . map ( |tx| tx. hash ( ) . as_fixed_bytes ( ) . into ( ) )
176
+ . collect ( ) ,
177
+ )
178
+ } ;
55
179
56
180
// Combine header and block body into the single json representation of the block.
57
181
let block = Block {
0 commit comments