区块链学习实战01 - 以太坊初试

区块链学习实战01 - 以太坊初试

  • Windows以太坊安装(geth安装)
  • 私有链创始区块搭建
  • 私有链节点的加入
  • 区块字段解读
  • 日志输出分析
  • 简单智能合约编写及部署运行
  • 交易字段分析
  • 参考资料

Windows以太坊安装(geth安装)

Geth,即go-ethereum是以太坊的客户端之一,是一个基于Go语言的客户端。以太坊还有别的客户端包括C++,JavaScript,python,Java等,比较常用的就是Go语言实现的客户端geth (go-ethereum),其他常用的还有一个叫testrpc的工具, 它使用了Python客户端pyethereum。

geth是一种CLI应用,它用Go语言编写,在主要的操作系统中都可使用。
对于Windows来说,geth是一个可执行文件。从官网下载windows版本的安装程序,运行即可(P.S. 由于安装程序修改系统环境变量,所以可能会被360拦下)。当然也可以通过源码安装。(前往官方安装教程)

检查是否安装成功:
区块链学习实战01 - 以太坊初试_第1张图片

私有链创始区块搭建

要创建私有网络,只需给出一个随机网络ID即可。可以简单使用--deth标记运行一个私有网络,该网络允许多个与日志和调试相关的标记,而不用给出一个随机网络ID并放上多个与日志和调试相关的标记。

  • 准备创世块文件
    配置自己的创世块是为了区分公有链,同一个网络中,创世块必须是一样的,否则无法联通

    • 新建文本文档,输入如下内容并保存:
      {
      		"config": {
      		"chainId": 8,
      		"homesteadBlock": 0,
      		"eip155Block": 0,
      		"eip158Block": 0
      		},
      		"coinbase" : "0x0000000000000000000000000000000000000000",
      		"difficulty" : "0x40000",
      		"extraData" : "",
      		"gasLimit" : "0xffffffff",
      		"nonce" : "0x0000000000000042",
      		"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
      		"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
      		"timestamp" : "0x00",
      		"alloc": { }
      }
      
    • 将上述文本文档重命名为genesis.json(个人实践时,如果直接用Notepad创建文件genesis.json会发生编码错误),将文件移动到私有链的相应目录(例如:cd D:\geth\privatechain
  • 创建数据存放地址并初始化创世块

    • 运行CMD
    • 进入该目录,例如:cd D:\geth\privatechain
    • 执行如下命令(创建数据存放地址并初始化创世块):
      geth --datadir ./data/node0 init ./genesis.json 
      
      区块链学习实战01 - 以太坊初试_第2张图片
  • 启动私有链,并进入JS控制台

    geth --datadir ./data/node0 --networkid 314590 --ipcdisable --port 61910 --rpcport 8200 console
    

    区块链学习实战01 - 以太坊初试_第3张图片

私有链节点的加入

  • 创建另一个节点,打开一个新的CMD窗口

    • 初始化创始区块(P.S. 同样先进入D:\geth\privatechain目录)

      geth --datadir ./data/node1 init ./genesis.json
      

      区块链学习实战01 - 以太坊初试_第4张图片

    • 启动新节点(注意使用不同的端口号rpcportport而使用同样的子网号networkid,使用不同的identity

      geth --datadir ./data/node1 --networkid 314590 --ipcdisable --port 61911 --rpcport 8101 console
      

      区块链学习实战01 - 以太坊初试_第5张图片

  • 查看新创建的节点的信息,在JS控制台输入如下命令

    admin.nodeInfo
    

    区块链学习实战01 - 以太坊初试_第6张图片

  • 加入新创建的节点
    在node0的控制台中,输入如下命令,其中addPeer()中的内容为node1的enode的内容

    admin.addPeer('enode://28fa4507a3c0612c706f47777007a9f763cdac2cd9569b9bf68eaddaacdcd5b85ead7e45c516c534787ee5c7697333eec21c4b5d1e17a45a1c1cdca8f0b67506@127.0.0.1:61911')
    

    addPeer
    区块链学习实战01 - 以太坊初试_第7张图片

区块字段解读

在控制台输入命令eth.getBlock("latest")获取最新一块区块的结构(也可指定区块号获取指定区块)
区块链学习实战01 - 以太坊初试_第8张图片
其各字段解读如下:

字段 含义
difficulty 挖矿难度
extraData 与此区块相关的附加数据
gasLimit 当前区块允许使用的最大gas
gasUsed 当前区块累计使用的gas
hash 区块的哈希值。如果区块没有被确认,这个字段会是null值
logsBloom 区块日志的布隆过滤器,区块没被确认是值为null
miner 取得该区块记账权的矿工
mixHash 一个Hash值,当与nonce组合时,证明此区块已经执行了足够的计算
nonce PoW生成的哈希值
number 区块号
parentHash 前一个区块的哈希值
receiptsRoot 收据树的根哈希值
sha3Uncles 数据块的哈希值
size 当前区块的字节大小
stateRoot 区块状态树的根哈希
timestamp 区块打包时的unix时间戳
totalDifficulty 区块链到当前区块的总难度
transactions 交易的对象
transactionsRoot 区块的交易树的根哈希
uncles 叔哈希的数组

日志输出分析

在以太坊的语境里,日志代表对事件的存储。通过命令eth.getTransactionReceipt()可以获取日志。以下例子为在TA提供的网页(可能需要中大校园网才能访问)上的控制台中进行测试。

  • 获取某一区块的结构,展开其交易的哈希值
    区块链学习实战01 - 以太坊初试_第9张图片
    复制其中一个交易的哈希值(例如transaction[5]),作为下一个调用方法的输入
  • 获取交易收据
web3.eth.getTransactionReceipt("0xa9b49f7db4a11f0abda177053144c3cc1016ec89f35ad92dfcd44d8ed0f00e99")
  • 展开其中的日志数组,可以看到如下结果
    区块链学习实战01 - 以太坊初试_第10张图片
字段 含义
address 智能合约的地址
blockHash 所在区块的哈希值
blockNumber 所在区块号
data 触发事件的时候传给事件的实际参数值
logIndex 即本条日志在区块中记录的日志数组中的索引下标
topics数组 数组里的第一个数据元素就是事件的签名,其它数据元素就是被索引收录的事件参数值,所有在 topics 里的内容,都是被索引收录,可以通过 bloom filter 进行过滤的。
transactionHash 交易哈希值
transactionIndex 本交易在所属区块中所有打包交易数组中的索引下标

简单智能合约编写及部署运行

  • 编写一个简单的加法合约,代码如下:
pragma solidity ^0.4.0;
contract TestContract
{
    function sum(uint a, uint b) returns (uint)
    {
        return a + b;
    }
}
  • 启动私有链节点

  • 通过命令personal.newAccount("你的密码")创建两个账户
    node1Account1
    node1Account2

  • 挖矿获取一些以太币
    账号创建后,还没有以太币,需要在私有链上挖矿,输入命令

    miner.start(1)
    

    P.S. miner命令括号中的1表示用一个线程进行挖矿,如果不配置,就会让CPU全速运行,影响计算机的使用。
    运行一会后,主账号就会获取很多以太币,这个时候屏幕会快速刷屏
    区块链学习实战01 - 以太坊初试_第11张图片

  • 输入命令miner.stop()停止挖矿

  • 查看账户余额
    balance

  • 尝试进行一次交易,例如从账户0向账户1转账:

    • 先解锁账户0
      区块链学习实战01 - 以太坊初试_第12张图片
    • 发送交易,账户 0 -> 账户 1
      区块链学习实战01 - 以太坊初试_第13张图片
      此时由于没有挖矿,用txpool.status命令可以看到本地交易池中有一个待确认的交易,可以使用eth.getBlock("pending", true).transactions查看当前待确认交易
      区块链学习实战01 - 以太坊初试_第14张图片
    • 使用下面命令开始挖矿:
      miner.start(1);admin.sleepBlocks(1);miner.stop();
      
      区块链学习实战01 - 以太坊初试_第15张图片
    • 新区块挖出后,挖矿结束,查看账户1的余额,已经收到了账户0的以太币
      account1Balance
      P.S. 以太币的单位:
      K w e i ( B a b b a g e ) = 1 0 3 W e i Kwei(Babbage) = 10^3 Wei Kwei(Babbage)=103Wei
      M w e i ( L o v e l a c e ) = 1 0 6 W e i Mwei(Lovelace) = 10^6Wei Mwei(Lovelace)=106Wei
      G w e i ( S h a n n o n ) = 1 0 9 W e i Gwei(Shannon) = 10^9Wei Gwei(Shannon)=109Wei
      M i c r o e t h e r ( S z a b o ) = 1 0 12 W e i Microether(Szabo) = 10^{12}Wei Microether(Szabo)=1012Wei
      M i l l i e t h e r ( F i n n e y ) = 1 0 15 W e i Milliether(Finney) = 10^{15}Wei Milliether(Finney)=1015Wei
      E t h e r = 1 0 18 W e i Ether = 10^{18}Wei Ether=1018Wei
  • 编译和部署智能合约

    • 在Remix上编译调试智能合约代码
      注意,选择的编译器版本要与代码中声明的编译器版本一致
      区块链学习实战01 - 以太坊初试_第16张图片
      编译成功

    • 将智能合约部署到私有链上
      因为我们要将该智能合约部署到私有链上,需要得到智能合约编译后的EVM二进制码Bytecode和JSON ABI(Application Binary Interface)。将生成的交易保存到scenario.json文件。在Remix上部署该交易,记录其input
      区块链学习实战01 - 以太坊初试_第17张图片
      回到Geth的控制台,用变量code记录和abi对应记录上面两个值,例如:

      code = "0x606060405260818060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063cad0899b146039576035565b6002565b34600257605a60048080359060200190919080359060200190919050506070565b6040518082815260200191505060405180910390f35b60008183019050607b565b9291505056"
      abi = [{"constant": false,"inputs": [{"name": "a","type": "uint256"},{"name": "b","type": "uint256"}],"name": "sum","outputs": [{"name": "","type": "uint256"}],"payable": false,"type": "function","stateMutability": "nonpayable"}]
      
    • 使用账户0来部署合约,首先解锁账户
      区块链学习实战01 - 以太坊初试_第18张图片

    • 创建合约实例,发送部署合约的交易
      输入:

      myContract = eth.contract(abi)
      

      区块链学习实战01 - 以太坊初试_第19张图片
      输入:

      contract=myContract.new({from:eth.accounts[0],data:code,gas:1000000})
      

      区块链学习实战01 - 以太坊初试_第20张图片
      此时如果没有挖矿,用txpool.status命令可以看到本地交易池中有一个待确认的交易。使用miner.start(1);admin.sleepBlocks(1);miner.stop();命令开始挖矿,一段时间后交易会被确认。
      区块链学习实战01 - 以太坊初试_第21张图片

  • 调用智能合约

    • 使用以下命令通过发送交易来调用合约,sendTransaction方法的前几个参数应该与合约中的sum方法的输入参数对应。这种情况下,交易会通过挖矿记录到区块链中(注意首先依然要先解锁账户)

      personal.unlockAccount(eth.accounts[0])
      contract.sum.sendTransaction(2, 4, {from:eth.accounts[0]})
      

      区块链学习实战01 - 以太坊初试_第22张图片
      这时同样可以通过txpool.status查看到本地交易池中有一个待确认的交易,也可以使用eth.getBlock("pending", true).transactions查看当前待确认交易
      区块链学习实战01 - 以太坊初试_第23张图片

    • 在本地运行该方法可直接查看返回结果,不会记录到区块链中

      contract.sum.call(2,4)
      

      contractCall

交易字段分析

前面已经讲到可以通过发送交易的方式调用智能合约,这里以该交易为例分析交易字段的含义:

字段 含义
blockHash 这个交易所在的块的哈希值
blockNumber 这个交易所在的块的编号
from 发起这个交易的账户或者用户
gas 执行这个交易所需要的gas
gasPrice 当前gas与以太币换算的汇率(或者说gas的单价)
hash 当前这个交易的哈希值
input 合约的16进制代码
nonce 交易下的nonce值,是账户发起交易所维护的nonce,一个交易对应一个nonce值(P.S. 不同于PoW的nonce)
r,v,s 交易签名和用去决定交易的发送者的对应值
to 交易接收者的地址(P.S. 创建合约时这一字段值为null)
transactionIndex 这个交易在其对应区块的序号
value 交易要给交易接收者发送的以太币数量

参考资料

[1] 邹均,于斌,庄鹏,邢春晓.区块链核心技术与应用[M].北京:机械工业出版社,2018
[2] Narayan Prusty.区块链项目开发指南[M].北京:机械工业出版社,2018
[3] 前辈的博客
[4] 前辈的博客
[5] 前辈的博客
[6] 前辈的博客

你可能感兴趣的:(区块链)