Skip to content

Commit

Permalink
Fix TestSubnetValidatorBLSKeyDiffAfterExpiry (#3409)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored Sep 23, 2024
1 parent 46bbf0d commit c4912bc
Showing 1 changed file with 94 additions and 81 deletions.
175 changes: 94 additions & 81 deletions vms/platformvm/vm_regression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"context"
"errors"
"strconv"
"testing"
"time"

Expand Down Expand Up @@ -1437,9 +1438,19 @@ func TestAddValidatorDuringRemoval(t *testing.T) {

// GetValidatorSet must return the BLS keys for a given validator correctly when
// queried at a previous height, even in case it has currently expired
//
// 1. Add primary network validator
// 2. Advance chain time for the primary network validator to be moved to the
// current validator set
// 3. Add permissioned subnet validator
// 4. Advance chain time for the subnet validator to be moved to the current
// validator set
// 5. Advance chain time for the subnet validator to be removed
// 6. Advance chain time for the primary network validator to be removed
// 7. Re-add the primary network validator with a different BLS key
// 8. Advance chain time for the primary network validator to be moved to the
// current validator set
func TestSubnetValidatorBLSKeyDiffAfterExpiry(t *testing.T) {
// setup
require := require.New(t)
vm, _, _ := defaultVM(t, upgradetest.Cortina)
vm.ctx.Lock.Lock()
defer vm.ctx.Lock.Unlock()
Expand All @@ -1449,7 +1460,6 @@ func TestSubnetValidatorBLSKeyDiffAfterExpiry(t *testing.T) {
subnetIDs: []ids.ID{subnetID},
})

// A subnet validator stakes and then stops; also its primary network counterpart stops staking
var (
primaryStartTime = genesistest.DefaultValidatorStartTime.Add(executor.SyncBound)
subnetStartTime = primaryStartTime.Add(executor.SyncBound)
Expand All @@ -1468,7 +1478,7 @@ func TestSubnetValidatorBLSKeyDiffAfterExpiry(t *testing.T) {
}
)
sk1, err := bls.NewSecretKey()
require.NoError(err)
require.NoError(t, err)
pk1 := bls.PublicFromSecretKey(sk1)

// build primary network validator with BLS key
Expand All @@ -1488,22 +1498,23 @@ func TestSubnetValidatorBLSKeyDiffAfterExpiry(t *testing.T) {
rewardsOwner,
reward.PercentDenominator,
)
require.NoError(err)
require.NoError(t, err)

vm.ctx.Lock.Unlock()
require.NoError(vm.issueTxFromRPC(primaryTx))
require.NoError(t, vm.issueTxFromRPC(primaryTx))
vm.ctx.Lock.Lock()
require.NoError(buildAndAcceptStandardBlock(vm))
require.NoError(t, buildAndAcceptStandardBlock(vm))

// move time ahead, promoting primary validator to current
vm.clock.Set(primaryStartTime)
require.NoError(buildAndAcceptStandardBlock(vm))
require.NoError(t, buildAndAcceptStandardBlock(vm))

_, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID)
require.NoError(err)
require.NoError(t, err)

primaryStartHeight, err := vm.GetCurrentHeight(context.Background())
require.NoError(err)
require.NoError(t, err)
t.Logf("primaryStartHeight: %d", primaryStartHeight)

// insert the subnet validator
subnetTx, err := wallet.IssueAddSubnetValidatorTx(
Expand All @@ -1517,60 +1528,63 @@ func TestSubnetValidatorBLSKeyDiffAfterExpiry(t *testing.T) {
Subnet: subnetID,
},
)
require.NoError(err)
require.NoError(t, err)

vm.ctx.Lock.Unlock()
require.NoError(vm.issueTxFromRPC(subnetTx))
require.NoError(t, vm.issueTxFromRPC(subnetTx))
vm.ctx.Lock.Lock()
require.NoError(buildAndAcceptStandardBlock(vm))
require.NoError(t, buildAndAcceptStandardBlock(vm))

// move time ahead, promoting the subnet validator to current
vm.clock.Set(subnetStartTime)
require.NoError(buildAndAcceptStandardBlock(vm))
require.NoError(t, buildAndAcceptStandardBlock(vm))

_, err = vm.state.GetCurrentValidator(subnetID, nodeID)
require.NoError(err)
require.NoError(t, err)

subnetStartHeight, err := vm.GetCurrentHeight(context.Background())
require.NoError(err)
require.NoError(t, err)
t.Logf("subnetStartHeight: %d", subnetStartHeight)

// move time ahead, terminating the subnet validator
vm.clock.Set(subnetEndTime)
require.NoError(buildAndAcceptStandardBlock(vm))
require.NoError(t, buildAndAcceptStandardBlock(vm))

_, err = vm.state.GetCurrentValidator(subnetID, nodeID)
require.ErrorIs(err, database.ErrNotFound)
require.ErrorIs(t, err, database.ErrNotFound)

subnetEndHeight, err := vm.GetCurrentHeight(context.Background())
require.NoError(err)
require.NoError(t, err)
t.Logf("subnetEndHeight: %d", subnetEndHeight)

// move time ahead, terminating primary network validator
vm.clock.Set(primaryEndTime)
blk, err := vm.Builder.BuildBlock(context.Background()) // must be a proposal block rewarding the primary validator
require.NoError(err)
require.NoError(blk.Verify(context.Background()))
require.NoError(t, err)
require.NoError(t, blk.Verify(context.Background()))

proposalBlk := blk.(snowman.OracleBlock)
options, err := proposalBlk.Options(context.Background())
require.NoError(err)
require.NoError(t, err)

commit := options[0].(*blockexecutor.Block)
require.IsType(&block.BanffCommitBlock{}, commit.Block)
require.IsType(t, &block.BanffCommitBlock{}, commit.Block)

require.NoError(blk.Accept(context.Background()))
require.NoError(commit.Verify(context.Background()))
require.NoError(commit.Accept(context.Background()))
require.NoError(vm.SetPreference(context.Background(), vm.manager.LastAccepted()))
require.NoError(t, blk.Accept(context.Background()))
require.NoError(t, commit.Verify(context.Background()))
require.NoError(t, commit.Accept(context.Background()))
require.NoError(t, vm.SetPreference(context.Background(), vm.manager.LastAccepted()))

_, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID)
require.ErrorIs(err, database.ErrNotFound)
require.ErrorIs(t, err, database.ErrNotFound)

primaryEndHeight, err := vm.GetCurrentHeight(context.Background())
require.NoError(err)
require.NoError(t, err)
t.Logf("primaryEndHeight: %d", primaryEndHeight)

// reinsert primary validator with a different BLS key
sk2, err := bls.NewSecretKey()
require.NoError(err)
require.NoError(t, err)
pk2 := bls.PublicFromSecretKey(sk2)

primaryRestartTx, err := wallet.IssueAddPermissionlessValidatorTx(
Expand All @@ -1589,70 +1603,69 @@ func TestSubnetValidatorBLSKeyDiffAfterExpiry(t *testing.T) {
rewardsOwner,
reward.PercentDenominator,
)
require.NoError(err)
require.NoError(t, err)

vm.ctx.Lock.Unlock()
require.NoError(vm.issueTxFromRPC(primaryRestartTx))
require.NoError(t, vm.issueTxFromRPC(primaryRestartTx))
vm.ctx.Lock.Lock()
require.NoError(buildAndAcceptStandardBlock(vm))
require.NoError(t, buildAndAcceptStandardBlock(vm))

// move time ahead, promoting restarted primary validator to current
vm.clock.Set(primaryReStartTime)
require.NoError(buildAndAcceptStandardBlock(vm))
require.NoError(t, buildAndAcceptStandardBlock(vm))

_, err = vm.state.GetCurrentValidator(constants.PrimaryNetworkID, nodeID)
require.NoError(err)
require.NoError(t, err)

primaryRestartHeight, err := vm.GetCurrentHeight(context.Background())
require.NoError(err)
require.NoError(t, err)
t.Logf("primaryRestartHeight: %d", primaryRestartHeight)

// Show that validators are rebuilt with the right BLS key
for height := primaryStartHeight; height < primaryEndHeight; height++ {
require.NoError(checkValidatorBlsKeyIsSet(
vm.State,
nodeID,
constants.PrimaryNetworkID,
height,
pk1,
))
}
for height := primaryEndHeight; height < primaryRestartHeight; height++ {
err := checkValidatorBlsKeyIsSet(
vm.State,
nodeID,
constants.PrimaryNetworkID,
primaryEndHeight,
pk1,
)
require.ErrorIs(err, database.ErrNotFound)
}
require.NoError(checkValidatorBlsKeyIsSet(
vm.State,
nodeID,
constants.PrimaryNetworkID,
primaryRestartHeight,
pk2,
))
for height := uint64(0); height <= primaryRestartHeight; height++ {
t.Run(strconv.Itoa(int(height)), func(t *testing.T) {
require := require.New(t)

for height := subnetStartHeight; height < subnetEndHeight; height++ {
require.NoError(checkValidatorBlsKeyIsSet(
vm.State,
nodeID,
subnetID,
height,
pk1,
))
}
// The primary network validator doesn't exist for heights
// [0, primaryStartHeight) and [primaryEndHeight, primaryRestartHeight).
var expectedPrimaryNetworkErr error
if height < primaryStartHeight || (height >= primaryEndHeight && height < primaryRestartHeight) {
expectedPrimaryNetworkErr = database.ErrNotFound
}

for height := subnetEndHeight; height <= primaryRestartHeight; height++ {
err := checkValidatorBlsKeyIsSet(
vm.State,
nodeID,
subnetID,
primaryEndHeight,
pk1,
)
require.ErrorIs(err, database.ErrNotFound)
// The primary network validator's BLS key is pk1 for the first
// validation period and pk2 for the second validation period.
var expectedPrimaryNetworkBLSKey *bls.PublicKey
if height >= primaryStartHeight && height < primaryEndHeight {
expectedPrimaryNetworkBLSKey = pk1
} else if height >= primaryRestartHeight {
expectedPrimaryNetworkBLSKey = pk2
}

err := checkValidatorBlsKeyIsSet(
vm.State,
nodeID,
constants.PrimaryNetworkID,
height,
expectedPrimaryNetworkBLSKey,
)
require.ErrorIs(err, expectedPrimaryNetworkErr)

// The subnet validator doesn't exist for heights
// [0, subnetStartHeight) and [subnetEndHeight, primaryRestartHeight).
var expectedSubnetErr error
if height < subnetStartHeight || height >= subnetEndHeight {
expectedSubnetErr = database.ErrNotFound
}

err = checkValidatorBlsKeyIsSet(
vm.State,
nodeID,
subnetID,
height,
pk1,
)
require.ErrorIs(err, expectedSubnetErr)
})
}
}

Expand Down

0 comments on commit c4912bc

Please sign in to comment.