交易纯函数调用关系 - Agzs/geth-pbft-study GitHub Wiki

1、数据库中账户余额增减角度逆推


======================
func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction)

func (b *BlockGen) AddTx(tx *types.Transaction)

ApplyTransaction(b.config, nil, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
======================
-----------
func (b *SimulatedBackend) Commit()

b.blockchain.InsertChain([]*types.Block{b.pendingBlock})
-----------
func (bc *BlockChain) procFutureBlocks()

bc.InsertChain(blocks[i : i+1])
-----------
func newCanonical(n int, full bool)

blockchain.InsertChain(blocks)
-----------
func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, blockchainId, networkId uint64, maxPeers int, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database)

manager.blockchain.InsertChain(blocks)
-----------
go worker.wait()

self.chain.InsertChain(types.Blocks{block})
-----------

func (bc *BlockChain) InsertChain(chain types.Blocks) 

bc.processor.Process(block, state, bc.vmConfig)

func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config)

ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, totalUsedGas, cfg)
=======================
-----------
*******
fullNode, err := eth.New(ctx, cfg)
func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error)

eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine)

newWorker(config, engine, common.Address{}, eth, mux)

go worker.update() + go worker.wait() + worker.commitNewWork()

self.commitNewWork()
*******
^^^^^^^
func startNode(ctx *cli.Context, stack *node.Node)

ethereum.StartMining(true)
+++++++
func (api *PrivateMinerAPI) Start(threads *int)

api.e.StartMining(true)
+++++++

func (s *Ethereum) StartMining(local bool)

go s.miner.Start(eb)
^^^^^^^

fullNode, err := eth.New(ctx, cfg)
func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error)

eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine)

go miner.update()

func (self *Miner) update()

self.Start(self.coinbase)
^^^^^^^

func (self *Miner) Start(coinbase common.Address)

self.worker.commitNewWork()
*******
func (self *worker) commitNewWork()

work.commitTransactions(self.mux, txs, self.chain, self.coinbase)
-----------
...

newWorker(config, engine, common.Address{}, eth, mux)

go worker.update()

self.current.commitTransactions(self.mux, txset, self.chain, self.coinbase)
-----------

func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsByPriceAndNonce, bc *core.BlockChain, coinbase common.Address)

env.commitTransaction(tx, bc, coinbase, gp)

ApplyTransaction(env.config, bc, &coinbase, gp, env.state, env.header, tx, env.header.GasUsed, vm.Config{})
==============

func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config)

ApplyMessage(vmenv, msg, gp)

st.TransitionDb()

evm.Call(sender, st.to().Address(), st.data, st.gas, st.value)

evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)

// Transfer subtracts amount from sender and adds amount to recipient using the given Db
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {
	db.SubBalance(sender, amount)
	db.AddBalance(recipient, amount)
}

db.SubBalance(sender, amount) >> StateDb.SubBalance(sender, amount) >> stateObject.SubBalance(amount) >> c.SetBalance(new(big.Int).Sub(c.Balance(), amount)) >> stateObject.SetBalance(amount) >> stateObject.setBalance(amount)

db.AddBalance(recipient, amount) >> StateDB.AddBalance(recipient, amount) >> stateObject.AddBalance(amount) >> c.SetBalance(new(big.Int).Add(c.Balance(), amount)) >> stateObject.SetBalance(amount) >> stateObject.setBalance(amount)

2、命令行产生交易操作流程

eth.sendTransaction()

func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs)

submitTransaction(ctx, s.b, signed)

func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction)

    b.SendTx(ctx, tx) >> func (b *EthApiBackend) SendTx((ctx, tx) >> b.eth.txPool.AddLocal(signedTx) >> pool.addTx(tx, !pool.config.NoLocals) >> pool.add(tx, local)


=============================
personal.sendTransaction()

func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string)

submitTransaction(ctx, s.b, signed)

3、交易传递、广播

ProtocolManager.Start()

go pm.txBroadcastLoop()

self.BroadcastTx(event.Tx.Hash(), event.Tx)             

peer.SendTransactions(types.Transactions{tx})

p2p.Send(p.rw, TxMsg, txs)

===================
------
newPool := core.NewTxPool(config.TxPool, eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)

go pool.eventLoop() ==>顺序执行 pool.resetState()

pool.resetState()

func (pool *TxPool) resetState()

pool.promoteExecutables(currentState, nil)
------
******
func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) >> b.SendTx(ctx, tx)

func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction)

b.eth.txPool.AddLocal(signedTx)

pool.addTx(tx, !pool.config.NoLocals)
******
func (pool *TxPool) AddRemote(tx *types.Transaction),没有被调用,仅用于测试

pool.addTx(tx, false)
******
func (pool *TxPool) addTx(tx *types.Transaction, local bool)

pool.promoteExecutables(state, []common.Address{from})
------
******
fullNode, err := eth.New(ctx, cfg)
func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error)

newPool := core.NewTxPool(config.TxPool, eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)

go pool.eventLoop()

pool.addTxs(ev.Txs, false)
******
func (pool *TxPool) AddLocals(txs []*types.Transaction),没有被调用,仅用于测试

pool.addTxs(txs, !pool.config.NoLocals)
******
func (pm *ProtocolManager) handleMsg(p *peer)的case msg.Code == TxMsg分支,执行pm.txpool.AddRemotes(txs)

func (pool *TxPool) AddRemotes(txs []*types.Transaction)

pool.addTxs(txs, false)
******

func (pool *TxPool) addTxs(txs []*types.Transaction, local bool)

pool.promoteExecutables(state, addrs)
------

func (pool *TxPool) promoteExecutables(state *state.StateDB, accounts []common.Address)

pool.promoteTx(addr, hash, tx)

go pool.eventMux.Post(TxPreEvent{tx})

sub.deliver(event) >> s.postC <- event, postC <=> readC

func (s *TypeMuxSubscription) Chan() <-chan *TypeMuxEvent { return s.readC }

Chan()方法在txBroadcastLoop()中被调用,进一步触发BroadcastTx(),然后将TxMsg广播出去,这是最重要的功能

Chan()方法在worker.update()中被调用,在TxPreEvent分支,进一步触发`Apply transaction to the pending state if we're not mining`相关操作,其中包含self.current.commitTransactions(self.mux, txset, self.chain, self.coinbase)

Chan()方法在EventSystem.eventLoop()中被调用,进一步触发es.broadcast(index, ev)