智能合约是运行在区块链上的一段代码,代码的逻辑定义了合约的内容。由于智能合约的存在,以太坊能够实现比较复杂的交易。

智能合约的创建和运行

  • 智能合约的代码写完后,要编译成bytecode
  • 创建合约:外部帐户发起一个转账交易到0x0的地址
            • 转账的金额是0,但是要支付汽油费
            • 合约的代码放在data域里
  • 智能合约运行在EVM(Ethereum Virtual Machine)上
            EVM的作用:通过EVM,为智能合约的运行提供一个一致性的平台。
  • 以太坊是一个交易驱动的状态机
            • 调用智能合约的交易发布到区块链上后,每个矿工都会执行这个交易,从当前状态确定性地转移到下一个状态

注:

        智能合约在执行过程中,任何对账户状态的修改,都是在全节点本地进行修改,等到包含的所有交易请求的智能合约都执行完之后,再将所有的修改一起发布出去。只有当区块发布到区块链上,该修改才能变成外部可见的,变成区块链上的共识。因此,以太坊中是先执行智能合约,再挖矿。
        当其他全节点收到该全节点发布的区块后,再将该区块中的所有交易请求的智能合约都执行一遍进行验证,验证无误后,更新本地的三棵树(状态树、交易树、收据树)

汽油费(Gas fee)

        以太坊和比特币系统的设计模式相差很大,其中很重要的一点就是,比特币系统不是图灵完备的,而以太坊是图灵完备的,因此以太坊可以实现的功能比比特币系统要复杂。但这也带来一个问题,如果出现了死循环怎么办?那么就意味着一个智能合约一直被调用,直至停机。而在理论上无法证明一段程序是否会造成停机,因此,以太坊将该问题抛给了调用智能合约的用户。如果用户要调用一个智能合约,需要支付一定的汽油费。
        下面是交易数据的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type txdata struct {
//交易序号(用来防止重放攻击(replay attack))
AccountNonce uint64 `json:"nonce" gencodec:"required"`
//单位汽油价格
Price *big.Int `json:"gasPrice" gencodec:"required"`
//用户愿意支付的最大汽油量
GasLimit uint64 `json:"gas" gencodec:"required"`
//收款人的地址
Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation
//转账金额
Amount *big.Int `json:"value" gencodec:"required"`
//用于存放用户要调用合约中的哪个函数,以及传入的参数
Payload []byte `json:"input" gencodec:"required"`

}

Gas fee = Price*GasLimit

错误处理

  • 智能合约中不存在自定义的try-catch结构。
  • 一旦遇到异常,除特殊情况外,本次执行操作全部回滚。下面是可能引起操作回滚的情况:

        1、汽油费不够(此时,已执行的操作所消耗的汽油费不退回给用户)
        2、可以抛出错误的语句:
        • assert(bool condition):如果条件不满足就抛出—用于内部错误。
        • require(bool condition):如果条件不满足就抛掉—用于输入或者外部组件引起的错误。
        • revert():终止运行并回滚状态变动。

嵌套调用

  • 智能合约的执行具有原子性:执行过程中出现错误,会导致回滚。
  • 嵌套调用是指一个合约调用另一个合约中的函数。
  • 嵌套调用是否会触发连锁式的回滚?

        • 如果一个合约采用“直接调用”方式调用另一个合约,则若被调用的合约执行过程中发生异常,会触发连锁式的回滚。
        • 如果一个合约通过“call()函数”方式调用另一个合约,不会触发连锁式的回滚。

  • 一个合约直接向一个合约帐户里转账,没有指明调用哪个函数,仍然会引起嵌套调用(调用fallback()函数)

智能合约可以获得的信息

1、区块信息

block.blockhash(uint blockNumber) returns (bytes32):给定区块的哈希-仅对最近的256个区块而不包括当前区块。
block.coinbase(address):挖出当前区块的矿工地址。
block.difficulty(uint):当前区块难度。
block.gaslimit(uint):当前区块gas限额。
block.number(uint):当前区块号。
block.timestamp(uint):自uinx epoch起始,当前区块以秒计的时间戳。


2、调用信息

msg.data(bytes):完整的calldata。
msg.gas(uint):剩余gas。
msg.sender(address):当前消息发送者。
msg.sig(bytes4):calldata的前四个字节(数字签名,即函数标识符)。
msg.value(uint):随消息发送的 wei 的数量。
now(uint):当前区块的时间戳。
tx.gasprice(uint):交易的gas价格。
tx.origin(address):交易发起者的地址。

本文参考:
https://www.youtube.com/watch?v=RADwCuRRoFs&list=PLnTPdMjBRmAYehJkVbAXqxO-0cc9ALC6V&index=22

最后更新: 2019年03月28日 21:52

原始链接: http://yoursite.com/2019/03/28/以太坊-智能合约/