Governance

Governance

The state chain implements DAO governance through multisig blocks. A quorum of DAO members must sign each block before it can be applied to the chain. The DAO keyset -- the set of authorised signers and their quorum threshold -- is stored in the chain's own KV store, making governance self-referential: the keyset governs changes to itself.

#DAOKeyset

go
type DAOKeyset struct {    Keys      []string // hex-encoded ed25519 public keys (64 hex chars each)    Threshold int      // minimum number of valid signatures required}

The keyset is stored under the sys.dao_keyset key in the state chain's KV store. It is set in the genesis block and can be updated by subsequent blocks (signed by the current keyset).

#Block structure

go
type Block struct {    Index      uint64           `json:"index"`    PrevHash   string           `json:"prev_hash"`    Ops        []Op             `json:"ops"`    Signatures []BlockSignature `json:"signatures"`    Hash       string           `json:"hash"`    Timestamp  int64            `json:"timestamp"`}
FieldDescription
IndexSequential position in the chain (genesis = 0)
PrevHashSHA-256 hash of the previous block (empty string for genesis)
OpsArray of key-value operations to apply
SignaturesArray of ed25519 signatures from DAO members
HashSHA-256 hash computed over the operations only
TimestampUnix nanoseconds; must be >= previous block's timestamp

#BlockSignature

go
type BlockSignature struct {    PublicKey string `json:"public_key"` // hex-encoded ed25519 public key    Sig       string `json:"signature"`  // hex-encoded ed25519 signature}

Each signature is over the block's Hash field. The signer must be a member of the current DAOKeyset.

#Multisig validation

When AddBlock processes a new block, it validates the multisig:

  1. Hash verification -- recompute the hash from ops and compare to block.Hash.
  2. Duplicate check -- reject blocks with the same signer appearing twice.
  3. Keyset membership -- every signer's public key must be in the current DAOKeyset.Keys.
  4. Signature verification -- each ed25519.Verify(pubkey, hash, signature) must pass.
  5. Threshold check -- the count of valid signatures must be >= DAOKeyset.Threshold.
diagram
Block arrives    │    ▼Verify block hash (recompute from ops)    │    ▼For each signature:    ├── Duplicate signer? → reject    ├── Not in keyset? → reject    └── Signature invalid? → reject    │    ▼Valid count >= threshold? → accept

#Chain management

#NewChain

go
func NewChain(store StateChainStore, genesis *Block) (*Chain, error)

Creates a new chain instance:

  1. Validates the genesis block.
  2. Creates an empty KV store.
  3. Applies genesis ops (must include sys.dao_keyset).
  4. Replays all stored blocks to rebuild KV state.
  5. Verifies a valid keyset exists after replay.

#AddBlock

go
func (c *Chain) AddBlock(b *Block) error

Validates and applies a new block:

  1. Verify hash -- recompute and compare.
  2. Duplicate/fork check -- if the block's index is at or below the tip, check for duplicate or fork.
  3. Gap check -- index must be exactly tip.Index + 1.
  4. PrevHash check -- must match the tip's hash.
  5. Timestamp monotonicity -- must be >= previous block's timestamp.
  6. Op validation -- each operation is validated (key format, value size, JSON validity).
  7. Block size check -- serialized block must not exceed MaxBlockSize.
  8. Multisig validation -- using the current keyset.
  9. Persist and apply -- store the block, update KV state, advance tip.

#Fork detection

If a block arrives with the same index as an existing block but a different hash, a fork is detected:

  1. The incoming block's multisig is verified (to filter out garbage).
  2. If valid, the forkCallback is invoked with both the existing and incoming blocks.
  3. The fork is rejected -- the chain does not switch branches.

#Chain struct

go
type Chain struct {    store        StateChainStore    kv           *KVStore           // in-memory key-value state    tip          *Block             // latest block    genesis      *Block             // genesis block (index 0)    onBlock      func(*Block)       // callback on new block applied    forkCallback func(existing, incoming *Block) // fork alert}
MethodDescription
Tip()Returns the latest block
GetBlock(index)Retrieves a block by index
GetBlocks(start, limit)Retrieves a range of blocks
BlockCount()Total blocks including genesis
GetKV(key)Reads a value from the KV store
GetKVByPrefix(prefix)Reads all keys matching a prefix
GetAllKV()Dumps the entire KV store
DAOKeyset()Returns the current DAO keyset
SetOnBlock(fn)Registers a callback for new blocks
SetForkCallback(fn)Registers a callback for fork detection

#Size limits

LimitValueDescription
MaxKeyLength128 bytesMaximum key length in an operation
MaxValueSize65,536 bytes (64 KB)Maximum value size in a set operation
MaxBlockSize262,144 bytes (256 KB)Maximum serialized block size
MinDAOThreshold2Minimum allowed DAO keyset threshold