From b5d56d72003c0406d406bc61a68ae27717732abb Mon Sep 17 00:00:00 2001 From: Pino' Surace <95283998+pinosu@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:21:22 +0200 Subject: [PATCH] Improve wasmd instantiate2, execute and migrate sections (#123) * Improve wasmd instantiate2, execute and migrate sections * Fix errors and typos * Fix comments --- src/pages/wasmd/getting-started/cli.mdx | 389 ++++++++++++++++++++---- 1 file changed, 332 insertions(+), 57 deletions(-) diff --git a/src/pages/wasmd/getting-started/cli.mdx b/src/pages/wasmd/getting-started/cli.mdx index bdd56a39..8c422ede 100644 --- a/src/pages/wasmd/getting-started/cli.mdx +++ b/src/pages/wasmd/getting-started/cli.mdx @@ -56,7 +56,7 @@ ID. wasmd q tx 2C19314D369E7EF3C77CBD1B33E02DB0401619B5C8E1B1E5BD15AB46C3704E96 -o json ``` -Output: +The command will return a JSON object similar to the following: ```json { @@ -128,7 +128,7 @@ To query the metadata of a specific code ID, use the following command: wasmd q wasm code-info $CODE_ID -o json ``` -Output: +The command will return a JSON object similar to the following: ```json { @@ -142,10 +142,10 @@ Output: } ``` -- Code ID: This is the reference to the stored WASM code -- Creator: This is the address of the account that uploaded the code -- Data Hash: This is the checksum of the stored WASM code -- Instantiate Permission: This is the instantiate permission configuration. It is optional, and the +- `"code_id"` is the reference to the stored WASM code +- `"creator"` is the address of the account that uploaded the code +- `"data_hash"` is the checksum of the stored WASM code +- `"instantiate_permission"` is the instantiate permission configuration. It is optional, and the default value is `Everybody`, which means everybody can create an instance of the uploaded WASM code @@ -268,7 +268,7 @@ To query the metadata of a specific contract, use the following command: wasmd q wasm contract $CONTRACT -o json ``` -Output: +The command will return a JSON object similar to the following: ```json { @@ -288,137 +288,395 @@ Output: } ``` -- Address: This is the address of the contract on the blockchain. It uniquely identifies the - contract and is used for interacting with it. -- Code ID: This is the reference to the stored WASM code from which the contract was instantiated. -- Creator: This is the blockchain address of the account that initially instantiated the contract. - It indicates who created the contract instance. -- Admin: This is the address of the account that has administrative privileges over the contract, - such as the ability to execute migrations. This field is optional and can be set during - instantiation. -- Label: This is an optional field used to give a human-readable label to the contract. It helps in +- `"address"` is the address of the contract on the blockchain. It uniquely identifies the contract + and is used for interacting with it. +- `"code_id"` is the reference to the stored WASM code from which the contract was instantiated. +- `"creator"` is the blockchain address of the account that initially instantiated the contract. It + indicates who created the contract instance. +- `"admin"` is the address of the account that has administrative privileges over the contract, such + as the ability to execute migrations. This field is optional and can be set during instantiation. +- `"label"` is an optional field used to give a human-readable label to the contract. It helps in identifying the contract instance, especially when multiple instances of the same code are deployed. -- Created: This section provides details about the transaction in which the contract was - instantiated, including the block height at which the contract was created and the index of the - transaction within the block. -- IBC Port ID: This is the Port ID for Inter-Blockchain Communication [IBC](../../ibc.mdx). If the +- `"created"` section provides details about the transaction in which the contract was instantiated, + including the block height at which the contract was created and the index of the transaction + within the block. +- `"ibc_port_id"` is the Port ID for Inter-Blockchain Communication [IBC](../../ibc.mdx). If the contract is set up to interact with other blockchains via IBC, this field will contain the relevant port ID. -- Extention: This is is an extension point to store custom metadata within the persistence model +- `"extension"` is is an extension point to store custom metadata within the persistence model ## Instantiation with Predictable Address +Instantiation with a predictable address refers to the process of deploying a smart contract on a +blockchain such that the resulting contract address can be determined in advance. This is +particularly useful in scenarios where you need to know the contract address before its actual +deployment for purposes like pre-configuring other contracts or systems to interact with it. + ### Create a new contract instance with predictable address +First, we need to define a salt value. The salt is a unique value that, when combined with the +contract's code ID and initialization parameters, helps derive a unique and predictable contract +address. This ensures that even if the same contract code and initialization parameters are used, +different salt values will result in different contract addresses. + ```sh -RESP=$(wasmd tx wasm instantiate2 "$CODE_ID" "$INIT" 10 \ +SALT=10 +``` + +Run the following command to instantiate the contract with predicatable address: + +```sh +wasmd tx wasm instantiate2 "$CODE_ID" "$INIT" "$SALT" \ --admin="$ALICE_ADDR" \ --from alice \ --amount="100stake" \ --label "local0.1.0" \ - --fix-msg \ --gas 1000000 \ -y \ --chain-id=docs-chain-1 \ - -b sync \ -o json \ - --keyring-backend=test) - -sleep 6 - -CONTRACT_PREDICTABLE=$(wasmd query wasm list-contract-by-code "$CODE_ID" -o json | jq -r '.contracts[-1]') - -# Print contract address -echo "* Predictable contract address: $CONTRACT_PREDICTABLE" + --keyring-backend=test ``` +- `wasmd tx wasm instantiate2 "$CODE_ID" "$INIT" "$SALT"` instantiates a new contract instance with + the specified code ID, initialization parameters, and the salt value +- `--admin="$ALICE_ADDR"` specifies Alice as the admin who can later update the contract +- `--from alice` specifies Alice as the sender of the transaction +- `--amount="100stake"`: Sends `100 stake` to the contract upon instantiation +- `--label "local0.1.0"` assigns a label to this contract instance for easy identification +- `--gas 1000000` sets the gas limit for the transaction +- `-y` automatically accepts the transaction without prompting for confirmation +- `--chain-id=docs-chain-1` specifies the chain ID of the blockchain +- `-o json` outputs the result in JSON format +- `--keyring-backend=test` specifies the keyring backend to use + ### Query contracts by code id -You can get a list of contracts instantiated from a specific Code ID, by running the following -command: +To get a list of contracts instantiated from a specific Code ID, you can use the following command. +This will query the blockchain and return a JSON object containing the addresses of the contracts +associated with the given Code ID. ```sh -wasmd q wasm list-contract-by-code $CODE_ID +wasmd q wasm list-contract-by-code $CODE_ID -o json ``` +The command will return a JSON object similar to the following: + +```json +{ + "contracts": [ + "wasm1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtqhs9hr8", + "wasm19ph090ka8tzrd2wrp8gnn7lachwt7r2npvf6rdnd3ha3jv5n5gqquzcpd0" + ], + "pagination": { + "next_key": null, + "total": "0" + } +} +``` + +In this example, there are two contracts associated with the Code ID. + ### Query contracts by creator -You can get a list of contracts instantiated from a specific creator, by running the following -command: +To get a list of contracts instantiated by a specific creator, you can use the following command. +This will query the blockchain and return a JSON object containing the addresses of the contracts +associated with the given creator's address. ```sh -wasmd q wasm list-contracts-by-creator $ALICE_ADDR +wasmd q wasm list-contracts-by-creator $BOB_ADDR -o json +``` + +The command will return a JSON object similar to the following: + +```json +{ + "contract_addresses": [], + "pagination": { + "next_key": null, + "total": "0" + } +} ``` +In this example, there are no contract addresses associated with Bob's address. + ## Execution +Executing a command on a WASM contract involves sending a message to the contract. + ### Execute a command on a wasm contract -To execute a command on a wasm contract you can run the following commands: +First, we have to define the message to send to the contract. In this example we want to call the +release function of the contract: ```sh -echo "## Execute contract $CONTRACT" +MSG='{"release":{}}' +``` +Run the following command to execute the message on the contract: + +```sh +wasmd tx wasm execute "$CONTRACT" "$MSG" \ + --from alice \ + --gas 1000000 \ + -y \ + --chain-id=docs-chain-1 \ + -o json \ + --keyring-backend=test +``` + +- `"$CONTRACT"` specifies the address of the contract +- `"$MSG"` specifies the message to execute +- `--from alice` specifies Alice as the sender of the transaction +- `--gas 1000000` sets the gas limit for the transaction +- `-y` automatically accepts the transaction without prompting for confirmation +- `--chain-id=docs-chain-1` specifies the chain ID of the blockchain +- `-o json` outputs the result in JSON format +- `--keyring-backend=test` specifies the keyring backend to use + +By querying the transaction using the `txhash`, we can check the events emitted by the contract. The +output will look similar to the following: + +```json +{ + ... + "events": [ + ... + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "/cosmwasm.wasm.v1.MsgExecuteContract", + "index": true + }, + { + "key": "sender", + "value": "wasm1hvgm6p76gccgg4dl4caa8a7v03dsqww6r9sk4g", + "index": true + }, + { + "key": "module", + "value": "wasm", + "index": true + }, + { + "key": "msg_index", + "value": "0", + "index": true + } + ] + }, + { + "type": "execute", + "attributes": [ + { + "key": "_contract_address", + "value": "wasm1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtqhs9hr8", + "index": true + }, + { + "key": "msg_index", + "value": "0", + "index": true + } + ] + }, + ] +} +``` + +`"events"` are logs emitted by the contract during its execution, providing detailed information +about the actions performed and the resulting state changes. + +Below is the full script that combines all the steps for executing a command on a WASM contract and +querying the events: + +```sh +# Define the message to send to the contract, in this case a "release" command MSG='{"release":{}}' +# Execute the contract with the specified message RESP=$(wasmd tx wasm execute "$CONTRACT" "$MSG" \ --from alice \ --gas 1000000 \ -y \ --chain-id=docs-chain-1 \ - -b sync \ -o json \ --keyring-backend=test) +# Wait for the transaction to be processed sleep 6 -wasmd q tx $(echo "$RESP"| jq -r '.txhash') -o json | jq +# Query the transaction using its hash to check the events emitted by the contract +wasmd q tx $(echo "$RESP" | jq -r '.txhash') -o json | jq ``` ### Query contract state +To query the state of a WASM contract, you can use the following command. + +```sh +wasmd query wasm contract-state all "$CONTRACT" -o json +``` + +The output will look similar to this: + +```json +{ + "models": [ + { + "key": "636F6E666967", + "value": "eyJ2ZXJpZmllciI6Indhc20xaHZnbTZwNzZnY2NnZzRkbDRjYWE4YTd2MDNkc3F3dzZyOXNrNGciLCJiZW5lZmljaWFyeSI6Indhc20xcGEyOWxhYzVzODVrZ2o3cG45ejZnYzB0NHNxZ3psbGNndWhmMjQiLCJmdW5kZXIiOiJ3YXNtMWh2Z202cDc2Z2NjZ2c0ZGw0Y2FhOGE3djAzZHNxd3c2cjlzazRnIn0=" + } + ], + "pagination": { + "next_key": null, + "total": "0" + } +} +``` + +`Models` are key-value pairs representing the state data of the contract base64-encoded. + +We can decode the contract state using the following command: + ```sh -wasmd query wasm contract-state all "$CONTRACT" -o json | jq -r '.models[0].value' | base64 -d | jq +wasmd query wasm contract-state all "$CONTRACT" -o json | jq -r '.models[0].value' | base64 -d +``` + +The output will be similar to the following: + +```json +{ + "verifier": "wasm1hvgm6p76gccgg4dl4caa8a7v03dsqww6r9sk4g", + "beneficiary": "wasm1pa29lac5s85kgj7pn9z6gc0t4sqgzllcguhf24", + "funder": "wasm1hvgm6p76gccgg4dl4caa8a7v03dsqww6r9sk4g" +} ``` ## Migration +Migration is the process of upgrading an existing contract to a new version without changing its +address or losing its state. This ensures that the contract can evolve over time while preserving +the data of the original contract. + ### Migrate a wasm contract to a new code version +First, upload the new contract code to the blockchain: + +```sh +RESP=$(wasmd tx wasm store "./x/wasm/keeper/testdata/burner.wasm" \ + --from alice \ + --gas 1100000 \ + -y \ + --chain-id=docs-chain-1 \ + -o json \ + --keyring-backend=test) +``` + +Query the transaction to get the code ID of the newly uploaded code: + +```sh +RESP=$(wasmd q tx $(echo "$RESP" | jq -r '.txhash') -o json) +BURNER_CODE_ID=$(echo "$RESP" | jq -r '.events[] | select(.type=="store_code").attributes[] | select(.key=="code_id").value') +``` + +Set up the migration message that will be used during the migration process. + +```sh +DEST_ACCOUNT=$(wasmd keys show bob -a --keyring-backend=test) +MIGRATION_MSG="{\"payout\": \"$DEST_ACCOUNT\"}" +``` + +Next, migrate the existing contract to use the new code ID. + +```sh +RESP=$(wasmd tx wasm migrate "$CONTRACT" "$BURNER_CODE_ID" "$MIGRATION_MSG" \ + --from alice \ + --chain-id=docs-chain-1 \ + -y \ + -o json \ + --keyring-backend=test) +``` + +Finally, query the transaction to check its status and view the results + ```sh -echo "## Migrate contract" -echo "### Upload new code" +wasmd q tx $(echo "$RESP" | jq -r '.txhash') -o json +``` + +The output will be similar to the following: + +```json +{ + ... + "events": [ + ... + { + "type": "migrate", + "attributes": [ + { + "key": "code_id", + "value": "3", + "index": true + }, + { + "key": "_contract_address", + "value": "wasm1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtqhs9hr8", + "index": true + }, + { + "key": "msg_index", + "value": "0", + "index": true + } + ] + }, + ] +} +``` + +In this case, the contract was migrated to use code ID 3. +Below is the full script that combines all the steps for a wasm contract to a new code version + +```sh +# Upload the new contract code RESP=$(wasmd tx wasm store "./x/wasm/keeper/testdata/burner.wasm" \ --from alice \ --gas 1100000 \ -y \ --chain-id=docs-chain-1 \ - --node=http://localhost:26657 \ - -b sync \ -o json \ --keyring-backend=test) +# Wait for the transaction to be processed sleep 6 +# Query the transaction to get the code ID RESP=$(wasmd q tx $(echo "$RESP" | jq -r '.txhash') -o json) BURNER_CODE_ID=$(echo "$RESP" | jq -r '.events[] | select(.type=="store_code").attributes[] | select(.key=="code_id").value') -echo "### Migrate to code id: $BURNER_CODE_ID" - +# Get the destination account address DEST_ACCOUNT=$(wasmd keys show bob -a --keyring-backend=test) +# Define the migration message +MIGRATION_MSG="{\"payout\": \"$DEST_ACCOUNT\"}" -RESP=$(wasmd tx wasm migrate "$CONTRACT" "$BURNER_CODE_ID" "{\"payout\": \"$DEST_ACCOUNT\"}" \ +# Migrate the contract to the new code ID +RESP=$(wasmd tx wasm migrate "$CONTRACT" "$BURNER_CODE_ID" "$MIGRATION_MSG" \ --from alice \ --chain-id=docs-chain-1 \ - -b sync \ -y \ -o json \ --keyring-backend=test) +# Wait for the transaction to be processed sleep 6 +# Query the migration transaction wasmd q tx $(echo "$RESP" | jq -r '.txhash') -o json | jq ``` @@ -427,10 +685,12 @@ wasmd q tx $(echo "$RESP" | jq -r '.txhash') -o json | jq You can query the history entries for a contract by running the following command: ```sh -wasmd q wasm contract-history $CONTRACT -o json | jq +wasmd q wasm contract-history $CONTRACT -o json ``` -Output: +This command retrieves the history of changes made to the specified contract, including initial +instantiation and subsequent migrations. The command will return a JSON object similar to the +following: ```json { @@ -466,11 +726,17 @@ Output: } ``` +Each `entry` provides details about a specific operation performed on the contract. Entry Fields: + +- `"operation"` is the type of operation performed, such as initialization or migration. +- `"code_id"` is the code ID associated with the operation. +- `"updated"` contains information about when the operation was performed. +- `"msg"` is the message payload associated with the operation. + ### Set contract admin The admin is the only address that can migrate a contract. The admin can be updated by the current -admin with the following command. In this case, the admin is updated from Alice's address to Bob's -address. +admin with the following command: ```sh wasmd tx wasm set-contract-admin \ @@ -482,15 +748,24 @@ wasmd tx wasm set-contract-admin \ -y ``` +After running this command, Bob will be the new admin of the contract, and only he will have the +authority to migrate the contract to a new code version or further update the admin role. + ### Clear contract admin -You can clear the admin address from a contract. This action prevents any further migration. +Clearing the admin address from a WASM contract removes the ability to migrate the contract to a new +code version. This action effectively locks the contract, preventing any further migrations. + +Run the following command to clear the contract admin: ```sh wasmd tx wasm clear-contract-admin \ "$CONTRACT" \ - --from alice \ + --from bob \ --keyring-backend=test \ --chain-id=docs-chain-1 \ -y ``` + +After running this command, the contract will no longer have an admin, and no one will be able to +migrate the contract to a new code version.