Skip to content
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

Conversation

Janislav
Copy link
Contributor

Pull Request

Closes: PRO-xxx

Checklist

Please conduct a thorough self-review before opening the PR.

  • I am confident that the code works.
  • I have updated documentation where appropriate.

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.

@linear
Copy link

linear bot commented Sep 22, 2023

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

See https://github.com/chainflip-io/chainflip-backend/blob/chore/mainnet-ccm-gaslimit-test/state-chain/chains/src/evm.rs#L422)

Initial outline here:

#3968

@codecov
Copy link

codecov bot commented Sep 22, 2023

Codecov Report

Merging #4044 (151b53e) into main (4b2d251) will decrease coverage by 1%.
Report is 33 commits behind head on main.
The diff coverage is 8%.

❗ Current head 151b53e differs from pull request most recent head 1e53f6b. Consider uploading reports for the commit 1e53f6b to get more accurate results

@@           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     
Files Coverage Δ
state-chain/chains/src/lib.rs 40% <ø> (ø)
state-chain/chains/src/mocks.rs 59% <ø> (ø)
state-chain/chains/src/none.rs 0% <ø> (ø)
state-chain/runtime/src/lib.rs 39% <ø> (-<1%) ⬇️
engine/src/eth/rpc.rs 0% <0%> (ø)
state-chain/chains/src/btc.rs 85% <0%> (+1%) ⬆️
state-chain/chains/src/dot.rs 41% <0%> (-<1%) ⬇️
state-chain/pallets/cf-broadcast/src/mock.rs 90% <60%> (-3%) ⬇️
state-chain/chains/src/eth.rs 65% <0%> (-7%) ⬇️
engine/src/state_chain_observer/sc_observer/mod.rs 36% <0%> (-1%) ⬇️
... and 3 more

... and 91 files with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@Janislav Janislav changed the title Feature/pro 819/broadcast confirmation for evm transactions feature/PRO-819/broadcast-confirmation-for-evm-transactions Oct 4, 2023
Copy link
Collaborator

@dandanlen dandanlen left a 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, ());
Copy link
Collaborator

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)?;
Copy link
Collaborator

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);
Copy link
Collaborator

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,
Copy link
Collaborator

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.

Comment on lines +516 to +517
transaction: transaction_payload.clone(),
transaction_signature: eth_rpc.sign_transaction(transaction_payload).await?.to_vec(),
Copy link
Collaborator

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<
Copy link
Collaborator

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) {
Copy link
Collaborator

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(),
Copy link
Collaborator

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).

@dandanlen
Copy link
Collaborator

Please hold up before fixing this. There might be a simpler way. (See Linear)

@Janislav
Copy link
Contributor Author

Janislav commented Oct 6, 2023

Okay. I start a new PR then.

@Janislav
Copy link
Contributor Author

Janislav commented Oct 6, 2023

Closing this one now. Started a new one: #4078

@Janislav Janislav closed this Oct 6, 2023
@ahasna ahasna deleted the feature/PRO-819/broadcast-confirmation-for-evm-transactions branch May 23, 2024 13:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants