Use dubhe to migrate a contract
β οΈ This tutorial uses the Dubhe v1 API (
Schema,counter_schema,dapp__version, etc.) and is no longer accurate for Dubhe v2. In v2, storage is split intoDappStorageandUserStorage; version bumping is handled automatically bydubhe upgrade --bump-version; andmigrate_to_vNis generated by the toolchain rather than written by hand.For the current upgrade workflow, see Contract Upgrading.
Because there is always the possibility of bugs or new logic being added to a written contract, it becomes necessary to upgrade the contract.
This section describes how to use Dubhe for versioning and upgrading contracts. Take the 101 contract as an example of a contract upgrade
Setting up a project
β pnpm create dubhe
Downloading registry.npmjs.org/create-dubhe/0.0.11: 8.98 MB/8.98 MB, done
../Library/pnpm/store/v3/tmp/dlx-54343 | +149 +++++++++++++++
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: /Library/pnpm/store/v3
Virtual store is at: ../Library/pnpm/store/v3/tmp/dlx-54343/node_modules/.pnpm
../Library/pnpm/store/v3/tmp/dlx-54343 | Progress: resolved 149, reused 146, downloaded 3, added 149, done
β Input your projectName. β¦ dubhe-template-project
β Pick your chain. βΊ sui
β Pick your platform. βΊ 101
============================================================
π Project creation successful!
π Project location: /Project/dubhe-template-project
------------------------------------------------------------
Next steps:
cd dubhe-template-project
pnpm install
============================================================cd dubhe-template-project && pnpm installStart a Local Node
β pnpm dubhe node
Welcome to Dubhe
--from team@obelisk
________ ___ ___ ________ ___ ___ _______
|\ ___ \|\ \|\ \|\ __ \|\ \|\ \|\ ___ \
\ \ \_|\ \ \ \\\ \ \ \|\ /\ \ \\\ \ \ __/|
\ \ \ \\ \ \ \\\ \ \ __ \ \ __ \ \ \_|/__
\ \ \_\\ \ \ \\\ \ \ \|\ \ \ \ \ \ \ \_|\ \
\ \_______\ \_______\ \_______\ \__\ \__\ \_______\
\|_______|\|_______|\|_______|\|__|\|__|\|_______|
π Starting Local Node...
ββ Faucet: Enabled
ββ Force Regenesis: Yes
ββ HTTP server: http://127.0.0.1:9000/
ββ Faucet server: http://127.0.0.1:9123/
πAccounts
==========
ββ Account #0: 0xe7f93ad7493035bcd674f287f78526091e195a6df9d64f23def61a7ce3adada9(1000 SUI)
ββ Private Key: suiprivkey1qq3ez3dje66l8pypgxynr7yymwps6uhn7vyczespj84974j3zya0wdpu76v
ββ Account #1: 0x492404a537c32b46610bd6ae9f7f16ba16ff5a607d272543fe86cada69d8cf44(1000 SUI)
ββ Private Key: suiprivkey1qp6vcyg8r2x88fllmjmxtpzjl95gd9dugqrgz7xxf50w6rqdqzetg7x4d7s
ββ Account #2: 0xd27e203483700d837a462d159ced6104619d8e36f737bf2a20c251153bf39f24(1000 SUI)
ββ Private Key: suiprivkey1qpy3a696eh3m55fwa8h38ss063459u4n2dm9t24w2hlxxzjp2x34q8sdsnc
ββ Account #3: 0x018f1f175c9b6739a14bc9c81e7984c134ebf9031015cf796fefcef04b8c4990(1000 SUI)
ββ Private Key: suiprivkey1qzxwp29favhzrjd95f6uj9nskjwal6nh9g509jpun395y6g72d6jqlmps4c
ββ Account #4: 0x932f6aab2bc636a25374f99794dc8451c4e27c91e87083e301816ed08bc98ed0(1000 SUI)
ββ Private Key: suiprivkey1qzhq4lv38sesah4uzsqkkmeyjx860xqjdz8qgw36tmrdd5tnle3evxpng57
ββ Account #5: 0x9a66b2da3036badd22529e3de8a00b0cd7dbbfe589873aa03d5f885f5f8c6501(1000 SUI)
ββ Private Key: suiprivkey1qzez45sjjsepjgtksqvpq6jw7dzw3zq0dx7a4sulfypd73acaynw5jl9x2c
==========
β οΈWARNING: These accounts, and their private keys, are publicly known.
Any funds sent to them on Mainnet or any other live network WILL BE LOST.
Check the current main code
import { DubheConfig, storage } from '@0xobelisk/sui-common';
export const dubheConfig = {
name: 'counter',
description: 'counter contract',
schemas: {
value: storage('u32')
},
events: {
increment: { value: 'u32' }
},
errors: {
invalid_increment: "Number can't be incremented, must be more than 0"
}
} as DubheConfig;module counter::counter_system {
use counter::counter_schema::Schema;
use counter::counter_events::increment_event;
use counter::counter_errors::invalid_increment_error;
public entry fun inc(schema: &mut Schema, number: u32) {
// Check if the increment value is valid.
invalid_increment_error(number > 0 && number < 100);
let value = schema.value()[];
schema.value().set(value + number);
increment_event(number);
}
}module counter::counter_migrate {
use counter::counter_schema::Schema;
const ON_CHAIN_VERSION: u32 = 1;
public fun on_chain_version(): u32 {
ON_CHAIN_VERSION
}
}Add version checking code
import { DubheConfig, storage } from '@0xobelisk/sui-common';
export const dubheConfig = {
name: 'counter',
description: 'counter contract',
schemas: {
value: storage('u32')
},
events: {
increment: { value: 'u32' }
},
errors: {
invalid_increment: "Number can't be incremented, must be more than 0",
invalid_version: 'The version must be up to date'
}
} as DubheConfig;Execute the generate command
pnpm dubhe generateDetermine if the version is up to date
module counter::counter_system {
use counter::counter_schema::Schema;
use counter::counter_events::increment_event;
use counter::counter_errors::{invalid_increment_error, invalid_version_error};
use counter::counter_migrate::on_chain_version;
public entry fun inc(schema: &mut Schema, number: u32) {
// Check if it is the latest version
invalid_version_error(schema.dapp__version()[] == on_chain_version());
// Check if the increment value is valid.
invalid_increment_error(number > 0 && number < 100);
let value = schema.value()[];
schema.value().set(value + number);
increment_event(number);
}
}β pnpm dubhe publish
π Starting Contract Publication...
ββ Project: /Volumes/project/dubhe/packages/sui-cli/contracts/dubhe-framework
ββ Network: localnet
ββ Account: 0x018f1f175c9b6739a14bc9c81e7984c134ebf9031015cf796fefcef04b8c4990
π¦ Building Contract...
π Publishing Contract...
ββ Package ID: 0x47948f7ec4622cbf3ec0fa7f2621a55980587102bf928d39d8bc03100ef03b4e
ββ Upgrade Cap: 0x86048d1548551a6a025c49c6e50fc71eacd4057064299fa8ffdd45db39f436fd
ββ Transaction: A5UXiyLjjQ7d8G2vGsys31zUvZx2zVKvFCfSAdJ7ZWG
Update deploy log: /Volumes/project/dubhe/packages/sui-cli/contracts/dubhe-framework/.history/sui_localnet/latest.json
β
Dubhe Framework deployed successfully
Updated Dubhe dependency in /Volumes/project/dubhe/packages/sui-cli/contracts/counter/Move.toml for localnet.
π Starting Contract Publication...
ββ Project: /Volumes/project/dubhe/packages/sui-cli/contracts/counter
ββ Network: localnet
ββ ChainId: 90dbabed
ββ Validating Environment...
ββ Account: 0x018f1f175c9b6739a14bc9c81e7984c134ebf9031015cf796fefcef04b8c4990
π¦ Building Contract...
π Publishing Contract...
ββ Processing publication results...
ββ Upgrade Cap: 0x20bcea3558938d4c1b03a8cab5d26ec9656f90a82fa49397d8ce6123573608d6
ββ Package ID: 0xd45e866f9d87b197913c10dcc1b16c311787a267447d9ded36c96bbca1534f33
ββ Transaction: 8jSgk1dNCuaG1eBFRPFg69Jstip9PKi168b3AXEdEn4t
β‘ Executing Deploy Hook...
ββ Hook execution successful
ββ Transaction: 54MNe2PRRoQHSuCCQ3jvjTHZQYjuB9NFcxv9pg8KysSY
π Created Schemas:
ββ 0xd45e866f9d87b197913c10dcc1b16c311787a267447d9ded36c96bbca1534f33::counter_schema::Schema
ββ ID: 0x9b884efc078de5f4ca9aeefa7203fa34b29be535f80b84c905549fe4b067c279
Update deploy log: /Volumes/project/dubhe/packages/sui-cli/contracts/counter/.history/sui_localnet/latest.json
β
Contract Publication Complete
Migrate a contract
Migrating contracts need to follow the basic guidelines of Sui Move upgrades, otherwise the upgrade will fail.
- Generate a new schema: value_v2, used to record the current number and the last number.
- Parameter number from 0-100 reduced to 0-10.
- Migrate value from the original value schema to the value_v2 schema.
Create a new schema
import { DubheConfig, storage } from '@0xobelisk/sui-common';
export const dubheConfig = {
name: 'counter',
description: 'counter contract',
data: {
Number: { last_number: 'u32', current_number: 'u32' }
}
schemas: {
value: storage('u32'),
value_v2: storage('Number'),
},
events: {
increment: { value: 'u32' },
},
errors: {
invalid_increment: "Number can't be incremented, must be more than 0",
invalid_version: "The version must be up to date"
},
} as DubheConfig;Execute the generate command
pnpm dubhe generateModify the limitations of the number parameter, deprecate value in favor of value_2
module counter::counter_system {
use counter::counter_schema::Schema;
use counter::counter_events::increment_event;
use counter::counter_errors::{invalid_increment_error, invalid_version_error};
use counter::counter_migrate::on_chain_version;
use counter::counter_number;
public entry fun inc(schema: &mut Schema, number: u32) {
// Check if it is the latest version
invalid_version_error(schema.dapp__version()[] == on_chain_version());
// Check if the increment value is valid.
invalid_increment_error(number > 0 && number < 10);
let (_, current_number) = schema.value_v2()[].get();
let number_v2 = counter_number::new(current_number, current_number + number);
schema.value_v2().set(number_v2);
increment_event(number);
}
}Writing migration scripts, Please note that the migrated method must have a version number after migrateto,
For example if you migrate from v1 to v2 then your migration method is migrate_to_v2, v2 to v3 is migrate_to_v3
- we change ON_CHAIN_VERSION from 1 to 2
- second step adds the migrate_to_v2 method
module counter::counter_migrate {
use counter::counter_schema::Schema;
use counter::counter_number;
const ON_CHAIN_VERSION: u32 = 2;
public fun on_chain_version(): u32 {
ON_CHAIN_VERSION
}
public entry fun migrate_to_v2(schema: &mut Schema, new_package_id: address, new_version: u32, ctx: &mut TxContext) {
// This line of code should never be changed, it's the first step in the migration method, and it's followed by the logic you're writing
schema.upgrade(new_package_id, new_version, ctx);
// Customized Logic
let current_number = schema.value()[];
let number = counter_number::new(current_number, current_number);
schema.value_v2().set(number);
schema.value().remove();
}
}After modifying the contract, we upgrade.
β pnpm dubhe upgrade
INCLUDING DEPENDENCY Dubhe
INCLUDING DEPENDENCY Sui
INCLUDING DEPENDENCY MoveStdlib
BUILDING counter
π Starting Upgrade Process...
π OldPackageId: 0xd45e866f9d87b197913c10dcc1b16c311787a267447d9ded36c96bbca1534f33
π UpgradeCap Object Id: 0x20bcea3558938d4c1b03a8cab5d26ec9656f90a82fa49397d8ce6123573608d6
π OldVersion: 1
Upgrade Transaction Digest: 4rVGakd166ujDBdz2BwgkPj8X4BwnFBTUZfMu8SF1yBv
counter new PackageId: 0xacdf1875de568829f0a6d4390369b293d3a737bddbf0fa77e16ba161b40896e1
counter new Version: 2
Update deploy log: /Volumes/project/dubhe/packages/sui-cli/contracts/counter/.history/sui_localnet/latest.json
π Starting Migration Process...
π Added Fields: {
"schemaName": "value_v2",
"fields": "StorageValue<Number>"
}
Migration Transaction Digest: CFsNjaqCWFtx4vWPcH18jb4jBGuBQevJw4U9vkXPaAYASo far the upgrade steps have been completed. OldPackageId is currently not working properly, newPackageId will work properly according to our newly added logic.