-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Expand file tree
/
Copy pathabci.go
More file actions
120 lines (100 loc) · 4.27 KB
/
Copy pathabci.go
File metadata and controls
120 lines (100 loc) · 4.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package keeper
import (
"context"
"errors"
"fmt"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/upgrade/types"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// PreBlocker will check if there is a scheduled plan and if it is ready to be executed.
// If the current height is in the provided set of heights to skip, it will skip and clear the upgrade plan.
// If it is ready, it will execute it if the handler is installed, and panic/abort otherwise.
// If the plan is not ready, it will ensure the handler is not registered too early (and abort otherwise).
//
// The purpose is to ensure the binary is switched EXACTLY at the desired block, and to allow
// a migration to be executed if needed upon this switch (migration defined in the new binary)
// skipUpgradeHeightArray is a set of block heights for which the upgrade must be skipped
func (k Keeper) PreBlocker(ctx context.Context) error {
defer telemetry.ModuleMeasureSince(types.ModuleName, telemetry.Now(), telemetry.MetricKeyBeginBlocker)
blockHeight := k.environment.HeaderService.GetHeaderInfo(ctx).Height
plan, err := k.GetUpgradePlan(ctx)
if err != nil && !errors.Is(err, types.ErrNoUpgradePlanFound) {
return err
}
found := err == nil
sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO remove with consensus messages
if !k.DowngradeVerified() {
k.SetDowngradeVerified(true)
// This check will make sure that we are using a valid binary.
// It'll panic in these cases if there is no upgrade handler registered for the last applied upgrade.
// 1. If there is no scheduled upgrade.
// 2. If the plan is not ready.
// 3. If the plan is ready and skip upgrade height is set for current height.
if !found || !plan.ShouldExecute(blockHeight) || (plan.ShouldExecute(blockHeight) && k.IsSkipHeight(blockHeight)) {
lastAppliedPlan, _, err := k.GetLastCompletedUpgrade(ctx)
if err != nil {
return err
}
if lastAppliedPlan != "" && !k.HasHandler(lastAppliedPlan) {
var appVersion uint64
cp := sdkCtx.ConsensusParams()
if cp.Version != nil {
appVersion = cp.Version.App
}
return fmt.Errorf("wrong app version %d, upgrade handler is missing for %s upgrade plan", appVersion, lastAppliedPlan)
}
}
}
if !found {
return nil
}
logger := k.Logger(ctx)
// To make sure clear upgrade is executed at the same block
if plan.ShouldExecute(blockHeight) {
// If skip upgrade has been set for current height, we clear the upgrade plan
if k.IsSkipHeight(blockHeight) {
skipUpgradeMsg := fmt.Sprintf("UPGRADE \"%s\" SKIPPED at %d: %s", plan.Name, plan.Height, plan.Info)
logger.Info(skipUpgradeMsg)
// Clear the upgrade plan at current height
if err := k.ClearUpgradePlan(ctx); err != nil {
return err
}
return nil
}
// Prepare shutdown if we don't have an upgrade handler for this upgrade name (meaning this software is out of date)
if !k.HasHandler(plan.Name) {
// Write the upgrade info to disk. The UpgradeStoreLoader uses this info to perform or skip
// store migrations.
err := k.DumpUpgradeInfoToDisk(blockHeight, plan)
if err != nil {
return fmt.Errorf("unable to write upgrade info to filesystem: %w", err)
}
upgradeMsg := BuildUpgradeNeededMsg(plan)
logger.Error(upgradeMsg)
// Returning an error will end up in a panic
return errors.New(upgradeMsg)
}
// We have an upgrade handler for this upgrade name, so apply the upgrade
logger.Info(fmt.Sprintf("applying upgrade \"%s\" at %s", plan.Name, plan.DueAt()))
sdkCtx = sdkCtx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter())
if err := k.ApplyUpgrade(sdkCtx, plan); err != nil {
return err
}
return nil
}
// if we have a pending upgrade, but it is not yet time, make sure we did not
// set the handler already
if k.HasHandler(plan.Name) {
downgradeMsg := fmt.Sprintf("BINARY UPDATED BEFORE TRIGGER! UPGRADE \"%s\" - in binary but not executed on chain. Downgrade your binary", plan.Name)
logger.Error(downgradeMsg)
// Returning an error will end up in a panic
return errors.New(downgradeMsg)
}
return nil
}
// BuildUpgradeNeededMsg prints the message that notifies that an upgrade is needed.
func BuildUpgradeNeededMsg(plan types.Plan) string {
return fmt.Sprintf("UPGRADE \"%s\" NEEDED at %s: %s", plan.Name, plan.DueAt(), plan.Info)
}