Dapp开发以太坊- Ethereum区块链技术文章

以太坊开发(五)使用 Browser-solidity 在 Go

2018-02-25  本文已影响1523人  yuyangray

基本概念

智能合约

智能合约是存储在区块链上的一段代码,它们可以被区块链上的交易所触发,触发后,这段代码可以从区块链上读取数据或者向区块链上写入数据。

Solidity

Solidity 是 Ethereum 的一种契约型编程语言,运行在Ethereum虚拟机(EVM)之上。

Solidity的语言特性

它的语法接近于Javascript,是一种面向对象的语言。但作为一种真正意义上运行在网络上的去中心合约,它又有很多的不同,下面列举一些:

Browser-solidity

Browser-solidity 是一个官方提供的一个基于浏览器的合约编译器,非常好用,而且build版本会紧跟最新的Solidity的build版本。但由于网络原因以及GFW的存在,有可能会另一部分人访问很慢,进而影响开发效率。

可以直接在线使用,访问后面的地址:https://remix.ethereum.org

源码地址:https://github.com/ethereum/browser-solidity

本文环境:

Mac OS 10.13.3

Geth v1.8.1

Browser-solidity

Nvm v0.33.8

本地安装Browser-solidity

安装NVM

安装Browser-solidity需要依赖node、npm、nvm。
官方GitHub:

Make sure that you have the correct version of node, npm and nvm.

使用以下命令确认是否安装:

node --version
npm --version
nvm --version

以下是三者简单的介绍及关系说明:原文

  1. nvm的官方叫法:nodejs版本管理工具。
    nvm相当于是家长,一个家长可以管理多个孩子。
    也就是说:一个nvm可以管理很多node版本和npm版本。
  1. nodejs
    在项目开发时的所需要的代码库
  1. npm
    在安装的nodejs的时候,npm也会跟着一起安装,它是包管理工具。
    npm管理nodejs中的第三方插件
  1. nvm、nodejs、npm的关系:
    nvm是爸爸,管理nodejs和npm这一对双胞胎兄弟。npm是哥哥, npm哥哥可以管理node弟弟的东西。

前面已经讲过node的安装了,这里安装nvm。

官方GitHub:https://github.com/creationix/nvm

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash

安装完成后查看是否成功:

yuyangdeMacBook-Pro:~ yuyang$ nvm --version
0.33.8

安装Browser-solidity

git clone https://github.com/ethereum/remix-ide.git
cd browser-solidity
npm install

安装完成后,使用以下命令启动:

npm start

启动后,控制台会输出如下信息:

yuyangdeMacBook-Pro:~ yuyang$ cd /Users/yuyang/browser-solidity 
yuyangdeMacBook-Pro:browser-solidity yuyang$ npm start

> browser-solidity@0.0.0 start /Users/yuyang/browser-solidity
> npm-run-all -lpr serve watch onchange remixd

[serve   ] 
[serve   ] > browser-solidity@0.0.0 serve /Users/yuyang/browser-solidity
[serve   ] > execr --silent http-server .
[serve   ] 
[onchange] 
[onchange] > browser-solidity@0.0.0 onchange /Users/yuyang/browser-solidity
[onchange] > onchange build/app.js -- npm-run-all lint
[onchange] 
[remixd  ] 
[remixd  ] > browser-solidity@0.0.0 remixd /Users/yuyang/browser-solidity
[remixd  ] > node ./node_modules/remixd/src/main.js -s ./contracts
[remixd  ] 
[watch   ] 
[watch   ] > browser-solidity@0.0.0 watch /Users/yuyang/browser-solidity
[watch   ] > watchify src/index.js -dv -p browserify-reload -o build/app.js
[watch   ] 
[remixd  ] example: --dev-path /home/devchains/chain1 --mist --geth --frontend /home/frontend --frontend-port 8084 --auto-mine
[remixd  ] 
[remixd  ]   Usage: main -s <shared folder>
[remixd  ] 
[remixd  ]   Provide a two ways connection between the local computer and Remix IDE
[remixd  ] 
[remixd  ] 
[remixd  ]   Options:
[remixd  ] 
[remixd  ]     -s, --shared-folder <path>            Folder to share with Remix IDE
[remixd  ]     -m, --mist                            start mist
[remixd  ]     -g, --geth                            start geth
[remixd  ]     -p, --dev-path <dev-path>             Folder used by mist/geth to start the development instance
[remixd  ]     -f, --frontend <front-end>            Folder that should be served by remixd
[remixd  ]     -p, --frontend-port <front-end-port>  Http port used by the frontend (default 8082)
[remixd  ]     -a, --auto-mine                       mine pending transactions
[remixd  ]     -r, --rpc <cors-domains>              start rpc server. Values are CORS domain
[remixd  ]     -rp, --rpc-port                       rpc server port (default 8545)
[remixd  ]     -h, --help                            output usage information
[remixd  ] [WARN] Any application that runs on your computer can potentially read from and write to all files in the directory.
[remixd  ] [WARN] Symbolinc links are not forwarded to Remix IDE
[remixd  ] 
[remixd  ] [WARN] Symbolic link modification not allowed : ./contracts | /Users/yuyang/browser-solidity/contracts
[remixd  ] Shared folder : ./contracts
[remixd  ] Sat Feb 24 2018 16:15:42 GMT+0800 (CST) Remixd is listening on 127.0.0.1:65520
[watch   ] WS server listening on  51844

然后打开浏览器,在地址栏输入:http://127.0.0.1:8080,可以看到以下效果:

图中代码是我已经准备好的代码

使用 Browser-solidity 编译代码

下面是一个简单的智能合约代码,输入任何数值,都加上100。

pragma solidity 0.4.20;
contract testContract {
     function add(uint a) public returns (uint b) {  
        uint resutl = a + 100;
        return (resutl);
    }  
}

智能合约Solidity源代码分析

接下来试着做一些简单的分析,并介绍一些最基本的Solidity知识。

第一行

pragma solidity 0.4.20;

第二行

contract testContract {
       ...
}

这里引用一段说明Solidity里的Contract

Contracts in Solidity are similar to classes in object-oriented languages. They contain persistent data in state variables and functions that can modify these variables. Calling a function on a different contract (instance) will perform an EVM function call and thus switch the context such that state variables are inaccessible. (引用自 here)

中文翻译:

第三行

function f(uint a) returns (uint b) 
        {
            ...
        }

Function的核心代码

function add(uint a) public returns (uint b) {  
        uint resutl = a + 100;
        return (resutl);
    }  

这是一段很平常的js代码,值得注意的是以下两点:

  1. Solidity是一个类型语言,因此每个变量都需要定义他的类型,uint/int/string/var。

Solidity is a statically typed language, which means that the type of each variable (state and local) needs to be specified (or at least known – see Type Deduction below) at compile-time. Solidity provides several elementary types which can be combined to form complex types. 引用自here

  1. 关于编码风格 uint result = a + 100;,solidity鼓励在操作符中有一个空格。

    More than one space around an assignment or other operator to align with 引用自here

Yes:
x = 1;
y = 2;
long_variable = 3;

更多关于Solidity的编码风格,请参考官方文档: https://solidity.readthedocs.io/en/develop/style-guide.html

Browser-solidity 细节详解

Setting标签

Setting

在Setting标签下可以查看当前的solidity的版本,并且要和代码框中的版本一致。

点击下拉框,可以选择不同的版本,包括还未成熟的最新构建版本,或者是之前的版本等。 个人强烈建议,尽量选择release版本,如下图所示的这些:

版本选择

Run标签

点击Create后的效果
transaction cost    101270 gas 
execution cost  36482 gas 

创建合约

刚刚通过点击Create已经创建了合约。

调试合约

add按钮旁的输入框输入数字,点击add进行调试,下方窗口会出现新的信息,点击Details`查看调试详情,可以看到实际调用所消耗的Gas。

点击add后的效果
transaction cost    21716 gas 
execution cost  252 gas 

Compile标签 & 编译合约

切换到Compile标签,点击Publish on Swarm 提示成功 点击Details 编译后的内容

稍微解释一下编译后的内容:

var testcontractContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"add","outputs":[{"name":"b","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]);
var testcontract = testcontractContract.new(
   {
     from: web3.eth.accounts[0], 
     data: '0x6060604052341561000f57600080fd5b60b68061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631003e2d2146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b600080606483019050809150509190505600a165627a7a723058208f5727572e0f6113593417a5211692c99ed69158e62764f4e3f76c0c5846afc30029', 
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

WEB3DEPLOY

将 Browser-solidity编译后的合约部署到Geth

发送部署合约的交易

> var testcontract = testcontractContract.new(
...    {
......      from: web3.eth.accounts[0], 
......      data: '0x6060604052341561000f57600080fd5b60b68061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631003e2d2146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b600080606483019050809150509190505600a165627a7a723058208f5727572e0f6113593417a5211692c99ed69158e62764f4e3f76c0c5846afc30029', 
......      gas: '4700000'
......    }, function (e, contract){
......     console.log(e, contract);
......     if (typeof contract.address !== 'undefined') {
.........          console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
.........     }
......  })
INFO [02-25|18:18:54] Submitted contract creation              fullhash=0x2f659199d3aceee8d61d90b42260e0aceeebf8ce30f6555896c67b1696a6b376 contract=0x810B81978509E6E8110C7A2eF7d2837d8054dcC6
null [object Object]
undefined

这里如果出现Error: exceeds block gas limit undefined的报错信息,请查看这篇文章

输入testcontract可以看到合约的一些信息

> testcontract
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "add",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: undefined,
  transactionHash: "0x2f659199d3aceee8d61d90b42260e0aceeebf8ce30f6555896c67b1696a6b376"
}

查看本地交易池中待确认的交易

输入txpool.status

> txpool.status
{
  pending: 1,
  queued: 0
}

可以看到交易池中有一个待确认的交易

查看待确认交易的详情

使用命令web3.eth.getTransaction,参数为transactionHash:

>web3.eth.getTransaction("0x2f659199d3aceee8d61d90b42260e0aceeebf8ce30f6555896c67b1696a6b376")
{
  blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  blockNumber: null,
  from: "0xb6cd75af6594f46374378cf3a7d9cbfc06485994",
  gas: 4700000,
  gasPrice: 18000000000,
  hash: "0x2f659199d3aceee8d61d90b42260e0aceeebf8ce30f6555896c67b1696a6b376",
  input: "0x6060604052341561000f57600080fd5b60b68061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631003e2d2146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b600080606483019050809150509190505600a165627a7a723058208f5727572e0f6113593417a5211692c99ed69158e62764f4e3f76c0c5846afc30029",
  nonce: 2,
  r: "0x98087a648c5a1307206820863ee889b8ff874a72033a323bac3b246294d70d7b",
  s: "0xe73e891d87b8a11b21268cf6e6fea70ea2b6dc4dd37e6e71f3d4c1a5f08ed26",
  to: null,
  transactionIndex: 0,
  v: "0x37",
  value: 0
}

由于交易还未确认,所以所属区块为null,blockNumber: null

调用合约

通过testcontract.add.call调用:

> testcontract.add.call(10)
TypeError: Cannot access member 'call' of undefined
    at <anonymous>:1:1

出现TypeError: Cannot access member 'call' of undefined的错误,是因为我们没有挖矿,之前提到过,如果停止挖矿,是不能进行转帐和智能合约的部署。

重新启动挖矿,等待一段时间,停止挖矿,调用合约,就可以输出正确的值了。

> miner.start()
.... ....(mining)
> miner.stop()
> testcontract.add.call(10)
110
> testcontract.add.call(100)
200

这时再查询交易详情,可以看到已经写到编号为21的区块上了blockNumber: 21

> web3.eth.getTransaction("0x2f659199d3aceee8d61d90b42260e0aceeebf8ce30f6555896c67b1696a6b376")
{
  blockHash: "0xe88ca3e86d7bca40effd2b90e821818cf90c35b4801f8cc949b4a7a14fdcadde",
  blockNumber: 21,
  from: "0xb6cd75af6594f46374378cf3a7d9cbfc06485994",
  gas: 4700000,
  gasPrice: 18000000000,
  hash: "0x2f659199d3aceee8d61d90b42260e0aceeebf8ce30f6555896c67b1696a6b376",
  input: "0x6060604052341561000f57600080fd5b60b68061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631003e2d2146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b600080606483019050809150509190505600a165627a7a723058208f5727572e0f6113593417a5211692c99ed69158e62764f4e3f76c0c5846afc30029",
  nonce: 2,
  r: "0x98087a648c5a1307206820863ee889b8ff874a72033a323bac3b246294d70d7b",
  s: "0xe73e891d87b8a11b21268cf6e6fea70ea2b6dc4dd37e6e71f3d4c1a5f08ed26",
  to: null,
  transactionIndex: 2,
  v: "0x37",
  value: 0
}

此时交易池中也没有等待确认的交易了。

> txpool.status
{
  pending: 0,
  queued: 0
}

参考:

  1. 使用 Browser-solidity 在 Go-Ethereum1.7.2 上进行简单的智能合约部署
    作者:迦壹
  2. 区块链学堂(10):Browser-solidity
    作者:以太中文网
  3. 区块链学堂(11):Browser-solidity 2–右侧的奥秘
    作者:以太中文网
上一篇下一篇

猜你喜欢

热点阅读