• 以太坊源码探究之交易与签名


    与比特币相比,以太坊中的交易结构有相当明显的不同。下面是以太坊中Transaction数据结构的UML图:
     
    以太坊交易类图

    右边的txdata才是实际的交易数据,它在core/types/transaction.go里是这样声明的:

    type txdata struct {
        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"`
    
        // Signature values
        V *big.Int `json:"v" gencodec:"required"`
        R *big.Int `json:"r" gencodec:"required"`
        S *big.Int `json:"s" gencodec:"required"`
    
        // This is only used when marshaling to JSON.
        Hash *common.Hash `json:"hash" rlp:"-"`
    }
    

    第一个字段AccountNonce,直译就是账户随机数。它是以太坊中很小但也很重要的一个细节。以太坊为每个账户和交易都创建了一个Nonce,当从账户发起交易的时候,当前账户的Nonce值就被作为交易的Nonce。这里,如果是普通账户那么Nonce就是它发出的交易数,如果是合约账户就是从它的创建合约数。

    为什么要使用这个Nonce呢?其主要目的就是为了防止重复攻击(Replay Attack)。因为交易都是需要签名的,假定没有Nonce,那么只要交易数据和发起人是确定的,签名就一定是相同的,这样攻击者就能在收到一个交易数据后,重新生成一个完全相同的交易并再次提交,比如A给B发了个交易,因为交易是有签名的,B虽然不能改动这个交易数据,但只要反复提交一模一样的交易数据,就能把A账户的所有资金都转到B手里。

    当使用账户Nonce之后,每次发起一个交易,A账户的Nonce值就会增加,当B重新提交时,因为Nonce对不上了,交易就会被拒绝。这样就可以防止重复攻击。当然,事情还没有完,因为还能跨链实施攻击,直到EIP-155引入了chainID,才实现了不同链之间的交易数据不兼容。事实上,Nonce并不能真正防止重复攻击,比如A向B买东西,发起交易T1给B,紧接着又提交另一个交易T2,T2的Gas价格更高、优先级更高将被优先处理,如果恰好T2处理完成后剩余资金已经不足以支付T1,那么T1就会被拒绝。这时如果B已经把东西给了A,那A也就攻击成功了。所以说,就算交易被处理了也还要再等待一定时间,确保生成足够深度的区块,才能保证交易的不可逆。

    Price指的是单位Gas的价格,所谓Gas就是交易的消耗,Price就是单位Gas要消耗多少以太币(Ether),Gas * Price就是处理交易需要消耗多少以太币,它就相当于比特币中的交易手续费。

    GasLimit限定了本次交易允许消耗资源的最高上限,换句话说,以太坊中的交易不可能无限制地消耗资源,这也是以太坊的安全策略之一,防止攻击者恶意占用资源。

    Recipient是交易接收者,它是common.Address指针类型,代表一个地址。这个值也可以是空的,这时在交易执行时,会通过智能合约创建一个地址来完成交易。

    Amount是交易额。这个简单,不用解释。

    Payload比较重要,它是一个字节数组,可以用来作为创建合约的指令数组,这时每个字节都是一个单独的指令;也可以作为数据数组,由合约指令来进行操作。合约由以太坊虚拟机(Ethereum Virtual Machine,EVM)创建并执行。

    V、R、S是交易的签名数据。以太坊当中,交易经过数字签名之后,生成的signature是一个长度65的字节数组,它被截成三段,前32字节被放进R,再32字节放进S,最后1个字节放进V。那么为什么要被截成3段呢?以太坊用的是ECDSA算法,R和S就是ECSDA签名输出,V则是Recovery ID。看下面的javascript代码:

    var sig = secp256k1.sign(msgHash, privateKey)
      var ret = {}
      ret.r = sig.signature.slice(0, 32)
      ret.s = sig.signature.slice(32, 64)
      ret.v = sig.recovery + 27
    


    作者:魏兆华
    链接:https://www.jianshu.com/p/30833db88330
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    Eclipse在线集成maven M2eclipse插件
    RBAC用户权限管理数据库设计
    Linux下修改mysql密码
    Red hat 6.4下面的qt安装
    export default {} 和new Vue()区别
    Ajax中POST和GET的区别
    JS es6-Symbol
    JS es6编程规范
    JS之箭头函数
    JS异步加载的方式
  • 原文地址:https://www.cnblogs.com/feng9exe/p/9896443.html
Copyright © 2020-2023  润新知