Documentation
¶
Overview ¶
Package state manages persistent state for the S-Chain — the Lux storage VM.
M0 persists exactly two things over the chain's database namespace:
- MANIFESTS — the (bucket, object) -> {fileIds, size, etag} mapping that records which content blobs make up an object.
- LAST-BLOCK pointer — the last-accepted block id + height, the recovery anchor.
Every accessor reads/writes through the supplied database.Database, which the VM hands in as a *versiondb.Database (the per-block in-memory version layer). A Put therefore stages into the version layer during block processing and becomes durable ONLY when the VM commits the batch at Accept — the exact commit discipline dexvm/state/state.go follows. This package never imports the zapdb engine directly; it speaks only the luxfi/database interface, so the VM is free to swap the backing store.
Index ¶
- Variables
- type Manifest
- type State
- func (s *State) GetLastBlock() (ids.ID, uint64)
- func (s *State) GetManifest(bucket, object string) (m Manifest, found bool, err error)
- func (s *State) Initialize() error
- func (s *State) PutManifest(bucket, object string, m Manifest) error
- func (s *State) Root() (ids.ID, error)
- func (s *State) SetLastBlock(blockID ids.ID, height uint64) error
Constants ¶
This section is empty.
Variables ¶
var ( // ErrStateCorrupted is returned when a stored value cannot be decoded into // its expected shape — a corrupt record must never be silently reinterpreted. ErrStateCorrupted = errors.New("state corrupted") )
Functions ¶
This section is empty.
Types ¶
type Manifest ¶
type Manifest struct {
FileIDs []string `json:"fileIds"`
Size int64 `json:"size"`
ETag string `json:"etag"`
}
Manifest is the committed content manifest for one object: the file blobs that compose it plus the object-level metadata an S3 HEAD returns. It is encoded as a deterministic JSON body (no maps, declaration-order fields), the same self-describing, protobuf-free style dexvm uses for its structured values.
type State ¶
type State struct {
// contains filtered or unexported fields
}
State manages the S-Chain's persistent state over the version layer `db`.
func New ¶
New creates a state manager over db — the per-block version layer the VM commits atomically at Accept. Mirrors dexstate.New (dexvm/state/state.go:96), minus the durable receipt side-channel the storage VM does not need in M0.
func (*State) GetLastBlock ¶
GetLastBlock returns the last accepted block id and height.
func (*State) GetManifest ¶
GetManifest returns the manifest for (bucket, object). found is false when no manifest exists. Reads through the version layer, so it observes a manifest staged in this block before commit (the in-flight view) and the durable store after commit — identical to dexvm's versiondb-backed reads.
func (*State) Initialize ¶
Initialize loads the last-accepted block pointer from the database.
func (*State) PutManifest ¶
PutManifest stages a manifest into the version layer. It becomes durable only when the VM commits the block's batch at Accept — before that, a GetManifest on a freshly-constructed reader over the base DB does not see it. This is the versiondb/CommitBatch discipline the M0 proof asserts.
func (*State) Root ¶
Root returns a deterministic SHA-256 commitment over the COMMITTED manifest keyspace: every manifest/<bucket>/<object> -> {fileIds,size,etag} entry the chain holds after this block's writes are staged. It is the value the block header binds, so two validators whose manifest state actually diverges (a different object set, a changed etag/size/fileIds for the same object) ALWAYS produce different roots — divergence can never hide behind a matching block hash. This is the manifest-VM analog of dexvm's State.StateHash (dexvm/state/ state.go:395), narrowed to the storage VM's one keyspace.
The walk uses the zapdb prefix iterator NewIteratorWithStartAndPrefix(nil, prefixManifest), so it reads through the versiondb (this block's staged in-memory writes merged over the durable base, deleted keys dropped) and only the manifest keyspace — the last-block pointer is consensus binding folded separately into the header via blockHash/height, NOT object state, so it is excluded here exactly as dexvm excludes its proposer-local receipt prefix.
Keys come out in lexicographic order, so the digest is independent of write history. Each field (domain, key, value) is framed with SP 800-185 left_encode of its BIT length before it is absorbed, so no two distinct (key,value) splits can collide by concatenation — the same canonicalization the validator NodeID scheme uses (ids/node_id_scheme.go). The hash is SHAKE256 (SHA-3): not length-extendable (unlike SHA-256), domain-separated by stateRootDomain, and PQ-strength (256-bit output → 128-bit collision/preimage even under Grover).