主页 > 鸿蒙系统安装imtoken > 以太坊中常见的交易(源码分析)

以太坊中常见的交易(源码分析)

鸿蒙系统安装imtoken 2023-04-03 07:36:48

交易流程

以太坊的转账过程基本上是这样的:

发起交易:指定目标地址和交易金额,以及所需的gas/gasLimit 交易签名:使用账户私钥对交易进行签名 提交交易:验证交易并将交易提交至交易缓冲池 广播交易:通知以太坊虚拟机向其他节点广播交易信息Transaction

主要包括:Txid、TxSize、from address、payee address、transaction Amount、Gas related、signature information

这里的数据结构和比特币不同,没有Input[]的概念,因为以太坊的世界有状态机,记录用户的余额以太坊在哪个平台交易好,不需要UTXO来计算用户余额是否充足

type Transaction struct {
    //交易数据
    data txdata
    hash atomic.Value
    size atomic.Value
    //钱包根据 from来找到 
    //account := accounts.Account{Address: args.From}
    from atomic.Value
}
type txdata struct {
    //发送者发起的交易总数
    AccountNonce uint64          `json:"nonce"    gencodec:"required"`
    //交易的Gas价格
    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"`
    //其他数据
    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
    Hash *common.Hash `json:"hash" rlp:"-"`
}

交易签名的生成

根据私钥+txHash生成签名,返回一个byte[]以太坊在哪个平台交易好,然后拆分成3个big.Int属性,格式为[R || 年代|| V]

//根据ECDSA算法生成签名,以字节数组的形式返回  按[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
    // 交易相关签名数据
    V *big.Int `json:"v" gencodec:"required"`
    R *big.Int `json:"r" gencodec:"required"`
    S *big.Int `json:"s" gencodec:"required"`

交易池

更重要的参数:

添加交易池逻辑:

先锁池,将交易加入队列(待处理的交易),先查看交易池中是否已经存在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
}

添加到交易池中,判断是否已经全部存在,拒绝重复添加交易,验证交易的合法性

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
}

参考

以太坊交易