以太坊项目最初目标是打造一个智能合约的平台,该平台支持图灵完备的应用,按照智能合约的约定逻辑自动执行,理想状态下将不存在故障停机、审查、欺诈,以及第三方干预等问题。
与比特币相比。以太坊主要具有以下特点:
- 支持图灵完备的智能合约,设计了编程语言Solidity和虚拟机EVM;
- 选用了内存需求较高的哈希函数,避免出现强算力矿机、矿池攻击;
- 叔块(uncle block)激励机制,降低矿池的优势,并减少了区块产生间隔(10分钟降低到15秒左右);
- 采用账户系统和世界状态,而不是UTXO,容易支持更复杂的逻辑;
- 通过Gas限制代码执行指令数,避免循环执行攻击;
- 支持POW共识算法,并计划支持效率更高的POS算法。
以太坊将比特币针对数字货币交易的功能进一步进行拓展,面向更复杂和灵活的应用场景,支持智能合约新特性,从单一基于UTXO的数字货币交易,延伸到图灵完备的通用计算机领域。
核心概念
- 智能合约
以计算机程序的方式来缔结和运行各种合约。
- 账户
以太坊采用账户来记录系统状态,每个账户存储余额信息、智能合约代码和内部数据存储等。
账户有两种类型:合约账户和外部账户。
- 合约账户
存储执行的智能合约代码,只能被外部账户来调用激活; - 外部账户
以太币拥有者账户,对应的某公钥。账户包括nonce、balance、storageRoot、codeHash等字段,由个人控制。
- 交易
交易在以太坊中是指从一个账户到另一个账户的消息数据。消息数据可以是以太币或者智能合约执行参数。
以太坊采用交易作为执行操作的最小单位。每个交易宝库奥如下字段:
- to:目标账户地址
- value:可以指定转移的以太币数量;
- nonce:交易相关的字串;
- gasPrice:执行交易需要消耗的Gas价格;
- startgas:交易消耗的最大Gas值;
- signature:签名信息。
- 以太币
以太币(Ether)是以太坊网络中的货币。
- 燃料(Gas)
燃料控制某次交易执行指令的上限。每执行一条合约指令会消耗固定的燃料,当某个交易还未执行结束,而燃料消耗完时,合约执行终止并回滚状态。
主要设计
智能合约相关设计
以以太坊虚拟机作为智能合约的运行环境。
采用solidity智能合约编程语言。
交易模型
比特币UTXO模型,以太坊账户模型。
特性 | UTXO模型 | 账户模型 |
---|---|---|
状态查询和变更 | 需要回溯历史 | 直接访问 |
存储空间 | 较大 | 较小 |
易用性 | 较难处理 | 易于理解和编程 |
安全性 | 较好 | 需要处理好重放攻击等情况 |
可追溯性 | 支持历史 | 不支持追溯历史 |
共识
以太坊目前采用基于成熟的POW共识的变种算法Ethash协议作为共识机制。
降低攻击
以太坊网络降低攻击的核心设计思想仍然是通过经济激励机制防止少数人作恶:
- 所有交易都需要提供交易费用,避免DDoS攻击;
- 程序运行执行数通过Gas来限制,所消耗的费用超过设定上的上限时就会被取消,避免出现恶意合约。
提高扩展性
通过分片(sharding)机制来提高整个网络的可扩展性。
代码解析-Solidity
智能合约-投票
pragma solidity >=0.4.22 <0.6.0; //指定该合约兼容的编译器版本
contract Ballot {
//结构体
struct Voter { //投票人
uint weight; //该投票人权重
bool voted; //是否已投票
uint8 vote; //提案索引号
address delegate; //受委托人的账户地址
}
struct Proposal { //提案
uint voteCount; //获得的票数
}
//状态变量
address chairperson; //投票发起人,类型为address
mapping(address => Voter) voters; //所有投票人,类型为address到Voter的映射
Proposal[] proposals; //所有提案,类型为Proposal数组
/// Create a new ballot with $(_numProposals) different proposals.
constructor(uint8 _numProposals) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
proposals.length = _numProposals;
}
//函数
/// Give $(toVoter) the right to vote on this ballot.
/// May only be called by $(chairperson).
function giveRightToVote(address toVoter) public { //赋予投票权
if (msg.sender != chairperson || voters[toVoter].voted) return;
voters[toVoter].weight = 1;
}
/// Delegate your vote to the voter $(to).
function delegate(address to) public { //委托投票权
Voter storage sender = voters[msg.sender]; // assigns reference 获取委托人
if (sender.voted) return;
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
to = voters[to].delegate;
if (to == msg.sender) return;
sender.voted = true;
sender.delegate = to;
Voter storage delegateTo = voters[to];
if (delegateTo.voted)
proposals[delegateTo.vote].voteCount += sender.weight;
else
delegateTo.weight += sender.weight;
}
/// Give a single vote to proposal $(toProposal).
function vote(uint8 toProposal) public { //进行投票
Voter storage sender = voters[msg.sender];
if (sender.voted || toProposal >= proposals.length) return;
sender.voted = true;
sender.vote = toProposal;
proposals[toProposal].voteCount += sender.weight;
}
function winningProposal() public view returns (uint8 _winningProposal) { //查询获胜提案
uint256 winningVoteCount = 0;
for (uint8 prop = 0; prop < proposals.length; prop++)
if (proposals[prop].voteCount > winningVoteCount) {
winningVoteCount = proposals[prop].voteCount;
_winningProposal = prop;
}
}
}