-
Notifications
You must be signed in to change notification settings - Fork 11.3k
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
Package Upgrade documentation #10475
Changes from 8 commits
2fdabd2
c744e5a
57ec6e3
6f77af1
fc24719
d5f20bf
9f7b689
07e627a
4a0b171
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,283 @@ | ||
--- | ||
title: Package Upgrades | ||
--- | ||
|
||
Sui smart contracts are represented by immutable package objects consisting of a collection of Move modules. Because the packages are immutable, transactions can safely access smart contracts without full consensus (fast-path transactions). If someone could change these packages, they would become [shared objects](../learn/objects.md#shared), which would require full consensus before completing a transaction. | ||
|
||
The inability to change package objects, however, becomes a problem when considering the iterative nature of code development. Builders require the ability to update their code and pull changes from other developers while still being able to reap the benefits of fast-path transactions. Fortunately, the Sui network provides a method of upgrading your packages while still retaining their immutable properties. | ||
|
||
This topic examines how to upgrade packages using the Sui Client CLI. Move developers can reference the [package module documentation](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/package.md) for options on working with package upgrades on a code level. | ||
|
||
## Requirements | ||
|
||
To upgrade a package, your package must satisfy the following requirements: | ||
* You must have an `UpgradeTicket` for the package you want to upgrade. The Sui network issues `UpgradeCap`s when you publish a package, then you can issue `UpgradeTicket`s as the owner of that `UpgradeCap`. The Sui Client CLI handles this requirement automatically. | ||
* Your changes must be layout-compatible with the previous version. | ||
* Existing `public` function signatures and struct layouts must remain the same. | ||
* You can add new structs and functions. | ||
* You can add abilities to existing structs. | ||
* You can remove generic type constraints from existing functions (public or otherwise). | ||
* You can change function implementations. | ||
* You can change non-`public` function signatures, including `friend` and `entry` function signatures. | ||
|
||
**Note:** If you have a package with a dependency, and that dependency is upgraded, your package does not automatically depend on the newer version. You must explicitly upgrade your own package to point to the new dependency. | ||
|
||
## Upgrading | ||
|
||
Use the `sui client upgrade` command to upgrade packages that meet the previous requirements, providing values for the following flags: | ||
|
||
* `--gas-budget`: The maximum number of gas units that can be expended before the network cancels the transaction. | ||
* `--cap`: The ID of the `UpgradeCap`. You receive this ID as a return from the publish command. | ||
|
||
Developers upgrading packages using Move code have access to types and functions to define custom upgrade policies. For example, a Move developer might want to disallow upgrading a package, regardless of the current package owner. The [`make_immutable` function](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/package.md#0x2_package_make_immutable) is available to them to create this behavior. More advanced policies using available types like `UpgradeTicket` and `Upgrade Receipt` are also possible. For an example, see this [custom upgrade policy](https://github.com/MystenLabs/sui/issues/2045#:~:text=Implement%20a%20custom%20upgrade%20policy) on GitHub. | ||
|
||
When you use the Sui Client CLI, the `upgrade` command handles generating the upgrade digest, authorizing the upgrade with the `UpgradeCap` to get an `UpgradeTicket`, and updating the `UpgradeCap` with the `UpgradeReceipt` after a successful upgrade. To learn more about these processes, see the Move documentation for the [package module](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/package.md). | ||
|
||
## Example | ||
|
||
You develop a package named `sui_package`. Its manifest looks like the following: | ||
|
||
```move | ||
[package] | ||
name = "sui_package" | ||
version = "0.0.0" | ||
|
||
[addresses] | ||
sui_package = "0x0" | ||
``` | ||
|
||
When your package is ready, you publish it: | ||
|
||
```shell | ||
sui client publish --gas-budget <GAS-BUDGET-AMOUNT> | ||
``` | ||
And receive the response: | ||
|
||
```shell | ||
INCLUDING DEPENDENCY Sui | ||
INCLUDING DEPENDENCY MoveStdlib | ||
BUILDING MyFirstPackage | ||
Successfully verified dependencies on-chain against source. | ||
----- Transaction Digest ---- | ||
2bn3EtHvbVY4bM1887MvFiGWnqq1YZ2RKmbeK7TrRbLL | ||
----- Transaction Data ---- | ||
Transaction Signature: [Signature(Ed25519SuiSignature(Ed25519SuiSignature([0, 156, 133, 71, 156, 44, 204, 30, 31, 250, 204, 247, 60, 212, 249, 61, 112, 249, 148, 180, 83, 207, 236, 58, 99, 134, 5, 174, 115, 226, 41, 139, 192, 1, 183, 133, 38, 73, 254, 205, 190, 54, 210, 112, 144, 204, 137, 3, 8, 30, 165, 147, 120, 199, 227, 119, 53, 208, 28, 101, 34, 239, 102, 210, 1, 103, 111, 108, 165, 156, 100, 95, 13, 236, 27, 13, 127, 150, 50, 47, 155, 217, 27, 164, 61, 245, 254, 81, 182, 121, 231, 58, 150, 214, 46, 27, 222])))] | ||
Transaction Kind : Programmable | ||
Inputs: [Pure(SuiPureValue { value_type: Some(Address), value: "<PUBLISHER-ID>" })] | ||
Commands: [ | ||
Publish(_,,0x00000000000000000000000000000000000000000000000000000000000000010x0000000000000000000000000000000000000000000000000000000000000002), | ||
TransferObjects([Result(0)],Input(0)), | ||
] | ||
|
||
Sender: <PUBLISHER-ID> | ||
Gas Payment: Object ID:, version: 0x6, digest: HLAcq3SFPZm4xvcPryXk5MjA718xGVnTYCdtWbFsaJpe | ||
Gas Owner: <PUBLISHER-ID> | ||
Gas Price: 1 | ||
Gas Budget: <GAS-BUDGET-AMOUNT> | ||
|
||
----- Transaction Effects ---- | ||
Status : Success | ||
Created Objects: | ||
- ID: <ORIGINAL-PACKAGE-ID> , Owner: Immutable | ||
- ID: <UPGRADE-CAP-ID> , Owner: Account Address ( <PUBLISHER-ID> ) | ||
- ID: <PUBLISHER-ID> , Owner: Account Address ( <PUBLISHER-ID> ) | ||
Mutated Objects: | ||
- ID: <GAS-COIN-ID> , Owner: Account Address ( <PUBLISHER-ID> ) | ||
|
||
----- Events ---- | ||
Array [] | ||
----- Object changes ---- | ||
Array [ | ||
Object { | ||
"type": String("mutated"), | ||
"sender": String("<PUBLISHER-ID>"), | ||
"owner": Object { | ||
"AddressOwner": String("<PUBLISHER-ID>"), | ||
}, | ||
"objectType": String("0x2::coin::Coin<0x2::sui::SUI>"), | ||
"objectId": String("<GAS-COIN-ID>"), | ||
"version": Number(7), | ||
"previousVersion": Number(6), | ||
"digest": String("6R39f68p4tGqJWJTakKCyL8tz2w2XTvJ3Mu5nGwxadda"), | ||
}, | ||
Object { | ||
"type": String("published"), | ||
"packageId": String("<ORIGINAL-PACKAGE-ID>"), | ||
"version": Number(1), | ||
"digest": String("FrBhLF2Rn4jP3SUsss7aXqwDDRtoKxgGbPm8eVkH7jrQ"), | ||
"modules": Array [ | ||
String("sui_package"), | ||
], | ||
}, | ||
Object { | ||
"type": String("created"), | ||
"sender": String("<PUBLISHER-ID>"), | ||
"owner": Object { | ||
"AddressOwner": String("<PUBLISHER-ID>"), | ||
}, | ||
"objectType": String("0x2::package::UpgradeCap"), | ||
"objectId": String("<UPGRADE-CAP-ID>"), | ||
"version": Number(7), | ||
"digest": String("BoGQ63r27DFZDMC8p7YwRcDpToFpbZ9rG1R4o4uXkaUw"), | ||
}, | ||
Object { | ||
"type": String("created"), | ||
"sender": String("<PUBLISHER-ID>"), | ||
"owner": Object { | ||
"AddressOwner": String("<PUBLISHER-ID>"), | ||
}, | ||
"objectType": String("<ORIGINAL-PACKAGE-ID>::sui_package::<MODULE-NAME>"), | ||
"objectId": String("<PUBLISHER-ID>"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the objectID matches the publisher ID? |
||
"version": Number(7), | ||
"digest": String("BC3KeuATKJozLNipbUz2GWzoDXbodXH4HLm59TxJSmVd"), | ||
}, | ||
] | ||
----- Balance changes ---- | ||
Array [ | ||
Object { | ||
"owner": Object { | ||
"AddressOwner": String("<PUBLISHER-ID>"), | ||
}, | ||
"coinType": String("0x2::sui::SUI"), | ||
"amount": String("-9328480"), | ||
}, | ||
] | ||
``` | ||
|
||
The result includes an **Object changes** section with two pieces of information you need for upgrading, an `UpgradeCap` ID and your package ID. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does it need the |
||
|
||
You can identify the different objects using the `Object.objectType` value in the response. The `UpgradeCap` entry has a value of `String("0x2::package::UpgradeCap")` and the `objectType` for the package reads `String("<PACKAGE-ID>::sui_package::<MODULE-NAME>")` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it calls out package ID but then says |
||
|
||
To make sure your other packages can use this package as a dependency, you must update the manifest (Move.toml file) for your package to include this information. | ||
|
||
Update the alias address and add a new `published-at` entry in the `[package]` section, both pointing to the value of the on-chain ID: | ||
|
||
```toml | ||
[package] | ||
name = "sui_package" | ||
version = "0.0.0" | ||
published-at = "<ORIGINAL-PACKAGE-ID>" | ||
|
||
[addresses] | ||
sui_package = "<ORIGINAL-PACKAGE-ID>" | ||
``` | ||
|
||
The `published-at` value allows the Move compiler to verify dependencies against on-chain versions of those packages. | ||
|
||
After a while, you decide to upgrade your `sui_package` to include some requested features. Before running the `upgrade` command, you need to edit the manifest again. In the `[addresses]` section, you update the `sui_package` address value to `0x0` again so the validator issues a new address for the upgrade package. You can leave the `published-at` value the same, because it is only read by the toolchain when publishing a dependent package. The saved manifest now resembles the following: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. validator - Since this is a specific node type is there a different word to use here? |
||
|
||
```toml | ||
[package] | ||
name = "sui_package" | ||
version = "0.0.1" | ||
published-at = "<ORIGINAL-PACKAGE-ID>" | ||
|
||
[addresses] | ||
sui_package = "0x0" | ||
``` | ||
|
||
With the new manifest and code in place, it's time to use the `sui client upgrade` command to upgrade your package. Pass the `UpgradeCap` ID to the `--upgrade-capability` flag. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in the example output this is UPGRADE CAP ID |
||
|
||
```shell | ||
sui client upgrade --gas-budget <GAS-BUDGET-AMOUNT> --upgrade-capability <UPGRADE-CAP-ID> | ||
``` | ||
|
||
The console alerts you if the new package doesn't satisfy [requirements](#requirements), otherwise the compiler publishes the upgraded package to the network and returns its result: | ||
|
||
```shell | ||
INCLUDING DEPENDENCY Sui | ||
INCLUDING DEPENDENCY MoveStdlib | ||
BUILDING MyFirstPackage | ||
Successfully verified dependencies on-chain against source. | ||
----- Transaction Digest ---- | ||
HZdnGWE2VoqDWwBhoBwe17tDFn7uYgfBpK5nk75Rmh5z | ||
----- Transaction Data ---- | ||
Transaction Signature: [Signature(Ed25519SuiSignature(Ed25519SuiSignature([0, 108, 166, 235, 244, 238, 72, 232, 143, 49, 225, 180, 55, 63, 131, 155, 146, 126, 50, 158, 138, 213, 174, 71, 162, 222, 62, 198, 245, 219, 224, 171, 82, 43, 197, 56, 16, 252, 186, 83, 154, 109, 104, 90, 212, 236, 122, 78, 175, 173, 107, 9, 2, 10, 30, 74, 101, 138, 228, 251, 170, 39, 25, 242, 8, 103, 111, 108, 165, 156, 100, 95, 13, 236, 27, 13, 127, 150, 50, 47, 155, 217, 27, 164, 61, 245, 254, 81, 182, 121, 231, 58, 150, 214, 46, 27, 222])))] | ||
Transaction Kind : Programmable | ||
Inputs: [Object(ImmOrOwnedObject { object_id: <UPGRADE-CAP-ID>, version: SequenceNumber(9), digest: o#Bvy7R33o4ogLuyfzM76nmM1RqKnEALQrbd34CLWZhf5Y }), Pure(SuiPureValue { value_type: Some(U8), value: 0 }), Pure(SuiPureValue { value_type: Some(Vector(U8)), value: [202,122,179,32,64,155,14,236,160,5,75,17,159,202,125,114,234,36,182,41,159,84,56,222,99,121,250,82,206,19,212,5] })] | ||
Commands: [ | ||
MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::package::authorize_upgrade(,Input(0),Input(1)Input(2))), | ||
Upgrade(Result(0),,0x00000000000000000000000000000000000000000000000000000000000000010x0000000000000000000000000000000000000000000000000000000000000002, <ORIGINAL-PACKAGE-ID>, _)), | ||
MoveCall(0x0000000000000000000000000000000000000000000000000000000000000002::package::commit_upgrade(,Input(0)Result(1))), | ||
] | ||
|
||
Sender: <PUBLISHER-ID> | ||
Gas Payment: Object ID: <GAS-COIN-ID>, version: 0x9, digest: 84ZKQcZZLTCmyAoRp9QhDrxxZ7nzGtdoBw18UbNm26ad | ||
Gas Owner: <PUBLISHER-ID> | ||
Gas Price: 1 | ||
Gas Budget: <GAS-BUDGET-AMOUNT> | ||
|
||
----- Transaction Effects ---- | ||
Status : Success | ||
Created Objects: | ||
- ID: <MODULE-ID> , Owner: Immutable | ||
Mutated Objects: | ||
- ID: <GAS-COIN-ID> , Owner: Account Address ( <PUBLISHER-ID> ) | ||
- ID: <UPGRADE-CAP-ID> , Owner: Account Address ( <PUBLISHER-ID> ) | ||
|
||
----- Events ---- | ||
Array [] | ||
----- Object changes ---- | ||
Array [ | ||
Object { | ||
"type": String("mutated"), | ||
"sender": String("<PUBLISHER-ID>"), | ||
"owner": Object { | ||
"AddressOwner": String("<PUBLISHER-ID>"), | ||
}, | ||
"objectType": String("0x2::coin::Coin<0x2::sui::SUI>"), | ||
"objectId": String("<GAS-COIN-ID>"), | ||
"version": Number(10), | ||
"previousVersion": Number(9), | ||
"digest": String("EvfMLHBDXFRUeMd7vgmAMaacnwZbGFHg8d7Kov3fTt9L"), | ||
}, | ||
Object { | ||
"type": String("mutated"), | ||
"sender": String("<PUBLISHER-ID>"), | ||
"owner": Object { | ||
"AddressOwner": String("<PUBLISHER-ID>"), | ||
}, | ||
"objectType": String("0x2::package::UpgradeCap"), | ||
"objectId": String("<UPGRADE-CAP-ID>"), | ||
"version": Number(10), | ||
"previousVersion": Number(9), | ||
"digest": String("FZ9AruCAnhjW8zrozUMgtsY79SggTiHr3suwZNe5eMnM"), | ||
}, | ||
Object { | ||
"type": String("published"), | ||
"packageId": String("<UPGRADED-PACKAGE-ID>"), | ||
"version": Number(2), | ||
"digest": String("8RDsE6kFND2V2gxGiytwxa815mctwxNh7A8YqRS4AJME"), | ||
"modules": Array [ | ||
String("<MODULE-NAME>"), | ||
], | ||
}, | ||
] | ||
----- Balance changes ---- | ||
Array [ | ||
Object { | ||
"owner": Object { | ||
"AddressOwner": String("<PUBLISHER-ID>"), | ||
}, | ||
"coinType": String("0x2::sui::SUI"), | ||
"amount": String("-6350420"), | ||
}, | ||
] | ||
|
||
|
||
``` | ||
|
||
The result provides a new ID for the upgraded package. As was the case before the upgrade, you need to include that information in your manifest so any of your other packages that depend on your `sui_package` know where to find the on-chain bytecode for verification. Edit your manifest once again to provide the upgraded package ID for the `published-at` value, and return the original `sui_package` ID value in the `[addresses]` section: | ||
|
||
|
||
```move | ||
[package] | ||
name = "sui_package" | ||
version = "0.0.1" | ||
published-at = "<UPGRADED-PACKAGE-ID>" | ||
|
||
[addresses] | ||
sui_package = "<ORIGINAL-PACKAGE-ID>" | ||
``` | ||
|
||
The `published-at` value changes with every upgrade. The ID for the `sui_package` in the `[addresses]` section always points to the original ID after upgrading. You must always change that value back to `0x0`, however, before running the `upgrade` command so the validator knows to create a new ID for the upgrade. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. original package ID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this the address of the package owner? Is it confusing to introduce a new ID type in this topic that is used only in this topic?