Truffle在ganache-cli部署合约

本文介绍了如何使用Truffle框架和GanacheCLI在本地设置以太坊开发环境,进行智能合约的编译、部署和迁移。讲解了Truffle的迁移文件原理,以及如何处理合约间的依赖关系。同时展示了在不同网络环境下部署的策略,并提到了合约部署后的账户管理和链接库操作。
摘要由CSDN通过智能技术生成

准备

确保安装好了 Truffle Framework 和 Ganache CLI.

$ sudo npm install -g truffle
$ sudo npm install -g ganache-cli   

开始

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

contract Storage {

    mapping (string => string) private _store;

    function addData(string memory key, string memory value) public {
        require(bytes(_store[key]).length == 0);
        _store[key] = value;
    }

    function removeData(string memory key) public returns (string memory) {
        require(bytes(_store[key]).length != 0);
        string memory prev = _store[key];
        delete _store[key];
        return prev;
    }

    function changeData(string memory key, string memory newValue) public {
        require(bytes(_store[key]).length != 0);
        _store[key] = newValue;
    }

}

solidity 0.5.0版本更新后,string后面要加上memory,否则编译会报错。

初始的迁移(Migrations)文件及部署规则

你可以能已经看到了在运行 truffle init 时生成的 Migrations.sol1_initial_migration.js

初始迁移合约一般不需要修改,他们是跟踪部署在区块链上的地址。当然也可以按照自己的需要修改 Migrations.sol 合约文件,进行一些高级的迁移管理,但需要保留truffle init命令创建的接口。

1_initial_migration.js 迁移文件,仅仅是说明如何把 Migrations.sol 合约部署到对应的链上。

1_initial_migration.js 迁移文件名,前面的序号,代表着 truffle migrate 运行迁移文件的顺序,1 表示第一个运行的迁移文件(从 1 开始)。 我们可以创建其他的迁移文件: 2_mycontract_migration.js ,在每个合约部署完成,Truffle 会把迁移序号保存到 Migrations 合约的 last_completed_migration

假设 migrations 就这两个迁移文件,truffle migrate运行时实际会发生 4 笔交易:

运行 1_initial_migration.js 进行部署
把序号 1 写入到合约 Migrations
运行 2_mycontract_migration.js 进行部署
把序号 2 写入到合约Migrations
last_completed_migration 表示的是最后部署的迁移,之后再加入其它的迁移文件:3_yourcontract.js 时, 运行truffle migrate时 Truffle 会首先读取 last_completed_migration 状态变量,参看之前部署到了哪些,再部署比 last_completed_migration 序号大的(所有)迁移文件,这样就可以保证不会重复部署。

注意,如果修改一个已有的合约,需要重新部署的话,直接运行 truffle migrate 是不会自动部署的,需要新加(或修改)一个更高序号的迁移文件,再运行 truffle migrate

truffle migrate 可以接一个 -f 序号 来强制从一个序号开始执行迁移(此时会忽略 last_completed_migration的值)。 例如: truffle migrate -f 2 会从第 2 个迁移文件开始部署。

迁移的相关数据

编写迁移文件

有了这些知识,让我们写下我们的第一个迁移文件 2_deploy_contracts.js, 代码如下:

// 获取对应的合约文件
var Storage = artifacts.require("./Storage.sol");

// JavaScript export
module.exports = function(deployer) {
    // deployer 是用来部署

    // 部署
    deployer.deploy(Storage);
}

编写迁移就这么简单。

为了运行迁移脚本,请在终端中运行以下命令:

truffle migrate

不过这时候,会得到一个错误:

Error: No network specified. Cannot determine current network.

意思是 Truffle 找不到要部署到的网络,这时可以在命令行终端打开一个新的 tab 运行 ganache-cli 来启动一个模拟的测试区块链,启动后,有会类似输出:

/TruffleTest$ ganache-cli
Ganache CLI v6.12.2 (ganache-core: 2.13.2)

Available Accounts
==================
(0) 0x36eC0bC604780Da01da74fdc21062090342422F0 (100 ETH)
(1) 0x5df8Ff0fC05Fa2d0eDE36a14c22958652b5e2396 (100 ETH)
(2) 0xEB20b6e8844A32c50F1149Df54f6AAC55754b248 (100 ETH)
(3) 0x8Bb575F18d54dc570449E14A3A453555628e597F (100 ETH)
(4) 0xf29Bae551395fd286345518262A197950Ffb3903 (100 ETH)
(5) 0xEfd420BB71682725fCEf27a48D88dfc04d20c171 (100 ETH)
(6) 0xC07026932a7C29C3505Ec28baf2c372177849f8a (100 ETH)
(7) 0x4d219b1490B21849BFdADC071B18E761863B9AB1 (100 ETH)
(8) 0xF33e7CeaA8825c90cAFb332EA3A0448fFEE242E7 (100 ETH)
(9) 0xd0Ffeb7caA16025e713EabF1761a9bb431406322 (100 ETH)

Private Keys
==================
(0) 0x627e7ad2299bf54679de34746714d4559b7dd463d4c869d37a540d8f0f00fba4
(1) 0x0fb839122b11abe05bb8783578a74d0a1ac11ea314b200050b3e394ab3e6119c
(2) 0x51a4f0d22d1ecad211a580944152f03b8ea7fdf13b5e22def7fbec17bb0750bb
(3) 0x8d95d6d02882d591beddaa46a8f59910db588b7ef3c5cc43ee58dd9b67fc93ac
(4) 0x9dd25620de22ce96616aa933066a2f240f09819beed9cb611e0004034fc61bff
(5) 0x5e4d89ce7885cb5f645eee49a8b844c29edb4447b0e7bfa9449583a412e8aa06
(6) 0x79d5edde2f9cf0c2e0d572cfc74ee2b6b2efe4883bcb9d095f27bfd72cc106c2
(7) 0xd9c62a643dc16531a4e22c50491af696f30a029422d9170cd2776ac6f8303621
(8) 0x9e0d415bb50dbc5f095a001f0a642bc069560cbc37b229b0d2960c90719dc664
(9) 0xb214a0f61c14119b47decdfb59124cb2f6ffe33960ac2af08b45a52da6e766bf

HD Wallet
==================
Mnemonic:      entire exhaust spoon client ladder used harsh hobby cabbage swing cave where
Base HD Path:  m/44'/60'/0'/0/{account_index}

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Call Gas Limit
==================
9007199254740991

Listening on 127.0.0.1:8545

现在已经建立了一个私有区块链,它运行在localhost:8545上。

现在让我们配置 Truffle 以便部署合约到该网络。
打开 truffle-config.js 文件,加入以下内容:

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "*"
    }
  }
};

上面配置的含义是把编译的合约部署到 localhost:8545 所在的网络上。

现在运行 truffle migrate , 得到以下输出:

/TruffleTest$ truffle migrate

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.



Starting migrations...
======================
> Network name:    'development'
> Network id:      1628492486749
> Block gas limit: 6721975 (0x6691b7)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > transaction hash:    0x8a16df1dde1da9624236320f31505e1149b1401ea3229347f830fe074690f8d7
   > Blocks: 0            Seconds: 0
   > contract address:    0xeaFd135174544015f10edCC4C38494f2967EC72D
   > block number:        1
   > block timestamp:     1628492566
   > account:             0x36eC0bC604780Da01da74fdc21062090342422F0
   > balance:             99.99616114
   > gas used:            191943 (0x2edc7)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00383886 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00383886 ETH


2_deploy_contracts.js
=====================

   Deploying 'Storage'
   -------------------
   > transaction hash:    0x6c34134d752cf425413d27fe1d102a05afb0e684655f6d5826cf4efa60648202
   > Blocks: 0            Seconds: 0
   > contract address:    0x7c91Ba1Fa7395B94909021Fe186fc172F0b1a71D
   > block number:        3
   > block timestamp:     1628492566
   > account:             0x36eC0bC604780Da01da74fdc21062090342422F0
   > balance:             99.98386434
   > gas used:            572502 (0x8bc56)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.01145004 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.01145004 ETH


Summary
=======
> Total deployments:   2
> Final cost:          0.0152889 ETH


可以看到truffle migrate部署合约时使用的账户是 ganache-cli 预置的10个账户的第一个账户: 0x36eC0bC604780Da01da74fdc21062090342422F0

Truffle 将合约迁移到网络并保存了构件(artifacts)。 在构建目录(build/contracts/)的 Storage.json文件中,通过检查 networks 对象来检查它是否正确。 您应该看到类似以下内容:

  "networks": {
    "1628492486749": {
      "events": {},
      "links": {},
      "address": "0x7c91Ba1Fa7395B94909021Fe186fc172F0b1a71D",
      "transactionHash": "0x6c34134d752cf425413d27fe1d102a05afb0e684655f6d5826cf4efa60648202"
    }
  },

1628492486749 是网络的 ID,以太坊网络主网和测试网都有固定的 ID(主网是 1)。
address 是部署合约的地址。
transactionHash 是部署合约的交易hash。

在后面会看到如何使用。

部署多合约

Truffle 迁移的真正亮点是能进行多个合约的编译、部署和跟踪(几乎所有区块链项目都是这样)。

迁移文件不仅允许我们使用单个命令部署多个合约,还允许我们调用合约的函数,如获取这些函数的返回值并将其传递给后续合约。

我们在 contracts 目录下,添加一个新合约 InfoManager.sol, 代码如下:

pragma solidity >0.4.21;

import "./Storage.sol";

contract InfoManager {

    Storage private _dataStore;

    uint private _lastAdded;

    constructor(Storage dataStore) public {
        _dataStore = dataStore;
    }

    function addData(string memory key, string memory value) public {
        require((now - 1 days) > _lastAdded);
        _dataStore.addData(key, value);
    }

}

可以看出,InfoManager 依赖 Storage 合约,不仅如此,InfoManager的构造函数还需要 Storage 合约作为参数。

重新修改一下 2_deploy_contracts.js 让它可以完成 InfoManager 的部署:

var Storage = artifacts.require("./Storage.sol");
var InfoManager = artifacts.require("./InfoManager.sol");

module.exports = function(deployer) {

    // 部署 Storage
    deployer.deploy(Storage)
        // 等待、直到合约部署完成
        .then(() => Storage.deployed())
        // 传递 Storage 合约地址,部署 InfoManager 合约
        .then(() => deployer.deploy(InfoManager, Storage.address));
}

部署的语法是:

...
deployer.deploy(`ContractName`, [`constructor params`]) // 返回一个 promise
...

因为 deploy(...) 返回一个 promise, 我们可以按自己喜欢的方式处理它,不过要注意的是在部署文件里,还不支持 async

我们还可以在部署合约后自定义调用函数。例如,迁移还可以这样:

deployer.deploy(Storage)
    .then(() => Storage.deployed())
    .then((instance) => {
        instance.addData("Hello", "world")
    }).then(() => deployer.deploy(InfoManager, Storage.address));

这样在部署 InfoManager 之前,先给Storage 添加一条数据。

这个技巧很有用,因为有时相互依赖的合约可能需要在构造函数的之外写入。

根据网络进行部署

还可以根据所处的网络不同,进行不同的部署。这对于在开发阶段使用模拟链的数据而在主网上线时使用已部署的主网合约作为输入参数到合约中都非常有用。

通过导出函数 module.exports 扩展一个参数 network

module.exports = function(deployer, network) {
    if (network == "live") {
        // do one thing
    } else if (network == "development") {
        // do other thing
    }
}

选择账号进行部署

module.exports 默认函数还可以公开一个账号参数,这些账号是以太坊节点或钱包provider “暴露” 出来的,看看下面的例子:

module.exports = function(deployer, network, accounts) {
    var defaultAccount;
    if (network == "live") {
        defaultAccount = accounts[0]
    } else {
        defaultAccount = accounts[1]
    }
}

链接库

你还可以通过 deployer.link(...) 连接已经存在(部署)的库:

...
deployer.deploy(MyLibrary);
deployer.link(MyLibrary, MyContract);
deployer.deploy(MyContract);
...

结论

通过使用上面的这些技术,可以把大部分区块链部署工作自动化,并减少开发去中心化应用程序涉及的大量重复工作。

相关内容:
TypeError: Data location must be “memory“ for parameter in function, but none was given.

Truffle框架是一个用于以太坊智能合约开发的开发环境和工具集,Ganache则是一个用于本地测试以太坊智能合约的工具。下面是使用Truffle框架和Ganache网络进行智能合约部署的具体流程和代码。 1. 安装Truffle框架和Ganache网络 首先需要在本地安装Truffle框架和Ganache网络。可以使用npm命令进行安装: ``` npm install -g truffle npm install -g ganache-cli ``` 2. 创建Truffle项目 使用Truffle框架创建一个新的项目: ``` truffle init ``` 这将会在当前目录下创建一个名为`truffle-config.js`的配置文件和一个名为`contracts`的合约目录。 3. 编写智能合约代码 在`contracts`目录下创建一个名为`MyContract.sol`的智能合约文件,并编写合约代码。例如,创建一个简单的存储合约: ``` pragma solidity ^0.8.0; contract MyContract { uint256 private value; function setValue(uint256 newValue) public { value = newValue; } function getValue() public view returns (uint256) { return value; } } ``` 4. 配置Truffle项目 在`truffle-config.js`文件中配置Truffle项目。首先需要指定要使用的网络,这里使用Ganache网络: ``` module.exports = { networks: { development: { host: "localhost", port: 8545, network_id: "*" } } }; ``` 5. 编译智能合约 使用Truffle框架编译智能合约: ``` truffle compile ``` 6. 部署智能合约 使用Truffle框架部署智能合约: ``` truffle migrate ``` 这将会将智能合约部署Ganache网络上。 7. 与智能合约交互 现在可以使用Web3.js或其他以太坊客户端库与智能合约进行交互。以下是一个使用Web3.js与上一步中部署的存储合约进行交互的示例代码: ``` const Web3 = require('web3'); const web3 = new Web3('http://localhost:8545'); const myContract = new web3.eth.Contract([{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"setValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}], '0x1234567890123456789012345678901234567890'); myContract.methods.setValue(42).send({from: '0x1234567890123456789012345678901234567890'}) .then(() => myContract.methods.getValue().call()) .then(value => console.log(value)); ``` 这段代码首先创建了一个Web3实例,并连接到Ganache网络。然后创建了一个`myContract`实例,它表示上一步中部署的存储合约。最后使用`myContract`实例调用`setValue`方法将值设置为42,并使用`getValue`方法获取当前值并输出到控制台。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值