Giter Site home page Giter Site logo

ckb-script-templates's Introduction

ckb-script-templates

This repository keeps a series of CKB script templates that can be inflated via cargo-generate. Those templates enable a native development flow on mainstream Linux, macOS and Windows machines using stock version of latest stable Rust & clang C compiler.

Usage

Dependencies

The following dependencies are required for the templates:

  • git, make, sed, bash, sha256sum and others Unix utilities. Refer to the documentation for your operating systems for how to install them. Chances are your system might already have them.
  • Rust: latest stable Rust installed via rustup should work. Make sure you have riscv64 target installed via: rustup target add riscv64imac-unknown-none-elf
  • Clang: make sure you have clang 16+ installed, sample installtion steps for selected platforms are:
    • Debian / Ubuntu: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 16 && rm llvm.sh
    • Fedora 39+: sudo dnf -y install clang
    • Archlinux: sudo pacman --noconfirm -Syu clang
    • macOS: brew install llvm@16
    • Windows(with [Scoop](scoop install llvm yasm)): scoop install llvm yasm
  • cargo-generate: You can install this via cargo install cargo-generate, or follow the steps here

Creating workspace

To generate a workspace template, use the following command:

$ cargo generate gh:cryptape/ckb-script-templates workspace
โš ๏ธ   Favorite `gh:cryptape/ckb-script-templates` not found in config, using it as a git repository: https://github.com/cryptape/ckb-script-templates.git
๐Ÿคท   Project Name: my-first-contract-workspace
๐Ÿ”ง   Destination: /tmp/my-first-contract-workspace ...
๐Ÿ”ง   project-name: my-first-contract-workspace ...
๐Ÿ”ง   Generating template ...
๐Ÿ”ง   Moving generated files into: `/tmp/my-first-contract-workspace`...
๐Ÿ”ง   Initializing a fresh Git repository
โœจ   Done! New project created /tmp/my-first-contract-workspace

Or you can manually specify the name and skip the prompt:

$ cargo generate gh:cryptape/ckb-script-templates workspace --name my-first-contract-workspace
โš ๏ธ   Favorite `gh:cryptape/ckb-script-templates` not found in config, using it as a git repository: https://github.com/cryptape/ckb-script-templates.git
๐Ÿ”ง   Destination: /tmp/my-first-contract-workspace ...
๐Ÿ”ง   project-name: my-first-contract-workspace ...
๐Ÿ”ง   Generating template ...
๐Ÿ”ง   Moving generated files into: `/tmp/my-first-contract-workspace`...
๐Ÿ”ง   Initializing a fresh Git repository
โœจ   Done! New project created /tmp/my-first-contract-workspace

This is probably the only longer command you will deal with when using the templates repository. You can save them as an alias in your shell:

$ alias create-ckb-scripts="cargo generate gh:cryptape/ckb-script-templates workspace"
$ create-ckb-scripts
โš ๏ธ   Favorite `gh:cryptape/ckb-script-templates` not found in config, using it as a git repository: https://github.com/cryptape/ckb-script-templates.git
๐Ÿคท   Project Name: my-first-contract-workspace
๐Ÿ”ง   Destination: /tmp/my-first-contract-workspace ...
๐Ÿ”ง   project-name: my-first-contract-workspace ...
๐Ÿ”ง   Generating template ...
๐Ÿ”ง   Moving generated files into: `/tmp/my-first-contract-workspace`...
๐Ÿ”ง   Initializing a fresh Git repository
โœจ   Done! New project created /tmp/my-first-contract-workspace

Generating contract crates in the workspace

First, navigate to the workspace directory you just created:

$ cd my-first-contract-workspace

First thing you can notice, is that we have created a standard Rust workspace project:

$ tree .
.
โ”œโ”€โ”€ Cargo.toml
โ”œโ”€โ”€ Makefile
โ”œโ”€โ”€ scripts
โ”‚ย ย  โ””โ”€โ”€ find_clang
โ””โ”€โ”€ tests
    โ”œโ”€โ”€ Cargo.toml
    โ””โ”€โ”€ src
        โ”œโ”€โ”€ lib.rs
        โ””โ”€โ”€ tests.rs

4 directories, 6 files

The only exception here, is that a Makefile, together with a scripts folder has been created to simplify contract building.

We can use make generate to create our first contract:

$ make generate
๐Ÿคท   Project Name: first-contract
๐Ÿ”ง   Destination: /tmp/my-first-contract-workspace/contracts/first-contract ...
๐Ÿ”ง   project-name: first-contract ...
๐Ÿ”ง   Generating template ...
๐Ÿ”ง   Moving generated files into: `/tmp/my-first-contract-workspace/contracts/first-contract`...
๐Ÿ”ง   Initializing a fresh Git repository
โœจ   Done! New project created /tmp/my-first-contract-workspace/contracts/first-contract

You can also supply the contract create name when executing the make task:

$ make generate CRATE=second-contract
๐Ÿ”ง   Destination: /tmp/my-first-contract-workspace/contracts/second-contract ...
๐Ÿ”ง   project-name: second-contract ...
๐Ÿ”ง   Generating template ...
๐Ÿ”ง   Moving generated files into: `/tmp/my-first-contract-workspace/contracts/second-contract`...
๐Ÿ”ง   Initializing a fresh Git repository
โœจ   Done! New project created /tmp/my-first-contract-workspace/contracts/second-contract

By default, the newly created crate is using contract template, which is put into contracts sub-folder, the workspace-level Makefile assumes all Rust contracts are stored in contracts folder, and treat crates stored in other folders as dependency-only Rust crates.

But chances are you would want to tweak the default settings in certain scenarios:

  • Sometimes you want to use a different template as a contract starting point other than contract template.
  • Sometimes you want to use a different template since you are generating a plain Rust crate, which will also likely be put in a different subfolder other than contracts
  • Note: while you could technically put a Rust contract in a different subfolder other than contracts, we don't really recommend this, since the workspace-level Makefile is leveraging the convention that all CKB contracts live in contracts folder.

You can do this by customizing parameters to make generate:

$ make generate TEMPLATE=atomics-contract                      # generate a Rust contract crate in contracts subfolder, but use atomics-contract template
$ make DESTINATION=crates                                      # generate a crate in crates folder, and still use the default contract template
$ make generate TEMPLATE=c-wrapper-crate DESTINATION=crates    # generate a crate in crates folder, but use c-wrapper-crate template

Ready-to-use templates have been put together for different use cases:

  • contract: default contract template you should use if no special requirements are neeeded.
  • atomics-contract: a contract template that supports atomic builtins without requiring RISC-V A extension. This template allows you to use log, bytes crate or other code that might deal with atomics.
  • stack-reorder-contract: a contract template that adjusts memory layout so stack lives at lower address, and heap lives at higher address. This way a program would explicitly signal errors when stack space is fully use.
  • c-wrapper-crate: a crate template that shows how to glue C code in a Rust crate for CKB's contract usage.
  • x64-simulator-crate: a crate template that contains Rust-only code, but usees ckb-x64-simulator for tests.

Certain template might require external modules to be available, for example:

  • All C code would require ckb-c-stdlib: git submodule add https://github.com/nervosnetwork/ckb-c-stdlib deps/ckb-c-stdlib
  • atomics-contract requires lib-dummy-atomics: git submodule add https://github.com/xxuejie/lib-dummy-atomics deps/lib-dummy-atomics
  • stack-reorder-contract requires ckb-stack-reorg-bootloader: git submodule add https://github.com/xxuejie/ckb-stack-reorg-bootloader deps/ckb-stack-reorg-bootloader

In future versions, we might leverage cargo-generate hooks to add submodules automatically, but for now, manual steps are required.

Build & Test

Note that when you supply the contract crate name, our Makefile will be smart enough to automatically insert the crate in to Cargo.toml file, so you don't have to edit it manually.

Now you can build the contracts(or adjust parameters):

$ make build
$ make build MODE=debug                   # for debug build
$ make build CUSTOM_RUSTFLAGS=""          # release build without debug assertions
$ make build CARGO_ARGS="--verbose"       # release build with `--verbose` attached to cargo command, you can use other arguments accepted by cargo
$ make build CONTRACT=second-contract     # build a single contract
$ make build CLEAN_BUILD_DIR_FIRST=false  # keep old untouched binaries
$ make build CLANG=clang-17               # use a specific clang version to build C code

We have prepared a tests crate where you can also add contract tests. If you want to run the tests, run the following command:

make test

The templates provided here, use the same conventions as ckb-native-build-sample project, so feel free to refer to the more detailed usage doc in the sample project.

Reproducible Build

When using this set of templates, we always recommend to use locally installed native versions of LLVM & Rust to build and test your scripts. However, reproducible build is an important part of CKB scripts, which would require locked versions of LLVM & Rust to work. It might not be an easy task when using locally installed versions of compilers.

For the time being, we have prepared a script that does reproducible build via a docker container image. We do want to mention that docker is not necessarily THE way to do reproducible build, nor is it the best way to do reproducible build. There might well be other ways that are better, such as chroot or Nix. It's just that historically, docker has been used in CKB script's build process, and adding a script leveraging docker here, provides an easy solution into the issue.

To do reproducible build, you can use the included script with varying commands:

$ ./scripts/reproducible_build_docker               # Clean current repository, used locked LLVM & Rust from a docker container
                                                    # to build all contracts, then test the binaries against a checksum file.

$ ./scripts/reproducible_build_docker --update      # Update the checksum file with new binaries, could be handy when you have
                                                    # made changes to the binaries.

$ ./scripts/reproducible_build_docker --no-clean    # Do not clean intermediate files before building, it is not recommended to
                                                    # use this but when you really know what you are doing, it could help you save
                                                    # some time.

$ ./scripts/reproducible_build_docker --proxy "..." # Setup docker container so it pulls Rust crates using a proxy server

By default, the checksum file is stored in checksums.txt in the root of the repository. It is strongly recommended that this file is checked into version control, and a CI is setup so reproducible build is always checked in new commits.

Standalone Contract Crate

In rare cases if you want to simply use a standalone contract crate without a workspace. The standalone-contract template is prepared for you:

$ cargo generate gh:cryptape/ckb-script-templates standalone-contract
โš ๏ธ   Favorite `gh:cryptape/ckb-script-templates` not found in config, using it as a git repository: https://github.com/cryptape/ckb-script-templates.git
๐Ÿคท   Project Name: standalone-first-contract
๐Ÿ”ง   Destination: /tmp/standalone-first-contract ...
๐Ÿ”ง   project-name: standalone-first-contract ...
๐Ÿ”ง   Generating template ...
๐Ÿ”ง   Moving generated files into: `/tmp/standalone-first-contract`...
๐Ÿ”ง   Initializing a fresh Git repository
โœจ   Done! New project created /tmp/standalone-first-contract

You can then build and test the standalone crate as usual:

$ cd standalone-first-contract
$ make build
$ make tests
$ make check
$ make clippy

The template is tailored built for usage outside of workspace, typically, it is not expected to be used inside a workspace. Feel free to compare it with the default contract workspace for differences.

This standalone template also has its own test setup, where in a workspace, a dedicated tests crate will handle most of the testing work.

ckb-script-templates's People

Contributors

xxuejie avatar joii2020 avatar quake avatar jjyr avatar xujiandong avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.