github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/blocks/proposer_slashing_test.go (about)

     1  package blocks_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    11  	v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
    12  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    13  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    14  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    15  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    16  	"github.com/prysmaticlabs/prysm/shared/bls"
    17  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    18  	"github.com/prysmaticlabs/prysm/shared/params"
    19  	"github.com/prysmaticlabs/prysm/shared/testutil"
    20  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    21  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    22  )
    23  
    24  func TestProcessProposerSlashings_UnmatchedHeaderSlots(t *testing.T) {
    25  
    26  	beaconState, _ := testutil.DeterministicGenesisState(t, 20)
    27  	currentSlot := types.Slot(0)
    28  	slashings := []*ethpb.ProposerSlashing{
    29  		{
    30  			Header_1: &ethpb.SignedBeaconBlockHeader{
    31  				Header: &ethpb.BeaconBlockHeader{
    32  					ProposerIndex: 1,
    33  					Slot:          params.BeaconConfig().SlotsPerEpoch + 1,
    34  				},
    35  			},
    36  			Header_2: &ethpb.SignedBeaconBlockHeader{
    37  				Header: &ethpb.BeaconBlockHeader{
    38  					ProposerIndex: 1,
    39  					Slot:          0,
    40  				},
    41  			},
    42  		},
    43  	}
    44  	require.NoError(t, beaconState.SetSlot(currentSlot))
    45  
    46  	b := testutil.NewBeaconBlock()
    47  	b.Block = &ethpb.BeaconBlock{
    48  		Body: &ethpb.BeaconBlockBody{
    49  			ProposerSlashings: slashings,
    50  		},
    51  	}
    52  	want := "mismatched header slots"
    53  	_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, b.Block.Body.ProposerSlashings, v.SlashValidator)
    54  	assert.ErrorContains(t, want, err)
    55  }
    56  
    57  func TestProcessProposerSlashings_SameHeaders(t *testing.T) {
    58  
    59  	beaconState, _ := testutil.DeterministicGenesisState(t, 2)
    60  	currentSlot := types.Slot(0)
    61  	slashings := []*ethpb.ProposerSlashing{
    62  		{
    63  			Header_1: &ethpb.SignedBeaconBlockHeader{
    64  				Header: &ethpb.BeaconBlockHeader{
    65  					ProposerIndex: 1,
    66  					Slot:          0,
    67  				},
    68  			},
    69  			Header_2: &ethpb.SignedBeaconBlockHeader{
    70  				Header: &ethpb.BeaconBlockHeader{
    71  					ProposerIndex: 1,
    72  					Slot:          0,
    73  				},
    74  			},
    75  		},
    76  	}
    77  
    78  	require.NoError(t, beaconState.SetSlot(currentSlot))
    79  	b := testutil.NewBeaconBlock()
    80  	b.Block = &ethpb.BeaconBlock{
    81  		Body: &ethpb.BeaconBlockBody{
    82  			ProposerSlashings: slashings,
    83  		},
    84  	}
    85  	want := "expected slashing headers to differ"
    86  	_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, b.Block.Body.ProposerSlashings, v.SlashValidator)
    87  	assert.ErrorContains(t, want, err)
    88  }
    89  
    90  func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
    91  	registry := []*ethpb.Validator{
    92  		{
    93  			PublicKey:         []byte("key"),
    94  			Slashed:           true,
    95  			ActivationEpoch:   0,
    96  			WithdrawableEpoch: 0,
    97  		},
    98  	}
    99  	currentSlot := types.Slot(0)
   100  	slashings := []*ethpb.ProposerSlashing{
   101  		{
   102  			Header_1: &ethpb.SignedBeaconBlockHeader{
   103  				Header: &ethpb.BeaconBlockHeader{
   104  					ProposerIndex: 0,
   105  					Slot:          0,
   106  					BodyRoot:      []byte("foo"),
   107  				},
   108  				Signature: bytesutil.PadTo([]byte("A"), 96),
   109  			},
   110  			Header_2: &ethpb.SignedBeaconBlockHeader{
   111  				Header: &ethpb.BeaconBlockHeader{
   112  					ProposerIndex: 0,
   113  					Slot:          0,
   114  					BodyRoot:      []byte("bar"),
   115  				},
   116  				Signature: bytesutil.PadTo([]byte("B"), 96),
   117  			},
   118  		},
   119  	}
   120  
   121  	beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
   122  		Validators: registry,
   123  		Slot:       currentSlot,
   124  	})
   125  	require.NoError(t, err)
   126  	b := testutil.NewBeaconBlock()
   127  	b.Block = &ethpb.BeaconBlock{
   128  		Body: &ethpb.BeaconBlockBody{
   129  			ProposerSlashings: slashings,
   130  		},
   131  	}
   132  	want := fmt.Sprintf(
   133  		"validator with key %#x is not slashable",
   134  		bytesutil.ToBytes48(beaconState.Validators()[0].PublicKey),
   135  	)
   136  	_, err = blocks.ProcessProposerSlashings(context.Background(), beaconState, b.Block.Body.ProposerSlashings, v.SlashValidator)
   137  	assert.ErrorContains(t, want, err)
   138  }
   139  
   140  func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
   141  	// We test the case when data is correct and verify the validator
   142  	// registry has been updated.
   143  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   144  	proposerIdx := types.ValidatorIndex(1)
   145  
   146  	header1 := &ethpb.SignedBeaconBlockHeader{
   147  		Header: testutil.HydrateBeaconHeader(&ethpb.BeaconBlockHeader{
   148  			ProposerIndex: proposerIdx,
   149  			StateRoot:     bytesutil.PadTo([]byte("A"), 32),
   150  		}),
   151  	}
   152  	var err error
   153  	header1.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, header1.Header, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   154  	require.NoError(t, err)
   155  
   156  	header2 := testutil.HydrateSignedBeaconHeader(&ethpb.SignedBeaconBlockHeader{
   157  		Header: &ethpb.BeaconBlockHeader{
   158  			ProposerIndex: proposerIdx,
   159  			StateRoot:     bytesutil.PadTo([]byte("B"), 32),
   160  		},
   161  	})
   162  	header2.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, header2.Header, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   163  	require.NoError(t, err)
   164  
   165  	slashings := []*ethpb.ProposerSlashing{
   166  		{
   167  			Header_1: header1,
   168  			Header_2: header2,
   169  		},
   170  	}
   171  
   172  	block := testutil.NewBeaconBlock()
   173  	block.Block.Body.ProposerSlashings = slashings
   174  
   175  	newState, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Block.Body.ProposerSlashings, v.SlashValidator)
   176  	require.NoError(t, err)
   177  
   178  	newStateVals := newState.Validators()
   179  	if newStateVals[1].ExitEpoch != beaconState.Validators()[1].ExitEpoch {
   180  		t.Errorf("Proposer with index 1 did not correctly exit,"+"wanted slot:%d, got:%d",
   181  			newStateVals[1].ExitEpoch, beaconState.Validators()[1].ExitEpoch)
   182  	}
   183  }
   184  
   185  func TestVerifyProposerSlashing(t *testing.T) {
   186  	type args struct {
   187  		beaconState iface.BeaconState
   188  		slashing    *ethpb.ProposerSlashing
   189  	}
   190  
   191  	beaconState, sks := testutil.DeterministicGenesisState(t, 2)
   192  	currentSlot := types.Slot(0)
   193  	require.NoError(t, beaconState.SetSlot(currentSlot))
   194  	rand1, err := bls.RandKey()
   195  	require.NoError(t, err)
   196  	sig1 := rand1.Sign([]byte("foo")).Marshal()
   197  
   198  	rand2, err := bls.RandKey()
   199  	require.NoError(t, err)
   200  	sig2 := rand2.Sign([]byte("bar")).Marshal()
   201  
   202  	tests := []struct {
   203  		name    string
   204  		args    args
   205  		wantErr string
   206  	}{
   207  		{
   208  			name: "same header, same slot as state",
   209  			args: args{
   210  				slashing: &ethpb.ProposerSlashing{
   211  					Header_1: testutil.HydrateSignedBeaconHeader(&ethpb.SignedBeaconBlockHeader{
   212  						Header: &ethpb.BeaconBlockHeader{
   213  							ProposerIndex: 1,
   214  							Slot:          currentSlot,
   215  						},
   216  					}),
   217  					Header_2: testutil.HydrateSignedBeaconHeader(&ethpb.SignedBeaconBlockHeader{
   218  						Header: &ethpb.BeaconBlockHeader{
   219  							ProposerIndex: 1,
   220  							Slot:          currentSlot,
   221  						},
   222  					}),
   223  				},
   224  				beaconState: beaconState,
   225  			},
   226  			wantErr: "expected slashing headers to differ",
   227  		},
   228  		{ // Regression test for https://github.com/sigp/beacon-fuzz/issues/74
   229  			name: "same header, different signatures",
   230  			args: args{
   231  				slashing: &ethpb.ProposerSlashing{
   232  					Header_1: testutil.HydrateSignedBeaconHeader(&ethpb.SignedBeaconBlockHeader{
   233  						Header: &ethpb.BeaconBlockHeader{
   234  							ProposerIndex: 1,
   235  						},
   236  						Signature: sig1,
   237  					}),
   238  					Header_2: testutil.HydrateSignedBeaconHeader(&ethpb.SignedBeaconBlockHeader{
   239  						Header: &ethpb.BeaconBlockHeader{
   240  							ProposerIndex: 1,
   241  						},
   242  						Signature: sig2,
   243  					}),
   244  				},
   245  				beaconState: beaconState,
   246  			},
   247  			wantErr: "expected slashing headers to differ",
   248  		},
   249  		{
   250  			name: "slashing in future epoch",
   251  			args: args{
   252  				slashing: &ethpb.ProposerSlashing{
   253  					Header_1: &ethpb.SignedBeaconBlockHeader{
   254  						Header: &ethpb.BeaconBlockHeader{
   255  							ProposerIndex: 1,
   256  							Slot:          65,
   257  							StateRoot:     bytesutil.PadTo([]byte{}, 32),
   258  							BodyRoot:      bytesutil.PadTo([]byte{}, 32),
   259  							ParentRoot:    bytesutil.PadTo([]byte("foo"), 32),
   260  						},
   261  					},
   262  					Header_2: &ethpb.SignedBeaconBlockHeader{
   263  						Header: &ethpb.BeaconBlockHeader{
   264  							ProposerIndex: 1,
   265  							Slot:          65,
   266  							StateRoot:     bytesutil.PadTo([]byte{}, 32),
   267  							BodyRoot:      bytesutil.PadTo([]byte{}, 32),
   268  							ParentRoot:    bytesutil.PadTo([]byte("bar"), 32),
   269  						},
   270  					},
   271  				},
   272  				beaconState: beaconState,
   273  			},
   274  			wantErr: "",
   275  		},
   276  	}
   277  	for _, tt := range tests {
   278  		t.Run(tt.name, func(t *testing.T) {
   279  
   280  			sk := sks[tt.args.slashing.Header_1.Header.ProposerIndex]
   281  			d, err := helpers.Domain(tt.args.beaconState.Fork(), helpers.SlotToEpoch(tt.args.slashing.Header_1.Header.Slot), params.BeaconConfig().DomainBeaconProposer, tt.args.beaconState.GenesisValidatorRoot())
   282  			require.NoError(t, err)
   283  			if tt.args.slashing.Header_1.Signature == nil {
   284  				sr, err := helpers.ComputeSigningRoot(tt.args.slashing.Header_1.Header, d)
   285  				require.NoError(t, err)
   286  				tt.args.slashing.Header_1.Signature = sk.Sign(sr[:]).Marshal()
   287  			}
   288  			if tt.args.slashing.Header_2.Signature == nil {
   289  				sr, err := helpers.ComputeSigningRoot(tt.args.slashing.Header_2.Header, d)
   290  				require.NoError(t, err)
   291  				tt.args.slashing.Header_2.Signature = sk.Sign(sr[:]).Marshal()
   292  			}
   293  			if err := blocks.VerifyProposerSlashing(tt.args.beaconState, tt.args.slashing); (err != nil || tt.wantErr != "") && err.Error() != tt.wantErr {
   294  				t.Errorf("VerifyProposerSlashing() error = %v, wantErr %v", err, tt.wantErr)
   295  			}
   296  		})
   297  	}
   298  }