Merge branch 'v2.0.6-p2' into develop-2.1-pre-milestone3

This commit is contained in:
Cassandra Heart 2025-01-15 19:03:35 -06:00
commit bd08966076
No known key found for this signature in database
GPG Key ID: 6352152859385958
12 changed files with 238 additions and 209 deletions

View File

@ -157,7 +157,7 @@ var Signatories = []string{
"9ab76d775487c85c8e5aa0c5b3f961772967899a14644651031ae5f98ac197bee3f8880492c4fdba268716fc4b7c38ffcac370b663ac10b600",
"81d63a45f068629f568de812f18be5807bfe828a830097f09cf02330d6acd35e3607401df3fda08b03b68ea6e68afd506b23506b11e87a0f80",
"6e2872f73c4868c4286bef7bfe2f5479a41c42f4e07505efa4883c7950c740252e0eea78eef10c584b19b1dcda01f7767d3135d07c33244100",
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"0ca6f5a9d7f86c1111be5edf31e26979918aa4fa3daae6de1120e05c2a09bdb8d2feeb084286a3347e06ced25530358cbc74c204d2a1753a00",
}
var unlock *SignedGenesisUnlock

View File

@ -6,7 +6,7 @@ import (
)
func GetMinimumVersionCutoff() time.Time {
return time.Date(2024, time.November, 24, 0, 0, 0, 0, time.UTC)
return time.Date(2025, time.January, 13, 0, 0, 0, 0, time.UTC)
}
// Gets the minimum patch version This should only be set in a release series
@ -43,7 +43,7 @@ func FormatVersion(version []byte) string {
}
func GetPatchNumber() byte {
return 0x01
return 0x02
}
func GetRCNumber() byte {

View File

@ -10,9 +10,12 @@ import (
"source.quilibrium.com/quilibrium/monorepo/node/config"
"source.quilibrium.com/quilibrium/monorepo/node/consensus/data/internal"
"source.quilibrium.com/quilibrium/monorepo/node/internal/frametime"
"source.quilibrium.com/quilibrium/monorepo/node/tries"
"github.com/iden3/go-iden3-crypto/poseidon"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/pkg/errors"
mt "github.com/txaty/go-merkletree"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
@ -428,3 +431,146 @@ func (e *DataClockConsensusEngine) syncWithPeer(
}
}
}
func (e *DataClockConsensusEngine) initiateProvers(
latestFrame *protobufs.ClockFrame,
) {
if latestFrame.Timestamp > time.Now().UnixMilli()-60000 {
if !e.IsInProverTrie(e.pubSub.GetPeerID()) {
e.logger.Info("announcing prover join")
for _, eng := range e.executionEngines {
eng.AnnounceProverJoin()
break
}
} else {
if e.previousFrameProven != nil &&
e.previousFrameProven.FrameNumber == latestFrame.FrameNumber {
return
}
h, err := poseidon.HashBytes(e.pubSub.GetPeerID())
if err != nil {
panic(err)
}
peerProvingKeyAddress := h.FillBytes(make([]byte, 32))
ring := -1
if tries := e.GetFrameProverTries(); len(tries) > 1 {
for i, tries := range tries[1:] {
i := i
if tries.Contains(peerProvingKeyAddress) {
ring = i
}
}
}
e.clientReconnectTest++
if e.clientReconnectTest >= 10 {
e.tryReconnectDataWorkerClients()
e.clientReconnectTest = 0
}
previousTreeRoot := []byte{}
if e.previousTree != nil {
previousTreeRoot = e.previousTree.Root
}
outputs := e.PerformTimeProof(latestFrame, previousTreeRoot, latestFrame.Difficulty, ring)
if outputs == nil || len(outputs) < 3 {
e.logger.Info("workers not yet available for proving")
return
}
modulo := len(outputs)
var proofTree *mt.MerkleTree
var output [][]byte
if latestFrame.FrameNumber >= application.PROOF_FRAME_COMBINE_CUTOFF {
proofTree, output, err = tries.PackOutputIntoMultiPayloadAndProof(
outputs,
modulo,
latestFrame,
e.previousTree,
)
} else {
proofTree, output, err = tries.PackOutputIntoPayloadAndProof(
outputs,
modulo,
latestFrame,
e.previousTree,
)
}
if err != nil {
e.logger.Error(
"could not successfully pack proof, reattempting",
zap.Error(err),
)
return
}
e.previousFrameProven = latestFrame
e.previousTree = proofTree
mint := &protobufs.MintCoinRequest{
Proofs: output,
}
if err := mint.SignED448(e.pubSub.GetPublicKey(), e.pubSub.SignMessage); err != nil {
e.logger.Error("could not sign mint", zap.Error(err))
return
}
if err := mint.Validate(); err != nil {
e.logger.Error("mint validation failed", zap.Error(err))
return
}
e.logger.Info(
"submitting data proof",
zap.Int("ring", ring),
zap.Int("active_workers", len(outputs)),
zap.Uint64("frame_number", latestFrame.FrameNumber),
zap.Duration("frame_age", frametime.Since(latestFrame)),
)
if err := e.publishMessage(e.txFilter, mint.TokenRequest()); err != nil {
e.logger.Error("could not publish mint", zap.Error(err))
}
if e.config.Engine.AutoMergeCoins {
_, addrs, _, err := e.coinStore.GetCoinsForOwner(
peerProvingKeyAddress,
)
if err != nil {
e.logger.Error(
"received error while iterating coins",
zap.Error(err),
)
return
}
if len(addrs) > 25 {
refs := []*protobufs.CoinRef{}
for _, addr := range addrs {
refs = append(refs, &protobufs.CoinRef{
Address: addr,
})
}
merge := &protobufs.MergeCoinRequest{
Coins: refs,
}
if err := merge.SignED448(
e.pubSub.GetPublicKey(),
e.pubSub.SignMessage,
); err != nil {
e.logger.Error("could not sign merge", zap.Error(err))
return
}
if err := merge.Validate(); err != nil {
e.logger.Error("merge validation failed", zap.Error(err))
return
}
if err := e.publishMessage(e.txFilter, merge.TokenRequest()); err != nil {
e.logger.Warn("could not publish merge", zap.Error(err))
}
}
}
}
}
}

View File

@ -4,8 +4,6 @@ import (
"bytes"
"time"
"github.com/iden3/go-iden3-crypto/poseidon"
mt "github.com/txaty/go-merkletree"
"go.uber.org/zap"
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application"
@ -233,7 +231,7 @@ func (e *DataClockConsensusEngine) processFrame(
latestFrame *protobufs.ClockFrame,
dataFrame *protobufs.ClockFrame,
) *protobufs.ClockFrame {
e.logger.Info(
"current frame head",
zap.Uint64("frame_number", dataFrame.FrameNumber),
@ -282,144 +280,6 @@ func (e *DataClockConsensusEngine) processFrame(
return nextFrame
} else {
if latestFrame.Timestamp > time.Now().UnixMilli()-120000 {
if !e.IsInProverTrie(e.pubSub.GetPeerID()) {
e.logger.Info("announcing prover join")
for _, eng := range e.executionEngines {
eng.AnnounceProverJoin()
break
}
} else {
if e.previousFrameProven != nil &&
e.previousFrameProven.FrameNumber == latestFrame.FrameNumber {
return latestFrame
}
h, err := poseidon.HashBytes(e.pubSub.GetPeerID())
if err != nil {
panic(err)
}
peerProvingKeyAddress := h.FillBytes(make([]byte, 32))
ring := -1
if tries := e.GetFrameProverTries(); len(tries) > 1 {
for i, tries := range tries[1:] {
i := i
if tries.Contains(peerProvingKeyAddress) {
ring = i
}
}
}
e.clientReconnectTest++
if e.clientReconnectTest >= 10 {
e.tryReconnectDataWorkerClients()
e.clientReconnectTest = 0
}
previousTreeRoot := []byte{}
if e.previousTree != nil {
previousTreeRoot = e.previousTree.Root
}
outputs := e.PerformTimeProof(latestFrame, previousTreeRoot, latestFrame.Difficulty, ring)
if outputs == nil || len(outputs) < 3 {
e.logger.Info("workers not yet available for proving")
return latestFrame
}
modulo := len(outputs)
var proofTree *mt.MerkleTree
var output [][]byte
if latestFrame.FrameNumber >= application.PROOF_FRAME_COMBINE_CUTOFF {
proofTree, output, err = tries.PackOutputIntoMultiPayloadAndProof(
outputs,
modulo,
latestFrame,
e.previousTree,
)
} else {
proofTree, output, err = tries.PackOutputIntoPayloadAndProof(
outputs,
modulo,
latestFrame,
e.previousTree,
)
}
if err != nil {
e.logger.Error(
"could not successfully pack proof, reattempting",
zap.Error(err),
)
return latestFrame
}
e.previousFrameProven = latestFrame
e.previousTree = proofTree
mint := &protobufs.MintCoinRequest{
Proofs: output,
}
if err := mint.SignED448(e.pubSub.GetPublicKey(), e.pubSub.SignMessage); err != nil {
e.logger.Error("could not sign mint", zap.Error(err))
return latestFrame
}
if err := mint.Validate(); err != nil {
e.logger.Error("mint validation failed", zap.Error(err))
return latestFrame
}
e.logger.Info(
"submitting data proof",
zap.Int("ring", ring),
zap.Int("active_workers", len(outputs)),
zap.Uint64("frame_number", latestFrame.FrameNumber),
zap.Duration("frame_age", frametime.Since(latestFrame)),
)
if err := e.publishMessage(e.txFilter, mint.TokenRequest()); err != nil {
e.logger.Error("could not publish mint", zap.Error(err))
}
if e.config.Engine.AutoMergeCoins {
_, addrs, _, err := e.coinStore.GetCoinsForOwner(
peerProvingKeyAddress,
)
if err != nil {
e.logger.Error(
"received error while iterating coins",
zap.Error(err),
)
return latestFrame
}
if len(addrs) > 25 {
refs := []*protobufs.CoinRef{}
for _, addr := range addrs {
refs = append(refs, &protobufs.CoinRef{
Address: addr,
})
}
merge := &protobufs.MergeCoinRequest{
Coins: refs,
}
if err := merge.SignED448(
e.pubSub.GetPublicKey(),
e.pubSub.SignMessage,
); err != nil {
e.logger.Error("could not sign merge", zap.Error(err))
return latestFrame
}
if err := merge.Validate(); err != nil {
e.logger.Error("merge validation failed", zap.Error(err))
return latestFrame
}
if err := e.publishMessage(e.txFilter, merge.TokenRequest()); err != nil {
e.logger.Warn("could not publish merge", zap.Error(err))
}
}
}
}
}
return latestFrame
}
}

View File

@ -253,6 +253,8 @@ func (e *DataClockConsensusEngine) handleClockFrame(
}
if frame.FrameNumber > head.FrameNumber {
go e.initiateProvers(frame)
if _, err := e.dataTimeReel.Insert(e.ctx, frame); err != nil {
e.logger.Debug("could not insert frame", zap.Error(err))
}

View File

@ -109,7 +109,7 @@ func (p *prover) generateTransfer(coin []byte) *protobufs.TokenRequest {
func (p *prover) generateSplit(addr []byte) *protobufs.TokenRequest {
payload := []byte("split")
payload = append(payload, addr...)
bi1, _ := new(big.Int).SetString("2047999999999", 10)
bi1, _ := new(big.Int).SetString("2048000000000", 10)
bi2, _ := new(big.Int).SetString("2048000000000", 10)
payload = append(payload, bi1.FillBytes(make([]byte, 32))...)
payload = append(payload, bi2.FillBytes(make([]byte, 32))...)
@ -174,6 +174,7 @@ func (p *prover) generateProof(
proofTree *merkletree.MerkleTree,
breakWesoProof bool,
breakTreeProof bool,
treeRecovery bool,
) (*merkletree.MerkleTree, [][]byte, *protobufs.TokenRequest) {
challenge := []byte{}
challenge = append(challenge, []byte(p.peerId)...)
@ -181,50 +182,32 @@ func (p *prover) generateProof(
challenge,
frame.FrameNumber,
)
individualChallenge := append([]byte{}, challenge...)
individualChallenge = binary.BigEndian.AppendUint32(
individualChallenge,
uint32(0),
)
individualChallenge = append(individualChallenge, frame.Output...)
if proofTree != nil {
individualChallenge = append(individualChallenge, proofTree.Root...)
}
out1, _ := wprover.CalculateChallengeProof(individualChallenge, 10000)
if breakWesoProof {
out1[4] ^= 0xff
}
individualChallenge = append([]byte{}, challenge...)
individualChallenge = binary.BigEndian.AppendUint32(
individualChallenge,
uint32(1),
)
individualChallenge = append(individualChallenge, frame.Output...)
if proofTree != nil {
individualChallenge = append(individualChallenge, proofTree.Root...)
}
out2, _ := wprover.CalculateChallengeProof(individualChallenge, 10000)
if breakWesoProof {
out2[4] ^= 0xff
outs := []merkletree.DataBlock{}
target := 8
if treeRecovery {
target = 4
}
for i := 0; i < target; i++ {
individualChallenge := append([]byte{}, challenge...)
individualChallenge = binary.BigEndian.AppendUint32(
individualChallenge,
uint32(i),
)
individualChallenge = append(individualChallenge, frame.Output...)
if proofTree != nil {
individualChallenge = append(individualChallenge, proofTree.Root...)
}
out, _ := wprover.CalculateChallengeProof(individualChallenge, 10000)
if breakWesoProof {
out[0] ^= 0xff
}
individualChallenge = append([]byte{}, challenge...)
individualChallenge = binary.BigEndian.AppendUint32(
individualChallenge,
uint32(2),
)
individualChallenge = append(individualChallenge, frame.Output...)
if proofTree != nil {
individualChallenge = append(individualChallenge, proofTree.Root...)
}
out3, _ := wprover.CalculateChallengeProof(individualChallenge, 10000)
if breakWesoProof {
out3[4] ^= 0xff
outs = append(outs, tries.NewProofLeaf(out))
}
proofTree, output, _ := tries.PackOutputIntoMultiPayloadAndProof(
[]merkletree.DataBlock{tries.NewProofLeaf(out1), tries.NewProofLeaf(out2), tries.NewProofLeaf(out3)},
3,
outs,
len(outs),
frame,
proofTree,
)
@ -237,7 +220,7 @@ func (p *prover) generateProof(
}
mint.SignED448([]byte(p.pubKey), p.privKey.Sign)
return proofTree, [][]byte{out1, out2}, &protobufs.TokenRequest{
return proofTree, [][]byte{}, &protobufs.TokenRequest{
Request: &protobufs.TokenRequest_Mint{
Mint: mint,
},
@ -336,7 +319,7 @@ func TestHandleProverJoin(t *testing.T) {
proofTrees := []*merkletree.MerkleTree{}
reqs := []*protobufs.TokenRequest{}
for _, prover := range provers {
proofTree, _, req := prover.generateProof(frame2, wprover, nil, false, false)
proofTree, _, req := prover.generateProof(frame2, wprover, nil, false, false, false)
proofTrees = append(proofTrees, proofTree)
reqs = append(reqs, req)
}
@ -386,7 +369,7 @@ func TestHandleProverJoin(t *testing.T) {
txn.Commit()
for i, prover := range provers {
proofTree, _, req := prover.generateProof(frame3, wprover, proofTrees[i], false, false)
proofTree, _, req := prover.generateProof(frame3, wprover, proofTrees[i], false, false, true)
proofTrees[i] = proofTree
reqs[i] = req
}
@ -430,7 +413,7 @@ func TestHandleProverJoin(t *testing.T) {
err = txn.Commit()
assert.NoError(t, err)
assert.Len(t, success.Requests, 1)
assert.Len(t, app.TokenOutputs.Outputs, 3)
assert.Len(t, app.TokenOutputs.Outputs, 2)
txn, _ = app.ClockStore.NewTransaction(false)
frame4, _ := wprover.ProveDataClockFrame(frame3, [][]byte{}, []*protobufs.InclusionAggregateProof{}, bprivKey, time.Now().UnixMilli(), 10000)
@ -440,7 +423,7 @@ func TestHandleProverJoin(t *testing.T) {
txn.Commit()
for i, prover := range provers {
proofTree, _, req := prover.generateProof(frame4, wprover, proofTrees[i], false, false)
proofTree, _, req := prover.generateProof(frame4, wprover, proofTrees[i], false, false, true)
proofTrees[i] = proofTree
reqs[i] = req
}

View File

@ -59,12 +59,7 @@ func PackOutputIntoPayloadAndProof(
binary.BigEndian.AppendUint64([]byte{}, frame.FrameNumber),
}
if previousTree != nil {
// don't let node produce invalid proofs that would otherwise fail
if len(previousTree.Proofs) != modulo {
return nil, nil, errors.Wrap(errors.New("invalid tree size"), "pack output into payload and proof")
}
if previousTree != nil && len(previousTree.Proofs) == modulo {
hash := sha3.Sum256(frame.Output)
pick := BytesToUnbiasedMod(hash, uint64(modulo))
if uint64(modulo) < pick {
@ -119,12 +114,7 @@ func PackOutputIntoMultiPayloadAndProof(
binary.BigEndian.AppendUint64([]byte{}, frame.FrameNumber),
}
if previousTree != nil {
// don't let node produce invalid proofs that would otherwise fail
if len(previousTree.Proofs) != modulo {
return nil, nil, errors.Wrap(errors.New("invalid tree size"), "pack output into payload and proof")
}
if previousTree != nil && len(previousTree.Proofs) == modulo {
hash := sha3.Sum256(append(append([]byte{}, frame.Output...), previousTree.Root...))
pick := BytesToUnbiasedMod(hash, uint64(modulo))
if uint64(modulo) < pick {

View File

@ -298,3 +298,51 @@ func TestPackAndVerifyMultiOutput(t *testing.T) {
})
}
}
func TestPackAndVerifyOutputFailover(t *testing.T) {
outputs := make([]mt.DataBlock, 3)
for i := range outputs {
data := make([]byte, 32)
binary.BigEndian.PutUint32(data, uint32(i))
outputs[i] = tries.NewProofLeaf(data)
}
frame := &protobufs.ClockFrame{
FrameNumber: 1,
Output: make([]byte, 516),
}
rand.Read(frame.Output)
var previousTree *mt.MerkleTree
prevOutputs := make([]mt.DataBlock, 4)
for i := range prevOutputs {
data := make([]byte, 32)
binary.BigEndian.PutUint32(data, uint32(i))
prevOutputs[i] = tries.NewProofLeaf(data)
}
var err error
previousTree, err = mt.New(
&mt.Config{
HashFunc: func(data []byte) ([]byte, error) {
hash := sha3.Sum256(data)
return hash[:], nil
},
Mode: mt.ModeProofGen,
DisableLeafHashing: true,
},
prevOutputs,
)
require.NoError(t, err)
tree, output, err := tries.PackOutputIntoMultiPayloadAndProof(
outputs,
3,
frame,
previousTree,
)
require.NoError(t, err)
require.NotNil(t, tree)
require.NotEmpty(t, output)
require.Len(t, output, 3)
}

View File

@ -1,4 +1,4 @@
-----BEGIN PUBLIC KEY-----
MEMwBQYDK2VxAzoARQdib3Fk59jDBMB/+NLiPBE/4QiyIdLmBnL00HdQNFgV4rSz
zD3000Zr8vZpw1wxcuBlEScGEqsA
MEMwBQYDK2VxAzoAtt8OurbqIMwutxjbWHPAe7UM8jmha7Ywa74PJCgGZPmfcyxA
SbjtoSJgZ+cP+4GViDTUhpQqEiEA
-----END PUBLIC KEY-----

View File

@ -1,4 +1,4 @@
-----BEGIN PUBLIC KEY-----
MEMwBQYDK2VxAzoAT7JTc0Xka+PV+WNAwUQQB1AXAt1b+vbb9pQ7vvzsqPsrlOwK
ihovSYUPvh0QJEiJpPQKv6ngyeAA
MEMwBQYDK2VxAzoAPgh3ccNgmMstNxcR/YgtMJtMrrvQbe0wd6l1IxNE8CetMccG
nna6UHBFHY61q/Kb/rNPzfm6kGSA
-----END PUBLIC KEY-----

View File

@ -1,4 +1,4 @@
-----BEGIN PUBLIC KEY-----
MEMwBQYDK2VxAzoAVUevxxsCgh4vW/3TD74TdMOFOJje/yChtcxym46BZw+7udHp
F/hdFT6ksmu/b5xUbcG2S5kWYI2A
MEMwBQYDK2VxAzoAmrdtd1SHyFyOWqDFs/lhdylniZoUZEZRAxrl+YrBl77j+IgE
ksT9uiaHFvxLfDj/ysNwtmOsELYA
-----END PUBLIC KEY-----

View File

@ -1,4 +1,4 @@
-----BEGIN PUBLIC KEY-----
MEMwBQYDK2VxAzoAoRSwYfjTXj80l8jEPYO6a0r2eqezm3Q7Gwo18tZhELUFHdPY
b2m1cSKjW2TmJLgYC+5jthUvzkKA
MEMwBQYDK2VxAzoADKb1qdf4bBERvl7fMeJpeZGKpPo9qubeESDgXCoJvbjS/usI
QoajNH4GztJVMDWMvHTCBNKhdToA
-----END PUBLIC KEY-----