以太坊私有链搭建,建立节点集群,部署智能合约,攻击智能合约

本文目的:
1.搭建Ethereum私有链和节点集群;
2.熟悉以太坊智能合约的部署和使用流程;
3.了解以太坊智能合约的应用和常见安全性问题;

参考:
https://www.jianshu.com/p/3aa80732ed73
https://blog.csdn.net/Jade0214/article/details/80043776
https://www.8btc.com/article/100840

Ethereum官网以及Ethereum Wallet下载:
https://www.ethereum.org/

Solidity在线撰写和编译:
http://remix.ethereum.org/

Ethernaut智能合约安全演练:
https://ethernaut.zeppelin.solutions/

一、以太坊私有链搭建

参考:https://blog.csdn.net/sportshark/article/details/51855007
以太坊(英文Ethereum)是一个开源的有智能合约功能的公共区块链平台,通过其专用加密货币以太币(Ether)提供去中心化的虚拟机(“以太虚拟机” Ethereum Virtual Machine)来处理点对点合约。
区块链1.0时代通常是指在2009年到2014年之间,以比特币为代表的区块链应用发展阶段,它们主要致力于解决货币和支付手段的去中心化问题;2014年之后,开发者们越来越注重于解决比特币在技术和扩展性方面的不足。2013年底,Vitalik Buterin(V神)发布了以太坊白皮书《以太坊:下一代智能合约和去中心化应用平台》,将智能合约引入区块链,打开了区块链在货币领域以外的应用,从而开启了区块链2.0时代。
截至2018年11月,以太坊是市值NO.2的加密货币,仅次于比特币。

1.前言

我们先看看从比特币到以太坊,智能合约是如何演变的。注意下方智能合约的位置,这个位置表明上方的应用(APP)必须通过智能合约来实现对应区块链网络的功能。
在这里插入图片描述
那么,我们看一个简单的例子,就是A转账给B,在比特币和以太坊中大概都怎么实现的:
在这里插入图片描述
在这里插入图片描述
以太坊智能合约实现的方式貌似能看懂,比较易读。
事实也是这样的,智能合约使得区块链的扩展性更强,且实现上更简洁,从而让以太坊发展成为目前最大的一个区块链开发平台。

2.安装geth

Go-ethereum客户端通常被称为Geth,它是个命令行界面,执行在Go上实现的完整以太坊节点。Geth得益于Go语言的多平台特性,支持在多个平台上使用(比如Windows、Linux、Mac)。Geth是以太坊协议的具体落地实现,通过Geth,你可以实现以太坊的各种功能,如账户的新建编辑删除,开启挖矿,ether币的转移,智能合约的部署和执行等等。所以,我们选择 geth工具来进行开发。
geth安装方式(linux):
在这里插入图片描述
或者(windows):
在这里插入图片描述
或者(mac):
在这里插入图片描述
检查是否安装成功:$ geth --help
如果输出一些帮助命令,则安装成功。

3.初始化区块链

定义创世区块

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

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

启动Geth即可以启动以太坊的区块链,为了构建私有链 ,需要在Geth启动时加入一些参数,Geth参数含义如下:

identity–区块链的标示,随便填写,用于标示目前网络的名字

init–指定创世块文件的位置,并创建初始块

datadir–设置当前区块链网络数据存放的位置

port–网络监听端口

rpc–启动rpc通信,可以进行智能合约的部署和调试

rpcapi–设置允许连接的rpc的客户端,一般为db,eth,net,web3

networkid–设置当前区块链的网络ID,用于区分不同的网络,是一个数字

console–启动命令行模式,可以在Geth中执行命令

4.启动私有链节点

接下来在windows启动区块链节点:
进入Windows下Geth的目录 ,放置配置好的genesis.json文件,执行如下命令:
geth --datadir “%cd%\chain” init genesis.json
在这里插入图片描述
geth --identity “PICCetherum” -rpc --rpccorsdomain “*” --datadir “%cd%\chain” --port “30303” --rpcapi “db,eth,net,web3” --networkid 95518 console
在这里插入图片描述
如图说明启动成功。
这是一个交互式的Javascript执行环境,在这里面可以执行Javascript代码,其中>是命令提示符。在这个环境里也内置了一些用来操作以太坊的Javascript对象,可以直接使用这些对象。这些对象主要包括:
eth:包含一些跟操作区块链相关的方法
net:包含以下查看p2p网络状态的方法
admin:包含一些与管理节点相关的方法
miner:包含启动&停止挖矿的一些方法
personal:主要包含一些管理账户的方法
txpool:包含一些查看交易内存池的方法
web3:包含了以上对象,还包含一些单位换算的方法

初始化成功之后目录如下:
在这里插入图片描述
其中geth/chaindata中存放的是区块数据,keystore中存放的是账户数据。

5.以太坊Javascript Console

进入以太坊Javascript Console后,就可以使用里面的内置对象做一些操作,这些内置对象提供的功能很丰富,比如查看区块和交易、创建账户、挖矿、发送交易、部署智能合约等。接下来介绍几个常用功能,下面的操作中,前面带>的表示在Javascript Console中执行的命令。

使用节点创建账号

启动节点成功后,会进入Geth的命令行模式,输入如下命令
personal.newAccount()
系统会提示你输入密码,并确认,最后会显示一个新生成的账号。
Passphrase其实就是密码的意思,输入两次密码后,就创建了一个账户。
在这里插入图片描述
再次执行命令:
在这里插入图片描述
这时候用eth.accounts命令查看,就会发现有两个账户了:
在这里插入图片描述
账户默认会保存在数据目录的keystore文件夹中。查看目录结构,发现chain/keystore中多了两个文件,这两个文件就对应刚才创建的两个账户,这是json格式的文本文件,可以打开查看,里面存的是私钥经过密码加密后的信息:
在这里插入图片描述
每次记一长串的地址很麻烦,我们可以通过设置变量来表示账户:
在这里插入图片描述

查看账户余额

在这里插入图片描述

启动、停止挖矿

在这里插入图片描述
其中start的参数表示挖矿使用的线程数。第一次启动挖矿会先生成挖矿所需的DAG文件,这个过程有点慢,等进度达到100%后,就会开始挖矿,此时屏幕会被挖矿信息刷屏:
在这里插入图片描述

如果想停止挖矿,并且进度已经达到100%之后,可以在js console中输入
在这里插入图片描述

在这里插入图片描述
挖到一个区块会奖励5个以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做coinbase,默认情况下coinbase是本地账户中的第一个账户:
在这里插入图片描述
和上文的第一个账户对比一下,是一致的。
getBalance()返回值的单位是wei,wei是以太币的最小单位,1个以太币=10的18次方个wei。要查看有多少个以太币,可以用web3.fromWei()将返回值换算成以太币:
在这里插入图片描述

发送一笔交易

eth.sendTransaction({from:acc0,to:acc1,value:20})
在这里插入图片描述
这里报错了,原因是账户每隔一段时间就会被锁住,要发送交易,必须先解锁账户,由于我们要从账户0发送交易,所以要解锁账户0:
personal.unlockAccount(acc0)
输入创建账户时设置的密码,就可以成功解锁账户。
在这里插入图片描述
解锁后后再发送交易。
我们去查看账户1中的余额,发现还没转过去,此时交易已经提交到区块链,但还未被处理,这可以通过查看txpool来验证:
txpool.status
在这里插入图片描述
其中有一条pending的交易,pending表示已提交但还未被处理的交易。
要使交易被处理,必须要挖矿。这里我们启动挖矿,然后等待挖到一个区块之后就停止挖矿:
miner.start(1);admin.sleepBlocks(1);miner.stop();
在这里插入图片描述
当miner.stop()返回true后,txpool中pending的交易数量应该为0了,说明交易已经被处理了,而账户1应该收到币了:
web3.fromWei(eth.getBalance(acc1),‘ether’)
在这里插入图片描述

查看交易

eth对象封装了查看交易和区块信息的方法。
查看当前区块总数:
eth.blockNumber
在这里插入图片描述

5.图形界面Ethereum Wallet连接私有链

Ethereum Wallet是以太坊提供的官方应用,具备创建账户,转移以太币,部署调用智能合约等功能。这里我们可以用它连接到我们自己的私有链上,作为辅助工具更方便地进行私链操作。

二、建立节点集群

在私有网络中建立多个节点组成的集群,并互相发现,产生交易。
如果是为了在本地网络运行多个以太坊节点的实例,必须确保以下几点:

  1. 每个实例都有独立的数据目录(–datadir)
  2. 每个实例运行都有独立的端口.(eth和rpc两者都是)(–port 和 --rpcprot)
  3. 在集群的情况下, 实例之间都必须要知道彼此.
  4. 唯一的ipc通信端点,或者禁用ipc.

在这里,我们选择在不同的电脑上分别建立节点组成集群,互相发现,产生交易。
在第一台电脑上启动节点:
在这里插入图片描述
在第二台电脑上初始化(使用相同的json文件)并启动节点,注意网络ID要相同,确保节点都在一个私有网络中:
在这里插入图片描述
bootnodes后边的参数是第一台电脑上节点的enode url ,包括ip和端口号等信息,都可以在第一台电脑上通过如下命令来获取:
在这里插入图片描述
至此两个节点应该就链接成功了。
节点间发送以太币:
在这里插入图片描述
from中填当前节点的账号地址,to中填要发送给的节点的账号地址。
执行以上命令发送一个以太币。注意发送交易操作前要先解锁账号,然后执行挖矿才能让交易生效。

三、在以太坊私有链上部署第一个智能合约

智能合约是一段代码和数据的集合,可以部署以太坊网络上运行。如果做比喻的话智能合约更像是JAVA程序,JAVA程序通过JAVA虚拟机(JVM)将代码解释字节进行执行,以太坊的智能合约通过以太坊虚拟机(EVM)解释成字节码进行执行,如果你学过汇编,会发现编译后的字节码和汇编很类似。同时智能合约有自己的账户,在时间或事件的驱动下能自动执行一些功能,如可以在相互之间传递信息,修改区块链的状态比如账户信息等。以太坊的智能合约最大的特点是图灵完备,通俗来说可以完全模拟一台计算机所能做的所有事情,大家熟知的比特币其实也可以执行一些简单脚本,但是他就不是图灵完备,比如循环指令比特币就无法执行。
本文的智能合约采用以太坊官方的示例合约,功能就是在区块链上存储一个数字,并能够读取出来。代码如下:

pragma solidity ^0.4.0;
contract SimpleStorage{
	uint storedData;

	function set(uint x){
	storedData=x;
	}

	function get() constant returns (uint retVal){
		return storedData;
	}

}

即使没有学过Solidity语言也可以大致看出,该合约set函数存储一个数字在X变量中,get函数从X变量中读取这个数字出来,下面对这个合约进行部署。

在部署合约前,需要准备两样东西:
1.编译后的代码。
2.应用程序二进制接口(ABI),它是一个定义如何与合约进行交互的JavaScript对象。
我们可以通过使用Solidity编译器来获得这两者。
在线编译器remix的地址:http://remix.ethereum.org/#optimize=false&version=soljson-v0.4.25+commit.59dbf8f1.js

获得编译后的代码

将源代码复制到Remix,点击编译。
在这里插入图片描述

要访问已编译的代码,直接点击菜单右边的details按钮。 在弹出窗口中,向下滚动并复制WEB3DEPLOY文本框中的所有代码:
在这里插入图片描述
可以将结果直接粘贴到geth窗口中,然后执行挖矿:
miner.start(1);admin.sleepBlocks(1);miner.stop();
等待一会终端中会看到这样的消息:
在这里插入图片描述
可能必须先使用你在开始时选择的密码来“解锁”发送交易的帐户,因为你需要支付部署合同的GAS费用。
可以使用以下命令来验证已部署的代码(将被编译):
eth.getCode(simplestorage.address)
在这里插入图片描述
如果它返回“0x”以外的任何内容,那么恭喜,代码已经被部署了。 如果再次创建合同(通过执行另一个eth.sendTransaction),它将发布到新地址。

执行合约

只需在终端上输入以下命令:
simplestorage.get()
在这里插入图片描述
如果出现以下问题:在这里插入图片描述
请输入:
在这里插入图片描述
出现账户锁定问题时解锁账户即可。

让其他节点与合约代码交互

为了让其他人来执行你的合同,他们需要两个东西:
1.合同所在地址
2. ABI(应用程序二进制接口),这是一种用户手册,描述合同功能的名称以及如何将它们调用到您的JavaScript控制台
想要获取地址,请运行以下命令:
simplestorage.address
在这里插入图片描述
为了得到ABI,你需要直接从Remix复制ABI,类似于复制WEB3DEPLOY编译代码的方式。 在右侧窗格中,单击详细信息按钮并向下滚动到ABI文本框。 点击复制按钮复制整个ABI,然后将其粘贴到临时文本中。
在这里插入图片描述
然后,你可以实例化一个可用于在连接到网络的任何计算机上调用合同的JavaScript对象。 在以下行中,替换ABI(一个数组)和Address(一个字符串)以在JavaScript中创建合同对象:
var simplestorage = eth.contract(ABI).at(Address)
如下:
在这里插入图片描述
这样别的节点就也可以通过
在这里插入图片描述
来调用你的智能合约了。
当某个节点改变了合约中存储的值,任一节点启动挖矿确认交易之后,每个节点都可以再次通过调用函数看到改变后的新值。

四、攻击一份智能合约

据相关统计,以太坊、EOS等平台上每日智能合约创建数量呈现上升趋势,其管理的数字资产数量提升,面临的威胁也随之增长。然而由于一般开发人员的安全意识不够,可能在开发智能合约时无意留下了安全隐患,从而造成损失。并且智能合约难以通过传统的升级、打补丁等方式填补漏洞,每一个暴露在开放网络上的智能合约都有可能成为专业黑客团队的攻击目标。
用例选自Ethernaut levels/04:
https://ethernaut.zeppelin.solutions/level/0x6b7b4a5260b67c1ee9196a42dd1ed8633231ba0a
以下是一个非常简单的智能合约,可能已经被其他任何人部署,我们需要做的是改变这个合约的owner,使之成为自己的地址。
在这里插入图片描述
可以看到合约本身提供了changeOwner的方法,但是直接调用是行不通的,需要满足if语句中的条件,相关参考:
https://bitshuo.com/topic/59afc169fbcd445a40a3e2e6
理解了原理,我们就可以写一份攻击合约:
在这里插入图片描述
先看看此时合约的拥有者:
在这里插入图片描述
部署并成功调用攻击合约:
在这里插入图片描述
之后,可以发现owner成功改变为自身地址:
在这里插入图片描述
更多关卡请查看:
https://ethernaut.zeppelin.solutions/

实际上,在现有各大区块链平台上,利用各种漏洞部署恶意合约代码进行攻击的手段屡见不鲜。区块链具有的开放共识、去中心、去信任、匿名性、安全不可篡改、可追溯性等特点能够为如何有效地保障数据安全提供一条解决问题的思路,但也带来了很多新的安全问题,区块链技术的成熟和完善正经历着考验。

猜你喜欢

转载自blog.csdn.net/z714405489/article/details/83660443