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