By Sfxdx, edited by Michael Chen

Introduction

The doc describes the implementation details of DAGchain scope1.

Definitions

Objects

EventHeader

Team member ̶C̶o̶n̶s̶e̶n̶s̶u̶s̶ ̶n̶o̶d̶e̶

Election table (RAM-only)

It’s a map, located in memory:

Global state

Transaction

Activities

Setting up genesis superframe

input: genesis superframe params

Write genesis transactions state <last SfSealer> = construct event, according to genesis params <superframe height> = 1 <team> = nodes, according to genesis balances

Additional event checks

input: event

if event.<superframe height> != state.<superframe height>

a) ignore event isSfStarter = <event height> == 0 if isSfStarter

a) check that linked only to <last SfSealer>

p2p synchronization

When node requests current heights of last events, it specifies the superframe it’s interested in

Transactions posting

if event frame >= SUPERFRAME_LEN — 3

a) Don’t post transactions

Events posting

input: newly created event

if <last event from me> == nil // beginning of a superframe

a) event.parent = <last SfSealer>

Consensus activities

stronglySee

Input: event hash A, event hash B

output: bool

event — a current event. witness — a witness of the previous frame. counter — a counter for calculating strongly seeing. nodes — consensus nodes. for node range nodes

a) if witness.FirstSeq[node.ID] <= event.LastSeq[node.ID]

i. counter = counter + 1 if counter >= ⅔ * nodes.length

i. return true return false

rootStronglySeesRoot

Input: root hash A, frame height B, node id B

output: root hash or nil

Returns hash of root B, if root A strongly sees root B. Due to a fork, there may be many roots B with the same pair of {frame height B, node id B}, but strongly seen may be only one of them (if no more than 1/3n are Byzantine), with a specific hash.

A doesn’t exist

a) return nil there’s no root B with {frame height B, node id B}

a) return nil for B := range roots{frame height B, node id B}

a) if A strongly sees B

i. return B.hash return nil

election.processRoot

input: root

output: (decided frame height, sfWitness hash) or nil

calculate SfWitness votes only for the new root. If this root sees that the current election is decided, then return decided sfWitness

election.ProcessKnownRoots

input: frameToDecide

output: (decided frame height, sfWitness hash) or nil

The function is similar to processRootVotes, but it fully re-processes the current voting. This routine is called after node startup, and after each decided frame.

confirmEvents(sfWitness hash)

eventsToConfirm = not confirmed events, which are seen by sfWitness orderedEventsToConfirm = someOrderingAlgorithm(eventsToConfirm) for event := range orderedEventsToConfirm

a) event.confirmedBy = sfWitness // it should be written in a DB, and indexed by decided frame height

b) for tx := range event.txs

i. // execute tx against current global state, including changes after prev. executed txs in this loop. We don’t need to take old state, we take the latest one.

ii. p.executeTx(tx, p.txsState)

sealSuperframe

input: sfWitness

Remove the current hashgraph, except raw events history and transactions state. Calculate new team for the next superframe.

p.<last SfSealer> = sfWitness p.<superframe height> += 1 calculate new <team>

a) // if we’re here, txs are already executed

b) nodes = balances in the latest txs state

c) sortedNodes = sort nodes by stake amount, public ID

d) p.<team> = take first CONSENSUS_TEAM_SIZE elements from sortedNodes prune the caches and indexes. Except events history, transactions state and values above

onFrameDecided

input: decided frame height, sfWitness hash

confirmEvents(sfWitness) if decided frame height == SUPERFRAME_LEN — 1

a) sealSuperframe(sfWitness) clear election caches for the decided frame

consensus routine for each event

input: event