Upgrading the Module
How to upgrade your module?
Aptos에서는 이미 배포가 되어있는 module이라도 추가적인 코드를 작성하여 업그레이드 할 수 있습니다. 이를 Module Upgrade 라고 하며 이번 튜토리얼에서는 기존에 작성된 Module을 이용해 업데이트 하는 방법을 알아보겠습니다.
본 튜토리얼을 진행하기 위해서는 사용자가 배포한 Fungible Asset Module과 배포 환경이 필요합니다!
배포한 모듈이 없는 경우 아래 링크를 클릭하여 Nodit Aptos Tutorial을 따라 Message Module을 배포해 보세요!
이 튜토리얼을 통해 아래 내용을 배울 수 있습니다!
- Module의 함수를 호출하는 방법을 알 수 있습니다.
- 새로운 함수를 작성하여 Module에서 이용하는 로직을 변경하는 방법을 알 수 있습니다.
- 전체 튜토리얼 코드는 아래 링크를 통해 확인할 수 있습니다.
- Nodit Aptos Upgrading the Module 튜토리얼 코드 확인하기
Upgrade your Module
Nodit 튜토리얼을 통해 배포한 Message Module의 코드는 다음과 같습니다.
module ownerAddress::message {
use std::signer;
use std::string::{Self,utf8, String};
use std::error;
struct Message has key {
message_counter : u64,
message : String,
}
const ENO_MESSAGE: u64 = 0;
public fun get_message(message_owner : address) : string::String acquires Message {
assert!(exists<Message>(message_owner), error::not_found(ENO_MESSAGE));
borrow_global<Message>(message_owner).message
}
public entry fun set_message(admin: &signer, message : String) acquires Message{
let message_owner_address = signer::address_of(admin);
if (exists<Message>(message_owner_address)) {
let stored_message = borrow_global_mut<Message>(message_owner_address);
stored_message.message = message;
} else {
move_to(admin, Message{
message_counter : 1,
message : message
});
}
}
#[test(account = @ownerAddress)]
public entry fun test_message(account: &signer) acquires Message {
let message = utf8(b"Hello, World!");
set_message(account, message);
let message_owner_address = signer::address_of(account);
let stored_message = get_message(message_owner_address);
assert!(message == stored_message, 0);
}
}
코드를 살펴보면 set_message에서 로직이 이상한 부분을 찾을 수 있습니다. 바로 기존 메시지를 사용자가 새로 입력한 메시지로 변경하는 경우, 메시지는 정상적으로 변경되나 message_counter가 증가하지 않는다는 점입니다. 이를 해결하기 위해 Module을 업데이트 하도록 하겠습니다.
Step 1. Module의 함수 변경
기존의 Module에 있는 set_message 함수는 사용자가 입력한 message만 변경하고 message_counter는 변경하지 않는 로직이었습니다.
public entry fun set_message(admin: &signer, message : String) acquires Message{
let message_owner_address = signer::address_of(admin);
if (exists<Message>(message_owner_address)) {
let stored_message = borrow_global_mut<Message>(message_owner_address);
stored_message.message = message;
} else {
move_to(admin, Message{
message_counter : 1,
message : message
});
}
}
이러한 로직을 수정한 새로운 set_message 함수를 작성합니다. 이제 메시지를 변경할 때 마다 message_counter 역시 1 증가합니다.
public entry fun set_message_with_message_counter(admin: &signer, message : String) acquires Message{
let message_owner_address = signer::address_of(admin);
if (exists<Message>(message_owner_address)) {
let stored_message = borrow_global_mut<Message>(message_owner_address);
// 표시
stored_message.message_counter = stored_message.message_counter+1;
stored_message.message = message;
} else {
move_to(admin, Message{
message_counter : 1,
message : message
});
}
}
그리고 사용자가 혼선을 겪지 않도록 기존의 set_message 함수에 #[deprecated]
코드를 작성하여 변경되었음을 알립니다.
#[deprecated]
public entry fun set_message(admin: &signer, message : String) acquires Message{
let message_owner_address = signer::address_of(admin);
if (exists<Message>(message_owner_address)) {
let stored_message = borrow_global_mut<Message>(message_owner_address);
stored_message.message = message;
} else {
move_to(admin, Message{
message_counter : 1,
message : message
});
}
}
전체적인 코드는 다음과 같습니다.
module ownerAddress::message {
use std::signer;
use std::string::{Self,utf8, String};
use std::error;
struct Message has key {
message_counter : u64,
message : String,
}
const ENO_MESSAGE: u64 = 0;
public fun get_message(message_owner : address) : string::String acquires Message {
assert!(exists<Message>(message_owner), error::not_found(ENO_MESSAGE));
borrow_global<Message>(message_owner).message
}
#[deprecated]
public entry fun set_message(admin: &signer, message : String) acquires Message{
let message_owner_address = signer::address_of(admin);
if (exists<Message>(message_owner_address)) {
let stored_message = borrow_global_mut<Message>(message_owner_address);
stored_message.message = message;
} else {
move_to(admin, Message{
message_counter : 1,
message : message
});
}
}
public entry fun set_message_with_message_counter(admin: &signer, message : String) acquires Message{
let message_owner_address = signer::address_of(admin);
if (exists<Message>(message_owner_address)) {
let stored_message = borrow_global_mut<Message>(message_owner_address);
stored_message.message_counter = stored_message.message_counter+1;
stored_message.message = message;
} else {
move_to(admin, Message{
message_counter : 1,
message : message
});
}
}
#[test(account = @ownerAddress)]
public entry fun test_message(account: &signer) acquires Message {
let message = utf8(b"Hello, World!");
set_message_with_counter(account, message);
let message_owner_address = signer::address_of(account);
let stored_message = get_message(message_owner_address);
assert!(message == stored_message, 0);
}
}
Step 2. Compile 및 배포
코드 변경을 완료하였다면 터미널에 아래 명령어를 실행하여 정상적으로 컴파일이 되는지 확인합니다.
$ aptos move compile
정상적으로 컴파일이 완료되면 다음과 같은 응답을 받을 수 있습니다.
Compiling, may take a little while to download git dependencies...
UPDATING GIT DEPENDENCY https://github.com/aptos-labs/aptos-core.git
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING myFungibleAsset
{
"Result": [
"<your_account_address>::<your_module_name>"
]
}
컴파일 완료 후 터미널에 아래 명령어를 실행하여 Aptos 네트워크에 변경된 Module을 배포합니다.
- 배포 시 owner의 Account가 기존의 owner와 다를 경우 신규 모듈로 배포가 될 수 있습니다.
- 기존의 함수가 지워지거나 변경될 경우 배포에 실패할 수 있습니다.
- Move.toml, module name 등 기존 설정이 변경된 경우 배포에 실패할 수 있습니다.
$ aptos move publish
정상적으로 배포가 되었다면 아래와 같이 트랜잭션에 대한 결과를 확인할 수 있습니다.
{
"Result": {
"transaction_hash": "<Your_transaction_hash>",
"gas_used": 165,
"gas_unit_price": 150,
"sender": "<Your_Account_Address>",
"sequence_number": 2,
"success": true,
"timestamp_us": 1720774008922260,
"version": 5066304958,
"vm_status": "Executed successfully"
}
}
Step 3. 변경된 module 확인
Nodit에서 제공하는 Aptos Node API의 Get account module API를 이용하여 배포된 Module의 ABI를 확인합니다.
curl --request GET \
--url https://aptos-testnet.nodit.io/v1/accounts/<your_account_address>/module/<your_module_name> \
--header 'X-API-KEY: <your X-API-KEY>' \
--header 'accept: application/json'
다음과 같이 Module에 수정하여 배포한 set_message_with_message_counter 함수에 대한 값을 찾을 수 있나요?
...
{
name:"set_message_with_message_counter"
visibility:"public"
is_entry:true
is_view:false
generic_type_params:[]
params:[
0:"&signer"
1:"0x1::string::String"
]
return:[]
}
...
- 확인이 되지 않는다면 위의 코드와 다른 부분이 있는지 확인해 보세요.
- 위의 코드와 차이가 없는데 되지 않나요? 여기[QnA 링크]를 클릭하여 QnA로 남겨주세요!
Aptos는 매우 빠르게 업데이트 되고 있습니다!
Aptos 재단에서 배포한 SDK 버전에 따라 변경되는 점이 있을 수 있습니다. Nodit은 항상 이를 확인하고 있으나 시점에 따라 코드 변경으로 인한 오류가 발생할 수 있습니다.
Updated 5 months ago