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

[SPEC] Proposals and their pallet flow #142

Open
akileshtangella opened this issue Feb 4, 2022 · 4 comments
Open

[SPEC] Proposals and their pallet flow #142

akileshtangella opened this issue Feb 4, 2022 · 4 comments
Labels
spec 🆕 Specification details for future implementation

Comments

@akileshtangella
Copy link
Contributor

akileshtangella commented Feb 4, 2022

Types

  • r_id (resource ID) - 32 byte string:
    • Last 6 bytes reserved for chain id type (2 bytes chain type + 4 bytes chain identifier)
    • Last adjacent 20 bytes are for ... (more on this in the next section).

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:

  • r_id: ResourceId (32 bytes)
  • zeroes: [u8, 4] (4 bytes)
  • nonce: T::ProposalNonce (4 bytes)
  • call (the length of this is proposal specific)

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

  • r_id is the r_id
  • wrapping_fee_percent is the new token wrapping fee
  • into_pool_share_id is the id of the pool share we are setting the wrapping fee for (recall we have wrapping fees per pool share)

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

  • r_id is the r_id
  • name is the name of the pool share
  • asset_id is the id of the asset being added to the pool share.

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

  • r_id is the r_id
  • name is the name of the pool share
  • asset_id is the id of the asset being removed from the pool share.

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

  • deposit_size is the denomination size of the anchor
  • src_chain_id is the id of the source chain
  • r_id is r_id
  • max_edges is the maximum number of anchors the created anchor can have an edge to
  • tree_depth is the depth of the Merkle tree maintained by the anchor
  • asset is the type of asset (CurrencyIdOf) that can be deposited into the created anchor

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

  • r_id is the r_id
  • src_chain_id is the id of the source chain
  • root is the new root of the Merkle tree
  • latest_leaf_index is the index of the latest inserted leaf (corresponds to the updated root above)

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

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

@akileshtangella
Copy link
Contributor Author

akileshtangella commented Feb 8, 2022

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

drewstone commented Feb 8, 2022

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

Related task list: #164

@dutterbutter dutterbutter added the spec 🆕 Specification details for future implementation label Sep 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
spec 🆕 Specification details for future implementation
Projects
Status: Not Started 🕧
Development

No branches or pull requests

3 participants