交易数据结构
//go-ethereum/core/types/transaction.go
type Transaction struct {
data txdata
// caches
hash atomic.Value
size atomic.Value
from atomic.Value
}
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:"-"`
}
交易的执行
Block 类型的基本目的之一,就是为了执行交易。狭义的交易可能仅仅是一笔转帐,而广义的交易同时还会支持许多其他的意图。Ethereum 中采用的是广义交易概念。按照其架构设计,交易的执行可大致分为内外两层结构:
第一层是虚拟机外
包括执行前将Transaction类型转化成Message,创建虚拟机(EVM)对象,计算一些Gas消耗,以及执行交易完毕后创建收据(Receipt)对象并返回等;
go-ethereum/core/state_processor.go
func (p *StateProcessor) Process(block *Block, statedb *StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) {
var {
receipts types.Receipts
totalUsedGas = big.NewInt(0)
header = block.Header()
allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit())
}
...
for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, _, err := ApplyTransaction(p.config, p.bc, author:nil, gp, statedb, header, tx, totalUsedGas, cfg)
if err != nil { return nil, nil, nil, err}
receipts = append(receipts, receipt)
allLogs = append(allLogs, receipt.Logs...)
}
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts)
return receipts, allLogs, totalUsedGas, nil
}
第二层是虚拟机内
包括执行转帐,和创建合约并执行合约的指令数组。