This document provides informative notes about good practices for implementing Enterprise Ethereum clients and for setting up and configuring Enterprise Ethereum blockchains.

This Specification is copyright © 2018-2021 Enterprise Ethereum Alliance Incorporated (EEA). It is made available under the terms of the Apache License version 2.0. [[Apache2]]

This is an editors' draft of the Enterprise Ethereum Alliance Client Implementation Guide version 4. It has not yet been reviewed by the Enterprise Ethereum Alliance (EEA) Technical Specification Working Group (TSWG) or anyone else. It is not appropriate to quote or reference this document except as "Work in Progress". Please send any comments to the EEA Technical Steering Committee at [https://entethalliance.org/contact/](https://entethalliance.org/contact/).

Introduction

This document describes good practices and information that is useful to implement Enterprise Ethereum clients (a client); the software that implements Enterprise Ethereum and is used to run nodes on an Enterprise Ethereum permissioned blockchain.

Enterprise Ethereum is the set of enterprise-focused extensions to public Ethereum that are defined in the Enterprise Ethereum Alliance Client Specification [[EEA-clients]]. These extensions provide the ability to perform private transactions, and enforce access controls (permissioning), for Ethereum blockchains that use them. Such blockchains are formally known as Enterprise Ethereum Permissioned Blockchains.

Public Ethereum (Ethereum) is the public blockchain-based distributed computing platform featuring smart contract (programming) functionality defined by the [[Ethereum-Yellow-Paper]], [[EIPs]], and associated specifications. The mainnet is a public ethereum blockchain, with `chainId` and `NetworkId` values of 1.

There are other public ethereum blockchains, usually with slightly different characteristics. For example "testnets" like Ropsten, Rinkeby, and Goerli are all used to test Ethereum technnology.

About the EEA Client Specification

The Enterprise Ethereum Client Specification [[EEA-clients]] defines the implementation requirements for Enterprise Ethereum clients, including the interfaces to external-facing components of Enterprise Ethereum and how they are intended to be used. A partial list of the use cases [[EEA-client-usecases]] that specification attempts to address is available, as an editors' draft for a work in progress. A companion document, the Enterprise Ethereum Alliance Permissioned Blockchains Specification [[EEA-chains]] defines requirements for Enterprise Ethereum blockchains to ensure that clients that conform to the Client Specification can work interopably on blockchains that meet the requirements defined in that document.

Experimental Requirements

The Client Specification includes requirements and APIs that are described as experimental. This means that a requirement or API is in early stages of development and might change as feedback is incorporated. Implementors are encouraged to implement these experimental requirements, with the knowledge that requirements in future versions of the Specification are not guaranteed to be compatible with the current version. Please send comments and feedback on experimental portions of the Specification to the EEA via [https://entethalliance.org/contact/](https://entethalliance.org/contact/).

Requirement Categorization

All requirements in this Specification are categorized as either:

Difference to public Ethereum client

An Enterprise Ethereum client can be developed by extending the capabilities for an Ethereum MainNet client, making the following changes:

Permissioning

An Enterprise Ethereum Client is used to interact with an Enterprise Ethereum Permissioned Blockchain. Core to the interaction are the permissioning contracts. These determine whether a given node is permitted to access a blockchain, and whether a given transaction submitted is valid based on factors such as the accounts involved, whether they deploy smart contracts, and the like. An Enterprise Ethereum Permissioned Blockchain has a permissioning contract, that enables an Enterprise Ethereum Client to call the methods connectionAllowed and transactionAllowed at a known address, to determine whether to allow an incoming connection, or whether to treat a given transaction as valid. An Enterprise Ethereum Client can cache results from calling the methods of a permissioning contract, in order to minimise such calls. To do so safely, it must listen for update events emmitted by the contract, and modify its cache appropriately.

Private Transactions

An Enterprise Ethereum Client is required to implement a form of private transaction; either restricted private transactions or unrestricted private transactions. Enterprise Ethereum clients implement the `eea_sendTransaction` and `eea_sendRawTransaction` JSON-RPC-API methods to submit private transactions to the blockchain.
Restricted Private Transactions
Transactions communicated directly between the parties involved. These are notarised in a marker transaction on the blockchain, that records a transaction took place, but does not contain the details of the transaction. Instead, those details are only available to nodes that are party to the transaction.
Unrestricted Private Transactions
Transactions that are recorded on the blockchain, but only parties to the transaction have the necessary information to interpret the full meaning of the transaction, using a mechanism such as zero-knowledge proofs.
In either case, Enterprise Ethereum Clients implement at least one synchronous private transaction method. The `eea_sendTransactionAsync` and `eea_sendRawTransactionAsync` methods enable higher transaction throughput by allowing a user to submit a private transaction without stopping to wait for a return. They are currently defined as experimental. To enable interoperability in restricted private transactions, a common messaging format needs to be used. Current implementations use Java Message serialisation. The Working Group considers this would be a bad option for interoperability. The group believes that CBOR [[rfc8949]] would be a suitable format. The group requests input on whether a formal requirement helps another implementation.

Configuration Parameters

The Enterprise Ethereum client specification defines a standard form of Network Configuration Parameters, using a JSON object in the genesis block that Enterprise Ethereum Clients are required to interpret. The Enterprise Ethereum-specific parameters defined are:
maxcodesize
The maximum size of a smart contract to be valid for deployment. It can either specify an integer, which means a number of kilobytes, or a JSON object describing limits applied for a range of blocks, to enable nodes to correctly validate when trying to sync an existing blockchain where the value has changed over time.
nodePermissionContract
The address to use when calling the connectionAllowed method.
transactionPermissionContract
This specifies the address to use when calling the transactionAllowed method.
The optional organizationRegistryContract
The address of an Organization Registry contract, if there is one.

Consensus Algorithms

Conforming Enterprise Ethereum Clients implement the Byzantine Fault-tolerat [[QBFT]] Consensus Algorithms defined by the EEA, and the Clique Proof of Authority algorithm defined in [[EIP-225]]. Most clients implement more consensus algorithms. Clients that also operate on the pre-merge MainNet need to implement EthHash (Proof of Work).

Organization Registry

An Enterprise Ethereum Permissioned blockchain can implement an Organization Registry. This is a contract defined in the chainspec [[EEA-chains]] that establishes if an account is acting on behalf of a known organization.

Smart Contract Tools Sublayer

Implementations need to provide deployment and debugging tools for Enterprise Ethereum smart contracts. Tools used in public Ethereum, for example, include [[Truffle]] and [[Remix]].

Implementations should also extend formal verification methods for use with Enterprise Ethereum smart contracts.

Integration Libraries

Implementations might provide integration libraries enabling convenience of interaction through additional language bindings. These libraries might include [[web3j]], [[web3.js]], [[Nethereum]], [[protocol-buffers]], or a REST API.

Enterprise Management Systems

Implementations can provide enterprise-ready software fault reporting capabilities, including the ability to:

- Log software fault conditions. - Generate events to notify of software fault conditions. - Accept diagnostic commands from software fault management systems.

Implementations might also provide enterprise-ready performance management capabilities, including the ability to easily provide relevant performance management metrics for analysis by enterprise performance management systems.

Implementations can also provide enterprise-ready security management interaction capabilities, including the ability for logs, events, and secure network traffic to be monitored by enterprise security management systems.

Implementations might provide enterprise-ready capabilities to support historical analysis, including the ability for relevant metrics to be easily collected by an enterprise data warehouse system for detailed historical analysis and creating analytical reports.

Implementations might also provide support for other enterprise management systems, as appropriate, such as:

- Common Management Information Protocol (CMIP) - Web-Based Enterprise Management (WBEM) - Application Service Management (ASM) instrumentation.

Inter-chain

Enterprise Ethereum implementations might provide inter-chain mediation capabilities to enable interaction with different blockchains.

Performance and Scalability

Performance is important to many (but not all) Enterprise Ethereum use cases. However, performance is multidimensional; attempts to require specific performance targets on a single aspect generally leads to all implementations being optimised for that target instead of meeting the varying needs of Enterprise Ethereum customers.

There are some common goals however. Specifically, increasing the cost of a blockchain over time is incompatible with many use cases, and many use cases need to ensure significant scalability is feasible.

Constant Power Requirements

The computing power to validate blocks is meant to remain constant over time, regardless of the blockchain size or the number of network participants. The constant power requirements include:

- Ensuring the power required to validate a block does not increase significantly. - Using "fast sync" methods, like a specialized format for import/export, to enable a client to sync, or moving the genesis point regularly to limit the data required for a sync. - Pruning the data tree to ensure the lookup of recent data is cheap.

Scalability

Off-chain processing is a mechanism that can improve scalability. Likewise, Sharding, a mechanism proposed for Ethereum 2.0, will probably improve scalability too.

Storage and Ledger Sublayer

Implementations might implement data storage used for optional off-chain operations. For example, implementations could locally choose to cache the results from a trusted oracle or store information related to other systems extensions not covered by the [Client Specification](https://entethalliance.github.io/client-spec/spec.html).

Persistent storage that is resistant to brute force attacks generally uses a "defense-in-depth" approach. For example, instead of relying on restricted access to protect plain text storage, an implementation can further protect the data by encrypting it with an Authenticated Encryption with Additional Data (AEAD) algorithm, such as one described in [[RFC5116]].

Consensus

The consensus algorithms supported by implementations need to be properly documented to enable interoperability. Consensus algorithm implementation should be modular and configurable.

Permissioning Requirements

Enterprise Ethereum clients might support local key management allowing users to secure their private keys.

Clients might also support secure interaction with an external key management system for key generation and secure key storage.

For example, implementations could securely interact with a Hardware Security Module (HSM), a physical device to provide strong and secure key generation, key storage, and cryptographic processing for deployments where strong security is needed.

Permissioning Management Examples

The smart contracts that allow Enterprise Ethereum clients to apply permissioning require a management system behind them. This section provides some examples of how such a system might work, but each Enterprise Ethereum blockchain is free to implement whatever system is suitable, as long as it includes the required functions for clients to query.

Permissioning Contracts: Interoperable on chain node whitelist for testnet

This section describes an approach for achieving interoperable node permissioning using an on chain white list. The interop is desired between as many enterprise ethereum clients as possible. Whilst this example is for node permissioning, the approach can be extended to include account permissioning. The components described in the remainder of this section align with the Permissioning Management and Permissioning Enforcement sections described in the Permissioning Smart Contract section of the Enterprise Ethereum Alliance Client Specification [[EEA-clients]].

Permissioning Management

The on chain white list consists of smart contract management functions essentially implementing the following operations: - Add a node to whitelist. - Remove a node from whitelist. - Get whitelist which returns the nodes in the whitelist. These smart contract functions can be based on one of the existing node permissioning white listing smart contracts provided by one of the client vendors. These include: - [Autonity whitelist management smart contract](https://github.com/clearmatics/autonity/blob/develop/contracts/autonity/contract/contracts/Autonity.sol) - [Besu whitelist management smart contract](https://github.com/PegaSysEng/permissioning-smart-contracts/tree/master/contracts) - [Quorum whitelist management smart contract](https://github.com/jpmorganchase/quorum/tree/master/permission/) - Strato's whitelist management smart contract is the basis of the ["member groups and authorised users" contracts](#sec-permissioning-contracts-memberGroups-and-authorizedUsers) in this document These whitelist management functions are called from a Dapp or utility function via RPC utilising an authorized account to perform the transactions.

Permissioning Enforcement

Integration with EEA Spec node permissioning `connectionAllowed` smart contract function
The on chain whitelist smart contracts include an implementation of the node permissioning enforcement function `connectionAllowed` as defined in the EEA client specification. This function will access the on-chain permissioning data to determine if a connection is allowed.
Integration for clients that do not yet utilise the EEA Spec node permissioning smart contract function
Some clients do not yet utilise the EEA Spec node permissioning smart contract function `connectionAllowed`. Instead, they utilise other non-EEA smart contract functions to perform this task. In order to integrate these clients into the permissioned network, they need to operate on the same on-chain permissioning data. This is achieved by implementing the non-EEA smart contract functions which access the same on-chain permissioning data as the EEA functions.

Permissioning Contracts: Simple Authorization Whitelist

This is an example of a basic permissioning contract that maintains a whitelist of enodes allowed to participate in the Enterprise Ethereum blockchain, and a list of administrative accounts that can alter that whitelist. In this model administrators are allowed to add and remove administrators, and add and remove nodes. Clients can check whether a given connection is permitted using the `connectionAllowed` function, which checks that the enode addresses of both nodes involved in the connection are in the whitelist. When a permission rule update occurs a `NodePermissionsUpdated` event is emitted indicating that a rule change has occurred, and whether the rule change makes the Enterprise Ethereum blockchain more permissive or adds new restrictions. When deploying the contract it is initialised with the account deploying it as the first administrator. This account can then add additional administrators and add nodes to the whitelist. This contract serves as an example only. As written, it has shortcomings. These need to be considered before using the code any production environment. Some potentially desirable features that are not included in this example are:
pragma solidity >=0.4.0 <0.6.0;
contract SimplePermissioning {
    // Struct representing an enode
    struct Enode {
        bytes32 enodeHigh;
        bytes32 enodeLow;
        bytes16 enodeHost;
        uint16 enodePort;
    }

    // Event emitted when a rules change occurs
    event NodePermissionsUpdated(
        bool addsRestrictions,
        bool addsPermissions
    );

    // List of nodes permitted to participate in the network
    mapping(bytes => Enode) private whitelist;

    // List of accounts allowed to modify the network
    mapping(address => bool) private adminList;

    constructor() public {
        // set the contract creator as the first admin
        adminList[msg.sender] = true;
    }

    // Guard modifier for functions that can only be invokable by admins
    modifier onlyAdmin() {
        require(adminList[msg.sender] == true, "Cannot be called except by members of the admin list");
        _;
    }

    // Add an admin to the contract
    function addAdmin(address newAdmin) public onlyAdmin {
        adminList[newAdmin] = true;
    }

    // Remove an admin from the contract
    function removeAdmin(address oldAdmin) public onlyAdmin {
        adminList[oldAdmin] = false;
    }

    // Check if a connection between two nodes will be permitted
    function connectionAllowed(
        bytes32 sourceEnodeHigh,
        bytes32 sourceEnodeLow,
        bytes16 sourceEnodeIp,
        uint16 sourceEnodePort,
        bytes32 destinationEnodeHigh,
        bytes32 destinationEnodeLow,
        bytes16 destinationEnodeIp,
        uint16 destinationEnodePort
    ) public view returns (bytes32) {
        // Check that both are in the whitelist
        if (
            enodeAllowed(sourceEnodeHigh, sourceEnodeLow, sourceEnodeIp, sourceEnodePort)
            && enodeAllowed(destinationEnodeHigh, destinationEnodeLow, destinationEnodeIp, destinationEnodePort)
        ) {
            // If both are then indicate permitted by returning the first bit as set
            return 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
        } else {
            // If one or neither are permitted then indicate not permitted by unsetting the first bit
            return 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
        }
    }

    // Check if a specified enode is in the whitelist
    function enodeAllowed(
        bytes32 sourceEnodeHigh,
        bytes32 sourceEnodeLow,
        bytes16 sourceEnodeIp,
        uint16 sourceEnodePort
    ) public view returns (bool){
        bytes memory key = computeKey(sourceEnodeHigh, sourceEnodeLow, sourceEnodeIp, sourceEnodePort);
        Enode storage whitelistSource = whitelist[key];
        if (whitelistSource.enodeHost > 0) {
            return true;
        }
    }

    // Add a specified enode to the whitelist
    function addEnode(
        bytes32 enodeHigh,
        bytes32 enodeLow,
        bytes16 enodeIp,
        uint16 enodePort
    ) public onlyAdmin {
        Enode memory newEnode = Enode(enodeHigh, enodeLow, enodeIp, enodePort);
        bytes memory key = computeKey(enodeHigh, enodeLow, enodeIp, enodePort);
        whitelist[key] = newEnode;
        // Emit an event indicating a permissioning update occurred that only
        // allows new nodes into the network
        emit NodePermissionsUpdated(false, true);
    }

    // Remove a specified enode from the whitelist
    function removeEnode(
        bytes32 enodeHigh,
        bytes32 enodeLow,
        bytes16 enodeIp,
        uint16 enodePort
    ) public onlyAdmin {
        bytes memory key = computeKey(enodeHigh, enodeLow, enodeIp, enodePort);
        Enode memory zeros = Enode(bytes32(0), bytes32(0), bytes16(0), 0);
        whitelist[key] = zeros;
        // Emit an event indicating a permissioning update occurred that can
        // cause existing connections to now be disallowed
        emit NodePermissionsUpdated(true, false);
    }

    // Compute a consistent hashkey for a given enode
    function computeKey(
        bytes32 enodeHigh,
        bytes32 enodeLow,
        bytes16 enodeIp,
        uint16 enodePort
    ) public pure returns (bytes memory) {
        return abi.encode(enodeHigh, enodeLow, enodeIp, enodePort);
    }
}

Permissioning Contracts: memberGroups and authorizedUsers

This is an example permissioning model with four smart contract interfaces for management, and methods for enforcement. These example interfaces are for node permissioning. A permissioned Enterprise Ethereum blockchain includes smart contracts that implement the permissioning enforcement interfaces specified in Section , along with whatever management functions are appropriate for the chosen permissioning model. The model in this example is based on the concept of a network, that consists of a set of memberGroups, each representing an enterprise or organization, and each made up of authorizedUsers. In this model nodes are added to or removed from the node list of a memberGroup. If a memberGroup joins the network, the nodes associated with that memberGroup are permitted to join. Conversely, if the memberGroup is removed from the network, the nodes associated with that memberGroup are disconnected. As noted, memberGroups are a collection of authorizedUsers. An authorizedUser is represented by one or more Ethereum accounts. This provides robustness in case a given user loses the keys to one of their accounts, as well as reflecting the reality that many users operate more than one account. Each authorizedUser has individually specified permissions to act on behalf of the memberGroup in administering the Enterprise Ethereum blockchain. Depending on the specific permissions they have, an authorizedUser can make changes, such as adding a new authorizedUser to a memberGroup, adding a new node to a memberGroup node list, or inviting another memberGroup to join the Enterprise Ethereum blockchain. A permissioning decider function is used to decide whether or not a memberGroup is permitted to join the network, when to evict a memberGroup, and especially whether to change the permissioning decider itself. This model uses four fundamental smart contract interfaces: - `AuthorizedUser` - `MemberGroup` - `Network` - `PermissioningDecider`.

AuthorizedUser

The `AuthorizedUser` smart contract contains authorizedUsers, initialized with a name and an identifier, like an email address. Additional information, such as alternative contact information or PGP public keys, could also be included by implementations of `AuthorizedUser`.
pragma solidity ^0.5.1;
interface AuthorizedUser {

    // Metadata

    // Retrieve the user's name.
    function getName() external view returns (string memory);

    // Retrieve the user's identifier.
    function getId() external view returns (string memory);

    // Authorization mutation.

    // Add an Ethereum account address for an authorizedUser. Multiple addresses
    // can be added.
    function addAddress(address _owner) external;

    // Remove an Ethereum account address from an authorizedUser.
    function removeAddress(address _owner) external;

    // Authorization queries.

    // Check if the authorizedUser owns a specific Ethereum account address.
    function owns(address _owner) external view returns (bool);

    // Network of trust (reputation) mutators.

    // Check if the authorizedUser vouches for another (child) authorizedUser.
    function hasEndorsed(AuthorizedUser _child) external view returns (bool);

    // Vouch for another authorizedUser.
    function endorse(AuthorizedUser _child) external;

    // Stop vouching for an authorizedUser
    function unendorse(AuthorizedUser _child) external;

    // Network of trust backlinks. These are called by `endorse` and
    // `unendorse` implementations respectively, to provide pointers about where
    // to look for endorsements.

    // Set the (parent) authorizedUser as vouching for the authorizedUser.
    function recordEndorsement(AuthorizedUser _parent) external;

    // Set the (parent) authorizedUser to no longer vouch for the authorizedUser.
    function eraseEndorsement(AuthorizedUser _parent) external;
}
A user is responsible for deciding to endorse someone as an authorizedUser. Some examples of how Alice might decide to endorse Bob as an authorizedUser include: - alice@a.net sends an email to bob@a.net, asking to confirm Bob's authorizedUser address. - alice@a.net sends an email to bob@b.com, asking Bob to join a video call to assert his ownership of a given Ethereum account. - Alice walks over to Bob's desk and asks for his Ethereum account address.

Any caller can add any address as a parent of an authorizedUser. To authenticate an authorizedUser, the contract follows the parent links and checks that the corresponding child link is present.

MemberGroup

The `MemberGroup` smart contract represents a group of authorizedUsers and their permissions.
pragma solidity ^0.5.1;
import "./AuthorizedUser.sol";
interface MemberGroup {

    // Metadata

    // Retrieve the memberGroup name.
    function getName() external view returns (string memory);

    // Retrieve the permissions for an authorizedUser.
    function permission(AuthorizedUser) external view returns (uint);

    // Retrieve the number of authorizedUsers in the memberGroup.
    function memberCount() external view returns (uint);

    // Retrieve an authorizedUser, specified by index idx, from the memberGroup.
    function getMember(uint idx) external view returns (AuthorizedUser);

    // Managing membership of the group

    // Add an authorizedUser to the memberGroup. Requester needs
    // `CAN_ADD_USER` permission.
    function addUser(AuthorizedUser requester, AuthorizedUser object,
                                   uint _permission) external;

    // Remove a authorizedUsers from the memberGroup. Requester needs
    // `CAN_REMOVE_USER` permission.
    function removeUser(AuthorizedUser requester,
                                   AuthorizedUser object) external;

    // Events

    // Emitted when an authorizedUser is added to a memberGroup.
    event MemberAdded(AuthorizedUser _user, uint _permission);

    // Emitted when an authorizedUser is removed from a memberGroup.
    event MemberRemoved(AuthorizedUser _user, uint _permission);
}
An authorizedUser is given permissions as follows: - The authorizedUser who calls the `addUser` function (the requester) proposes a set of permissions as the `_permission` parameter. - The contract does a bitwise AND of the requester's own permissions with the request. - The result is recorded as the permission for the newly added authorizedUser. A partial definition of permissions could be as follows:
pragma solidity ^0.5.1;
contract Permissions {

    // Permission to add or remove an authorizedUser.
    uint constant public CAN_ADD_USER = 0x1;
    uint constant public CAN_REMOVE_USER = 0x2;

    // Permission to change the node list of a memberGroup.
    uint constant public CAN_ADD_NODE = 0x4;
    uint constant public CAN_REMOVE_NODE = 0x8;

    // Permission to vote for other memberGroups to join or leave the network.
    uint constant public CAN_INVITE_MEMBERGROUP = 0x10;
    uint constant public CAN_UNINVITE_MEMBERGROUP = 0x20;

    // Permission to vote for a new permissioning decider
    uint constant public CAN_PROPOSE_DECIDER = 0x100;

    uint constant public ADMIN = 0x1ff;

    function meets(uint have, uint needed) public pure returns (bool) {
        return have & needed == needed;
    }
}

Network

As described above, networks are a collection of memberGroups. Each memberGroup manages a node list (a list of [[enode]] URLs, corresponding to the nodes allowed to connect to the Enterprise Ethereum blockchain that are controlled by the memberGroup). Any authorizedUser that is part of the memberGroup and has the `CAN_ADD_NODE` permission can add to the node list for that memberGroup. To add a memberGroup to, or remove a memberGroup from, the Enterprise Ethereum blockchain, every memberGroup that is already a member can vote to `invite` or `uninvite` that memberGroup. The permissioning decider for the network determines whether to update the network members, given the current set of requests. A memberGroup can have `WRITE` or `READ` permissions, set as part of adding it to the network. A node belonging to a memberGroup that has `WRITE` permission can submit a transaction, but transactions from a node in a memberGroup that only has `READ` permission result in the `transactionAllowed` method returning `res: false` for that transaction.
pragma solidity ^0.5.1;
import "./MemberGroup.sol";
import "./AuthorizedUser.sol";
import "./PermissioningDecider.sol";
interface Network {

    // Node queries.

    // Retrieve the memberGroup that a node is part of.
    function memberGroupOf(string calldata _node) external view
        returns (MemberGroup);

    // Retrieve the number of nodes in the memberGroup.
    function memberGroupsNodeCount(MemberGroup) external view
        returns (uint);

    // Retrieve a node, specified by index idx, from the memberGroup.
    function memberGroupsNode(MemberGroup, uint idx) external view
        returns (string memory);

    // Authorization queries.

    // Retrieve the permissions for the memberGroup.
    function permission(MemberGroup) external view returns (uint);

    // Check if 2 nodes are allowed to connect to one another
    function connectionAllowed(
        bytes32 sourceEnodeHigh,
        bytes32 sourceEnodeLow,
        bytes32 sourceIp,
        bytes32 sourcePort,
        bytes32 destinationEnodeHigh,
        bytes32 destinationEnodeLow,
        bytes32 destinationIp,
        bytes32 destinationPort
    ) external view returns (bytes32);

    // Group administration.

    // Add a node to a memberGroup. This will fail unless the authorizedUser has
    // `CAN_ADD_NODE` permission.
    function addNode(MemberGroup, AuthorizedUser, string calldata _node) external;

    // Remove a node from a memberGroup. This will fail unless the authorizedUser has
    // `CAN_REMOVE_NODE` permission
    function removeNode(MemberGroup, AuthorizedUser, string calldata _node) external;

    // Group membership queries.

    // Retrieve the number of memberGroups.
    function memberGroupCount() external view returns (uint);

    // Retrieve a memberGroup, specified by index idx
    function getmemberGroup(uint idx) external view
        returns (MemberGroup);

    // Network vote counts.

    // Retrieve the number of invites for the memberGroup to have `READ`
    // permissions in the context of the network.
    function readInvitesReceived(MemberGroup) external view
        returns (uint);

    // Retrieve the number of invites for the memberGroup to have `WRITE`
    // permissions in the context of the network.
    function writeInvitesReceived(MemberGroup) external view
        returns (uint);

    // Retrieve the number of uninvites for the memberGroup to leave the
    // network.
    function uninvitesReceived(MemberGroup) external view returns (uint);

    // Group membership mutators.

    // Invite a memberGroup to join the network. This will fail unless the authorizedUser has
    // `CAN_INVITE_MEMBERGROUP` permission.
    function invite(MemberGroup _invitee, MemberGroup _ginviter,
                          AuthorizedUser _uinviter, string calldata _node, uint _perm) external;

    // Uninvite a memberGroup from the network. This will fail unless the authorizedUser has
    // `CAN_UNINVITE_MEMBERGROUP` permission.
    function uninvite(MemberGroup _invitee, MemberGroup _ginviter,
                          AuthorizedUser _uinviter) external;

    // Rule inspection.

    // Retrieve the permissioning decider function currently in use.
    function decider() external view returns (PermissioningDecider);

    // Rule vote counts.

    // Retrieve the number of votes received for the permissioning decider.
    function deciderVotesReceived(PermissioningDecider) external view
        returns (uint);

    // Retrieve the permissioning decider nominated by the memberGroup.
    // Useful for admin weighting.
    function nominatedDecider(MemberGroup) external view
        returns (PermissioningDecider);

    // Change the rule engine.

    // Propose a new permissioning decider.
    function proposeDecider(PermissioningDecider _next,
                                MemberGroup _gproposer, AuthorizedUser _uproposer)
                                external;
    // Emitted events.

    // The permissions set was updated
    event NodePermissionsUpdated(bool addsRestrictions, bool addsPermissions);

    // A node was added to a memberGroup.
    event NodeAdded(MemberGroup _changed_group, string _node);

    // A node was removed from a memberGroup.
    event NodeRemoved(MemberGroup _changed_group, string _node);

    // An authorizedUser has invited a memberGroup to join the network.
    event memberGroupInvited(MemberGroup _invited_group,
                                    uint _permission);

    // An authorizedUser has uninvited a memberGroup from the network.
    event memberGroupUnInvited(MemberGroup _uninvited_group,
                                    uint _permission);

    // A memberGroup was added to the network.
    event memberGroupAdded(MemberGroup _added_group,
                                    uint _permission);

    // A memberGroup was removed from the network.
    event memberGroupRemoved(MemberGroup _removed_group,
                                    uint _permission);

    // A permissioning decider function was swapped to a new one.
    event DeciderSwapped(PermissioningDecider _old, PermissioningDecider _new);
}
The `Network` contract checks whether the caller has permission to call the `invite`, `uninvite`, `proposeDecider`, `addNode`, and `removeNode` functions. The granularity of permissions is implementation-dependent.

PermissioningDecider

The `PermissioningDeciders` smart contract< customizes the bylaws of a `Network` smart contract.
pragma solidity ^0.5.1;
import "./MemberGroup.sol";
import "./Network.sol";
interface PermissioningDecider {

    // The permission the memberGroup now has, if approved.
    function inviteApproved(Network, MemberGroup) external view
        returns (uint8);

    // Whether the network will remove the memberGroup.
    function inviteRevoked(Network, MemberGroup) external view
        returns (bool);

    // Whether the network will change its permissioning decider.
    function swapDecider(Network, PermissioningDecider) external view
        returns (bool);
}
Some example `PermissioningDeciders` include: - Static: memberGroups are never removed or added from the `Network`. Any attempt to change the `PermissioningDecider` will fail. - AutoApprove: memberGroups are automatically included (or removed) when invited (or uninvited). The decider swaps the first time it is asked. - AdminRun: The `Network` has an administrator group, which is the only vote counted for approving or revoking approval of a memberGroup, or changing the `PermissionDecider`. - MajorityRules: A prospective memberGroup needs more than half of the current memberGroups to invite it for membership. A prospective `PermissioningDecider` needs more than half of the current groups to nominate it before this `Decider` relinquishes control.

Node Blacklisting

Blacklisting a node from a memberGroup level can be done by by adding the following functions to the `MemberGroup` smart contract.
interface MemberGroup {

    ...
    // Blacklist an authorizedUser.
    function blacklistNode(AuthorizedUser, string _node) interface;

    // Remove an authorizedUser from the blacklist.
    function unblacklistNode(AuthorizedUser, string _node) interface;
    ...

}
Blacklisting of nodes for the whole Enterprise Ethereum blockchain can be done by adding the following functions to the `Network` and `PermissioningDecider` smart contracts.
interface Network {

    ...
    // Vote to add an authorizedUser to the blacklist.
    voteToBlacklist(MemberGroup, AuthorizedUser, string _node) external;

    // Vote to remove an authorizedUser from the blacklist.
    voteToUnblacklist(MemberGroup, AuthorizedUser, string _node) external;

    // Retrieve the number of votes for the node to be added to the blacklist.
    blacklistVotesReceived(string _node) external view returns (uint);

    // Retrieve the number of votes for the node to be removed from the
    // blacklist.
    unblacklistVotesReceived(string _node) external view returns (uint);

    // Emitted when a node is added to the blacklist.
    event NodeBlacklisted(MemberGroup _blacklisted_group, string _node);

    // Emitted when a node is removed from the blacklist.
    event NodeUnblacklisted(MemberGroup _unblacklisted_group, string _node);
    ...

}
interface PermissioningDecider {

...
// Whether the node will be added to the blacklist.
function blacklistApproved(Network, string _node) external view
    returns (bool);

// Returns whether the node will be removed from the blacklist.
function unblacklistApproved(Network, string _node) external view
    returns (bool);
...

}

Legal Notice

The copyright in this document is owned by Enterprise Ethereum Alliance Inc. (“EEA” or “Enterprise Ethereum Alliance”).

No modifications, edits or changes to the information in this document are permitted. Subject to the terms and conditions described herein, this document may be duplicated for internal use, provided that all copies contain all proprietary notices and disclaimers included herein. Except as otherwise provided herein, no license, express or implied, by estoppel or otherwise, to any intellectual property rights are granted herein.

Use of this document and any related intellectual property incorporated herein, is also governed by the Bylaws, Intellectual Property Rights Policy and other governing documents and policies of EEA and is subject to the disclaimers and limitations described below.

No use or display of any of the following names or marks "Enterprise Ethereum Alliance", the acronym "EEA", the EEA logo, or any combination thereof, to claim compliance with or conformance to this document (or similar statements) is permitted absent EEA membership and express written permission from the EEA. The EEA is in process of developing a compliance testing and certification program only for the EEA members in good standing, which it targets to launch towards the end of 2020.

THE CONTENTS OF THIS DOCUMENT ARE PROVIDED "AS IS" WITH NO WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY PARTICULAR PURPOSE, SATISFACTORY QUALITY, OR REASONABLE SKILL OR CARE, OR ANY WARRANTY ARISING OUT OF ANY COURSE OF DEALING, USAGE, TRADE PRACTICE, PROPOSAL, SPECIFICATION OR SAMPLE. EEA DOES NOT WARRANT THAT THIS DOCUMENT IS COMPLETE OR WITHOUT ERROR AND DISCLAIMS ANY WARRANTIES TO THE CONTRARY.

Each user of this document hereby acknowledges that sofftware or products implementing the technology specified in this document ("EEA-Compliant Products") may be subject to various regulatory controls under the laws and regulations of various governments worldwide. Such laws and regulatory controls may govern, among other things, the combination, operation, use, implementation and distribution of EEA-Compliant Products. Examples of such laws and regulatory controls include, but are not limited to, airline regulatory controls, telecommunications regulations, finance industry and security regulations, technology transfer controls, health and safety and other types of regulations. Each user of this document is solely responsible for the compliance by their EEA-Compliant Products with any such laws and regulations and for obtaining any and all required authorizations, permits, or licenses for their EEA-Compliant Products related to such regulations within the applicable jurisdictions. Each user of this document acknowledges that nothing in this document or the relevant specification provides any information or assistance in connection with securing such compliance, authorizations or licenses. NOTHING IN THIS DOCUMENT CREATES ANY WARRANTIES WHATSOEVER REGARDING THE APPLICABILITY OR NON-APPLICABILITY OF ANY SUCH LAWS OR REGULATIONS OR THE SUITABILITY OR NON-SUITABILITY OF ANY SUCH PRODUCT OR SERVICE FOR USE IN ANY JURISDICTION.

EEA has not investigated or made an independent determination regarding title or non-infringement of any technologies that may be incorporated, described or referenced in this document. Use of this document or implementation of any technologies described or referenced herein may therefore infringe undisclosed third-party patent rights or other intellectual property rights. The user is solely responsible for making all assessments relating to title and non-infringement of any technology, standard, or specification referenced in this document and for obtaining appropriate authorization to use such technologies, standards, and specifications, including through the payment of any required license fees.

NOTHING IN THIS DOCUMENT CREATES ANY WARRANTIES OF TITLE OR NONINFRINGEMENT WITH RESPECT TO ANY TECHNOLOGIES, STANDARDS OR SPECIFICATIONS REFERENCED OR INCORPORATED INTO THIS DOCUMENT.

IN NO EVENT SHALL EEA OR ANY OF ITS MEMBERS BE LIABLE TO THE USER OR TO A THIRD PARTY FOR ANY CLAIM ARISING FROM OR RELATING TO THE USE OF THIS DOCUMENT, INCLUDING, WITHOUT LIMITATION, A CLAIM THAT SUCH USE INFRINGES A THIRD PARTY’S INTELLECTUAL PROPERTY RIGHTS OR THAT IT FAILS TO COMPLY WITH APPLICABLE LAWS OR REGULATIONS. BY USE OF THIS DOCUMENT, THE USER WAIVES ANY SUCH CLAIM AGAINST EEA AND ITS MEMBERS RELATING TO THE USE OF THIS DOCUMENT.

EEA reserves the right to adopt any changes or alterations to this document as it deems necessary or appropriate without any notice. User is solely responsible for determining whether this document has been superseded by a later version or a different document.