一、以太坊
1、以太坊历史
以太坊(Ethereum)的目标是一个运行智能合约的去中心化平台,一台“世界计算机”。该
平台支持图灵完备的分布式应用,按照智能合约所约定的逻辑自动执行,理想情况下将不存在
攻击、欺诈等问题。
以太坊由创始人 Vitalik Buterin 提出。目前支持 Go、C++、Python 等多种语言实现的客户
端,智能合约使用 Solidity 语言实现。
- 2013 年底,Vitalik Buterin 提出在比特币一样的去中心化网络上运行任意图灵完备的应用程
- 序(以太坊白皮书)
- 2014 年 7 月,以太币预售,共筹集超过 1800 万美元的比特币
- •2016 年 6 月,DAO 众筹受到漏洞攻击,造成价值超过 5000 万美元的以太币被冻结,通过硬分叉解决
2、扩展:硬分叉
概念:区块链发生永久性分歧,在新共识规则发布后,部分没有升级的节点无法验证已经升级 的节点生产的区块,通常硬分叉就会发生
3、以太坊特点
特点:
•(1)以太坊支持图灵完备的智能合约,以及支持智能合约的虚拟机 EVM
图灵完备:图灵完备是指在可计算性理论里,如果一系列操作数据的规则(如指令集、编程 语言、细胞自动机)可以用来模拟单带图灵机。虽然图灵机会受到储存能力的物理限制,图灵完全 性通常指“具有无限存储能力的通用物理机器或编程语言”。
虚拟机 EVM:EVM的存在是为了能让我们用Solidity编写的合约代码,运行在以太坊的环境 中。这样类比的话,以太坊就相当于计算机环境,EVM把合约代码编译成以太坊能识别的机器码运 行。那现在可能还不止以太坊,市面上涌现了很多新的公链也兼容EVM
• (2)选用了内存需求较高的 HASH 函数,避免出现强算力矿机和矿池攻击
比特币挖矿,其实就是在找一个随机数n,使得n拼接上交易信息的Hash值前m位为 零。前m位为零,代表的是挖矿的计算复杂度,假设要寻找前60比特为0的Hash值,那 么他的计算复杂度就是260次运算。
• (3)叔块(uncle block)激励机制,并减少区块产生间隔时间(15 秒左右)
区块链由于是一种去中心化的技 术,全世界所有的矿工同时工作,各 自独立的挖掘满足要求的区块。由于 是各自独立的工作,就有可能出现两 个独立的矿工先后发现了两个不同的 满足要求的区块,就像下面这种情况, 被称为临时分叉。
两位矿工都发现了高度2的区块,那么该采用谁的呢?区块链只承认最长的链,黄色和绿色的区块谁 先有后继区块,变成最长的链,谁就会被承认,失败的就会被抛弃。为了成为最长的链,两个矿工都拼命 的把自己挖到的区块通过广播的方式告诉更多的节点,并希望他们能把自己的区块传播得更广,从而使更 多的矿工在自己挖出的区块下挖掘下一个区块,最终让自己的区块变成最长链的一部分。 然而,胜利者只有一个,失败者将被抛弃,其中的交易会重新被打包到之后的区块中。下面这张图就 是绿色区块获得了胜利,黄色区块成为孤块,被抛弃。
区块如果被废弃了,其中包含的挖矿奖励怎么办呢?对比特币来说,赢者通吃,失败者一无所有, 竹篮打水一场空。但是在以太坊中创造了一个新的名词叔块。对高度3的区块来说,绿色区块是他的父 区块。黄色区块虽然失败了,但好歹也是高度1的区块的子区块,绿区块的兄弟区块。于是,高度3的区 块就尊称这个黄区块为叔叔,叔块就是这么得名的。
如果孤块有幸被后来的区块通过uncles字段收留进区块链就变成了叔块。如果一个孤儿区块没有被 任何区块收留,这个孤儿区块还是会被丢弃,不会进入区块链,也就是说孤儿区块被收留后才会变成叔 块。
叔块也是可以获得奖励的,矿工们再也不用担心白忙乎了。而且以后的区块谁要是把叔块收留了, 收留了叔块的区块还有额外的奖励,收留叔块也被称为包含叔块。
以太坊为什么要这么设计呢?因为以 太坊的区块时间是15秒左右,相对于比特 币,更容易出现临时分叉和孤儿区块。而 且较短的区块时间,也使得区块在整个网 络中更难以充分传播,尤其是对那些网速 慢的矿工,这是一种极大的不公平。为了 平衡各方利益,才设计了这样一个叔块机 制
• (4)通过 Gas 限制代码执行指令数,避免循环执行攻击
程序运行指令数通过Gas来限制,所消耗的费用超过设定上限时就会被取消,避免出现恶意合约。难 以通过构造恶意的循环或不稳定合约代码来对网络造成破坏。
• (5)支持 POW 共识算法,并支持效率更高的 POS 算法
为了防止ASIC矿机矿池的算力攻击,跟原始POW 的计算密集型Hash 运算不同,Ethash 在执行时 候需要消耗大量内存,反而跟计算效率关系不大。因此,很难制造出专门针对Ethash的芯片,反而通用 机器可能更加有效。 虽然,Ethash相对原始的POW进行了改进,但仍然需要进行大量无效的运算,以太坊网络社区已经 有计划在未来采用更高效的Proof-of-Stake(POS)作为共识机制。
4、以太坊帐户与交易
(1)以太坊中的账户主要分为两种类型:
第一种为合约账户,用于存储智能合约代码。 当合约账户被调用时,存储其中的智能合约会在节点的虚拟机中执行,并消耗一定的燃料。
第二种是外部账户,它是以太币拥有者账户,对应到拥有者公钥 可以创建交易发给其他合约账户或外部账户。
(2)以太坊中的交易:指从一个账户发送到其他账户的消息数据
• Recipient 是指目标 账户地址;
• Amount 指可以指定转移的以太币数量;
• AccountNonce 指记录已发送过的交易 序号,用于防止交易被重放;
• Price 指执行交易需要消耗的 Gas 价格;
• GasLimit 指交易执 行允许消耗的最大 Gas 值;
• Signature 指签名相关数据
根据用途可分为:转账、 创建合约和调用合约三种类型
(3)以太坊可以认为是一个分布式的状态机,通过交易实现状态转移,以太坊所有的节点维护 相同的状态
5、以太坊客户端
(1)以太坊客户端
Geth :Go-Ethereum ,是目前最受欢迎的以太坊客户端,用于管理以太坊账户,部署执行智 能合约,下载以太坊主链的交易数据
以太坊客户端
以太坊客户端是一个软件应用程序,它实现以太坊规范并通过 p2p 网络与其他以太坊 客 户端进行通信。
• 完成与其他客户建立 p2p 通信信道,签署和广播交易,挖掘,部署和与智能合约交互等 的软件。客户端通常被 称为节点。
• 如果不同的以太坊客户端符合参考规范和标准化通信协议,则可以进行 相互操作。
• 以太坊节点必须遵循的功能的正式定义在以太坊黄皮书中定义,黄皮书定义了网络上 节 点所需的函数,挖掘算法,私钥/公钥 ECDSA 参数。它定义了使节点与以太坊客户端完 全兼容的全部功能。
• 迄今为止最受欢迎的客户端是 Geth 和 Parity。实现的不同之处主要在于选择的编程语 言: Geth 使用 Golang,而 Parity 使用 Rus
(2)以太坊客户端go ethereum安装
(3)安装go-ethereum客户端 :
cd /opt
sudo add-apt-repository -y ppa:ethereum/ethereum #增加ethereum库
sudo apt-get update #更新本地软件数据库
sudo apt-get install ethereum #安装以太坊客户端
geth version #验证Geth的版本
(4)运行一个以太坊节点
geth console #连接主网,以终 端方式运行以太坊客户端按
“ctrl+D” 可以退出信息同步
geth -h #打印帮助信
二、私有链
1、什么是私有链
• 私有链:仅限于企业、国家机构或者单独个体使用,不完全能够解决信任问题,但是可 以改善可审计性。
• 常用于企业内部的数据库管理、审计等,政府的预算和执行,或者政府的行业统计数据 等。他们彼此之间需要透明,但没必要对外公众透明。
• 私有链的价值主要是提供安全、可追溯、不可篡改、自动执行的运算平台,可以同时防 范来自内部和外部对数据的安全攻击,这个在传统的系统是很难做到的。
2、以太坊私有链
以太坊私有链的搭建流程为:首先 在配置文件 genesis.json 中创建配置 创世块,然后以命令行或 docker 方式 启动该链。
三、FISCO BCOS 单群组联盟链搭建
1、FISCO BCOS 单群组联盟链搭建
(1)、安装依赖
开发部署工具 build_chain.sh
脚本依赖于openssl, curl
,使用以下命令安装openssl
和curl
。
apt install -y openssl curl
(2)、搭建单群组4节点联盟链
在fisco
目录下创建一个bin目录,并把fisco-bcos文件移动到bin目录下,执行下面的指令,生成一条单群组4
节点的FISCO
链:
cd /fisco
mkdir bin
mv fisco-bcos bin
bash build_chain.sh -l 127.0.0.1:4 -p 30300,20200,8545 -e bin/fisco-bcos
其中-p
选项指定起始端口,分别是p2p_port
,channel_port
,jsonrpc_port
.
执行上述步骤的时候可能会出现权限不足的情况,此时我们需要进入到bin目录下执行命令:
chmod +x fisco-bcos
会成功执行并输出。
(3)、启动FISCO BCOS链
bash
为linux系统自带的命令处理工具,下面命令由bash
解析执行脚本,启动fisco
区块链:
bash nodes/127.0.0.1/start_all.sh
启动成功会输出类似下面内容的响应。否则请使用netstat -an | grep tcp
检查机器的30300~30303, 20200~20203, 8545~8548
端口是否被占用。
try to start node0
try to start node1
try to start node2
try to start node3
node1 start successfully
node2 start successfully
node0 start successfully
node3 start successfully
(4)、检查进程
检查进程是否启动
Linux ps
(英文全拼:process status)命令用于显示当前进程的状态,类似于 windows 的任务管理器。
Linux grep
命令用于查找文件里符合条件的字符串。
下面的命令意思是使用ps
查看linux中正在运行的进程(ps -ef
),然后找到不包含grep
的进程列表(grep -v grep
),再找到包含fisco-bcos
的进程列表(grep fisco-bcos
),中间的竖线代表管道,将上一个命令的输出,转换为下一个命令的输入。
ps -ef | grep -v grep | grep fisco-bcos
正常情况会有类似下面的输出,如果进程数不为4,则进程没有启动(一般是端口被占用导致的):
fisco 5453 1 1 17:11 pts/0 00:00:02 /home/ubuntu/fisco/nodes/127.0.0.1/node0/../fisco-bcos -c config.ini
fisco 5459 1 1 17:11 pts/0 00:00:02 /home/ubuntu/fisco/nodes/127.0.0.1/node1/../fisco-bcos -c config.ini
fisco 5464 1 1 17:11 pts/0 00:00:02 /home/ubuntu/fisco/nodes/127.0.0.1/node2/../fisco-bcos -c config.ini
fisco 5476 1 1 17:11 pts/0 00:00:02 /home/ubuntu/fisco/nodes/127.0.0.1/node3/../fisco-bcos -c config.ini
(5)、检查日志输出
查看节点node0
链接的节点数。tail
命令可用于查看文件的内容,有一个常用的参数 -f
表示查看文件尾部新增加的内容。
tail -f nodes/127.0.0.1/node0/log/log* | grep connected
正常情况会不停地输出连接信息,从输出可以看出node0
与另外3
个节点有连接。
执行下面指令,检查是否在共识
tail -f nodes/127.0.0.1/node0/log/log* | grep +++
正常情况会不停输出++++Generating seal
,表示共识正常。
2、FISCO BCOS控制台安装和使用
(1)、准备依赖
安装java
,下面命令更新系统的安装源,安装默认的java jdk。
apt update
apt install -y openjdk-8-jdk
回到fisco
子目录,解压控制台程序
cd /fisco
tar zxvf console.tar.gz
解压完成后,拷贝控制台配置文件,若节点未采用默认端口,请将文件中的20200
替换成节点对应的channel
端口。
# 最新版本控制台使用如下命令拷贝配置文件
cp -n console/conf/config-example.toml console/conf/config.toml
配置控制台证书,复制BCOS的证书到console
的配置目录
cp -r nodes/127.0.0.1/sdk/* console/conf/
(2)、启动控制台
进入控制台程序所在目录,执行下面命令启动控制台
cd /fisco/console && bash start.sh
输出信息表明启动成功 否则请检查conf/config.toml
中节点端口配置是否正确
(3)、用控制台获取信息
获取客户端版本:
getNodeVersion
获取节点信息:
getPeers
退出控制台:
quit
3、用控制台部署智能合约
(1)、编写HelloWorld合约
HelloWorld
合约提供两个接口,分别是get()
和set()
,用于获取/设置合约变量name
。合约内容如下:
pragma solidity ^0.4.24;
contract HelloWorld {
string name;
function HelloWorld() {
name = "Hello, World!";
}
function get()constant returns(string) {
return name;
}
function set(string n) {
name = n;
}
}
(2)、部署HelloWorld合约
重新启动控制台后,在控制台输入以下指令,部署成功则返回合约地址:
deploy HelloWorld
显示:
transaction hash: 0xd0305411e36d2ca9c1a4df93e761c820f0a464367b8feb9e3fa40b0f68eb23fa
contract address:0xb3c223fc0bf6646959f254ac4e4a7e355b50a344
(3)、调用HelloWorld合约
查看当前块高:
getBlockNumber
调用get
接口获取name
变量:
注意:此处的合约地址是之前步骤中部署合约deploy
指令返回的地址,每个人不一样,注意替换。
call HelloWorld 0xb3c223fc0bf6646959f254ac4e4a7e355b50a344 get
get接口不更改账本状态,所以区块高度不变。
调用set
设置name
,注意这里合约地址的替换:
call HelloWorld 0xb3c223fc0bf6646959f254ac4e4a7e355b50a344 set "Hello, FISCO BCOS"
显示:
transaction hash: 0x7e742c44091e0d6e4e1df666d957d123116622ab90b718699ce50f54ed791f6e
---------------------------------------------------------------------------------------------
transaction status: 0x0
description: transaction executed successfully
---------------------------------------------------------------------------------------------
Output
Receipt message: Success
Return message: Success
---------------------------------------------------------------------------------------------
Event logs
Event: {}
再次查看当前块高,块高增加表示已出块,账本状态已更改
调用get
接口获取name
变量,检查设置是否生效,注意这里合约地址需要替换:
call HelloWorld 0xb3c223fc0bf6646959f254ac4e4a7e355b50a344 get
注意:上面操作,地址和hash
等,需要替换为自己实际操作返回的值,否则会报错。