By Sfxdx, edited by Michael Chen

Introduction

This doc describes 2 approaches of implementation of the ChainWitness consensus algorithm — the “monolithic DAG” and the “DAGchain”. It also summarizes other algorithms — ordering function, fork mechanics.

Option 1: Monolithic DAG

Overview

The approach is to store events in one DAG — like Swirlds or Lachesis papers.

It has the following engineering difficulties:

At any time, a node may discover a new event, which links to a far-in-past event. It limits us regarding which events we may prune. Also it doesn’t allow us to prune old some indexes (node balances, as an example). The event is authorized via node stake. The stake may change. We need an algorithm, which will allow to calculate authorization-stake consistently.

These difficulties aren’t related to consensus itself, they are engineering difficulties.

We’re sure that these difficulties may be solved, but we don’t have any good solution at the moment.

We tried the following directions:

Forbidding links to “old” events, which would allow node to prune old indexes. We didn’t find the rules without counterexamples. Self-contained event. The event contains the cryptographic proof of its authorization stake amount. It’s easy to prove the stake amount via Merkle path, if we can refer to a Merkle tree of balances. We’ve found some ways to self-prove the authorization stake, but they were not effective. Like in Swirlds paper, re-processing of events if stakes are changed during deciding a frame. Event has different stakes: consensus stake, authorization stake. This approach is difficult to implement. Also it’s a considerable overhead as well.

The only known working solution is re-calculation of events after every consensus stake change, and usage of different calculations of stake for different purposes. It’s difficult to implement.

Scope1

Authorization stake

Implement authorization stake as a node’s balance after execution of subgraph internal transactions. To implement it efficiently, events are stored with a cache of executed subgraph internal transactions. Additional research is needed to define an exact algorithm.

Event’s subgraph is the same on all the nodes, so this value is guaranteed to be equal on all the nodes.

Consensus stake

After each decided frame = f, confirmed transactions are executed. Stakes may change after execution of transactions. If they did change, then all the events from frames > f are re-calculated (strongly see condition changes). Only root status may change. It cannot lead to dropping event, because consensus stake isn’t used for event authorization.

Sybil attack mitigation

To mitigate the Sybil attack, only nodes with top-30 stakes have a right to create events. 30 is discussable constant.

It’s possible to use a randomized selection algorithm, but it’ll be harder to implement, as we’ll have to implement a “fare” source of random number.

Also it’s possible to implement voting for nodes which may create events — like in dPoS. It’s also hard to implement.

The stake send should burn a fee. To mitigate the attack when node constantly sends its stake to a new node. Every node (event with 1 event) consumes certain amount of disk storage.

Currently, we have an issue with current stake send transaction:

Currently the transaction which sends stake, may only be included into sender’s event. So if a node has stake, but it’s not top-30 stake, then node cannot send this stake because it cannot create event.

Scope2

At the moment, we’re not sure how exactly the difficulties of the approach may be solved.

Option 2: Chain of small DAGs (“DAGchain”)

Overview

The approach is to store events within a chain, where each chain element is a DAG with 100 decided frames. These small DAGs are currently called superframes. 100 is a discussable constant.

Once current superframe has a decided 100th frame, all the internal indexes related to this superframe are pruned. Events may be pruned as well, it depends on the config. If new event arrives for a sealed superframe, then this message may be ignored. It’s possible because superframes don’t depend on prev superframes, only on their finalized state.

Pros/cons

In terms of trade-offs, this approach has cons:

The events at the end of superframe never get confirmed, and used only to decide 100th frame. Txs within these events will have to be re-posted in new superframe. It doesn’t affect the average transaction latency (because it happens only at the end, which is rarely), but increases the maximum transaction latency at the end of superframe. Node may place a fork after 100th ChainWitness, and the cheating node will not get punished for that because this event will not get confirmed. To cover this case, we would need to add a new transaction, which will contain 2 conflicting events headers as a proof of doublesign. So in the current superframe, other nodes will post this transaction. It would be very nice-to-have but not critical for security if 2/3n are honest.

pros:

Pruning data is possible Node stakes are frozen within superframe, so it’s not needed to re-process events after stake change. FastSync may be implemented in a similar way, in which ETH FastSync is implemented. SPV-like wallet is possible as well. Caching may be more efficient if number of frames is limited. Easier to deploy upgrades (hard forks), because they may be anchored to superframe height, instead of frame height.

Scope1

Implement superframes

Every superframe starts with a link to 100th ChainWitness of previous superframe. This link may be implemented as a parent, or as a separate field. This link has to be checked during syncing as a sanity check. superframe is considered as sealed, when 100th frame is decided. When superframe is sealed, all the internal caches and indexes are pruned. New events for this superframe are ignored, because they cannot change the finalized state (unless more than 1/3n are Byzantine). Within superframe, node stakes are frozen, and nodes list is frozen. The changes are applied only in the next superframe.

Sybil attack mitigation

To mitigate the Sybil attack, only nodes with top-30 stakes have a right to create events. 30 is discussable constant.

It’s possible to use a randomized selection algorithm, but it’ll be harder to implement, as we’ll have to implement a “fare” source of random number.

Also it’s possible to implement voting for nodes which may create events — like in dPoS. It’s also hard to implement.

Currently, we have an issue with current stake send transaction:

Currently the transaction which sends stake, may only be included into sender’s event. So if a node has stake, but it’s not top-30 stake, then node cannot send this stake because it cannot create event.

Scope2

FastSync

FastSync syncing algorithm plot:

When superframe is sealed, nodes sign the final state (or only a difference since prev. superframe state), and nodes list in the new superframe. FastSync nodes receive these signatures, and authenticate them against the list of nodes (which is signed by prev. signatures) FastSync nodes download only the last state, or the chain of differences between states FastSync nodes continue syncing as FullNodes

2 layers of nodes

Discussable idea:

Nodes from top-30 have a right to create root events and non-root events.

Nodes from top-200 have a right to create non-root events.

It’s possible because the most of the overhead is related to root events.

The node should have a flag which will or will not allow to be in first group of nodes.

Fast sealing of superframe

The events at the end of superframe never get confirmed, and used only to decide 100th frame.

To decrease the latency of these txs, nodes send events with frame >= 100 without txs and with no delays. This way, the last frame will get decided faster than others, and the new superframe will start sooner.

Pruning events

If node is launched with a specific config, then node prones the events of decided superframes. Depending on params, it may store up to N last superframes.

Dismissing dead nodes

If node is top-30 and it has no confirmed event during a superframe, then it gets dismissed. The economic penalty may be applied.

It’ll help to mitigate the situation when more than 1/3n of nodes are offline.

Node should have a way to flag that it’s not ready to create events (as example, we can have staked balance and untouchable balance).

Other algorithms

Fork mechanics

https://docs.google.com/document/d/1BZ6WaDi3epAsE20doOY22PSUBuy5CtgnBxSpWAS1qok/edit?usp=sharing

Ordering function

We believe, we have to choose from 2 groups of approaches — one group are “fast” algorithms without sorting, second group are “fare” (i.e. their ordering/timestamps are unbiased, close to real clock time) algorithms.

Fast ordering

Regarding “fast” algorithms, we have only 1 algorithm to propose:

Breadth-first traversal of the events since last confirmed events, starting from the ChainWitness. Traverse events in order in which they are referenced by event. We started with the last event, so we should write them in a reversed order

Pros:

- low computational complexity

- should be “simple” to implement

- ordering is at least related to the real time (as we traverse graph “layer by layer”)

- it iterates over all the confirmed events, which may be a dual use

Cons:

- it iterates events in the reversed order

- ordering isn’t completely predictable. It’s possible (in certain cases) that self-parent is earlier than a descendant

- ordering is easy to bias

- doesn’t assign timestamp. Timestamp isn’t needed in consensus, but may be used by a VM during txs execution.

“Fare” ordering

The algorithm is based on the lamport timestamps. The intuition is to estimate a timestamp of the event with greatest lamport timestamp (it’s always Chain Witness). Then linearly interpolate consensus timestamps from lowest lamport timestamp to the greatest.

Pros:

- assigns timestamps. Timestamp isn’t needed in consensus, but may be used by a VM during txs execution.

- We may not store the consensus timestamps, instead we may store only timeRatio and timeOffset for each ChainWitness, and lamport timestamp for each event

- hard to bias the timestamp more than time passed since previous Chain Witness

- ordering is predictable. Every event will get greater timestamp than its parents

Cons:

- we cannot store timestamps in “secs”, we need more precision for interpolation. Should be “usec” or “nsec”.