tangle-network / protocol-substrate

Webb protocol implementation in Substrate.
https://docs.webb.tools/v1/anchor-system/overview/
Apache License 2.0
37 stars 11 forks source link

[SPEC] Proposals and their pallet flow #142

Open akileshtangella opened 2 years ago

akileshtangella commented 2 years ago

Types

More on r_id's

r_id's serve two purposes. Let's take the example of an anchor-update.

  1. There is a r_id to method name mapping called Resources on the signature-bridge.
  2. On the anchor-handler pallet, there is a mapping called AnchorList that maps r_id's to tree_id's. This is how the update method knows which anchor to update. Therefore, the r_id should contain some uniquely identifiable information about the tree_id (or the tree_id itself). Don't think putting just the tree_id will be enough since it just an integer...may not be unique enough. Might want to do something like the world 'ANCHOR" concatenated with the tree_id.

Overarching Schema of Proposal Data

Proposal Data:

Terminology: We will call the (r_id, zeroes, nonce) as the proposal header. The proposal header is a total of 40 bytes. We add 4 bytes of zeroes padding to match the length of the EVM/Solidity proposal header. On the EVM/Solidity side, these 4 bytes are taken up by the functionSig.

See how execute_proposal works (including pseudocode) in the comment below.

List of Proposals

1. Set Wrapping Fee Proposal Pallet Flow: bridge/signature-bridge -> token-wrapper-handler -> token-wrapper Proposal Data: (r_id, zeroes, nonce, call) Total Bytes: 40 + (size of call) Call Structure: Call::TokenWrapperHandler(Call::execute_wrapping_fee_proposal { r_id, wrapping_fee_percent, into_pool_share_id })

2. Add Token to Pool Share Proposal Pallet Flow: bridge/signature-bridge -> token-wrapper-handler -> token-wrapper -> asset-registry Proposal Data: (r_id, zeroes, nonce, call) Total Bytes: 40 + (size of call) Call Structure: Call::TokenWrapperHandler(Call::execute_add_token_to_pool_share { r_id, name, asset_id })

3. Remove Token from Pool Share Proposal Pallet Flow: bridge/signature-bridge -> token-wrapper-handler -> token-wrapper -> asset-registry Proposal Data: (r_id, zeroes, nonce, call) Total Bytes: 40 + (size of call) Call Structure: Call::TokenWrapperHandler(Call::execute_remove_token_from_pool_share { r_id, name, asset_id })

4. Anchor Create Proposal Pallet Flow: bridge/signature-bridge -> anchor-handler -> anchor Proposal Data: (r_id, zeroes, nonce, call) Total Bytes: 40 + (size of call) Call Structure: Call::AnchorHandler(Call::execute_anchor_create_proposal { deposit_size, src_chain_id, r_id, max_edges, tree_depth, asset })

5. Anchor Update Proposal Pallet Flow: bridge/signature-bridge -> anchor-handler -> anchor Proposal Data: (r_id, zeroes, nonce, call) Total Bytes: 40 + (size of call) Call Structure: Call::AnchorHandler(Call::execute_anchor_update_proposal { r_id, anchor_metadata: EdgeMetadata { src_chain_id, root, latest_leaf_index } })

6. Register r_id Proposal Pallet Flow: signature-bridge/bridge Proposal Data: (r_id, zeroes, nonce, call) Total Bytes: 40 + (size of call) Call Structure:

7. Set fee recipient proposal Pallet Flow: signature-bridge -> token-wrapper-handler -> token-wrapper Proposal Data: (r_id, zeroes, nonce, call) Total Bytes: 40 + (size of call) Call Structure:

8. Rescue Tokens Proposal Pallet Flow: signature-bridge -> token-wrapper-handler -> token-wrapper Proposal Data: (r_id, zeroes, nonce, call) Total Bytes: 40 + (size of call) Call Structure:

Questions/Comments/Issues

  1. How many bytes is a call?
  2. How many bytes is a T::AssetId? It seems to just be an integer, so 4 bytes should be enough to cover the different asset types we will encounter.
drewstone commented 2 years ago

Code examples would be useful here for parsing proposals and understanding how the verification will look from your perspective.

akileshtangella commented 2 years ago

Another idea:

We can use your idea of signing the call and heavily simplify things in the following way.

The proposal data for all the proposals listed above is simply:

(r_id, nonce, call) Total Bytes: 32 + 4 + (size of call) = 36 + (size of call)

The signature is the signature of this proposal data.

execute_proposal will then look like:

pub fn execute_proposal(
    origin: OriginFor<T>,
    src_id: T::ChainId,
    call: Box<<T as Config<I>>::Proposal>,
    proposal_data: Vec<u8>,
    signature: Vec<u8>,
) -> DispatchResultWithPostInfo {
    let _ = ensure_signed(origin)?;
    let r_id = parse_r_id_from_proposal_data(proposal_data);
    let nonce = parse_nonce_from_proposal_data(proposal_data);
    let call = parse_call_from_proposal_data(proposal_data); 

    ensure!(
        T::SignatureVerifier::verify(&Self::maintainer(), &proposal_data[..], &signature)
            .unwrap_or(false),
        Error::<T, I>::InvalidPermissions,
    );
    ensure!(Self::chain_whitelisted(src_id), Error::<T, I>::ChainNotWhitelisted);
    ensure!(Self::resource_exists(r_id), Error::<T, I>::ResourceDoesNotExist);

    // Ensure that the call and the r_id are consistent
    let call_method = parse_method_name_from_call(call);
    ensure!(call_method == Self::resources(r_id), Error::<T, I>::CallDoesNotMatchResourceId);

    // Ensure this chain id matches the r_id
    let execution_chain_id_type = parse_chain_id_type_from_r_id(r_id);
    ensure!(execution_chain_id_type == 
        T::ChainId::try_from(compute_chain_id_type(
        T::ChainIdentifier::get(),
        T::ChainType::get()
    )), Error<T,I>::IncorrectExecutionChainIdType);

    Self::finalize_execution(src_id, nonce, call)
}

The downside of this approach is it does not allow us to verify the data in the call against the proposal_data.

The only thing left to decide would be the structure of the r_id's.

drewstone commented 2 years ago

I also mean we should sign the entire proposal data + call (as in the proposal data contains the encoded call as well)

Nonetheless, that looks like a much better starting implementation for these updates. I would continue with an implementation of this firstly and then we can begin adding the relevant proposal tests.

dutterbutter commented 2 years ago

Related task list: https://github.com/webb-tools/protocol-substrate/issues/164