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

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拦下)。当然也可以通过源码安装。(前往官方安装教程

检查是否安装成功:
success

私有链创始区块搭建

要创建私有网络,只需给出一个随机网络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 
      
      node0genesis
  • 启动私有链,并进入JS控制台

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

    node0console

私有链节点的加入

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

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

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

      node1genesis

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

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

      node1console

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

    admin.nodeInfo
    

    node1Info

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

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

    addPeer
    peerCount

区块字段解读

在控制台输入命令eth.getBlock("latest")获取最新一块区块的结构(也可指定区块号获取指定区块)
getBlock
其各字段解读如下:

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

日志输出分析

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

  • 获取某一区块的结构,展开其交易的哈希值
    transactions
    复制其中一个交易的哈希值(例如transaction[5]),作为下一个调用方法的输入
  • 获取交易收据
web3.eth.getTransactionReceipt("0xa9b49f7db4a11f0abda177053144c3cc1016ec89f35ad92dfcd44d8ed0f00e99")
  • 展开其中的日志数组,可以看到如下结果
    logs
字段含义
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全速运行,影响计算机的使用。
    运行一会后,主账号就会获取很多以太币,这个时候屏幕会快速刷屏
    minerStart

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

  • 查看账户余额
    balance

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

    • 先解锁账户0
      unlockAccount
    • 发送交易,账户 0 -> 账户 1
      sendTransaction
      此时由于没有挖矿,用txpool.status命令可以看到本地交易池中有一个待确认的交易,可以使用eth.getBlock("pending", true).transactions查看当前待确认交易
      pendingTransactions
    • 使用下面命令开始挖矿:
      miner.start(1);admin.sleepBlocks(1);miner.stop();
      
      mine
    • 新区块挖出后,挖矿结束,查看账户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上编译调试智能合约代码
      注意,选择的编译器版本要与代码中声明的编译器版本一致
      compile
      编译成功

    • 将智能合约部署到私有链上
      因为我们要将该智能合约部署到私有链上,需要得到智能合约编译后的EVM二进制码Bytecode和JSON ABI(Application Binary Interface)。将生成的交易保存到scenario.json文件。在Remix上部署该交易,记录其input
      input
      回到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来部署合约,首先解锁账户
      unlockAccount

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

      myContract = eth.contract(abi)
      

      myContract
      输入:

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

      contract
      此时如果没有挖矿,用txpool.status命令可以看到本地交易池中有一个待确认的交易。使用miner.start(1);admin.sleepBlocks(1);miner.stop();命令开始挖矿,一段时间后交易会被确认。
      txpool

  • 调用智能合约

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

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

      call
      这时同样可以通过txpool.status查看到本地交易池中有一个待确认的交易,也可以使用eth.getBlock("pending", true).transactions查看当前待确认交易
      pendingContract

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

      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] 前辈的博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值