关于区块链:Conflux-Truffle-使用完全指南

6次阅读

共计 13881 个字符,预计需要花费 35 分钟才能阅读完成。

cfxtruffle 应用齐全指南

Truffle 是以太坊生态驰名的智能合约开发工具,提供编译,链接,测试,部署等实用功能,为宽广 Solidity 开发者所青睐。
Conflux 作为新一代高性能公链,不仅在齐全去中心化的前提下实现了两个量级的性能晋升,还实现了跟 EVM 兼容的虚拟机,
意味着 Dapp 开发者不必学习新开发语言即能够在 Conflux 网络上开发利用。
为了晋升 Conflux 的合约开发体验,官网最近也对 Truffle 进行了迁徙革新,打造了 Conflux-Truffle,使之可能反对 Conflux 的合约开发。
本文会具体介绍如何应用 Conflux Truffle 开发 Conflux 智能合约,从环境搭建,创立我的项目,开发,编译,测试,部署,一一介绍。

  1. 基本概念介绍
  2. Dependencies 筹备
  3. 应用 cfxtruffle 开发智能合约
  4. 参考文档

基本概念介绍

区块链世界是去中心化的,所有参加的节点具备雷同的数据,人人平等。而数据在区块链上的组织模式是:首先多笔交易被一块打包造成一个区块 (block),
而后区块之间依据先后顺序链接起来,造成一条链,因而叫区块链 (blockchain)。最后的区块链(bitcoin chain)只反对转账,因而只有一个利用(bitcoin)。
以太坊开创性的增加了 EVM 的性能,具备了图灵完整性,因而在其上能够自在开发各种去中心化利用(Dapp)。

Epoch & storageLimit

传统的区块链账本是一条单链,从前往后每个区块都有一个编号,叫做区块号(block number),conflux 开发了一种全新的账本构造: 树图,实现了高吞吐,低提早。

在树图账本构造中,如果只看父边他是一个 Tree,如果父边援用边都看则是一个 Graph。正是这种构造使得 conflux 网络能够并收回块,即多个区块能够
都在某个区块之后生成。因而在 Conflux 是没有 block number 的概念。
但为了实现全序,Conflux 通过 GHAST 规定从创世区块开始,在其所有子区块中抉择最重子树 block 为 pivot block,所有的 pivot block 链到一块也造成一条链
定义为 pivot chain,如果只看 pivot chain 其跟一般的区块链构造统一,在这条链上基于每个 pivot block 定义一个 Epoch,因而你能够把 conflux 中的
Epoch 了解为跟 block number 对应的概念,只不过 conflux 中的每个 epoch 中可能会有多个 block。

在事实世界中,发送转账交易须要给银行付手续费,在比特币中发送交易须要给矿工付手续费,在以太坊中同样如此。具体来讲,以太坊网络的交易最终是由矿工
运行的 EVM 执行的,gas 是用来掂量一笔交易执行的工作量(能够了解为工作的工时),交易发送者,发送交易时能够指定违心给每个工作量付的价格即 gasPrice。
因而最终一笔交易的手续费为 gas * gasPrice。
在发送一笔交易时指定的 gas 则是一个限度值,即发送方最大违心为一笔交易领取 gas 这么多的工时,如果交易须要的工作量超过 gas,则不会再付钱,交易不会被执行。

在 Dapp 零碎中,交易执行除了须要矿工进行计算付出计算资源外,还须要矿工存储合约的状态,因而须要付出存储资源。在 Conflux 零碎中发送交易时,还须要为状态存储
抵押一部分费用,因而在 conflux 中发送交易时会比以太坊多一个 storageLimit 参数,用于设置违心为某笔交易存储所抵押的费用下限。在合约开释掉应用的存储空间之后,抵押的费用
也会失去返还。

Dapp

传统 App 的所有状态都存储于中心化服务器的数据库上,其状态的查问和批改,间接通过 API 到数据库中执行 SQL 操作即可,尽管速度快,但有数据轻易篡改,隐衷泄露等问题。
Dapp 是运行于区块链零碎之上的利用,被称为去中心化利用。利用状态存储于区块链零碎之上,状态查问须要通过网络,状态更改只能通过发送交易的模式

Wallet

在传统互联网利用中,是通过账号拜访服务的,但数据实质存储于服务提供商的服务器上。在区块链世界中所有的交易发送都须要通过钱包来实现,比方以太坊的 MetaMask,Conflux 的 Portal。
在钱包中你能够查看余额,发送交易,与 Dapp 交互,支付测试网代币等。
其实实质的是,钱包中存有你账户的私钥,在区块链世界中只有私钥能够签名发送交易。
私钥只应该被你本人所保有,不能被他人晓得。

Dependencies 筹备

在进行智能合约开发前,须要先筹备一些开发环境.

NPM

npm 是 node.js 的包管理工具,因为 cfxtruffle 是应用 node 开发,所以须要应用 npm 装置。
npm 蕴含在 node 的安装包中,只有 node 装置胜利,npm 也就装置胜利了。
装置 node 能够间接下载官网的安装包,或者应用 nvm,
装置好之后,能够应用如下命令查看版本:

$ node -v
$ npm -v

cfxtruffle

npm 装置胜利之后,就能装置 cfxtruffle 了。

$ npm install -g conflux-truffle
# 装置实现之后, 可应用如下命令测试
$ cfxtruffle -v

有两点须要留神的中央:

  1. npm install 的时候须要通过 -g 指定全局装置
  2. npm install 包的名字为 conflux-truffle, 装置后的命令行程序为 cfxtruffle

conflux-rust docker

开发合约调试须要运行本地节点,运行 conflux 最简略的办法是应用 docker 运行 conflux-rust 镜像,此形式不须要本人编译程序,筹备配置文件。只须要本地装置有 docker 环境即可。

# 下载 conflux-rust docker 镜像
$ docker pull confluxchain/conflux-rust
# 启动节点
$ docker run -p 12537:12537 --name cfx-node confluxchain/conflux-rust

简略一个命令即启动了一个本地 Conflux 节点,并且该节点会同时创立 10 个本地账号,每个账号调配 1000 CFX 用于合约部署和交互,且这些账号会主动 unlock。
conflux-rust 镜像启动之后,cfxtruffle 能够间接应用它来部署合约,以及同合约交互。

当然也能够本人编译或下载节点程序,自定义配置文件,而后运行本地节点,具体可参看这篇介绍。
当然节点运行起来之后须要手动创立本地账号,并转账给他们使之有余额,以及手动进行解锁。

阐明:

  1. 本地账号能够应用节点命令行(conflux account new)或 local rpc 创立,本地账号能够被节点程序拜访,并间接用于交易签名。
  2. 本地账号能够间接通过 cfx_sendTransaction 发送交易,交易的签名操作由节点实现,不须要当时签名,本地开发 Dapp 十分不便。
  3. 本地账号为了平安,须要解锁能力间接发送交易,能够在调用 cfx_sendTransaction 时通过第二个参数传递明码,也能够当时调用 unlock rpc 解锁账号。
  4. 目前的 cfxtruffle 须要 0.6.0 以上版本的 conflux-rust 镜像搭配应用。

conflux portal

Conflux portal 是一款浏览器插件钱包,反对 Chrome 和 Firefox 等浏览器。在官网点击链接即可下载安装(可能须要翻墙)。

装置后该钱包可切换不同 conflux 网络,当然也能够连贯本地网络,并且能够申领测试网络代币,如果合约本地测试完之后,可部署到测试网络测试。

应用 cfxtruffle 开发智能合约

环境筹备好之后,能够应用 cfxtruffle 开发智能合约了,咱们会应用 cfxtruffle 开发一个具备铸币和转账性能的 coin 合约。

首先来看下 cfxtruffle 所有命令:

$ cfxtruffle -h
Usage: cfxtruffle <command> [options]

Commands:
  compile   Compile contract source files
  config    Set user-level configuration options
  console   Run a console with contract abstractions and commands available
  create    Helper to create new contracts, migrations and tests
  debug     Interactively debug any transaction on the blockchain
  deploy    (alias for migrate)
  exec      Execute a JS module within this Conflux-Truffle environment
  help      List all commands or provide information about a specific command
  init      Initialize new and empty Conflux project
  install   Install a package from the Conflux Package Registry
  migrate   Run migrations to deploy contracts
  networks  Show addresses for deployed contracts on each network
  obtain    Fetch and cache a specified compiler
  opcode    Print the compiled opcodes for a given contract
  publish   Publish a package to the Conflux Package Registry
  run       Run a third-party command
  test      Run JavaScript and Solidity tests
  unbox     Download a Conflux-Truffle Box, a pre-built Conflux-Truffle project
  version   Show version number and exit
  watch     Watch filesystem for changes and rebuild the project automatically

See more at http://truffleframework.com/docs

咱们也能够查看某个具体命令的应用帮忙:

$ cfxtruffle help create

创立我的项目

第一步咱们须要创立一个 cfxtruffle 根底我的项目:

# 创立一个空我的项目
$ cfxtruffle init project-name
# 查看我的项目目录构造
$ cd project-name && tree
.
├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
└── truffle-config.js

3 directories, 3 files

新创建的我的项目有以下文件夹和文件:

  • contracts solidity 合约代码目录
  • migrations 合约部署迁徙脚本目录
  • test 单元测试目录
  • truffle-config.js cfxtruffle 配置文件(js 文件)

另外 cfxtruffle 也提供了许多性能更欠缺的我的项目模板(box)或者叫脚手架,应用模板,会节俭许多初始化工作:

$ mkdir project-name && cd project-name
$ cfxtruffle unbox metacoin

你能够到官网的 box) 列表看看是否有满足你需要的模板.

注:这两个命令,在国内可能须要翻墙。

增加合约

init 命令只会创立一个空我的项目,外面蕴含一个根底的 Migrations 合约及它的迁徙脚本。
咱们须要增加新的文件,来用于开发新的合约,create 命令能够用于创立一个合约相干的所有文件,包含合约源码(contract),部署脚本 (migration),测试脚本(test)。
其应用形式为:cfxtruffle create <artifact_type> <ArtifactName>

当初咱们来创立 Coin 合约的源码文件

$ cfxtruffle create contract Coin

以上命令执行完之后, 会在 contracts 目录创立一个 Coin.sol 文件,咱们能够在其中编写 solidity 代码。
如下是 Coin 合约的 solidity,其实现了铸币,转账,余额查问的性能。

pragma solidity ^0.5.10;

contract Coin {
    // An `address` is comparable to an email address - it's used to identify an account on Ethereum.
    // Addresses can represent a smart contract or an external (user) accounts.
    // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
    address public owner;

    // A `mapping` is essentially a hash table data structure.
    // This `mapping` assigns an unsigned integer (the token balance) to an address (the token holder).
    // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
    mapping (address => uint) public balances;

    // Events allow for logging of activity on the blockchain.
    // Ethereum clients can listen for events in order to react to contract state changes.
    // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
    event Transfer(address from, address to, uint amount);

    // Initializes the contract's data, setting the `owner`
    // to the address of the contract creator.
    constructor() public {
        // All smart contracts rely on external transactions to trigger its functions.
        // `msg` is a global variable that includes relevant data on the given transaction,
        // such as the address of the sender and the ETH value included in the transaction.
        // Learn more: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
        owner = msg.sender;
    }

    // Creates an amount of new tokens and sends them to an address.
    function mint(address receiver, uint amount) public {
        // `require` is a control structure used to enforce certain conditions.
        // If a `require` statement evaluates to `false`, an exception is triggered,
        // which reverts all changes made to the state during the current call.
        // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions

        // Only the contract owner can call this function
        require(msg.sender == owner, "You are not the owner.");

        // Ensures a maximum amount of tokens
        require(amount < 1e60, "Maximum issuance succeeded");

        // Increases the balance of `receiver` by `amount`
        balances[receiver] += amount;
    }

    // Sends an amount of existing tokens from any caller to an address.
    function transfer(address receiver, uint amount) public {
        // The sender must have enough tokens to send
        require(amount <= balances[msg.sender], "Insufficient balance.");

        // Adjusts token balances of the two addresses
        balances[msg.sender] -= amount;
        balances[receiver] += amount;

        // Emits the event defined earlier
        emit Transfer(msg.sender, receiver, amount);
    }
}

该合约具体属性和办法如下:

  • owner 属性:合约所有者,只有合约所有者能够执行铸币操作,owner 具备 public 属性,因而也会主动创立一个对应的办法,用于查问合约的所有者
  • balances 属性:余额,map 类型,用于存储账户的余额信息,
  • constructor 办法:该办法仅会在合约创立的时候执行一次,之后不会再执行,次要用于设置合约初始状态
  • mint 办法:铸币,能够给某个地址生成指定数额的 coin
  • transfer 办法:转账,给另外账户转账
  • Transfer 事件:每当转账操作产生,会触发一个此事件,

compile

solidity 是一种高级语言,其语法参考了 C ++, python, js, 但 solidity 不能间接部署,须要先进行编译。
这其实跟 C++ 程序比拟相似,须要编译为 binary 程序能力执行。
solidity 的编译器是 solc 能够独自装置和应用,不过 cfxtruffle 中集成了编译 compile 的性能能够间接应用。

# 编译合约
$ cfxtruffle compile
# 首次执行,会创立一个 build 目录,编译后的内容会保留在该目录于合约对应的 json 文件中。

solidity 编译后,会生成 bytecode 和 abi(Application Binary Interface 合约对外接口的形容),这两者在部署的时候都会用到。
cfxtruffle 编译后生成的 json 文件中,该文件蕴含有合约的 bytecode,abi,ast,name 等信息,该文件在之后的部署,调试等步骤中都会被用到。

truffle-config.js

truffle-config.js 是我的项目的配置文件,十分重要,cfxtruffle 许多命令运行时都会应用取这里的配置。

module.exports = {
  networks: {
    development: {host: "127.0.0.1",     // Localhost (default: none)
     port: 12537,            // Standard Conflux port (default: none)
     network_id: "*",       // Any network (default: none)
    },
  },
}

其中最重要的配置项为 networks,用于配置 cfxtruffle 部署交互的网络,默认应用 development 网络。
除此之外,还能够配置测试,compiler 等信息,具体参看官网文档

本地部署

合约开发的时候,会先在本地节点部署和测试,前边咱们介绍了如何应用 docker 启动一个本地节点。启动的节点能够用来做本地部署和测试。
cfxtruffle 中的 migrate 命令次要用于合约部署(deploy 是 migrate 的别名)。
migrations 文件夹用于寄存 migration 脚本,这些脚本治理着合约的部署,通常每个合约对应一个 migration 脚本。
cfxtruffle 我的项目创立后会有一个 Migrations.sol 合约,及其对应的迁徙脚本。
该合约次要用于在链上记录合约的部署序号(整数序号)。
每次 migrate 命令执行时会到链上查问上次部署的地位,而后判断是否有新合约须要部署。

Migrations.sol 合约代码如下:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;

contract Migrations {
  address public owner;
  uint public last_completed_migration;

  constructor() public {owner = msg.sender;}

  modifier restricted() {if (msg.sender == owner) _;
  }

  function setCompleted(uint completed) public restricted {last_completed_migration = completed;}
}

当初让咱们来应用 create 命令,增加一个 Coin 合约的部署脚本

$ cfxtruffle create migration Coin
# 生成的 migration 脚本文件名中,会蕴含一个工夫戳数字,咱们须要手动改为递增的序号比方 2_coin.js

而后能够在外面退出如下代码

// require the Coin artifact
const Coin = artifacts.require("Coin")
module.exports = function(deployer) {
  // when `deploy` command run, will execute code here
  deployer.deploy(Coin);
};

设置实现之后能够运行部署命令了

$ cfxtruffle deploy
...
...
2_coin.js
=========

   Deploying 'Coin'
   ----------------
   > transaction hash:    0xd001fb34df8e634e21d7d225bfd0da6128237cd74f170fbc97ad820098ceaeff
   > Blocks: 0            Seconds: 0
   > contract address:    0x8DCe85c454d401318C03956529674b9E2B8E8680
   > block number:        1608
   > block timestamp:     1595475207
   > account:             0x1357DA1577f40EE27aE8870C7f582bD345C65A1c
   > balance:             997.71313608
   > gas used:            437390 (0x6ac8e)
   > gas price:           20 GDrip
   > value sent:          0 CFX
   > total cost:          0.0087478 CFX


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:           0.0087478 CFX


Summary
=======
> Total deployments:   2
> Final cost:          0.01221746 CFX

deploy 命令执行实现之后,会输入部署的后果,比方交易 hash,合约地址,破费的费用等。

合约交互

合约部署之后,通常咱们会须要跟合约进行交互,比方查问状态,发动转账等等。cfxtruffle 内含 console 命令,能够开启一个交互式的命令行环境,
该环境提供了合约的 JS 对象,账号列表,以及 js-conflux-sdk 实例及 util 等十分不便。
你能够在外面实例化合约对象,而后通过实例对象与合约交互,比方:查问状态,批改余额等。
以下是 Coin 合约交互的例子:

$ cfxtruffle console
cfxtruffle(development)> .help  # 查看帮忙
cfxtruffle(development)> Object.keys(global) # 查看 console 环境,可用的全局对象: accounts, cfx, cfxutil, Coin, Migrations
# 实例一个 Coin 合约, 调用合约对象的 deployed() 办法
cfxtruffle(development)> let coin = await Coin.deployed()
# 查看合约的 owner 是谁
cfxtruffle(development)> let owner = await coin.owner()
cfxtruffle(development)> owner
'0x1357DA1577f40EE27aE8870C7f582bD345C65A1c'
# 查看所有可用 account
cfxtruffle(development)> accounts
[
  '0x1357DA1577f40EE27aE8870C7f582bD345C65A1c',
  '0x148A9696F8DCf4d6cB01eC80F1047a3476bA5C56',
  '0x1f69a930B6A4F2BC5Ac03B79A88af9f6bBa0d137'
]
# 查问余额
cfxtruffle(development)> let balance = await coin.balances('0x1357DA1577f40EE27aE8870C7f582bD345C65A1c')
cfxtruffle(development)> balance.toString()
# 铸造新币
cfxtruffle(development)> await coin.mint('0x1357DA1577f40EE27aE8870C7f582bD345C65A1c', 10000)
cfxtruffle(development)> balance = await coin.balances('0x1357DA1577f40EE27aE8870C7f582bD345C65A1c')
cfxtruffle(development)> balance.toString()
'10000'
# 转账
cfxtruffle(development)> await coin.transfer('0x148A9696F8DCf4d6cB01eC80F1047a3476bA5C56', 100)
cfxtruffle(development)> balance = await coin.balances('0x1357DA1577f40EE27aE8870C7f582bD345C65A1c')
cfxtruffle(development)> balance.toString()
'9900'
# 指定交易的 gasPrice
cfxtruffle(development)> await coin.transfer('0x148A9696F8DCf4d6cB01eC80F1047a3476bA5C56', 100, {gasPrice: '0x100'})
# 集成的 cfx 对象是一个 js-conlfux-sdk 实例
cfxtruffle(development)> await cfx.getBalance('0x148A9696F8DCf4d6cB01eC80F1047a3476bA5C56')
cfxtruffle(development)> await cfx.getNextNonce("0xbbd9e9be525ab967e633bcdaeac8bd5723ed4d6b")
# cfxutil
cfxtruffle(development)> let drip = cfxutil.unit.fromCFXToGDrip(0.1)
cfxtruffle(development)> let randomKey = cfxutil.sign.randomPrivateKey()
# 
cfxtruffle(development)> .exit
  • 除此之外还能够在 console 部署新合约,实例化指定地址的合约,estimateGas 等, 对于合约的具体交互方式,能够参看这里文档
  • 另外在 console 中,能够间接执行 cfxtruffle 的命令: networks, compile 等
  • 注:目前 cfxtruffle 暂不反对 develop 命令

合约测试

cfxtruffle 内置了测试框架 (Mocha & Chai),能够编写 js 和 solidity 测试,所有的测试代码位于 test 文件夹中。
接下来应用 create 命令创立一个测试文件。

$ cfxtruffle create test Coin

在外面能够增加以下代码

const Coin = artifacts.require("Coin");
// 留神:这里应用 contract 而不是 describe
contract("Coin", function(accounts) {it("should assert true", async function() {let instance = await Coin.deployed();
    await instance.mint(accounts[0], 10000)
    let balance = await instance.balances(accounts[0]);
    assert.equal(balance.toString(), '10000', "10000 wasn't in the first account");
  });
});

而后应用 test 命令即可执行测试

$ cfxtruffle test

cfxtruffle 每次运行测试,都会齐全新部署一个合约(clean-room), 对于具体如何编写测试代码,能够参看 js 和 solidity 的测试编写阐明。

部署到远端节点

合约在本地开发,测试实现之后,能够尝试部署到测试网络,或者到主网公布合约,cfxtruffle 也反对远端部署。
首先须要在我的项目配置文件中增加一个新的网络配置比方 testnet, 外面设置好 host 和 port。
而后须要设置 privateKeys 字段,该字段是一个私钥数组(远端部署只能在本地进行签名)。

testnet: {
    host: "wallet-testnet-jsonrpc.conflux-chain.org",
    port: 12537,            
    network_id: "*",       
    // 留神:从 portal 获取的私钥须要增加 0x 前缀,privateKeys 也能够指定单个 key,若配置了私钥,请留神不要将代码上传到公开代码仓储中。privateKeys: ['your-private-key']  
},

Conflux portal 的测试环境 存入 按钮外面提供了 CFX 水龙头,可申领一些测试环境的代币用于合约部署。

而后能够通过执行 deploy 命令的时候指定 –network,就能够将合约部署到指定的网络上

$ cfxtruffle deploy --network testnet

执行内部脚本或命令

cfxtruffle 还提供了两个命令 exec, run 可用于执行内部脚本,脚本里能够编写一些与合约交互的逻辑,许多时候这会十分有用。

你能够在我的项目根目录下增加一个脚本 get-balance.js 内容如下

const Coin = artifacts.require("Coin");
module.exports = async function(callback) {
    try {let instance = await Coin.deployed();
        let accounts = await cfx.getAccounts();
        let balance = await instance.balances(accounts[0]);
        console.log(`balance of ${accounts[0]} is: ${balance.toString()}`);
    } catch(e) {console.error(e);
    }
    callback();}

而后就能够应用 exec 命令执行它了

$ cfxtruffle exec ./get-balance.js

run 命令则可用于执行 truffle 的 plugin:

$ npm install --save-dev truffle-plugin-hello

并在 truffle-config.js 中增加对插件的申明

module.exports = {
  /* ... rest of truffle-config */

  plugins: ["truffle-plugin-hello"]
}

而后就能够用 run 命令执行了

$ cfxtruffle run hello

当初在 npm 下面有一些 合约 verify,lint,coverage 等插件能够间接应用, 当然你也能够编写本人的插件,具体方法参看这里

总结

至此咱们从头到尾应用 cfxtruffle 开发了一个 Coin 智能合约,其各个性能的应用办法及其他高级命令没有一一具体介绍,能够参看 truffle 的官网文档。
Conflux 作为新一代公链,主网行将齐全上线,心愿智能合约开发小伙伴都来体验一下它飞个别的性能。也心愿越来越多的利用,能诞生于 Conflux 网络。
实现信赖的真正数字化。

参考

  1. truffle 文档
  2. conflux-rust docker
  3. conflux rpc
  4. 如何运行一个 conflux 本地节点
  5. Solidity 文档
  6. js-conflux-sdk
  7. conflux portal
  8. conflux scan

相干资料库:

  • Conflux 开发材料包
  • conflux-chain github
  • conflux-fans github
正文完
 0