Skip to content

Introduction to Private Chains

STRATO allows users to create side chains. These private side chains are useful to maintain state that need not be shared with the entire network. Some use cases may require certain information to be visible only to a subset of participants. Private chains allow us to achieve this by only sharing state in the private chains with authorized nodes and users, while still leveraging the consensus protocol on the main chain to provide immutability.

Each private chain is made up of one or more members on one or more nodes. A private chain is essentially a brand new chain with its own set of ether balances and contract states.

The amount of ether value available for all transactions on the chain is sum of all the balances that were specified at the time of chain initiation. No value can be added to the chain at a later point in time. For this reason, we recommend that there be atleast one member with sufficient ether balance, who can then be used to faucet future members.

Create New Private Chain

To create a private chain, a user specifies:

  1. A list of members and their starting balances
  2. A label for the chain
  3. A governance smart contract which determines under what circumstances users can be added or removed from this private chain.

A member on a private chain is identified by a combination of :

  1. An ethereum address
  2. An enode url in the eNode url format

Thus, the same user on two different nodes, is actually two separate identities from a private chain perspective. This helps STRATO determine which user and nodes need to see the state on the private chain.

We currently provide four default contracts with built-in rules (AutoApprove, TwoVotesIn, MajorityRules, and AdminOnly). As a quick note about governance contracts, there are a few reserve words to be aware of. We currently reserve one variable name, address[] __members__, that Bloc will automatically populate with the initial member list when the chain is created (the governance contract developer is responsible for providing the correct logic to update this list if a member is added or removed). We also currently reserve three events, MemberAdded(address,string), MemberRemoved(address), and ChainTerminated(). These direct the STRATO core to add a member, remove a member, or terminate the chain, respectively. The ChainTerminated() event is not currently enabled but in the future, it will allow chains to be destroyed, freeing up memory/storage for the nodes (similar to the SELFDESTRUCT opcode used by smart contracts).

By API

To create a private chain by API, the following endpoint can be used:

curl -X POST "https://stratodemo.blockapps.net/bloc/v2.2/chain" -H "accept: application/json;charset=utf-8" -H "Content-Type: application/json;charset=utf-8" -d "{\"args\":{\"removeRule\":\"<your_removal_rule>\",\"addRule\":\"<your_approval_rule>\"},\"balances\":[{\"balance\":<member_1_balance>,\"address\":\"<member_1_user_address>\"},{\"balance\":<member_1_balance>,\"address\":\"<member_2_user_address>\"}],\"members\":[{\"address\":\"<member_1_user_address>\",\"enode\":\<member_1_enode_address>"},{\"address\":\"<member_2_user_address>\",\"enode\":\<member_2_enode_address>}],\"contract\":\"Governance\",\"src\":\"<your_governance_contract_or_the_default_contract>",\"metadata\":{\"history\":\"Governance\"},\"label\":\"<string_identifier>\"}"

As an example using data:

curl -X POST "https://stratodemo.blockapps.net/bloc/v2.2/chain" -H "accept: application/json;charset=utf-8" -H "Content-Type: application/json;charset=utf-8" -d "{\"args\":{\"removeRule\":\"AutoApprove\",\"addRule\":\"AutoApprove\"},\"balances\":[{\"balance\":20000000,\"address\":\"5815b9975001135697b5739956b9a6c87f1c575c\"},{\"balance\":999999,\"address\":\"93fdd1d21502c4f87295771253f5b71d897d911c\"}],\"members\":[{\"address\":\"5815b9975001135697b5739956b9a6c87f1c575c\",\"enode\":\"enode://6d8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec0129[email protected]171.16.0.4:30303\"},{\"address\":\"93fdd1d21502c4f87295771253f5b71d897d911c\",\"enode\":\"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec0129[email protected]172.16.0.5:30303?discport=30303\"}],\"contract\":\"Governance\",\"src\":\"contract Governance { enum Rule { AutoApprove, TWO_VOTES_IN, MAJORITY_RULES } Rule addRule; Rule removeRule; Rule terminateRule; event MemberAdded (address member, string enode); event MemberRemoved (address member); event ChainTerminated(); address[] __members__ ; struct MemberVotes { address member; uint votes; } MemberVotes[] addVotes; MemberVotes[] removeVotes; uint terminateVotes; function voteToAdd(address m, string e) { MemberAdded(m,e); } function voteToRemove(address m) { MemberRemoved(m); } function voteToTerminate() { terminateVotes++; if (satisfiesRule(terminateRule, terminateVotes)) { ChainTerminated(); } } function satisfiesRule(Rule rule, uint votes) returns (bool) { if (rule == Rule.AutoApprove) { return true; } else if (rule == Rule.TWO_VOTES_IN) { return votes >= 2; } else { return true; } } }\",\"metadata\":{\"history\":\"Governance\"},\"label\":\"my chain\"}"

The POST chain endpoint returns a JSON with the chain ID to identify our new private blockchain:

{
  "chainId": "02468101214"
}

Note: The use of the private chain API currently requires that you identify an eNode for each member address. This documentation does not address the mechanics of creating an eNode address and assumes that users will create or already have an enode address.

Governance Contract

You'll notice that we use a governance.sol contract to create a new private chain.

  • Rule: Sets the voting process for a private chain. New members can be added automatically (AutoApprove), democratically (MajorityRules), or semi-democratically (TwoIn).
  • Event: Generates an event in the EVM logs when a new member is added or removed from the private chain.
  • Mapping: Defines a hash table mapping of user addresses to the number of votes cast by each user.
contract Governance {
  enum Rule { AutoApprove, TwoIn, MajorityRules }
  Rule addRule;
  Rule removeRule;

  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 (satisfiesRule(addRule, votes)) {
      MemberAdded(m,e);
      addVotes[m] = 0;
    }
    else {
      addVotes[m] = votes;
    }
  }

  function voteToRemove(address m) {
    uint votes = removeVotes[m] + 1;
    if (satisfiesRule(removeRule, votes)) {
      MemberRemoved(m);
      removeVotes[m] = 0;
    }
    else {
      removeVotes[m] = votes;
    }
  }

  function satisfiesRule(Rule rule, uint votes) private returns (bool) {
    if (rule == Rule.AutoApprove) {
      return true;
    }
    else if (rule == Rule.TwoIn) {
      return votes >= 2;
    } else {
      return false;
    }
  }
}

Get Private Chain Details

To get information about our private chain, we can run GET /chain:

curl -X GET "http://localhost/strato-api/eth/v1.2/chain"
    -H  "accept: application/json;charset=utf-8"

Which returns a JSON with a list of chain members, member balances, and governance rules:

{
  "balances": [
    {
      "address": "5815b9975001135697b5739956b9a6c87f1c575c",
      "balance": 20000000000000000000
    },
    {
      "address": "93fdd1d21502c4f87295771253f5b71d897d911c",
      "balance": 999999
    }
  ],
  "label": "my chain",
  "members": [
    {
      "address": "5815b9975001135697b5739956b9a6c87f1c575c",
      "enode": "enode://<public-key>@<ip>:<port>?discport=<port>"
    },
    {
      "address": "93fdd1d21502c4f87295771253f5b71d897d911c",
      "enode": "enode://<public-key>@<ip>:<port>?discport=<port>"
    }
}