(&self, tx: ValidatedTransaction<E>)
| 86 | E: ValidatedTransactionExtensions<BasePooledTransaction>, |
| 87 | { |
| 88 | async fn insert_validated_transaction(&self, tx: ValidatedTransaction<E>) -> RpcResult<()> { |
| 89 | debug!( |
| 90 | sender = %tx.sender, |
| 91 | "rpc::insert_validated_transaction" |
| 92 | ); |
| 93 | let sender = tx.sender; |
| 94 | let has_extensions = !tx.extensions.is_empty(); |
| 95 | |
| 96 | if has_extensions && !self.accept_extensions { |
| 97 | BuilderApiMetrics::extension_errors().increment(1); |
| 98 | return Err(ErrorObjectOwned::owned( |
| 99 | ErrorCode::InvalidParams.code(), |
| 100 | "transaction extensions are disabled", |
| 101 | None::<()>, |
| 102 | )); |
| 103 | } |
| 104 | |
| 105 | tx.extensions.validate(self.max_extension_items).map_err(|e| { |
| 106 | BuilderApiMetrics::extension_errors().increment(1); |
| 107 | ErrorObjectOwned::owned(ErrorCode::InvalidParams.code(), e.to_string(), None::<()>) |
| 108 | })?; |
| 109 | |
| 110 | // Decode the EIP-2718 transaction bytes |
| 111 | let consensus_tx = |
| 112 | BaseTransactionSigned::decode_2718(&mut tx.raw.as_ref()).map_err(|e| { |
| 113 | BuilderApiMetrics::decode_errors().increment(1); |
| 114 | ErrorObjectOwned::owned( |
| 115 | ErrorCode::InvalidParams.code(), |
| 116 | format!("failed to decode transaction: {e}"), |
| 117 | None::<()>, |
| 118 | ) |
| 119 | })?; |
| 120 | let tx_hash = *consensus_tx.hash(); |
| 121 | let encoded_len = tx.raw.len(); |
| 122 | |
| 123 | let recovered = Recovered::new_unchecked(consensus_tx, sender); |
| 124 | let pool_tx = BasePooledTransaction::new(recovered, encoded_len).with_bundle_metadata( |
| 125 | tx.min_block_number, |
| 126 | tx.max_block_number, |
| 127 | tx.min_timestamp, |
| 128 | tx.max_timestamp, |
| 129 | ); |
| 130 | |
| 131 | // Attach any extension data carried on the wire. This is a no-op for |
| 132 | // `NoExtensions`, the default payload. |
| 133 | let pool_tx = tx.extensions.apply(pool_tx).map_err(|e| { |
| 134 | BuilderApiMetrics::extension_errors().increment(1); |
| 135 | ErrorObjectOwned::owned(ErrorCode::InvalidParams.code(), e.to_string(), None::<()>) |
| 136 | })?; |
| 137 | |
| 138 | // Extension-bearing transactions remain private so normal P2P gossip |
| 139 | // cannot propagate the raw transaction without its extension metadata. |
| 140 | let start = Instant::now(); |
| 141 | let result = if has_extensions { |
| 142 | self.pool.add_transaction(TransactionOrigin::Private, pool_tx).await |
| 143 | } else { |
| 144 | self.pool.add_external_transaction(pool_tx).await |
| 145 | }; |
no test coverage detected