2020-11-01以太坊搭建

参考博客
https://blog.csdn.net/weixin_42172261/article/details/106915121
https://infura.io/dashboard/ethereum(创建项目的网站)
https://blog.csdn.net/weixin_40788897/article/details/103918598
https://blog.csdn.net/shangsongwww/article/details/89977236
https://blog.csdn.net/u011240877/article/details/76582670
https://blog.csdn.net/qq_20513027/article/details/85041353
跟着博客学习https://www.qikegu.com/docs/4839

环境安装

ubuntu下安装nodejs和npm
安装nodejs

sudo apt-get install nodejs

运行 nodejs -v 会弹出安装node的版本号

这里使用的是 nodejs 并不是常用的node ,可以通过

sudo ln -s /usr/bin/nodejs /usr/bin/node

命令让node与nodejs
建立软连接,接着就可以使用 node命令

安装npm:

sudo apt-get install npm

测试安装是否成功: npm -v 弹出安装的版本号,即可证明安装成功

Truffle 框架安装

使用 $ npm install -g truffle 这个一直失败

于是,看了一些帖子,找到了它

sudo -E npm install truffle@2.0.8 -g
truffle --version

出现Truffle v5.0.35 - a development framework for Ethereum成功。

安装Ganache
我使用了图形界面,因为用命令行的我总是报错。
ganache:用于测试和开发的快速以太坊RPC客户端,其目前有两个版本:图形界面的版本和命令行版本,任选一个下载即可。我使用了图形界面,因为命令行的我总是报错。

图形界面版本
1)对于Linux系统,在 https://github.com/trufflesuite/ganache/releases下载以.AppImage为后缀的包(windows:.appx mac:dmg)
或在终端输入wget https://github.com/trufflesuite/ganache/releases/download/v1.1.0/ganache-1.1.0-x86_64.AppImage进行下载
2)修改权限chmod +x ganache-1.1.0-x86_64.AppImage
3)直接在命令行输入sudo ./ganache-1.1.0-x86_64.AppImage即可运行
下面是命令行的方式,大家可以参考。

1.命令行版本ganache-cli
1)输入sudo npm install -g ganache-cli
2)将truffle复制到/usr/local/bin路径中,输入:
sudo ln -s /opt/node-v8.9.4-linux-x64/bin/ganache-cli /usr/local/bin/ganache-cli

安装 MetaMask

要安装Chrome版本MetaMask ,前往*Chrome网上应用店*,然后点击添加到Chrome按钮。

要安装FireFox版本MetaMask ,前往*Firefox附加组件页面*并单击添加到Firefox按钮。

Ganache本地区块链

启动Ganache,因为我用的是图像化界面,所以使用sudo ./ganache-1.1.0-x86_64.AppImage即可运行。

开发智能合约

首先创建项目目录:

$ mkdir mydapp
$ cd mydapp
$ truffle init

truffle init:初始化项目,将生成项目模板文件。

添加package.json文件
package.json是npm用来管理包的配置文件,在项目根目录下创建此文件,内容如下:

{
  "name": "ethereum-demo",
  "version": "1.0.0",
  "description": "以太坊demo",
  "main": "truffle-config.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "dev": "lite-server",
    "test": "echo \"Error: no test specified\" && sexit 1"
  },
  "author": "kevinhwu@qikegu.com",
  "license": "ISC",
  "devDependencies": {
    "@truffle/contract": "^4.0.33",
    "dotenv": "^8.1.0",
    "lite-server": "^2.5.4",
    "truffle-hdwallet-provider": "^1.0.17"
  }
}

ps:不能少了 “dev”: “lite-server”,不然后面运行服务器的时候容易出问题。

添加智能合约源文件
在contracts 目录中创建一个新文件MyContract.sol,内容如下所示:

// 声明solidity版本
pragma solidity ^0.5.0;

// 声明智能合约MyContract,合约的所有代码都包含在花括号中。
contract MyContract {

    // 声明一个名为value的状态变量
    string value;

    // 合约构造函数,每当将合约部署到网络时都会调用它。
    // 此函数具有public函数修饰符,以确保它对公共接口可用。
    // 在这个函数中,我们将公共变量value的值设置为“myValue”。
    constructor() public {
        value = "myValue";
    }

    // 本函数读取值状态变量的值。可见性设置为public,以便外部帐户可以访问它。
    // 它还包含view修饰符并指定一个字符串返回值。
    function get() public view returns(string memory ) {
        return value;
    }

    // 本函数设置值状态变量的值。可见性设置为public,以便外部帐户可以访问它。
    function set(string memory _value) public {
        value = _value;
    }
}

PS:pragma solidity ^0.5.0;,构造函数constructor() public, view修饰符这些在编译的时候都会报错,我用了最简单粗暴的方法,把他们删掉了。出错原因目前不明。

编译项目

$ truffle compile

部署智能合约到Ganache

更新配置文件
更新项目的配置文件,修改网络配置连接到本地区块链网络(Ganache)。

打开位于项目根目录下的truffle-config.js文件,修改内容如下:

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*" // Match any network id
    }
  },
  solc: {
    optimizer: {
      enabled: true,
      runs: 200
    }
  }
}

这些网络配置,包括ip地址、端口等,应该与Ganache的网络配置匹配:

在这里插入图片描述创建迁移脚本
接下来,我们将在migrations目录中创建迁移脚本,告诉Truffle如何部署智能合约,在该目录中创建文件2_deploy_contracts.js。

vi 2_deploy_contracts.js

注意,在migrations目录中所有文件都有编号,作用是让Truffle知道执行它们的顺序。

2_deploy_contracts.js文件内容如下:

var MyContract = artifacts.require("./MyContract.sol");

module.exports = function(deployer) {
  deployer.deploy(MyContract);
};

执行迁移命令

$ truffle migrate

使用 truffle console 访问智能合约

启动 truffle console:

$ truffle console
MyContract.deployed().then((instance) => { app = instance } )
app.get()
// => 'myValue'
app.get()
// => 'myValue'
app.get()
// => 'New Value'
.exit

由于第一句MyContract.deployed().then((instance) => { app = instance } )出现问题,后面几句都没运行成功。我运行了`MyContract.deployed(),可以成功。

智能合约测试(truffle test)

在项目根目录下的test目录中,添加测试脚本文件: MyContract.js

vi MyContract.js

MyContract.js中的测试代码:

// 首先,`require`合约并将其分配给一个变量`MyContract`
const MyContract = artifacts.require('./MyContract.sol');

// 调用“contract”函数,并在回调函数中编写所有测试
// 回调函数提供一个“accounts”变量,表示本地区块链上的所有帐户。
contract('MyContract', (accounts) => {

    // 第1个测试:调用get()函数,检查返回值,测试合约中value初始值是否是: 'myValue'
    it('initializes with the correct value', async () => {
        // 获取合约实例
        const myContract = await MyContract.deployed()
        const value = await myContract.get()
        // 使用断言测试value的值
        assert.equal(value, 'myValue')
    })

    // 第2个测试: 调用set()函数来设置value值,然后调用get()函数来确保更新了值
    it('can update the value', async () => {
        const myContract = await MyContract.deployed()
        myContract.set('New Value');
        const value = await myContract.get()
        assert.equal(value, 'New Value')
    })
})

运行测试脚本

$ truffle test

连接公链

设置钱包来管理公链帐户
打开Ganache,主界面上可以看到一个名为“MNEMONIC”的部分:这是一个种子短语(几个单词的集合),用于构建由Ganache管理的钱包。我们可以使用这个种子短语加密重建钱包,来连接到公链。

复制这个值,保存到一个秘密文件,MNEMONIC是一个秘密值,需要保密。在项目根目录中创建一个.env文件,保存MNEMONIC值,如下所示:

$ vi .env
MNEMONIC="你的mnemonic"

连接到以太坊节点
比较方便的方法是,使用Infura访问Ethereum节点。Infura(https://infura.io/dashboard/ethereum)是一个免费提供Ethereum节点的服务。

在Infura上注册账号,创建项目,在项目详情页上可以查看API KEY
在这里插入图片描述在这里插入图片描述使用API KEY,就可以访问以太坊网络节点。

在.env文件中添加Infura api key的配置:

INFURA_API_KEY="https://kovan.infura.io/v3/543526cd4d3846acbc3826484e934564"
MNEMONIC="你的mnemonic"

更新项目设置
修改truffle-config.js文件

// 导入dotenv库创用于读取`.env`文件中的设置
require('dotenv').config();
// 导入truffle-hdwallet-provider库重建钱包
const HDWalletProvider = require('truffle-hdwallet-provider');

module.exports = {
  networks: {
    development: {
     host: "127.0.0.1",     // Localhost (default: none)
     port: 7545,            // Standard Ethereum port (default: none)
     network_id: "*",       // Any network (default: none)
    },
    // Useful for deploying to a public network.
    // NB: It's important to wrap the provider as a function.
    kovan: {
      provider: () => new HDWalletProvider(
        process.env.MNEMONIC, 
        process.env.INFURA_API_KEY
      ),
      gas: 5000000,
      gasPrice: 25000000000,
      network_id: 42
    },
  },
  solc: {
    optimizer: {
      enabled: true,
      runs: 200
    }
  }
}

访问以太坊节点
由于用到了dotenv与truffle-hdwallet-provider这2个库,我们需要先安装:

切换到项目目录,执行以下命令

npm install dotenv --save-dev
npm install truffle-hdwallet-provider --save-dev

访问以太坊节点
使用truffle console连接到公共区块链网络:

$ truffle console --network kovan

复制要验证连接,可以从区块链中读取一些数据,获取一些关于最新区块的信息,在控制台上执行:

web3.eth.getBlock('latest').then(console.log)

上面这句话我又没成功,于是我就执行了web3.eth.getBlock('latest')

部署智能合约到公链

部署需要消耗Gas,获取测试以太币用于部署
可以从Kovan faucet Gitter聊天室(https://gitter.im/kovan-testnet/faucet#)获取测试用的伪以太币。只需把钱包地址发送出去,约5分钟内,有人会给你发测试用的伪以太币。

打开Ganache并复制列表中第一个帐户的地址(钱包地址),类似下面所示:

0x29920e756f41F8e691aE0b12D417C19204371E91
复制

发送到聊天室内,稍等片刻,你的账号将收到一笔以太币。
部署智能合约
现在帐户里已经有了资金,可以进行部署了。

执行部署命令:

truffle migrate --network kovan

一旦部署完成,应该会看到部署成功的消息。
验证部署
现在打开truffle控制台,与kovan测试网络上的智能合约进行交互:

$ truffle console --network kovan

复制
在控制台中执行:

truffle(kovan)> MyContract.deployed().then((c) => { contract = c })

我又只能执行半句话MyContract.deployed().

然后:(下面的我也无法执行)

truffle(kovan)> contract.get()
'myValue'
truffle(kovan)> contract.set("hello world")
{ tx:
   '0x7bf63444f3a7bd70e981a7bd49228b1cf1a8c3754daf64c4c7765b8eee46bf37',
  receipt:
   { blockHash:
      '0xe03d0f43d85f4e41c18a90aa563ebda08899c6b9c38d0cd7779937046e2aed0c',
     blockNumber: 13447763,
     contractAddress: null,
     cumulativeGasUsed: 33629,
     from: '0x29920e756f41f8e691ae0b12d417c19204371e91',
     gasUsed: 33629,
     logs: [],
     logsBloom:
      '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
     root: null,
     status: true,
     to: '0x4d3cfaf8457cea76c0409f989f9870115b4d2d82',
     transactionHash:
      '0x7bf63444f3a7bd70e981a7bd49228b1cf1a8c3754daf64c4c7765b8eee46bf37',
     transactionIndex: 0,
     rawLogs: [] },
  logs: [] }
truffle(kovan)> contract.get()
'hello world'

truffle脚本

在项目根目录下,创建script.js文件,内容如下:

module.exports = function(callback) {
  web3.eth.getBlock('latest').then(console.log)
}

该脚本将从Kovan测试网络获取最新区块的信息。
执行脚本:

truffle exec script.js --network kovan

下面的代码智能合约MyContract中,读取value值,将script.js脚本文件中的代码替换为:

const MyContract = artifacts.require("./MyContract.sol");

module.exports = async function(callback) {
  const contract = await MyContract.deployed()
  const value = await contract.get()
  console.log("Value:", value)
}

执行脚本:

truffle exec script.js --network kovan

输出:

Value: hello world

脚本运行器是一个非常有用的功能

让浏览器支持区块链(MetaMask)

安装MetaMask
我们将为Chrome浏览器安装Metamask钱包插件(需翻墙)。

安装好后,确保插件的启用按钮打开,在浏览器的右上角会看到一个狐狸🦊图标。

导入账号
把钱包账号从Ganache导入到Metamask中,这样我们就可以连接到区块链了。

打开Ganache主界面,复制MNEMONIC(随机种子),也可以叫私钥。打开Metamask,选择通过Seed Phrase导入账号,把复制MNEMONIC的值,粘贴到Wallet Seed。
可以参考这篇:https://blog.csdn.net/shangsongwww/article/details/89977236
进入钱包
查看Kovan网络,可以看到里面有一些测试以太币余额。

智能合约前端页面

显示当前连接的帐户
配置web服务器
首先,让我们来配置web服务器。服务器使用lite-server,安装lite-server:

$ npm install lite-server --save-dev

项目根目录下,创建lite-server的配置文件bs-config.json,内容如下:

{
  "server": {
    "baseDir": [
      "./src",
      "./build/contracts"
    ],
    "routes": {
      "/vendor": "./node_modules"
    }
  }
}

创建前端页面
项目根目录下,创建src目录,用于存放前端页面。

前端页面包含2个文件:

src/index.html
src/app.js

index.html
添加index.html页面,内容如下:

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>以太坊 DApp Demo</title>

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
      <h1>账号: <span id="account"></span></h1>
      <hr>
      <div id="content">
          <h2>智能合约:MyContract</b></h2>
          <p>获取智能合约中的value值: <span id="value"></span></p>

            <h5>设置value值</h5>
            <form onSubmit="App.set(); return false;" role="form">
            <div >
                <input id="newValue" type="text"></input>
            </div>
            <button type="submit" >设置</button>
            </form>
      </div>
      <div id="loader">正在加载...</div>


    </div>

    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="https://etherscan.io/jss/web3.min.js"></script>
    <script src="vendor/@truffle/contract/dist/truffle-contract.js"></script>
    <script src="app.js"></script>
  </body>
</html>

添加javascript脚本文件:app.js

App = {
    web3Provider: null,
    contracts: {},
    account: '0x0',
    loading: false,
    contractInstance: null,

    init: async () => {
        // 加载web3
        await App.loadWeb3()
        // 加载智能合约
        await App.loadContract()
        // 网页刷新
        await App.render()
    },

    // https://medium.com/metamask/https-medium-com-metamask-breaking-change-injecting-web3-7722797916a8
    loadWeb3: async () => {
        if (typeof web3 !== 'undefined') {
            App.web3Provider = web3.currentProvider
            web3 = new Web3(web3.currentProvider)
        } else {
            window.alert("Please connect to Metamask.")
        }
        // MetaMask新版本…
        if (window.ethereum) {
            window.web3 = new Web3(ethereum)
            try {
                // 向用户请求帐户访问
                await ethereum.enable()
                // 用户允许使用账户
                web3.eth.sendTransaction({/* ... */ })
            } catch (error) {
                // 用户拒绝使用账户
            }
        }
        // MetaMask老版本…
        else if (window.web3) {
            App.web3Provider = web3.currentProvider
            window.web3 = new Web3(web3.currentProvider)
            // 无需向用户请求,可以直接使用账号
            web3.eth.sendTransaction({/* ... */ })
        }
        // 没有安装以太坊钱包插件(MetaMask)...
        else {
            console.log('需要安装以太坊钱包插件(例如MetaMask)才能使用!')
        }
    },

    loadContract: async () => {
        const contract = await $.getJSON('MyContract.json')
        App.contracts.MyContract = TruffleContract(contract)
        App.contracts.MyContract.setProvider(App.web3Provider)
    },

    render: async () => {
        // 如果正在加载,直接返回,避免重复操作
        if (App.loading) {
            return
        }

        // 更新app加载状态
        App.setLoading(true)

        // 设置当前区块链帐户
        const accounts = await ethereum.enable()
        App.account = accounts[0]
        $('#account').html(App.account)

        // 加载智能合约
        const contract = await App.contracts.MyContract.deployed()
        App.contractInstance = contract

        const value = await App.contractInstance.get()
        $('#value').html(value)

        App.setLoading(false)
    },

    set: async () => {
        App.setLoading(true)

        const newValue = $('#newValue').val()

        await App.contractInstance.set(newValue, {from: App.account})
        window.alert('更新成功,页面值不会马上更新,等待几秒后多刷新几次。')
        App.setLoading(false)
    },

    setLoading: (boolean) => {
        App.loading = boolean
        const loader = $('#loader')
        const content = $('#content')
        if (boolean) {
            loader.show()
            content.hide()
        } else {
            loader.hide()
            content.show()
        }
    }
}

$(document).ready(function () {
    App.init()
});

现在安装、启动服务器:

$ npm install @truffle/contract --save-dev

$ npm run dev

然后使用安装了MetaMask插件的Chrome浏览器,打开网址:http://localhost:3000,就可以查看前端页面,与区块链上的智能合约进行交互。

问题汇总

1、contracts/Migrations.sol: ParsedContract.sol:7:14: ParserError: Expected identifier, got 'LParen'
  constructor() public {
             ^
Compilation failed. See above.
~/eth-hunt/ 

truffle 编译构造函数出问题。目前还没有解决。

2、ubuntu中如何创建一个.env文件
$ vi .env

在ubuntu中,创建任何后缀文件,都用vi

3、MyContract.deployed().then((instance) => { app = instance } )

这个语句执行不了,,每次只能执行前半句MyContract.deployed().

4、TypeError: web3.eth.contract is not a function

参考:https://blog.csdn.net/chyabc123456hh/article/details/107858454

5、lzk@lzk-virtual-machine:~/mydapp/src$ npm run dev
npm ERR! missing script: dev

原因是package.json文件中少了配置。dev.

6、truffle create contract MyContract报错

改为truffle create:contract MyContract

 7、truffle compile 
TypeError: this is not a typed array.

升级npm

npm update npm -g

很多问题,都不同版本引起的问题。

慢慢摸索中,有一起学习区块链方向的小伙伴,可以加我一起探讨!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值