@@ -10,8 +10,66 @@ use uuid::Uuid;
1010/// Block time in microseconds
1111pub const BLOCK_TIME : u128 = 2_000_000 ;
1212
13- pub trait BundleProperties {
14- fn bundle_hash ( & self ) -> B256 ;
13+ pub struct BundleTransactions ( Vec < Bytes > ) ;
14+
15+ impl From < Vec < Bytes > > for BundleTransactions {
16+ fn from ( txs : Vec < Bytes > ) -> Self {
17+ BundleTransactions ( txs)
18+ }
19+ }
20+
21+ impl BundleTransactions {
22+ pub fn bundle_hash ( & self ) -> B256 {
23+ let mut concatenated = Vec :: new ( ) ;
24+ for tx in self . 0 . iter ( ) {
25+ concatenated. extend_from_slice ( tx) ;
26+ }
27+ keccak256 ( & concatenated)
28+ }
29+
30+ /// Get transaction hashes for all transactions in the bundle
31+ pub fn txn_hashes ( & self ) -> Result < Vec < TxHash > , String > {
32+ self . transactions ( ) ?
33+ . iter ( )
34+ . map ( |t| Ok ( t. tx_hash ( ) ) )
35+ . collect ( )
36+ }
37+
38+ /// Get sender addresses for all transactions in the bundle
39+ pub fn senders ( & self ) -> Result < Vec < Address > , String > {
40+ self . transactions ( ) ?
41+ . iter ( )
42+ . map ( |t| {
43+ t. recover_signer ( )
44+ . map_err ( |e| format ! ( "failed to recover signer: {e}" ) )
45+ } )
46+ . collect ( )
47+ }
48+
49+ /// Get total gas limit for all transactions in the bundle
50+ pub fn gas_limit ( & self ) -> Result < u64 , String > {
51+ Ok ( self . transactions ( ) ?. iter ( ) . map ( |t| t. gas_limit ( ) ) . sum ( ) )
52+ }
53+
54+ /// Get total data availability size for all transactions in the bundle
55+ pub fn da_size ( & self ) -> Result < u64 , String > {
56+ Ok ( self
57+ . transactions ( ) ?
58+ . iter ( )
59+ . map ( |t| tx_estimated_size_fjord_bytes ( & t. encoded_2718 ( ) ) )
60+ . sum ( ) )
61+ }
62+
63+ /// Decode all transactions from bytes to OpTxEnvelope
64+ pub fn transactions ( & self ) -> Result < Vec < OpTxEnvelope > , String > {
65+ self . 0
66+ . iter ( )
67+ . map ( |b| {
68+ OpTxEnvelope :: decode_2718_exact ( b)
69+ . map_err ( |e| format ! ( "failed to decode transaction: {e}" ) )
70+ } )
71+ . collect ( )
72+ }
1573}
1674
1775#[ derive( Default , Debug , Serialize , Deserialize , Clone , PartialEq , Eq ) ]
@@ -60,26 +118,6 @@ pub struct Bundle {
60118 pub dropping_tx_hashes : Vec < TxHash > ,
61119}
62120
63- impl BundleProperties for Bundle {
64- fn bundle_hash ( & self ) -> B256 {
65- let transactions: Vec < OpTxEnvelope > = self
66- . txs
67- . iter ( )
68- . map ( |b| {
69- OpTxEnvelope :: decode_2718_exact ( b)
70- . map_err ( |e| format ! ( "failed to decode transaction: {e}" ) )
71- } )
72- . collect :: < Result < Vec < _ > , _ > > ( )
73- . expect ( "failed to decode transactions" ) ;
74-
75- let mut concatenated = Vec :: new ( ) ;
76- for tx in transactions {
77- concatenated. extend_from_slice ( tx. tx_hash ( ) . as_slice ( ) ) ;
78- }
79- keccak256 ( & concatenated)
80- }
81- }
82-
83121#[ derive( Debug , Clone , Serialize , Deserialize ) ]
84122#[ serde( rename_all = "camelCase" ) ]
85123pub struct BundleHash {
@@ -131,45 +169,13 @@ impl BundleWithMetadata {
131169 } )
132170 }
133171
134- pub fn transactions ( & self ) -> & [ OpTxEnvelope ] {
135- self . transactions . as_slice ( )
136- }
137-
138172 pub fn uuid ( & self ) -> & Uuid {
139173 & self . uuid
140174 }
141175
142- pub fn txn_hashes ( & self ) -> Vec < TxHash > {
143- self . transactions ( ) . iter ( ) . map ( |t| t. tx_hash ( ) ) . collect ( )
144- }
145-
146176 pub fn bundle ( & self ) -> & Bundle {
147177 & self . bundle
148178 }
149-
150- pub fn senders ( & self ) -> Vec < Address > {
151- self . transactions ( )
152- . iter ( )
153- . map ( |t| t. recover_signer ( ) . unwrap ( ) )
154- . collect ( )
155- }
156-
157- pub fn gas_limit ( & self ) -> u64 {
158- self . transactions . iter ( ) . map ( |t| t. gas_limit ( ) ) . sum ( )
159- }
160-
161- pub fn da_size ( & self ) -> u64 {
162- self . transactions
163- . iter ( )
164- . map ( |t| tx_estimated_size_fjord_bytes ( & t. encoded_2718 ( ) ) )
165- . sum ( )
166- }
167- }
168-
169- impl BundleProperties for BundleWithMetadata {
170- fn bundle_hash ( & self ) -> B256 {
171- self . bundle . bundle_hash ( )
172- }
173179}
174180
175181#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -243,10 +249,11 @@ mod tests {
243249 bundle. bundle. replacement_uuid,
244250 Some ( bundle. uuid( ) . to_string( ) )
245251 ) ;
246- assert_eq ! ( bundle. txn_hashes( ) . len( ) , 1 ) ;
247- assert_eq ! ( bundle. txn_hashes( ) [ 0 ] , tx1. tx_hash( ) ) ;
248- assert_eq ! ( bundle. senders( ) . len( ) , 1 ) ;
249- assert_eq ! ( bundle. senders( ) [ 0 ] , alice. address( ) ) ;
252+ let bundle_txs: BundleTransactions = bundle. bundle ( ) . txs . clone ( ) . into ( ) ;
253+ assert_eq ! ( bundle_txs. txn_hashes( ) . unwrap( ) . len( ) , 1 ) ;
254+ assert_eq ! ( bundle_txs. txn_hashes( ) . unwrap( ) [ 0 ] , tx1. tx_hash( ) ) ;
255+ assert_eq ! ( bundle_txs. senders( ) . unwrap( ) . len( ) , 1 ) ;
256+ assert_eq ! ( bundle_txs. senders( ) . unwrap( ) [ 0 ] , alice. address( ) ) ;
250257
251258 // Bundle hashes are keccack256(...txnHashes)
252259 let expected_bundle_hash_single = {
@@ -255,7 +262,7 @@ mod tests {
255262 hasher. finalize ( )
256263 } ;
257264
258- assert_eq ! ( bundle . bundle_hash( ) , expected_bundle_hash_single) ;
265+ assert_eq ! ( bundle_txs . bundle_hash( ) , expected_bundle_hash_single) ;
259266
260267 let uuid = Uuid :: new_v4 ( ) ;
261268 let bundle = BundleWithMetadata :: load (
@@ -271,12 +278,13 @@ mod tests {
271278
272279 assert_eq ! ( * bundle. uuid( ) , uuid) ;
273280 assert_eq ! ( bundle. bundle. replacement_uuid, Some ( uuid. to_string( ) ) ) ;
274- assert_eq ! ( bundle. txn_hashes( ) . len( ) , 2 ) ;
275- assert_eq ! ( bundle. txn_hashes( ) [ 0 ] , tx1. tx_hash( ) ) ;
276- assert_eq ! ( bundle. txn_hashes( ) [ 1 ] , tx2. tx_hash( ) ) ;
277- assert_eq ! ( bundle. senders( ) . len( ) , 2 ) ;
278- assert_eq ! ( bundle. senders( ) [ 0 ] , alice. address( ) ) ;
279- assert_eq ! ( bundle. senders( ) [ 1 ] , alice. address( ) ) ;
281+ let bundle_txs2: BundleTransactions = bundle. bundle ( ) . txs . clone ( ) . into ( ) ;
282+ assert_eq ! ( bundle_txs2. txn_hashes( ) . unwrap( ) . len( ) , 2 ) ;
283+ assert_eq ! ( bundle_txs2. txn_hashes( ) . unwrap( ) [ 0 ] , tx1. tx_hash( ) ) ;
284+ assert_eq ! ( bundle_txs2. txn_hashes( ) . unwrap( ) [ 1 ] , tx2. tx_hash( ) ) ;
285+ assert_eq ! ( bundle_txs2. senders( ) . unwrap( ) . len( ) , 2 ) ;
286+ assert_eq ! ( bundle_txs2. senders( ) . unwrap( ) [ 0 ] , alice. address( ) ) ;
287+ assert_eq ! ( bundle_txs2. senders( ) . unwrap( ) [ 1 ] , alice. address( ) ) ;
280288
281289 let expected_bundle_hash_double = {
282290 let mut hasher = Keccak256 :: default ( ) ;
@@ -285,7 +293,7 @@ mod tests {
285293 hasher. finalize ( )
286294 } ;
287295
288- assert_eq ! ( bundle . bundle_hash( ) , expected_bundle_hash_double) ;
296+ assert_eq ! ( bundle_txs2 . bundle_hash( ) , expected_bundle_hash_double) ;
289297 }
290298
291299 #[ test]
0 commit comments