zoukankan      html  css  js  c++  java
  • 以太坊 EVM内交易执行分析(一)

     以太坊上交易最终都会由EVM进行解析存入数据库,今天就来探讨一下,一笔交易是如何别EVM执行的。我们可以把交易分为三种。(注意,和交易相关的模块很多,交易的生命周期存在于整个以太坊中,我们这次只是分析和EVM相关的部分。)

         1、以太币转移,两个账户之间只发生了以太币的转移。

         2、合约创建,用户创建智能合约的交易。这类交易的to地址都是空着的。

         3、调用合约,用户去调用智能合约中的某个函数,这类交易中data信息包含了需要调用的函数hash值的前4个字节,以及参数。例如基于ERC20的Token转账就是这种类型,前四个字节是0xa9059cbb表示transfer(address _to, uint256 _value),后边跟了两个参数,to地址和交易数量。

         最好结合代码理解一下。

    https://github.com/ethereum/go-ethereum/blob/461291882edce0ac4a28f64c4e8725b7f57cbeae/core/vm/evm.go

        以太币转移

        先看一下以太币转移类型的交易,这类交易比较简单,主要函数是由context中的两个函数完成的,CanTransfer CanTransferFunc。

    type Context struct {
    // 账户余额够不够
    CanTransfer CanTransferFunc
    // 把eth转移给另外一个账户
    Transfer TransferFunc
    // 对入参n返回一个hash
    GetHash GetHashFunc

    // Message information
    Origin common.Address // Provides information for ORIGIN
    GasPrice *big.Int // Provides information for GASPRICE

    // Block information
    Coinbase common.Address // Provides information for COINBASE
    GasLimit uint64 // Provides information for GASLIMIT
    BlockNumber *big.Int // Provides information for NUMBER
    Time *big.Int // Provides information for TIME
    Difficulty *big.Int // Provides information for DIFFICULTY
    }
     

    下边具体分析一下怎么实现的。


    func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {
    return db.GetBalance(addr).Cmp(amount) >= 0
    }

    func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {
    db.SubBalance(sender, amount)
    db.AddBalance(recipient, amount)
    }
        怎么样是不是so easy,一眼就看出来了;就是调用数据接口,实现数据库的数据的修改就可以了,对账户的余额进行增加、减少和查询;当然实际情况并非这么简单,之所以看着这么简单,就是我们常说的解耦;后续我会继续分析state和数据库等模块,那会儿我们就会有更清晰的认识。

    合约创建调用合约

     

    合约创建,evm.Create的逻辑和Call方法比较类似的。

    call和create几点不同:

    1)由于智能合约的创建是没有to地址的,所以SetCallCode方法的参数是从直接有用户传进去的的;而call则不一样,例如你转账erc20代币的时候,to地址是合约地址,所以SetCallCode方法的入参则是从to地址的关联的code中获取的。

    2)智能合约创建是一个从无到有的过程,所以statedb中没有合约的地址和账户,所以创建合约地址和账户是必然的过程。

    3)call()的input类型为[]byte,和create()的code类型同样为[]byte;这两者从交易的角度是一样的;但是当系统解析到to地址时,才有了分化;to地址不为空,则tx.data被当作contract的input,to地址为空的时候,则tx.data被当作contract的code。

         还有后续继续分析一下,交易是如何被解释器具体分析执行的。

  • 相关阅读:
    SSH框架——(二)四层结构:DAO,Service,Controller,View层
    Spring知识概括梳理
    设计模式——(一)工厂模式2
    设计模式——(一)工厂模式1
    Spring——(一)IoC
    Toad 实现 SQL 优化
    string 和String的区别
    StructureMap依赖注入
    Oracle/PLSQL: BitAnd Function
    log.debug(e.getMessage());
  • 原文地址:https://www.cnblogs.com/405845829qq/p/10071658.html
Copyright © 2011-2022 走看看