diff --git a/beacon-chain/blockchain/forkchoice/service.go b/beacon-chain/blockchain/forkchoice/service.go index 26cac82f7..57635a984 100644 --- a/beacon-chain/blockchain/forkchoice/service.go +++ b/beacon-chain/blockchain/forkchoice/service.go @@ -401,6 +401,7 @@ func (s *Store) filterBlockTree(ctx context.Context, blockRoot [32]byte, filtere return false, nil } + headState, err := s.db.State(ctx, blockRoot) if err != nil { return false, err diff --git a/beacon-chain/blockchain/receive_attestation.go b/beacon-chain/blockchain/receive_attestation.go index 8d21b6526..471e3a556 100644 --- a/beacon-chain/blockchain/receive_attestation.go +++ b/beacon-chain/blockchain/receive_attestation.go @@ -74,6 +74,12 @@ func (s *Service) processAttestation() { ctx := context.Background() atts := s.attPool.ForkchoiceAttestations() for _, a := range atts { + hasState := s.beaconDB.HasState(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot)) + hasBlock := s.beaconDB.HasBlock(ctx, bytesutil.ToBytes32(a.Data.BeaconBlockRoot)) + if !(hasState && hasBlock) { + continue + } + if err := s.attPool.DeleteForkchoiceAttestation(a); err != nil { log.WithError(err).Error("Could not delete fork choice attestation in pool") } diff --git a/beacon-chain/db/iface/interface.go b/beacon-chain/db/iface/interface.go index 12bb5eac9..c5ac6f3bb 100644 --- a/beacon-chain/db/iface/interface.go +++ b/beacon-chain/db/iface/interface.go @@ -55,6 +55,7 @@ type Database interface { SaveState(ctx context.Context, state *ethereum_beacon_p2p_v1.BeaconState, blockRoot [32]byte) error DeleteState(ctx context.Context, blockRoot [32]byte) error DeleteStates(ctx context.Context, blockRoots [][32]byte) error + HasState(ctx context.Context, blockRoot [32]byte) bool // Slashing operations. ProposerSlashing(ctx context.Context, slashingRoot [32]byte) (*eth.ProposerSlashing, error) AttesterSlashing(ctx context.Context, slashingRoot [32]byte) (*eth.AttesterSlashing, error) diff --git a/beacon-chain/db/kafka/passthrough.go b/beacon-chain/db/kafka/passthrough.go index 5b1183999..70785608e 100644 --- a/beacon-chain/db/kafka/passthrough.go +++ b/beacon-chain/db/kafka/passthrough.go @@ -281,6 +281,11 @@ func (e Exporter) DeleteStates(ctx context.Context, blockRoots [][32]byte) error return e.db.DeleteStates(ctx, blockRoots) } +// HasState -- passthrough. +func (e Exporter) HasState(ctx context.Context, blockRoot [32]byte) bool { + return e.db.HasState(ctx, blockRoot) +} + // IsFinalizedBlock -- passthrough. func (e Exporter) IsFinalizedBlock(ctx context.Context, blockRoot [32]byte) bool { return e.db.IsFinalizedBlock(ctx, blockRoot) diff --git a/beacon-chain/db/kv/state.go b/beacon-chain/db/kv/state.go index df650ea3e..74b593f7b 100644 --- a/beacon-chain/db/kv/state.go +++ b/beacon-chain/db/kv/state.go @@ -98,6 +98,20 @@ func (k *Store) SaveState(ctx context.Context, state *pb.BeaconState, blockRoot }) } +// HasState checks if a state by root exists in the db. +func (k *Store) HasState(ctx context.Context, blockRoot [32]byte) bool { + ctx, span := trace.StartSpan(ctx, "BeaconDB.HasState") + defer span.End() + var exists bool + // #nosec G104. Always returns nil. + k.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket(stateBucket) + exists = bucket.Get(blockRoot[:]) != nil + return nil + }) + return exists +} + // DeleteState by block root. func (k *Store) DeleteState(ctx context.Context, blockRoot [32]byte) error { ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteState") diff --git a/beacon-chain/db/kv/state_test.go b/beacon-chain/db/kv/state_test.go index a234b30a2..f7c009996 100644 --- a/beacon-chain/db/kv/state_test.go +++ b/beacon-chain/db/kv/state_test.go @@ -18,10 +18,18 @@ func TestState_CanSaveRetrieve(t *testing.T) { s := &pb.BeaconState{Slot: 100} r := [32]byte{'A'} + if db.HasState(context.Background(), r) { + t.Fatal("wanted false") + } + if err := db.SaveState(context.Background(), s, r); err != nil { t.Fatal(err) } + if !db.HasState(context.Background(), r) { + t.Fatal("wanted true") + } + savedS, err := db.State(context.Background(), r) if err != nil { t.Fatal(err)