Skip to content

Commit 72d730d

Browse files
authored
feat: recalibrate self-test on the fly (#221)
1 parent 99702af commit 72d730d

File tree

7 files changed

+79
-37
lines changed

7 files changed

+79
-37
lines changed

node/config/version.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
)
77

88
func GetMinimumVersionCutoff() time.Time {
9-
return time.Date(2024, time.May, 24, 4, 0, 0, 0, time.UTC)
9+
return time.Date(2024, time.May, 28, 3, 0, 0, 0, time.UTC)
1010
}
1111

1212
func GetMinimumVersion() []byte {
@@ -27,3 +27,7 @@ func FormatVersion(version []byte) string {
2727
version[0], version[1], version[2],
2828
)
2929
}
30+
31+
func GetPatchNumber() byte {
32+
return 0x01
33+
}

node/consensus/master/broadcast_messaging.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ func (e *MasterClockConsensusEngine) handleSelfTestReport(
132132
e.logger.Warn(
133133
"received invalid proof from peer",
134134
zap.String("peer_id", peer.ID(peerID).String()),
135+
zap.Int("proof_size", len(report.Proof)),
136+
zap.Uint32("cores", report.Cores),
135137
)
136138
e.pubSub.SetPeerScore(peerID, -1000)
137139
return errors.Wrap(errors.New("invalid report"), "handle self test report")
@@ -148,6 +150,7 @@ func (e *MasterClockConsensusEngine) handleSelfTestReport(
148150
return nil
149151
}
150152

153+
info.DifficultyMetric = report.DifficultyMetric
151154
info.MasterHeadFrame = report.MasterHeadFrame
152155

153156
if info.Bandwidth <= 1048576 {
@@ -169,7 +172,8 @@ func (e *MasterClockConsensusEngine) handleSelfTestReport(
169172
timestamp := binary.BigEndian.Uint64(proof[:8])
170173
proof = proof[8:]
171174

172-
// Ignore outdated reports, give 3 minutes for propagation delay
175+
// Ignore outdated reports, give 3 minutes + proof time for propagation
176+
// delay
173177
if int64(timestamp) < (time.Now().UnixMilli() - (480 * 1000)) {
174178
return nil
175179
}
@@ -255,6 +259,7 @@ func (e *MasterClockConsensusEngine) handleSelfTestReport(
255259
return nil
256260
}
257261

262+
// This does not publish any longer, frames strictly are picked up from sync
258263
func (e *MasterClockConsensusEngine) publishProof(
259264
frame *protobufs.ClockFrame,
260265
) error {
@@ -265,17 +270,6 @@ func (e *MasterClockConsensusEngine) publishProof(
265270

266271
e.masterTimeReel.Insert(frame, false)
267272

268-
peers, err := e.GetMostAheadPeers()
269-
if err != nil || len(peers) == 0 {
270-
// publish if we don't see anyone (empty peer list) or if we're the most
271-
// ahead:
272-
e.report.MasterHeadFrame = frame.FrameNumber
273-
274-
if err := e.publishMessage(e.filter, e.report); err != nil {
275-
e.logger.Debug("error publishing message", zap.Error(err))
276-
}
277-
}
278-
279273
e.state = consensus.EngineStateCollecting
280274

281275
return nil

node/consensus/master/master_clock_consensus_engine.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ func (e *MasterClockConsensusEngine) Start() <-chan error {
181181
panic(err)
182182
}
183183

184-
if head.FrameNumber > newFrame.FrameNumber || newFrame.FrameNumber-head.FrameNumber > 128 {
184+
if head.FrameNumber > newFrame.FrameNumber ||
185+
newFrame.FrameNumber-head.FrameNumber > 128 {
185186
e.logger.Debug(
186187
"frame out of range, ignoring",
187188
zap.Uint64("number", newFrame.FrameNumber),
@@ -238,6 +239,8 @@ func (e *MasterClockConsensusEngine) Start() <-chan error {
238239
go func() {
239240
// Let it sit until we at least have a few more peers inbound
240241
time.Sleep(30 * time.Second)
242+
difficultyMetric := int64(100000)
243+
skew := (difficultyMetric * 12) / 10
241244

242245
for {
243246
head, err := e.masterTimeReel.Head()
@@ -246,22 +249,31 @@ func (e *MasterClockConsensusEngine) Start() <-chan error {
246249
}
247250

248251
e.report.MasterHeadFrame = head.FrameNumber
252+
e.report.DifficultyMetric = difficultyMetric
249253
parallelism := e.report.Cores - 1
250-
skew := (e.report.DifficultyMetric * 12) / 10
254+
251255
challenge := binary.BigEndian.AppendUint64(
252256
[]byte{},
253257
e.report.MasterHeadFrame,
254258
)
255259
challenge = append(challenge, e.pubSub.GetPeerID()...)
256260

257-
ts, proofs, err := e.frameProver.CalculateChallengeProof(
258-
challenge,
259-
parallelism,
260-
skew,
261-
)
261+
ts, proofs, nextDifficultyMetric, err :=
262+
e.frameProver.CalculateChallengeProof(
263+
challenge,
264+
parallelism,
265+
skew,
266+
)
262267
if err != nil {
263268
panic(err)
264269
}
270+
e.logger.Info(
271+
"recalibrating difficulty metric",
272+
zap.Int64("previous_difficulty_metric", difficultyMetric),
273+
zap.Int64("next_difficulty_metric", nextDifficultyMetric),
274+
)
275+
difficultyMetric = nextDifficultyMetric
276+
skew = (nextDifficultyMetric * 12) / 10
265277

266278
proof := binary.BigEndian.AppendUint64([]byte{}, uint64(ts))
267279
for i := 0; i < len(proofs); i++ {
@@ -391,6 +403,10 @@ func (e *MasterClockConsensusEngine) performVerifyTest(
391403
)
392404
e.pubSub.SetPeerScore(challenge.peerID, -1000)
393405
} else {
406+
e.logger.Debug(
407+
"received valid proof from peer",
408+
zap.String("peer_id", peer.ID(challenge.peerID).String()),
409+
)
394410
info := e.peerInfoManager.GetPeerInfo(challenge.peerID)
395411
info.LastSeen = time.Now().UnixMilli()
396412
}

node/crypto/frame_prover.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ type FrameProver interface {
5555
challenge []byte,
5656
parallelism uint32,
5757
skew int64,
58-
) (int64, [][]byte, error)
58+
) (int64, [][]byte, int64, error)
5959
VerifyChallengeProof(
6060
challenge []byte,
6161
timestamp int64,

node/crypto/wesolowski_frame_prover.go

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"go.uber.org/zap"
1616
"golang.org/x/crypto/sha3"
1717
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf"
18+
"source.quilibrium.com/quilibrium/monorepo/node/config"
1819
"source.quilibrium.com/quilibrium/monorepo/node/keys"
1920
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
2021
"source.quilibrium.com/quilibrium/monorepo/node/tries"
@@ -549,7 +550,9 @@ func (w *WesolowskiFrameProver) VerifyWeakRecursiveProof(
549550
}
550551

551552
filter := proof[:len(frame.Filter)]
552-
check := binary.BigEndian.Uint64(proof[len(frame.Filter) : len(frame.Filter)+8])
553+
check := binary.BigEndian.Uint64(
554+
proof[len(frame.Filter) : len(frame.Filter)+8],
555+
)
553556
timestamp := binary.BigEndian.Uint64(
554557
proof[len(frame.Filter)+8 : len(frame.Filter)+16],
555558
)
@@ -600,26 +603,25 @@ func (w *WesolowskiFrameProver) CalculateChallengeProof(
600603
challenge []byte,
601604
parallelism uint32,
602605
skew int64,
603-
) (int64, [][]byte, error) {
604-
now := time.Now().UnixMilli()
605-
input := binary.BigEndian.AppendUint64([]byte{}, uint64(now))
606+
) (int64, [][]byte, int64, error) {
607+
now := time.Now()
608+
nowMs := now.UnixMilli()
609+
input := binary.BigEndian.AppendUint64([]byte{}, uint64(nowMs))
606610
input = append(input, challenge...)
607611
outputs := make([][]byte, parallelism)
608612

609613
wg := sync.WaitGroup{}
610614
wg.Add(int(parallelism))
611615

616+
// 4.5 minutes = 270 seconds, one increment should be ten seconds
617+
proofDuration := 270 * 1000
618+
calibratedDifficulty := (int64(proofDuration) * 10000) / skew
612619
for i := uint32(0); i < parallelism; i++ {
613620
i := i
614621
go func() {
615622
instanceInput := binary.BigEndian.AppendUint32([]byte{}, i)
616623
instanceInput = append(instanceInput, input...)
617-
b := sha3.Sum256(input)
618-
619-
// 4.5 minutes = 270 seconds, one increment should be ten seconds
620-
proofDuration := 270 * 1000
621-
calibratedDifficulty := (int64(proofDuration) / skew) * 10000
622-
624+
b := sha3.Sum256(instanceInput)
623625
v := vdf.New(uint32(calibratedDifficulty), b)
624626

625627
v.Execute()
@@ -632,7 +634,10 @@ func (w *WesolowskiFrameProver) CalculateChallengeProof(
632634
}
633635

634636
wg.Wait()
635-
return now, outputs, nil
637+
after := time.Since(now)
638+
nextSkew := (skew * after.Milliseconds()) / int64(proofDuration)
639+
640+
return nowMs, outputs, nextSkew, nil
636641
}
637642

638643
func (w *WesolowskiFrameProver) VerifyChallengeProof(
@@ -644,24 +649,39 @@ func (w *WesolowskiFrameProver) VerifyChallengeProof(
644649
input := binary.BigEndian.AppendUint64([]byte{}, uint64(timestamp))
645650
input = append(input, challenge...)
646651

652+
if assertedDifficulty < 1 {
653+
return false
654+
}
655+
647656
for i := uint32(0); i < uint32(len(proof)); i++ {
648657
if len(proof[i]) != 516 {
649658
return false
650659
}
651660

652661
instanceInput := binary.BigEndian.AppendUint32([]byte{}, i)
653662
instanceInput = append(instanceInput, input...)
654-
b := sha3.Sum256(input)
663+
b := sha3.Sum256(instanceInput)
655664

656665
// 4.5 minutes = 270 seconds, one increment should be ten seconds
657666
proofDuration := 270 * 1000
658667
skew := (assertedDifficulty * 12) / 10
659-
calibratedDifficulty := (int64(proofDuration) / skew) * 10000
668+
calibratedDifficulty := (int64(proofDuration) * 10000) / skew
660669

661670
v := vdf.New(uint32(calibratedDifficulty), b)
662671
check := v.Verify([516]byte(proof[i]))
663672
if !check {
664-
return false
673+
// TODO: Remove after 2024-05-28
674+
if time.Now().Before(config.GetMinimumVersionCutoff()) {
675+
calibratedDifficulty = (int64(proofDuration) / skew) * 10000
676+
677+
v = vdf.New(uint32(calibratedDifficulty), sha3.Sum256(input))
678+
check = v.Verify([516]byte(proof[i]))
679+
if !check {
680+
return false
681+
}
682+
} else {
683+
return false
684+
}
665685
}
666686
}
667687

node/crypto/wesolowski_frame_prover_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ func TestMasterProve(t *testing.T) {
3030
func TestChallengeProof(t *testing.T) {
3131
l, _ := zap.NewProduction()
3232
w := crypto.NewWesolowskiFrameProver(l)
33-
now, proofs, err := w.CalculateChallengeProof([]byte{0x01, 0x02, 0x03}, 3, 120000)
33+
now, proofs, nextSkew, err := w.CalculateChallengeProof([]byte{0x01, 0x02, 0x03}, 3, 120000)
3434
assert.NoError(t, err)
3535
assert.True(t, w.VerifyChallengeProof([]byte{0x01, 0x02, 0x03}, now, 100000, proofs))
36+
now, proofs, _, err = w.CalculateChallengeProof([]byte{0x01, 0x02, 0x03}, 3, nextSkew*12/10)
37+
assert.NoError(t, err)
38+
assert.True(t, w.VerifyChallengeProof([]byte{0x01, 0x02, 0x03}, now, nextSkew, proofs))
3639
}

node/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,11 @@ func printLogo() {
735735
}
736736

737737
func printVersion() {
738+
patch := config.GetPatchNumber()
739+
patchString := ""
740+
if patch != 0x00 {
741+
patchString = fmt.Sprintf("-p%d", patch)
742+
}
738743
fmt.Println(" ")
739-
fmt.Println(" Quilibrium Node - v" + config.GetVersionString() + " – Nebula")
744+
fmt.Println(" Quilibrium Node - v" + config.GetVersionString() + patchString + " – Nebula")
740745
}

0 commit comments

Comments
 (0)