Skip to content

Privacy

Introduction

STRATO utilizes Private Chains to implement data privacy. Private Chains combine the audibility and verifiability of data stored on the blockchain with the ability to permission that data to different nodes in the network. Private chains operate similarly to the Main Chain - they have their own accounts and transactions which operate exclusively within their own space. All private chain data is only visible to the permissioned members of the chain. User accounts become members of a private chain by being added by existing members.

Data Visibility

Private chains connect their own private transactions to the Main Chain by putting a secure hash of a transaction into a block's transaction data. This allows the transactions and data on a private chain to be recorded on the main chain, but not identifiable by non-members. A user that does not have access to a Private Chain will only see the hashed data of the private chain, but the data will have no other indication of what transactions occurred on the private chain, or any other information about the chain such as its members or chain ID. This hash acts as an encrypted "stub" of the transaction on the main chain, indicating a transaction exists, but no more details are visible.

Private Chain Use Cases

Private chains enable privacy by allowing data to be privileged amongst users. As an example, an application might have three types of user roles - Administrators, Managers, and User (A standard app user). There is global app data that needs to be visible to all users, however there also needs to be data that is only visible to Admins or only Managers. This would be accomplished by organizing the chains as follows:

  • Main Chain
  • Contains all public application contracts
  • Administrator Private Chain
  • Contains all contracts containing data for Administrators.
  • Child of the Main Chain.
  • Manager Private Chain
  • Contains all contracts containing data for Managers.
  • Child of the Main Chain.

Since private chains enable data to be permissioned by a user's identity, private chains are also especially useful when dealing with data visibility between internal and external parties'. This is useful when an application must be capable of handling data visibility from multiple parties, who might not have the same levels of permissions on a given asset or agreement. An internal party might be a member of your own organization, or group, and an external party might be a member of the network able to see or interact with data of your own organization or group. Private chains could be used for external and internal data respectively:

  • External Chain
  • Contains data and contracts visible to external parties.
  • Internal Chain
  • Contains data and contracts visible to internal parties.

Private Chains in Smart Contracts

Since private chains are not a feature of standard Ethereum, they cannot be accessed or be interacted with from standard Solidity contracts compiled and executed with the EVM. You must use BlockApps SolidVM to use private chain functionality within smart contracts. SolidVM uses the account type to combine an account address and chain ID into a single type that allows an account on any chain to be referenced. The account type behaves similarly to the Solidity address type. Read more about the account type.

Node Synchronization

The STRATO P2P Protocol enables nodes to synchronize private chain data between its members. A node will only send and receive a private chain's data if a user account on it is currently a member of the chain. When a node sends a private transaction to STRATO, the full transaction data is only sent to the nodes of members of that chain, and not the entire network. The encrypted transaction stub is sent to the entire network to be inserted into a block. Non-member nodes do not validate transactions.

When a user is added as a member of a private chain, the STRATO P2P protocol will immediately initialize a synchronization between the node of the new user and the existing member nodes. This provides the new node with the data for the private chain. This includes all past transactions and state data for accounts on the chain. The node also receives a list of the current members of the chain in order to facilitate further transactions on this chain.

When a node is completely removed as a member of a private chain, the remaining member nodes will cease sending private transactions from this chain to the removed node. The node will still retain all past transactions from the chain that it already had. Since membership is associated with a member on a node, private chain information will continue to sync and be accessible to any account on a node as long as there is 1 or more member of a chain on that node. For this reason we recommend designing your network with this in mind. For the most secure usage of private chains, allocate one node to each user in your consortium.

Info

If a user is added as a member of a chain but they are not a member of its parent chain, the node will not sync chain data until it has been added as a member of the parent chain and a new transaction on the child chain has been sent through the network. Users must be added as members of a chain in ascending order of their depth.

If a user is removed as a member of a parent chain, but they are still a member of a child chain, they will cease receiving transactions for both parent and child chains. This follows the rule of a user needing to be a member of a parent chain to be a member of any of its children chains. The removal of membership from a chain "cuts ties" between the node and all of the chain's descendants.

Tip

User-level privacy is coming soon to STRATO, so be sure to keep up-to-date on the latest STRATO versions and check out the Release Notes frequently.

Chain Relationships

Private Chains are created as children of other chains. Children chains are also referred to as "nested chains" since they are nested below the current chain. A private chain is created as a child of a chain by declaring its Parent Chain when creating it. By default a private chain is created as a child of the main chain. STRATO supports arbitrary levels of chain nesting which enables granular data permissioning by creating more and more restrictions on chain memberships. Similarly, data can be isolated between chains at the same level/depth to create entirely different membership groups. Chain nesting builds a complex tree of chain relationships and therefore much of the terminology used for tree graphs is borrowed to describe private chain relationships.

Chain Relationship Diagram

Chain Components

A chain has the following properties:

  • Chain ID
  • Label
  • Members
  • Parent Chain
  • Creator

Chain ID

The chain ID is a unique 64-character long hexadecimal number generated when the chain is created. It is the hash of the metadata used to create the chain. For example a chain ID might look like: 0x4574c8c75d6e88acd28f7e467dac97b5C60c3838d9dad993900bdf402152228e. The chain ID is used within STRATO to reference contract accounts and other transactions that are a part of that private chain.

Label

The chain label is a user provided string used to identify it. Labels are useful when viewing different chains through a graphical user interface. Multiple chains may have the same label.

Members

A chain's members are the STRATO users that are a part of this chain. A user's membership of a chain is recorded with their address and enode address. A member of a chain is a STRATO user on a specific node. If a user wishes to access a private chain on a different node, they must be declared a member on that node.

User accounts have separate token balances on every chain. If gas in on in your network, make sure to grant each member enough tokens to make transactions. Members added at chain creation time can have a initial balance, however new members must be given a balance once they have been added to the chain.

Parent Chain

The parent of this chain.

Creator

The information about the user account that created this chain. This includes the account address, as well as the user's public key information.

Chain Access Rules

The following is a list of data access rules that apply to User and Contract Accounts:

  • Accounts must necessarily be a member of a chain's parent chain to be a member of this chain. All User Accounts on the network are members of the Main Chain.
  • Contract Accounts can only access data on an ancestor chain or itself.
  • Contract Accounts cannot access children, sibling, or cousin chains.
  • Contract Accounts cannot modify (directly or indirectly) the state of accounts on another chain.

Create a Private Chain

Create a new private chain with a provided governance contract.

A chain creation request body contains the following properties:

  • args : object
    • Any constructor args to pass to the governance contract.
    • An object containing key-value pairs for each argument.
  • members : array
    • The initial members of the chain.
    • An array of objects, each object containing only the address and enode of the member.
  • balances : array
    • The token balances for each initial member of the chain.
    • Only relevant when gas is enabled in your network, however the balances property must still be present in any request, regardless of gas being enabled or disabled.
  • contract : string
    • The name of governance contract of this chain.
    • Omitted when using a Code Pointer as the contract.
  • src : string
    • Governance contract source code.
    • Omitted when using a Code Pointer as the contract.
  • metadata : object
    • Optional
    • Metadata such as enabling contract history, or disabling contract indexing.
    • Specify VM used for the Governance Contract.
    • See API reference for more information about using metadata.
  • label : string
    • The label for this chain.
  • parentChain : string
    • Optional
    • The chain ID of this chain's parent chain.
    • Omitted when the parent chain is the Main Chain.
  • codePtr : object
    • Optional
    • Contains the keys account and name of a contract that will be used as the chain's governance contract.
    • Used in place of the contract and src arguments.
    • See Code Pointers.

Endpoint

POST https://<strato_address>/bloc/v2.2/chain

Example

This example uses the Auto-Approve Governance Contract. Since the AutoApprove contract does not take any constructor args, the request args are empty.

curl -X POST \
  -H "Authorization: Bearer <token>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
      "args": {},
      "members": 
        [
          {
            "address": <member_1_user_address>,
            "enode": <member_1_enode_address>
          },
          {
            "address": <member_2_user_address>,
            "enode" <member_2_enode_address>
          }
        ],
      "balances":
        [
          {
            "address": <member_1_user_address>,
            "balance": <member_1_balance>
          },
          {
            "address": <member_2_user_address>,
            "balance": <member_2_balance>
          }
        ],
      "contract": "AutoApprove",
      "src": <governance-src>,
      "metadata": {
        "history": "AutoApprove",
        "VM": "SolidVM"
      },
      "label": "MyPrivateChain"
    }' \
"https://<strato_address>/bloc/v2.2/chain"
const contractSrc = await importer.combine("AutoApprove.sol") // import Governance Contract from file system

const chainInfo = {
  label: "MyPrivateChain",
  src: contractSrc,
  args : {},
  members : [
    {
      address: member_1_user_address,
      enode: member_1_enode_address
    },
    {
      address: member_2_user_address,
      enode: member_2_enode_address
    }
  ],
  balances: [
    {
      address: member_1_user_address,
      balance: member_1_balance
    },
    {
      address: member_2_user_address,
      balance: member_2_balance
    },
  ]
} // declare chain information

const contractInfo = {
  name: "AutoApprove"
} // governance contract information

const chainId = await rest.createChain(stratoUser, chainInfo, contractInfo, options); // create the chain

Response

The chain ID of the newly created chain:

"4574c8c75d6e88acd28f7e467dac97b5C60c3838d9dad993900bdf402152228e"

Note

Hexadecimal values such as Chain ID and Address are returned from the STRATO API without the 0x prefix. Similarly these values are stored in the STRATO databases without the prefix, so there is no need to append this prefix to API queries.

Using Existing Contract Code

STRATO allows governance contracts to use Code Pointers to reference existing governance contracts that have already been used to create other private chains. A code pointer acts as a pointer to the code that exists at the referenced address, not as a copy of code. Since addresses may contain more than one contract (the account holds a code collection), the name of the contract at the address must also be provided. This allows for faster, more consistent, and more reliable private chain creation. Since the governance contract code is already accessible to STRATO, it does not need to reparse or recompile any new contract code. It also eliminates the need for users to individually manage governance contracts, instead new chains can be created with a proven reliable code that has already been written and used. Governance contracts that use code pointers allow for more consistent namespacing in Cirrus when using Contract Versioning and X.509 Identity. This is due to the fact that the code used is an actual reference to an address, not a copy of the code with this user's details. The Cirrus table for a code pointer contract will maintain the same name (prefixing the creator's organization/group) it had as the original creator, ensuring that the organization and group of the original creator is kept intact. This would be beneficial in applications where a user must create private chains that are permissioned to different organization than their own. By knowing the pointer to an existing governance contract for that organization, it allows external party to create a private chain that belongs to that organization.

As a security measure, code pointers can only be used by user accounts that have access to the chain that the original governance contract is on. Furthermore, code pointers cannot be used to create any other type of contract except the governance contract.

To use a pointer to existing code, provide the Contract Account address and name in a codePtr field of the chain creation payload. This is in place of the source and contract fields in the chain payload. Since code at an account may contain multiple contract definitions, the name must still be specified in the chain payload, as well as the codePtr object. The code referenced may be any contract already uploaded as long as it is accessible from the newly created chain.

Example

In this example, let there be an existing governance contract at some address that is on the Main Chain.

curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
      "args": {},
      "members": 
        [
          {
            "address": <member_1_user_address>,
            "enode": <member_1_enode_address>
          },
          {
            "address": <member_2_user_address>,
            "enode" <member_2_enode_address>
          }
        ],
      "balances":
        [
          {
            "address": <member_1_user_address>,
            "balance": <member_1_balance>
          },
          {
            "address": <member_2_user_address>,
            "balance": <member_2_balance>
          }
        ],
      "codePtr": {
        "account": "<codePtr-address>",
        "name": "<codePtr-contract-name>"
      },
      "metadata": {
        "VM": "SolidVM"
      },
      "label": "MyPrivateChain"
    }' \
"https://<strato_address>/bloc/v2.2/chain"
const chainInfo = {
  label: "MyPrivateChain",
  codePtr: {
    account: `${codePtrAddress}`,
    name: codePtrContractName
  },
  args : {},
  members : [
    {
      address: member_1_user_address,
      enode: member_1_enode_address
    },
    {
      address: member_2_user_address,
      enode: member_2_enode_address
    }
  ],
  balances: [
    {
      address: member_1_user_address,
      balance: member_1_balance
    },
    {
      address: member_2_user_address,
      balance: member_2_balance
    },
  ],
} // declare chain information

const contractInfo = {
  name: codePtrContractName
} // governance contract information

const chainId = await rest.createChain(stratoUser, chainInfo, contractInfo, options); // create the chain

Access Chain Information

Get information about a specific chain or a number of chains.

Query parameters:

  • chainid (optional)
    • The chain ID of the chain to get information about.
    • To query for more than chain, use a new chainid parameter for each chain ID (demonstrated in example below.)
    • If not specified, all chains this user has access to are returned.

Endpoint

GET https://<strato_address>/strato-api/eth/v1.2/chain"

Example

curl -X GET \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <token>" \
  "https://<strato_address>/strato-api/eth/v1.2/chain?chainid=4574c8c75d6e88acd28f7e467dac97b5C60c3838d9dad993900bdf402152228e&chainid=3c18ee0fbe01bdb9056cfabcebee1a413e7c33e0a0a1af41210f430a97028d2f"
const chainIds = ["4574c8c75d6e88acd28f7e467dac97b5C60c3838d9dad993900bdf402152228e", "3c18ee0fbe01bdb9056cfabcebee1a413e7c33e0a0a1af41210f430a97028d2f"]

const multipleChains = await rest.getChains(stratoUser, chainIds, options) // retrieve chain info

const chainId = "37dfbbbc20a3d0816a345cf1ac3aacf0b04ba66ed9ffa00c2bb68e4172cc950c"

const singleChain = await rest.getChain(stratoUser, chainId, options) // retrieve chain info

Response

[
  {

    "id": "4574c8c75d6e88acd28f7e467dac97b5C60c3838d9dad993900bdf402152228e",
    "info": {
      "signature": null,
      "accountInfo": [
        {
          "balance": 123,
          "address": "abcdef1234567",
        }
      ],
      "members": [
        {
          "address": "abcdef1234567",
          "enode": "enode://<public-key>@<ip-address>:30303"
        }
      ],
      "metadata": {},
      "creationBlock": "e8dd451531e2689273dafd7b1fb732fb7c509fbd0f570a2d3aece68820840853",
      "codeInfo": [
        {
          "name": "AutoApprove",
          "src": "<governance-src>",
          "code": "<code-hash>"
        }
      ],
      "label": "MyPrivateChain",
      "nonce": "0a2d3aece8dd451e68820840531ef92738853dafd7b19fbd0f57b732fb7c5026",
      "parentChain": null
    }
  },
  {
    "id": "3c18ee0fbe01bdb9056cfabcebee1a413e7c33e0a0a1af41210f430a97028d2f",
    "info": {
      ...,
      "label": "MySecondPrivateChain",
      "members": [...],
      "accountInfo": [...],
      "nonce": "456...",
      "codeInfo": [...],
      "parentChain": null
    }
  }
]

Private Transactions

To execute a transaction on a private chain, use the normal transaction payload syntax and add the chain ID in a chainid query parameter or as the chainid property in a transaction payload.

We use the following SimpleStorage contract as the contract we are calling functions on:

contract SimpleStorage {
  uint x;
  constructor(uint _x) {
    x = _x;
  }
  function set(uint _x) returns (uint) {
    x = _x;
    return x;
  }
}
Example

curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
      "txs": [
        {
          "payload": {
            "contractName": "SimpleStorage",
            "contractAddress": "90f0a711cd0ab921bbc9b54c4a6bdb3219e590f9",
            "method": "set",
            "args": {
              "_x": 5
            },
            "chainid": <chain-id>
          },
          "type": "FUNCTION"
        }
      ],
      "txParams": {
        "gasLimit": 32100000000,
        "gasPrice": 1
      }
    }' \
"https://<strato_address>/strato/v2.3/transaction?resolve=true"

Alternatively using the query parameter:

curl -X POST \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
      "txs": [
        {
          "payload": {
            "contractName": "SimpleStorage",
            "contractAddress": "90f0a711cd0ab921bbc9b54c4a6bdb3219e590f9",
            "method": "set",
            "args": {
              "_x": 5
            }
          },
          "type": "FUNCTION"
        }
      ],
      "txParams": {
        "gasLimit": 32100000000,
        "gasPrice": 1
      }
    }' \
"https://<strato_address>/strato/v2.3/transaction?resolve=true?chainid=<chain-id>"

Returns

[
  { 
    "status": "Success",
    "hash": "936f9af8004c11edea1f29edd4f71c4b99c3e653c6a06f5c90687b9d7341e6c1",
    "txResult": {
       "deletedStorage": "",
      "status": "success",
      "contractsDeleted": "",
      "gasUsed": "00000000000000000000000000000000000000000000000000000007794f2100",
      "stateDiff": "",
      "time": 0.0005209,
      "kind": "SolidVM",
      "chainId": "a6bff1b5361ebd13d7dd90b29f03554971128ab16d51b7fce60144601419f80b",
      "response": "",
      "blockHash": "c8a61f221886ac2f721a2467257ef11666812de5a3ef6037a9fe4465f97c585e",
      "transactionHash": "6c55e2b27ba0d88cda3c4236deb616f8f8a8bbb77932f45e248200997f346a01",
      "etherUsed": "00000000000000000000000000000000000000000000000000000007794f2100",
      "newStorage": "",
      "message": "Success!",
      "trace": "",
      "contractsCreated": ""
    },
    "data": {
      "tag": "Call",
      "contents": [
        "7"
      ]
    }
  }
]
const transaction = {
  contract: {
    name: "SimpleStorage",
    address: contractAddress,
  },
  method: "set",
  args: {
    _x: 5
  },
  chainid: chainId,
};
const result = await rest.callList(stratoUser, [transaction], options)

Returns

A list of each transactions' return values:

[
  [
    "7"
  ]
]

Governance

When a Private Chain is created, it is necessary to provide method through which to add or remove members. This is referred to as the Governance of a private chain.

Note

Network Consensus/Governance, and Private Chain Governance are completely separate topics and should not be confused. Network Governance is the method through which new nodes join or leave a network, and the management of Validator Nodes. These operations are done outside of smart contracts. Private Chain governance is the management of the members of a private chain. All operations occur within a smart contract.

Governance Contract

The smart contract that provides the rules of governance for a private chain is known as the Governance Contract. This is the first or "base" contract of the Private Chain. The Governance contract must be sent with the payload of a chain creation. The Governance Contract always resides at the Governance Address, which is constant across all chains.

The Governance Address is 0000000000000000000000000000000000000100 or simply 0x100.

Governance Methods

The method of governance is defined in the logic of the Governance Contract.

To add or remove a member, use the following Solidity Events from within the Governance Contract:

// define event types within the Governance Contract
event MemberAdded(address member, string enode);
event MemberRemoved(address member);
// emit events within a contract
emit MemberAdded(member, enode);
emit MemberRemoved(member);

These event names are reserved within STRATO to add/remove the listed member when the event is emitted from the Governance Contract. STRATO will not add/remove members when an event is not emitted from the Governance Contract.

The governance algorithm used is heavily dependent on the required use case, however we provide some common ways in which governance may be administered. The Auto-Approve, Majority Rules, Two-In, and Admin Approval governance methods are shipped with STRATO and can be easily accessed from the STRATO Management Dashboard when creating a new chain.

Governance Contract Constructors

The constructor method behaves differently for EVM and SolidVM.

Within EVM, any arguments passed in the args object will set the respective state variables of the same name to those values. If a variable has not been declared as a state variable, its value will be ignored. Any logic within the constructor is ignored. For this reason constructors in governance contracts are not needed when using the EVM.

For SolidVM, the contract constructor behaves normally with all internal logic being executed. Arguments passed in via the args object will be given to the constructor as parameters.

Auto-Approve

The Auto-Approve method of governance will unconditionally add/remove a member when the respective functions are called.

contract AutoApprove { 
  event MemberAdded (address member, string enode); 
  event MemberRemoved (address member); 

  function voteToAdd(address m, string e) { 
    emit MemberAdded(m, e); 
  } 

  function voteToRemove(address m) { 
    emit MemberRemoved(m); 
  } 
}

Majority Rules

The Majority Rules method of governance requires that a majority of members must issue a vote for a member to be successfully added/removed. This is very similar to how STRATO's PBFT consensus algorithm and Validator Node voting already operates. Rather than relying on a ⅔ majority, this method only requires a ½ majority. This contract (and other contracts that rely on the existing members of the chain) manually tracks its own members so that it can be referenced within the proper functions.

contract MajorityRules { 
  event MemberAdded (address member, string enode); 
  event MemberRemoved (address member); 

  mapping(address => uint) addVotes; 
  mapping(address => uint) removeVotes; 

  address[] __members__; 

  function voteToAdd(address m, string e) { 
    uint votes = addVotes[m] + 1; 
    uint mlen = __members__.length; 
    if (votes > mlen / 2) { 
      addVotes[m] = 0; 
      bool found = false; 
      for (uint i = 0; i < mlen; i++) { 
        if (__members__[i] == m) { 
          found = true; 
          i = mlen;
        } 
      } 
      if (!found) { 
        __members__.push(m); 
        emit MemberAdded(m, e); 
      } 
    } 
    else { 
      addVotes[m] = votes; 
    } 
  } 

  function voteToRemove(address m) { 
    uint votes = removeVotes[m] + 1; 
    uint mlen = __members__.length; 
    if (votes > mlen / 2) { 
      removeVotes[m] = 0; 
      for (uint i = 0; i < mlen; i++) { 
        if (__members__[i] == m) { 
          __members__[i] = __members__[mlen - 1]; 
          delete __members__[mlen - 1]; 
          __members__.length--; 
          emit MemberRemoved(m); 
          i = mlen; 
        } 
      } 
    } 
    else { 
      removeVotes[m] = votes; 
    } 
  } 
}

Two-In

The Two-In method of governance only requires that two members issue a vote to sucessfully add/remove a member.

contract TwoIn { 
  event MemberAdded(address member, string enode); 
  event MemberRemoved(address member); 

  mapping(address => uint) addVotes; 
  mapping(address => uint) removeVotes;

  function voteToAdd(address m, string e) { 
    uint votes = addVotes[m] + 1; 
    if (votes >= 2) { 
      emit MemberAdded(m, e); 
      addVotes[m] = 0; 
    } 
    else { 
      addVotes[m] = votes; 
    } 
  } 

  function voteToRemove(address m) { 
    uint votes = removeVotes[m] + 1; 
    if (votes >= 2) { 
      emit MemberRemoved(m); 
      removeVotes[m] = 0; 
    } 
    else { 
      removeVotes[m] = votes; 
    } 
  } 
}

Admin Approval

The Admin Approval method of governance only allows an admin to add or remove members. The admin's address is provided at the creation of the private chain.

contract AdminOnly {
  event MemberAdded (address member, string enode); 
  event MemberRemoved (address member); 

  address admin; 

  constructor(address _admin) {
    admin = _admin;
  }
  function voteToAdd(address m, string e) {
    require(msg.sender == admin, "You do not have permission to vote");
    emit MemberAdded(m, e); 
  } 

  function voteToRemove(address m) {
    require(msg.sender == admin, "You do not have permission to vote");
    emit MemberRemoved(m); 
  } 
}

Group Membership

This Governance method requires that new members be a member of a given organization. This method utilizes X.509 certificates to associate a user address with an group/organization. It assumes that a given address already has a registered certificate. This method could be combined with any other governance algorithm to make a more complex algorithm. The provided example allows users within the "admin" group to add members within their own organization, however removing a member requires a ½ majority from the "manager" group.

pragma solidvm 3.0;
contract GroupMembership {
  event MemberAdded (address member, string enode); 
  event MemberRemoved (address member);

  mapping(address => uint) removeVotes;

  address[] __members__;
  address[] __managers__;
  string org;
  constructor() {
    org = tx.organization; // set the chain creator's organization to this chain's organization.
  }

  function addMember(address m, string e) {
    mapping(string => string) originCert = getUserCert(tx.origin);
    require(originCert["organization"] == org && originCert["group"] == "admin", "You do not have permission to add members");
    mapping(string => string) userCert = getUserCert(m);
    require(userCert["organization"] == org, "User is not a part of this organization");
    emit MemberAdded(m, e);
    __members__.push(m);
    if (userCert["group"] == "manager") {
      __managers__.push(m);
    }
  }

  function voteToRemove(address m) {
    mapping(string => string) originCert = getUserCert(tx.origin);
    require(originCert["organization"] == org && originCert["group"] == "manager", "You do not have permission to remove members");
    uint votes = removeVotes[m] + 1; 
    uint managerlen = __managers__.length;
    uint memberlen = __members__.length;
    if (votes > managerlen / 2) { 
      removeVotes[m] = 0;
      for (uint i = 0; i < memberlen; i++) { 
        if (__members__[i] == m) {
          __members__[i] = __members__[memberlen - 1]; 
          delete __members__[memberlen - 1]; 
          __members__.length--;
          emit MemberRemoved(m);
          i = mlen;
        }
      }
      if (getUserCert(m)["group"] == "manager") {
        for (uint i = 0; i < managerlen; i++) { 
          if (__managers__[i] == m) {
            __managers__[i] = __managers__[managerlen - 1]; 
            delete __managers__[managerlen - 1]; 
            __managers__.length--;
            i = mlen;
          }
        }
      }
    } 
    else { 
      removeVotes[m] = votes; 
    } 
  } 
}

~

These are just a few examples of possible governance algorithms. The power of Solidity smart contracts allow for robust and complex voting algorithms.

Here are some more ideas for Governance Methods to inspire developers to create their own:

  • Users may create a request to join a private chain via a smart contract deployed to the main chain. Private Chain members check for existing requests and approve or deny each one on a per-request basis.
  • As new users join an application, a smart contract with their information is created on the main chain. Periodically a Governance Contract addMembers function is called that checks the existing users contracts and adds users to the chain based on their credentials (such as their X.509 Certificate).