github.com/prysmaticlabs/prysm@v1.4.4/validator/db/kv/proposer_protection_test.go (about) 1 package kv 2 3 import ( 4 "context" 5 "testing" 6 7 types "github.com/prysmaticlabs/eth2-types" 8 "github.com/prysmaticlabs/prysm/shared/bytesutil" 9 "github.com/prysmaticlabs/prysm/shared/params" 10 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 11 "github.com/prysmaticlabs/prysm/shared/testutil/require" 12 ) 13 14 func TestProposalHistoryForSlot_InitializesNewPubKeys(t *testing.T) { 15 pubkeys := [][48]byte{{30}, {25}, {20}} 16 db := setupDB(t, pubkeys) 17 18 for _, pub := range pubkeys { 19 signingRoot, _, err := db.ProposalHistoryForSlot(context.Background(), pub, 0) 20 require.NoError(t, err) 21 expected := bytesutil.PadTo([]byte{}, 32) 22 require.DeepEqual(t, expected, signingRoot[:], "Expected proposal history slot signing root to be empty") 23 } 24 } 25 26 func TestNewProposalHistoryForSlot_ReturnsNilIfNoHistory(t *testing.T) { 27 valPubkey := [48]byte{1, 2, 3} 28 db := setupDB(t, [][48]byte{}) 29 30 _, proposalExists, err := db.ProposalHistoryForSlot(context.Background(), valPubkey, 0) 31 require.NoError(t, err) 32 assert.Equal(t, false, proposalExists) 33 } 34 35 func TestSaveProposalHistoryForSlot_OK(t *testing.T) { 36 pubkey := [48]byte{3} 37 db := setupDB(t, [][48]byte{pubkey}) 38 39 slot := types.Slot(2) 40 41 err := db.SaveProposalHistoryForSlot(context.Background(), pubkey, slot, []byte{1}) 42 require.NoError(t, err, "Saving proposal history failed: %v") 43 signingRoot, _, err := db.ProposalHistoryForSlot(context.Background(), pubkey, slot) 44 require.NoError(t, err, "Failed to get proposal history") 45 46 require.NotNil(t, signingRoot) 47 require.DeepEqual(t, bytesutil.PadTo([]byte{1}, 32), signingRoot[:], "Expected DB to keep object the same") 48 } 49 50 func TestNewProposalHistoryForPubKey_ReturnsEmptyIfNoHistory(t *testing.T) { 51 valPubkey := [48]byte{1, 2, 3} 52 db := setupDB(t, [][48]byte{}) 53 54 proposalHistory, err := db.ProposalHistoryForPubKey(context.Background(), valPubkey) 55 require.NoError(t, err) 56 assert.DeepEqual(t, make([]*Proposal, 0), proposalHistory) 57 } 58 59 func TestSaveProposalHistoryForPubKey_OK(t *testing.T) { 60 pubkey := [48]byte{3} 61 db := setupDB(t, [][48]byte{pubkey}) 62 63 slot := types.Slot(2) 64 65 root := [32]byte{1} 66 err := db.SaveProposalHistoryForSlot(context.Background(), pubkey, slot, root[:]) 67 require.NoError(t, err, "Saving proposal history failed: %v") 68 proposalHistory, err := db.ProposalHistoryForPubKey(context.Background(), pubkey) 69 require.NoError(t, err, "Failed to get proposal history") 70 71 require.NotNil(t, proposalHistory) 72 want := []*Proposal{ 73 { 74 Slot: slot, 75 SigningRoot: root[:], 76 }, 77 } 78 require.DeepEqual(t, want[0], proposalHistory[0]) 79 } 80 81 func TestSaveProposalHistoryForSlot_Overwrites(t *testing.T) { 82 pubkey := [48]byte{0} 83 tests := []struct { 84 signingRoot []byte 85 }{ 86 { 87 signingRoot: bytesutil.PadTo([]byte{1}, 32), 88 }, 89 { 90 signingRoot: bytesutil.PadTo([]byte{2}, 32), 91 }, 92 { 93 signingRoot: bytesutil.PadTo([]byte{3}, 32), 94 }, 95 } 96 97 for _, tt := range tests { 98 db := setupDB(t, [][48]byte{pubkey}) 99 err := db.SaveProposalHistoryForSlot(context.Background(), pubkey, 0, tt.signingRoot) 100 require.NoError(t, err, "Saving proposal history failed") 101 proposalHistory, err := db.ProposalHistoryForPubKey(context.Background(), pubkey) 102 require.NoError(t, err, "Failed to get proposal history") 103 104 require.NotNil(t, proposalHistory) 105 require.DeepEqual(t, tt.signingRoot, proposalHistory[0].SigningRoot, "Expected DB to keep object the same") 106 require.NoError(t, db.Close(), "Failed to close database") 107 } 108 } 109 110 func TestPruneProposalHistoryBySlot_OK(t *testing.T) { 111 slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch 112 wsPeriod := params.BeaconConfig().WeakSubjectivityPeriod 113 pubKey := [48]byte{0} 114 tests := []struct { 115 slots []types.Slot 116 storedSlots []types.Slot 117 removedSlots []types.Slot 118 }{ 119 { 120 // Go 2 epochs past pruning point. 121 slots: []types.Slot{slotsPerEpoch / 2, slotsPerEpoch*5 + 6, slotsPerEpoch.Mul(uint64(wsPeriod+3)) + 8}, 122 storedSlots: []types.Slot{slotsPerEpoch*5 + 6, slotsPerEpoch.Mul(uint64(wsPeriod+3)) + 8}, 123 removedSlots: []types.Slot{slotsPerEpoch / 2}, 124 }, 125 { 126 // Go 10 epochs past pruning point. 127 slots: []types.Slot{ 128 slotsPerEpoch + 4, 129 slotsPerEpoch * 2, 130 slotsPerEpoch * 3, 131 slotsPerEpoch * 4, 132 slotsPerEpoch * 5, 133 slotsPerEpoch.Mul(uint64(wsPeriod+10)) + 8, 134 }, 135 storedSlots: []types.Slot{slotsPerEpoch.Mul(uint64(wsPeriod+10)) + 8}, 136 removedSlots: []types.Slot{ 137 slotsPerEpoch + 4, 138 slotsPerEpoch * 2, 139 slotsPerEpoch * 3, 140 slotsPerEpoch * 4, 141 slotsPerEpoch * 5, 142 }, 143 }, 144 { 145 // Prune none. 146 slots: []types.Slot{slotsPerEpoch + 4, slotsPerEpoch*2 + 3, slotsPerEpoch*3 + 4, slotsPerEpoch*4 + 3, slotsPerEpoch*5 + 3}, 147 storedSlots: []types.Slot{slotsPerEpoch + 4, slotsPerEpoch*2 + 3, slotsPerEpoch*3 + 4, slotsPerEpoch*4 + 3, slotsPerEpoch*5 + 3}, 148 }, 149 } 150 signedRoot := bytesutil.PadTo([]byte{1}, 32) 151 152 for _, tt := range tests { 153 db := setupDB(t, [][48]byte{pubKey}) 154 for _, slot := range tt.slots { 155 err := db.SaveProposalHistoryForSlot(context.Background(), pubKey, slot, signedRoot) 156 require.NoError(t, err, "Saving proposal history failed") 157 } 158 159 signingRootsBySlot := make(map[types.Slot][]byte) 160 proposalHistory, err := db.ProposalHistoryForPubKey(context.Background(), pubKey) 161 require.NoError(t, err) 162 163 for _, hist := range proposalHistory { 164 signingRootsBySlot[hist.Slot] = hist.SigningRoot 165 } 166 167 for _, slot := range tt.removedSlots { 168 _, ok := signingRootsBySlot[slot] 169 require.Equal(t, false, ok) 170 } 171 for _, slot := range tt.storedSlots { 172 root, ok := signingRootsBySlot[slot] 173 require.Equal(t, true, ok) 174 require.DeepEqual(t, signedRoot, root, "Unexpected difference in bytes for epoch %d", slot) 175 } 176 require.NoError(t, db.Close(), "Failed to close database") 177 } 178 } 179 180 func TestStore_ProposedPublicKeys(t *testing.T) { 181 ctx := context.Background() 182 validatorDB, err := NewKVStore(ctx, t.TempDir(), &Config{}) 183 require.NoError(t, err, "Failed to instantiate DB") 184 t.Cleanup(func() { 185 require.NoError(t, validatorDB.Close(), "Failed to close database") 186 require.NoError(t, validatorDB.ClearDB(), "Failed to clear database") 187 }) 188 189 keys, err := validatorDB.ProposedPublicKeys(ctx) 190 require.NoError(t, err) 191 assert.DeepEqual(t, make([][48]byte, 0), keys) 192 193 pubKey := [48]byte{1} 194 dummyRoot := [32]byte{} 195 err = validatorDB.SaveProposalHistoryForSlot(ctx, pubKey, 1, dummyRoot[:]) 196 require.NoError(t, err) 197 198 keys, err = validatorDB.ProposedPublicKeys(ctx) 199 require.NoError(t, err) 200 assert.DeepEqual(t, [][48]byte{pubKey}, keys) 201 } 202 203 func TestStore_LowestSignedProposal(t *testing.T) { 204 ctx := context.Background() 205 pubkey := [48]byte{3} 206 dummySigningRoot := [32]byte{} 207 validatorDB := setupDB(t, [][48]byte{pubkey}) 208 209 _, exists, err := validatorDB.LowestSignedProposal(ctx, pubkey) 210 require.NoError(t, err) 211 require.Equal(t, false, exists) 212 213 // We save our first proposal history. 214 err = validatorDB.SaveProposalHistoryForSlot(ctx, pubkey, 2 /* slot */, dummySigningRoot[:]) 215 require.NoError(t, err) 216 217 // We expect the lowest signed slot is what we just saved. 218 slot, exists, err := validatorDB.LowestSignedProposal(ctx, pubkey) 219 require.NoError(t, err) 220 require.Equal(t, true, exists) 221 assert.Equal(t, types.Slot(2), slot) 222 223 // We save a higher proposal history. 224 err = validatorDB.SaveProposalHistoryForSlot(ctx, pubkey, 3 /* slot */, dummySigningRoot[:]) 225 require.NoError(t, err) 226 227 // We expect the lowest signed slot did not change. 228 slot, exists, err = validatorDB.LowestSignedProposal(ctx, pubkey) 229 require.NoError(t, err) 230 require.Equal(t, true, exists) 231 assert.Equal(t, types.Slot(2), slot) 232 233 // We save a lower proposal history. 234 err = validatorDB.SaveProposalHistoryForSlot(ctx, pubkey, 1 /* slot */, dummySigningRoot[:]) 235 require.NoError(t, err) 236 237 // We expect the lowest signed slot indeed changed. 238 slot, exists, err = validatorDB.LowestSignedProposal(ctx, pubkey) 239 require.NoError(t, err) 240 require.Equal(t, true, exists) 241 assert.Equal(t, types.Slot(1), slot) 242 } 243 244 func TestStore_HighestSignedProposal(t *testing.T) { 245 ctx := context.Background() 246 pubkey := [48]byte{3} 247 dummySigningRoot := [32]byte{} 248 validatorDB := setupDB(t, [][48]byte{pubkey}) 249 250 _, exists, err := validatorDB.HighestSignedProposal(ctx, pubkey) 251 require.NoError(t, err) 252 require.Equal(t, false, exists) 253 254 // We save our first proposal history. 255 err = validatorDB.SaveProposalHistoryForSlot(ctx, pubkey, 2 /* slot */, dummySigningRoot[:]) 256 require.NoError(t, err) 257 258 // We expect the highest signed slot is what we just saved. 259 slot, exists, err := validatorDB.HighestSignedProposal(ctx, pubkey) 260 require.NoError(t, err) 261 require.Equal(t, true, exists) 262 assert.Equal(t, types.Slot(2), slot) 263 264 // We save a lower proposal history. 265 err = validatorDB.SaveProposalHistoryForSlot(ctx, pubkey, 1 /* slot */, dummySigningRoot[:]) 266 require.NoError(t, err) 267 268 // We expect the lowest signed slot did not change. 269 slot, exists, err = validatorDB.HighestSignedProposal(ctx, pubkey) 270 require.NoError(t, err) 271 require.Equal(t, true, exists) 272 assert.Equal(t, types.Slot(2), slot) 273 274 // We save a higher proposal history. 275 err = validatorDB.SaveProposalHistoryForSlot(ctx, pubkey, 3 /* slot */, dummySigningRoot[:]) 276 require.NoError(t, err) 277 278 // We expect the highest signed slot indeed changed. 279 slot, exists, err = validatorDB.HighestSignedProposal(ctx, pubkey) 280 require.NoError(t, err) 281 require.Equal(t, true, exists) 282 assert.Equal(t, types.Slot(3), slot) 283 }