-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(node): support legacy transactions #1235
Conversation
_ => error::error_with_revert( | ||
ExitCode::USR_ILLEGAL_ARGUMENT, | ||
"txn type not supported", | ||
None::<Vec<u8>>, | ||
), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
they should be the same, debug_assert_eq
should be fine for release build though, more like a sanity check for tests.
@@ -612,6 +615,14 @@ pub async fn get_uncle_by_block_number_and_index<C>( | |||
Ok(None) | |||
} | |||
|
|||
fn normalize_signature(sig: &mut et::Signature) -> JsonRpcResult<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use Signature::as_signature(), which returns a normalized recoverable signature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it's not exposed...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, a lot of methods are not exposed. Could be helpful util tools.
let sender = msg.from; | ||
let nonce = msg.sequence; | ||
|
||
let msg = SignedMessage { | ||
origin_kind: derive_origin_kind(&tx)?, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't remain forever as it's using LRU cache. It will just stay for some time, depending on the configuration.
/// Cache submitted transactions by their Ethereum hash, because the CometBFT | ||
/// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_transaction
for legacy transactions. This PR removes this assumption. To achieve it, the following changes are made:OriginKind
enum to explicitly specify the original transaction type. The type information is lost when converting to Fvm messages.TransactionCache
is updated to use(TypeTransaction, Signature)
instead of the response dtoTransaction
.