Skip to content

Commit

Permalink
Participation Key Interface (#3164)
Browse files Browse the repository at this point in the history
## Summary

* new `ParticipationRegistry` interface designed to manage keys and collect usage metrics.
* new REST endpoints for interacting with keys.
* improved `goal account partkeyinfo` and `goal account listpartkeys` formatting.

## Test Plan

New unit and integration tests.
  • Loading branch information
winder authored Nov 15, 2021
1 parent 3937401 commit 387f6a6
Show file tree
Hide file tree
Showing 44 changed files with 4,939 additions and 437 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ GOLDFLAGS := $(GOLDFLAGS_BASE) \
UNIT_TEST_SOURCES := $(sort $(shell GOPATH=$(GOPATH) && GO111MODULE=off && go list ./... | grep -v /go-algorand/test/ ))
ALGOD_API_PACKAGES := $(sort $(shell GOPATH=$(GOPATH) && GO111MODULE=off && cd daemon/algod/api; go list ./... ))

MSGP_GENERATE := ./protocol ./protocol/test ./crypto ./crypto/compactcert ./data/basics ./data/transactions ./data/committee ./data/bookkeeping ./data/hashable ./agreement ./rpcs ./node ./ledger ./ledger/ledgercore ./compactcert
MSGP_GENERATE := ./protocol ./protocol/test ./crypto ./crypto/compactcert ./data/basics ./data/transactions ./data/committee ./data/bookkeeping ./data/hashable ./agreement ./rpcs ./node ./ledger ./ledger/ledgercore ./compactcert ./data/account

default: build

Expand Down
4 changes: 4 additions & 0 deletions agreement/abstractions.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ type KeyManager interface {
// valid for the provided votingRound, and were available at
// keysRound.
VotingKeys(votingRound, keysRound basics.Round) []account.Participation

// Record indicates that the given participation action has been taken.
// The operation needs to be asynchronous to avoid impacting agreement.
Record(account basics.Address, round basics.Round, participationType account.ParticipationAction)
}

// MessageHandle is an ID referring to a specific message.
Expand Down
9 changes: 5 additions & 4 deletions agreement/agreementtest/keyManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/algorand/go-algorand/data/basics"
)

// SimpleKeyManager provides a simple implementation of a KeyManager.
// SimpleKeyManager provides a simple implementation of a KeyManager for unit tests.
type SimpleKeyManager []account.Participation

// VotingKeys implements KeyManager.VotingKeys.
Expand All @@ -37,7 +37,8 @@ func (m SimpleKeyManager) VotingKeys(votingRound, _ basics.Round) []account.Part

// DeleteOldKeys implements KeyManager.DeleteOldKeys.
func (m SimpleKeyManager) DeleteOldKeys(r basics.Round) {
// for _, acc := range m {
// acc.DeleteOldKeys(r)
// }
}

// Record implements KeyManager.Record.
func (m SimpleKeyManager) Record(account basics.Address, round basics.Round, action account.ParticipationAction) {
}
2 changes: 1 addition & 1 deletion agreement/cryptoVerifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ func BenchmarkCryptoVerifierProposalVertification(b *testing.B) {
pn := &asyncPseudonode{
factory: testBlockFactory{Owner: 0},
validator: testBlockValidator{},
keys: simpleKeyManager(participations),
keys: makeRecordingKeyManager(participations),
ledger: ledger,
log: serviceLogger{logging.Base()},
}
Expand Down
3 changes: 2 additions & 1 deletion agreement/fuzzer/fuzzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/algorand/go-deadlock"

"github.com/algorand/go-algorand/agreement"
"github.com/algorand/go-algorand/agreement/agreementtest"
"github.com/algorand/go-algorand/agreement/gossip"
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
Expand Down Expand Up @@ -132,7 +133,7 @@ func (n *Fuzzer) initAgreementNode(nodeID int, filters ...NetworkFilterFactory)
Logger: logger,
Ledger: n.ledgers[nodeID],
Network: gossip.WrapNetwork(n.facades[nodeID], logger),
KeyManager: simpleKeyManager(n.accounts[nodeID : nodeID+1]),
KeyManager: agreementtest.SimpleKeyManager(n.accounts[nodeID : nodeID+1]),
BlockValidator: n.blockValidator,
BlockFactory: testBlockFactory{Owner: nodeID},
Clock: n.clocks[nodeID],
Expand Down
34 changes: 0 additions & 34 deletions agreement/fuzzer/keyManager_test.go

This file was deleted.

74 changes: 74 additions & 0 deletions agreement/keyManager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (C) 2019-2021 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// go-algorand is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.

package agreement

import (
"testing"

"github.com/algorand/go-deadlock"
"github.com/stretchr/testify/require"

"github.com/algorand/go-algorand/data/account"
"github.com/algorand/go-algorand/data/basics"
)

func makeRecordingKeyManager(accounts []account.Participation) *recordingKeyManager {
return &recordingKeyManager{
keys: accounts,
recording: make(map[basics.Address]map[account.ParticipationAction]basics.Round),
}
}

// recordingKeyManager provides a simple implementation of a KeyManager for unit tests.
type recordingKeyManager struct {
keys []account.Participation
recording map[basics.Address]map[account.ParticipationAction]basics.Round
mutex deadlock.Mutex
}

// VotingKeys implements KeyManager.VotingKeys.
func (m *recordingKeyManager) VotingKeys(votingRound, _ basics.Round) []account.Participation {
var km []account.Participation
for _, acc := range m.keys {
if acc.OverlapsInterval(votingRound, votingRound) {
km = append(km, acc)
}
}
return km
}

// DeleteOldKeys implements KeyManager.DeleteOldKeys.
func (m *recordingKeyManager) DeleteOldKeys(r basics.Round) {
}

// Record implements KeyManager.Record.
func (m *recordingKeyManager) Record(acct basics.Address, round basics.Round, action account.ParticipationAction) {
m.mutex.Lock()
defer m.mutex.Unlock()
if _, ok := m.recording[acct]; !ok {
m.recording[acct] = make(map[account.ParticipationAction]basics.Round)
}
m.recording[acct][action] = round
}

// ValidateVoteRound requires that the given address voted on a particular round.
func (m *recordingKeyManager) ValidateVoteRound(t *testing.T, address basics.Address, round basics.Round) {
m.mutex.Lock()
require.Equal(t, round, m.recording[address][account.Vote])
require.Equal(t, round, m.recording[address][account.BlockProposal])
m.mutex.Unlock()
}
2 changes: 2 additions & 0 deletions agreement/pseudonode.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ func (t pseudonodeVotesTask) execute(verifier *AsyncVoteVerifier, quit chan stru
for _, r := range verifiedResults {
select {
case t.out <- messageEvent{T: voteVerified, Input: r.message, Err: makeSerErr(r.err)}:
t.node.keys.Record(r.v.R.Sender, r.v.R.Round, account.Vote)
case <-quit:
return
case <-t.context.Done():
Expand Down Expand Up @@ -528,6 +529,7 @@ func (t pseudonodeProposalsTask) execute(verifier *AsyncVoteVerifier, quit chan
for _, r := range verifiedVotes {
select {
case t.out <- messageEvent{T: voteVerified, Input: r.message, Err: makeSerErr(r.err)}:
t.node.keys.Record(r.v.R.Sender, r.v.R.Round, account.BlockProposal)
case <-quit:
return
case <-t.context.Done():
Expand Down
9 changes: 7 additions & 2 deletions agreement/pseudonode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func TestPseudonode(t *testing.T) {
sLogger := serviceLogger{logging.NewLogger()}
sLogger.SetLevel(logging.Warn)

keyManager := simpleKeyManager(accounts)
keyManager := makeRecordingKeyManager(accounts)
pb := makePseudonode(pseudonodeParams{
factory: testBlockFactory{Owner: 0},
validator: testBlockValidator{},
Expand Down Expand Up @@ -222,6 +222,8 @@ func TestPseudonode(t *testing.T) {
}
messageEvent, typeOk := ev.(messageEvent)
assert.True(t, true, typeOk)
// Verify votes are recorded - everyone is voting and proposing blocks.
keyManager.ValidateVoteRound(t, messageEvent.Input.Vote.R.Sender, startRound)
events[messageEvent.t()] = append(events[messageEvent.t()], messageEvent)
}
assert.Subset(t, []int{5, 6, 7, 8, 9, 10}, []int{len(events[voteVerified])})
Expand Down Expand Up @@ -390,6 +392,9 @@ func (k *KeyManagerProxy) VotingKeys(votingRound, balanceRound basics.Round) []a
return k.target(votingRound, balanceRound)
}

func (k *KeyManagerProxy) Record(account basics.Address, round basics.Round, action account.ParticipationAction) {
}

func TestPseudonodeLoadingOfParticipationKeys(t *testing.T) {
partitiontest.PartitionTest(t)

Expand All @@ -403,7 +408,7 @@ func TestPseudonodeLoadingOfParticipationKeys(t *testing.T) {
sLogger := serviceLogger{logging.NewLogger()}
sLogger.SetLevel(logging.Warn)

keyManager := simpleKeyManager(accounts)
keyManager := makeRecordingKeyManager(accounts)
pb := makePseudonode(pseudonodeParams{
factory: testBlockFactory{Owner: 0},
validator: testBlockValidator{},
Expand Down
18 changes: 1 addition & 17 deletions agreement/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,6 @@ func (c *testingClock) fire(d time.Duration) {
close(c.TA[d])
}

type simpleKeyManager []account.Participation

func (m simpleKeyManager) VotingKeys(votingRound, _ basics.Round) []account.Participation {
var km []account.Participation
for _, acc := range m {
if acc.OverlapsInterval(votingRound, votingRound) {
km = append(km, acc)
}
}
return km
}

func (m simpleKeyManager) DeleteOldKeys(basics.Round) {
// noop
}

type testingNetwork struct {
validator BlockValidator

Expand Down Expand Up @@ -743,7 +727,7 @@ func setupAgreementWithValidator(t *testing.T, numNodes int, traceLevel traceLev
m.coserviceListener = am.coserviceListener(nodeID(i))
clocks[i] = makeTestingClock(m)
ledgers[i] = ledgerFactory(balances)
keys := simpleKeyManager(accounts[i : i+1])
keys := makeRecordingKeyManager(accounts[i : i+1])
endpoint := baseNetwork.testingNetworkEndpoint(nodeID(i))
ilog := log.WithFields(logging.Fields{"Source": "service-" + strconv.Itoa(i)})

Expand Down
Loading

0 comments on commit 387f6a6

Please sign in to comment.