diff --git a/node/consensus/data/consensus_frames.go b/node/consensus/data/consensus_frames.go index 1a195dd..1688702 100644 --- a/node/consensus/data/consensus_frames.go +++ b/node/consensus/data/consensus_frames.go @@ -202,6 +202,7 @@ func (e *DataClockConsensusEngine) prove( if err != nil { return nil, errors.Wrap(err, "prove") } + e.lastProven = previousFrame.FrameNumber e.logger.Info( "returning new proven frame", @@ -233,12 +234,6 @@ func (e *DataClockConsensusEngine) GetMostAheadPeer( max := frameNumber var peer []byte = nil e.peerMapMx.RLock() - beaconInfo, ok := e.peerMap[string(e.beaconPeerId)] - if !ok { - e.peerMapMx.RUnlock() - return nil, 0, p2p.ErrNoPeersAvailable - } - for _, v := range e.peerMap { e.logger.Debug( "checking peer info", @@ -248,7 +243,7 @@ func (e *DataClockConsensusEngine) GetMostAheadPeer( zap.Binary("version", v.version), ) _, ok := e.uncooperativePeersMap[string(v.peerId)] - if v.maxFrame <= beaconInfo.maxFrame && v.maxFrame > max && + if v.maxFrame > max && v.timestamp > config.GetMinimumVersionCutoff().UnixMilli() && bytes.Compare(v.version, config.GetMinimumVersion()) >= 0 && !ok { peer = v.peerId diff --git a/node/consensus/data/data_clock_consensus_engine.go b/node/consensus/data/data_clock_consensus_engine.go index 513d203..3b4fc48 100644 --- a/node/consensus/data/data_clock_consensus_engine.go +++ b/node/consensus/data/data_clock_consensus_engine.go @@ -1,7 +1,6 @@ package data import ( - "bytes" "context" "crypto" "encoding/binary" @@ -11,8 +10,6 @@ import ( "time" "github.com/iden3/go-iden3-crypto/poseidon" - pcrypto "github.com/libp2p/go-libp2p/core/crypto" - "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/discovery/backoff" "github.com/multiformats/go-multiaddr" mn "github.com/multiformats/go-multiaddr/net" @@ -98,7 +95,6 @@ type DataClockConsensusEngine struct { currentReceivingSyncPeersMx sync.Mutex currentReceivingSyncPeers int announcedJoin int - beaconPeerId []byte frameChan chan *protobufs.ClockFrame executionEngines map[string]execution.ExecutionEngine @@ -198,17 +194,6 @@ func NewDataClockConsensusEngine( panic(errors.New("peer info manager is nil")) } - genesis := config.GetGenesis() - beaconPubKey, err := pcrypto.UnmarshalEd448PublicKey(genesis.Beacon) - if err != nil { - panic(err) - } - - beaconPeerId, err := peer.IDFromPublicKey(beaconPubKey) - if err != nil { - panic(err) - } - minimumPeersRequired := cfg.Engine.MinimumPeersRequired if minimumPeersRequired == 0 { minimumPeersRequired = 3 @@ -256,7 +241,6 @@ func NewDataClockConsensusEngine( infoMessageProcessorCh: make(chan *pb.Message), config: cfg, preMidnightMint: map[string]struct{}{}, - beaconPeerId: []byte(beaconPeerId), } logger.Info("constructing consensus engine") @@ -396,20 +380,6 @@ func (e *DataClockConsensusEngine) Start() <-chan error { continue } - e.peerMapMx.RLock() - beaconInfo, ok := e.peerMap[string(e.beaconPeerId)] - if !ok { - e.peerMapMx.RUnlock() - time.Sleep(120 * time.Second) - continue - } - e.peerMapMx.RUnlock() - - if nextFrame.FrameNumber < beaconInfo.maxFrame-100 { - time.Sleep(120 * time.Second) - continue - } - frame = nextFrame timestamp := time.Now().UnixMilli() @@ -1135,29 +1105,3 @@ func (e *DataClockConsensusEngine) createParallelDataClientsFromBaseMultiaddr( ) return clients, nil } - -func (e *DataClockConsensusEngine) announceProverJoin() { - msg := []byte("join") - head, _ := e.dataTimeReel.Head() - msg = binary.BigEndian.AppendUint64(msg, head.FrameNumber) - msg = append(msg, bytes.Repeat([]byte{0xff}, 32)...) - sig, err := e.pubSub.SignMessage(msg) - if err != nil { - panic(err) - } - - e.publishMessage(e.txFilter, &protobufs.TokenRequest{ - Request: &protobufs.TokenRequest_Join{ - Join: &protobufs.AnnounceProverJoin{ - Filter: bytes.Repeat([]byte{0xff}, 32), - FrameNumber: head.FrameNumber, - PublicKeySignatureEd448: &protobufs.Ed448Signature{ - Signature: sig, - PublicKey: &protobufs.Ed448PublicKey{ - KeyValue: e.pubSub.GetPublicKey(), - }, - }, - }, - }, - }) -} diff --git a/node/consensus/data/main_data_loop.go b/node/consensus/data/main_data_loop.go index 13f2132..9e7d524 100644 --- a/node/consensus/data/main_data_loop.go +++ b/node/consensus/data/main_data_loop.go @@ -83,8 +83,7 @@ func (e *DataClockConsensusEngine) processFrame( } } - if latestFrame != nil && - dataFrame.FrameNumber > latestFrame.FrameNumber { + if latestFrame != nil && dataFrame.FrameNumber > latestFrame.FrameNumber { latestFrame = dataFrame } @@ -131,7 +130,11 @@ func (e *DataClockConsensusEngine) processFrame( if !e.IsInProverTrie(e.pubSub.GetPeerID()) && dataFrame.Timestamp > time.Now().UnixMilli()-30000 { e.logger.Info("announcing prover join") - e.announceProverJoin() + for _, eng := range e.executionEngines { + eng.AnnounceProverMerge() + eng.AnnounceProverJoin() + break + } } return latestFrame } diff --git a/node/execution/execution_engine.go b/node/execution/execution_engine.go index 6b08130..806d73a 100644 --- a/node/execution/execution_engine.go +++ b/node/execution/execution_engine.go @@ -19,4 +19,6 @@ type ExecutionEngine interface { GetFrame() *protobufs.ClockFrame GetSeniority() *big.Int GetRingPosition() int + AnnounceProverMerge() + AnnounceProverJoin() } diff --git a/node/execution/intrinsics/token/application/token_application.go b/node/execution/intrinsics/token/application/token_application.go index 0f8f7b0..832734c 100644 --- a/node/execution/intrinsics/token/application/token_application.go +++ b/node/execution/intrinsics/token/application/token_application.go @@ -139,6 +139,41 @@ func (a *TokenApplication) ApplyTransitions( requests = transitions.Requests } + parallelismMap := map[int]uint64{} + for i := range a.Tries[1:] { + parallelismMap[i] = 0 + } + + seen := map[string]struct{}{} + + for _, transition := range requests { + switch t := transition.Request.(type) { + case *protobufs.TokenRequest_Mint: + ring, parallelism, err := t.Mint.RingAndParallelism( + func(addr []byte) int { + if _, ok := seen[string(addr)]; ok { + return -1 + } + + ring := -1 + for i, t := range a.Tries[1:] { + if t.Contains(addr) { + ring = i + seen[string(addr)] = struct{}{} + } + } + + return ring + }, + ) + if err != nil { + continue + } + + parallelismMap[ring] = parallelismMap[ring] + uint64(parallelism) + } + } + for _, transition := range requests { req: switch t := transition.Request.(type) { @@ -319,7 +354,13 @@ func (a *TokenApplication) ApplyTransitions( transition, ) case *protobufs.TokenRequest_Mint: - success, err := a.handleMint(currentFrameNumber, lockMap, t.Mint, frame) + success, err := a.handleMint( + currentFrameNumber, + lockMap, + t.Mint, + frame, + parallelismMap, + ) if err != nil { if !skipFailures { return nil, nil, nil, errors.Wrap( diff --git a/node/execution/intrinsics/token/application/token_handle_mint.go b/node/execution/intrinsics/token/application/token_handle_mint.go index 905b74b..0e4af67 100644 --- a/node/execution/intrinsics/token/application/token_handle_mint.go +++ b/node/execution/intrinsics/token/application/token_handle_mint.go @@ -18,11 +18,14 @@ import ( "source.quilibrium.com/quilibrium/monorepo/node/tries" ) +const PROOF_FRAME_CUTOFF = 46500 + func (a *TokenApplication) handleMint( currentFrameNumber uint64, lockMap map[string]struct{}, t *protobufs.MintCoinRequest, frame *protobufs.ClockFrame, + parallelismMap map[int]uint64, ) ([]*protobufs.TokenOutput, error) { if t == nil || t.Proofs == nil || t.Signature == nil { return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") @@ -119,7 +122,7 @@ func (a *TokenApplication) handleMint( }, } return outputs, nil - } else if len(t.Proofs) > 0 && currentFrameNumber > 0 { + } else if len(t.Proofs) > 0 && currentFrameNumber > PROOF_FRAME_CUTOFF { a.Logger.Debug( "got mint from peer", zap.String("peer_id", base58.Encode([]byte(peerId))), @@ -134,7 +137,6 @@ func (a *TokenApplication) handleMint( return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") } ring := -1 - proverSet := int64((len(a.Tries) - 1) * 1024) for i, t := range a.Tries[1:] { if t.Contains(altAddr.FillBytes(make([]byte, 32))) { ring = i @@ -232,8 +234,12 @@ func (a *TokenApplication) handleMint( ) } + // Current frame - 2 is because the current frame is the newly created frame, + // and the provers are submitting proofs on the frame preceding the one they + // last saw. This enforces liveness and creates a punishment for being + // late. if (previousFrame != nil && newFrameNumber <= previousFrame.FrameNumber) || - newFrameNumber < currentFrameNumber-10 { + newFrameNumber < currentFrameNumber-2 { previousFrameNumber := uint64(0) if previousFrame != nil { previousFrameNumber = previousFrame.FrameNumber @@ -349,15 +355,9 @@ func (a *TokenApplication) handleMint( ) } if verified && delete != nil && len(t.Proofs) > 3 { - ringFactor := big.NewInt(2) - ringFactor.Exp(ringFactor, big.NewInt(int64(ring)), nil) - - // const for testnet - storage := big.NewInt(int64(256 * parallelism)) - unitFactor := big.NewInt(8000000000) - storage.Mul(storage, unitFactor) - storage.Quo(storage, big.NewInt(proverSet)) - storage.Quo(storage, ringFactor) + storage := PomwBasis(1, ring, currentFrameNumber) + storage.Quo(storage, big.NewInt(int64(parallelismMap[ring]))) + storage.Mul(storage, big.NewInt(int64(parallelism))) a.Logger.Debug( "issued reward", @@ -458,3 +458,52 @@ func (a *TokenApplication) handleMint( ) return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") } + +func PomwBasis(generation uint64, ring int, currentFrameNumber uint64) *big.Int { + prec := uint(53) + + one := new(big.Float).SetPrec(prec).SetInt64(1) + divisor := new(big.Float).SetPrec(prec).SetInt64(1048576) + + normalized := new(big.Float).SetPrec(prec) + // A simple hack for estimating state growth in terms of frames, based on + // linear relationship of state growth: + normalized.SetInt64(int64((737280 + currentFrameNumber) / 184320)) + normalized.Quo(normalized, divisor) + + // 1/2^n + exp := new(big.Float).SetPrec(prec).SetInt64(1) + if generation > 0 { + powerOfTwo := new(big.Float).SetPrec(prec).SetInt64(2) + powerOfTwo.SetInt64(1) + for i := uint64(0); i < generation; i++ { + powerOfTwo.Mul(powerOfTwo, big.NewFloat(2)) + } + exp.Quo(one, powerOfTwo) + } + + // (d/1048576)^(1/2^n) + result := new(big.Float).Copy(normalized) + if generation > 0 { + for i := uint64(0); i < generation; i++ { + result.Sqrt(result) + } + } + + // Calculate 1/result + result.Quo(one, result) + + // Divide by 2^s + if ring > 0 { + divisor := new(big.Float).SetPrec(prec).SetInt64(1) + for i := 0; i < ring; i++ { + divisor.Mul(divisor, big.NewFloat(2)) + } + result.Quo(result, divisor) + } + + result.Mul(result, new(big.Float).SetPrec(prec).SetInt64(8000000000)) + + out, _ := result.Int(new(big.Int)) + return out +} diff --git a/node/execution/intrinsics/token/application/token_handle_prover_announce.go b/node/execution/intrinsics/token/application/token_handle_prover_announce.go index 28dfc03..518f0ce 100644 --- a/node/execution/intrinsics/token/application/token_handle_prover_announce.go +++ b/node/execution/intrinsics/token/application/token_handle_prover_announce.go @@ -16,7 +16,8 @@ func (a *TokenApplication) handleAnnounce( var primary *protobufs.Ed448Signature payload := []byte{} - if t == nil || t.PublicKeySignaturesEd448 == nil { + if t == nil || t.PublicKeySignaturesEd448 == nil || + len(t.PublicKeySignaturesEd448) == 0 { return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce") } for i, p := range t.PublicKeySignaturesEd448 { @@ -44,11 +45,18 @@ func (a *TokenApplication) handleAnnounce( return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce") } - for _, p := range t.PublicKeySignaturesEd448 { + for _, p := range t.PublicKeySignaturesEd448[1:] { lockMap[string(p.PublicKey.KeyValue)] = struct{}{} } outputs := []*protobufs.TokenOutput{} + if currentFrameNumber >= PROOF_FRAME_CUTOFF { + outputs = append(outputs, &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Announce{ + Announce: t, + }, + }) + } return outputs, nil } diff --git a/node/execution/intrinsics/token/application/token_handle_prover_join.go b/node/execution/intrinsics/token/application/token_handle_prover_join.go index c723ef5..7ec14a1 100644 --- a/node/execution/intrinsics/token/application/token_handle_prover_join.go +++ b/node/execution/intrinsics/token/application/token_handle_prover_join.go @@ -46,6 +46,10 @@ func (a *TokenApplication) handleDataAnnounceProverJoin( []*protobufs.TokenOutput, error, ) { + if currentFrameNumber < PROOF_FRAME_CUTOFF { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle join") + } + payload := []byte("join") if t == nil || t.PublicKeySignatureEd448 == nil { diff --git a/node/execution/intrinsics/token/application/token_handle_prover_join_test.go b/node/execution/intrinsics/token/application/token_handle_prover_join_test.go index 2d0b2ab..4306b3e 100644 --- a/node/execution/intrinsics/token/application/token_handle_prover_join_test.go +++ b/node/execution/intrinsics/token/application/token_handle_prover_join_test.go @@ -176,12 +176,13 @@ func TestHandleProverJoin(t *testing.T) { fmt.Printf("%x\n", individualChallenge) out2, _ := wprover.CalculateChallengeProof(individualChallenge, 10000) - proofTree, payload, output := tries.PackOutputIntoPayloadAndProof( + proofTree, payload, output, err := tries.PackOutputIntoPayloadAndProof( []merkletree.DataBlock{tries.NewProofLeaf(out1), tries.NewProofLeaf(out2)}, 2, frame2, nil, ) + assert.NoError(t, err) sig, _ = privKey.Sign(payload) app, success, _, err = app.ApplyTransitions(2, &protobufs.TokenRequests{ @@ -240,12 +241,13 @@ func TestHandleProverJoin(t *testing.T) { app.ClockStore.CommitDataClockFrame(frame3.Filter, 3, selbi.FillBytes(make([]byte, 32)), app.Tries, txn, false) txn.Commit() - proofTree, payload, output = tries.PackOutputIntoPayloadAndProof( + proofTree, payload, output, err = tries.PackOutputIntoPayloadAndProof( []merkletree.DataBlock{tries.NewProofLeaf(out1), tries.NewProofLeaf(out2)}, 2, frame3, proofTree, ) + assert.NoError(t, err) sig, _ = privKey.Sign(payload) app, success, _, err = app.ApplyTransitions(3, &protobufs.TokenRequests{ diff --git a/node/execution/intrinsics/token/application/token_handle_prover_leave.go b/node/execution/intrinsics/token/application/token_handle_prover_leave.go index c49f0ce..f39afe6 100644 --- a/node/execution/intrinsics/token/application/token_handle_prover_leave.go +++ b/node/execution/intrinsics/token/application/token_handle_prover_leave.go @@ -15,6 +15,10 @@ func (a *TokenApplication) handleDataAnnounceProverLeave( []*protobufs.TokenOutput, error, ) { + if currentFrameNumber < PROOF_FRAME_CUTOFF { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle leave") + } + payload := []byte("leave") if t == nil || t.PublicKeySignatureEd448 == nil { diff --git a/node/execution/intrinsics/token/application/token_handle_prover_pause.go b/node/execution/intrinsics/token/application/token_handle_prover_pause.go index b504cc6..859fd14 100644 --- a/node/execution/intrinsics/token/application/token_handle_prover_pause.go +++ b/node/execution/intrinsics/token/application/token_handle_prover_pause.go @@ -15,6 +15,10 @@ func (a *TokenApplication) handleDataAnnounceProverPause( []*protobufs.TokenOutput, error, ) { + if currentFrameNumber < PROOF_FRAME_CUTOFF { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle pause") + } + payload := []byte("pause") if t == nil || t.PublicKeySignatureEd448 == nil { diff --git a/node/execution/intrinsics/token/application/token_handle_prover_resume.go b/node/execution/intrinsics/token/application/token_handle_prover_resume.go index af070a0..0b7003c 100644 --- a/node/execution/intrinsics/token/application/token_handle_prover_resume.go +++ b/node/execution/intrinsics/token/application/token_handle_prover_resume.go @@ -15,6 +15,10 @@ func (a *TokenApplication) handleDataAnnounceProverResume( []*protobufs.TokenOutput, error, ) { + if currentFrameNumber < PROOF_FRAME_CUTOFF { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle resume") + } + payload := []byte("resume") if t == nil || t.PublicKeySignatureEd448 == nil { diff --git a/node/execution/intrinsics/token/token_execution_engine.go b/node/execution/intrinsics/token/token_execution_engine.go index 9a2f7c4..51be47d 100644 --- a/node/execution/intrinsics/token/token_execution_engine.go +++ b/node/execution/intrinsics/token/token_execution_engine.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "math/big" "slices" + "strconv" "strings" "sync" gotime "time" @@ -32,17 +33,24 @@ import ( "source.quilibrium.com/quilibrium/monorepo/node/tries" ) -type peerSeniorityItem struct { +type PeerSeniorityItem struct { seniority uint64 addr string } -type peerSeniority map[string]peerSeniorityItem +func NewPeerSeniorityItem(seniority uint64, addr string) PeerSeniorityItem { + return PeerSeniorityItem{ + seniority: seniority, + addr: addr, + } +} -func newFromMap(m map[string]uint64) *peerSeniority { - s := &peerSeniority{} +type PeerSeniority map[string]PeerSeniorityItem + +func newFromMap(m map[string]uint64) *PeerSeniority { + s := &PeerSeniority{} for k, v := range m { - (*s)[k] = peerSeniorityItem{ + (*s)[k] = PeerSeniorityItem{ seniority: v, addr: k, } @@ -50,7 +58,7 @@ func newFromMap(m map[string]uint64) *peerSeniority { return s } -func toSerializedMap(m *peerSeniority) map[string]uint64 { +func toSerializedMap(m *PeerSeniority) map[string]uint64 { s := map[string]uint64{} for k, v := range *m { s[k] = v.seniority @@ -58,7 +66,7 @@ func toSerializedMap(m *peerSeniority) map[string]uint64 { return s } -func (p peerSeniorityItem) Priority() *big.Int { +func (p PeerSeniorityItem) Priority() *big.Int { return big.NewInt(int64(p.seniority)) } @@ -82,7 +90,7 @@ type TokenExecutionEngine struct { alreadyPublishedShare bool intrinsicFilter []byte frameProver qcrypto.FrameProver - peerSeniority *peerSeniority + peerSeniority *PeerSeniority } func NewTokenExecutionEngine( @@ -116,7 +124,6 @@ func NewTokenExecutionEngine( var inclusionProof *qcrypto.InclusionAggregateProof var proverKeys [][]byte var peerSeniority map[string]uint64 - genesisCreated := false if err != nil && errors.Is(err, store.ErrNotFound) { origin, inclusionProof, proverKeys, peerSeniority = CreateGenesisState( @@ -133,7 +140,6 @@ func NewTokenExecutionEngine( ); err != nil { panic(err) } - genesisCreated = true } else if err != nil { panic(err) } else { @@ -155,7 +161,6 @@ func NewTokenExecutionEngine( coinStore, uint(cfg.P2P.Network), ) - genesisCreated = true } } @@ -165,8 +170,29 @@ func NewTokenExecutionEngine( panic(err) } if peerSeniority == nil { - RebuildPeerSeniority(clockStore) + peerSeniority, err = RebuildPeerSeniority(uint(cfg.P2P.Network)) + if err != nil { + panic(err) + } + + txn, err := clockStore.NewTransaction() + if err != nil { + panic(err) + } + + err = clockStore.PutPeerSeniorityMap(txn, intrinsicFilter, peerSeniority) + if err != nil { + txn.Abort() + panic(err) + } + + if err = txn.Commit(); err != nil { + txn.Abort() + panic(err) + } } + } else { + LoadAggregatedSeniorityMap() } e := &TokenExecutionEngine{ @@ -251,126 +277,26 @@ func NewTokenExecutionEngine( e.proverPublicKey = publicKeyBytes e.provingKeyAddress = provingKeyAddress - if genesisCreated { - go func() { - keys := [][]byte{} - ksigs := [][]byte{} - if len(e.engineConfig.MultisigProverEnrollmentPaths) != 0 { - for _, conf := range e.engineConfig.MultisigProverEnrollmentPaths { - extraConf, err := config.LoadConfig(conf, "", false) - if err != nil { - panic(err) - } - - peerPrivKey, err := hex.DecodeString(extraConf.P2P.PeerPrivKey) - if err != nil { - panic(errors.Wrap(err, "error unmarshaling peerkey")) - } - - privKey, err := pcrypto.UnmarshalEd448PrivateKey(peerPrivKey) - if err != nil { - panic(errors.Wrap(err, "error unmarshaling peerkey")) - } - - pub := privKey.GetPublic() - pubBytes, err := pub.Raw() - if err != nil { - panic(errors.Wrap(err, "error unmarshaling peerkey")) - } - - keys = append(keys, pubBytes) - sig, err := privKey.Sign(e.pubSub.GetPublicKey()) - if err != nil { - panic(errors.Wrap(err, "error unmarshaling peerkey")) - } - ksigs = append(ksigs, sig) - } - } - - keyjoin := []byte{} - for _, k := range keys { - keyjoin = append(keyjoin, k...) - } - - mainsig, err := e.pubSub.SignMessage(keyjoin) - if err != nil { - panic(err) - } - - announce := &protobufs.TokenRequest_Announce{ - Announce: &protobufs.AnnounceProverRequest{ - PublicKeySignaturesEd448: []*protobufs.Ed448Signature{}, - }, - } - - announce.Announce.PublicKeySignaturesEd448 = append( - announce.Announce.PublicKeySignaturesEd448, - &protobufs.Ed448Signature{ - PublicKey: &protobufs.Ed448PublicKey{ - KeyValue: e.pubSub.GetPublicKey(), - }, - Signature: mainsig, - }, - ) - - for i := range keys { - announce.Announce.PublicKeySignaturesEd448 = append( - announce.Announce.PublicKeySignaturesEd448, - &protobufs.Ed448Signature{ - PublicKey: &protobufs.Ed448PublicKey{ - KeyValue: keys[i], - }, - Signature: ksigs[i], - }, - ) - } - - req := &protobufs.TokenRequest{ - Request: announce, - } - - // need to wait for peering - gotime.Sleep(30 * gotime.Second) - e.publishMessage(append([]byte{0x00}, intrinsicFilter...), req) - }() - } else { + go func() { f, tries, err := e.clockStore.GetLatestDataClockFrame(e.intrinsicFilter) - fn, err := coinStore.GetLatestFrameProcessed() if err != nil { - panic(err) + return } - if f.FrameNumber != fn && fn == 0 { - txn, err := coinStore.NewTransaction() + shouldResume := false + for _, trie := range tries[1:] { + altAddr, err := poseidon.HashBytes(e.pubSub.GetPeerID()) if err != nil { - panic(err) + break } - err = coinStore.SetLatestFrameProcessed(txn, f.FrameNumber) - if err != nil { - txn.Abort() - panic(err) - } - - if err = txn.Commit(); err != nil { - panic(err) - } - } else if f.FrameNumber-fn == 1 && f.FrameNumber > fn { - txn, err := coinStore.NewTransaction() - if err != nil { - panic(err) - } - e.logger.Info( - "replaying last data frame", - zap.Uint64("frame_number", f.FrameNumber), - ) - e.ProcessFrame(txn, f, tries) - if err = txn.Commit(); err != nil { - panic(err) + if trie.Contains(altAddr.FillBytes(make([]byte, 32))) { + shouldResume = true + break } } - if err == nil { + if shouldResume { msg := []byte("resume") msg = binary.BigEndian.AppendUint64(msg, f.FrameNumber) msg = append(msg, e.intrinsicFilter...) @@ -380,7 +306,17 @@ func NewTokenExecutionEngine( } // need to wait for peering - gotime.Sleep(30 * gotime.Second) + for { + gotime.Sleep(30 * gotime.Second) + peerMap := e.pubSub.GetBitmaskPeers() + if peers, ok := peerMap[string( + append([]byte{0x00}, e.intrinsicFilter...), + )]; ok { + if len(peers) >= 3 { + break + } + } + } e.publishMessage( append([]byte{0x00}, e.intrinsicFilter...), &protobufs.TokenRequest{ @@ -399,7 +335,7 @@ func NewTokenExecutionEngine( }, ) } - } + }() return e } @@ -591,17 +527,23 @@ func (e *TokenExecutionEngine) ProcessFrame( txn.Abort() return nil, errors.Wrap(err, "process frame") } - // testnet: if len(o.Proof.Amount) == 32 && - !bytes.Equal(o.Proof.Amount, make([]byte, 32)) { + !bytes.Equal(o.Proof.Amount, make([]byte, 32)) && + o.Proof.Commitment != nil { addr := string(o.Proof.Owner.GetImplicitAccount().Address) + for _, t := range app.Tries { + if t.Contains([]byte(addr)) { + t.Add([]byte(addr), frame.FrameNumber) + break + } + } if _, ok := (*e.peerSeniority)[addr]; !ok { - (*e.peerSeniority)[addr] = peerSeniorityItem{ + (*e.peerSeniority)[addr] = PeerSeniorityItem{ seniority: 10, addr: addr, } } else { - (*e.peerSeniority)[addr] = peerSeniorityItem{ + (*e.peerSeniority)[addr] = PeerSeniorityItem{ seniority: (*e.peerSeniority)[addr].seniority + 10, addr: addr, } @@ -622,6 +564,96 @@ func (e *TokenExecutionEngine) ProcessFrame( txn.Abort() return nil, errors.Wrap(err, "process frame") } + case *protobufs.TokenOutput_Announce: + peerIds := []string{} + for _, sig := range o.Announce.PublicKeySignaturesEd448 { + peerId, err := e.getPeerIdFromSignature(sig) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "process frame") + } + + peerIds = append(peerIds, peerId.String()) + } + + mergeable := true + for i, peerId := range peerIds { + addr, err := e.getAddressFromSignature( + o.Announce.PublicKeySignaturesEd448[i], + ) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "process frame") + } + + sen, ok := (*e.peerSeniority)[string(addr)] + if !ok { + e.logger.Debug( + "peer announced with no seniority", + zap.String("peer_id", peerId), + ) + continue + } + + peer := new(big.Int).SetUint64(sen.seniority) + if peer.Cmp(e.GetAggregatedSeniority([]string{peerId})) != 0 { + e.logger.Debug( + "peer announced but is already different seniority", + zap.String("peer_id", peerIds[0]), + ) + mergeable = false + break + } + } + + if mergeable { + addr, err := e.getAddressFromSignature( + o.Announce.PublicKeySignaturesEd448[0], + ) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "process frame") + } + + additional := uint64(0) + _, prfs, err := e.coinStore.GetPreCoinProofsForOwner(addr) + if err != nil && !errors.Is(err, store.ErrNotFound) { + txn.Abort() + return nil, errors.Wrap(err, "process frame") + } + + for _, pr := range prfs { + if pr.IndexProof == nil && pr.Difficulty == 0 && pr.Commitment == nil { + // approximate average per interval: + add := new(big.Int).SetBytes(pr.Amount) + add.Quo(add, big.NewInt(58800000)) + if add.Cmp(big.NewInt(4000000)) > 0 { + add = big.NewInt(4000000) + } + additional = add.Uint64() + } + } + + (*e.peerSeniority)[string(addr)] = PeerSeniorityItem{ + seniority: e.GetAggregatedSeniority(peerIds).Uint64() + additional, + addr: string(addr), + } + + for _, sig := range o.Announce.PublicKeySignaturesEd448[1:] { + addr, err := e.getAddressFromSignature( + sig, + ) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "process frame") + } + + (*e.peerSeniority)[string(addr)] = PeerSeniorityItem{ + seniority: 0, + addr: string(addr), + } + } + } case *protobufs.TokenOutput_Join: addr, err := e.getAddressFromSignature(o.Join.PublicKeySignatureEd448) if err != nil { @@ -629,12 +661,12 @@ func (e *TokenExecutionEngine) ProcessFrame( return nil, errors.Wrap(err, "process frame") } if _, ok := (*e.peerSeniority)[string(addr)]; !ok { - (*e.peerSeniority)[string(addr)] = peerSeniorityItem{ + (*e.peerSeniority)[string(addr)] = PeerSeniorityItem{ seniority: 20, addr: string(addr), } } else { - (*e.peerSeniority)[string(addr)] = peerSeniorityItem{ + (*e.peerSeniority)[string(addr)] = PeerSeniorityItem{ seniority: (*e.peerSeniority)[string(addr)].seniority + 20, addr: string(addr), } @@ -662,19 +694,28 @@ func (e *TokenExecutionEngine) ProcessFrame( case *protobufs.TokenOutput_Penalty: addr := string(o.Penalty.Account.GetImplicitAccount().Address) if _, ok := (*e.peerSeniority)[addr]; !ok { - (*e.peerSeniority)[addr] = peerSeniorityItem{ + (*e.peerSeniority)[addr] = PeerSeniorityItem{ seniority: 0, addr: addr, } proverTrieLeaveRequests = append(proverTrieLeaveRequests, []byte(addr)) } else { if (*e.peerSeniority)[addr].seniority > o.Penalty.Quantity { - (*e.peerSeniority)[addr] = peerSeniorityItem{ + for _, t := range app.Tries { + if t.Contains([]byte(addr)) { + _, latest, _ := t.Get([]byte(addr)) + if frame.FrameNumber-latest > 100 { + proverTrieLeaveRequests = append(proverTrieLeaveRequests, []byte(addr)) + } + break + } + } + (*e.peerSeniority)[addr] = PeerSeniorityItem{ seniority: (*e.peerSeniority)[addr].seniority - o.Penalty.Quantity, addr: addr, } } else { - (*e.peerSeniority)[addr] = peerSeniorityItem{ + (*e.peerSeniority)[addr] = PeerSeniorityItem{ seniority: 0, addr: addr, } @@ -684,11 +725,11 @@ func (e *TokenExecutionEngine) ProcessFrame( } } - joinAddrs := tries.NewMinHeap[peerSeniorityItem]() - leaveAddrs := tries.NewMinHeap[peerSeniorityItem]() + joinAddrs := tries.NewMinHeap[PeerSeniorityItem]() + leaveAddrs := tries.NewMinHeap[PeerSeniorityItem]() for _, addr := range proverTrieJoinRequests { if _, ok := (*e.peerSeniority)[string(addr)]; !ok { - joinAddrs.Push(peerSeniorityItem{ + joinAddrs.Push(PeerSeniorityItem{ addr: string(addr), seniority: 0, }) @@ -698,7 +739,7 @@ func (e *TokenExecutionEngine) ProcessFrame( } for _, addr := range proverTrieLeaveRequests { if _, ok := (*e.peerSeniority)[string(addr)]; !ok { - leaveAddrs.Push(peerSeniorityItem{ + leaveAddrs.Push(PeerSeniorityItem{ addr: string(addr), seniority: 0, }) @@ -707,36 +748,14 @@ func (e *TokenExecutionEngine) ProcessFrame( } } - joinReqs := make([]peerSeniorityItem, len(joinAddrs.All())) + joinReqs := make([]PeerSeniorityItem, len(joinAddrs.All())) copy(joinReqs, joinAddrs.All()) slices.Reverse(joinReqs) - leaveReqs := make([]peerSeniorityItem, len(leaveAddrs.All())) + leaveReqs := make([]PeerSeniorityItem, len(leaveAddrs.All())) copy(leaveReqs, leaveAddrs.All()) slices.Reverse(leaveReqs) - for _, addr := range joinReqs { - rings := len(app.Tries) - last := app.Tries[rings-1] - set := last.FindNearestAndApproximateNeighbors(make([]byte, 32)) - if len(set) == 1024 || rings == 1 { - app.Tries = append( - app.Tries, - &tries.RollingFrecencyCritbitTrie{}, - ) - last = app.Tries[rings] - } - if !last.Contains([]byte(addr.addr)) { - last.Add([]byte(addr.addr), frame.FrameNumber) - } - } - for _, addr := range leaveReqs { - for _, t := range app.Tries { - if t.Contains([]byte(addr.addr)) { - t.Remove([]byte(addr.addr)) - break - } - } - } + ProcessJoinsAndLeaves(joinReqs, leaveReqs, app, e.peerSeniority, frame) err = e.clockStore.PutPeerSeniorityMap( txn, @@ -757,6 +776,57 @@ func (e *TokenExecutionEngine) ProcessFrame( return app.Tries, nil } +func ProcessJoinsAndLeaves( + joinReqs []PeerSeniorityItem, + leaveReqs []PeerSeniorityItem, + app *application.TokenApplication, + seniority *PeerSeniority, + frame *protobufs.ClockFrame, +) { + for _, addr := range joinReqs { + rings := len(app.Tries) + last := app.Tries[rings-1] + set := last.FindNearestAndApproximateNeighbors(make([]byte, 32)) + if len(set) == 2048 || rings == 1 { + app.Tries = append( + app.Tries, + &tries.RollingFrecencyCritbitTrie{}, + ) + last = app.Tries[rings] + } + if !last.Contains([]byte(addr.addr)) { + last.Add([]byte(addr.addr), frame.FrameNumber) + } + } + for _, addr := range leaveReqs { + for _, t := range app.Tries[1:] { + if t.Contains([]byte(addr.addr)) { + t.Remove([]byte(addr.addr)) + break + } + } + } + + if len(app.Tries) > 2 { + for i, t := range app.Tries[2:] { + setSize := len(app.Tries[1+i].FindNearestAndApproximateNeighbors(make([]byte, 32))) + if setSize < 2048 { + nextSet := t.FindNearestAndApproximateNeighbors(make([]byte, 32)) + eligibilityOrder := tries.NewMinHeap[PeerSeniorityItem]() + for _, n := range nextSet { + eligibilityOrder.Push((*seniority)[string(n.External.Key)]) + } + process := eligibilityOrder.All() + slices.Reverse(process) + for s := 0; s+setSize < 2048; s++ { + app.Tries[1+i].Add([]byte(process[s].addr), frame.FrameNumber) + app.Tries[2+i].Remove([]byte(process[s].addr)) + } + } + } + } +} + func (e *TokenExecutionEngine) publishMessage( filter []byte, message proto.Message, @@ -913,6 +983,235 @@ func (e *TokenExecutionEngine) GetSeniority() *big.Int { return sen.Priority() } +func (e *TokenExecutionEngine) GetAggregatedSeniority(peerIds []string) *big.Int { + highestFirst := uint64(0) + highestSecond := uint64(0) + highestThird := uint64(0) + highestFourth := uint64(0) + + for _, f := range firstRetro { + found := false + for _, p := range peerIds { + if p != f.PeerId { + continue + } + found = true + } + if !found { + continue + } + // these don't have decimals so we can shortcut + max := 157208 + actual, err := strconv.Atoi(f.Reward) + if err != nil { + panic(err) + } + + s := uint64(10 * 6 * 60 * 24 * 92 / (max / actual)) + if s > uint64(highestFirst) { + highestFirst = s + } + } + + for _, f := range secondRetro { + found := false + for _, p := range peerIds { + if p != f.PeerId { + continue + } + found = true + } + if !found { + continue + } + + amt := uint64(0) + if f.JanPresence { + amt += (10 * 6 * 60 * 24 * 31) + } + + if f.FebPresence { + amt += (10 * 6 * 60 * 24 * 29) + } + + if f.MarPresence { + amt += (10 * 6 * 60 * 24 * 31) + } + + if f.AprPresence { + amt += (10 * 6 * 60 * 24 * 30) + } + + if f.MayPresence { + amt += (10 * 6 * 60 * 24 * 31) + } + + if amt > uint64(highestSecond) { + highestSecond = amt + } + } + + for _, f := range thirdRetro { + found := false + for _, p := range peerIds { + if p != f.PeerId { + continue + } + found = true + } + if !found { + continue + } + + s := uint64(10 * 6 * 60 * 24 * 30) + if s > uint64(highestThird) { + highestThird = s + } + } + + for _, f := range fourthRetro { + found := false + for _, p := range peerIds { + if p != f.PeerId { + continue + } + found = true + } + if !found { + continue + } + + s := uint64(10 * 6 * 60 * 24 * 31) + if s > uint64(highestFourth) { + highestFourth = s + } + } + return new(big.Int).SetUint64( + highestFirst + highestSecond + highestThird + highestFourth, + ) +} + +func (e *TokenExecutionEngine) AnnounceProverMerge() { + currentHead := e.GetFrame() + if currentHead == nil || + currentHead.FrameNumber < application.PROOF_FRAME_CUTOFF { + return + } + keys := [][]byte{} + ksigs := [][]byte{} + if len(e.engineConfig.MultisigProverEnrollmentPaths) != 0 && + e.GetSeniority().Cmp(e.GetAggregatedSeniority( + []string{peer.ID(e.pubSub.GetPeerID()).String()}, + )) == 0 { + for _, conf := range e.engineConfig.MultisigProverEnrollmentPaths { + extraConf, err := config.LoadConfig(conf, "", false) + if err != nil { + panic(err) + } + + peerPrivKey, err := hex.DecodeString(extraConf.P2P.PeerPrivKey) + if err != nil { + panic(errors.Wrap(err, "error unmarshaling peerkey")) + } + + privKey, err := pcrypto.UnmarshalEd448PrivateKey(peerPrivKey) + if err != nil { + panic(errors.Wrap(err, "error unmarshaling peerkey")) + } + + pub := privKey.GetPublic() + pubBytes, err := pub.Raw() + if err != nil { + panic(errors.Wrap(err, "error unmarshaling peerkey")) + } + + keys = append(keys, pubBytes) + sig, err := privKey.Sign(e.pubSub.GetPublicKey()) + if err != nil { + panic(errors.Wrap(err, "error unmarshaling peerkey")) + } + ksigs = append(ksigs, sig) + } + } + + keyjoin := []byte{} + for _, k := range keys { + keyjoin = append(keyjoin, k...) + } + + mainsig, err := e.pubSub.SignMessage(keyjoin) + if err != nil { + panic(err) + } + + announce := &protobufs.TokenRequest_Announce{ + Announce: &protobufs.AnnounceProverRequest{ + PublicKeySignaturesEd448: []*protobufs.Ed448Signature{}, + }, + } + + announce.Announce.PublicKeySignaturesEd448 = append( + announce.Announce.PublicKeySignaturesEd448, + &protobufs.Ed448Signature{ + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.pubSub.GetPublicKey(), + }, + Signature: mainsig, + }, + ) + + for i := range keys { + announce.Announce.PublicKeySignaturesEd448 = append( + announce.Announce.PublicKeySignaturesEd448, + &protobufs.Ed448Signature{ + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: keys[i], + }, + Signature: ksigs[i], + }, + ) + } + + req := &protobufs.TokenRequest{ + Request: announce, + } + + e.publishMessage(append([]byte{0x00}, e.intrinsicFilter...), req) +} + +func (e *TokenExecutionEngine) AnnounceProverJoin() { + msg := []byte("join") + head := e.GetFrame() + if head == nil || + head.FrameNumber < application.PROOF_FRAME_CUTOFF { + return + } + msg = binary.BigEndian.AppendUint64(msg, head.FrameNumber) + msg = append(msg, bytes.Repeat([]byte{0xff}, 32)...) + sig, err := e.pubSub.SignMessage(msg) + if err != nil { + panic(err) + } + + e.publishMessage( + append([]byte{0x00}, e.intrinsicFilter...), + &protobufs.TokenRequest{ + Request: &protobufs.TokenRequest_Join{ + Join: &protobufs.AnnounceProverJoin{ + Filter: bytes.Repeat([]byte{0xff}, 32), + FrameNumber: head.FrameNumber, + PublicKeySignatureEd448: &protobufs.Ed448Signature{ + Signature: sig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.pubSub.GetPublicKey(), + }, + }, + }, + }, + }, + ) +} + func (e *TokenExecutionEngine) GetRingPosition() int { altAddr, err := poseidon.HashBytes(e.pubSub.GetPeerID()) if err != nil { @@ -933,6 +1232,28 @@ func (e *TokenExecutionEngine) GetRingPosition() int { return -1 } +func (e *TokenExecutionEngine) getPeerIdFromSignature( + sig *protobufs.Ed448Signature, +) (peer.ID, error) { + if sig.PublicKey == nil || sig.PublicKey.KeyValue == nil { + return "", errors.New("invalid data") + } + + pk, err := pcrypto.UnmarshalEd448PublicKey( + sig.PublicKey.KeyValue, + ) + if err != nil { + return "", errors.Wrap(err, "get address from signature") + } + + peerId, err := peer.IDFromPublicKey(pk) + if err != nil { + return "", errors.Wrap(err, "get address from signature") + } + + return peerId, nil +} + func (e *TokenExecutionEngine) getAddressFromSignature( sig *protobufs.Ed448Signature, ) ([]byte, error) { diff --git a/node/execution/intrinsics/token/token_execution_engine_test.go b/node/execution/intrinsics/token/token_execution_engine_test.go new file mode 100644 index 0000000..68fcfdf --- /dev/null +++ b/node/execution/intrinsics/token/token_execution_engine_test.go @@ -0,0 +1,52 @@ +package token_test + +import ( + "crypto/rand" + "testing" + + "github.com/stretchr/testify/assert" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/tries" +) + +func TestProcessJoinsAndLeaves(t *testing.T) { + set := [][]byte{} + for i := 0; i < 6000; i++ { + b := make([]byte, 32) + rand.Read(b) + set = append(set, b) + } + + joins := []token.PeerSeniorityItem{} + seniority := &token.PeerSeniority{} + for i, s := range set { + joins = append(joins, token.NewPeerSeniorityItem(uint64(i), string(s))) + (*seniority)[string(s)] = token.NewPeerSeniorityItem(uint64(i), string(s)) + } + tr := []*tries.RollingFrecencyCritbitTrie{ + &tries.RollingFrecencyCritbitTrie{}, + &tries.RollingFrecencyCritbitTrie{}, + } + app := &application.TokenApplication{ + Tries: tr, + } + token.ProcessJoinsAndLeaves(joins, []token.PeerSeniorityItem{}, app, seniority, &protobufs.ClockFrame{FrameNumber: 20}) + + assert.Equal(t, len(app.Tries), 4) + assert.Equal(t, len(app.Tries[1].FindNearestAndApproximateNeighbors(make([]byte, 32))), 2048) + assert.Equal(t, len(app.Tries[2].FindNearestAndApproximateNeighbors(make([]byte, 32))), 2048) + assert.Equal(t, len(app.Tries[3].FindNearestAndApproximateNeighbors(make([]byte, 32))), 1904) + + leaves := []token.PeerSeniorityItem{} + leaves = append(leaves, joins[30]) + leaves = append(leaves, joins[2047]) + leaves = append(leaves, joins[4095]) + token.ProcessJoinsAndLeaves([]token.PeerSeniorityItem{}, leaves, app, seniority, &protobufs.ClockFrame{FrameNumber: 20}) + + assert.Equal(t, len(app.Tries), 4) + assert.Equal(t, len(app.Tries[1].FindNearestAndApproximateNeighbors(make([]byte, 32))), 2048) + assert.Equal(t, len(app.Tries[2].FindNearestAndApproximateNeighbors(make([]byte, 32))), 2048) + assert.Equal(t, len(app.Tries[3].FindNearestAndApproximateNeighbors(make([]byte, 32))), 1901) +} diff --git a/node/execution/intrinsics/token/token_genesis.go b/node/execution/intrinsics/token/token_genesis.go index d415678..5c2279d 100644 --- a/node/execution/intrinsics/token/token_genesis.go +++ b/node/execution/intrinsics/token/token_genesis.go @@ -75,25 +75,140 @@ var thirdRetroJsonBinary []byte //go:embed fourth_retro.json var fourthRetroJsonBinary []byte -func RebuildPeerSeniority(clockStore store.ClockStore) { - // testnet: - txn, err := clockStore.NewTransaction() +var firstRetro []*FirstRetroJson +var secondRetro []*SecondRetroJson +var thirdRetro []*ThirdRetroJson +var fourthRetro []*FourthRetroJson + +func LoadAggregatedSeniorityMap() { + firstRetro = []*FirstRetroJson{} + secondRetro = []*SecondRetroJson{} + thirdRetro = []*ThirdRetroJson{} + fourthRetro = []*FourthRetroJson{} + + err := json.Unmarshal(firstRetroJsonBinary, &firstRetro) if err != nil { panic(err) } - err = clockStore.PutPeerSeniorityMap( - txn, - p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3), - map[string]uint64{}, - ) + err = json.Unmarshal(secondRetroJsonBinary, &secondRetro) if err != nil { panic(err) } - if err = txn.Commit(); err != nil { + err = json.Unmarshal(thirdRetroJsonBinary, &thirdRetro) + if err != nil { panic(err) } + + err = json.Unmarshal(fourthRetroJsonBinary, &fourthRetro) + if err != nil { + panic(err) + } +} + +func RebuildPeerSeniority(network uint) (map[string]uint64, error) { + if network != 0 { + return map[string]uint64{}, nil + } + + firstRetro = []*FirstRetroJson{} + secondRetro = []*SecondRetroJson{} + thirdRetro = []*ThirdRetroJson{} + fourthRetro = []*FourthRetroJson{} + + err := json.Unmarshal(firstRetroJsonBinary, &firstRetro) + if err != nil { + return nil, err + } + + err = json.Unmarshal(secondRetroJsonBinary, &secondRetro) + if err != nil { + return nil, err + } + + err = json.Unmarshal(thirdRetroJsonBinary, &thirdRetro) + if err != nil { + return nil, err + } + + err = json.Unmarshal(fourthRetroJsonBinary, &fourthRetro) + if err != nil { + return nil, err + } + + peerSeniority := map[string]uint64{} + for _, f := range firstRetro { + // these don't have decimals so we can shortcut + max := 157208 + actual, err := strconv.Atoi(f.Reward) + if err != nil { + return nil, err + } + + p := []byte(f.PeerId) + addr, _ := poseidon.HashBytes(p) + + peerSeniority[string( + addr.FillBytes(make([]byte, 32)), + )] = uint64(10 * 6 * 60 * 24 * 92 / (max / actual)) + } + + for _, f := range secondRetro { + p := []byte(f.PeerId) + addr, _ := poseidon.HashBytes(p) + addrBytes := string(addr.FillBytes(make([]byte, 32))) + + if _, ok := peerSeniority[addrBytes]; !ok { + peerSeniority[addrBytes] = 0 + } + + if f.JanPresence { + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 31) + } + + if f.FebPresence { + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 29) + } + + if f.MarPresence { + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 31) + } + + if f.AprPresence { + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 30) + } + + if f.MayPresence { + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 31) + } + } + + for _, f := range thirdRetro { + p := []byte(f.PeerId) + addr, _ := poseidon.HashBytes(p) + addrBytes := string(addr.FillBytes(make([]byte, 32))) + + if _, ok := peerSeniority[addrBytes]; !ok { + peerSeniority[addrBytes] = 0 + } + + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 30) + } + + for _, f := range fourthRetro { + p := []byte(f.PeerId) + addr, _ := poseidon.HashBytes(p) + addrBytes := string(addr.FillBytes(make([]byte, 32))) + + if _, ok := peerSeniority[addrBytes]; !ok { + peerSeniority[addrBytes] = 0 + } + + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 31) + } + + return peerSeniority, nil } // Creates a genesis state for the intrinsic @@ -147,10 +262,10 @@ func CreateGenesisState( if network == 0 { bridged := []*BridgedPeerJson{} vouchers := []string{} - firstRetro := []*FirstRetroJson{} - secondRetro := []*SecondRetroJson{} - thirdRetro := []*ThirdRetroJson{} - fourthRetro := []*FourthRetroJson{} + firstRetro = []*FirstRetroJson{} + secondRetro = []*SecondRetroJson{} + thirdRetro = []*ThirdRetroJson{} + fourthRetro = []*FourthRetroJson{} err = json.Unmarshal(bridgedPeersJsonBinary, &bridged) if err != nil { @@ -200,6 +315,9 @@ func CreateGenesisState( peerSeniority := map[string]uint64{} logger.Info("encoding first retro state") for _, f := range firstRetro { + p := []byte(f.PeerId) + addr, _ := poseidon.HashBytes(p) + addrBytes := string(addr.FillBytes(make([]byte, 32))) if _, ok := bridgedAddrs[f.PeerId]; !ok { peerIdTotals[f.PeerId], err = decimal.NewFromString(f.Reward) if err != nil { @@ -214,7 +332,7 @@ func CreateGenesisState( panic(err) } - peerSeniority[f.PeerId] = uint64(10 * 6 * 60 * 24 * 92 / (max / actual)) + peerSeniority[addrBytes] = uint64(10 * 6 * 60 * 24 * 92 / (max / actual)) } logger.Info("encoding voucher state") @@ -226,6 +344,10 @@ func CreateGenesisState( logger.Info("encoding second retro state") for _, f := range secondRetro { + p := []byte(f.PeerId) + addr, _ := poseidon.HashBytes(p) + addrBytes := string(addr.FillBytes(make([]byte, 32))) + if _, ok := bridgedAddrs[f.PeerId]; !ok { existing, ok := peerIdTotals[f.PeerId] @@ -241,33 +363,37 @@ func CreateGenesisState( } } - if _, ok := peerSeniority[f.PeerId]; !ok { - peerSeniority[f.PeerId] = 0 + if _, ok := peerSeniority[addrBytes]; !ok { + peerSeniority[addrBytes] = 0 } if f.JanPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 31) } if f.FebPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 29) + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 29) } if f.MarPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 31) } if f.AprPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 30) + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 30) } if f.MayPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 31) } } logger.Info("encoding third retro state") for _, f := range thirdRetro { + p := []byte(f.PeerId) + addr, _ := poseidon.HashBytes(p) + addrBytes := string(addr.FillBytes(make([]byte, 32))) + existing, ok := peerIdTotals[f.PeerId] amount, err := decimal.NewFromString(f.Reward) @@ -281,15 +407,19 @@ func CreateGenesisState( peerIdTotals[f.PeerId] = existing.Add(amount) } - if _, ok := peerSeniority[f.PeerId]; !ok { - peerSeniority[f.PeerId] = 0 + if _, ok := peerSeniority[addrBytes]; !ok { + peerSeniority[addrBytes] = 0 } - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 30) + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 30) } logger.Info("encoding fourth retro state") for _, f := range fourthRetro { + p := []byte(f.PeerId) + addr, _ := poseidon.HashBytes(p) + addrBytes := string(addr.FillBytes(make([]byte, 32))) + existing, ok := peerIdTotals[f.PeerId] amount, err := decimal.NewFromString(f.Reward) @@ -303,11 +433,11 @@ func CreateGenesisState( peerIdTotals[f.PeerId] = existing.Add(amount) } - if _, ok := peerSeniority[f.PeerId]; !ok { - peerSeniority[f.PeerId] = 0 + if _, ok := peerSeniority[addrBytes]; !ok { + peerSeniority[addrBytes] = 0 } - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) + peerSeniority[addrBytes] = peerSeniority[addrBytes] + (10 * 6 * 60 * 24 * 31) } genesisState := &protobufs.TokenOutputs{ diff --git a/node/protobufs/node.go b/node/protobufs/node.go index 1742958..0ece2a6 100644 --- a/node/protobufs/node.go +++ b/node/protobufs/node.go @@ -1,6 +1,14 @@ package protobufs -import "math/big" +import ( + "encoding/binary" + "math/big" + + "github.com/iden3/go-iden3-crypto/poseidon" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/pkg/errors" +) func (t *TokenRequest) Priority() *big.Int { switch p := t.Request.(type) { @@ -11,3 +19,42 @@ func (t *TokenRequest) Priority() *big.Int { } return big.NewInt(0) } + +func (t *MintCoinRequest) RingAndParallelism( + ringCalc func(addr []byte) int, +) (int, uint32, error) { + payload := []byte("mint") + for _, p := range t.Proofs { + payload = append(payload, p...) + } + if err := t.Signature.Verify(payload); err != nil { + return -1, 0, errors.New("invalid") + } + pk, err := pcrypto.UnmarshalEd448PublicKey( + t.Signature.PublicKey.KeyValue, + ) + if err != nil { + return -1, 0, errors.New("invalid") + } + + peerId, err := peer.IDFromPublicKey(pk) + if err != nil { + return -1, 0, errors.New("invalid") + } + + altAddr, err := poseidon.HashBytes([]byte(peerId)) + if err != nil { + return -1, 0, errors.New("invalid") + } + + ring := ringCalc(altAddr.FillBytes(make([]byte, 32))) + if ring == -1 { + return -1, 0, errors.New("invalid") + } + + if t.Proofs != nil && len(t.Proofs) >= 3 && len(t.Proofs[1]) == 4 { + return ring, binary.BigEndian.Uint32(t.Proofs[1]), nil + } + + return -1, 0, errors.New("invalid") +} diff --git a/node/store/coin.go b/node/store/coin.go index 83d785f..a5da8c7 100644 --- a/node/store/coin.go +++ b/node/store/coin.go @@ -23,6 +23,7 @@ type CoinStore interface { ) GetCoinByAddress(txn Transaction, address []byte) (*protobufs.Coin, error) GetPreCoinProofByAddress(address []byte) (*protobufs.PreCoinProof, error) + RangePreCoinProofs() (Iterator, error) PutCoin( txn Transaction, frameNumber uint64, @@ -251,6 +252,18 @@ func (p *PebbleCoinStore) GetPreCoinProofByAddress(address []byte) ( return proof, nil } +func (p *PebbleCoinStore) RangePreCoinProofs() (Iterator, error) { + iter, err := p.db.NewIter( + proofKey(bytes.Repeat([]byte{0x00}, 32)), + proofKey(bytes.Repeat([]byte{0xff}, 32)), + ) + if err != nil { + return nil, errors.Wrap(err, "range pre coin proofs") + } + + return iter, nil +} + func (p *PebbleCoinStore) PutCoin( txn Transaction, frameNumber uint64, diff --git a/node/tries/proof_leaf_test.go b/node/tries/proof_leaf_test.go index 378391b..70af86c 100644 --- a/node/tries/proof_leaf_test.go +++ b/node/tries/proof_leaf_test.go @@ -89,12 +89,13 @@ func TestPackAndVerifyOutput(t *testing.T) { require.NoError(t, err) } - tree, payload, output := tries.PackOutputIntoPayloadAndProof( + tree, payload, output, err := tries.PackOutputIntoPayloadAndProof( outputs, tc.modulo, frame, previousTree, ) + require.NoError(t, err) require.NotNil(t, tree) require.NotEmpty(t, payload) require.NotEmpty(t, output) diff --git a/node/tries/rolling_frecency_critbit_trie.go b/node/tries/rolling_frecency_critbit_trie.go index 20354e3..7049b26 100644 --- a/node/tries/rolling_frecency_critbit_trie.go +++ b/node/tries/rolling_frecency_critbit_trie.go @@ -134,7 +134,7 @@ func (t *RollingFrecencyCritbitTrie) FindNearestAndApproximateNeighbors( var traverse func(p *Node, address []byte) bool traverse = func(p *Node, address []byte) bool { - if len(ret) > 1024 { + if len(ret) > 2048 { return true }