type Transaction struct { inner TxData // Consensus contents of a transaction //time 包的特点是时间分成显示和计算两部分 time time.Time // Time first seen locally (spam avoidance)
// encodeTyped writes the canonical encoding of a typed transaction to w. func(tx *Transaction) encodeTyped(w *bytes.Buffer) error { w.WriteByte(tx.Type()) //先写入类型,第一个字节 return rlp.Encode(w, tx.inner) }
//检查签名的合法性 funcsanityCheckSignature(v *big.Int, r *big.Int, s *big.Int, maybeProtected bool)error { if isProtectedV(v) && !maybeProtected { return ErrUnexpectedProtection }
var plainV byte if isProtectedV(v) { chainID := deriveChainId(v).Uint64() plainV = byte(v.Uint64() - 35 - 2*chainID) } elseif maybeProtected { // Only EIP-155 signatures can be optionally protected. Since // we determined this v value is not protected, it must be a // raw 27 or 28. plainV = byte(v.Uint64() - 27) } else { // If the signature is not optionally protected, we assume it // must already be equal to the recovery id. plainV = byte(v.Uint64()) } if !crypto.ValidateSignatureValues(plainV, r, s, false) { return ErrInvalidSig }
returnnil }
//是否开启了防止重放攻击 funcisProtectedV(V *big.Int)bool { if V.BitLen() <= 8 { v := V.Uint64() return v != 27 && v != 28 && v != 1 && v != 0 } // anything not 27 or 28 is considered protected returntrue }
// EffectiveGasTip returns the effective miner gasTipCap for the given base fee. // Note: if the effective gasTipCap is negative, this method returns both error // the actual negative value, _and_ ErrGasFeeCapTooLow func(tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) { if baseFee == nil { return tx.GasTipCap(), nil } var err error gasFeeCap := tx.GasFeeCap()
var h common.Hash if tx.Type() == LegacyTxType { //根据 Txdata 计算交易哈希 h = rlpHash(tx.inner) } else { h = prefixedRlpHash(tx.Type(), tx.inner) } tx.hash.Store(h) return h }
矿工对交易的封装和排序
首先封装交易和对应矿工费,矿工费为上文分析的手续费。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// TxWithMinerFee wraps a transaction with its gas price or effective miner gasTipCap type TxWithMinerFee struct { tx *Transaction minerFee *big.Int }
// NewTxWithMinerFee creates a wrapped transaction, calculating the effective // miner gasTipCap if a base fee is provided. // Returns error in case of a negative effective miner gasTipCap. funcNewTxWithMinerFee(tx *Transaction, baseFee *big.Int) (*TxWithMinerFee, error) { minerFee, err := tx.EffectiveGasTip(baseFee) if err != nil { returnnil, err } return &TxWithMinerFee{ tx: tx, minerFee: minerFee, }, nil }
接着需要根据 nonce 和手续费对交易排序
1 2 3 4 5 6
type TransactionsByPriceAndNonce struct { txs map[common.Address]Transactions // Per account nonce-sorted list of transactions heads TxByPriceAndTime // Next transaction for each unique account (price heap) signer Signer // Signer for the set of transactions baseFee *big.Int // Current base fee }
// Shift replaces the current best head with the next one from the same account. func(t *TransactionsByPriceAndNonce) Shift() { acc, _ := Sender(t.signer, t.heads[0].tx) //根据签名和交易获取的地址 if txs, ok := t.txs[acc]; ok && len(txs) > 0 { //封装交易和矿工费,取出矿工费最小的交易 if wrapped, err := NewTxWithMinerFee(txs[0], t.baseFee); err == nil { t.heads[0], t.txs[acc] = wrapped, txs[1:] heap.Fix(&t.heads, 0) //Fix 在索引 i 处的元素更改其值后重新建立堆排序。 return } } heap.Pop(&t.heads)//删除第一个元素 }
Message 对象
message 会封装合约,方便后面执行代码,日后将会移除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Message is a fully derived transaction and implements core.Message // // NOTE: In a future PR this will be removed. type Message struct { to *common.Address from common.Address nonce uint64 amount *big.Int gasLimit uint64 gasPrice *big.Int gasFeeCap *big.Int gasTipCap *big.Int data []byte accessList AccessList isFake bool }
影响交易的 EIP
EIP-155
重放攻击保护——防止了在一个以太坊链上的交易被重复广播到另外一条链。从区块高度 2,675,000 开始,为了签名计算交易哈希时应该加入 chainid,并且签名的 v 需要为 {0,1} + CHAIN_ID * 2 + 35,如果是不加入 chainid,那么 v 为 {0,1} + 27 也可以。
EIP-1559
改变交易的手续费机制,并且通过动态的区块大小避免短时间的拥塞。
首选对于单位 gas 都有基础费用,它是由父区块使用的 gas(gasused)和 gas 上限决定。这个机制导致当父区块的 gas 上限过大时,单位 gas 的基础费用就增加,反之则减少。基础费用会销毁而不是分给矿工。交易可以指定最高的 gas 单价,它包括了基础的区块费用和为交易优先打包的小费。
EIP-2718
定义新的交易类型,它可以作为未来的交易类型的封装。未来可能会通过底层的交易类型来指定转移支付 gas 的交易、多签名的交易,而不用通过合约实现复杂且高消耗的逻辑。封装一层,将来出现不同的 Txdata 时能保证向后兼容。