欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Windows下以太坊Geth客户端安装使用以及简单合约的部署

程序员文章站 2022-06-15 14:18:13
...

操作系统:Windows 10
参考资料:如何搭建以太坊私有链智能合约开发环境搭建及Hello World合约

以太坊安装

以太坊客户端与Java虚拟机和.NET运行环境类似,能够让你在电脑上运行"以太坊程序"。

以太坊的客户端有很多版本,在这里选择Geth(Go-ethereum)。只需要直接到官网下载Windows对应.exe可执行文件,并安装即可。

安装完成后,打开cmd命令提示符,输入命令geth --help显示以下信息,表明安装成功。
Windows下以太坊Geth客户端安装使用以及简单合约的部署
PS:如果不加任何参数,只使用geth命令执行,或双击安装目录下的geth.exe,会自动连接到以太坊公网,并开始同步区块(你会发现一直卡着不动),此时区块数据存储的路径可以在geth --help中查看到。

私有链创世区块搭建

以太坊支持自定义创世区块,要运行私有链,我们就需要定义自己的创世区块,创世区块信息写在一个 json 格式的配置文件中。

在磁盘的某个地方创建一个新文件夹,在该文件夹中新建创世区块配置文件genesis.json,内容如下:

{
  "config": {
        "chainId": 15,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
    "coinbase" : "0x0000000000000000000000000000000000000000",
    "difficulty" : "0x07000",
    "extraData" : "",
    "gasLimit" : "0xffffffff",
    "nonce" : "0x0000000000000042",
    "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp" : "0x00",
    "alloc": { }
}

字段的具体含义在这里就不展开叙述了。之后在cmd窗口进入该文件夹,执行如下命令:

geth --datadir data init genesis.json

上面命令的主体是 geth init,表示初始化区块链,命令可以带有选项和参数,其中 --datadir 选项后面跟一个目录名,这里为 data,表示指定数据存放目录为 datagenesis.jsoninit 命令的参数。执行后结果如下,可以看到,私有链搭建成功。
Windows下以太坊Geth客户端安装使用以及简单合约的部署
PS:在data目录下,会有两个文件:gethkeystore,前者保存区块数据,后者存放账户信息。

私有链节点的加入

在完成上述步骤后,就已经有了一条自己的私有链了,可以加入自己的私有链节点,使用以下命令启动节点:

geth --datadir data --networkid 2629 console

命令的主体是 geth console,表示启动节点并进入交互式控制台,--datadir 选项指定使用 data 作为数据目录,--networkid 选项后面跟一个数字,这里是 2629,表示指定这个私有链的网络 id 为 2629。网络 id 在连接到其他节点的时候会用到,以太坊公网的网络 id 是 1,为了不与公有链网络冲突,运行私有链节点的时候要指定自己的网络 id 。执行后,结果如下:
Windows下以太坊Geth客户端安装使用以及简单合约的部署
如图,会进入到一个交互式的 Javascript 执行环境,里面可以执行 Javascript 的代码,如输入1+1会输出2。 在这个环境中,可以进行很多操作,例如:查看区块和交易、创建账户、挖矿、发送交易、部署智能合约等。

然后执行如下一系列的操作,进行创建用户,挖矿,就不展开叙述了:

personal.newAccount("123") //创建用户,引号中的是账户密码

eth.accounts //可查看账户信息

miner.start(2) 	//启动挖矿,参数表示使用的线程数。启动后就会被挖矿信息刷屏
				//挖矿所得以太币默认存入第一个账户
miner.start();admin.sleepBlocks(1);miner.stop()//使用这个命令会在挖到一次矿后自动停止

miner.stop() //停止挖矿

eth.getBalance(eth.accounts[0]) //可以查看账户余额,单位是wei
web3.fromWei(eth.getBalance(eth.accounts[0]),'ether') //将余额单位换算成以太币

交易

PS:下文的操作我换用了Windows PowerShell

按照相同方式再创建一个账户,此时先前的账户有余额,而新创建的账户余额为0,可以通过以下命令将10个以太币从账户0转移到账户1:

amount = web3.toWei(10,'ether')
eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount})

此时会报错如下:
Windows下以太坊Geth客户端安装使用以及简单合约的部署
原因是账户每隔一段时间就会被锁住,要发送交易,必须先解锁账户,由于我们要从账户 0 发送交易,所以要解锁账户 0,执行图中所示命令(需要输入密码):
Windows下以太坊Geth客户端安装使用以及简单合约的部署
解锁后,重新执行之前的命令。

交易后,查看账户1余额,会发现还是0,这是因为交易已经提交到区块链,但还未被处理。正如之前所学到的,需要矿工进行挖矿,处理并记录这个交易。所以我们进行挖矿后,得到如下结果:
Windows下以太坊Geth客户端安装使用以及简单合约的部署
可以看到,账户1的余额已经变成10了,说明交易已被处理。

查看区块

使用命令eth.blockNumber查看当前的区块总数,eth.getBlock(10)查看具体的区块,执行结果如下:
Windows下以太坊Geth客户端安装使用以及简单合约的部署
区块的各字段含义如下:

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

查看交易

使用命令eth.getTransaction(" ")查看交易,其中引号需加上交易的hash值,在交易执行后会有显示。执行结果如下,该交易是上文所述交易:
Windows下以太坊Geth客户端安装使用以及简单合约的部署
交易的各字段含义如下:

  • blockHash:这个交易所在的区块的哈希值
  • blockNumber:这个交易所在的区块的编号
  • from:发起交易的账户
  • gas:执行这个交易所需要的gas
  • gasPrice:当前gas与以太币换算的汇率
  • hash:这个交易的哈希值
  • input:合约的16进制代码
  • nonce:交易下的nonce值,是账户发起交易所维护的nonce,一个交易对应一个nonce值
  • r,s,v:交易签名后的值,它们可以被用来生成签名者的公钥;r,s是ECDSA椭圆加密算法的输出值,v是用于恢复结果的ID
  • to:交易接收账户。如果是一个创建智能合约的交易,to为空
  • transactionIndex:这个交易在其对应区块的序号
  • value:交易的以太币数量。如图所示,正是10个以太币

查看日志

进行到这里才发现有日志功能…

日志功能开启方法:在上文启动以太坊节点时在后面加上2>> test.log,日志的名称可以自己随意设置。

简单来说,日志的作用就是将我之前在执行命令时会输出的各种提示信息,例如INFOWARN,不直接输出到屏幕上,而是重定向写入到我们指定的日志文件中。日志文件部分内容如下:

Windows下以太坊Geth客户端安装使用以及简单合约的部署

上图显示的内容就是启动节点后,geth初始化的一些信息。

对于选择将这些提示信息输入到日志中,我认为有好处也有坏处:好处就是没有这些提示信息后,geth命令行界面和之前相比显得更加简介了,同时有了日志的记录,方便日后的查看;坏处就是似乎少了一些什么的感觉,比如挖矿时刷屏的快感。

编写简单的智能合约

使用Remix - Ethereum IDE直接在浏览器中编写和编译Solidity代码

参考网上博客(见本文开头部分的参考资料),创建helloworld.sol,并编写代码如下:

pragma solidity ^0.4.22;
contract hello {
    
    string greeting;
    
    function hello(string _greeting) public {
        greeting = _greeting;
    }
    
    function say() constant public returns (string) {
        return greeting;
    }
    
}

上述代码创建了一个hello合约。点击页面中的Compile进行编译。对于博客提供的代码似乎给了警告,意思好像是要求写构造函数,不过既然不是报错,暂时先不管。

编译通过后,点击下方的 Compilation Details,找到 WEB3DEPLOY 选项旁的复制按钮进行复制,得到如下结果:

var _greeting = /* var of type string here */ ;
var helloContract = web3.eth.contract([{"constant":true,"inputs":[],"name":"say","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_greeting","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
var hello = helloContract.new(
   _greeting,
   {
     from: web3.eth.accounts[0], 
     data: '0x608060405234801561001057600080fd5b506040516102a83803806102a8833981018060405281019080805182019291905050508060009080519060200190610049929190610050565b50506100f5565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061009157805160ff19168380011785556100bf565b828001600101855582156100bf579182015b828111156100be5782518255916020019190600101906100a3565b5b5090506100cc91906100d0565b5090565b6100f291905b808211156100ee5760008160009055506001016100d6565b5090565b90565b6101a4806101046000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063954ab4b214610046575b600080fd5b34801561005257600080fd5b5061005b6100d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561009b578082015181840152602081019050610080565b50505050905090810190601f1680156100c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606060008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561016e5780601f106101435761010080835404028352916020019161016e565b820191906000526020600020905b81548152906001019060200180831161015157829003601f168201915b50505050509050905600a165627a7a72305820bd9c8f1aad9fb4da7211d57eeaea5ede4555a3d028220142c0fa5bfe05d3874d0029', 
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

继续按照博客要求,将第一行的注释部分改为“Hello World”(可以先复制到文本中进行修改)。修改完成后,拷贝到geth控制台中。注意先要解锁合约中from字段对应的账户!

**然后需要进行挖矿!**我起初没有进行挖矿,所以一直以为哪里出错了。查看Log日志可以看到,当我们将上述内容拷贝到控制台后,日志中提示以下信息:

INFO [10-09|21:44:27.864] Submitted contract creation

在开始挖矿一段时间后,可以看到如下所示的提示信息,表示合约已经部署成功了。

Windows下以太坊Geth客户端安装使用以及简单合约的部署
此时查看对应账户余额,可以看到,余额变少了。

运行hello合约,得到如下结果:
Windows下以太坊Geth客户端安装使用以及简单合约的部署
结果符合预期,即输出了Hello World,合约成功运行!