Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions data/account/participationRegistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ type ParticipationRegistry interface {
// once, an error will occur when the data is flushed when inserting a duplicate key.
AppendKeys(id ParticipationID, keys StateProofKeys) error

// DeleteStateProofKeys removes all stateproof keys preceding a given round (including)
// DeleteStateProofKeys removes all stateproof keys preceding a given round (excluded)
Comment thread
id-ms marked this conversation as resolved.
Outdated
DeleteStateProofKeys(id ParticipationID, round basics.Round) error

// Delete removes a record from storage.
Expand Down Expand Up @@ -347,7 +347,7 @@ const (
insertKeysetQuery = `INSERT INTO Keysets (participationID, account, firstValidRound, lastValidRound, keyDilution, vrf, stateProof) VALUES (?, ?, ?, ?, ?, ?, ?)`
insertRollingQuery = `INSERT INTO Rolling (pk, voting) VALUES (?, ?)`
appendStateProofKeysQuery = `INSERT INTO StateProofKeys (pk, round, key) VALUES(?, ?, ?)`
deleteStateProofKeysQuery = `DELETE FROM StateProofKeys WHERE pk=? AND round<=?`
deleteStateProofKeysQuery = `DELETE FROM StateProofKeys WHERE pk=? AND round<?`

// SELECT pk FROM Keysets WHERE participationID = ?
selectPK = `SELECT pk FROM Keysets WHERE participationID = ? LIMIT 1`
Expand Down
3 changes: 2 additions & 1 deletion data/accountManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ type AccountManager struct {
log logging.Logger
}

// DeleteStateProofKey deletes all keys connected to ParticipationID that came before (including) the given round.
// DeleteStateProofKey deletes all keys connected to ParticipationID that came before the given round.
Comment thread
id-ms marked this conversation as resolved.
Outdated
// The round is excluded.
func (manager *AccountManager) DeleteStateProofKey(id account.ParticipationID, round basics.Round) error {
return manager.registry.DeleteStateProofKeys(id, round)
}
Expand Down
23 changes: 23 additions & 0 deletions stateproof/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ func (spw *Worker) builder(latest basics.Round) {
}

spw.deleteOldSigs(&hdr)
spw.deleteOldKeys(&hdr)
spw.deleteOldBuilders(&hdr)

// Broadcast signatures based on the previous block(s) that
Expand Down Expand Up @@ -461,6 +462,28 @@ func (spw *Worker) deleteOldSigs(currentHdr *bookkeeping.BlockHeader) {
}
}

func (spw *Worker) deleteOldKeys(currentHdr *bookkeeping.BlockHeader) {
proto := config.Consensus[currentHdr.CurrentProtocol]
stateProofNextRound := currentHdr.StateProofTracking[protocol.StateProofBasic].StateProofNextRound
if proto.StateProofInterval == 0 || stateProofNextRound == 0 {
return
}

oldestRoundToRemove := stateProofNextRound.SubSaturate(basics.Round(proto.StateProofInterval))
Comment thread
algonathan marked this conversation as resolved.
Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, for every round (?) we're going to be going over all of the participation records, extracting the state proof keys from them and removing stale keys? It might be worth it to hold the previous state proof next round to decide if we have to do that, even if we put aside the question of changing state proof intervals.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a point. I've addressed that. take a second look


keys := spw.accts.StateProofKeys(oldestRoundToRemove)
for _, key := range keys {
roundToRemove, err := key.StateProofSecrets.FirstRoundInKeyLifetime()
if err != nil {
spw.log.Warnf("deleteOldKeys: could not calculate keylifetime for account %v on round %s: %v", key.ParticipationID, roundToRemove, err)
Comment thread
id-ms marked this conversation as resolved.
Outdated
Comment thread
algonathan marked this conversation as resolved.
Outdated
}
err = spw.accts.DeleteStateProofKey(key.ParticipationID, basics.Round(roundToRemove))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to use roundToRemove? Why not latestRoundToKeep instead?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we delete roundToRemove we might delete a key that should be used for a later state proof.

if err != nil {
spw.log.Warnf("deleteOldKeys: could not remove key for account %v on round %s: %v", key.ParticipationID, roundToRemove, err)
}
}
}

func (spw *Worker) deleteOldBuilders(currentHdr *bookkeeping.BlockHeader) {
oldestRoundToRemove := GetOldestExpectedStateProof(currentHdr)

Expand Down
20 changes: 1 addition & 19 deletions stateproof/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto/merklesignature"
"github.com/algorand/go-algorand/data/account"
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/protocol"
Expand Down Expand Up @@ -117,8 +116,6 @@ func (spw *Worker) signStateProof(hdr bookkeeping.BlockHeader) {
}

sigs := make([]sigFromAddr, 0, len(keys))
ids := make([]account.ParticipationID, 0, len(keys))
usedSigners := make([]*merklesignature.Signer, 0, len(keys))

stateproofMessage, err := GenerateStateProofMessage(spw.ledger, uint64(votersHdr.Round), hdr)
if err != nil {
Expand Down Expand Up @@ -155,30 +152,15 @@ func (spw *Worker) signStateProof(hdr bookkeeping.BlockHeader) {
Round: hdr.Round,
Sig: sig,
})
ids = append(ids, key.ParticipationID)
usedSigners = append(usedSigners, key.StateProofSecrets)
}

// any error in handle sig indicates the signature wasn't stored in disk, thus we cannot delete the key.
for i, sfa := range sigs {
for _, sfa := range sigs {
if _, err := spw.handleSig(sfa, nil); err != nil {
spw.log.Warnf("spw.signBlock(%d): handleSig: %v", hdr.Round, err)
continue
}

spw.log.Infof("spw.signBlock(%d): sp message was signed with address %v", hdr.Round, sfa.SignerAddress)
firstRoundInKeyLifetime, err := usedSigners[i].FirstRoundInKeyLifetime() // Calculate first round of the key in order to delete all previous keys (and keep the current one for now)
if err != nil {
spw.log.Warnf("spw.signBlock(%d): Signer.FirstRoundInKeyLifetime: %v", hdr.Round, err)
continue
}
if firstRoundInKeyLifetime == 0 {
continue // No previous keys to delete (also underflows when subtracting 1)
}

// Safe to delete key for sfa.Round because the signature is now stored in the disk.
if err := spw.accts.DeleteStateProofKey(ids[i], basics.Round(firstRoundInKeyLifetime-1)); err != nil { // Subtract 1 to delete all keys up to this one
spw.log.Warnf("spw.signBlock(%d): DeleteStateProofKey: %v", hdr.Round, err)
}
}
}
Loading