以太坊的普通交易(源碼分析)

交易流程

以太坊的轉(zhuǎn)賬流程基本是這樣的:

  1. 發(fā)起交易:指定目標(biāo)地址和交易金額,以及必需的gas/gasLimit
  2. 交易簽名:使用賬戶私鑰對(duì)交易進(jìn)行簽名
  • 和比特幣一樣,也是先對(duì)交易本身求hash,再進(jìn)行簽名
  1. 提交交易:驗(yàn)簽交易,并將交易提交到交易緩沖池
  2. 廣播交易:通知以太坊虛擬機(jī)吧交易信息廣播給其他節(jié)點(diǎn)

Transaction

主要包括: Txid、TxSize、from地址、收款人地址、交易Amount、Gas相關(guān)、簽名信息
這里面和的數(shù)據(jù)結(jié)構(gòu)和比特幣不同,并沒有Input[]的概念,因?yàn)橐蕴坏氖澜缡怯袪顟B(tài)機(jī)的,記錄了該用戶的余額,不需要才UTXO來計(jì)算用戶余額是否充足

type Transaction struct {
    //交易數(shù)據(jù)
    data txdata
    hash atomic.Value
    size atomic.Value

    //錢包根據(jù) from來找到 
    //account := accounts.Account{Address: args.From}
    from atomic.Value
}

type txdata struct {
    //發(fā)送者發(fā)起的交易總數(shù)
    AccountNonce uint64          `json:"nonce"    gencodec:"required"`
    //交易的Gas價(jià)格
    Price        *big.Int        `json:"gasPrice" gencodec:"required"`
    //交易允許消耗的最大Gas
    GasLimit     uint64          `json:"gas"      gencodec:"required"`
    //交易接收者地址
    Recipient    *common.Address `json:"to"       rlp:"nil"` // nil means contract creation
    //交易額
    Amount       *big.Int        `json:"value"    gencodec:"required"`
    //其他數(shù)據(jù)
    Payload      []byte          `json:"input"    gencodec:"required"`

    // Signature values
    // 交易相關(guān)簽名數(shù)據(jù)
    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
    Hash *common.Hash `json:"hash" rlp:"-"`
}

交易簽名的生成

根據(jù) 私鑰 + txHash 生成簽名,返回一個(gè)byte[],再拆分為3個(gè)big.Int屬性,按[R || S || V]格式

//根據(jù)ECDSA算法生成簽名,以字節(jié)數(shù)組的形式返回  按[R || S || V]格式
func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
    seckey := math.PaddedBigBytes(prv.D, prv.Params().BitSize/8)
    return secp256k1.Sign(hash, seckey)
}

func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
    r, s, v, err := signer.SignatureValues(tx, sig)
    if err != nil {
        return nil, err
    }
    cpy := &Transaction{data: tx.data}
    cpy.data.R, cpy.data.S, cpy.data.V = r, s, v
    return cpy, nil
}

    // Signature values
    // 交易相關(guān)簽名數(shù)據(jù)
    V *big.Int `json:"v" gencodec:"required"`
    R *big.Int `json:"r" gencodec:"required"`
    S *big.Int `json:"s" gencodec:"required"`

交易池

比較重要的參數(shù):

  • pending map[common.Address]*txList // All currently processable transactions
  • queue map[common.Address]*txList // Queued but non-processable transactions
  • all *txLookup // all = queue + pending
  • priced *txPricedList // All transactions sorted by price

交易池的添加邏輯:

  1. 先給pool加鎖
  2. 把交易添加到queue里面(待處理交易),先check是否在交易池中已經(jīng)存在 txid

./core/tx_pool.go

type TxPool struct {
    config       TxPoolConfig
    chainconfig  *params.ChainConfig
    chain        blockChain
    gasPrice     *big.Int
    txFeed       event.Feed
    scope        event.SubscriptionScope
    chainHeadCh  chan ChainHeadEvent
    chainHeadSub event.Subscription
    signer       types.Signer
    mu           sync.RWMutex

    currentState  *state.StateDB      // Current state in the blockchain head
    pendingState  *state.ManagedState // Pending state tracking virtual nonces
    currentMaxGas uint64              // Current gas limit for transaction caps

    locals  *accountSet // Set of local transaction to exempt from eviction rules
    journal *txJournal  // Journal of local transaction to back up to disk

    pending map[common.Address]*txList   // All currently processable transactions
    queue   map[common.Address]*txList   // Queued but non-processable transactions
    beats   map[common.Address]time.Time // Last heartbeat from each known account
    all     *txLookup                    // All transactions to allow lookups
    priced  *txPricedList                // All transactions sorted by price

    wg sync.WaitGroup // for shutdown sync
    homestead bool
}

添加到交易池

  1. 判斷all中是否已經(jīng)存在了,拒絕重復(fù)添加交易
  1. 驗(yàn)證交易的合法性
  • Gas的設(shè)置,不能小于pool的最小值設(shè)置,也不能大于currentMaxGas
  • TxSize不能超過32kb
  • 簽名認(rèn)證
  • 確認(rèn)Nonce的順序
  • 確認(rèn)余額是否足夠 // Cost = amount + gasprice * gaslimit Cost > Balance
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
    // Heuristic limit, reject transactions over 32KB to prevent DOS attacks
    if tx.Size() > 32*1024 {
        return ErrOversizedData
    }

    if tx.Value().Sign() < 0 {
        return ErrNegativeValue
    }
    // Ensure the transaction doesn't exceed the current block limit gas.
    if pool.currentMaxGas < tx.Gas() {
        return ErrGasLimit
    }
    // Make sure the transaction is signed properly
    from, err := types.Sender(pool.signer, tx)
    
    // Drop non-local transactions under our own minimal accepted gas price
    local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
    if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
        return ErrUnderpriced
    }
    // Ensure the transaction adheres to nonce ordering
    if pool.currentState.GetNonce(from) > tx.Nonce() {
        return ErrNonceTooLow
    }
    // Transactor should have enough funds to cover the costs
    // cost == V + GP * GL
    if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
        return ErrInsufficientFunds
    }
    intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)

    if tx.Gas() < intrGas {
        return ErrIntrinsicGas
    }
    return nil
}

參考

以太坊交易
http://www.lxweimin.com/p/6df19510507c

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容