Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 3 additions & 2 deletions crypto/merklesignature/persistentMerkleSignatureScheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ var (
errKeyDecodeError = errors.New("failed to decode stateproof key")
)

func merkleSignatureInstallDatabase(tx *sql.Tx) error {
// InstallStateProofTable creates (or migrates if exists already) the StateProofKeys database table
func InstallStateProofTable(tx *sql.Tx) error {
var schemaVersion sql.NullInt32
err := tx.QueryRow("SELECT version FROM schema where tablename = ?", merkleSignatureTableSchemaName).Scan(&schemaVersion)
switch err {
Expand Down Expand Up @@ -99,7 +100,7 @@ func (s *Secrets) Persist(store db.Accessor) error {
round := indexToRound(s.FirstValid, s.Interval, 0)
encodedKey := protocol.GetEncodingBuf()
err := store.Atomic(func(ctx context.Context, tx *sql.Tx) error {
err := merkleSignatureInstallDatabase(tx) // assumes schema table already exists (created by partInstallDatabase)
err := InstallStateProofTable(tx) // assumes schema table already exists (created by partInstallDatabase)
if err != nil {
return err
}
Expand Down
20 changes: 19 additions & 1 deletion crypto/merklesignature/persistentMerkleSignatureScheme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@ func TestSecretsDatabaseUpgrade(t *testing.T) {
a.NoError(err)

err = store.Atomic(func(ctx context.Context, tx *sql.Tx) error {
err := merkleSignatureInstallDatabase(tx) // assumes schema table already exists (created by partInstallDatabase)
err := InstallStateProofTable(tx) // assumes schema table already exists (created by partInstallDatabase)
if err != nil {
return err
}
return nil
})

a.NoError(err)
version, err := getStateProofTableSchemaVersions(*store)
a.NoError(err)
a.Equal(merkleSignatureSchemaVersion, version)
}

func TestFetchRestoreAllSecrets(t *testing.T) {
Expand Down Expand Up @@ -114,3 +117,18 @@ func createTestDB(a *require.Assertions) *db.Accessor {

return &store
}

func getStateProofTableSchemaVersions(db db.Accessor) (int, error) {
var version int
err := db.Atomic(func(ctx context.Context, tx *sql.Tx) (err error) {
row := tx.QueryRow("SELECT version FROM schema where tablename = ?", merkleSignatureTableSchemaName)
return row.Scan(&version)
})
if err == sql.ErrNoRows {
return 0, nil
}
if err != nil {
return 0, err
}
return version, nil
}
6 changes: 5 additions & 1 deletion data/account/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,16 @@ func RestoreParticipation(store db.Accessor) (acc PersistedParticipation, err er

// RestoreParticipationWithSecrets restores a Participation from a database
// handle. In addition, this function also restores all stateproof secrets
func RestoreParticipationWithSecrets(store db.Accessor) (acc PersistedParticipation, err error) {
func RestoreParticipationWithSecrets(store db.Accessor) (PersistedParticipation, error) {
persistedParticipation, err := RestoreParticipation(store)
if err != nil {
return PersistedParticipation{}, err
}

if persistedParticipation.StateProofSecrets == nil { // no state proof keys to restore
return persistedParticipation, nil
}

err = persistedParticipation.StateProofSecrets.RestoreAllSecrets(store)
if err != nil {
return PersistedParticipation{}, err
Expand Down
9 changes: 7 additions & 2 deletions data/account/participation.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type Participation struct {

VRF *crypto.VRFSecrets
Voting *crypto.OneTimeSignatureSecrets
// StateProofSecrets is used to sign compact certificates. might be nil
// StateProofSecrets is used to sign compact certificates.
StateProofSecrets *merklesignature.Secrets

// The first and last rounds for which this account is valid, respectively.
Expand Down Expand Up @@ -303,7 +303,12 @@ func (part PersistedParticipation) Persist() error {
// Calls through to the migration helper and returns the result.
func Migrate(partDB db.Accessor) error {
return partDB.Atomic(func(ctx context.Context, tx *sql.Tx) error {
return partMigrate(tx)
err := partMigrate(tx)
if err != nil {
return err
}

return merklesignature.InstallStateProofTable(tx)
})
}

Expand Down
28 changes: 27 additions & 1 deletion data/account/participation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,15 @@ func TestRetrieveFromDBAtVersion1(t *testing.T) {
retrivedPart, err := RestoreParticipation(partDB)
a.NoError(err)
assertionForRestoringFromDBAtLowVersion(a, retrivedPart)
assertStateProofTablesExists(a, partDB)

retrivedPart, err = RestoreParticipationWithSecrets(partDB)
a.NoError(err)
assertionForRestoringFromDBAtLowVersion(a, retrivedPart)
assertStateProofTablesExists(a, partDB)
}

func TestRetriveFromDBAtVersion2(t *testing.T) {
func TestRetrieveFromDBAtVersion2(t *testing.T) {
partitiontest.PartitionTest(t)

a := require.New(t)
Expand All @@ -222,6 +228,18 @@ func TestRetriveFromDBAtVersion2(t *testing.T) {
retrivedPart, err := RestoreParticipation(partDB)
a.NoError(err)
assertionForRestoringFromDBAtLowVersion(a, retrivedPart)
assertStateProofTablesExists(a, partDB)
versions, err := getSchemaVersions(partDB)
a.NoError(err)
a.Equal(versions[PartTableSchemaName], PartTableSchemaVersion)

retrivedPart, err = RestoreParticipationWithSecrets(partDB)
a.NoError(err)
assertionForRestoringFromDBAtLowVersion(a, retrivedPart)
assertStateProofTablesExists(a, partDB)
versions, err = getSchemaVersions(partDB)
a.NoError(err)
a.Equal(versions[PartTableSchemaName], PartTableSchemaVersion)
}

func TestKeyRegCreation(t *testing.T) {
Expand All @@ -244,6 +262,14 @@ func closeDBS(dbAccessor ...db.Accessor) {
}
}

func assertStateProofTablesExists(a *require.Assertions, store db.Accessor) {
err := store.Atomic(func(ctx context.Context, tx *sql.Tx) error {
_, err := tx.Exec("select count(*) From StateProofKeys;")
return err
})
a.NoError(err)

}
func assertionForRestoringFromDBAtLowVersion(a *require.Assertions, retrivedPart PersistedParticipation) {
a.NotNil(retrivedPart)
a.Nil(retrivedPart.StateProofSecrets)
Expand Down
4 changes: 4 additions & 0 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,10 @@ func (node *AlgorandFullNode) loadParticipationKeys() error {

func insertStateProofToRegistry(part account.PersistedParticipation, node *AlgorandFullNode) error {
partID := part.ID()
// in case there are no state proof keys for that participant
if part.StateProofSecrets == nil {
return nil
}
keys := part.StateProofSecrets.GetAllKeys()
keysSinger := make(account.StateProofKeys, len(keys))
for i := uint64(0); i < uint64(len(keys)); i++ {
Expand Down
4 changes: 1 addition & 3 deletions test/e2e-go/upgrades/stateproof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,9 @@ func TestKeysWithoutStateProofKeyCanRegister(t *testing.T) {
defer fixtures.ShutdownSynchronizedTest(t)

a := require.New(fixtures.SynchronizedTest(t))
consensus := getStateProofConsensus()

var fixture fixtures.RestClientFixture
fixture.SetConsensus(consensus)
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodesWithoutStateProofPartkeys.json"))
fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50EachV30.json"))
defer fixture.Shutdown()
lastValid := uint64(1000 * 5)

Expand Down