Fix VC DB conversion when no proposer settings is defined and add Experimental flag in the --enable-minimal-slashing-protection help. (#13691)

* VC: Allow DB conversion without proposer settings.

* `enable-minimal-slashing-protection` flag: Add `Experimental warning`.
This commit is contained in:
Manu NALEPA 2024-03-06 15:48:18 +01:00 committed by GitHub
parent ee9274a9bc
commit 21775eed52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 196 additions and 184 deletions

View File

@ -97,7 +97,7 @@ var (
} }
EnableMinimalSlashingProtection = &cli.BoolFlag{ EnableMinimalSlashingProtection = &cli.BoolFlag{
Name: "enable-minimal-slashing-protection", Name: "enable-minimal-slashing-protection",
Usage: "Enables the minimal slashing protection. See EIP-3076 for more details.", Usage: "(Experimental): Enables the minimal slashing protection. See EIP-3076 for more details.",
} }
enableDoppelGangerProtection = &cli.BoolFlag{ enableDoppelGangerProtection = &cli.BoolFlag{
Name: "enable-doppelganger", Name: "enable-doppelganger",

View File

@ -124,13 +124,18 @@ func ConvertDatabase(ctx context.Context, sourceDataDir string, targetDataDir st
// ----------------- // -----------------
// Get the proposer settings. // Get the proposer settings.
proposerSettings, err := sourceDatabase.ProposerSettings(ctx) proposerSettings, err := sourceDatabase.ProposerSettings(ctx)
if err != nil {
return errors.Wrap(err, "could not get proposer settings from source database")
}
// Save the proposer settings. switch err {
if err := targetDatabase.SaveProposerSettings(ctx, proposerSettings); err != nil { case nil:
return errors.Wrap(err, "could not save proposer settings") // Save the proposer settings.
if err := targetDatabase.SaveProposerSettings(ctx, proposerSettings); err != nil {
return errors.Wrap(err, "could not save proposer settings")
}
case kv.ErrNoProposerSettingsFound, filesystem.ErrNoProposerSettingsFound:
// Nothing to do.
default:
return errors.Wrap(err, "could not get proposer settings from source database")
} }
// Attestations // Attestations

View File

@ -49,217 +49,224 @@ func TestDB_ConvertDatabase(t *testing.T) {
defaultFeeRecipient := getFeeRecipientFromString(t, defaultFeeRecipientString) defaultFeeRecipient := getFeeRecipientFromString(t, defaultFeeRecipientString)
customFeeRecipient := getFeeRecipientFromString(t, customFeeRecipientString) customFeeRecipient := getFeeRecipientFromString(t, customFeeRecipientString)
for _, minimalToComplete := range []bool{false, true} { for _, minimalToComplete := range [...]bool{false, true} {
t.Run(fmt.Sprintf("minimalToComplete=%v", minimalToComplete), func(t *testing.T) { for _, withProposerSettings := range [...]bool{false, true} {
// Create signing root t.Run(fmt.Sprintf("minimalToComplete=%v", minimalToComplete), func(t *testing.T) {
signingRoot := [fieldparams.RootLength]byte{} // Create signing root
var signingRootBytes []byte signingRoot := [fieldparams.RootLength]byte{}
if minimalToComplete { var signingRootBytes []byte
signingRootBytes = signingRoot[:] if minimalToComplete {
} signingRootBytes = signingRoot[:]
}
// Create database directoriy path. // Create database directoriy path.
datadir := t.TempDir() datadir := t.TempDir()
// Run source DB preparation. // Run source DB preparation.
// -------------------------- // --------------------------
// Create the source database. // Create the source database.
var ( var (
sourceDatabase, targetDatabase iface.ValidatorDB sourceDatabase, targetDatabase iface.ValidatorDB
err error err error
) )
if minimalToComplete { if minimalToComplete {
sourceDatabase, err = filesystem.NewStore(datadir, &filesystem.Config{ sourceDatabase, err = filesystem.NewStore(datadir, &filesystem.Config{
PubKeys: [][fieldparams.BLSPubkeyLength]byte{pubkey1, pubkey2}, PubKeys: [][fieldparams.BLSPubkeyLength]byte{pubkey1, pubkey2},
}) })
} else { } else {
sourceDatabase, err = kv.NewKVStore(ctx, datadir, &kv.Config{ sourceDatabase, err = kv.NewKVStore(ctx, datadir, &kv.Config{
PubKeys: [][fieldparams.BLSPubkeyLength]byte{pubkey1, pubkey2}, PubKeys: [][fieldparams.BLSPubkeyLength]byte{pubkey1, pubkey2},
}) })
} }
require.NoError(t, err, "could not create source database") require.NoError(t, err, "could not create source database")
// Save the genesis validator root. // Save the genesis validator root.
expectedGenesisValidatorRoot := []byte("genesis-validator-root") expectedGenesisValidatorRoot := []byte("genesis-validator-root")
err = sourceDatabase.SaveGenesisValidatorsRoot(ctx, expectedGenesisValidatorRoot) err = sourceDatabase.SaveGenesisValidatorsRoot(ctx, expectedGenesisValidatorRoot)
require.NoError(t, err, "could not save genesis validator root") require.NoError(t, err, "could not save genesis validator root")
// Save the graffiti file hash. // Save the graffiti file hash.
// (Getting the graffiti ordered index will set the graffiti file hash) // (Getting the graffiti ordered index will set the graffiti file hash)
expectedGraffitiFileHash := [32]byte{1} expectedGraffitiFileHash := [32]byte{1}
_, err = sourceDatabase.GraffitiOrderedIndex(ctx, expectedGraffitiFileHash) _, err = sourceDatabase.GraffitiOrderedIndex(ctx, expectedGraffitiFileHash)
require.NoError(t, err, "could not get graffiti ordered index") require.NoError(t, err, "could not get graffiti ordered index")
// Save the graffiti ordered index. // Save the graffiti ordered index.
expectedGraffitiOrderedIndex := uint64(1) expectedGraffitiOrderedIndex := uint64(1)
err = sourceDatabase.SaveGraffitiOrderedIndex(ctx, expectedGraffitiOrderedIndex) err = sourceDatabase.SaveGraffitiOrderedIndex(ctx, expectedGraffitiOrderedIndex)
require.NoError(t, err, "could not save graffiti ordered index") require.NoError(t, err, "could not save graffiti ordered index")
// Save the proposer settings. // Save the proposer settings.
var relays []string = nil var relays []string = nil
expectedProposerSettings := &proposer.Settings{}
expectedProposerSettings := &proposer.Settings{ if withProposerSettings {
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{ expectedProposerSettings = &proposer.Settings{
pubkey1: { ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{ pubkey1: {
FeeRecipient: customFeeRecipient, FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: customFeeRecipient,
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 42,
Relays: relays,
},
},
}, },
BuilderConfig: &proposer.BuilderConfig{ DefaultConfig: &proposer.Option{
Enabled: true, FeeRecipientConfig: &proposer.FeeRecipientConfig{
GasLimit: 42, FeeRecipient: defaultFeeRecipient,
Relays: relays, },
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: 43,
Relays: relays,
},
},
}
err = sourceDatabase.SaveProposerSettings(ctx, expectedProposerSettings)
require.NoError(t, err, "could not save proposer settings")
}
// Save some attestations.
completeAttestations := []*ethpb.IndexedAttestation{
{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{
Epoch: 1,
},
Target: &ethpb.Checkpoint{
Epoch: 2,
},
}, },
}, },
}, {
DefaultConfig: &proposer.Option{ Data: &ethpb.AttestationData{
FeeRecipientConfig: &proposer.FeeRecipientConfig{ Source: &ethpb.Checkpoint{
FeeRecipient: defaultFeeRecipient, Epoch: 2,
}, },
BuilderConfig: &proposer.BuilderConfig{ Target: &ethpb.Checkpoint{
Enabled: false, Epoch: 3,
GasLimit: 43, },
Relays: relays,
},
},
}
err = sourceDatabase.SaveProposerSettings(ctx, expectedProposerSettings)
require.NoError(t, err, "could not save proposer settings")
// Save some attestations.
completeAttestations := []*ethpb.IndexedAttestation{
{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{
Epoch: 1,
},
Target: &ethpb.Checkpoint{
Epoch: 2,
}, },
}, },
}, }
{
Data: &ethpb.AttestationData{ expectedAttestationRecords1 := []*common.AttestationRecord{
Source: &ethpb.Checkpoint{ {
Epoch: 2, PubKey: pubkey1,
}, Source: primitives.Epoch(2),
Target: &ethpb.Checkpoint{ Target: primitives.Epoch(3),
Epoch: 3, SigningRoot: signingRootBytes,
},
}, },
}, }
}
expectedAttestationRecords1 := []*common.AttestationRecord{ expectedAttestationRecords2 := []*common.AttestationRecord{
{ {
PubKey: pubkey1, PubKey: pubkey2,
Source: primitives.Epoch(2), Source: primitives.Epoch(2),
Target: primitives.Epoch(3), Target: primitives.Epoch(3),
SigningRoot: signingRootBytes, SigningRoot: signingRootBytes,
}, },
} }
expectedAttestationRecords2 := []*common.AttestationRecord{ err = sourceDatabase.SaveAttestationsForPubKey(ctx, pubkey1, [][]byte{{1}, {2}}, completeAttestations)
{ require.NoError(t, err, "could not save attestations")
PubKey: pubkey2,
Source: primitives.Epoch(2),
Target: primitives.Epoch(3),
SigningRoot: signingRootBytes,
},
}
err = sourceDatabase.SaveAttestationsForPubKey(ctx, pubkey1, [][]byte{{1}, {2}}, completeAttestations) err = sourceDatabase.SaveAttestationsForPubKey(ctx, pubkey2, [][]byte{{1}, {2}}, completeAttestations)
require.NoError(t, err, "could not save attestations") require.NoError(t, err, "could not save attestations")
err = sourceDatabase.SaveAttestationsForPubKey(ctx, pubkey2, [][]byte{{1}, {2}}, completeAttestations) // Save some block proposals.
require.NoError(t, err, "could not save attestations") err = sourceDatabase.SaveProposalHistoryForSlot(ctx, pubkey1, 42, []byte{})
require.NoError(t, err, "could not save block proposal")
// Save some block proposals. err = sourceDatabase.SaveProposalHistoryForSlot(ctx, pubkey1, 43, []byte{})
err = sourceDatabase.SaveProposalHistoryForSlot(ctx, pubkey1, 42, []byte{}) require.NoError(t, err, "could not save block proposal")
require.NoError(t, err, "could not save block proposal")
err = sourceDatabase.SaveProposalHistoryForSlot(ctx, pubkey1, 43, []byte{}) expectedProposals := []*common.Proposal{
require.NoError(t, err, "could not save block proposal") {
Slot: 43,
SigningRoot: signingRootBytes,
},
}
expectedProposals := []*common.Proposal{ // Close the source database.
{ err = sourceDatabase.Close()
Slot: 43, require.NoError(t, err, "could not close source database")
SigningRoot: signingRootBytes,
},
}
// Close the source database. // Source to target DB conversion.
err = sourceDatabase.Close() // -------------------------------
require.NoError(t, err, "could not close source database") err = ConvertDatabase(ctx, datadir, datadir, minimalToComplete)
require.NoError(t, err, "could not convert source to target database")
// Source to target DB conversion. // Check the target database.
// ---------------------------------------- // --------------------------
err = ConvertDatabase(ctx, datadir, datadir, minimalToComplete) if minimalToComplete {
require.NoError(t, err, "could not convert source to target database") targetDatabase, err = kv.NewKVStore(ctx, datadir, nil)
} else {
targetDatabase, err = filesystem.NewStore(datadir, nil)
}
require.NoError(t, err, "could not get minimal database")
// Check the target database. // Check the genesis validator root.
// -------------------------- actualGenesisValidatoRoot, err := targetDatabase.GenesisValidatorsRoot(ctx)
if minimalToComplete { require.NoError(t, err, "could not get genesis validator root from target database")
targetDatabase, err = kv.NewKVStore(ctx, datadir, nil) require.DeepSSZEqual(t, expectedGenesisValidatorRoot, actualGenesisValidatoRoot, "genesis validator root should match")
} else {
targetDatabase, err = filesystem.NewStore(datadir, nil)
}
require.NoError(t, err, "could not get minimal database")
// Check the genesis validator root. // Check the graffiti file hash.
actualGenesisValidatoRoot, err := targetDatabase.GenesisValidatorsRoot(ctx) actualGraffitiFileHash, exists, err := targetDatabase.GraffitiFileHash()
require.NoError(t, err, "could not get genesis validator root from target database") require.NoError(t, err, "could not get graffiti file hash from target database")
require.DeepSSZEqual(t, expectedGenesisValidatorRoot, actualGenesisValidatoRoot, "genesis validator root should match") require.Equal(t, true, exists, "graffiti file hash should exist")
require.Equal(t, expectedGraffitiFileHash, actualGraffitiFileHash, "graffiti file hash should match")
// Check the graffiti file hash. // Check the graffiti ordered index.
actualGraffitiFileHash, exists, err := targetDatabase.GraffitiFileHash() actualGraffitiOrderedIndex, err := targetDatabase.GraffitiOrderedIndex(ctx, expectedGraffitiFileHash)
require.NoError(t, err, "could not get graffiti file hash from target database") require.NoError(t, err, "could not get graffiti ordered index from target database")
require.Equal(t, true, exists, "graffiti file hash should exist") require.Equal(t, expectedGraffitiOrderedIndex, actualGraffitiOrderedIndex, "graffiti ordered index should match")
require.Equal(t, expectedGraffitiFileHash, actualGraffitiFileHash, "graffiti file hash should match")
// Check the graffiti ordered index. if withProposerSettings {
actualGraffitiOrderedIndex, err := targetDatabase.GraffitiOrderedIndex(ctx, expectedGraffitiFileHash) // Check the proposer settings.
require.NoError(t, err, "could not get graffiti ordered index from target database") actualProposerSettings, err := targetDatabase.ProposerSettings(ctx)
require.Equal(t, expectedGraffitiOrderedIndex, actualGraffitiOrderedIndex, "graffiti ordered index should match") require.NoError(t, err, "could not get proposer settings from target database")
require.DeepEqual(t, expectedProposerSettings, actualProposerSettings, "proposer settings should match")
}
// Check the proposer settings. // Check the attestations.
actualProposerSettings, err := targetDatabase.ProposerSettings(ctx) actualAttestationRecords, err := targetDatabase.AttestationHistoryForPubKey(ctx, pubkey1)
require.NoError(t, err, "could not get proposer settings from target database") require.NoError(t, err, "could not get attestations from target database")
require.DeepEqual(t, expectedProposerSettings, actualProposerSettings, "proposer settings should match") require.DeepEqual(t, expectedAttestationRecords1, actualAttestationRecords, "attestations should match")
// Check the attestations. actualAttestationRecords, err = targetDatabase.AttestationHistoryForPubKey(ctx, pubkey2)
actualAttestationRecords, err := targetDatabase.AttestationHistoryForPubKey(ctx, pubkey1) require.NoError(t, err, "could not get attestations from target database")
require.NoError(t, err, "could not get attestations from target database") require.DeepEqual(t, expectedAttestationRecords2, actualAttestationRecords, "attestations should match")
require.DeepEqual(t, expectedAttestationRecords1, actualAttestationRecords, "attestations should match")
actualAttestationRecords, err = targetDatabase.AttestationHistoryForPubKey(ctx, pubkey2) // Check the block proposals.
require.NoError(t, err, "could not get attestations from target database") actualProposals, err := targetDatabase.ProposalHistoryForPubKey(ctx, pubkey1)
require.DeepEqual(t, expectedAttestationRecords2, actualAttestationRecords, "attestations should match") require.NoError(t, err, "could not get block proposals from target database")
require.DeepEqual(t, expectedProposals, actualProposals, "block proposals should match")
// Check the block proposals. // Close the target database.
actualProposals, err := targetDatabase.ProposalHistoryForPubKey(ctx, pubkey1) err = targetDatabase.Close()
require.NoError(t, err, "could not get block proposals from target database") require.NoError(t, err, "could not close target database")
require.DeepEqual(t, expectedProposals, actualProposals, "block proposals should match")
// Close the target database. // Check the source database does not exist anymore.
err = targetDatabase.Close() var existing bool
require.NoError(t, err, "could not close target database")
// Check the source database does not exist anymore. if minimalToComplete {
var existing bool databasePath := filepath.Join(datadir, filesystem.DatabaseDirName)
existing, err = file.Exists(databasePath, file.Directory)
} else {
databasePath := filepath.Join(datadir, kv.ProtectionDbFileName)
existing, err = file.Exists(databasePath, file.Regular)
}
if minimalToComplete { require.NoError(t, err, "could not check if source database exists")
databasePath := filepath.Join(datadir, filesystem.DatabaseDirName) require.Equal(t, false, existing, "source database should not exist")
existing, err = file.Exists(databasePath, file.Directory) })
} else { }
databasePath := filepath.Join(datadir, kv.ProtectionDbFileName)
existing, err = file.Exists(databasePath, file.Regular)
}
require.NoError(t, err, "could not check if source database exists")
require.Equal(t, false, existing, "source database should not exist")
})
} }
} }