Conversation
| _ => error::error_with_revert( | ||
| ExitCode::USR_ILLEGAL_ARGUMENT, | ||
| "txn type not supported", | ||
| None::<Vec<u8>>, | ||
| ), |
There was a problem hiding this comment.
Why are we duplicating this logic here? send_raw_transaction is already producing this error?
fendermint/eth/api/src/apis/eth.rs
Outdated
| } | ||
| data.tx_cache.insert( | ||
| msghash, | ||
| from_eth::to_eth_transaction_response(&tx, sig, msghash)?, |
There was a problem hiding this comment.
What do you mean with transaction response here? This module is an API, so I interpret as if this is returning the response the API sends to the caller, which isn't the case? (unless there's an error)
We are duplicating the transaction type validation in this method and when we calculate the origin kind above. Can we refactor this to make it DRY?
BTW -- how can we have a module called from_eth that then has to_eth methods? Wouldn't they cancel each other out? 😆
| pub fn to_eth_transaction_response( | ||
| tx: &TypedTransaction, | ||
| sig: et::Signature, | ||
| hash: et::TxHash, | ||
| ) -> et::Transaction { | ||
| et::Transaction { | ||
| hash, | ||
| nonce: tx.nonce.unwrap_or_default(), | ||
| block_hash: None, | ||
| block_number: None, | ||
| transaction_index: None, | ||
| from: tx.from.unwrap_or_default(), | ||
| to: tx.to.and_then(|to| to.as_address().cloned()), | ||
| value: tx.value.unwrap_or_default(), | ||
| gas: tx.gas.unwrap_or_default(), | ||
| max_fee_per_gas: tx.max_fee_per_gas, | ||
| max_priority_fee_per_gas: tx.max_priority_fee_per_gas, | ||
| // Strictly speaking a "Type 2" transaction should not need to set this, but we do because Blockscout | ||
| // has a database constraint that if a transaction is included in a block this can't be null. | ||
| gas_price: Some( | ||
| tx.max_fee_per_gas.unwrap_or_default() | ||
| + tx.max_priority_fee_per_gas.unwrap_or_default(), | ||
| ) -> Result<et::Transaction, JsonRpcError> { |
There was a problem hiding this comment.
I really dislike that the cache uses et::Transaction -- this type is intended as a return type from the JSON-RPC API, not to store canonical signed transactions.
| tx.max_fee_per_gas.unwrap_or_default() | ||
| + tx.max_priority_fee_per_gas.unwrap_or_default(), | ||
| ) -> Result<et::Transaction, JsonRpcError> { | ||
| match &tx { |
There was a problem hiding this comment.
This all looks very repetitive. Can't you populate the common values from TransactionEssentials via essentials()? And then add the specifics?
Isn't there a method to normalize typed transactions into the Transaction response type in ethers?
There was a problem hiding this comment.
Isn't there a method to normalize typed transactions into the Transaction response type in ethers?
From what I found, not really. My guess is the Transaction response contains transaction index, which does not make sense to do the conversion usingFrom.
|
@raulk Because the types and |
| let hash = msg_hash(&res.tx_result.events, &res.tx); | ||
| let mut tx = to_eth_transaction(msg, chain_id, hash)?; | ||
| let mut tx = to_eth_transaction_response(msg, chain_id)?; | ||
| debug_assert_eq!(hash, tx.hash); |
There was a problem hiding this comment.
Not sure we want to crash the process here? Wouldn't it be best to return an internal error?
There was a problem hiding this comment.
they should be the same, debug_assert_eq should be fine for release build though, more like a sanity check for tests.
| Ok(None) | ||
| } | ||
|
|
||
| fn normalize_signature(sig: &mut et::Signature) -> JsonRpcResult<()> { |
There was a problem hiding this comment.
Why not use Signature::as_signature(), which returns a normalized recoverable signature?
There was a problem hiding this comment.
Looks like it's not exposed...
There was a problem hiding this comment.
Yeah, a lot of methods are not exposed. Could be helpful util tools.
| let nonce = msg.sequence; | ||
|
|
||
| let msg = SignedMessage { | ||
| origin_kind: derive_origin_kind(&tx)?, |
There was a problem hiding this comment.
Would it make sense to implement TryFrom<TypedTransaction> for OriginKind instead? Then you can do tx.try_into()? here?
| if let Some(tx) = tx.as_eip1559_ref() { | ||
| let tx = from_eth::to_eth_transaction(tx.clone(), sig, msghash); | ||
| data.tx_cache.insert(msghash, tx); | ||
| } |
There was a problem hiding this comment.
Am I reading right that prior to this PR, if a transaction failed the checks (broadcast_tx_sync or others), it would remain forever in the cache?
There was a problem hiding this comment.
It won't remain forever as it's using LRU cache. It will just stay for some time, depending on the configuration.
| /// API would not be able to find them until they are delivered to the application | ||
| /// and indexed by their domain hash, which some tools interpret as the transaction | ||
| /// being dropped from the mempool. | ||
| pub type TransactionCache = Cache<et::TxHash, et::Transaction>; |
There was a problem hiding this comment.
Honestly, now that I look at the final solution, I think this was better the way it was before. We ended up leaking all of ethers' type complexity into Tendermint. In fact, I don't think TypedTransaction should've leaked anywhere at all. I'll work on rolling this back, removing to_eth_typed_transaction, to_eth_legacy_request, to_eth_eip1559_request, etc.
There was a problem hiding this comment.
I feel the conv::* should not be in message crate. It should be shifted to eth crate. That might be better.
Co-authored-by: raulk <raul@protocol.ai>
raulk
left a comment
There was a problem hiding this comment.
Let's go ahead and merge this to unblock users who are waiting for this feature to land. We can clean this up in main later.
Closes #927.
The current main does not allow
send_raw_transactionfor legacy transactions. This PR removes this assumption. To achieve it, the following changes are made:OriginKindenum to explicitly specify the original transaction type. The type information is lost when converting to Fvm messages.TransactionCacheis updated to use(TypeTransaction, Signature)instead of the response dtoTransaction.