Multisig Revamp for StructuredData/AppendableData

Part 0 - Usability:

We will refer to Structured or Appendable Data as ShareableData for the purpose of this discussion as it concerns only the ownership aspects.

The present ownership evaluation by vaults is impractical for ownership sharing.

  1. Let S be the ShareableData created and thus owned by a. If a wants to share it with b, c, d and e so that it would have a total of 5 owners now, it needs to add their sign::PublicKey (henceforth sPK) and itself too to the current-owners field while also adding itself to previous-owners field too for vaults to grant ownership to all 5.

  2. If any of them wanted to modify S they would need to circulate it to al-least 3 others before the data was finally POST'd to the network else vaults would invalidate the update as an InvalidSuccessor. While this may be useful for certain cases, it is completely impractical for many others. E.g. if S was a shared-dir it is meaningless to expect majority to agree each time anyone wants to make changes. Also circulation would be out-of-band to the actual POST operation implying there is no certainty when it would be done (as it depends on a conscious decision of other parties).

  3. Once successfully shared, b, c, d and e could agree among themselves to remove a out of ownership. This again may not represent all the use cases as in many you would want the original owner/creator a to be incharge of ownership revocation.

Point (2) is the main one here. I’ll provide a baseline structure addressing it from where we can flag off our discussions. A weight-age system seems to be a nice starting point. This (as far as I am aware of) was originally hinted by @Fraser. Putting that idea along with a few others to address other points too together:

struct Owner {
    key: sPK,
    data_modification_weight: f32, // [0, 100] => 0% to 100%
    new_owner_add_weight: f32, // [0, 100]% - If this owner is allowed to grant ownership to others
    prev_owner_alter_weight: f32, // [0, 100]% - If this owner is allowed to revoke OR modify ownership of others 
}
    

ShareableData {
    //  .... other fields ...
    current_owners: HashSet<Owner>,
    prev_owners: HashSet<Owner>,
    signatures: HashSet<sign::Signature>,
}

The vault’s would check signatures would be:

  • If data field is modified: Total current owners in the copy of ShareableData present with the vault = n. This must be equal to either prev_owners in incoming data OR current_owners if the prev_owners is empty (Nothing different so far, just like the current implementation). Start checking signatures. As you validate singature of a particular owner, keep summing up data_modification_weight for that owner to the previous value.
  • Similarly if it is detected that there is an addition of new Owner check for corresponding weightage.
  • Finally if it is detected that there is an deletion of an existing Owner check for corresponding weightage.

Roughly:

let data_modified: bool = check_this();
let new_owners_added: bool = check_this(); // diff current_owners with previous_owners.
let prev_owners_removed: bool = check_this(); // diff current_owners with previous_owners.
let prev_owners_modified: bool = check_this(); // diff current_owners with previous_owners.
let prev_owners_altered = prev_owners_removed || prev_owners_modified;

let mut total_data_vote = 0;
let mut total_owner_add_vote = 0;
let mut total_owner_alter_vote = 0;

for owner in &stored_S.current_owners {
    if owner_has_signed_the_incoming_S {
         if data_modified && total_data_vote < 100 {
             total_data_vote += owner.data_modification_weight;
         }
         if new_owners_added && total_owner_add_vote < 100 {
             total_owner_add_vote += owner.new_owner_add_weight;
         }
         if prev_owners_altered && total_owner_alter_vote < 100 {
             total_owner_alter_vote += owner.prev_owner_alter_weight;
         }
     }
}
if data_modified && total_data_vote < 100 ||
   new_owners_added && total_owner_add_vote < 100 ||
   prev_owners_altered && total_owner_alter_vote < 100 {
     return Err(MutationError::InvalidSuccessor);
}
// ... Continue whatever it currently does

When you add an owner (POST operation, {For PUTs vaults don’t evaluate anything}), the following 3 fields:

new_owner_add_weight: f32,
prev_owner_alter_weight: f32,

must be 0. To make it non-0 for that new owner a fresh post must be required. This is to prevent misuse in which you can add new owner and form alliance with them to oust an existing one. Say a had 100% weight in eveything but b and c had 100 % for adding new owners but 40% each for removal. They could easily add a new owner d, give him > 20 % revocation power and oust a as b, c and d would be able to. To prevent this misuse, all weights apart from data-modification which is not as serious, should be 0 for new owner.

This design has great flexibility and answers many more problems than the current one.

  • For those who want to keep it simple and retain ownership would essentially grant 0 weight to the new owners they add except perhaps for the data field - e.g. private share by someone - this itself could be a major use case - One wouldn’t have to circulate data as each could have 100% weight for data-manipulation,
  • A particular forum owner a can add many people as moderators (who could add more moderators but not remove them) by giving them permission to add as 100% (unless a want to be involved too in decision making) and 0% as permission to remove etc.
  • For those who want more granularity, they can calculate the percentage accordingly.

I hope this provides some starting point from where we can take things further - chop things off (if we think it is complicated) or add to it or modify according to taste.

@nbaksalyar @madadam @Fraser @AndreasF @dirvine @Viv @vinipsmaker @Krishna @Qi_Ma (feel free to tag more if i missed someone).

8 Likes