From d499a60937de6e7a8d24ae37a25c58ab3e694bda Mon Sep 17 00:00:00 2001 From: Cassandra Heart <7929478+CassOnMars@users.noreply.github.com> Date: Fri, 16 Feb 2024 03:42:37 -0600 Subject: [PATCH] v1.2.6 (#47) --- node/app/db_console.go | 4 +- node/consensus/ceremony/consensus_frames.go | 5 +- node/consensus/consensus_engine.go | 2 +- node/consensus/time/data_time_reel.go | 84 +++++++++++++++++++-- node/consensus/time/data_time_reel_test.go | 48 +++++++----- node/main.go | 2 +- node/store/clock.go | 35 ++++++++- node/store/inmem.go | 2 - 8 files changed, 147 insertions(+), 35 deletions(-) diff --git a/node/app/db_console.go b/node/app/db_console.go index 25efbbd..40a4b9b 100644 --- a/node/app/db_console.go +++ b/node/app/db_console.go @@ -886,11 +886,11 @@ func logoVersion(width int) string { out += " ####################################### ########\n" out += " ############################# ##\n" out += " \n" - out += " Quilibrium Node - v1.2.5 – Dawn\n" + out += " Quilibrium Node - v1.2.6 – Dawn\n" out += " \n" out += " DB Console\n" } else { - out = "Quilibrium Node - v1.2.5 – Dawn - DB Console\n" + out = "Quilibrium Node - v1.2.6 – Dawn - DB Console\n" } return out } diff --git a/node/consensus/ceremony/consensus_frames.go b/node/consensus/ceremony/consensus_frames.go index 3e86f35..88579c6 100644 --- a/node/consensus/ceremony/consensus_frames.go +++ b/node/consensus/ceremony/consensus_frames.go @@ -201,15 +201,12 @@ func (e *CeremonyDataClockConsensusEngine) sync( from = 1 } - if maxFrame > from && maxFrame > 3 { - from = maxFrame - 2 - } - s, err := client.GetCompressedSyncFrames( context.Background(), &protobufs.ClockFramesRequest{ Filter: e.filter, FromFrameNumber: from, + ToFrameNumber: from + 8, }, grpc.MaxCallRecvMsgSize(600*1024*1024), ) diff --git a/node/consensus/consensus_engine.go b/node/consensus/consensus_engine.go index 00076a6..bc6bd61 100644 --- a/node/consensus/consensus_engine.go +++ b/node/consensus/consensus_engine.go @@ -59,5 +59,5 @@ func GetMinimumVersion() []byte { } func GetVersion() []byte { - return []byte{0x01, 0x02, 0x05} + return []byte{0x01, 0x02, 0x06} } diff --git a/node/consensus/time/data_time_reel.go b/node/consensus/time/data_time_reel.go index 69ba839..ed1a535 100644 --- a/node/consensus/time/data_time_reel.go +++ b/node/consensus/time/data_time_reel.go @@ -238,8 +238,15 @@ func (d *DataTimeReel) runLoop() { continue } - // If the frame has a gap from the head, mark it as pending: - if frame.FrameNumber-d.head.FrameNumber != 1 { + headSelector, err := d.head.GetSelector() + if err != nil { + panic(err) + } + + // If the frame has a gap from the head or is not descendent, mark it as + // pending: + if frame.FrameNumber-d.head.FrameNumber != 1 || + parent.Cmp(headSelector) != 0 { d.addPending(selector, parent, distance, frame) continue } @@ -264,10 +271,13 @@ func (d *DataTimeReel) runLoop() { distance.Cmp(d.headDistance) < 0 { d.totalDistance.Sub(d.totalDistance, d.headDistance) d.setHead(frame, distance) + d.processPending(d.head) + continue } // Choose fork d.forkChoice(frame, distance) + d.processPending(d.head) } else { // tag: dusk – we should have some kind of check here to avoid brutal // thrashing @@ -359,7 +369,6 @@ func (d *DataTimeReel) processPending(frame *protobufs.ClockFrame) { d.pending[frame.FrameNumber][1:] if len(d.pending[frame.FrameNumber]) == 0 { delete(d.pending, frame.FrameNumber) - break } nextFrame, err := d.clockStore.GetCandidateDataClockFrame( @@ -380,6 +389,7 @@ func (d *DataTimeReel) processPending(frame *protobufs.ClockFrame) { neighborPending, ok = d.pending[frame.FrameNumber] } + above := false if !neighbors { // Pull the next nextPending, ok := d.pending[frame.FrameNumber+1] @@ -400,6 +410,44 @@ func (d *DataTimeReel) processPending(frame *protobufs.ClockFrame) { if err != nil && !errors.Is(err, store.ErrNotFound) { panic(err) } + if nextFrame != nil { + above = true + go func() { + d.frames <- nextFrame + }() + } + } + } + + if !above { + // Pull below + min := frame.FrameNumber + for k := range d.pending { + if k < min { + min = k + } + } + if min == frame.FrameNumber { + return + } + nextPending, ok := d.pending[min] + if ok { + next := nextPending[0] + d.pending[min] = + d.pending[min][1:] + if len(d.pending[min]) == 0 { + delete(d.pending, min) + } + + nextFrame, err := d.clockStore.GetCandidateDataClockFrame( + d.filter, + min, + next.parentSelector.FillBytes(make([]byte, 32)), + next.distance.FillBytes(make([]byte, 32)), + ) + if err != nil && !errors.Is(err, store.ErrNotFound) { + panic(err) + } if nextFrame != nil { go func() { d.frames <- nextFrame @@ -509,7 +557,7 @@ func (d *DataTimeReel) forkChoice( left := d.head.ParentSelector right := frame.ParentSelector - rightReplaySelectors := [][]byte{selector.FillBytes(make([]byte, 32))} + rightReplaySelectors := [][]byte{} // Walk backwards through the parents, until we find a matching parent // selector: @@ -561,6 +609,8 @@ func (d *DataTimeReel) forkChoice( rightTotal.Add(rightTotal, rightIndexDistance) } + frameNumber := rightIndex.FrameNumber + // Choose new fork based on lightest distance sub-tree if rightTotal.Cmp(leftTotal) < 0 { for { @@ -568,12 +618,12 @@ func (d *DataTimeReel) forkChoice( break } next := rightReplaySelectors[0] - rightReplaySelectors[frame.FrameNumber] = - rightReplaySelectors[frame.FrameNumber][1:] + rightReplaySelectors = + rightReplaySelectors[1:] rightIndex, err = d.clockStore.GetParentDataClockFrame( d.filter, - rightIndex.FrameNumber+1, + frameNumber, next, ) if err != nil { @@ -597,6 +647,26 @@ func (d *DataTimeReel) forkChoice( if err = txn.Commit(); err != nil { panic(err) } + + frameNumber++ + } + + txn, err := d.clockStore.NewTransaction() + if err != nil { + panic(err) + } + + if err := d.clockStore.PutDataClockFrame( + frame, + d.proverTrie, + txn, + false, + ); err != nil { + panic(err) + } + + if err = txn.Commit(); err != nil { + panic(err) } d.head = frame diff --git a/node/consensus/time/data_time_reel_test.go b/node/consensus/time/data_time_reel_test.go index 453e0e1..05ea84b 100644 --- a/node/consensus/time/data_time_reel_test.go +++ b/node/consensus/time/data_time_reel_test.go @@ -1,11 +1,11 @@ package time_test import ( - "encoding/hex" "fmt" "strings" "sync" "testing" + gotime "time" "github.com/cloudflare/circl/sign/ed448" "github.com/iden3/go-iden3-crypto/poseidon" @@ -118,7 +118,7 @@ func TestDataTimeReel(t *testing.T) { addrMap, proverTrie := generateTestProvers() - // We're going to set this up by churning 100 master frames so we don't + // We're going to set this up by churning 40 master frames so we don't // have to zig zag on master and data frames to confirm data time reel // behaviors m := time.NewMasterTimeReel( @@ -143,14 +143,14 @@ func TestDataTimeReel(t *testing.T) { wg.Add(1) frameCh := m.NewFrameCh() go func() { - for i := 0; i < 100; i++ { + for i := 0; i < 40; i++ { frames = append(frames, <-frameCh) } wg.Done() }() // in order - for i := int64(0); i < 100; i++ { + for i := int64(0); i < 40; i++ { frame, err = prover.ProveMasterClockFrame(frame, i+1, 10) assert.NoError(t, err) @@ -160,12 +160,23 @@ func TestDataTimeReel(t *testing.T) { wg.Wait() - for i := 0; i < 100; i++ { + for i := 0; i < 40; i++ { assert.NotNil(t, frames[i]) assert.Equal(t, frames[i].FrameNumber, uint64(i+1)) } - filterBytes, _ := hex.DecodeString(filter) + filterBytes := []byte{ + 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, + } // Ok, now onto the data time reel. We're going to test the following // scenarios: @@ -203,7 +214,7 @@ func TestDataTimeReel(t *testing.T) { datawg.Add(1) dataFrameCh := d.NewFrameCh() go func() { - for i := 0; i < 40; i++ { + for i := 0; i < 41; i++ { dataFrames = append(dataFrames, <-dataFrameCh) } datawg.Done() @@ -211,7 +222,7 @@ func TestDataTimeReel(t *testing.T) { // 1. z-dist optimal – proof submission is strictly master-frame evoked leader for i := int64(0); i < 10; i++ { - masterSelector, err := frames[i+1].GetSelector() + masterSelector, err := frames[i].GetSelector() assert.NoError(t, err) proverSelection := proverTrie.FindNearest( @@ -236,7 +247,7 @@ func TestDataTimeReel(t *testing.T) { insertFrames := []*protobufs.ClockFrame{} for i := int64(10); i < 20; i++ { - masterSelector, err := frames[i+1].GetSelector() + masterSelector, err := frames[i].GetSelector() assert.NoError(t, err) proverSelection := proverTrie.FindNearest( @@ -265,7 +276,7 @@ func TestDataTimeReel(t *testing.T) { insertFrames = []*protobufs.ClockFrame{} for i := int64(20); i < 25; i++ { - masterSelector, err := frames[i+1].GetSelector() + masterSelector, err := frames[i].GetSelector() assert.NoError(t, err) proverSelection := proverTrie.FindNearest( @@ -285,7 +296,7 @@ func TestDataTimeReel(t *testing.T) { d.Insert(frame) } - masterSelector, err := frames[26].GetSelector() + masterSelector, err := frames[25].GetSelector() assert.NoError(t, err) proverSelections := proverTrie.FindNearestAndApproximateNeighbors( @@ -307,7 +318,7 @@ func TestDataTimeReel(t *testing.T) { insertFrames = append(insertFrames, frame) for i := int64(26); i < 30; i++ { - masterSelector, err := frames[i+1].GetSelector() + masterSelector, err := frames[i].GetSelector() assert.NoError(t, err) proverSelection := proverTrie.FindNearest( @@ -339,7 +350,7 @@ func TestDataTimeReel(t *testing.T) { optimalKeySet := [][]byte{} suppressedFrame := frame for i := int64(30); i < 40; i++ { - masterSelector, err := frames[i+1].GetSelector() + masterSelector, err := frames[i].GetSelector() assert.NoError(t, err) proverSelections := proverTrie.FindNearestAndApproximateNeighbors( @@ -357,7 +368,7 @@ func TestDataTimeReel(t *testing.T) { // What we're trying to simulate: the majority is intentionally ignoring // the most optimal signer - suppressedFrame, err := prover.ProveDataClockFrame( + suppressedFrame, err = prover.ProveDataClockFrame( suppressedFrame, [][]byte{}, []*protobufs.InclusionAggregateProof{}, @@ -379,26 +390,29 @@ func TestDataTimeReel(t *testing.T) { for i := 9; i >= 0; i-- { err := d.Insert(conflictFrames[i]) + // force linear ordering + gotime.Sleep(1 * gotime.Second) assert.NoError(t, err) } - // Someone is honest, but clumsy: + // Someone is honest, but running backwards: for i := 9; i >= 0; i-- { err := d.Insert(insertFrames[i]) + gotime.Sleep(1 * gotime.Second) assert.NoError(t, err) } datawg.Wait() - for i := 0; i < 40; i++ { + for i := 0; i < 41; i++ { assert.NotNil(t, dataFrames[i]) if i >= 40 { assert.Equal(t, uint64(i), dataFrames[i].FrameNumber) assert.Equal( t, + optimalKeySet[i-31], dataFrames[i].GetPublicKeySignatureEd448().PublicKey.KeyValue, - optimalKeySet[i-30], ) } else { assert.Equal(t, uint64(i+1), dataFrames[i].FrameNumber) diff --git a/node/main.go b/node/main.go index 1d58d89..e6ea937 100644 --- a/node/main.go +++ b/node/main.go @@ -284,5 +284,5 @@ func printLogo() { func printVersion() { fmt.Println(" ") - fmt.Println(" Quilibrium Node - v1.2.5 – Dawn") + fmt.Println(" Quilibrium Node - v1.2.6 – Dawn") } diff --git a/node/store/clock.go b/node/store/clock.go index f35a684..dbc4347 100644 --- a/node/store/clock.go +++ b/node/store/clock.go @@ -869,11 +869,18 @@ func (p *PebbleClockStore) GetParentDataClockFrame( frameNumber uint64, parentSelector []byte, ) (*protobufs.ClockFrame, error) { + check := false data, closer, err := p.db.Get( clockDataParentIndexKey(filter, frameNumber, parentSelector), ) - if err != nil { + if err != nil && !errors.Is(err, pebble.ErrNotFound) { return nil, errors.Wrap(err, "get parent data clock frame") + } else if err != nil && errors.Is(err, pebble.ErrNotFound) { + data, closer, err = p.db.Get(clockDataFrameKey(filter, frameNumber)) + if err != nil { + return nil, errors.Wrap(err, "get parent data clock frame") + } + check = true } parent := &protobufs.ClockFrame{} @@ -881,6 +888,16 @@ func (p *PebbleClockStore) GetParentDataClockFrame( return nil, errors.Wrap(err, "get parent data clock frame") } + if check { + selector, err := parent.GetSelector() + if err != nil { + return nil, errors.Wrap(err, "get parent data clock frame") + } + if !bytes.Equal(selector.FillBytes(make([]byte, 32)), parentSelector) { + return nil, errors.Wrap(ErrNotFound, "get parent data clock frame") + } + } + if err := p.fillAggregateProofs(parent); err != nil { return nil, errors.Wrap( errors.Wrap(err, ErrInvalidData.Error()), @@ -1019,6 +1036,22 @@ func (p *PebbleClockStore) PutDataClockFrame( return errors.Wrap(err, "put data clock frame") } + selector, err := frame.GetSelector() + if err != nil { + return errors.Wrap(err, "put data clock frame") + } + + if err = txn.Set( + clockDataParentIndexKey( + frame.Filter, + frame.FrameNumber, + selector.FillBytes(make([]byte, 32)), + ), + data, + ); err != nil { + return errors.Wrap(err, "put data clock frame") + } + proverData, err := proverTrie.Serialize() if err != nil { return errors.Wrap(err, "put data clock frame") diff --git a/node/store/inmem.go b/node/store/inmem.go index 7ec5661..8f27b74 100644 --- a/node/store/inmem.go +++ b/node/store/inmem.go @@ -166,7 +166,6 @@ func (t *InMemKVDBTransaction) Set(key []byte, value []byte) error { if !t.db.open { return errors.New("inmem db closed") } - t.changes = append(t.changes, InMemKVDBOperation{ op: SetOperation, key: key, @@ -205,7 +204,6 @@ func (t *InMemKVDBTransaction) Delete(key []byte) error { if !t.db.open { return errors.New("inmem db closed") } - t.changes = append(t.changes, InMemKVDBOperation{ op: DeleteOperation, key: key,