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

Mark transaction as tainted #5310

Open
wants to merge 32 commits into
base: main
Choose a base branch
from

Conversation

Janislav
Copy link
Contributor

@Janislav Janislav commented Oct 2, 2024

Pull Request

Closes: PRO-1664

Checklist

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

  • I am confident that the code works.
  • I have written sufficient tests.
  • I have written and tested required migrations.
  • I have updated documentation where appropriate.

Summary

  • Added the functionality to mark a transaction as tainted as a broker or LP.
  • Check transactions when we process the ingress and stop if the channel is marked as tainted.
  • Saving tainted transaction details to refund it later.

Non-Breaking changes

If this PR includes non-breaking changes, select the non-breaking label. On merge, CI will automatically cherry-pick the commit to a PR against the release branch.

- Extended DepositChannelDetails with owner field
- Added extrinsic to mark transaction as tainted
- Handling deposit and save details for a refund if tx is tainted
- Added tests to verify that tainted transactions can get detected for all possible swap types
- Added tests  to check that txs marked by other brokers are getting ignored
Copy link

codecov bot commented Oct 2, 2024

Codecov Report

Attention: Patch coverage is 87.54209% with 37 lines in your changes missing coverage. Please review.

Project coverage is 71%. Comparing base (33eb5eb) to head (e9ae4a7).

Files with missing lines Patch % Lines
state-chain/pallets/cf-ingress-egress/src/lib.rs 66% 15 Missing and 2 partials ⚠️
...ate-chain/pallets/cf-ingress-egress/src/weights.rs 0% 14 Missing ⚠️
state-chain/runtime/src/chainflip.rs 0% 4 Missing ⚠️
...ess/src/migrations/add_owner_to_channel_details.rs 99% 1 Missing ⚠️
state-chain/pallets/cf-lp/src/lib.rs 94% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@          Coverage Diff           @@
##            main   #5310    +/-   ##
======================================
- Coverage     71%     71%    -0%     
======================================
  Files        490     491     +1     
  Lines      85209   85327   +118     
  Branches   85209   85327   +118     
======================================
+ Hits       60659   60682    +23     
- Misses     21839   21922    +83     
- Partials    2711    2723    +12     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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.

Some early comments.

Comment on lines 546 to 547
<T::TargetChain as Chain>::DepositDetails,
TaintedTransactionDetails<T::AccountId>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Consider what happens if same tx is reported twice by different parties.

I think we might need a double-map.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point

state-chain/pallets/cf-ingress-egress/src/lib.rs Outdated Show resolved Hide resolved
state-chain/pallets/cf-ingress-egress/src/lib.rs Outdated Show resolved Hide resolved
state-chain/traits/src/liquidity.rs Outdated Show resolved Hide resolved
- Taking refund address if we open a deposit channel as lp
- Extended ChannelAction to take an optional refund address
- Removed all dependencies regarding the LpRegistration trait (added last commit)
- Refactored tests, benchmarks, etc
@Janislav Janislav marked this pull request as ready for review October 7, 2024 11:12
@Janislav Janislav requested a review from kylezs as a code owner October 7, 2024 11:12
@Janislav
Copy link
Contributor Author

Janislav commented Oct 7, 2024

Still working on the benchmark. It's written, but there is something odd with the way we generate the weights.

@@ -724,6 +724,7 @@ pub trait DepositApi<C: Chain> {
lp_account: Self::AccountId,
source_asset: C::ChainAsset,
boost_fee: BasisPoints,
refund_address: Option<ForeignChainAddress>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should not be optional.

If the LP hasn't registered a refund address, they can't open a channel, so we should always have this.

state-chain/pallets/cf-lp/src/lib.rs Outdated Show resolved Hide resolved
state-chain/pallets/cf-ingress-egress/src/lib.rs Outdated Show resolved Hide resolved
state-chain/pallets/cf-ingress-egress/src/lib.rs Outdated Show resolved Hide resolved
Comment on lines 1336 to 1338
let is_lp =
T::AccountRoleRegistry::has_account_role(&account_id, AccountRole::LiquidityProvider);
ensure!(is_broker || is_lp, BadOrigin);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually I'm not sure we want/need LPs to mark transactions as tainted. We need their deposit address in case a tx is marked, but in general they won't be marking their own.

We will probably add another account role or similar for the 'reporter' role, but that can be in a future PR. For now we can remove the LP here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd also suggest unwrapping the origin and doing permission checks in the extrinsic rather than in this inner method. Might make testing/benchmarking easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

"Inner" was a more temporary solution since we only wanted to support BTC for now and that would open a whole new number of problems with tests and benchmarks. Since I think it could make sense to support at least ETH as well, we can do this properly and the inner function warp can disappear. In general, I think we should try to benchmark as close as possible to be on the safe side.

Comment on lines 1340 to 1345
broker: account_id.clone(),
refund_address: None,
deposit_witness: None,
expires_at: <frame_system::Pallet<T>>::block_number()
.saturating_add(BlockNumberFor::<T>::from(TAINTED_TX_EXPIRATION_BLOCKS)),
marked_for_refund: false,
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 it would be clearer/safer/more efficient if we split this into two storage items:

// in a map of AccountId -> TxId -> TaintedTransactionDetails
struct TaintedTransactionDetails {
	// I don't think we need this, it's already in the key of the map:
	// reporter: AccountId,
	expires_at: BlockNumber,
}

// in a value of Vec<RejectionDetails>
struct RejectionDetails {
	refund_address: Address,
	deposit_witness: DepositWitness,
}

This avoids having to deal with the Options and filter against marked_for_refund etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think we need DepositWitness tbh. Definitely not for BTC (tx_id is enough here) and for ETH we need other stuff I (refund_address, asset, amount). Because we need to pass this information to the API call, I think we're going to end up to define a new type for that anyway. I would go for now with something static that works for ETH/BTC and extend the type as we go or make generic for the chain.

state-chain/pallets/cf-ingress-egress/src/lib.rs Outdated Show resolved Hide resolved
state-chain/pallets/cf-ingress-egress/src/lib.rs Outdated Show resolved Hide resolved
state-chain/pallets/cf-ingress-egress/src/lib.rs Outdated Show resolved Hide resolved
@dandanlen
Copy link
Collaborator

Also please remember to rebase against main to pick up the new compiler version.

#[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, TypeInfo, CloneNoBound)]
#[scale_info(skip_type_params(T, I))]
pub struct TaintedTransactionDetails<T: Config<I>, I: 'static> {
pub refund_address: Option<ForeignChainAddress>,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Until refund parameters are optional, this has to stay optional. We can change it after this is done.

Copy link
Collaborator

Choose a reason for hiding this comment

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

But we can't refund anything if there is no refund address?

Doesn't it make more sense to make it required here, and handle the case where we don't have it before storing this value?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't believe it doesn't make any difference other than having to deal with less complex code if we go with the option variant. In the point of the swap flow where we have (or have not) the refund address, it's already too late to do anything else than saving what we have and exit the swap logic. What do you want to save if, instead, if there is just no address? The solution is to make the refund parameters a requirement, so this can not happen, but since this is not done, yet we go with an option here and replace it after @msgmaxim has solved this in his PR.

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.

Some minor nits but I think it's nearly ready.

Don't worry about the version bump CI check - should go away when #5327 is merged.

Comment on lines +795 to +796
for (account, tx_id, expire_block) in TaintedTransactions::<T, I>::iter() {
if expire_block <= now {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't like having to iterate through all of the TaintedTransactions just to see if any have expired (99% of the time this will return nothing). It would be good to think of a better way to do this.

Comment on lines +1898 to +1900
let channel_owner = deposit_channel_details.owner.clone();

if TaintedTransactions::<T, I>::take(channel_owner.clone(), deposit_details.clone())
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
let channel_owner = deposit_channel_details.owner.clone();
if TaintedTransactions::<T, I>::take(channel_owner.clone(), deposit_details.clone())
if TaintedTransactions::<T, I>::take(&channel_owner, &deposit_details)

#[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, TypeInfo, CloneNoBound)]
#[scale_info(skip_type_params(T, I))]
pub struct TaintedTransactionDetails<T: Config<I>, I: 'static> {
pub refund_address: Option<ForeignChainAddress>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

But we can't refund anything if there is no refund address?

Doesn't it make more sense to make it required here, and handle the case where we don't have it before storing this value?

_,
Identity,
T::AccountId,
Twox64Concat,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Twox64Concat,
Blake2_128Concat,

DepositDetails can be freely set by the caller, so we need to be defensive here.

Comment on lines +32 to +33
for (account, channel_details) in old::DepositChannelLookup::<T, I>::drain() {
let dummy_account = T::AccountId::decode(&mut &[0u8; 32][..]).unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Prefer to use translate rather than drain+insert. According to the docs, inserting during iteration can cause unwanted side effects.

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