You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Proposal: return eth_getTransactionCount from the private mempool when RPC request is signed
This is a proposal to augment the RPC endpoint behavior as follows:
When a request is made for eth_getTransactionCount targeting the "pending" block specifier.
And the request is signed with the X-Flashbots-Signature header.
And the signature address matches the account being queried
Then the RPC endpoint will return the transaction count from it's internal "private mempool".
Current Behavior
Recall that eth_getTransactionCount takes two arguments:
The account to query
The EIP-1898 Block Specifier (e.g. "latest", "pending" or a block number or hash).
And returns the total number of transactions that account has executed at that block specifier. Furthermore, the "pending" specifier is somewhat special-cased, in that in addition to considering all transactions already executed on-chain, it also includes any pending transactions in the node's mempool that are considered executable by the node, where executable refers means that all previous nonces for the account in question are either already on-chain or themselves executable.
Currently, eth_getTransactionCount is treated like any other RPC not directly handled by the endpoint and the request is simply proxied to the PROXY_URL endpoint. However, this endpoint is typically not aware of any "private mempool" transactions sent by the user (e.g. eth_sendRawTransaction requests) so will give an inaccurate response when the "pending" block is queried and the user has any pending private transactions.
Desired Behavior
When a user sends the eth_getTransactionCount request to the RPC endpoint targeting the "pending" block the response should take into consideration any outstanding private transactions.
Security Concerns
However, there's a security concern, in that making this data openly available potentially leaks information about usage of the private mempool.
For example, a third party could continuously call eth_getTransactionCount targeting the account in question, and see when the user has submitted new transaction(s) to the private mempool.
If the account in question has known usage patterns this information could be used in an attempt to execute a blind back run or front run on the account.
As such, we propose that information about private mempool transaction counts is only included when the request is signed with the same X-Flashbots-Signature method we use for signing relay requests, and that the users wallet key is used to sign the request.
One potential complication with this approach is that we already have some custom handling of eth_getTransactionCount in place to "trick" MetaMask into correctly reporting dropped transactions, see #31 for details. We should confirm that this trick is still necessary, and either remove it or make sure it's compatible with the above logic when implementing these changes.
Redis Sorted Set Implementation
NOTE: This section will be further fleshed out once we approve the overall approach, for now consider this rough notes on implementation details.
Assuming these complications can be sorted out, we are already tracking the "max nonce" per sender (see RedisState.SetSenderMaxNonce) which gets us mostly there, the only question is how we want to handle "nonce gaps" since a correct implementation of eth_getTransactionCount should only consider executable transactions.
To handle nonce gaps, we can store a per-sender ZSet rather than a single "max nonce", where we use the nonce value as the score, and either the nonce or tx hash as the value. We will enter both the senders "on-chain" nonce (found via eth_getTransaction(sender, "latest") and any new private tx nonces into the ZSet. Then, to compute the "executable" count, we can retrieve the sorted set using ZRangeWithScores and return the highest nonce seen, stopping at either the last item in the set or any gaps. We can continue to use a 24h TTL for this sorted set, and can remove on-chain nonces from the set if it continue to grow beyond a size threshold of say 10 elements.
For example, consider the case where a user has never sent a transaction (next nonce is 0) and the account submits a private tx with nonce 1. Since eth_getTransactionCount(sender, "latest") returns 0, we would insert -1 into the set, alongside the submitted tx nonce of 1. Then their sorted set would contain [-1 1] which we would scan and stop at -1, and thus return 0.
If the user then came back and "filled the gap" a submitted a tx with nonce 0, the set would now contain [-1 0 1] and we would return 2 as the transaction count.
The text was updated successfully, but these errors were encountered:
Proposal: return
eth_getTransactionCount
from the private mempool when RPC request is signedThis is a proposal to augment the RPC endpoint behavior as follows:
eth_getTransactionCount
targeting the"pending"
block specifier.X-Flashbots-Signature
header.Current Behavior
Recall that
eth_getTransactionCount
takes two arguments:"latest"
,"pending"
or a block number or hash).And returns the total number of transactions that account has executed at that block specifier. Furthermore, the
"pending"
specifier is somewhat special-cased, in that in addition to considering all transactions already executed on-chain, it also includes any pending transactions in the node's mempool that are considered executable by the node, where executable refers means that all previous nonces for the account in question are either already on-chain or themselves executable.Currently,
eth_getTransactionCount
is treated like any other RPC not directly handled by the endpoint and the request is simply proxied to thePROXY_URL
endpoint. However, this endpoint is typically not aware of any "private mempool" transactions sent by the user (e.g.eth_sendRawTransaction
requests) so will give an inaccurate response when the"pending"
block is queried and the user has any pending private transactions.Desired Behavior
When a user sends the
eth_getTransactionCount
request to the RPC endpoint targeting the"pending"
block the response should take into consideration any outstanding private transactions.Security Concerns
However, there's a security concern, in that making this data openly available potentially leaks information about usage of the private mempool.
eth_getTransactionCount
targeting the account in question, and see when the user has submitted new transaction(s) to the private mempool.As such, we propose that information about private mempool transaction counts is only included when the request is signed with the same
X-Flashbots-Signature
method we use for signing relay requests, and that the users wallet key is used to sign the request.Implementation Logic
We propose the following implementation logic:
Implementation Details
One potential complication with this approach is that we already have some custom handling of
eth_getTransactionCount
in place to "trick" MetaMask into correctly reporting dropped transactions, see #31 for details. We should confirm that this trick is still necessary, and either remove it or make sure it's compatible with the above logic when implementing these changes.Redis Sorted Set Implementation
NOTE: This section will be further fleshed out once we approve the overall approach, for now consider this rough notes on implementation details.
Assuming these complications can be sorted out, we are already tracking the "max nonce" per sender (see
RedisState.SetSenderMaxNonce
) which gets us mostly there, the only question is how we want to handle "nonce gaps" since a correct implementation ofeth_getTransactionCount
should only consider executable transactions.To handle nonce gaps, we can store a per-sender ZSet rather than a single "max nonce", where we use the nonce value as the score, and either the nonce or tx hash as the value. We will enter both the senders "on-chain" nonce (found via
eth_getTransaction(sender, "latest")
and any new private tx nonces into the ZSet. Then, to compute the "executable" count, we can retrieve the sorted set usingZRangeWithScores
and return the highest nonce seen, stopping at either the last item in the set or any gaps. We can continue to use a 24h TTL for this sorted set, and can remove on-chain nonces from the set if it continue to grow beyond a size threshold of say 10 elements.For example, consider the case where a user has never sent a transaction (next nonce is
0
) and the account submits a private tx with nonce1
. Sinceeth_getTransactionCount(sender, "latest")
returns0
, we would insert-1
into the set, alongside the submitted tx nonce of1
. Then their sorted set would contain[-1 1]
which we would scan and stop at-1
, and thus return0
.If the user then came back and "filled the gap" a submitted a tx with nonce 0, the set would now contain
[-1 0 1]
and we would return2
as the transaction count.The text was updated successfully, but these errors were encountered: