目前支流的合约开发次要有ETH的solidity,Solana的bpf(linux中罕用)以及wasm;对于这些合约的开发,每条公链接都有本人的工具和框架,升高开发者在应用中的难度;明天就挑了三个比照,他们别离是 ETH的hardhat工具,Solana的anchor和substrate的ink!。

你将理解如下的内容:

  1. 工具/框架的应用办法
  2. 主动生成的模版以及如何进行简略的开发
  3. 综合比照

框架的应用和代码剖析

ETH hardhat

官网doc

官网Tutorial

环境配置:因为须要应用 Ethers.js 进行测试和交互,所以须要装置node.js;

装置:npm install --save-dev hardhat

初始化我的项目:在我的项目中执行 npx hardhat,通过提醒,抉择本人要应用的模版,而后会在根目录中创立必要的文件和目录;

.├── README.md├── contracts│   └── Greeter.sol├── hardhat.config.js├── node_modules├── package-lock.json├── package.json├── scripts│   └── sample-script.js└── test    └── sample-test.js

能够看到框架曾经帮咱们分好了目录,其中contracts目录下是具体的solidity合约代码;scripts中是部署合约须要的代码;test中是测试代码;

编译:npx hardhat complie

部署: npx hardhat run scripts/deploy.js --network <network-name>

  • 不带--network参数,会应用hardhat自带的默认网络,
  • 应用remote的网络(测试/正式网络)须要批改hardhat,config.js文件,具体的批改代码如下;
require("@nomiclabs/hardhat-waffle");// Go to https://www.alchemyapi.io, sign up, create// a new App in its dashboard, and replace "KEY" with its keyconst ALCHEMY_API_KEY = "KEY";// Replace this private key with your Ropsten account private key// To export your private key from Metamask, open Metamask and// go to Account Details > Export Private Key// Be aware of NEVER putting real Ether into testing accountsconst ROPSTEN_PRIVATE_KEY = "YOUR ROPSTEN PRIVATE KEY";module.exports = {  solidity: "0.8.4",  networks: {    ropsten: {      url: `https://eth-ropsten.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,      accounts: [`${ROPSTEN_PRIVATE_KEY}`]    }  }};

测试:npx hardhat test

因为hardhat自带本地ETH网络,所以不须要启动节点能够通过web3接口进行测试;

Debug:

 1. 在合约代码中增加 ```import "hardhat/console.sol";``` 导入日志工具; 2. 在须要应用的代码中通过 ```console.log("info %s", to);```的形式打印一些须要的调试信息; 3. 最初应用``` npx hardhat test``` 会输入调试信息;

Solana Anchor

官网文档

依赖装置配置:

  1. 装置rust
  2. 装置solana
  3. 装置node.js和yarn并且换源
  4. 装置anchor

初始化我的项目:

运行 anchor init <new-project-name>

.├── Anchor.toml     // Anchor 配置文件├── Cargo.toml      // Rust 工作区配置文件。├── app                            // 应用程序前端的目录├── migrations      // 合约迁徙部署的代码│   └── deploy.ts├── node_modules├── package.json├── programs          // 合约逻辑代码│   └── test│       ├── Cargo.toml│       ├── Xargo.toml│       └── src                └── lib.rs├── tests                        // 合约测试│   └── test.ts├── tsconfig.json└── yarn.lock

编译:anchor build

编译的命令是上面两条命令的组合;1. `cargo build-bpf`2. `anchor idl parse -f program/src/lib.rs -o target/idl/basic_0.json`

测试:anchor test

部署:anchor deploy

Anchor.toml文件中能够定义部署的网络环境和钱包信息等数据

[provider]    cluster = "localnet"    wallet = "~/.config/solana/id.json"

示例代码

use anchor_lang::prelude::*;declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");#[program]mod basic_1 {    use super::*;    pub fn initialize(ctx: Context<Initialize>, data: u64) -> ProgramResult {        let my_account = &mut ctx.accounts.my_account;        my_account.data = data;        Ok(())    }    pub fn update(ctx: Context<Update>, data: u64) -> ProgramResult {        let my_account = &mut ctx.accounts.my_account;        my_account.data = data;        Ok(())    }}#[derive(Accounts)]pub struct Initialize<'info> {    #[account(init, payer = user, space = 8 + 8)]    pub my_account: Account<'info, MyAccount>,    #[account(mut)]    pub user: Signer<'info>,    pub system_program: Program<'info, System>,}#[derive(Accounts)]pub struct Update<'info> {    #[account(mut)]    pub my_account: Account<'info, MyAccount>,}#[account]pub struct MyAccount {    pub data: u64,}#[error]pub enum ErrorCode {    #[msg("This account cannot update")]    CannotUpdate,}

示例代码解析

  • #[program] 上面的mod中蕴含了instructions,如果你不理解Solana中的instruction,能够看一下官网文档;
  • #[derive(Accounts)] 蕴含了账户信息,solana中的账户有点绕,你能够了解为Linux中所有皆文件的概念,具体的也须要你看官网文档;
  • #[account] 账户属性,账户初始化的时候须要领取租金和指定size;

    #[account(init, payer = user, space = 8 + 8)]#[account(mut)]
  • 上面两个派生宏的组合能够自定义错误信息

    • #[error]
    • #[msg("detail error info")]

ink!

官网Doc

装置依赖:

  1. 装置rust
  2. 装置cargo和wasm依赖
  3. 装置contracts-node

初始化我的项目:

应用命令创立新的合约我的项目:cargo contract new <new project name>

flipper  └─ lib.rs                <-- Contract Source Code  └─ Cargo.toml            <-- Rust Dependencies and ink! Configuration  └─ .gitignore

编译:cargo +nightly contract build

测试:cargo +nightly test

部署:间接在节点的UI界面上传编译之后的文件(target目录下的.contract结尾的文件),substrate的部署和运行时离开的,同一份代码只能部署一份,然而能够有很多的运行实例;

示例代码:

// We are importing the default ink! typesuse ink_lang as ink;#[ink::contract]mod MyContract {    // Our struct will use those default ink! types    #[ink(storage)]    pub struct MyContract {        number: u32,    }        impl MyContract {        /// Constructor that initializes the `u32` value to the given `init_value`.        #[ink(constructor)]        pub fn new(init_value: u32) -> Self {            Self {                number: init_value,            }        }                #[ink(message)]        pub fn my_public_function(&self) {            /* --snip-- */        }        /// Private function        fn my_private_function(&self) {            /* --snip-- */        }     }}self.env().emit_event()  // 用于收回event,向外界提示信息,能够认为和Solana Anchor中的console.log相似self.env().caller()             // 示意合约的调用者,solana中会应用programID来示意;

派生宏介绍

  • #[ink::contract] 用于合约的mod
  • #[ink(storage)] 用户合约中的数据存储,具体反对的数据类型,会对rust原生类型做一些封装;
  • #[ink(constructor) 用户初始化结构,不同与以太坊,这里能够有多个constructor;
  • #[ink(message)] 用于constuctor之外的 pub函数;

总提比照

平台 / 框架代码模版劣势特点难度
ETH / Hardhat包含部署目录,合约目录,测试目录,拆分比拟具体,构造很清晰次要是对代码模块逻辑进行拆分,没有对solidity进行过多的封装,原生迁徙比拟容易;须要理解solidity和javascript
Solana / Anchor包含部署目录,合约目录,测试目录,拆分比拟具体,构造很清晰进行了很多的宏封装,将很多instructions和account进行包装,尽管简化了开发难度和代码量,然而对与刚理解solana的开发者不太容易了解细节;须要理解solana的交易和account含意,并且要会rust
Substrate / ink!单纯的蕴含了合约代码,比拟简洁进行了一些宏封装,简化了开发难度,然而自由度比拟高,不必太局限于太多的链细节;须要会rust,对小白用户比拟敌对