summaryrefslogtreecommitdiff
path: root/ledger/voters.go
diff options
context:
space:
mode:
Diffstat (limited to 'ledger/voters.go')
-rw-r--r--ledger/voters.go161
1 files changed, 15 insertions, 146 deletions
diff --git a/ledger/voters.go b/ledger/voters.go
index 7f1749175..898604072 100644
--- a/ledger/voters.go
+++ b/ledger/voters.go
@@ -20,14 +20,10 @@ import (
"fmt"
"sync"
- "github.com/algorand/go-deadlock"
-
"github.com/algorand/go-algorand/config"
- "github.com/algorand/go-algorand/crypto"
- "github.com/algorand/go-algorand/crypto/compactcert"
- "github.com/algorand/go-algorand/crypto/merklearray"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
+ "github.com/algorand/go-algorand/ledger/ledgercore"
"github.com/algorand/go-algorand/protocol"
)
@@ -63,7 +59,7 @@ type votersTracker struct {
// the Merkle commitment to online accounts from the previous such block.
// Thus, we maintain X in the round map until we form a compact certificate
// for round X+CompactCertVotersLookback+CompactCertRounds.
- round map[basics.Round]*VotersForRound
+ round map[basics.Round]*ledgercore.VotersForRound
l ledgerForTracker
au *accountUpdates
@@ -73,44 +69,6 @@ type votersTracker struct {
loadWaitGroup sync.WaitGroup
}
-// VotersForRound tracks the top online voting accounts as of a particular
-// round, along with a Merkle tree commitment to those voting accounts.
-type VotersForRound struct {
- // Because it can take some time to compute the top participants and the
- // corresponding Merkle tree, the votersForRound is constructed in
- // the background. This means that fields (participants, adddToPos,
- // tree, and totalWeight) could be nil/zero while a background thread
- // is computing them. Once the fields are set, however, they are
- // immutable, and it is no longer necessary to acquire the lock.
- //
- // If an error occurs while computing the tree in the background,
- // loadTreeError might be set to non-nil instead. That also finalizes
- // the state of this VotersForRound.
- mu deadlock.Mutex
- cond *sync.Cond
- loadTreeError error
-
- // Proto is the ConsensusParams for the round whose balances are reflected
- // in participants.
- Proto config.ConsensusParams
-
- // Participants is the array of top #CompactCertVoters online accounts
- // in this round, sorted by normalized balance (to make sure heavyweight
- // accounts are biased to the front).
- Participants participantsArray
-
- // AddrToPos specifies the position of a given account address (if present)
- // in the Participants array. This allows adding a vote from a given account
- // to the certificate builder.
- AddrToPos map[basics.Address]uint64
-
- // Tree is a constructed Merkle tree of the Participants array.
- Tree *merklearray.Tree
-
- // TotalWeight is the sum of the weights from the Participants array.
- TotalWeight basics.MicroAlgos
-}
-
// votersRoundForCertRound computes the round number whose voting participants
// will be used to sign the compact cert for certRnd.
func votersRoundForCertRound(certRnd basics.Round, proto config.ConsensusParams) basics.Round {
@@ -124,7 +82,7 @@ func votersRoundForCertRound(certRnd basics.Round, proto config.ConsensusParams)
func (vt *votersTracker) loadFromDisk(l ledgerForTracker, au *accountUpdates) error {
vt.l = l
vt.au = au
- vt.round = make(map[basics.Round]*VotersForRound)
+ vt.round = make(map[basics.Round]*ledgercore.VotersForRound)
latest := l.Latest()
hdr, err := l.BlockHdr(latest)
@@ -173,23 +131,20 @@ func (vt *votersTracker) loadTree(hdr bookkeeping.BlockHeader) {
return
}
- tr := &VotersForRound{
- Proto: proto,
- }
- tr.cond = sync.NewCond(&tr.mu)
+ tr := ledgercore.MakeVotersForRound()
+ tr.Proto = proto
+
vt.round[r] = tr
vt.loadWaitGroup.Add(1)
go func() {
defer vt.loadWaitGroup.Done()
- err := tr.loadTree(vt.l, vt.au, hdr)
+ onlineAccounts := ledgercore.TopOnlineAccounts(vt.au.onlineTop)
+ err := tr.LoadTree(onlineAccounts, hdr)
if err != nil {
- vt.au.log.Warnf("votersTracker.loadTree(%d): %v", hdr.Round, err)
+ vt.l.trackerLog().Warnf("votersTracker.loadTree(%d): %v", hdr.Round, err)
- tr.mu.Lock()
- tr.loadTreeError = err
- tr.cond.Broadcast()
- tr.mu.Unlock()
+ tr.BroadcastError(err)
}
}()
return
@@ -201,70 +156,6 @@ func (vt *votersTracker) close() {
vt.loadWaitGroup.Wait()
}
-func (tr *VotersForRound) loadTree(l ledgerForTracker, au *accountUpdates, hdr bookkeeping.BlockHeader) error {
- r := hdr.Round
-
- // certRound is the block that we expect to form a compact certificate for,
- // using the balances from round r.
- certRound := r + basics.Round(tr.Proto.CompactCertVotersLookback+tr.Proto.CompactCertRounds)
-
- // sigKeyRound is the ephemeral key ID that we expect to be used for signing
- // the block from certRound. It is one higher because the keys for certRound
- // might be deleted by the time consensus is reached on the block and we try
- // to sign the compact cert for block certRound.
- sigKeyRound := certRound + 1
-
- top, err := au.onlineTop(r, sigKeyRound, tr.Proto.CompactCertTopVoters)
- if err != nil {
- return err
- }
-
- participants := make(participantsArray, len(top))
- addrToPos := make(map[basics.Address]uint64)
- var totalWeight basics.MicroAlgos
-
- for i, acct := range top {
- var ot basics.OverflowTracker
- rewards := basics.PendingRewards(&ot, tr.Proto, acct.MicroAlgos, acct.RewardsBase, hdr.RewardsLevel)
- money := ot.AddA(acct.MicroAlgos, rewards)
- if ot.Overflowed {
- return fmt.Errorf("votersTracker.loadTree: overflow adding rewards %d + %d", acct.MicroAlgos, rewards)
- }
-
- totalWeight = ot.AddA(totalWeight, money)
- if ot.Overflowed {
- return fmt.Errorf("votersTracker.loadTree: overflow computing totalWeight %d + %d", totalWeight.ToUint64(), money.ToUint64())
- }
-
- keyDilution := acct.VoteKeyDilution
- if keyDilution == 0 {
- keyDilution = tr.Proto.DefaultKeyDilution
- }
-
- participants[i] = compactcert.Participant{
- PK: acct.VoteID,
- Weight: money.ToUint64(),
- KeyDilution: keyDilution,
- }
- addrToPos[acct.Address] = uint64(i)
- }
-
- tree, err := merklearray.Build(participants)
- if err != nil {
- return err
- }
-
- tr.mu.Lock()
- tr.AddrToPos = addrToPos
- tr.Participants = participants
- tr.TotalWeight = totalWeight
- tr.Tree = tree
- tr.cond.Broadcast()
- tr.mu.Unlock()
-
- return nil
-}
-
func (vt *votersTracker) newBlock(hdr bookkeeping.BlockHeader) {
proto := config.Consensus[hdr.CurrentProtocol]
if proto.CompactCertRounds == 0 {
@@ -288,7 +179,7 @@ func (vt *votersTracker) newBlock(hdr bookkeeping.BlockHeader) {
if (r+proto.CompactCertVotersLookback)%proto.CompactCertRounds == 0 {
_, ok := vt.round[basics.Round(r)]
if ok {
- vt.au.log.Errorf("votersTracker.newBlock: round %d already present", r)
+ vt.l.trackerLog().Errorf("votersTracker.newBlock: round %d already present", r)
} else {
vt.loadTree(hdr)
}
@@ -311,7 +202,7 @@ func (vt *votersTracker) lowestRound(base basics.Round) basics.Round {
}
// getVoters() returns the top online participants from round r.
-func (vt *votersTracker) getVoters(r basics.Round) (*VotersForRound, error) {
+func (vt *votersTracker) getVoters(r basics.Round) (*ledgercore.VotersForRound, error) {
tr, ok := vt.round[r]
if !ok {
// Not tracked: compact certs not enabled.
@@ -319,32 +210,10 @@ func (vt *votersTracker) getVoters(r basics.Round) (*VotersForRound, error) {
}
// Wait for the Merkle tree to be constructed.
- tr.mu.Lock()
- defer tr.mu.Unlock()
- for tr.Tree == nil {
- if tr.loadTreeError != nil {
- return nil, tr.loadTreeError
- }
-
- tr.cond.Wait()
+ err := tr.Wait()
+ if err != nil {
+ return nil, err
}
return tr, nil
}
-
-//msgp:ignore participantsArray
-// participantsArray implements merklearray.Array and is used to commit
-// to a Merkle tree of online accounts.
-type participantsArray []compactcert.Participant
-
-func (a participantsArray) Length() uint64 {
- return uint64(len(a))
-}
-
-func (a participantsArray) GetHash(pos uint64) (crypto.Digest, error) {
- if pos >= uint64(len(a)) {
- return crypto.Digest{}, fmt.Errorf("participantsArray.Get(%d) out of bounds %d", pos, len(a))
- }
-
- return crypto.HashObj(a[pos]), nil
-}