github.com/Finschia/finschia-sdk@v0.48.1/x/upgrade/doc.go (about)

     1  /*
     2  Package upgrade provides a Cosmos SDK module that can be used for smoothly upgrading a live Cosmos chain to a
     3  new software version. It accomplishes this by providing a BeginBlocker hook that prevents the blockchain state
     4  machine from proceeding once a pre-defined upgrade block height has been reached. The module does not prescribe
     5  anything regarding how governance decides to do an upgrade, but just the mechanism for coordinating the upgrade safely.
     6  Without software support for upgrades, upgrading a live chain is risky because all of the validators need to pause
     7  their state machines at exactly the same point in the process. If this is not done correctly, there can be state
     8  inconsistencies which are hard to recover from.
     9  
    10  # General Workflow
    11  
    12  Let's assume we are running v0.38.0 of our software in our testnet and want to upgrade to v0.40.0.
    13  How would this look in practice? First of all, we want to finalize the v0.40.0 release candidate
    14  and there install a specially named upgrade handler (eg. "testnet-v2" or even "v0.40.0"). An upgrade
    15  handler should be defined in a new version of the software to define what migrations
    16  to run to migrate from the older version of the software. Naturally, this is app-specific rather
    17  than module specific, and  must be defined in `app.go`, even if it imports logic from various
    18  modules to perform the actions. You can register them with `upgradeKeeper.SetUpgradeHandler`
    19  during the app initialization (before starting the abci server), and they serve not only to
    20  perform a migration, but also to identify if this is the old or new version (eg. presence of
    21  a handler registered for the named upgrade).
    22  
    23  Once the release candidate along with an appropriate upgrade handler is frozen,
    24  we can have a governance vote to approve this upgrade at some future block height (e.g. 200000).
    25  This is known as an upgrade.Plan. The v0.38.0 code will not know of this handler, but will
    26  continue to run until block 200000, when the plan kicks in at BeginBlock. It will check
    27  for existence of the handler, and finding it missing, know that it is running the obsolete software,
    28  and gracefully exit.
    29  
    30  Generally the application binary will restart on exit, but then will execute this BeginBlocker
    31  again and exit, causing a restart loop. Either the operator can manually install the new software,
    32  or you can make use of an external watcher daemon to possibly download and then switch binaries,
    33  also potentially doing a backup. An example of such a daemon is https://github.com/cosmos/cosmos-sdk/tree/v0.40.0-rc5/cosmovisor
    34  described below under "Automation".
    35  
    36  When the binary restarts with the upgraded version (here v0.40.0), it will detect we have registered the
    37  "testnet-v2" upgrade handler in the code, and realize it is the new version. It then will run the upgrade handler
    38  and *migrate the database in-place*. Once finished, it marks the upgrade as done, and continues processing
    39  the rest of the block as normal. Once 2/3 of the voting power has upgraded, the blockchain will immediately
    40  resume the consensus mechanism. If the majority of operators add a custom `do-upgrade` script, this should
    41  be a matter of minutes and not even require them to be awake at that time.
    42  
    43  # Integrating With An App
    44  
    45  Setup an upgrade Keeper for the app and then define a BeginBlocker that calls the upgrade
    46  keeper's BeginBlocker method:
    47  
    48  	func (app *myApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
    49  		app.upgradeKeeper.BeginBlocker(ctx, req)
    50  		return abci.ResponseBeginBlock{}
    51  	}
    52  
    53  The app must then integrate the upgrade keeper with its governance module as appropriate. The governance module
    54  should call ScheduleUpgrade to schedule an upgrade and ClearUpgradePlan to cancel a pending upgrade.
    55  
    56  # Performing Upgrades
    57  
    58  Upgrades can be scheduled at a predefined block height. Once this block height is reached, the
    59  existing software will cease to process ABCI messages and a new version with code that handles the upgrade must be deployed.
    60  All upgrades are coordinated by a unique upgrade name that cannot be reused on the same blockchain. In order for the upgrade
    61  module to know that the upgrade has been safely applied, a handler with the name of the upgrade must be installed.
    62  Here is an example handler for an upgrade named "my-fancy-upgrade":
    63  
    64  	app.upgradeKeeper.SetUpgradeHandler("my-fancy-upgrade", func(ctx sdk.Context, plan upgrade.Plan) {
    65  		// Perform any migrations of the state store needed for this upgrade
    66  	})
    67  
    68  This upgrade handler performs the dual function of alerting the upgrade module that the named upgrade has been applied,
    69  as well as providing the opportunity for the upgraded software to perform any necessary state migrations. Both the halt
    70  (with the old binary) and applying the migration (with the new binary) are enforced in the state machine. Actually
    71  switching the binaries is an ops task and not handled inside the sdk / abci app.
    72  
    73  Here is a sample code to set store migrations with an upgrade:
    74  
    75  	// this configures a no-op upgrade handler for the "my-fancy-upgrade" upgrade
    76  	app.UpgradeKeeper.SetUpgradeHandler("my-fancy-upgrade",  func(ctx sdk.Context, plan upgrade.Plan) {
    77  		// upgrade changes here
    78  	})
    79  
    80  	upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
    81  	if err != nil {
    82  		// handle error
    83  	}
    84  
    85  	if upgradeInfo.Name == "my-fancy-upgrade" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
    86  		storeUpgrades := store.StoreUpgrades{
    87  			Renamed: []store.StoreRename{{
    88  				OldKey: "foo",
    89  				NewKey: "bar",
    90  			}},
    91  			Deleted: []string{},
    92  		}
    93  
    94  		// configure store loader that checks if version == upgradeHeight and applies store upgrades
    95  		app.SetStoreLoader(upgrade.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
    96  	}
    97  
    98  # Halt Behavior
    99  
   100  Before halting the ABCI state machine in the BeginBlocker method, the upgrade module will log an error
   101  that looks like:
   102  
   103  	UPGRADE "<Name>" NEEDED at height <NNNN>: <Info>
   104  
   105  where Name are Info are the values of the respective fields on the upgrade Plan.
   106  
   107  To perform the actual halt of the blockchain, the upgrade keeper simply panics which prevents the ABCI state machine
   108  from proceeding but doesn't actually exit the process. Exiting the process can cause issues for other nodes that start
   109  to lose connectivity with the exiting nodes, thus this module prefers to just halt but not exit.
   110  
   111  # Automation and Plan.Info
   112  
   113  We have deprecated calling out to scripts, instead with propose https://github.com/cosmos/cosmos-sdk/tree/v0.40.0-rc5/cosmovisor
   114  as a model for a watcher daemon that can launch simd as a subprocess and then read the upgrade log message
   115  to swap binaries as needed. You can pass in information into Plan.Info according to the format
   116  specified here https://github.com/cosmos/cosmos-sdk/tree/v0.40.0-rc5/cosmovisor/README.md#auto-download .
   117  This will allow a properly configured cosmsod daemon to auto-download new binaries and auto-upgrade.
   118  As noted there, this is intended more for full nodes than validators.
   119  
   120  # Cancelling Upgrades
   121  
   122  There are two ways to cancel a planned upgrade - with on-chain governance or off-chain social consensus.
   123  For the first one, there is a CancelSoftwareUpgrade proposal type, which can be voted on and will
   124  remove the scheduled upgrade plan. Of course this requires that the upgrade was known to be a bad idea
   125  well before the upgrade itself, to allow time for a vote. If you want to allow such a possibility, you
   126  should set the upgrade height to be 2 * (votingperiod + depositperiod) + (safety delta) from the beginning of
   127  the first upgrade proposal. Safety delta is the time available from the success of an upgrade proposal
   128  and the realization it was a bad idea (due to external testing). You can also start a CancelSoftwareUpgrade
   129  proposal while the original SoftwareUpgrade proposal is still being voted upon, as long as the voting
   130  period ends after the SoftwareUpgrade proposal.
   131  
   132  However, let's assume that we don't realize the upgrade has a bug until shortly before it will occur
   133  (or while we try it out - hitting some panic in the migration). It would seem the blockchain is stuck,
   134  but we need to allow an escape for social consensus to overrule the planned upgrade. To do so, there's
   135  a --unsafe-skip-upgrades flag to the start command, which will cause the node to mark the upgrade
   136  as done upon hitting the planned upgrade height(s), without halting and without actually performing a migration.
   137  If over two-thirds run their nodes with this flag on the old binary, it will allow the chain to continue through
   138  the upgrade with a manual override. (This must be well-documented for anyone syncing from genesis later on).
   139  
   140  Example:
   141  
   142  	simd start --unsafe-skip-upgrades <height1> <optional_height_2> ... <optional_height_N>
   143  
   144  NOTE: Here simd is used as an example binary, replace it with original binary
   145  */
   146  package upgrade