Skip to content
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

feat!: deploying large contracts (loader + blob support) #1472

Merged
merged 55 commits into from
Aug 9, 2024

Conversation

segfault-magnet
Copy link
Contributor

@segfault-magnet segfault-magnet commented Jul 24, 2024

closes: #1470
A thank you to @hal3e for brainstorming with me.

The Contract is now a type-state pattern. Please refer to the below diagram to help you understand the changes:
image

The change was needed so that the following might be achieved:

  • Loaders must not have configurables applied to them
  • We must be able to get the contract_id at every point
  • Flexibility around blob formation and upload

You basically have three states:

A regular contract

What you're used to seeing. It is either initialized from raw code or loaded from a file:

        let contract = Contract::regular(contract_binary, Salt::zeroed(), vec![]);

or

    let contract = Contract::load_from(
        "sway/contracts/storage/out/release/storage.bin",
        LoadConfiguration::default(),
    )?;

With the notable addition of being able to set configurables (previously possible only when using load_from):

    let contract =
        Contract::regular(binary, Salt::zeroed(), vec![]).with_configurables(configurables);

a regular contract can be deployed via deploy, which hasn't changed, or via smart_deploy that will use blobs/loader if the contract is above what can be deployed in a create tx:

        let contract_id = Contract::load_from(
            contract_binary,
            LoadConfiguration::default().with_salt(random_salt()),
        )?
        .smart_deploy(&wallet, TxPolicies::default(), max_words_per_blob)
        .await?;

Loader contract, blobs pending upload

You can turn a regular contract into a loader contract:

        let contract = Contract::load_from(
            contract_binary,
            LoadConfiguration::default(),
        )?
        .convert_to_loader(max_words_per_blob)?

or, if you have the blobs, create it directly:

        let contract = Contract::loader_for_blobs(blobs, random_salt(), vec![])?;

You can also revert back to the regular contract via revert_to_regular.

If you now call deploy the contract will first deploy the blobs and then the loader itself.

You can also split this into two parts by first calling upload_blobs and then deploy:

    let contract_id = Contract::load_from(contract_binary, LoadConfiguration::default())?
        .convert_to_loader(1024)?
        .upload_blobs(&wallet, TxPolicies::default())
        .await?
        .deploy(&wallet, TxPolicies::default())
        .await?;

doing so will have deploy only submit the create tx while the uploading will be done in upload_blobs.

Loader, with blobs deployed

You arrive at this contract type by eithers having the blob ids and creating it manually:

        let contract = Contract::loader_for_blob_ids(all_blob_ids, random_salt(), vec![])?;

or by calling upload_blobs as in the previous case:

        let contract = Contract::load_from(
            contract_binary,
            LoadConfiguration::default().with_salt(random_salt()),
        )?
        .convert_to_loader(max_words_per_blob)?
        .upload_blobs(&wallet, TxPolicies::default())
        .await?;

Calling deploy on this contract only deploys the loader.

Estimating max blob size

This is a bit tricky. Blob sizes are limited by two things: max transaction size and max transaction gas (both part of consensus parameters). So a blob can be as big as you want as long as the overall tx respects these two global tx limits.

So that means that properly estimating the max blob the user can send becomes a bit tricky. If you fund the tx with 2 coins instead of 1 the answer changes. If you use a predicate instead of a coin also changes the result. Basically whatever impacts the size or gas usage will impact how big the blob can be.

Say you put a blob of 20kb, and fund the tx. Oh look you have extra size and gas to spare. You increase that a bit but you no longer have 1 coin that can cover that but need to use 2. Ok the new blob size is no longer acceptable since you took up a bit of space adding that coin. Remove it. Ok now you can increase the blob size again. But now you again need 2 coins...

As a start, and until we figure something better and robust, there is a crude estimation available in the form of:

        let max_blob_size = BlobTransactionBuilder::default()
            .estimate_max_blob_size(&provider)
            .await?;

The docs explain the caveats of this estimation.

Breaking changes @digorithm

  • Contract::new is removed, replaced with Contract::regular.
  • Contract now accepts a generic argument denoting the type of contract (regular, loader, etc)

Checklist

  • I have linked to any relevant issues.
  • I have updated the documentation.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have added necessary labels.
  • I have done my best to ensure that my PR adheres to the Fuel Labs Code Review Standards.
  • I have requested a review from the relevant team or maintainers.

Copy link
Contributor

@Br1ght0ne Br1ght0ne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing but nits/typos - exceptional work. Still woozy after that asm, but I've never seen an asm block so well commented. LFG!

e2e/tests/contracts.rs Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
packages/fuels-programs/src/contract.rs Outdated Show resolved Hide resolved
packages/fuels-programs/src/contract.rs Outdated Show resolved Hide resolved
packages/fuels-programs/src/contract.rs Outdated Show resolved Hide resolved
packages/fuels-programs/src/contract.rs Outdated Show resolved Hide resolved
Br1ght0ne added a commit to FuelLabs/fuel-specs that referenced this pull request Jul 25, 2024
Found while reviewing FuelLabs/fuels-rs#1472.

### Before requesting review
- [x] I have reviewed the code myself
@segfault-magnet segfault-magnet added breaking Introduces or requires breaking changes and removed blocked labels Aug 8, 2024
Copy link
Contributor

@hal3e hal3e left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! I love the new workflow and the typesate pattern makes sense here. Left some nits.

e2e/tests/contracts.rs Outdated Show resolved Hide resolved
e2e/tests/contracts.rs Show resolved Hide resolved
packages/fuels-core/src/types/transaction_builders/blob.rs Outdated Show resolved Hide resolved
packages/fuels-programs/src/contract.rs Show resolved Hide resolved
packages/fuels-programs/src/contract/loader.rs Outdated Show resolved Hide resolved
packages/fuels-programs/src/contract/loader.rs Outdated Show resolved Hide resolved
docs/src/deploying/large_contract.md Outdated Show resolved Hide resolved
@segfault-magnet segfault-magnet requested a review from hal3e August 9, 2024 11:58
hal3e
hal3e previously approved these changes Aug 9, 2024
Copy link
Contributor

@hal3e hal3e left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

Br1ght0ne
Br1ght0ne previously approved these changes Aug 9, 2024
MujkicA
MujkicA previously approved these changes Aug 9, 2024
Copy link
Contributor

@MujkicA MujkicA left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got some nits. Great work 🚀

e2e/tests/contracts.rs Outdated Show resolved Hide resolved
examples/providers/src/lib.rs Show resolved Hide resolved
docs/src/SUMMARY.md Outdated Show resolved Hide resolved
e2e/tests/configurables.rs Show resolved Hide resolved
packages/fuels-programs/src/contract/loader.rs Outdated Show resolved Hide resolved
packages/fuels-programs/src/contract.rs Show resolved Hide resolved
@segfault-magnet segfault-magnet dismissed stale reviews from MujkicA, Br1ght0ne, and hal3e via 3006169 August 9, 2024 13:49
Copy link
Member

@digorithm digorithm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! The API is very clean. Still, I'm nervous to see how people will use it; the documentation is very on point and hopefully it'll help people. In any case, we'll have to keep our eyes here and quickly adjust things as needed.

e2e/Forc.toml Show resolved Hide resolved
@segfault-magnet segfault-magnet merged commit 71f68ac into master Aug 9, 2024
43 checks passed
@segfault-magnet segfault-magnet deleted the feat/chunked_contract_deploy_w_blobs branch August 9, 2024 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking Introduces or requires breaking changes enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Blob tx / large contract support
6 participants