右边的txdata才是实际的交易数据,它在core/types/transaction.go里是这样声明的:javascript
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就是它发出的交易数,若是是合约帐户就是从它的建立合约数。java
为何要使用这个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也就攻击成功了。因此说,就算交易被处理了也还要再等待必定时间,确保生成足够深度的区块,才能保证交易的不可逆。json
Price指的是单位Gas的价格,所谓Gas就是交易的消耗,Price就是单位Gas要消耗多少以太币(Ether),Gas * Price就是处理交易须要消耗多少以太币,它就至关于比特币中的交易手续费。数组
GasLimit限定了本次交易容许消耗资源的最高上限,换句话说,以太坊中的交易不可能无限制地消耗资源,这也是以太坊的安全策略之一,防止攻击者恶意占用资源。安全
Recipient是交易接收者,它是common.Address指针类型,表明一个地址。这个值也能够是空的,这时在交易执行时,会经过智能合约建立一个地址来完成交易。数据结构
Amount是交易额。这个简单,不用解释。ui
Payload比较重要,它是一个字节数组,能够用来做为建立合约的指令数组,这时每一个字节都是一个单独的指令;也能够做为数据数组,由合约指令来进行操做。合约由以太坊虚拟机(Ethereum Virtual Machine,EVM)建立并执行。spa
V、R、S是交易的签名数据。以太坊当中,交易通过数字签名以后,生成的signature是一个长度65的字节数组,它被截成三段,前32字节被放进R,再32字节放进S,最后1个字节放进V。那么为何要被截成3段呢?以太坊用的是ECDSA算法,R和S就是ECSDA签名输出,V则是Recovery ID。看下面的javascript代码:3d
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