github.com/prysmaticlabs/prysm@v1.4.4/validator/client/propose_protect_test.go (about)

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	types "github.com/prysmaticlabs/eth2-types"
     8  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
     9  	"github.com/prysmaticlabs/prysm/shared/featureconfig"
    10  	"github.com/prysmaticlabs/prysm/shared/testutil"
    11  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    12  	mockSlasher "github.com/prysmaticlabs/prysm/validator/testing"
    13  )
    14  
    15  func TestPreBlockSignLocalValidation_PreventsLowerThanMinProposal(t *testing.T) {
    16  	ctx := context.Background()
    17  	validator, _, validatorKey, finish := setup(t)
    18  	defer finish()
    19  	lowestSignedSlot := types.Slot(10)
    20  	pubKeyBytes := [48]byte{}
    21  	copy(pubKeyBytes[:], validatorKey.PublicKey().Marshal())
    22  
    23  	// We save a proposal at the lowest signed slot in the DB.
    24  	err := validator.db.SaveProposalHistoryForSlot(ctx, pubKeyBytes, lowestSignedSlot, []byte{1})
    25  	require.NoError(t, err)
    26  	require.NoError(t, err)
    27  
    28  	// We expect the same block with a slot lower than the lowest
    29  	// signed slot to fail validation.
    30  	block := &ethpb.BeaconBlock{
    31  		Slot:          lowestSignedSlot - 1,
    32  		ProposerIndex: 0,
    33  	}
    34  	err = validator.preBlockSignValidations(context.Background(), pubKeyBytes, block, [32]byte{4})
    35  	require.ErrorContains(t, "could not sign block with slot <= lowest signed", err)
    36  
    37  	// We expect the same block with a slot equal to the lowest
    38  	// signed slot to pass validation if signing roots are equal.
    39  	block = &ethpb.BeaconBlock{
    40  		Slot:          lowestSignedSlot,
    41  		ProposerIndex: 0,
    42  	}
    43  	err = validator.preBlockSignValidations(context.Background(), pubKeyBytes, block, [32]byte{1})
    44  	require.NoError(t, err)
    45  
    46  	// We expect the same block with a slot equal to the lowest
    47  	// signed slot to fail validation if signing roots are different.
    48  	block = &ethpb.BeaconBlock{
    49  		Slot:          lowestSignedSlot,
    50  		ProposerIndex: 0,
    51  	}
    52  	err = validator.preBlockSignValidations(context.Background(), pubKeyBytes, block, [32]byte{4})
    53  	require.ErrorContains(t, failedPreBlockSignLocalErr, err)
    54  
    55  	// We expect the same block with a slot > than the lowest
    56  	// signed slot to pass validation.
    57  	block = &ethpb.BeaconBlock{
    58  		Slot:          lowestSignedSlot + 1,
    59  		ProposerIndex: 0,
    60  	}
    61  	err = validator.preBlockSignValidations(context.Background(), pubKeyBytes, block, [32]byte{3})
    62  	require.NoError(t, err)
    63  }
    64  
    65  func TestPreBlockSignLocalValidation(t *testing.T) {
    66  	ctx := context.Background()
    67  	config := &featureconfig.Flags{
    68  		SlasherProtection: false,
    69  	}
    70  	reset := featureconfig.InitWithReset(config)
    71  	defer reset()
    72  	validator, _, validatorKey, finish := setup(t)
    73  	defer finish()
    74  
    75  	block := &ethpb.BeaconBlock{
    76  		Slot:          10,
    77  		ProposerIndex: 0,
    78  	}
    79  	pubKeyBytes := [48]byte{}
    80  	copy(pubKeyBytes[:], validatorKey.PublicKey().Marshal())
    81  
    82  	// We save a proposal at slot 1 as our lowest proposal.
    83  	err := validator.db.SaveProposalHistoryForSlot(ctx, pubKeyBytes, 1, []byte{1})
    84  	require.NoError(t, err)
    85  
    86  	// We save a proposal at slot 10 with a dummy signing root.
    87  	dummySigningRoot := [32]byte{1}
    88  	err = validator.db.SaveProposalHistoryForSlot(ctx, pubKeyBytes, 10, dummySigningRoot[:])
    89  	require.NoError(t, err)
    90  	pubKey := [48]byte{}
    91  	copy(pubKey[:], validatorKey.PublicKey().Marshal())
    92  
    93  	// We expect the same block sent out with the same root should not be slasahble.
    94  	err = validator.preBlockSignValidations(context.Background(), pubKey, block, dummySigningRoot)
    95  	require.NoError(t, err)
    96  
    97  	// We expect the same block sent out with a different signing root should be slasahble.
    98  	err = validator.preBlockSignValidations(context.Background(), pubKey, block, [32]byte{2})
    99  	require.ErrorContains(t, failedPreBlockSignLocalErr, err)
   100  
   101  	// We save a proposal at slot 11 with a nil signing root.
   102  	block.Slot = 11
   103  	err = validator.db.SaveProposalHistoryForSlot(ctx, pubKeyBytes, block.Slot, nil)
   104  	require.NoError(t, err)
   105  
   106  	// We expect the same block sent out should return slashable error even
   107  	// if we had a nil signing root stored in the database.
   108  	err = validator.preBlockSignValidations(context.Background(), pubKey, block, [32]byte{2})
   109  	require.ErrorContains(t, failedPreBlockSignLocalErr, err)
   110  
   111  	// A block with a different slot for which we do not have a proposing history
   112  	// should not be failing validation.
   113  	block.Slot = 9
   114  	err = validator.preBlockSignValidations(context.Background(), pubKey, block, [32]byte{3})
   115  	require.NoError(t, err, "Expected allowed block not to throw error")
   116  }
   117  
   118  func TestPreBlockSignValidation(t *testing.T) {
   119  	config := &featureconfig.Flags{
   120  		SlasherProtection: true,
   121  	}
   122  	reset := featureconfig.InitWithReset(config)
   123  	defer reset()
   124  	validator, _, validatorKey, finish := setup(t)
   125  	defer finish()
   126  	pubKey := [48]byte{}
   127  	copy(pubKey[:], validatorKey.PublicKey().Marshal())
   128  
   129  	block := testutil.NewBeaconBlock()
   130  	block.Block.Slot = 10
   131  	mockProtector := &mockSlasher.MockProtector{AllowBlock: false}
   132  	validator.protector = mockProtector
   133  	err := validator.preBlockSignValidations(context.Background(), pubKey, block.Block, [32]byte{2})
   134  	require.ErrorContains(t, failedPreBlockSignExternalErr, err)
   135  	mockProtector.AllowBlock = true
   136  	err = validator.preBlockSignValidations(context.Background(), pubKey, block.Block, [32]byte{2})
   137  	require.NoError(t, err, "Expected allowed block not to throw error")
   138  }
   139  
   140  func TestPostBlockSignUpdate(t *testing.T) {
   141  	config := &featureconfig.Flags{
   142  		SlasherProtection: true,
   143  	}
   144  	reset := featureconfig.InitWithReset(config)
   145  	defer reset()
   146  	validator, _, validatorKey, finish := setup(t)
   147  	defer finish()
   148  	pubKey := [48]byte{}
   149  	copy(pubKey[:], validatorKey.PublicKey().Marshal())
   150  	emptyBlock := testutil.NewBeaconBlock()
   151  	emptyBlock.Block.Slot = 10
   152  	emptyBlock.Block.ProposerIndex = 0
   153  	mockProtector := &mockSlasher.MockProtector{AllowBlock: false}
   154  	validator.protector = mockProtector
   155  	err := validator.postBlockSignUpdate(context.Background(), pubKey, emptyBlock, [32]byte{})
   156  	require.ErrorContains(t, failedPostBlockSignErr, err, "Expected error when post signature update is detected as slashable")
   157  	mockProtector.AllowBlock = true
   158  	err = validator.postBlockSignUpdate(context.Background(), pubKey, emptyBlock, [32]byte{})
   159  	require.NoError(t, err, "Expected allowed block not to throw error")
   160  }