-
Notifications
You must be signed in to change notification settings - Fork 15
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
feature/PRO-819/broadcast-confirmation-for-evm-transactions #4044
feature/PRO-819/broadcast-confirmation-for-evm-transactions #4044
Conversation
PRO-819 Broadcast confirmation for EVM transactions
When we request a transaction broadcast for EVM, we are trusting the validators to sign and send a transaction without tampering. We also set a very high cap on the gas limit for most transactions (15M gas). There is a possible attack vector whereby a validator could create a 'forwarding' contract that consumes any excess gas up to the limit, and forwards the calldata to the chainflip contract. The net effect would be that the KeyManager emits the correct event and we witness the transaction as succeeded, and register the consumed gas to be refunded to the validator. A validator could use this to drain funds from the vault (assuming we do refund the validator, which is something we intend to do!). As a solution, we should re-instate the signed transaction checks for these cases: in order to become whitelisted for a fee refund, a validator must prove that they signed the specific transaction without altering the transaction details. (Specific transaction details for the evm case are Initial outline here: |
Codecov Report
@@ Coverage Diff @@
## main #4044 +/- ##
=======================================
- Coverage 72% 72% -1%
=======================================
Files 366 369 +3
Lines 57530 59497 +1967
Branches 57530 59497 +1967
=======================================
+ Hits 41585 42683 +1098
- Misses 13858 14690 +832
- Partials 2087 2124 +37
... and 91 files with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
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.
Sorry, took me a while to to get round to looking at this. I think there are a few issues. I doubt it works right now.
// If the signature is valid, we can remove the transaction from storage | ||
Transaction::<T, I>::remove(broadcast_attempt_id.broadcast_id); | ||
// And mark the broadcast as validated | ||
BroadcastValidated::<T, I>::insert(broadcast_attempt_id.broadcast_id, ()); |
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.
We need to save the hash here so we can compare it at the broadcast success stage.
signature: Vec<u8>, | ||
tx_hash: H256, | ||
) -> Result<(), TransactionVerificationError> { | ||
let recovered = Self::recover_transaction(&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.
It's not possible to recover a transaction from a signature.
) -> Result<(), TransactionVerificationError> { | ||
let recovered = Self::recover_transaction(&signature)?; | ||
let hash = Self::recover_hash(recovered.clone()); | ||
ensure!(hash == tx_hash, TransactionVerificationError::InvalidTransactionHash); |
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.
We need to do this after broadcast, not before.
broadcast_attempt_id, | ||
transaction: transaction_payload.clone(), | ||
transaction_signature: eth_rpc.sign_transaction(transaction_payload).await?.to_vec(), | ||
transaction_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.
We don't need to submit this here.
transaction: transaction_payload.clone(), | ||
transaction_signature: eth_rpc.sign_transaction(transaction_payload).await?.to_vec(), |
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.
Here want the raw signed payload. The steps to get this are something like:
let transaction_request = Eip1559TransactionRequest::from(transaction_payload);
let signature = eth_rpc.sign_transaction(transaction_request).await?;
let typed_transaction = TypedTransaction::from(transaction_request);
let raw_signed_payload = typed_transaction.rlp_signed(&signature);
@@ -192,6 +202,13 @@ pub mod pallet { | |||
/// The save mode block margin | |||
type SafeModeBlockMargin: Get<BlockNumberFor<Self>>; | |||
|
|||
/// The thing thats validates the transaction | |||
type TransactionValidator: TransactionValidator< |
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.
The trait could be simpler: TransactionValidator<C: Chain>
.
TransactionFeeDeficit::<T, I>::mutate(signer_id, |fee_deficit| { | ||
*fee_deficit = fee_deficit.saturating_add(to_refund); | ||
}); | ||
if let Some(_) = BroadcastValidated::<T, I>::take(broadcast_id) { |
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 is where we need to check the tx hash.
state_chain_runtime::RuntimeCall::EthereumBroadcaster( | ||
pallet_cf_broadcast::Call::confirm_broadcast_attempt { | ||
broadcast_attempt_id, | ||
transaction: transaction_payload.clone(), |
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.
We are just resubmitting the same transaction that was emitted in the event. It needs to be the transaction that was actually signed. (actually the signed rlp payload, see the other comment).
Please hold up before fixing this. There might be a simpler way. (See Linear) |
Okay. I start a new PR then. |
Closing this one now. Started a new one: #4078 |
Pull Request
Closes: PRO-xxx
Checklist
Please conduct a thorough self-review before opening the PR.
Summary
Please include a succinct description of the purpose and content of the PR. What problem does it solve, and how? Link issues, discussions, other PRs, and anything else that will help the reviewer.