diff --git a/.changelog/4110.bugfix.md b/.changelog/4110.bugfix.md new file mode 100644 index 00000000000..0cdb003d0b0 --- /dev/null +++ b/.changelog/4110.bugfix.md @@ -0,0 +1,5 @@ +go/consensus/tendermint: Correctly propagate errors + +Not propagating the state unavailable error could lead to corruption when the +database becomes unavailable (e.g., due to running out of space or file +descriptors). diff --git a/go/consensus/tendermint/apps/staking/proposing_rewards.go b/go/consensus/tendermint/apps/staking/proposing_rewards.go index bfcee2344f8..0adf3bc7a0a 100644 --- a/go/consensus/tendermint/apps/staking/proposing_rewards.go +++ b/go/consensus/tendermint/apps/staking/proposing_rewards.go @@ -11,6 +11,7 @@ import ( abciAPI "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/api" registryState "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/apps/registry/state" stakingState "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/apps/staking/state" + registry "github.com/oasisprotocol/oasis-core/go/registry/api" staking "github.com/oasisprotocol/oasis-core/go/staking/api" ) @@ -18,18 +19,20 @@ func (app *stakingApplication) resolveEntityIDFromProposer( ctx *abciAPI.Context, regState *registryState.MutableState, request types.RequestBeginBlock, -) *signature.PublicKey { - var proposingEntity *signature.PublicKey +) (*signature.PublicKey, error) { proposerNode, err := regState.NodeByConsensusAddress(ctx, request.Header.ProposerAddress) - if err != nil { + switch err { + case nil: + case registry.ErrNoSuchNode: ctx.Logger().Warn("failed to get proposer node", "err", err, "address", hex.EncodeToString(request.Header.ProposerAddress), ) - } else { - proposingEntity = &proposerNode.EntityID + return nil, nil + default: + return nil, err } - return proposingEntity + return &proposerNode.EntityID, nil } func (app *stakingApplication) rewardBlockProposing( diff --git a/go/consensus/tendermint/apps/staking/staking.go b/go/consensus/tendermint/apps/staking/staking.go index 7ca84c177fa..dd786a5cf7b 100644 --- a/go/consensus/tendermint/apps/staking/staking.go +++ b/go/consensus/tendermint/apps/staking/staking.go @@ -59,16 +59,22 @@ func (app *stakingApplication) BeginBlock(ctx *api.Context, request types.Reques stakeState := stakingState.NewMutableState(ctx.State()) // Look up the proposer's entity. - proposingEntity := app.resolveEntityIDFromProposer(ctx, regState, request) + proposingEntity, err := app.resolveEntityIDFromProposer(ctx, regState, request) + if err != nil { + return fmt.Errorf("failed to resolve proposer entity ID: %w", err) + } // Go through all voters of the previous block and resolve entities. // numEligibleValidators is how many total validators are in the validator set, while // votingEntities is from the validators which actually voted. numEligibleValidators := len(request.GetLastCommitInfo().Votes) - votingEntities := app.resolveEntityIDsFromVotes(ctx, regState, request.GetLastCommitInfo()) + votingEntities, err := app.resolveEntityIDsFromVotes(ctx, regState, request.GetLastCommitInfo()) + if err != nil { + return fmt.Errorf("failed to resolve entity IDs from votes: %w", err) + } // Disburse fees from previous block. - if err := app.disburseFeesVQ(ctx, stakeState, proposingEntity, numEligibleValidators, votingEntities); err != nil { + if err = app.disburseFeesVQ(ctx, stakeState, proposingEntity, numEligibleValidators, votingEntities); err != nil { return fmt.Errorf("disburse fees voters and next proposer: %w", err) } @@ -76,12 +82,12 @@ func (app *stakingApplication) BeginBlock(ctx *api.Context, request types.Reques stakingState.SetBlockProposer(ctx, proposingEntity) // Add rewards for proposer. - if err := app.rewardBlockProposing(ctx, stakeState, proposingEntity, numEligibleValidators, len(votingEntities)); err != nil { + if err = app.rewardBlockProposing(ctx, stakeState, proposingEntity, numEligibleValidators, len(votingEntities)); err != nil { return fmt.Errorf("staking: block proposing reward: %w", err) } // Track signing for rewards. - if err := app.updateEpochSigning(ctx, stakeState, votingEntities); err != nil { + if err = app.updateEpochSigning(ctx, stakeState, votingEntities); err != nil { return fmt.Errorf("staking: failed to update epoch signing info: %w", err) } @@ -101,7 +107,7 @@ func (app *stakingApplication) BeginBlock(ctx *api.Context, request types.Reques continue } - if err := onEvidenceByzantineConsensus(ctx, reason, evidence.Validator.Address, evidence.Height, evidence.Time, evidence.Validator.Power); err != nil { + if err = onEvidenceByzantineConsensus(ctx, reason, evidence.Validator.Address, evidence.Height, evidence.Time, evidence.Validator.Power); err != nil { return err } } diff --git a/go/consensus/tendermint/apps/staking/votes.go b/go/consensus/tendermint/apps/staking/votes.go index bdc44f54cdd..ccf33950543 100644 --- a/go/consensus/tendermint/apps/staking/votes.go +++ b/go/consensus/tendermint/apps/staking/votes.go @@ -8,9 +8,14 @@ import ( "github.com/oasisprotocol/oasis-core/go/common/crypto/signature" abciAPI "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/api" registryState "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/apps/registry/state" + registry "github.com/oasisprotocol/oasis-core/go/registry/api" ) -func (app *stakingApplication) resolveEntityIDsFromVotes(ctx *abciAPI.Context, regState *registryState.MutableState, lastCommitInfo types.LastCommitInfo) []signature.PublicKey { +func (app *stakingApplication) resolveEntityIDsFromVotes( + ctx *abciAPI.Context, + regState *registryState.MutableState, + lastCommitInfo types.LastCommitInfo, +) ([]signature.PublicKey, error) { var entityIDs []signature.PublicKey for _, a := range lastCommitInfo.Votes { if !a.SignedLastBlock { @@ -20,16 +25,20 @@ func (app *stakingApplication) resolveEntityIDsFromVotes(ctx *abciAPI.Context, r // Map address to node/entity. node, err := regState.NodeByConsensusAddress(ctx, valAddr) - if err != nil { + switch err { + case nil: + case registry.ErrNoSuchNode: ctx.Logger().Warn("failed to get validator node", "err", err, "address", hex.EncodeToString(valAddr), ) continue + default: + return nil, err } entityIDs = append(entityIDs, node.EntityID) } - return entityIDs + return entityIDs, nil }