Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interface Analyzer #8923

Merged
merged 10 commits into from May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions BUILD.bazel
Expand Up @@ -120,6 +120,7 @@ nogo(
"//tools/analyzers/shadowpredecl:go_tool_library",
"//tools/analyzers/nop:go_tool_library",
"//tools/analyzers/slicedirect:go_tool_library",
"//tools/analyzers/interfacechecker:go_tool_library",
"//tools/analyzers/ineffassign:go_tool_library",
"//tools/analyzers/properpermissions:go_tool_library",
] + select({
Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/blockchain/head.go
Expand Up @@ -113,7 +113,7 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
if err != nil {
return errors.Wrap(err, "could not retrieve head state in DB")
}
if newHeadState == nil {
if newHeadState == nil || newHeadState.IsNil() {
return errors.New("cannot save nil head state")
}

Expand Down Expand Up @@ -262,7 +262,7 @@ func (s *Service) cacheJustifiedStateBalances(ctx context.Context, justifiedRoot
return err
}
}
if justifiedState == nil {
if justifiedState == nil || justifiedState.IsNil() {
return errors.New("justified state can't be nil")
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/info.go
Expand Up @@ -39,7 +39,7 @@ func (s *Service) TreeHandler(w http.ResponseWriter, r *http.Request) {
log.WithError(err).Error("Could not get head state")
return
}
if headState == nil {
if headState == nil || headState.IsNil() {
if _, err := w.Write([]byte("Unavailable during initial syncing")); err != nil {
log.WithError(err).Error("Failed to render p2p info page")
}
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/process_attestation_helpers.go
Expand Up @@ -29,7 +29,7 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (ifac
if err != nil {
return nil, errors.Wrap(err, "could not get cached checkpoint state")
}
if cachedState != nil {
if cachedState != nil && !cachedState.IsNil() {
return cachedState, nil
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/process_block.go
Expand Up @@ -203,7 +203,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []*ethpb.SignedBeaconBl
if err != nil {
return nil, nil, err
}
if preState == nil {
if preState == nil || preState.IsNil() {
return nil, nil, fmt.Errorf("nil pre state for slot %d", b.Slot)
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/process_block_helpers.go
Expand Up @@ -39,7 +39,7 @@ func (s *Service) getBlockPreState(ctx context.Context, b *ethpb.BeaconBlock) (i
if err != nil {
return nil, errors.Wrapf(err, "could not get pre state for slot %d", b.Slot)
}
if preState == nil {
if preState == nil || preState.IsNil() {
return nil, errors.Wrapf(err, "nil pre state for slot %d", b.Slot)
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/service.go
Expand Up @@ -135,7 +135,7 @@ func (s *Service) Start() {
attestationProcessorSubscribed := make(chan struct{}, 1)

// If the chain has already been initialized, simply start the block processing routine.
if beaconState != nil {
if beaconState != nil && !beaconState.IsNil() {
log.Info("Blockchain data already exists in DB, initializing...")
s.genesisTime = time.Unix(int64(beaconState.GenesisTime()), 0)
s.cfg.OpsService.SetGenesisTime(beaconState.GenesisTime())
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/blocks/eth1_data.go
Expand Up @@ -21,7 +21,7 @@ import (
// if state.eth1_data_votes.count(body.eth1_data) * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH:
// state.eth1_data = body.eth1_data
func ProcessEth1DataInBlock(_ context.Context, beaconState iface.BeaconState, eth1Data *ethpb.Eth1Data) (iface.BeaconState, error) {
if beaconState == nil {
if beaconState == nil || beaconState.IsNil() {
return nil, errors.New("nil state")
}
if err := beaconState.AppendEth1DataVotes(eth1Data); err != nil {
Expand Down
6 changes: 3 additions & 3 deletions beacon-chain/core/state/transition.go
Expand Up @@ -179,7 +179,7 @@ func ProcessSlotsUsingNextSlotCache(
}
// If the next slot state is not nil (i.e. cache hit).
// We replace next slot state with parent state.
if nextSlotState != nil {
if nextSlotState != nil && !nextSlotState.IsNil() {
parentState = nextSlotState
}

Expand Down Expand Up @@ -208,7 +208,7 @@ func ProcessSlotsUsingNextSlotCache(
func ProcessSlots(ctx context.Context, state iface.BeaconState, slot types.Slot) (iface.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlots")
defer span.End()
if state == nil {
if state == nil || state.IsNil() {
return nil, errors.New("nil state")
}
span.AddAttributes(trace.Int64Attribute("slots", int64(slot)-int64(state.Slot())))
Expand Down Expand Up @@ -399,7 +399,7 @@ func ProcessEpochPrecompute(ctx context.Context, state iface.BeaconState) (iface
defer span.End()
span.AddAttributes(trace.Int64Attribute("epoch", int64(helpers.CurrentEpoch(state))))

if state == nil {
if state == nil || state.IsNil() {
return nil, errors.New("nil state")
}
vp, bp, err := precompute.New(ctx, state)
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/state/transition_no_verify_sig.go
Expand Up @@ -121,7 +121,7 @@ func CalculateStateRoot(
traceutil.AnnotateError(span, ctx.Err())
return [32]byte{}, ctx.Err()
}
if state == nil {
if state == nil || state.IsNil() {
return [32]byte{}, errors.New("nil state")
}
if signed == nil || signed.Block == nil {
Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/db/kv/genesis.go
Expand Up @@ -70,7 +70,7 @@ func (s *Store) LoadGenesis(ctx context.Context, r io.Reader) error {
}
// If some different genesis state existed already, return an error. The same genesis state is
// considered a no-op.
if existing != nil {
if existing != nil && !existing.IsNil() {
a, err := existing.HashTreeRoot(ctx)
if err != nil {
return err
Expand Down Expand Up @@ -108,7 +108,7 @@ func (s *Store) EnsureEmbeddedGenesis(ctx context.Context) error {
if err != nil {
return err
}
if gs != nil {
if gs != nil && !gs.IsNil() {
return s.SaveGenesisData(ctx, gs)
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/db/kv/state.go
Expand Up @@ -294,7 +294,7 @@ func (s *Store) HighestSlotStatesBelow(ctx context.Context, slot types.Slot) ([]
return nil, err
}
}
if st == nil {
if st == nil || st.IsNil() {
st, err = s.GenesisState(ctx)
if err != nil {
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/p2p/gossip_scoring_params.go
Expand Up @@ -113,7 +113,7 @@ func (s *Service) retrieveActiveValidators() (uint64, error) {
if err != nil {
return 0, err
}
if genState == nil {
if genState == nil || genState.IsNil() {
return 0, errors.New("no genesis state exists")
}
activeVals, err := helpers.ActiveValidatorCount(genState, helpers.CurrentEpoch(genState))
Expand All @@ -128,7 +128,7 @@ func (s *Service) retrieveActiveValidators() (uint64, error) {
if err != nil {
return 0, err
}
if bState == nil {
if bState == nil || bState.IsNil() {
return 0, errors.Errorf("no state with root %#x exists", rt)
}
activeVals, err := helpers.ActiveValidatorCount(bState, helpers.CurrentEpoch(bState))
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/powchain/deposit.go
Expand Up @@ -17,7 +17,7 @@ func (s *Service) processDeposit(ctx context.Context, eth1Data *ethpb.Eth1Data,
if err != nil {
return errors.Wrap(err, "could not process pre-genesis deposits")
}
if beaconState != nil {
if beaconState != nil && !beaconState.IsNil() {
s.preGenesisState = beaconState
}
return nil
Expand Down
6 changes: 3 additions & 3 deletions beacon-chain/powchain/service.go
Expand Up @@ -247,7 +247,7 @@ func (s *Service) Start() {
if err != nil {
log.Fatal(err)
}
if genState == nil {
if genState == nil || genState.IsNil() {
log.Fatal("cannot create genesis state: no eth1 http endpoint defined")
}
}
Expand Down Expand Up @@ -611,7 +611,7 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*protodb.Deposit
if err != nil {
return errors.Wrap(err, "could not get finalized state")
}
if fState == nil {
if fState == nil || fState.IsNil() {
return errors.Errorf("finalized state with root %#x does not exist in the db", rt)
}
// Set deposit index to the one in the current archived state.
Expand Down Expand Up @@ -1014,7 +1014,7 @@ func (s *Service) ensureValidPowchainData(ctx context.Context) error {
return err
}
// Exit early if no genesis state is saved.
if genState == nil {
if genState == nil || genState.IsNil() {
return nil
}
eth1Data, err := s.cfg.BeaconDB.PowchainData(ctx)
Expand Down
6 changes: 3 additions & 3 deletions beacon-chain/rpc/beacon/validators_stream.go
Expand Up @@ -99,7 +99,7 @@ func (bs *Server) StreamValidatorsInfo(stream ethpb.BeaconChain_StreamValidators
if err != nil {
return status.Error(codes.Internal, "Could not access head state")
}
if headState == nil {
if headState == nil || headState.IsNil() {
return status.Error(codes.Internal, "Not ready to serve information")
}

Expand Down Expand Up @@ -260,7 +260,7 @@ func (is *infostream) generateValidatorsInfo(pubKeys [][]byte) ([]*ethpb.Validat
if err != nil {
return nil, status.Error(codes.Internal, "Could not access head state")
}
if headState == nil {
if headState == nil || headState.IsNil() {
return nil, status.Error(codes.Internal, "Not ready to serve information")
}
epoch := types.Epoch(headState.Slot() / params.BeaconConfig().SlotsPerEpoch)
Expand Down Expand Up @@ -450,7 +450,7 @@ func (is *infostream) handleBlockProcessed() {
log.Warn("Could not access head state for infostream")
return
}
if headState == nil {
if headState == nil || headState.IsNil() {
// We aren't ready to serve information
return
}
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/rpc/validator/attester.go
Expand Up @@ -90,7 +90,7 @@ func (vs *Server) GetAttestationData(ctx context.Context, req *ethpb.Attestation
return nil, status.Errorf(codes.Internal, "Could not get historical head state: %v", err)
}
}
if headState == nil {
if headState == nil || headState.IsNil() {
return nil, status.Error(codes.Internal, "Could not lookup parent state from head.")
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/rpc/validator/server.go
Expand Up @@ -154,7 +154,7 @@ func (vs *Server) WaitForChainStart(_ *emptypb.Empty, stream ethpb.BeaconNodeVal
if err != nil {
return status.Errorf(codes.Internal, "Could not retrieve head state: %v", err)
}
if head != nil {
if head != nil && !head.IsNil() {
res := &ethpb.ChainStartResponse{
Started: true,
GenesisTime: head.GenesisTime(),
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/rpc/validator/status.go
Expand Up @@ -219,7 +219,7 @@ func (vs *Server) validatorStatus(
}

func statusForPubKey(headState iface.ReadOnlyBeaconState, pubKey []byte) (ethpb.ValidatorStatus, types.ValidatorIndex, error) {
if headState == nil {
if headState == nil || headState.IsNil() {
return ethpb.ValidatorStatus_UNKNOWN_STATUS, 0, errors.New("head state does not exist")
}
idx, ok := headState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey))
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/state/interface/phase0.go
Expand Up @@ -43,6 +43,7 @@ type ReadOnlyBeaconState interface {
Slashings() []uint64
FieldReferencesCount() map[string]uint64
MarshalSSZ() ([]byte, error)
IsNil() bool
}

// WriteOnlyBeaconState defines a struct which only has write access to beacon state methods.
Expand Down
11 changes: 11 additions & 0 deletions beacon-chain/state/stateV0/state_test.go
Expand Up @@ -94,3 +94,14 @@ func TestBeaconState_NoDeadlock(t *testing.T) {
// Test will not terminate in the event of a deadlock.
wg.Wait()
}

func TestStateTrie_IsNil(t *testing.T) {
var emptyState *BeaconState
assert.Equal(t, true, emptyState.IsNil())

emptyProto := &BeaconState{state: nil}
assert.Equal(t, true, emptyProto.IsNil())

nonNilState := &BeaconState{state: &pb.BeaconState{}}
assert.Equal(t, false, nonNilState.IsNil())
}
6 changes: 6 additions & 0 deletions beacon-chain/state/stateV0/state_trie.go
Expand Up @@ -379,6 +379,12 @@ func (b *BeaconState) FieldReferencesCount() map[string]uint64 {
return refMap
}

// IsNil checks if the state and the underlying proto
// object are nil.
func (b *BeaconState) IsNil() bool {
return b == nil || b.state == nil
}

func (b *BeaconState) rootSelector(ctx context.Context, field fieldIndex) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "beaconState.rootSelector")
defer span.End()
Expand Down
6 changes: 3 additions & 3 deletions beacon-chain/state/stategen/getter.go
Expand Up @@ -78,7 +78,7 @@ func (s *State) StateByRootInitialSync(ctx context.Context, blockRoot [32]byte)
if err != nil {
return nil, errors.Wrap(err, "could not get ancestor state")
}
if startState == nil {
if startState == nil || startState.IsNil() {
return nil, errUnknownState
}
summary, err := s.stateSummary(ctx, blockRoot)
Expand Down Expand Up @@ -149,7 +149,7 @@ func (s *State) loadStateByRoot(ctx context.Context, blockRoot [32]byte) (iface.

// First, it checks if the state exists in hot state cache.
cachedState := s.hotStateCache.get(blockRoot)
if cachedState != nil {
if cachedState != nil && !cachedState.IsNil() {
return cachedState, nil
}

Expand Down Expand Up @@ -179,7 +179,7 @@ func (s *State) loadStateByRoot(ctx context.Context, blockRoot [32]byte) (iface.
if err != nil {
return nil, errors.Wrap(err, "could not get ancestor state")
}
if startState == nil {
if startState == nil || startState.IsNil() {
return nil, errUnknownBoundaryState
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/state/stategen/replay.go
Expand Up @@ -156,7 +156,7 @@ func executeStateTransitionStateGen(
func processSlotsStateGen(ctx context.Context, state iface.BeaconState, slot types.Slot) (iface.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "stategen.ProcessSlotsStateGen")
defer span.End()
if state == nil {
if state == nil || state.IsNil() {
return nil, errUnknownState
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/state/stategen/service.go
Expand Up @@ -101,7 +101,7 @@ func (s *State) Resume(ctx context.Context) (iface.BeaconState, error) {
if err != nil {
return nil, err
}
if fState == nil {
if fState == nil || fState.IsNil() {
return nil, errors.New("finalized state not found in disk")
}

Expand Down
7 changes: 7 additions & 0 deletions nogo_config.json
Expand Up @@ -84,6 +84,13 @@
".*_test\\.go": "Only tests"
}
},
"interfacechecker": {
"exclude_files": {
"external/.*": "Third party code",
"rules_go_work-.*": "Third party code",
".*/.*_test\\.go": "Tests are OK to ignore this check for"
}
},
"cryptorand": {
"only_files": {
"beacon-chain/.*": "",
Expand Down
26 changes: 26 additions & 0 deletions tools/analyzers/interfacechecker/BUILD.bazel
@@ -0,0 +1,26 @@
load("@prysm//tools/go:def.bzl", "go_library")
load("@io_bazel_rules_go//go:def.bzl", "go_tool_library")

go_library(
name = "go_default_library",
srcs = ["analyzer.go"],
importpath = "github.com/prysmaticlabs/prysm/tools/analyzers/interfacechecker",
visibility = ["//visibility:public"],
deps = [
"@org_golang_x_tools//go/analysis:go_default_library",
"@org_golang_x_tools//go/analysis/passes/inspect:go_default_library",
"@org_golang_x_tools//go/ast/inspector:go_default_library",
],
)

go_tool_library(
name = "go_tool_library",
srcs = ["analyzer.go"],
importpath = "interfacechecker",
visibility = ["//visibility:public"],
deps = [
"@org_golang_x_tools//go/analysis:go_tool_library",
"@org_golang_x_tools//go/analysis/passes/inspect:go_tool_library",
"@org_golang_x_tools//go/ast/inspector:go_tool_library",
],
)