Skip to content

Introduction to Private Chains

Some users may wish to transact with the protection of the blockchain without publicly sharing the details of the transactions. To provide transaction privacy, we introduce the concept of private transaction chains. With private transaction chains, participants on the public blockchain will be able to transact with each other privately, while maintaining the immutability and auditability of the public blockchain.

Each private chain is made up of two or more members. Additional members can be added either at initiation or after the chain is created. The rules governing the membership on the private chain are controlled by the choice of a governance contract, which is a smart contract with rules about approval and removal of members. Currently, there are a number of default governance contract options available, but a custom governance contract may also be used.

The amount of ether value available for all transactions on the chain is capped at the amount of value that the chain is initiated with. No value can be added to the chain at a later point in time. For this reason, we recommend that a private chain be initiated with a very high ether balance. If a low balance is used, transacting on the chain may become difficult over time without redistributing ether.

Create New Private Chain

We can begin by creating a new private blockchain. We can do this through an API endpoint or through the STRATO dashboard. Before we create the blockchain, we need to understand who the initial members are.

Each member is identified by both an eNode, which is how the member node is identified by their peers on the network, and their user address on the blockchain. The eNode needs to be provided in the eNode url format specified in the related Ethereum wiki page, which is enode://<enode-address>@<ip-address>:<TCP listening port>?discport=<UDP discovery port>. STRATO uses the address portion to determine chain membership. Each member also must be designated to have an initial ether balance. Unless being used for private data storage, a private chain should be created with at least two members. In addition, it is recommended to initiate your chain with a governance contract that designates the initial rules for adding and removing members. Without a governance contract, no new members can be added or removed to the chain at a later point. 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>"
    }
}