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

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).

[!WARNING] Minimum threshold The minimum allowed threshold is 2 (MinDAOThreshold). This prevents a single-signer takeover via threshold downgrade. A block that attempts to set sys.dao_keyset with threshold < 2 will be rejected.

Block structure

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"`
}

Field

Description

Index

Sequential position in the chain (genesis = 0)

PrevHash

SHA-256 hash of the previous block (empty string for genesis)

Ops

Array of key-value operations to apply

Signatures

Array of ed25519 signatures from DAO members

Hash

SHA-256 hash computed over the operations only

Timestamp

Unix nanoseconds; must be >= previous block's timestamp

[!NOTE] Hash covers ops only The block hash is computed from the operations only, not the signatures. This allows signatures to be collected independently -- different DAO members can sign the same block hash without needing to coordinate signature order.

BlockSignature

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.
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

[!IMPORTANT] Keyset at validation time Multisig validation uses the keyset from the KV state before the block's ops are applied. This means a block that updates sys.dao_keyset must still be signed by the current keyset, not the new one.

Chain management

NewChain

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

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.

[!DANGER] Fork = governance emergency A fork in the state chain means two validly-signed blocks exist at the same index. This indicates either a coordination failure or a compromised signer. The fork callback should trigger an alert.

Chain struct

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
}

Method

Description

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

Limit

Value

Description

MaxKeyLength

128 bytes

Maximum key length in an operation

MaxValueSize

65,536 bytes (64 KB)

Maximum value size in a set operation

MaxBlockSize

262,144 bytes (256 KB)

Maximum serialized block size

MinDAOThreshold

2

Minimum allowed DAO keyset threshold