# Testing Scenarios In the scenarios, for simplicity, we call the chains Kusama (KSM token) and Polkadot (DOT token), but they should be applicable to any other chains. The first scenario has detailed description about the entire process (also see the [sequence diagram](./scenario1.html)). Other scenarios only contain a simplified interaction focusing on things that are unique for that particular scenario. Notation: - kX - user X interacting with Kusama chain. - `k(kX)` - Kusama account id of user kX (native account id; usable on Kusama) - `p(kX)` - Polkadot account id of user kX (account id derived from `k(kX)` usable on Polkadot) - [Kusama] ... - Interaction happens on Kusama (e.g. the user interacts with Kusama chain) - [Polkadot] ... - Interaction happens on Polkadot Basic Scenarios =========================== Scenario 1: Kusama's Alice receiving & spending DOTs --------------------------- Kusama's Alice (kAlice) receives 5 DOTs from Polkadot's Bob (pBob) and sends half of them to kCharlie. 1. Generate kAlice's DOT address (`p(kAlice)`). See function: ```rust bp_runtime::derive_account_id(b"pdot", kAlice) ``` or: ```rust let hash = bp_polkadot::derive_kusama_account_id(kAlice); let p_kAlice = bp_polkadot::AccountIdConverter::convert(hash); ``` 2. [Polkadot] pBob transfers 5 DOTs to `p(kAlice)` 1. Creates & Signs a transaction with `Call::Transfer(..)` 1. It is included in block. 1. kAlice observers Polkadot chain to see her balance at `p(kAlice)` updated. 3. [Kusama] kAlice sends 2.5 DOTs to `p(kCharlie)` 1. kAlice prepares: ```rust let call = polkadot::Call::Balances(polkadot::Balances::Transfer(p(kCharlie), 2.5DOT)).encode(); let weight = call.get_dispatch_info().weight; ``` 1. kAlice prepares Kusama transaction: ```rust kusama::Call::Messages::::send_message( // dot-transfer-lane (truncated to 4bytes) lane_id, payload: MessagePayload { // Get from current polkadot runtime (kind of hardcoded) spec_version: 1, // kAlice should know the exact dispatch weight of the call on the target // source verifies: at least to cover call.length() and below max weight weight, // simply bytes, we don't know anything about that on the source chain call, // origin that should be used during dispatch on the target chain origin: CallOrigin::SourceAccount(kAlice), }, delivery_and_dispatch_fee: { (single_message_delivery_weight // source weight = X * target weight + convert_target_weight_to_source_weight(weight) + confirmation_transaction_weight ) // This uses an on-chain oracle to convert weights of the target chain to source fee * weight_to_fee // additional reward for the relayer (pallet parameter) + relayers_fee }, ) ``` 1. [Kusama] kAlice sends Kusama transaction with the above `Call` and pays regular fees. The dispatch additionally reservers target-chain delivery and dispatch fees (including relayer's reward). 4. [Kusama] kAlice's transaction is included in block `B1` ### Syncing headers loop 5. Relayer sees that `B1` has not yet been delivered to the target chain. [Sync loop code](https://github.com/paritytech/parity-bridges-common/blob/8b327a94595c4a6fae6d7866e24ecf2390501e32/relays/headers-relay/src/sync_loop.rs#L199). 1. Relayer prepares transaction which delivers `B1` and with all of the missing ancestors to the target chain (one header per transaction). 1. After the transaction is succesfully dispatched the Polkadot on-chain light client of the Kusama chain learns about block `B1` - it is stored in the on-chain storage. ### Syncing finality loop 8. Relayer is subscribed to finality events on Kusama. Relayer gets a finality notification for block `B3`. 1. The header sync informs the target chain about `B1..B3` blocks (see point 6). 1. Relayer learns about missing finalization of `B1..B3` on the target chain, see [finality maintenance code](https://github.com/paritytech/parity-bridges-common/blob/8b327a94595c4a6fae6d7866e24ecf2390501e32/relays/substrate/src/headers_maintain.rs#L107). 1. Relayer submits justification for `B3` to the target chain (`finalize_header`). See [#421](https://github.com/paritytech/parity-bridges-common/issues/421) for multiple authority set changes support in Relayer (i.e. what block the target chain expects, not only what I have). Relayer is doing two things: - syncing on demand (what blocks miss finality) - and syncing as notifications are received (recently finalized on-chain) 1. Eventually Polkadot on-chain light client of Kusama learns about finality of `B1`. ### Syncing messages loop 13. The relayer checks the on-chain storage (last finalized header on the source, best header on the target): - Kusama outbound lane - Polkadot inbound lane Lanes contains `latest_generated_nonce` and `latest_received_nonce` respectively. The relayer syncs messages between that range. 1. The relayer gets a proof for every message in that range (using the RPC of messages module) 1. The relayer creates a message delivery transaction (but it has weight, size, and count limits). The count limit is there to make the loop of delivery code bounded. ```rust receive_message_proof( relayer_id, // account id of the source chain proof, // messages + proofs (hash of source block `B1`, nonces, lane_id + storage proof) dispatch_weight // relayer declares how much it will take to dispatch all messages in that transaction, ) ``` The `proof` can also contain an update of outbound lane state of source chain, which indicates the delivery confirmation of these messages and reward payment, so that the target chain can truncate its unpayed rewards vector. The target chain stores `relayer_ids` that delivered messages because the relayer can generate a storage proof to show that they did indeed deliver those messages. The reward is paid on the source chain and we inform the target chain about that fact so it can prune these `relayer_ids`. It's totally fine if there are no messages, and we only include the reward payment proof when calling that function. 1. 🥳 the message is now delivered and dispatched on the target chain! 1. The relayer now needs to confirm the delivery to claim her payment and reward on the source chain. 1. The relayer creates a transaction on the source chain with call: ```rust receive_messages_delivery_proof( proof, // hash of the finalized target chain block, lane_id, storage proof ) ``` ### UI challenges - The UI should warn before (or prevent) sending to `k(kCharlie)`! Scenario 2: Kusama's Alice nominating validators with her DOTs --------------------------- kAlice receives 10 DOTs from pBob and nominates `p(pCharlie)` and `p(pDave)`. 1. Generate kAlice's DOT address (`p(kAlice)`) 2. [Polkadot] pBob transfers 5 DOTs to `p(kAlice)` 3. [Kusama] kAlice sends a batch transaction: - `staking::Bond` transaction to create stash account choosing `p(kAlice)` as the controller account. - `staking::Nominate(vec![p(pCharlie)])` to nominate pCharlie using the controller account. Scenario 3: Kusama Treasury receiving & spending DOTs --------------------------- pBob sends 15 DOTs to Kusama Treasury which Kusama Governance decides to transfer to kCharlie. 1. Generate source account for the treasury (`kTreasury`). 2. [Polkadot] pBob tarnsfers 15 DOTs to `p(kTreasury)`. 2. [Kusama] Send a governance proposal to send a bridge message which transfers funds to `p(kCharlie)`. 3. [Kusama] Dispatch the governance proposal using `kTreasury` account id. Extra scenarios =========================== Scenario 4: Kusama's Alice setting up 1-of-2 multi-sig to spend from either Kusama or Polkadot --------------------------- Assuming `p(pAlice)` has at least 7 DOTs already. 1. Generate multisig account id: `pMultiSig = multi_account_id(&[p(kAlice), p(pAlice)], 1)`. 2. [Kusama] Transfer 7 DOTs to `pMultiSig` using `TargetAccount` origin of `pAlice`. 3. [Kusama] Transfer 2 DOTs to `p(kAlice)` from the multisig: - Send `multisig::as_multi_threshold_1(vec![p(pAlice)], balances::Transfer(p(kAlice), 2))` Scenario 5: Kusama Treasury staking & nominating validators with DOTs --------------------------- Scenario 6: Kusama Treasury voting in Polkadot's democracy proposal --------------------------- Potentially interesting scenarios =========================== Scenario 7: Polkadot's Bob spending his DOTs by using Kusama chain --------------------------- We can assume he holds KSM. Problem: he can pay fees, but can't really send (sign) a transaction? Shall we support some kind of dispatcher? Scenario 8: Kusama Governance taking over Kusama's Alice DOT holdings --------------------------- We use `SourceRoot` call to transfer her's DOTs to Kusama treasury. Source chain root should also be able to send messages as `CallOrigin::SourceAccount(Alice)` though.