Ton-Dynasty / tondynasty-contracts

Ton-Dynasty Contracts is a library for efficient smart contract development by tact-lang
https://ton-dynasty.github.io/docs.contracts/
101 stars 16 forks source link

Feature - Upgradable trait #12

Open bymoses opened 3 months ago

bymoses commented 3 months ago

Disclaimer: Hi guys, I'm relative new to TON ecosystem but AFAIK there's no standardized approach for upgradable contracts in Tact.

Motivation

Motivation for this issue is to discuss some approaches for making contract upgrades here because tondynasty is relatively popular and it will be easier to find this information for newcomers.

Solution

A couple weeks ago @wedvjin created proof of concept repo. Using his example and tondynasty's traits approach I've created a basic Upgradable trait:

@name(set_code)
native setCode(code: Cell);

@name(set_data)
native setData(d: Cell);

message UpgradeContract {
  code: Cell;
  data: Cell?;
}

trait Upgradable {
  owner: Address;

  // @dev  Upgrade
  receive(msg: UpgradeContract) {
    let ctx: Context = context();
    self._upgrade_validate(ctx, msg);
    self._upgrade(ctx, msg);
  }

  // @dev  _upgrade_validate conduct some custom validating before upgrade
  virtual inline fun _upgrade_validate(ctx: Context, msg: UpgradeContract) {
    require(ctx.sender == self.owner, "Upgradable: Sender is not a contract owner");
  }

  // @dev  _upgrade
  virtual inline fun _upgrade(ctx: Context, msg: UpgradeContract) {
    setCode(msg.code);
    if (msg.data != null) {
      setData(msg.data)
    }
  }
}

Limitations

https://github.com/wedvjin/ton-tact-contract-upgrade?tab=readme-ov-file#issue

@alan890104 @howardpen9 please take a look, maybe you have some different approaches for this

alan890104 commented 3 months ago

@bymoses brilliant! Let me take a look at it 😎

bymoses commented 3 months ago

There's also comment in tact repo by @wedvjin himself https://github.com/tact-lang/tact/issues/27#issuecomment-2124694217 It seems that devs has planned implementation of native upgrade mechanism to v1.4.0, but there's no assignee, so maybe we shouldn't rely on it

alan890104 commented 3 months ago

@bymoses This idea looks fantastic! Would you be willing to try writing this upgradeable contract pattern example and become one of the open-source contributors to tondynasty-contracts?

bymoses commented 3 months ago

@alan890104 Sure, I've made basic commit at my fork https://github.com/Ton-Dynasty/tondynasty-contracts/commit/9e4ac701399542e01502c664b3f9c840420c3ee6 . Issue with 11 exit code is there, could you take a look at compiled funC code? I need some assistance here because I don't have experience with this language. Screenshot from 2024-06-03 00-53-16

alan890104 commented 3 months ago

I've got some matters to handle these days, so I might not be able to check this for you until after Wednesday. In the meantime, could you please take a look at this webpage?

alan890104 commented 3 months ago

@bymoses There's a strange issue: when I call the get counter method (a GET method) after upgrading to v3, I encounter an exit code 9. This is quite unusual and seems to suggest there might be something hidden within the mechanism of the Tact language.

bymoses commented 3 months ago

Ok, as far as I can tell we now have two options:

a. Off-chain computation of new storage cells. e.g. When you send UpgradeContract, data field should be computed on your server and your storage will be overwriten with it. Screenshot from 2024-06-06 18-41-13

b. On-chain migrations using lock mechanism:

  1. Lock contract
  2. Upgrade code with new overwritten _get_migrated_data method (asm SETCODE instruction shedule code upgrade when the contract execution finished, so we need two contract calls here)
  3. Call "Migrate storage" receiver to trigger newly upgraded _get_migrated_data method and update storage
  4. Unlock contract Screenshot from 2024-06-06 20-08-29
alan890104 commented 3 months ago

@bymoses Thank you for the time you have invested. After discussing with other teams, instead of incorporating the trait for upgrading contracts into the tondynasty contract, I would suggest that the Tact compiler team include this trait as a built-in feature. This way, everyone can use it upon installation.