mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-03-05 16:27:28 +08:00
* .20 testing * Read in the debug by env variable (#514) * v2.1.0.19 * enhanced error logging, fix seniority marker join blocker, fix sync message size limit defaults * resolve signature failure * additional error logging for merge-related signatures * fix: one-shot sync message size, app shard TC signature size, collector/hotstuff race condition, expired joins blocking new joins due to pruning disable * remove compat with old 2.0.0 blossomsub * fix: resolve abandoned prover joins * reload prover registry * fix stale worker proposal edge * add full sanity check on join before submitting to identify bug * resolve non-fallthrough condition that should be fallthrough * fix: resolve rare SIGFPE, fix orphan expired joins blocking workers from reallocating * add reconnect fallback if no peers are found with variable reconnect time (#511) Co-authored-by: Tyler Sturos <55340199+tjsturos@users.noreply.github.com> * update base peer count to 1 (#513) * fix: expired prover join frames, starting port ranges, proposer getting stuck, and seniority on joins * fix: panic on shutdown, libp2p discovery picking inaccessible peers, coverage event check not in shutdown logic, amend app shard worker behavior to mirror global for prover root reconciliation * fix: shutdown scenario quirks, reload hanging * fix: do not bailout early on shutdown of coverage check * fix: force registry refresh on worker waiting for registration * add more logging to wait for prover * fix: worker manager refreshes the filter on allocation, snapshots blocking close on shutdown * tweak: force shutdown after five seconds for app worker * fix: don't loop when shutting down * fix: slight reordering, also added named workers to trace hanging shutdowns * use deterministic key for peer id of workers to stop flagging workers as sybil attacks * fix: remove pubsub stop from app consensus engine as it shouldn't manage pubsub lifecycle, integrate shutdown context to PerformSync to prevent stuck syncs from halting respawn * fix: blossomsub pubsub interface does not properly track subscription status * fix: subscribe order to avoid nil panic * switch from dnsaddr to dns4 * add missing quic-v1 * additional logging to isolate respawn quirks * fix: dnsaddr -> dns4 for blossomsub * allow debug env var to be read --------- Co-authored-by: Cassandra Heart <cassandra@quilibrium.com> Co-authored-by: Tyler Sturos <55340199+tjsturos@users.noreply.github.com> Co-authored-by: Cassandra Heart <7929478+CassOnMars@users.noreply.github.com> * fix newPebbleDB constructor config param (#517) * fix: high CPU overhead in initial worker behaviors/ongoing sync * faster docker builds with better caching * qol: add extra data to node info, and query metrics from command line * leave proposals for overcrowded shards * hub-and-spoke global message broadcasts * small tweaks to cli output for join frames --------- Co-authored-by: winged-pegasus <55340199+winged-pegasus@users.noreply.github.com> Co-authored-by: Tyler Sturos <55340199+tjsturos@users.noreply.github.com> Co-authored-by: Black Swan <3999712+blacks1ne@users.noreply.github.com>
404 lines
14 KiB
Go
404 lines
14 KiB
Go
package tests
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"crypto/sha512"
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/cloudflare/circl/sign/ed448"
|
|
"github.com/stretchr/testify/mock"
|
|
"go.uber.org/zap"
|
|
"source.quilibrium.com/quilibrium/monorepo/config"
|
|
hg "source.quilibrium.com/quilibrium/monorepo/hypergraph"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/crypto"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/hypergraph"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/mocks"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/tries"
|
|
)
|
|
|
|
func TestHypergraph(t *testing.T) {
|
|
// Test conversion operations
|
|
t.Run("Conversion retains ordering", func(t *testing.T) {
|
|
prover := &mocks.MockInclusionProver{}
|
|
mockCommit := make([]byte, 74)
|
|
mockCommit[0] = 0x02
|
|
rand.Read(mockCommit[1:])
|
|
prover.On("CommitRaw", mock.Anything, mock.Anything).Return(mockCommit, nil)
|
|
verEnc := &mocks.MockVerifiableEncryptor{}
|
|
ves := make([]hypergraph.Encrypted, 1000)
|
|
for i := range ves {
|
|
ve := &mocks.MockVerEnc{}
|
|
ve.On("ToBytes").Return([]byte{byte(i)})
|
|
verEnc.On("FromBytes", []byte{byte(i)}).Return(ve)
|
|
|
|
ve.On("GetStatement").Return(bytes.Repeat([]byte{0x02, byte(i)}, 37))
|
|
ves[i] = ve
|
|
}
|
|
tree := hypergraph.EncryptedToVertexTree(prover, ves)
|
|
for i, leaf := range tries.GetAllPreloadedLeaves(tree.Root) {
|
|
if !bytes.Equal(leaf.HashTarget, bytes.Repeat([]byte{0x02, byte(i)}, 37)) {
|
|
t.Errorf("mismatch hashtarget on index %d", i)
|
|
}
|
|
if !bytes.Equal(leaf.Value, []byte{byte(i)}) {
|
|
t.Errorf("mismatch value on index %d", i)
|
|
}
|
|
}
|
|
|
|
encryptedSet := hypergraph.VertexTreeToEncrypted(verEnc, tree)
|
|
for i, e := range encryptedSet {
|
|
if !bytes.Equal(e.ToBytes(), []byte{byte(i)}) {
|
|
t.Errorf("mismatch value on index %d", i)
|
|
}
|
|
}
|
|
})
|
|
|
|
// Test vertex operations
|
|
t.Run("Vertex Operations", func(t *testing.T) {
|
|
logger, _ := zap.NewDevelopment()
|
|
s := store.NewPebbleDB(logger, &config.Config{DB: &config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}}, 0)
|
|
enc := &mocks.MockVerifiableEncryptor{}
|
|
prover := &mocks.MockInclusionProver{}
|
|
vep := &mocks.MockVerEncProof{}
|
|
ve := &mocks.MockVerEnc{}
|
|
pub, _, _ := ed448.GenerateKey(rand.Reader)
|
|
ve.On("ToBytes").Return([]byte{})
|
|
ve.On("GetStatement").Return(make([]byte, 74))
|
|
vep.On("Compress").Return(ve)
|
|
enc.On("Encrypt", make([]byte, 20), []byte(pub)).Return([]crypto.VerEncProof{
|
|
vep,
|
|
})
|
|
hgcrdt := hg.NewHypergraph(
|
|
logger,
|
|
store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}, s, logger, enc, prover),
|
|
prover,
|
|
[]int{},
|
|
&Nopthenticator{},
|
|
200,
|
|
)
|
|
data := enc.Encrypt(make([]byte, 20), pub)
|
|
verenc := data[0].Compress()
|
|
dataTree := &tries.VectorCommitmentTree{}
|
|
for _, d := range []hypergraph.Encrypted{verenc} {
|
|
dataBytes := d.ToBytes()
|
|
id := sha512.Sum512(dataBytes)
|
|
dataTree.Insert(id[:], dataBytes, d.GetStatement(), big.NewInt(int64(len(data)*55)))
|
|
}
|
|
dataTree.Commit(prover, false)
|
|
v1 := hg.NewVertex([32]byte{1}, [32]byte{1}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
v2 := hg.NewVertex([32]byte{1}, [32]byte{2}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
|
|
// Add vertices
|
|
err := hgcrdt.AddVertex(nil, v1)
|
|
if err != nil {
|
|
t.Errorf("Failed to add vertex v1: %v", err)
|
|
}
|
|
err = hgcrdt.AddVertex(nil, v2)
|
|
if err != nil {
|
|
t.Errorf("Failed to add vertex v2: %v", err)
|
|
}
|
|
|
|
// Lookup vertices
|
|
if !hgcrdt.LookupVertex(v1) {
|
|
t.Error("Failed to lookup vertex v1")
|
|
}
|
|
if !hgcrdt.LookupVertex(v2) {
|
|
t.Error("Failed to lookup vertex v2")
|
|
}
|
|
|
|
// Remove vertex
|
|
err = hgcrdt.RemoveVertex(nil, v1)
|
|
if err != nil {
|
|
t.Errorf("Failed to remove vertex v1: %v", err)
|
|
}
|
|
if hgcrdt.LookupVertex(v1) {
|
|
t.Error("Vertex v1 still exists after removal")
|
|
}
|
|
if !hgcrdt.LookupVertex(v2) {
|
|
t.Error("Vertex v2 was incorrectly removed")
|
|
}
|
|
})
|
|
|
|
// Test hyperedge operations
|
|
t.Run("Hyperedge Operations", func(t *testing.T) {
|
|
logger, _ := zap.NewDevelopment()
|
|
s := store.NewPebbleDB(logger, &config.Config{DB: &config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}}, 0)
|
|
enc := &mocks.MockVerifiableEncryptor{}
|
|
prover := &mocks.MockInclusionProver{}
|
|
vep := &mocks.MockVerEncProof{}
|
|
ve := &mocks.MockVerEnc{}
|
|
pub, _, _ := ed448.GenerateKey(rand.Reader)
|
|
mockCommit := make([]byte, 74)
|
|
mockCommit[0] = 0x02
|
|
rand.Read(mockCommit[1:])
|
|
prover.On("CommitRaw", mock.Anything, mock.Anything).Return(mockCommit, nil)
|
|
ve.On("ToBytes").Return([]byte{})
|
|
ve.On("GetStatement").Return(make([]byte, 74))
|
|
vep.On("Compress").Return(ve)
|
|
enc.On("Encrypt", make([]byte, 20), []byte(pub)).Return([]crypto.VerEncProof{
|
|
vep,
|
|
})
|
|
hgcrdt := hg.NewHypergraph(
|
|
logger,
|
|
store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}, s, logger, enc, prover),
|
|
prover,
|
|
[]int{},
|
|
&Nopthenticator{},
|
|
200,
|
|
)
|
|
data := enc.Encrypt(make([]byte, 20), pub)
|
|
verenc := data[0].Compress()
|
|
dataTree := &tries.VectorCommitmentTree{}
|
|
for _, d := range []hypergraph.Encrypted{verenc} {
|
|
dataBytes := d.ToBytes()
|
|
id := sha512.Sum512(dataBytes)
|
|
dataTree.Insert(id[:], dataBytes, d.GetStatement(), big.NewInt(int64(len(data)*55)))
|
|
}
|
|
dataTree.Commit(prover, false)
|
|
v3 := hg.NewVertex([32]byte{2}, [32]byte{1}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
v4 := hg.NewVertex([32]byte{2}, [32]byte{2}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
hgcrdt.AddVertex(nil, v3)
|
|
hgcrdt.AddVertex(nil, v4)
|
|
|
|
h1 := hg.NewHyperedge([32]byte{3}, [32]byte{1})
|
|
h1.AddExtrinsic(v3)
|
|
h1.AddExtrinsic(v4)
|
|
|
|
// Add hyperedge
|
|
err := hgcrdt.AddHyperedge(nil, h1)
|
|
if err != nil {
|
|
t.Errorf("Failed to add hyperedge h1: %v", err)
|
|
}
|
|
|
|
// Lookup hyperedge
|
|
if !hgcrdt.LookupHyperedge(h1) {
|
|
t.Error("Failed to lookup hyperedge h1")
|
|
}
|
|
|
|
// Remove hyperedge
|
|
err = hgcrdt.RemoveHyperedge(nil, h1)
|
|
if err != nil {
|
|
t.Errorf("Failed to remove hyperedge h1: %v", err)
|
|
}
|
|
if hgcrdt.LookupHyperedge(h1) {
|
|
t.Error("Hyperedge h1 still exists after removal")
|
|
}
|
|
})
|
|
|
|
// Test "within" relationship
|
|
t.Run("Within Relationship", func(t *testing.T) {
|
|
logger, _ := zap.NewDevelopment()
|
|
s := store.NewPebbleDB(logger, &config.Config{DB: &config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}}, 0)
|
|
enc := &mocks.MockVerifiableEncryptor{}
|
|
prover := &mocks.MockInclusionProver{}
|
|
vep := &mocks.MockVerEncProof{}
|
|
ve := &mocks.MockVerEnc{}
|
|
pub, _, _ := ed448.GenerateKey(rand.Reader)
|
|
mockCommit := make([]byte, 74)
|
|
mockCommit[0] = 0x02
|
|
rand.Read(mockCommit[1:])
|
|
prover.On("CommitRaw", mock.Anything, mock.Anything).Return(mockCommit, nil)
|
|
ve.On("ToBytes").Return([]byte{})
|
|
ve.On("GetStatement").Return(make([]byte, 74))
|
|
vep.On("Compress").Return(ve)
|
|
enc.On("Encrypt", make([]byte, 20), []byte(pub)).Return([]crypto.VerEncProof{
|
|
vep,
|
|
})
|
|
hgcrdt := hg.NewHypergraph(
|
|
logger,
|
|
store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}, s, logger, enc, prover),
|
|
prover,
|
|
[]int{},
|
|
&Nopthenticator{},
|
|
200,
|
|
)
|
|
data := enc.Encrypt(make([]byte, 20), pub)
|
|
verenc := data[0].Compress()
|
|
dataTree := &tries.VectorCommitmentTree{}
|
|
for _, d := range []hypergraph.Encrypted{verenc} {
|
|
dataBytes := d.ToBytes()
|
|
id := sha512.Sum512(dataBytes)
|
|
dataTree.Insert(id[:], dataBytes, d.GetStatement(), big.NewInt(int64(len(data)*55)))
|
|
}
|
|
dataTree.Commit(prover, false)
|
|
v5 := hg.NewVertex([32]byte{4}, [32]byte{1}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
v6 := hg.NewVertex([32]byte{4}, [32]byte{2}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
hgcrdt.AddVertex(nil, v5)
|
|
hgcrdt.AddVertex(nil, v6)
|
|
|
|
h2 := hg.NewHyperedge([32]byte{5}, [32]byte{1})
|
|
h2.AddExtrinsic(v5)
|
|
h2.AddExtrinsic(v6)
|
|
hgcrdt.AddHyperedge(nil, h2)
|
|
|
|
if !hgcrdt.Within(v5, h2) {
|
|
t.Error("v5 should be within h2")
|
|
}
|
|
if !hgcrdt.Within(v6, h2) {
|
|
t.Error("v6 should be within h2")
|
|
}
|
|
|
|
v7 := hg.NewVertex([32]byte{4}, [32]byte{3}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
hgcrdt.AddVertex(nil, v7)
|
|
if hgcrdt.Within(v7, h2) {
|
|
t.Error("v7 should not be within h2")
|
|
}
|
|
})
|
|
|
|
// Test nested hyperedges
|
|
t.Run("Nested Hyperedges", func(t *testing.T) {
|
|
logger, _ := zap.NewDevelopment()
|
|
s := store.NewPebbleDB(logger, &config.Config{DB: &config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}}, 0)
|
|
enc := &mocks.MockVerifiableEncryptor{}
|
|
prover := &mocks.MockInclusionProver{}
|
|
vep := &mocks.MockVerEncProof{}
|
|
ve := &mocks.MockVerEnc{}
|
|
pub, _, _ := ed448.GenerateKey(rand.Reader)
|
|
mockCommit := make([]byte, 74)
|
|
mockCommit[0] = 0x02
|
|
rand.Read(mockCommit[1:])
|
|
prover.On("CommitRaw", mock.Anything, mock.Anything).Return(mockCommit, nil)
|
|
ve.On("ToBytes").Return([]byte{})
|
|
ve.On("GetStatement").Return(make([]byte, 74))
|
|
vep.On("Compress").Return(ve)
|
|
enc.On("Encrypt", make([]byte, 20), []byte(pub)).Return([]crypto.VerEncProof{
|
|
vep,
|
|
})
|
|
hgcrdt := hg.NewHypergraph(
|
|
logger,
|
|
store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}, s, logger, enc, prover),
|
|
prover,
|
|
[]int{},
|
|
&Nopthenticator{},
|
|
200,
|
|
)
|
|
data := enc.Encrypt(make([]byte, 20), pub)
|
|
verenc := data[0].Compress()
|
|
dataTree := &tries.VectorCommitmentTree{}
|
|
for _, d := range []hypergraph.Encrypted{verenc} {
|
|
dataBytes := d.ToBytes()
|
|
id := sha512.Sum512(dataBytes)
|
|
dataTree.Insert(id[:], dataBytes, d.GetStatement(), big.NewInt(int64(len(data)*55)))
|
|
}
|
|
dataTree.Commit(prover, false)
|
|
v8 := hg.NewVertex([32]byte{6}, [32]byte{1}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
v9 := hg.NewVertex([32]byte{6}, [32]byte{2}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
hgcrdt.AddVertex(nil, v8)
|
|
hgcrdt.AddVertex(nil, v9)
|
|
|
|
h3 := hg.NewHyperedge([32]byte{7}, [32]byte{1})
|
|
h3.AddExtrinsic(v8)
|
|
h4 := hg.NewHyperedge([32]byte{7}, [32]byte{2})
|
|
h4.AddExtrinsic(h3)
|
|
h4.AddExtrinsic(v9)
|
|
hgcrdt.AddHyperedge(nil, h3)
|
|
hgcrdt.AddHyperedge(nil, h4)
|
|
|
|
if !hgcrdt.Within(v8, h4) {
|
|
t.Error("v8 should be within h4 (nested)")
|
|
}
|
|
if !hgcrdt.Within(v9, h4) {
|
|
t.Error("v9 should be within h4 (direct)")
|
|
}
|
|
})
|
|
|
|
// Test error cases
|
|
t.Run("Error Cases", func(t *testing.T) {
|
|
logger, _ := zap.NewDevelopment()
|
|
s := store.NewPebbleDB(logger, &config.Config{DB: &config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}}, 0)
|
|
enc := &mocks.MockVerifiableEncryptor{}
|
|
prover := &mocks.MockInclusionProver{}
|
|
vep := &mocks.MockVerEncProof{}
|
|
ve := &mocks.MockVerEnc{}
|
|
pub, _, _ := ed448.GenerateKey(rand.Reader)
|
|
mockCommit := make([]byte, 74)
|
|
mockCommit[0] = 0x02
|
|
rand.Read(mockCommit[1:])
|
|
prover.On("CommitRaw", mock.Anything, mock.Anything).Return(mockCommit, nil)
|
|
ve.On("ToBytes").Return([]byte{})
|
|
ve.On("GetStatement").Return(make([]byte, 74))
|
|
vep.On("Compress").Return(ve)
|
|
enc.On("Encrypt", make([]byte, 20), []byte(pub)).Return([]crypto.VerEncProof{
|
|
vep,
|
|
})
|
|
hgcrdt := hg.NewHypergraph(
|
|
logger,
|
|
store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}, s, logger, enc, prover),
|
|
prover,
|
|
[]int{},
|
|
&Nopthenticator{},
|
|
200,
|
|
)
|
|
data := enc.Encrypt(make([]byte, 20), pub)
|
|
verenc := data[0].Compress()
|
|
dataTree := &tries.VectorCommitmentTree{}
|
|
for _, d := range []hypergraph.Encrypted{verenc} {
|
|
dataBytes := d.ToBytes()
|
|
id := sha512.Sum512(dataBytes)
|
|
dataTree.Insert(id[:], dataBytes, d.GetStatement(), big.NewInt(int64(len(data)*55)))
|
|
}
|
|
dataTree.Commit(prover, false)
|
|
v10 := hg.NewVertex([32]byte{8}, [32]byte{1}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
|
|
h5 := hg.NewHyperedge([32]byte{8}, [32]byte{2})
|
|
h5.AddExtrinsic(v10)
|
|
|
|
// Add vertex and hyperedge
|
|
hgcrdt.AddVertex(nil, v10)
|
|
hgcrdt.AddHyperedge(nil, h5)
|
|
})
|
|
|
|
// Test sharding
|
|
t.Run("Sharding", func(t *testing.T) {
|
|
logger, _ := zap.NewDevelopment()
|
|
s := store.NewPebbleDB(logger, &config.Config{DB: &config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}}, 0)
|
|
enc := &mocks.MockVerifiableEncryptor{}
|
|
prover := &mocks.MockInclusionProver{}
|
|
vep := &mocks.MockVerEncProof{}
|
|
ve := &mocks.MockVerEnc{}
|
|
pub, _, _ := ed448.GenerateKey(rand.Reader)
|
|
mockCommit := make([]byte, 74)
|
|
mockCommit[0] = 0x02
|
|
rand.Read(mockCommit[1:])
|
|
prover.On("CommitRaw", mock.Anything, mock.Anything).Return(mockCommit, nil)
|
|
ve.On("ToBytes").Return([]byte{})
|
|
ve.On("GetStatement").Return(make([]byte, 74))
|
|
vep.On("Compress").Return(ve)
|
|
enc.On("Encrypt", make([]byte, 20), []byte(pub)).Return([]crypto.VerEncProof{
|
|
vep,
|
|
})
|
|
hgcrdt := hg.NewHypergraph(
|
|
logger,
|
|
store.NewPebbleHypergraphStore(&config.DBConfig{InMemoryDONOTUSE: true, Path: ".configtest/store"}, s, logger, enc, prover),
|
|
prover,
|
|
[]int{},
|
|
&Nopthenticator{},
|
|
200,
|
|
)
|
|
data := enc.Encrypt(make([]byte, 20), pub)
|
|
verenc := data[0].Compress()
|
|
dataTree := &tries.VectorCommitmentTree{}
|
|
for _, d := range []hypergraph.Encrypted{verenc} {
|
|
dataBytes := d.ToBytes()
|
|
id := sha512.Sum512(dataBytes)
|
|
dataTree.Insert(id[:], dataBytes, d.GetStatement(), big.NewInt(int64(len(data)*55)))
|
|
}
|
|
dataTree.Commit(prover, false)
|
|
v11 := hg.NewVertex([32]byte{9}, [32]byte{1}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
v12 := hg.NewVertex([32]byte{9}, [32]byte{2}, dataTree.Commit(prover, false), dataTree.GetSize())
|
|
hgcrdt.AddVertex(nil, v11)
|
|
hgcrdt.AddVertex(nil, v12)
|
|
|
|
shard11 := hypergraph.GetShardAddress(v11)
|
|
shard12 := hypergraph.GetShardAddress(v12)
|
|
|
|
if !bytes.Equal(shard11.L1[:], shard12.L1[:]) ||
|
|
!bytes.Equal(shard11.L2[:], shard12.L2[:]) ||
|
|
bytes.Equal(shard11.L3[:], shard12.L3[:]) {
|
|
t.Error("v11 and v12 should be in the same L1 shard and the same L2 shard but not the same L3 shard")
|
|
}
|
|
})
|
|
}
|