github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/light/txpool.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:39</date> 10 //</624450096854994944> 11 12 13 package light 14 15 import ( 16 "context" 17 "fmt" 18 "sync" 19 "time" 20 21 "github.com/ethereum/go-ethereum/common" 22 "github.com/ethereum/go-ethereum/core" 23 "github.com/ethereum/go-ethereum/core/rawdb" 24 "github.com/ethereum/go-ethereum/core/state" 25 "github.com/ethereum/go-ethereum/core/types" 26 "github.com/ethereum/go-ethereum/ethdb" 27 "github.com/ethereum/go-ethereum/event" 28 "github.com/ethereum/go-ethereum/log" 29 "github.com/ethereum/go-ethereum/params" 30 "github.com/ethereum/go-ethereum/rlp" 31 ) 32 33 const ( 34 //ChainHeadChansize是侦听ChainHeadEvent的通道的大小。 35 chainHeadChanSize = 10 36 ) 37 38 //TxPermanent是挖掘事务之后挖掘的块数 39 //被认为是永久的,不需要回滚 40 var txPermanent = uint64(500) 41 42 //TxPool为轻型客户机实现事务池,从而跟踪 43 //本地创建的事务的状态,检测是否包含这些事务 44 //在一个块(矿)或回卷。自从我们 45 //始终以相同的顺序接收所有本地签名的事务 46 //创建。 47 type TxPool struct { 48 config *params.ChainConfig 49 signer types.Signer 50 quit chan bool 51 txFeed event.Feed 52 scope event.SubscriptionScope 53 chainHeadCh chan core.ChainHeadEvent 54 chainHeadSub event.Subscription 55 mu sync.RWMutex 56 chain *LightChain 57 odr OdrBackend 58 chainDb ethdb.Database 59 relay TxRelayBackend 60 head common.Hash 61 nonce map[common.Address]uint64 //“待定” 62 pending map[common.Hash]*types.Transaction //按Tx哈希排序的挂起事务 63 mined map[common.Hash][]*types.Transaction //按块哈希挖掘的事务 64 clearIdx uint64 //可包含已开采Tx信息的最早区块编号 65 66 homestead bool 67 } 68 69 //txtrelaybackend提供了一个接口,用于转发Transacion的机制 70 //到ETH网络。函数的实现应该是非阻塞的。 71 // 72 //发送指示后端转发新事务 73 //new head在tx池处理后通知后端有关新头的信息, 74 //包括自上次事件以来的已挖掘和回滚事务 75 //Discard通知后端应该丢弃的事务 76 //因为它们被重新发送或被挖掘所取代 77 //很久以前,不需要回滚 78 type TxRelayBackend interface { 79 Send(txs types.Transactions) 80 NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) 81 Discard(hashes []common.Hash) 82 } 83 84 //newtxpool创建新的轻型事务池 85 func NewTxPool(config *params.ChainConfig, chain *LightChain, relay TxRelayBackend) *TxPool { 86 pool := &TxPool{ 87 config: config, 88 signer: types.NewEIP155Signer(config.ChainID), 89 nonce: make(map[common.Address]uint64), 90 pending: make(map[common.Hash]*types.Transaction), 91 mined: make(map[common.Hash][]*types.Transaction), 92 quit: make(chan bool), 93 chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), 94 chain: chain, 95 relay: relay, 96 odr: chain.Odr(), 97 chainDb: chain.Odr().Database(), 98 head: chain.CurrentHeader().Hash(), 99 clearIdx: chain.CurrentHeader().Number.Uint64(), 100 } 101 //从区块链订阅事件 102 pool.chainHeadSub = pool.chain.SubscribeChainHeadEvent(pool.chainHeadCh) 103 go pool.eventLoop() 104 105 return pool 106 } 107 108 //currentState返回当前头段的灯状态 109 func (pool *TxPool) currentState(ctx context.Context) *state.StateDB { 110 return NewState(ctx, pool.chain.CurrentHeader(), pool.odr) 111 } 112 113 //getnonce返回给定地址的“挂起”nonce。它总是询问 114 //也属于最新标题的nonce,以便检测是否有其他标题 115 //使用相同密钥的客户端发送了一个事务。 116 func (pool *TxPool) GetNonce(ctx context.Context, addr common.Address) (uint64, error) { 117 state := pool.currentState(ctx) 118 nonce := state.GetNonce(addr) 119 if state.Error() != nil { 120 return 0, state.Error() 121 } 122 sn, ok := pool.nonce[addr] 123 if ok && sn > nonce { 124 nonce = sn 125 } 126 if !ok || sn < nonce { 127 pool.nonce[addr] = nonce 128 } 129 return nonce, nil 130 } 131 132 //TxStateChanges存储的挂起/挖掘状态之间的最近更改 133 //交易。“真”表示已开采,“假”表示已回退,“不进入”表示无变化。 134 type txStateChanges map[common.Hash]bool 135 136 //setState将Tx的状态设置为“最近开采”或“最近回滚” 137 func (txc txStateChanges) setState(txHash common.Hash, mined bool) { 138 val, ent := txc[txHash] 139 if ent && (val != mined) { 140 delete(txc, txHash) 141 } else { 142 txc[txHash] = mined 143 } 144 } 145 146 //GetLists创建挖掘和回滚的Tx哈希列表 147 func (txc txStateChanges) getLists() (mined []common.Hash, rollback []common.Hash) { 148 for hash, val := range txc { 149 if val { 150 mined = append(mined, hash) 151 } else { 152 rollback = append(rollback, hash) 153 } 154 } 155 return 156 } 157 158 //checkminedTxs为当前挂起的事务检查新添加的块 159 //必要时标记为已开采。它还将块位置存储在数据库中 160 //并将它们添加到接收到的txtStateChanges映射中。 161 func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, number uint64, txc txStateChanges) error { 162 //如果没有交易悬而未决,我们什么都不在乎 163 if len(pool.pending) == 0 { 164 return nil 165 } 166 block, err := GetBlock(ctx, pool.odr, hash, number) 167 if err != nil { 168 return err 169 } 170 //收集在此块中挖掘的所有本地事务 171 list := pool.mined[hash] 172 for _, tx := range block.Transactions() { 173 if _, ok := pool.pending[tx.Hash()]; ok { 174 list = append(list, tx) 175 } 176 } 177 //如果挖掘了某些事务,请将所需数据写入磁盘并更新 178 if list != nil { 179 //检索属于此块的所有收据并写入循环表 180 if _, err := GetBlockReceipts(ctx, pool.odr, hash, number); err != nil { //ODR缓存,忽略结果 181 return err 182 } 183 rawdb.WriteTxLookupEntries(pool.chainDb, block) 184 185 //更新事务池的状态 186 for _, tx := range list { 187 delete(pool.pending, tx.Hash()) 188 txc.setState(tx.Hash(), true) 189 } 190 pool.mined[hash] = list 191 } 192 return nil 193 } 194 195 //RollbackTXS标记最近回滚块中包含的事务 196 //像卷回一样。它还删除任何位置查找条目。 197 func (pool *TxPool) rollbackTxs(hash common.Hash, txc txStateChanges) { 198 batch := pool.chainDb.NewBatch() 199 if list, ok := pool.mined[hash]; ok { 200 for _, tx := range list { 201 txHash := tx.Hash() 202 rawdb.DeleteTxLookupEntry(batch, txHash) 203 pool.pending[txHash] = tx 204 txc.setState(txHash, false) 205 } 206 delete(pool.mined, hash) 207 } 208 batch.Write() 209 } 210 211 //重新定位new head设置新的head header,处理(必要时回滚) 212 //从上一个已知头开始的块,并返回包含 213 //最近挖掘和回滚的事务哈希。如果出现错误(上下文 214 //超时)在检查新块时发生,它离开本地已知的头 215 //在最近选中的块上,仍然返回有效的txtStateChanges,使其 216 //可以在下一个链头事件中继续检查丢失的块 217 func (pool *TxPool) reorgOnNewHead(ctx context.Context, newHeader *types.Header) (txStateChanges, error) { 218 txc := make(txStateChanges) 219 oldh := pool.chain.GetHeaderByHash(pool.head) 220 newh := newHeader 221 //查找公共祖先,创建回滚和新块哈希的列表 222 var oldHashes, newHashes []common.Hash 223 for oldh.Hash() != newh.Hash() { 224 if oldh.Number.Uint64() >= newh.Number.Uint64() { 225 oldHashes = append(oldHashes, oldh.Hash()) 226 oldh = pool.chain.GetHeader(oldh.ParentHash, oldh.Number.Uint64()-1) 227 } 228 if oldh.Number.Uint64() < newh.Number.Uint64() { 229 newHashes = append(newHashes, newh.Hash()) 230 newh = pool.chain.GetHeader(newh.ParentHash, newh.Number.Uint64()-1) 231 if newh == nil { 232 //当CHT同步时发生,无需执行任何操作 233 newh = oldh 234 } 235 } 236 } 237 if oldh.Number.Uint64() < pool.clearIdx { 238 pool.clearIdx = oldh.Number.Uint64() 239 } 240 //回滚旧块 241 for _, hash := range oldHashes { 242 pool.rollbackTxs(hash, txc) 243 } 244 pool.head = oldh.Hash() 245 //检查新块的挖掘Txs(数组顺序相反) 246 for i := len(newHashes) - 1; i >= 0; i-- { 247 hash := newHashes[i] 248 if err := pool.checkMinedTxs(ctx, hash, newHeader.Number.Uint64()-uint64(i), txc); err != nil { 249 return txc, err 250 } 251 pool.head = hash 252 } 253 254 //清除旧块的旧挖掘Tx条目 255 if idx := newHeader.Number.Uint64(); idx > pool.clearIdx+txPermanent { 256 idx2 := idx - txPermanent 257 if len(pool.mined) > 0 { 258 for i := pool.clearIdx; i < idx2; i++ { 259 hash := rawdb.ReadCanonicalHash(pool.chainDb, i) 260 if list, ok := pool.mined[hash]; ok { 261 hashes := make([]common.Hash, len(list)) 262 for i, tx := range list { 263 hashes[i] = tx.Hash() 264 } 265 pool.relay.Discard(hashes) 266 delete(pool.mined, hash) 267 } 268 } 269 } 270 pool.clearIdx = idx2 271 } 272 273 return txc, nil 274 } 275 276 //BlockCheckTimeout是检查挖掘的新块的时间限制 277 //交易。如果超时,则在下一个链头事件时检查恢复。 278 const blockCheckTimeout = time.Second * 3 279 280 //EventLoop处理链头事件并通知Tx中继后端 281 //关于新头哈希和Tx状态更改 282 func (pool *TxPool) eventLoop() { 283 for { 284 select { 285 case ev := <-pool.chainHeadCh: 286 pool.setNewHead(ev.Block.Header()) 287 //为了避免锁被霸占,这部分会 288 //替换为后续的pr。 289 time.Sleep(time.Millisecond) 290 291 //系统停止 292 case <-pool.chainHeadSub.Err(): 293 return 294 } 295 } 296 } 297 298 func (pool *TxPool) setNewHead(head *types.Header) { 299 pool.mu.Lock() 300 defer pool.mu.Unlock() 301 302 ctx, cancel := context.WithTimeout(context.Background(), blockCheckTimeout) 303 defer cancel() 304 305 txc, _ := pool.reorgOnNewHead(ctx, head) 306 m, r := txc.getLists() 307 pool.relay.NewHead(pool.head, m, r) 308 pool.homestead = pool.config.IsHomestead(head.Number) 309 pool.signer = types.MakeSigner(pool.config, head.Number) 310 } 311 312 //停止停止轻型事务处理池 313 func (pool *TxPool) Stop() { 314 //取消订阅从txpool注册的所有订阅 315 pool.scope.Close() 316 //取消订阅从区块链注册的订阅 317 pool.chainHeadSub.Unsubscribe() 318 close(pool.quit) 319 log.Info("Transaction pool stopped") 320 } 321 322 //subscripeWtxEvent注册core.newtxSevent和的订阅 323 //开始向给定通道发送事件。 324 func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { 325 return pool.scope.Track(pool.txFeed.Subscribe(ch)) 326 } 327 328 //stats返回当前挂起(本地创建)的事务数 329 func (pool *TxPool) Stats() (pending int) { 330 pool.mu.RLock() 331 defer pool.mu.RUnlock() 332 333 pending = len(pool.pending) 334 return 335 } 336 337 //validatetx根据共识规则检查交易是否有效。 338 func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error { 339 //验证发送器 340 var ( 341 from common.Address 342 err error 343 ) 344 345 //验证事务发送方及其SIG。投掷 346 //如果“发件人”字段无效。 347 if from, err = types.Sender(pool.signer, tx); err != nil { 348 return core.ErrInvalidSender 349 } 350 //最后但不是最不重要的检查非关键错误 351 currentState := pool.currentState(ctx) 352 if n := currentState.GetNonce(from); n > tx.Nonce() { 353 return core.ErrNonceTooLow 354 } 355 356 //检查交易不超过当前 357 //阻塞限制气体。 358 header := pool.chain.GetHeaderByHash(pool.head) 359 if header.GasLimit < tx.Gas() { 360 return core.ErrGasLimit 361 } 362 363 //交易记录不能为负数。这可能永远不会发生 364 //使用RLP解码的事务,但如果创建 365 //例如,使用RPC的事务。 366 if tx.Value().Sign() < 0 { 367 return core.ErrNegativeValue 368 } 369 370 //交易人应该有足够的资金来支付费用。 371 //成本==V+gp*gl 372 if b := currentState.GetBalance(from); b.Cmp(tx.Cost()) < 0 { 373 return core.ErrInsufficientFunds 374 } 375 376 //应提供足够的固有气体 377 gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) 378 if err != nil { 379 return err 380 } 381 if tx.Gas() < gas { 382 return core.ErrIntrinsicGas 383 } 384 return currentState.Error() 385 } 386 387 //添加将验证新事务,并将其状态设置为挂起(如果可处理)。 388 //如果需要,它还会更新本地存储的nonce。 389 func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error { 390 hash := tx.Hash() 391 392 if self.pending[hash] != nil { 393 return fmt.Errorf("Known transaction (%x)", hash[:4]) 394 } 395 err := self.validateTx(ctx, tx) 396 if err != nil { 397 return err 398 } 399 400 if _, ok := self.pending[hash]; !ok { 401 self.pending[hash] = tx 402 403 nonce := tx.Nonce() + 1 404 405 addr, _ := types.Sender(self.signer, tx) 406 if nonce > self.nonce[addr] { 407 self.nonce[addr] = nonce 408 } 409 410 //通知订户。此事件在Goroutine中发布 411 //因为在“删除事务”后的某个位置 412 //调用,然后等待全局Tx池锁定和死锁。 413 go self.txFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}}) 414 } 415 416 //如果设置了足够低的级别,则打印日志消息 417 log.Debug("Pooled new transaction", "hash", hash, "from", log.Lazy{Fn: func() common.Address { from, _ := types.Sender(self.signer, tx); return from }}, "to", tx.To()) 418 return nil 419 } 420 421 //添加将事务添加到池中(如果有效)并将其传递到Tx中继 422 //后端 423 func (self *TxPool) Add(ctx context.Context, tx *types.Transaction) error { 424 self.mu.Lock() 425 defer self.mu.Unlock() 426 427 data, err := rlp.EncodeToBytes(tx) 428 if err != nil { 429 return err 430 } 431 432 if err := self.add(ctx, tx); err != nil { 433 return err 434 } 435 //fmt.println(“发送”,tx.hash()) 436 self.relay.Send(types.Transactions{tx}) 437 438 self.chainDb.Put(tx.Hash().Bytes(), data) 439 return nil 440 } 441 442 //addTransactions将所有有效事务添加到池中,并将它们传递给 443 //Tx中继后端 444 func (self *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) { 445 self.mu.Lock() 446 defer self.mu.Unlock() 447 var sendTx types.Transactions 448 449 for _, tx := range txs { 450 if err := self.add(ctx, tx); err == nil { 451 sendTx = append(sendTx, tx) 452 } 453 } 454 if len(sendTx) > 0 { 455 self.relay.Send(sendTx) 456 } 457 } 458 459 //GetTransaction返回包含在池中的事务 460 //否则为零。 461 func (tp *TxPool) GetTransaction(hash common.Hash) *types.Transaction { 462 //先检查TXS 463 if tx, ok := tp.pending[hash]; ok { 464 return tx 465 } 466 return nil 467 } 468 469 //GetTransactions返回所有当前可处理的事务。 470 //调用程序可以修改返回的切片。 471 func (self *TxPool) GetTransactions() (txs types.Transactions, err error) { 472 self.mu.RLock() 473 defer self.mu.RUnlock() 474 475 txs = make(types.Transactions, len(self.pending)) 476 i := 0 477 for _, tx := range self.pending { 478 txs[i] = tx 479 i++ 480 } 481 return txs, nil 482 } 483 484 //Content检索事务池的数据内容,并返回 485 //挂起和排队的事务,按帐户和nonce分组。 486 func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { 487 self.mu.RLock() 488 defer self.mu.RUnlock() 489 490 //检索所有挂起的事务,并按帐户和当前排序 491 pending := make(map[common.Address]types.Transactions) 492 for _, tx := range self.pending { 493 account, _ := types.Sender(self.signer, tx) 494 pending[account] = append(pending[account], tx) 495 } 496 //光池中没有排队的事务,只返回一个空映射 497 queued := make(map[common.Address]types.Transactions) 498 return pending, queued 499 } 500 501 //removeTransactions从池中删除所有给定的事务。 502 func (self *TxPool) RemoveTransactions(txs types.Transactions) { 503 self.mu.Lock() 504 defer self.mu.Unlock() 505 506 var hashes []common.Hash 507 batch := self.chainDb.NewBatch() 508 for _, tx := range txs { 509 hash := tx.Hash() 510 delete(self.pending, hash) 511 batch.Delete(hash.Bytes()) 512 hashes = append(hashes, hash) 513 } 514 batch.Write() 515 self.relay.Discard(hashes) 516 } 517 518 //removetx从池中删除具有给定哈希的事务。 519 func (pool *TxPool) RemoveTx(hash common.Hash) { 520 pool.mu.Lock() 521 defer pool.mu.Unlock() 522 //从挂起池中删除 523 delete(pool.pending, hash) 524 pool.chainDb.Delete(hash[:]) 525 pool.relay.Discard([]common.Hash{hash}) 526 } 527