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 setsys.dao_keysetwiththreshold < 2will 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:
- Hash verification -- recompute the hash from ops and compare to
block.Hash. - Duplicate check -- reject blocks with the same signer appearing twice.
- Keyset membership -- every signer's public key must be in the current
DAOKeyset.Keys. - Signature verification -- each
ed25519.Verify(pubkey, hash, signature)must pass. - 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_keysetmust 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:
- Validates the genesis block.
- Creates an empty KV store.
- Applies genesis ops (must include
sys.dao_keyset). - Replays all stored blocks to rebuild KV state.
- Verifies a valid keyset exists after replay.
AddBlock
func (c *Chain) AddBlock(b *Block) errorValidates and applies a new block:
- Verify hash -- recompute and compare.
- Duplicate/fork check -- if the block's index is at or below the tip, check for duplicate or fork.
- Gap check -- index must be exactly
tip.Index + 1. - PrevHash check -- must match the tip's hash.
- Timestamp monotonicity -- must be >= previous block's timestamp.
- Op validation -- each operation is validated (key format, value size, JSON validity).
- Block size check -- serialized block must not exceed
MaxBlockSize. - Multisig validation -- using the current keyset.
- 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:
- The incoming block's multisig is verified (to filter out garbage).
- If valid, the
forkCallbackis invoked with both the existing and incoming blocks. - 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