Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

FIX: Accept 'input' or 'data', (but not both), in transaction request #2697

Merged
merged 4 commits into from
Dec 8, 2023

Conversation

aakoshh
Copy link
Contributor

@aakoshh aakoshh commented Dec 7, 2023

Motivation

ethereum/go-ethereum#28078 changed the go-ethereum client to send the transaction payload in an input field instead of data, which is how it's defined in the API. Apparently most server implementations accept both fields, preferring input where both are present at the same time.

The Eip1559TransactionRequest has a data field, and thus it could not be used to deserialize such requests.

Solution

The PR annotates Eip1559TransactionRequest::data field so that it accepts either input or data. Initially I added a special deserializer to accept both fields at the same time and prefer input, but it's a bit of an overkill, and the trend seems to be that clients like web3.js are fixed not to send both unconditionally.

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

@aakoshh aakoshh marked this pull request as draft December 7, 2023 17:37
@aakoshh aakoshh marked this pull request as ready for review December 7, 2023 17:52
Comment on lines 46 to 49
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_input_or_data",
serialize_with = "serialize_input_or_data",
flatten
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is just alias = "input"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I tried to do as well, however it fails on the example where both fields are present:

---- types::transaction::eip1559::tests::test_tx_with_input_or_data stdout ----
thread 'types::transaction::eip1559::tests::test_tx_with_input_or_data' panicked at 'failed to parse request { "gas": "0x186a0",
                    "maxFeePerGas": "0x77359400",
                    "maxPriorityFeePerGas": "0x77359400",
                    "nonce": "0x2",
                    "to": "0x96216849c49358B10257cb55b28eA603c874b05E",
                    "value": "0x5af3107a4000",
                    "chainId": "0x539",
                    "accessList": [],
                     "data":"0x02", "input":"0x01" 
                }: duplicate field `data` at line 9 column 43', ethers-core/src/types/transaction/eip1559.rs:340:37

I'm not sure how important that is, whether there are actual clients that are so defensive that they send both fields, not knowing which one the server might expect; I only got it as a hint from someone who debugged this problem that certain implementation have a preference for input, which presumes that there is a choice to made.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sigh

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then I guess the only way is the serialize functions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just saw in web3/web3.js#1340 that Parity rejects the request if both input and data is present, so maybe it's okay to require one or the other with a simple alias.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplication used to be an issue with web3 but got fixed apparently: web3/web3.js#6301

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to alias, and added it to the legacy transaction type as well, just in case.

Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deserialize fn makes sense

Comment on lines 307 to 314
fn serialize_input_or_data<S: Serializer>(data: &Option<Bytes>, s: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
struct InputOrData<'a> {
data: &'a Option<Bytes>,
}

InputOrData { data }.serialize(s)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this we don't need, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or is this to make flatten work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought so too, but unfortunately the flatten trick which makes both input and data available for deserialize_input_or_data means that during serialization it also wants to flatten the results, which it can't because it's a String. This returns a {"data": "0x..."} object which can be flattened 😞

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed it to keep it simple.

@aakoshh aakoshh changed the title FIX: Accept 'input' or 'data' or both in transaction request FIX: Accept 'input' or 'data', (but not both), in transaction request Dec 8, 2023
Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mattsse mattsse merged commit 40cc8cc into gakonst:master Dec 8, 2023
17 of 19 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants