主页 > 鸿蒙系统安装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
}
参考
以太坊交易