mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
* v2.1.0.2 * restore tweaks to simlibp2p * fix: nil ref on size calc * fix: panic should induce shutdown from event_distributor * fix: friendlier initialization that requires less manual kickstarting for test/devnets * fix: fewer available shards than provers should choose shard length * fix: update stored worker registry, improve logging for debug mode * fix: shut the fuck up, peer log * qol: log value should be snake cased * fix:non-archive snap sync issues * fix: separate X448/Decaf448 signed keys, add onion key to registry * fix: overflow arithmetic on frame number comparison * fix: worker registration should be idempotent if inputs are same, otherwise permit updated records * fix: remove global prover state from size calculation * fix: divide by zero case * fix: eager prover * fix: broadcast listener default * qol: diagnostic data for peer authenticator * fix: master/worker connectivity issue in sparse networks tight coupling of peer and workers can sometimes interfere if mesh is sparse, so give workers a pseudoidentity but publish messages with the proper peer key * fix: reorder steps of join creation * fix: join verify frame source + ensure domain is properly padded (unnecessary but good for consistency) * fix: add delegate to protobuf <-> reified join conversion * fix: preempt prover from planning with no workers * fix: use the unallocated workers to generate a proof * qol: underflow causes join fail in first ten frames on test/devnets * qol: small logging tweaks for easier log correlation in debug mode * qol: use fisher-yates shuffle to ensure prover allocations are evenly distributed when scores are equal * qol: separate decisional logic on post-enrollment confirmation into consensus engine, proposer, and worker manager where relevant, refactor out scoring * reuse shard descriptors for both join planning and confirm/reject decisions * fix: add missing interface method and amend test blossomsub to use new peer id basis * fix: only check allocations if they exist * fix: pomw mint proof data needs to be hierarchically under global intrinsic domain * staging temporary state under diagnostics * fix: first phase of distributed lock refactoring * fix: compute intrinsic locking * fix: hypergraph intrinsic locking * fix: token intrinsic locking * fix: update execution engines to support new locking model * fix: adjust tests with new execution shape * fix: weave in lock/unlock semantics to liveness provider * fix lock fallthrough, add missing allocation update * qol: additional logging for diagnostics, also testnet/devnet handling for confirmations * fix: establish grace period on halt scenario to permit recovery * fix: support test/devnet defaults for coverage scenarios * fix: nil ref on consensus halts for non-archive nodes * fix: remove unnecessary prefix from prover ref * add test coverage for fork choice behaviors and replay – once passing, blocker (2) is resolved * fix: no fork replay on repeat for non-archive nodes, snap now behaves correctly * rollup of pre-liveness check lock interactions * ahead of tests, get the protobuf/metrics-related changes out so teams can prepare * add test coverage for distributed lock behaviors – once passing, blocker (3) is resolved * fix: blocker (3) * Dev docs improvements (#445) * Make install deps script more robust * Improve testing instructions * Worker node should stop upon OS SIGINT/SIGTERM signal (#447) * move pebble close to Stop() * move deferred Stop() to Start() * add core id to worker stop log message * create done os signal channel and stop worker upon message to it --------- Co-authored-by: Cassandra Heart <7929478+CassOnMars@users.noreply.github.com> --------- Co-authored-by: Daz <daz_the_corgi@proton.me> Co-authored-by: Black Swan <3999712+blacks1ne@users.noreply.github.com>
310 lines
7.9 KiB
Go
310 lines
7.9 KiB
Go
package hypergraph
|
||
|
||
import (
|
||
"math/big"
|
||
"slices"
|
||
|
||
"source.quilibrium.com/quilibrium/monorepo/types/crypto"
|
||
"source.quilibrium.com/quilibrium/monorepo/types/hypergraph"
|
||
"source.quilibrium.com/quilibrium/monorepo/types/tries"
|
||
)
|
||
|
||
// IdSet represents a set of atom IDs with their associated atoms.
|
||
// It uses a lazy vector commitment tree for efficient storage and proofs.
|
||
type idSet struct {
|
||
dirty bool
|
||
atomType hypergraph.AtomType
|
||
tree *tries.LazyVectorCommitmentTree
|
||
validator hypergraph.TreeValidator
|
||
}
|
||
|
||
// NewIdSet creates a new phase set for the specified atom and phase types.
|
||
// IdSets are CRDTs – combining two of them for add and remove phases creates a
|
||
// standard 2P set. These are combined for a 2P2P-Hypergraph CRDT.
|
||
func NewIdSet(
|
||
atomType hypergraph.AtomType,
|
||
phaseType hypergraph.PhaseType,
|
||
shardKey tries.ShardKey,
|
||
store tries.TreeBackingStore,
|
||
prover crypto.InclusionProver,
|
||
root tries.LazyVectorCommitmentNode,
|
||
coveredPrefix []int,
|
||
) *idSet {
|
||
return &idSet{
|
||
dirty: false,
|
||
atomType: atomType,
|
||
tree: &tries.LazyVectorCommitmentTree{
|
||
SetType: string(atomType),
|
||
PhaseType: string(phaseType),
|
||
ShardKey: shardKey,
|
||
Store: store,
|
||
InclusionProver: prover,
|
||
Root: root,
|
||
CoveredPrefix: coveredPrefix,
|
||
},
|
||
}
|
||
}
|
||
|
||
// AttachValidator attaches a validation function to this ID set. The validator
|
||
// will be called when validating trees during sync operations.
|
||
func (set *idSet) AttachValidator(validator hypergraph.TreeValidator) {
|
||
set.validator = validator
|
||
}
|
||
|
||
// GetTree returns the underlying tree. Be cautious when using this.
|
||
func (set *idSet) GetTree() *tries.LazyVectorCommitmentTree {
|
||
return set.tree
|
||
}
|
||
|
||
// ValidateTree validates a vector commitment tree using the attached validator.
|
||
// If no validator is attached, returns nil. This is used to validate data
|
||
// trees associated with atoms in the set.
|
||
func (set *idSet) ValidateTree(
|
||
key, value []byte,
|
||
tree *tries.VectorCommitmentTree,
|
||
) error {
|
||
if set.validator != nil {
|
||
return set.validator(key, value, tree)
|
||
} else {
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// IsDirty returns true if the set has been modified since last commit. A dirty
|
||
// set indicates uncommitted changes that need to be persisted.
|
||
func (set *idSet) IsDirty() bool {
|
||
return set.dirty
|
||
}
|
||
|
||
// Add inserts an atom into the ID set. The atom must match the set's atom type
|
||
// or ErrInvalidAtomType is returned. The atom is added to both the in-memory
|
||
// map and the backing tree store.
|
||
func (set *idSet) Add(
|
||
txn tries.TreeBackingStoreTransaction,
|
||
atom hypergraph.Atom,
|
||
) error {
|
||
if atom.GetAtomType() != set.atomType {
|
||
return hypergraph.ErrInvalidAtomType
|
||
}
|
||
|
||
id := atom.GetID()
|
||
set.dirty = true
|
||
return set.tree.Insert(
|
||
txn,
|
||
id[:],
|
||
atom.ToBytes(),
|
||
atom.Commit(set.tree.InclusionProver),
|
||
atom.GetSize(),
|
||
)
|
||
}
|
||
|
||
// Delete removes an atom from the ID set. The atom must match the set's atom
|
||
// type or ErrInvalidAtomType is returned. The atom is removed from the backing
|
||
// tree store.
|
||
func (set *idSet) Delete(
|
||
txn tries.TreeBackingStoreTransaction,
|
||
atom hypergraph.Atom,
|
||
) error {
|
||
if atom.GetAtomType() != set.atomType {
|
||
return hypergraph.ErrInvalidAtomType
|
||
}
|
||
|
||
id := atom.GetID()
|
||
set.dirty = true
|
||
return set.tree.Delete(txn, id[:])
|
||
}
|
||
|
||
// GetSize returns the total size of all atoms in the set. Returns 0 if the
|
||
// tree has no size information.
|
||
func (set *idSet) GetSize() *big.Int {
|
||
size := set.tree.GetSize()
|
||
if size == nil {
|
||
size = big.NewInt(0)
|
||
}
|
||
return size
|
||
}
|
||
|
||
// Has checks if an atom with the given ID exists in the set. Returns true if
|
||
// the atom is present, false otherwise.
|
||
func (set *idSet) Has(key [64]byte) bool {
|
||
_, err := set.tree.Store.GetNodeByKey(
|
||
set.tree.SetType,
|
||
set.tree.PhaseType,
|
||
set.tree.ShardKey,
|
||
key[:],
|
||
)
|
||
return err == nil
|
||
}
|
||
|
||
func (hg *HypergraphCRDT) GetCoveredPrefix() ([]int, error) {
|
||
hg.mu.RLock()
|
||
defer hg.mu.RUnlock()
|
||
return hg.getCoveredPrefix(), nil
|
||
}
|
||
|
||
func (hg *HypergraphCRDT) getCoveredPrefix() []int {
|
||
return slices.Clone(hg.coveredPrefix)
|
||
}
|
||
|
||
func (hg *HypergraphCRDT) SetCoveredPrefix(prefix []int) error {
|
||
hg.mu.Lock()
|
||
defer hg.mu.Unlock()
|
||
hg.coveredPrefix = slices.Clone(prefix)
|
||
|
||
for _, s := range hg.hyperedgeAdds {
|
||
s.GetTree().CoveredPrefix = prefix
|
||
}
|
||
|
||
for _, s := range hg.hyperedgeRemoves {
|
||
s.GetTree().CoveredPrefix = prefix
|
||
}
|
||
|
||
for _, s := range hg.vertexAdds {
|
||
s.GetTree().CoveredPrefix = prefix
|
||
}
|
||
|
||
for _, s := range hg.vertexRemoves {
|
||
s.GetTree().CoveredPrefix = prefix
|
||
}
|
||
|
||
return hg.store.SetCoveredPrefix(prefix)
|
||
}
|
||
|
||
// GetVertexAddsSet returns a specific vertex addition set by shard key.
|
||
// Note: This function is exposed for tests only – do not use directly unless
|
||
// verifying underlying state
|
||
func (
|
||
hg *HypergraphCRDT,
|
||
) GetVertexAddsSet(shardKey tries.ShardKey) hypergraph.IdSet {
|
||
return hg.getVertexAddsSet(shardKey)
|
||
}
|
||
|
||
func (
|
||
hg *HypergraphCRDT,
|
||
) getVertexAddsSet(shardKey tries.ShardKey) hypergraph.IdSet {
|
||
coveredPrefix := []int{}
|
||
if shardKey.L1 != [3]byte{0, 0, 0} {
|
||
coveredPrefix = hg.getCoveredPrefix()
|
||
}
|
||
adds, _ := hg.getOrCreateIdSet(
|
||
shardKey,
|
||
hg.vertexAdds,
|
||
hg.vertexRemoves,
|
||
hypergraph.VertexAtomType,
|
||
coveredPrefix,
|
||
)
|
||
return adds
|
||
}
|
||
|
||
// GetVertexRemovesSet returns a specific vertex removal set by shard key.
|
||
// Note: This function is exposed for tests only – do not use directly unless
|
||
// verifying underlying state
|
||
func (
|
||
hg *HypergraphCRDT,
|
||
) GetVertexRemovesSet(shardKey tries.ShardKey) hypergraph.IdSet {
|
||
return hg.getVertexRemovesSet(shardKey)
|
||
}
|
||
|
||
func (
|
||
hg *HypergraphCRDT,
|
||
) getVertexRemovesSet(shardKey tries.ShardKey) hypergraph.IdSet {
|
||
coveredPrefix := []int{}
|
||
if shardKey.L1 != [3]byte{0, 0, 0} {
|
||
coveredPrefix = hg.getCoveredPrefix()
|
||
}
|
||
_, removes := hg.getOrCreateIdSet(
|
||
shardKey,
|
||
hg.vertexAdds,
|
||
hg.vertexRemoves,
|
||
hypergraph.VertexAtomType,
|
||
coveredPrefix,
|
||
)
|
||
return removes
|
||
}
|
||
|
||
// GetHyperedgeAddsSet returns a specific hyperedge addition set by shard key.
|
||
// Note: This function is exposed for tests only – do not use directly unless
|
||
// verifying underlying state
|
||
func (
|
||
hg *HypergraphCRDT,
|
||
) GetHyperedgeAddsSet(shardKey tries.ShardKey) hypergraph.IdSet {
|
||
return hg.getHyperedgeAddsSet(shardKey)
|
||
}
|
||
|
||
func (
|
||
hg *HypergraphCRDT,
|
||
) getHyperedgeAddsSet(shardKey tries.ShardKey) hypergraph.IdSet {
|
||
coveredPrefix := []int{}
|
||
if shardKey.L1 != [3]byte{0, 0, 0} {
|
||
coveredPrefix = hg.getCoveredPrefix()
|
||
}
|
||
adds, _ := hg.getOrCreateIdSet(
|
||
shardKey,
|
||
hg.hyperedgeAdds,
|
||
hg.hyperedgeRemoves,
|
||
hypergraph.HyperedgeAtomType,
|
||
coveredPrefix,
|
||
)
|
||
return adds
|
||
}
|
||
|
||
// GetHyperedgeRemovesSet returns a specific hyperedge removal set by shard key.
|
||
// Note: This function is exposed for tests only – do not use directly unless
|
||
// verifying underlying state
|
||
func (
|
||
hg *HypergraphCRDT,
|
||
) GetHyperedgeRemovesSet(shardKey tries.ShardKey) hypergraph.IdSet {
|
||
return hg.getHyperedgeRemovesSet(shardKey)
|
||
}
|
||
|
||
func (
|
||
hg *HypergraphCRDT,
|
||
) getHyperedgeRemovesSet(shardKey tries.ShardKey) hypergraph.IdSet {
|
||
coveredPrefix := []int{}
|
||
if shardKey.L1 != [3]byte{0, 0, 0} {
|
||
coveredPrefix = hg.getCoveredPrefix()
|
||
}
|
||
_, removes := hg.getOrCreateIdSet(
|
||
shardKey,
|
||
hg.hyperedgeAdds,
|
||
hg.hyperedgeRemoves,
|
||
hypergraph.HyperedgeAtomType,
|
||
coveredPrefix,
|
||
)
|
||
return removes
|
||
}
|
||
|
||
// getOrCreateIdSet returns the add and remove sets for the given shard. If the
|
||
// sets don't exist, they are created with the appropriate parameters.
|
||
func (hg *HypergraphCRDT) getOrCreateIdSet(
|
||
shardAddr tries.ShardKey,
|
||
addMap map[tries.ShardKey]hypergraph.IdSet,
|
||
removeMap map[tries.ShardKey]hypergraph.IdSet,
|
||
atomType hypergraph.AtomType,
|
||
coveredPrefix []int,
|
||
) (hypergraph.IdSet, hypergraph.IdSet) {
|
||
if _, ok := addMap[shardAddr]; !ok {
|
||
addMap[shardAddr] = NewIdSet(
|
||
atomType,
|
||
hypergraph.AddsPhaseType,
|
||
shardAddr,
|
||
hg.store,
|
||
hg.prover,
|
||
nil,
|
||
coveredPrefix,
|
||
)
|
||
}
|
||
if _, ok := removeMap[shardAddr]; !ok {
|
||
removeMap[shardAddr] = NewIdSet(
|
||
atomType,
|
||
hypergraph.RemovesPhaseType,
|
||
shardAddr,
|
||
hg.store,
|
||
hg.prover,
|
||
nil,
|
||
coveredPrefix,
|
||
)
|
||
}
|
||
return addMap[shardAddr], removeMap[shardAddr]
|
||
}
|