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

Claim funds on Substrate chain by providing proof of funds locking on PoA chain #91

Merged
merged 143 commits into from
Jun 5, 2020

Conversation

svyatonik
Copy link
Contributor

@svyatonik svyatonik commented May 15, 2020

So there's new module - modules/currency-exchange, which has one entry point:

		pub fn import_peer_transaction(
			origin,
			transaction: <<T as Trait>::PeerBlockchain as Blockchain>::Transaction,
			block: <<T as Trait>::PeerBlockchain as Blockchain>::BlockHash,
			proof: <<T as Trait>::PeerBlockchain as Blockchain>::TransactionInclusionProof,
		) -> DispatchResult;

It checks whether provided tx is known to the 'bridge' module and its block is finalized, then it 'parses' that tx (for PoA -> Substrate transactions that means decoding sender, to, nonce, value and data fields + verifies that it is the tx sent to pre-configured address) + maps from this transaction to local Substrate chain receiver (in current impl, the tx mush have encoded Substrate' account id in its data field, as Tomek has suggested) + maps between currencies (currently 1:1) + grants given amount to given receiver.

/// Verify that transaction is included into given finalized block.
pub fn verify_transaction_finalized<S: Storage>(
storage: &S,
block: H256,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
block: H256,
block_hash: H256,

svyatonik and others added 9 commits June 2, 2020 10:16
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
}

// check if header is actually finalized
let is_finalized = match header.number < finalized_number {
Copy link
Contributor

Choose a reason for hiding this comment

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

Clippy would be mad if I didn't say anything :P
https://rust-lang.github.io/rust-clippy/master/index.html#match_bool

Copy link
Contributor

@HCastano HCastano left a comment

Choose a reason for hiding this comment

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

Tiny nits left over, but other than that it looks good!

T::DepositInto::deposit_into(recipient, amount).map_err(Error::<T>::from)?;

// remember that we have accepted this transfer
Transfers::<T>::insert(transfer_id, ());
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I was thinking about this when reviewing earlier, but I think the code is correct. To make it more future proof I'd suggest to group the two statements that are related into one block, like so:

let recipient = T::RecipientsMap::map(transaction.recipient).map_err(Error::<T>::from)?;
let amount = T::CurrencyConverter::convert(transaction.amount).map_err(Error::<T>::from)?;

// make sure to update the mapping if we deposit successfully to avoid double spending,
// i.e. whenever `deposit_into` is successful we MUST update `Transfers`.
{
    T::DepositInto::deposit_into(recipient, amount).map_err(Error::<T>::from)?;
    Transfers::<T>::insert(transfer_id, ())
}

This will make it harder to introduce ? statements in between deposit_into and Transfers::insert.

@svyatonik
Copy link
Contributor Author

One last problem that affects bridge and exchange modules combination is that now bridge may prune unfinalized headers. And since exchange only accepts proofs on finalized blocks, some claims may never be accepted (because headers may already be pruned and we don't have CHT). There are 3 possible solutions that came up:

  1. give some basic guarantees about claims - i.e. we only guarantee to accept claims that happened within last N finalized blocks. Pros: easy to implement. Cons: submitters have additional responsibilities + pruning window increases.
  2. allow claims on unfinalized blocks - i.e. if lock funds tx has been mined in PoA block N and current finalized PoA block is N - 10_000, then anyone can submit proof that tx has been included in block N (if headers is already accepted by the bridge). And then, when block N will be finalized by bridge, actually make the transfer. If some sibling of N is finalized, drop this claim. Pros: quite easy to implement + all required transactions may be submitted (almost) altogether. Cons: ???;
  3. construct CHTs when pruning + make required headers a part of proof-of-tx-inclusion. Pros: ???. Cons: large(r) and complex proofs + additional data that needs to be stored in bridge module.

I've implemented (1) option here by moving pruning strategy from bridge module to runtime level (that needs to be done anyway). So the solution is that we are not pruning ~24 hours of finalized blocks => the claimant have at least 24 hours to submit transaction. I think that is enough for initial launch, right?

What needs to be done in long term? I'm not sure. Option (2) seems almost ideal, but I remember that Tomek has mentioned CHTs in some other context. So if you have any thoughts on that - please share, so that we may file an issue about that.

@tomusdrw
Copy link
Contributor

tomusdrw commented Jun 4, 2020

I think that is enough for initial launch, right?
Yup, I think so.

allow claims on unfinalized blocks - i.e. if lock funds tx has been mined in PoA block N and current finalized PoA block is N - 10_000, then anyone can submit proof that tx has been included in block N.

I feel that claims on unfinalized blocks should be more expensive (in terms of weight cost), even exponentially expensive the more claims for unfinalized block there is. Otherwise we are risking claim spam on a block that potentially (or even most likely) is a fork block, but simply finality has stalled for a bit. Also this complicates cost of finalization quite a bit, cause now finalizing a header would need to perform the transfers. We could possibly do it lazily in on_initialize or require the users to enact transfers manually if the claim gets finalized, but that adds extra complexity and UX complications - the users now how to submit two transactions instead of one (could obviously be batched by some 3rd party though).
Given all these arguments, I feel that for convenient usage of option 2, using some 3rd party would be required anyway, and that doesn't really make that much of a difference compared to option 1 (like in theory, with 2-transaction approach, the 3rd party can't really censor the transaction completely, the enactment would just be delayed and would require an extra manual intervention).

I initially thought about option (3) as well, but without CHT - just storing Map<Number, Hash> forever and allow users to submit headers as part of the proof. Knowing the entire hash-chain also has other benefits - for instance we could easily do manual (but verifiable) rollback in case of bugs (simply submit enough pruned headers and reset last finalized block). CHT is probably another optimization on top of that, but I don't know how complicated it would be - maybe the implementation cost is not worth the gains (mid-term; cause long-term obviously minimizing the storage would be desirable).

So overall, let's start with Option 1, and have both Options 2 & 3 logged as possible "nice to have" improvements.

@HCastano HCastano merged commit 76ba7fd into master Jun 5, 2020
Rialto Release automation moved this from Pull Requests to Done Jun 5, 2020
@HCastano HCastano deleted the ethereum-exchange branch June 5, 2020 01:12
@HCastano
Copy link
Contributor

HCastano commented Jun 5, 2020

I assume that the discussions about fixing interaction between the exchange and ethereum pruning choices can be done in another PR, so I'm going to go ahead and merge this.

@svyatonik
Copy link
Contributor Author

svyatonik commented Jun 5, 2020

Yeah, thanks. I'll open PR and submit enhancement-issue once finality-cache PR is in.

TODO for myself - I think option (1) should have been described and implemented slightly differently. Instead of counting ~24hrs (20000 blocks) from best finalized PoA block, known to Substrate, we should leave (unpruned) every finalized PoA header in Substrate for at least ~24hrs. Example of why it is required:

  1. on PoA chain: authorities fail to finalize blocks [10_000; 50_000] - they need 1 additional signature to finalize all these blocks;
  2. on PoA chain: fund locks tx is at the block 10_000;
  3. on PoA chain: last required authority signs block 50_001;
  4. on Substrate chain: block 50_001 is imported and all headers in [10_000; ~50_000] range are marked for pruning (and in current impl header 10_000 is instantly pruned).

So the claimant has 0 possibility to present tx proof. And guarantees are not working.

The biggest problem is that we don't want to leave headers for 24hrs when we're still syncing. So probably rely on PoA timestamp (TBD)?

UPD: otoh, we do not want bridge to sync chain from the scratch, so disregard my note about "still syncing".

@tomusdrw
Copy link
Contributor

tomusdrw commented Jun 5, 2020

The biggest problem is that we don't want to leave headers for 24hrs when we're still syncing. So probably rely on PoA timestamp (TBD)?

Let's introduce an "admin" method to enabled/disable claims - that will allow us to prevent even a situation like this.
When the bridge matures we can simply set it to an empty account via governance decision.

svyatonik pushed a commit that referenced this pull request Jul 17, 2023
serban300 pushed a commit to serban300/parity-bridges-common that referenced this pull request Mar 27, 2024
… PoA chain (paritytech#91)

* ethereum exchange module

* continue

* continue

* added tests for exchange module

* moved

* remove println

* move again

* fixes

* removed redundant deps

* cargo fmt

* fund_locks_transaction_decode_works

* cargo fmt --all

* fix error processing

* added some tracing to bridge modules

* more tests

* more tests

* cargo fmt --all

* kovan.rs -> exchange.rs

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* added assumption doc

* Airdrop -> DepositInto

* AsIs -> Identity

* OnTransactionSubmitted

* Transfers::Key = Id

* typo

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* block+tx+proof -> proof { block, tx, proof }

* cargo fmt --all

* docs

* check <-> verify

* parse hex

* extracted exchange primitives to separate crate

* added docs to runtime::exchange module

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* typo

* Update modules/currency-exchange/Cargo.toml

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* add docs to currency-exchange module

* change tests names

* cargo fmt --all

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* fixed verify_transaction_finalized for siblings of finalized blocks

* cargo fmt --all

* added double spend note

* cargo fmt --all

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
serban300 pushed a commit to serban300/parity-bridges-common that referenced this pull request Apr 8, 2024
… PoA chain (paritytech#91)

* ethereum exchange module

* continue

* continue

* added tests for exchange module

* moved

* remove println

* move again

* fixes

* removed redundant deps

* cargo fmt

* fund_locks_transaction_decode_works

* cargo fmt --all

* fix error processing

* added some tracing to bridge modules

* more tests

* more tests

* cargo fmt --all

* kovan.rs -> exchange.rs

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* added assumption doc

* Airdrop -> DepositInto

* AsIs -> Identity

* OnTransactionSubmitted

* Transfers::Key = Id

* typo

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* block+tx+proof -> proof { block, tx, proof }

* cargo fmt --all

* docs

* check <-> verify

* parse hex

* extracted exchange primitives to separate crate

* added docs to runtime::exchange module

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* typo

* Update modules/currency-exchange/Cargo.toml

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* add docs to currency-exchange module

* change tests names

* cargo fmt --all

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update bin/node/runtime/src/exchange.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* fixed verify_transaction_finalized for siblings of finalized blocks

* cargo fmt --all

* added double spend note

* cargo fmt --all

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

3 participants