Skip to content
/ e2c Public

E2C Consensus Protocol implemented on Go-Quorum

License

LGPL-3.0, GPL-3.0 licenses found

Licenses found

LGPL-3.0
COPYING.LESSER
GPL-3.0
COPYING
Notifications You must be signed in to change notification settings

coltonfike/e2c

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

E2C - Energy Efficient State Machine Replication

E2C is a protocol outlined in a paper pending submission that is based on best-case optimality. It is an evolution of the Sync HotStuff protocol. The protocol sacrifices a small performance loss in the case of faulty nodes in order to outperform in the best-case. E2C requires O(1) signatures and O(n) verifications in the best-case as opposed to Sync HotStuff which requires O(n) signatures and O(n2) verifications.

This implementation is used to test its performance in a real system. We leverage the go-quorum so that we can use all features they have implemented. Our results show that E2C is capable of more transactions/second than the included IBFT.

Setup

Nodes should be generated by following the first two steps of the guide by Consensys for the IBFT protocol. When following this guide, it is important that you generate member nodes and not just validator nodes. member nodes (also referred to as client nodes) are nodes that do not participate in consensus and only follow the validator nodes. All Web3 scripts should only attach to member nodes, as they are guaranteed to have a correct state. A validator node is not guaranteed to have a correct state, since the node you attach to could be faulty and thus have an incorrect state. Next you must generate a genesis file. An example genesis.json file for an E2C network is as follows:

{
    "config": {
        "chainId": 10,
        "homesteadBlock": 0,
        "eip150Block": 0,
        "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "eip155Block": 0,
        "eip158Block": 0,
        "byzantiumBlock": 0,
        "constantinopleBlock": 0,
        "petersburgBlock": 0,
        "istanbulBlock": 0,
        "e2c": {
            "delta": 200,
            "blockSize": 200
        },
        "txnSizeLimit": 64,
        "maxCodeSize": 0,
        "qip714Block": 0,
        "isMPS": false,
        "isQuorum": true
    },
    "nonce": "0x0",
    "timestamp": "0x60e89145",
    "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000f899f85494030e71f5bedd0fe4582d1eac9b7e8743b9134e5f943a4390b9590ec4fe25877a2bd8472d66a9e9036c944ea3600670d3e931ad6f34fc91954d181fb91bd7945f324f4842656d640bc620288f4a644d3a12e3a4b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "gasLimit": "0xe0000000",
    "difficulty": "0x1",
    "mixHash": "0xd5d31c273f79321e73e40d6b891b153544c63beabb86b1c020578e7e998461f2",
    "coinbase": "0x0000000000000000000000000000000000000000",
    "alloc": {
        "030e71f5bedd0fe4582d1eac9b7e8743b9134e5f": {
            "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
        }
    },
    "number": "0x0",
    "gasUsed": "0x0",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}

Before using this genesis file, we must make a few changes. First, you will want to change the extra data field to one that will match the addresses you created by following the Consensys guide. To do this, we must first generate the correct extra data field by copying the address of all the nodes in the validator set and paste them into the array in this go program, which is included in testnet/encode/encode.go:

package main

import (
	"bytes"
	"fmt"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	atypes "github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/rlp"
)

func Encode(vanity string, validators []common.Address) (string, error) {
	newVanity, err := hexutil.Decode(vanity)
	if err != nil {
		return "", err
	}

	if len(newVanity) < atypes.E2CExtraVanity {
		newVanity = append(newVanity, bytes.Repeat([]byte{0x00}, atypes.E2CExtraVanity-len(newVanity))...)
	}
	newVanity = newVanity[:atypes.E2CExtraVanity]

	ist := &atypes.E2CExtra{
		Validators: validators,
		Seal:       make([]byte, atypes.E2CExtraSeal),
	}

	payload, err := rlp.EncodeToBytes(&ist)
	if err != nil {
		return "", err
	}

	return "0x" + common.Bytes2Hex(append(newVanity, payload...)), nil
}

func main() {
	addr := []common.Address{
		common.HexToAddress("0396ea1512b97c9f7e90f641a46f48967db064ba"),
		common.HexToAddress("17145655faf1fcbbd0473502c504f32ca9ebe144"),
		common.HexToAddress("1a80a2887c640c886606e34d9cfc48637a5b4ceb"),
		common.HexToAddress("200a7b1d5f2de512c05b0c46eb50e4d2f2922ada")
        // Repeat for as many addresses as you have in validator set
        }

	s, _ := Encode("0x00", addr)
	fmt.Println("Extra Data: " + s)
	E2CDigest := common.HexToHash(crypto.Keccak256Hash([]byte("E2C practical byzantine fault tolerance")).String())
	fmt.Println("Mix Hash: " + E2CDigest.String())
}

An example output of this script is:

Extra Data: 0x0000000000000000000000000000000000000000000000000000000000000000f899f854940396ea1512b97c9f7e90f641a46f48967db064ba9417145655faf1fcbbd0473502c504f32ca9ebe144941a80a2887c640c886606e34d9cfc48637a5b4ceb94200a7b1d5f2de512c05b0c46eb50e4d2f2922adab8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`
Mix Hash: 0xd5d31c273f79321e73e40d6b891b153544c63beabb86b1c020578e7e998461f2

For the field labeled extra data, replace the value with the extra data value given from the script.

You can create client accounts by using geth as you would normally. Next, you will likely want to prefund those created accounts. This is done in the genesis file by the alloc field here:

"alloc": {
        "030e71f5bedd0fe4582d1eac9b7e8743b9134e5f": {
            "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
        },
        "address 2": {
            "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
        },
        // Repeat for all address you want to prefund
    },

Finally, you may want to change some settings for the E2C engine. There are two settings available: delta and blockSize. delta is the upper bound on network speed in milliseconds. The E2C engine assumes that it never takes longer than delta for a message to be delivered. If delta is too small, the E2C engine will constantly be changing the leader due to nodes believing a leader is faulting. If delta is too large, the latency will increase. It is likely that you will want to try different values to see what works best, but 200 milliseconds is the default. blockSize determines how many transactions will be included in each block. An example configuration is given below:

"e2c": {
            "delta": 200,
            "blockSize": 200
        },

Running the Network

To compile the program, you will need to navigate to cmd/geth and run go install. We also include a script build.sh to do the compilation as well. There will be a warning when the program is compiled. This is expected and can be ignored.

To run a validator node, you run it as you would normally run any go-quorum node. It was run with PRIVATE_CONFIG=ignore geth --datadir $DIR --verbosity 4 --nodiscover --syncmode full --mine --networkid 10 --port 30300 --ws --ws.addr 'localhost' --ws.port 8500 --ws.api admin,eth,miner,net,txpool,personal,web3 --allow-insecure-unlock for our testing.

To run a client node, you use the same command, but without the --mine tag.

Sending transactions or performing any other Web3 operation is done via Web3 or via Geth Attach.

We provide the networks we used for testing in the testnet directory. We have networks with 4, 8, 16, and 32 nodes already setup that we used for testing. Included is a test script, run_test.sh, that will start the network, send numerous transactions, and output the transactions per second. To run a 4 node test, ./run_test.sh 4 "n4" "n4/e2c.json". To run an 8, 16, or 32 node test, use the same command but replace all 4's with whatever number of nodes you are running with.

About

E2C Consensus Protocol implemented on Go-Quorum

Resources

License

LGPL-3.0, GPL-3.0 licenses found

Licenses found

LGPL-3.0
COPYING.LESSER
GPL-3.0
COPYING

Security policy

Stars

Watchers

Forks

Packages

No packages published