github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/core/tx_pool.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2014 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package core 26 27 import ( 28 "errors" 29 "fmt" 30 "math" 31 "math/big" 32 "sort" 33 "sync" 34 "time" 35 36 "github.com/ethereum/go-ethereum/common" 37 "github.com/ethereum/go-ethereum/core/state" 38 "github.com/ethereum/go-ethereum/core/types" 39 "github.com/ethereum/go-ethereum/event" 40 "github.com/ethereum/go-ethereum/log" 41 "github.com/ethereum/go-ethereum/metrics" 42 "github.com/ethereum/go-ethereum/params" 43 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 44 ) 45 46 const ( 47 //ChainHeadChansize是侦听ChainHeadEvent的通道的大小。 48 chainHeadChanSize = 10 49 ) 50 51 var ( 52 //如果事务包含无效签名,则返回errInvalidSender。 53 ErrInvalidSender = errors.New("invalid sender") 54 55 //如果事务的nonce低于 56 //一个存在于本地链中。 57 ErrNonceTooLow = errors.New("nonce too low") 58 59 //如果交易的天然气价格低于最低价格,则返回定价错误。 60 //为事务池配置。 61 ErrUnderpriced = errors.New("transaction underpriced") 62 63 //如果试图替换事务,则返回erreplaceCunderpriced 64 //另一个没有要求的价格上涨。 65 ErrReplaceUnderpriced = errors.New("replacement transaction underpriced") 66 67 //如果执行事务的总成本为 68 //高于用户帐户的余额。 69 ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value") 70 71 //如果交易指定使用更少的气体,则返回errintrinsicgas 72 //启动调用所需的。 73 ErrIntrinsicGas = errors.New("intrinsic gas too low") 74 75 //如果交易请求的气体限制超过 76 //当前块的最大允许量。 77 ErrGasLimit = errors.New("exceeds block gas limit") 78 79 //errNegativeValue是一个健全的错误,用于确保没有人能够指定 80 //负值的交易记录。 81 ErrNegativeValue = errors.New("negative value") 82 83 //如果事务的输入数据大于 84 //而不是用户可能使用的一些有意义的限制。这不是共识错误 85 //使事务无效,而不是DoS保护。 86 ErrOversizedData = errors.New("oversized data") 87 ) 88 89 var ( 90 evictionInterval = time.Minute //检查可收回事务的时间间隔 91 statsReportInterval = 8 * time.Second //报告事务池统计的时间间隔 92 ) 93 94 var ( 95 //挂起池的指标 96 pendingDiscardCounter = metrics.NewRegisteredCounter("txpool/pending/discard", nil) 97 pendingReplaceCounter = metrics.NewRegisteredCounter("txpool/pending/replace", nil) 98 pendingRateLimitCounter = metrics.NewRegisteredCounter("txpool/pending/ratelimit", nil) //由于速率限制而下降 99 pendingNofundsCounter = metrics.NewRegisteredCounter("txpool/pending/nofunds", nil) //因资金不足而放弃 100 101 //排队池的指标 102 queuedDiscardCounter = metrics.NewRegisteredCounter("txpool/queued/discard", nil) 103 queuedReplaceCounter = metrics.NewRegisteredCounter("txpool/queued/replace", nil) 104 queuedRateLimitCounter = metrics.NewRegisteredCounter("txpool/queued/ratelimit", nil) //由于速率限制而下降 105 queuedNofundsCounter = metrics.NewRegisteredCounter("txpool/queued/nofunds", nil) //因资金不足而放弃 106 107 //一般Tx指标 108 invalidTxCounter = metrics.NewRegisteredCounter("txpool/invalid", nil) 109 underpricedTxCounter = metrics.NewRegisteredCounter("txpool/underpriced", nil) 110 ) 111 112 //txstatus是由池看到的事务的当前状态。 113 type TxStatus uint 114 115 const ( 116 TxStatusUnknown TxStatus = iota 117 TxStatusQueued 118 TxStatusPending 119 TxStatusIncluded 120 ) 121 122 //区块链提供区块链的状态和当前的天然气限制。 123 //Tx池和事件订阅服务器中的一些预检查。 124 type blockChain interface { 125 CurrentBlock() *types.Block 126 GetBlock(hash common.Hash, number uint64) *types.Block 127 StateAt(root common.Hash) (*state.StateDB, error) 128 129 SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription 130 } 131 132 //TxPoolConfig是事务池的配置参数。 133 type TxPoolConfig struct { 134 Locals []common.Address //默认情况下应视为本地地址的地址 135 NoLocals bool //是否应禁用本地事务处理 136 Journal string //在节点重新启动后幸存的本地事务日志 137 Rejournal time.Duration //重新生成本地事务日记帐的时间间隔 138 139 PriceLimit uint64 //用于验收的最低天然气价格 140 PriceBump uint64 //替换已存在交易的最低价格波动百分比(nonce) 141 142 AccountSlots uint64 //每个帐户保证的可执行事务槽数 143 GlobalSlots uint64 //所有帐户的最大可执行事务槽数 144 AccountQueue uint64 //每个帐户允许的最大不可执行事务槽数 145 GlobalQueue uint64 //所有帐户的最大不可执行事务槽数 146 147 Lifetime time.Duration //非可执行事务排队的最长时间 148 } 149 150 //DefaultTxPoolConfig包含事务的默认配置 151 //池。 152 var DefaultTxPoolConfig = TxPoolConfig{ 153 Journal: "transactions.rlp", 154 Rejournal: time.Hour, 155 156 PriceLimit: 1, 157 PriceBump: 10, 158 159 AccountSlots: 16, 160 GlobalSlots: 4096, 161 AccountQueue: 64, 162 GlobalQueue: 1024, 163 164 Lifetime: 3 * time.Hour, 165 } 166 167 //清理检查提供的用户配置并更改 168 //不合理或不可行。 169 func (config *TxPoolConfig) sanitize() TxPoolConfig { 170 conf := *config 171 if conf.Rejournal < time.Second { 172 log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) 173 conf.Rejournal = time.Second 174 } 175 if conf.PriceLimit < 1 { 176 log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit) 177 conf.PriceLimit = DefaultTxPoolConfig.PriceLimit 178 } 179 if conf.PriceBump < 1 { 180 log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump) 181 conf.PriceBump = DefaultTxPoolConfig.PriceBump 182 } 183 return conf 184 } 185 186 //TxPool包含所有当前已知的事务。交易 187 //从网络接收或提交时输入池 188 //局部地。当它们包含在区块链中时,它们退出池。 189 // 190 //池将可处理的事务(可应用于 191 //当前状态)和未来交易。事务在这些事务之间移动 192 //两种状态随着时间的推移而被接收和处理。 193 type TxPool struct { 194 config TxPoolConfig 195 chainconfig *params.ChainConfig 196 chain blockChain 197 gasPrice *big.Int 198 txFeed event.Feed 199 scope event.SubscriptionScope 200 chainHeadCh chan ChainHeadEvent 201 chainHeadSub event.Subscription 202 signer types.Signer 203 mu sync.RWMutex 204 205 currentState *state.StateDB //区块链头中的当前状态 206 pendingState *state.ManagedState //挂起状态跟踪虚拟当前 207 currentMaxGas uint64 //交易上限的当前天然气限额 208 209 locals *accountSet //要免除逐出规则的本地事务集 210 journal *txJournal //备份到磁盘的本地事务日志 211 212 pending map[common.Address]*txList //所有当前可处理的事务 213 queue map[common.Address]*txList //排队但不可处理的事务 214 beats map[common.Address]time.Time //每个已知帐户的最后一个心跳 215 all *txLookup //允许查找的所有事务 216 priced *txPricedList //按价格排序的所有交易记录 217 218 wg sync.WaitGroup //用于关机同步 219 220 homestead bool 221 } 222 223 //newtxpool创建一个新的事务池来收集、排序和筛选入站事务 224 //来自网络的事务。 225 func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain) *TxPool { 226 //对输入进行消毒,以确保不设定脆弱的天然气价格。 227 config = (&config).sanitize() 228 229 //使用事务池的初始设置创建事务池 230 pool := &TxPool{ 231 config: config, 232 chainconfig: chainconfig, 233 chain: chain, 234 signer: types.NewEIP155Signer(chainconfig.ChainID), 235 pending: make(map[common.Address]*txList), 236 queue: make(map[common.Address]*txList), 237 beats: make(map[common.Address]time.Time), 238 all: newTxLookup(), 239 chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), 240 gasPrice: new(big.Int).SetUint64(config.PriceLimit), 241 } 242 pool.locals = newAccountSet(pool.signer) 243 for _, addr := range config.Locals { 244 log.Info("Setting new local account", "address", addr) 245 pool.locals.add(addr) 246 } 247 pool.priced = newTxPricedList(pool.all) 248 pool.reset(nil, chain.CurrentBlock().Header()) 249 250 //如果启用了本地事务和日记,则从磁盘加载 251 if !config.NoLocals && config.Journal != "" { 252 pool.journal = newTxJournal(config.Journal) 253 254 if err := pool.journal.load(pool.AddLocals); err != nil { 255 log.Warn("Failed to load transaction journal", "err", err) 256 } 257 if err := pool.journal.rotate(pool.local()); err != nil { 258 log.Warn("Failed to rotate transaction journal", "err", err) 259 } 260 } 261 //从区块链订阅事件 262 pool.chainHeadSub = pool.chain.SubscribeChainHeadEvent(pool.chainHeadCh) 263 264 //启动事件循环并返回 265 pool.wg.Add(1) 266 go pool.loop() 267 268 return pool 269 } 270 271 //循环是事务池的主事件循环,等待并响应 272 //外部区块链事件以及各种报告和交易 273 //驱逐事件。 274 func (pool *TxPool) loop() { 275 defer pool.wg.Done() 276 277 //启动统计报告和事务逐出标记 278 var prevPending, prevQueued, prevStales int 279 280 report := time.NewTicker(statsReportInterval) 281 defer report.Stop() 282 283 evict := time.NewTicker(evictionInterval) 284 defer evict.Stop() 285 286 journal := time.NewTicker(pool.config.Rejournal) 287 defer journal.Stop() 288 289 //跟踪事务重新排序的前一个标题 290 head := pool.chain.CurrentBlock() 291 292 //持续等待并对各种事件作出反应 293 for { 294 select { 295 //处理ChainHeadEvent 296 case ev := <-pool.chainHeadCh: 297 if ev.Block != nil { 298 pool.mu.Lock() 299 if pool.chainconfig.IsHomestead(ev.Block.Number()) { 300 pool.homestead = true 301 } 302 pool.reset(head.Header(), ev.Block.Header()) 303 head = ev.Block 304 305 pool.mu.Unlock() 306 } 307 //由于系统停止而取消订阅 308 case <-pool.chainHeadSub.Err(): 309 return 310 311 //处理统计报告标记 312 case <-report.C: 313 pool.mu.RLock() 314 pending, queued := pool.stats() 315 stales := pool.priced.stales 316 pool.mu.RUnlock() 317 318 if pending != prevPending || queued != prevQueued || stales != prevStales { 319 log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales) 320 prevPending, prevQueued, prevStales = pending, queued, stales 321 } 322 323 //处理非活动帐户事务收回 324 case <-evict.C: 325 pool.mu.Lock() 326 for addr := range pool.queue { 327 //从逐出机制跳过本地事务 328 if pool.locals.contains(addr) { 329 continue 330 } 331 //任何年龄足够大的非本地人都应该被除名。 332 if time.Since(pool.beats[addr]) > pool.config.Lifetime { 333 for _, tx := range pool.queue[addr].Flatten() { 334 pool.removeTx(tx.Hash(), true) 335 } 336 } 337 } 338 pool.mu.Unlock() 339 340 //处理本地事务日记帐轮换 341 case <-journal.C: 342 if pool.journal != nil { 343 pool.mu.Lock() 344 if err := pool.journal.rotate(pool.local()); err != nil { 345 log.Warn("Failed to rotate local tx journal", "err", err) 346 } 347 pool.mu.Unlock() 348 } 349 } 350 } 351 } 352 353 //LockedReset是一个包装重置,允许在线程安全中调用它。 354 //态度。此方法仅在检测仪中使用! 355 func (pool *TxPool) lockedReset(oldHead, newHead *types.Header) { 356 pool.mu.Lock() 357 defer pool.mu.Unlock() 358 359 pool.reset(oldHead, newHead) 360 } 361 362 //重置检索区块链的当前状态并确保内容 363 //的事务池对于链状态有效。 364 func (pool *TxPool) reset(oldHead, newHead *types.Header) { 365 //如果要重新定位旧状态,请重新拒绝所有已删除的事务 366 var reinject types.Transactions 367 368 if oldHead != nil && oldHead.Hash() != newHead.ParentHash { 369 //如果REORG太深,请避免这样做(将在快速同步期间发生) 370 oldNum := oldHead.Number.Uint64() 371 newNum := newHead.Number.Uint64() 372 373 if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 { 374 log.Debug("Skipping deep transaction reorg", "depth", depth) 375 } else { 376 //REORG看起来很浅,足以将所有事务拉入内存 377 var discarded, included types.Transactions 378 379 var ( 380 rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) 381 add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) 382 ) 383 for rem.NumberU64() > add.NumberU64() { 384 discarded = append(discarded, rem.Transactions()...) 385 if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { 386 log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) 387 return 388 } 389 } 390 for add.NumberU64() > rem.NumberU64() { 391 included = append(included, add.Transactions()...) 392 if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { 393 log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) 394 return 395 } 396 } 397 for rem.Hash() != add.Hash() { 398 discarded = append(discarded, rem.Transactions()...) 399 if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { 400 log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) 401 return 402 } 403 included = append(included, add.Transactions()...) 404 if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { 405 log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) 406 return 407 } 408 } 409 reinject = types.TxDifference(discarded, included) 410 } 411 } 412 //将内部状态初始化为当前头部 413 if newHead == nil { 414 newHead = pool.chain.CurrentBlock().Header() //测试过程中的特殊情况 415 } 416 statedb, err := pool.chain.StateAt(newHead.Root) 417 if err != nil { 418 log.Error("Failed to reset txpool state", "err", err) 419 return 420 } 421 pool.currentState = statedb 422 pool.pendingState = state.ManageState(statedb) 423 pool.currentMaxGas = newHead.GasLimit 424 425 //插入由于重新排序而丢弃的任何事务 426 log.Debug("Reinjecting stale transactions", "count", len(reinject)) 427 senderCacher.recover(pool.signer, reinject) 428 pool.addTxsLocked(reinject, false) 429 430 //验证挂起事务池,这将删除 431 //包含在块中的任何交易或 432 //已因另一个交易(例如 433 //更高的天然气价格) 434 pool.demoteUnexecutables() 435 436 //将所有帐户更新为最新的已知挂起的当前帐户 437 for addr, list := range pool.pending { 438 txs := list.Flatten() //很重,但会被缓存,矿工无论如何都需要它。 439 pool.pendingState.SetNonce(addr, txs[len(txs)-1].Nonce()+1) 440 } 441 //检查队列并尽可能将事务转移到挂起的 442 //或者去掉那些已经失效的 443 pool.promoteExecutables(nil) 444 } 445 446 //stop终止事务池。 447 func (pool *TxPool) Stop() { 448 //取消订阅从txpool注册的所有订阅 449 pool.scope.Close() 450 451 //取消订阅从区块链注册的订阅 452 pool.chainHeadSub.Unsubscribe() 453 pool.wg.Wait() 454 455 if pool.journal != nil { 456 pool.journal.close() 457 } 458 log.Info("Transaction pool stopped") 459 } 460 461 //subscripeWtxsEvent注册newtxSevent和的订阅 462 //开始向给定通道发送事件。 463 func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscription { 464 return pool.scope.Track(pool.txFeed.Subscribe(ch)) 465 } 466 467 //Gasprice返回交易池强制执行的当前天然气价格。 468 func (pool *TxPool) GasPrice() *big.Int { 469 pool.mu.RLock() 470 defer pool.mu.RUnlock() 471 472 return new(big.Int).Set(pool.gasPrice) 473 } 474 475 //setgasprice更新交易池要求的 476 //新事务,并将所有事务降低到此阈值以下。 477 func (pool *TxPool) SetGasPrice(price *big.Int) { 478 pool.mu.Lock() 479 defer pool.mu.Unlock() 480 481 pool.gasPrice = price 482 for _, tx := range pool.priced.Cap(price, pool.locals) { 483 pool.removeTx(tx.Hash(), false) 484 } 485 log.Info("Transaction pool price threshold updated", "price", price) 486 } 487 488 //状态返回事务池的虚拟托管状态。 489 func (pool *TxPool) State() *state.ManagedState { 490 pool.mu.RLock() 491 defer pool.mu.RUnlock() 492 493 return pool.pendingState 494 } 495 496 //stats检索当前池的统计信息,即挂起的数目和 497 //排队(不可执行)的事务数。 498 func (pool *TxPool) Stats() (int, int) { 499 pool.mu.RLock() 500 defer pool.mu.RUnlock() 501 502 return pool.stats() 503 } 504 505 //stats检索当前池的统计信息,即挂起的数目和 506 //排队(不可执行)的事务数。 507 func (pool *TxPool) stats() (int, int) { 508 pending := 0 509 for _, list := range pool.pending { 510 pending += list.Len() 511 } 512 queued := 0 513 for _, list := range pool.queue { 514 queued += list.Len() 515 } 516 return pending, queued 517 } 518 519 //Content检索事务池的数据内容,并返回 520 //挂起的和排队的事务,按帐户分组并按nonce排序。 521 func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { 522 pool.mu.Lock() 523 defer pool.mu.Unlock() 524 525 pending := make(map[common.Address]types.Transactions) 526 for addr, list := range pool.pending { 527 pending[addr] = list.Flatten() 528 } 529 queued := make(map[common.Address]types.Transactions) 530 for addr, list := range pool.queue { 531 queued[addr] = list.Flatten() 532 } 533 return pending, queued 534 } 535 536 //挂起检索所有当前可处理的事务,按来源分组 537 //帐户并按nonce排序。返回的事务集是一个副本,可以 538 //通过调用代码自由修改。 539 func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { 540 pool.mu.Lock() 541 defer pool.mu.Unlock() 542 543 pending := make(map[common.Address]types.Transactions) 544 for addr, list := range pool.pending { 545 pending[addr] = list.Flatten() 546 } 547 return pending, nil 548 } 549 550 //局部变量检索池当前认为是本地的帐户。 551 func (pool *TxPool) Locals() []common.Address { 552 pool.mu.Lock() 553 defer pool.mu.Unlock() 554 555 return pool.locals.flatten() 556 } 557 558 //本地检索所有当前已知的本地事务,按来源分组 559 //帐户并按nonce排序。返回的事务集是一个副本,可以 560 //通过调用代码自由修改。 561 func (pool *TxPool) local() map[common.Address]types.Transactions { 562 txs := make(map[common.Address]types.Transactions) 563 for addr := range pool.locals.accounts { 564 if pending := pool.pending[addr]; pending != nil { 565 txs[addr] = append(txs[addr], pending.Flatten()...) 566 } 567 if queued := pool.queue[addr]; queued != nil { 568 txs[addr] = append(txs[addr], queued.Flatten()...) 569 } 570 } 571 return txs 572 } 573 574 //validatetx根据共识检查交易是否有效 575 //规则并遵守本地节点的一些启发式限制(价格和大小)。 576 func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { 577 //启发式限制,拒绝超过32KB的事务以防止DoS攻击 578 if tx.Size() > 32*1024 { 579 return ErrOversizedData 580 } 581 //交易记录不能为负数。使用RLP解码可能永远不会发生这种情况。 582 //但如果使用RPC创建事务,则可能发生事务。 583 if tx.Value().Sign() < 0 { 584 return ErrNegativeValue 585 } 586 //确保交易不超过当前区块限制天然气。 587 if pool.currentMaxGas < tx.Gas() { 588 return ErrGasLimit 589 } 590 //确保事务签名正确 591 from, err := types.Sender(pool.signer, tx) 592 if err != nil { 593 return ErrInvalidSender 594 } 595 //以我们自己接受的最低天然气价格取消非本地交易 596 local = local || pool.locals.contains(from) //即使事务从网络到达,帐户也可以是本地的 597 if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { 598 return ErrUnderpriced 599 } 600 //确保事务遵循非紧急排序 601 if pool.currentState.GetNonce(from) > tx.Nonce() { 602 return ErrNonceTooLow 603 } 604 //交易人应该有足够的资金来支付费用。 605 //成本==V+gp*gl 606 if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { 607 return ErrInsufficientFunds 608 } 609 intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) 610 if err != nil { 611 return err 612 } 613 if tx.Gas() < intrGas { 614 return ErrIntrinsicGas 615 } 616 return nil 617 } 618 619 //添加验证事务并将其插入到的不可执行队列中 620 //稍后等待提升和执行。如果交易是 621 //一个已挂起或排队的,它将覆盖上一个并返回此 622 //所以外部代码不会毫无用处地调用promote。 623 // 624 //如果新添加的事务标记为本地,则其发送帐户将 625 //白名单,防止任何关联交易退出 626 //由于定价限制而形成的池。 627 func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { 628 //如果事务已经知道,则丢弃它 629 hash := tx.Hash() 630 if pool.all.Get(hash) != nil { 631 log.Trace("Discarding already known transaction", "hash", hash) 632 return false, fmt.Errorf("known transaction: %x", hash) 633 } 634 //如果事务未能通过基本验证,则放弃它 635 if err := pool.validateTx(tx, local); err != nil { 636 log.Trace("Discarding invalid transaction", "hash", hash, "err", err) 637 invalidTxCounter.Inc(1) 638 return false, err 639 } 640 //如果事务池已满,则放弃定价过低的事务 641 if uint64(pool.all.Count()) >= pool.config.GlobalSlots+pool.config.GlobalQueue { 642 //如果新交易定价过低,不要接受 643 if !local && pool.priced.Underpriced(tx, pool.locals) { 644 log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) 645 underpricedTxCounter.Inc(1) 646 return false, ErrUnderpriced 647 } 648 //新的交易比我们糟糕的交易好,给它腾出空间。 649 drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) 650 for _, tx := range drop { 651 log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) 652 underpricedTxCounter.Inc(1) 653 pool.removeTx(tx.Hash(), false) 654 } 655 } 656 //如果事务正在替换已挂起的事务,请直接执行 657 from, _ := types.Sender(pool.signer, tx) //已验证 658 if list := pool.pending[from]; list != nil && list.Overlaps(tx) { 659 //一旦已经挂起,检查是否满足所需的价格上涨 660 inserted, old := list.Add(tx, pool.config.PriceBump) 661 if !inserted { 662 pendingDiscardCounter.Inc(1) 663 return false, ErrReplaceUnderpriced 664 } 665 //新交易更好,替换旧交易 666 if old != nil { 667 pool.all.Remove(old.Hash()) 668 pool.priced.Removed() 669 pendingReplaceCounter.Inc(1) 670 } 671 pool.all.Add(tx) 672 pool.priced.Put(tx) 673 pool.journalTx(from, tx) 674 675 log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) 676 677 //我们直接注入了一个替换事务,通知子系统 678 go pool.txFeed.Send(NewTxsEvent{types.Transactions{tx}}) 679 680 return old != nil, nil 681 } 682 //新事务没有替换挂起的事务,请推入队列 683 replace, err := pool.enqueueTx(hash, tx) 684 if err != nil { 685 return false, err 686 } 687 //标记本地地址和日记帐本地交易记录 688 if local { 689 if !pool.locals.contains(from) { 690 log.Info("Setting new local account", "address", from) 691 pool.locals.add(from) 692 } 693 } 694 pool.journalTx(from, tx) 695 696 log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) 697 return replace, nil 698 } 699 700 //enqueuetx将新事务插入到不可执行的事务队列中。 701 // 702 //注意,此方法假定池锁被保持! 703 func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, error) { 704 //尝试将事务插入将来的队列 705 from, _ := types.Sender(pool.signer, tx) //已验证 706 if pool.queue[from] == nil { 707 pool.queue[from] = newTxList(false) 708 } 709 inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) 710 if !inserted { 711 //旧的交易更好,放弃这个 712 queuedDiscardCounter.Inc(1) 713 return false, ErrReplaceUnderpriced 714 } 715 //放弃任何以前的交易并标记此交易 716 if old != nil { 717 pool.all.Remove(old.Hash()) 718 pool.priced.Removed() 719 queuedReplaceCounter.Inc(1) 720 } 721 if pool.all.Get(hash) == nil { 722 pool.all.Add(tx) 723 pool.priced.Put(tx) 724 } 725 return old != nil, nil 726 } 727 728 //JournalTx将指定的事务添加到本地磁盘日志(如果是) 729 //视为从本地帐户发送。 730 func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { 731 //只有启用了日记帐且事务是本地的 732 if pool.journal == nil || !pool.locals.contains(from) { 733 return 734 } 735 if err := pool.journal.insert(tx); err != nil { 736 log.Warn("Failed to journal local transaction", "err", err) 737 } 738 } 739 740 //promotetx将事务添加到挂起(可处理)的事务列表中 741 //并返回它是插入的还是旧的更好。 742 // 743 //注意,此方法假定池锁被保持! 744 func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { 745 //尝试将事务插入挂起队列 746 if pool.pending[addr] == nil { 747 pool.pending[addr] = newTxList(true) 748 } 749 list := pool.pending[addr] 750 751 inserted, old := list.Add(tx, pool.config.PriceBump) 752 if !inserted { 753 //旧的交易更好,放弃这个 754 pool.all.Remove(hash) 755 pool.priced.Removed() 756 757 pendingDiscardCounter.Inc(1) 758 return false 759 } 760 //否则放弃任何以前的交易并标记此 761 if old != nil { 762 pool.all.Remove(old.Hash()) 763 pool.priced.Removed() 764 765 pendingReplaceCounter.Inc(1) 766 } 767 //故障保护以绕过直接挂起的插入(测试) 768 if pool.all.Get(hash) == nil { 769 pool.all.Add(tx) 770 pool.priced.Put(tx) 771 } 772 //设置潜在的新挂起nonce并通知新tx的任何子系统 773 pool.beats[addr] = time.Now() 774 pool.pendingState.SetNonce(addr, tx.Nonce()+1) 775 776 return true 777 } 778 779 //addlocal将单个事务排入池中(如果该事务有效),标记 780 //同时将发送方作为本地发送方,确保它绕过本地发送方 781 //定价限制。 782 func (pool *TxPool) AddLocal(tx *types.Transaction) error { 783 return pool.addTx(tx, !pool.config.NoLocals) 784 } 785 786 //如果单个事务有效,则addremote将其排入池中。如果 787 //发送方不属于本地跟踪的发送方,完全定价约束将 788 //申请。 789 func (pool *TxPool) AddRemote(tx *types.Transaction) error { 790 return pool.addTx(tx, false) 791 } 792 793 //addlocals将一批事务排队放入池中,如果它们有效, 794 //同时将发送者标记为本地发送者,确保他们四处走动 795 //本地定价限制。 796 func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { 797 return pool.addTxs(txs, !pool.config.NoLocals) 798 } 799 800 //如果一批事务有效,addremotes会将其排队放入池中。 801 //如果发送方不在本地跟踪的发送方中,则完全定价约束 802 //将适用。 803 func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error { 804 return pool.addTxs(txs, false) 805 } 806 807 //addtx将单个事务排队放入池中(如果该事务有效)。 808 func (pool *TxPool) addTx(tx *types.Transaction, local bool) error { 809 pool.mu.Lock() 810 defer pool.mu.Unlock() 811 812 //尝试插入事务并更新任何状态 813 replace, err := pool.add(tx, local) 814 if err != nil { 815 return err 816 } 817 //如果我们添加了一个新事务,运行提升检查并返回 818 if !replace { 819 from, _ := types.Sender(pool.signer, tx) //已验证 820 pool.promoteExecutables([]common.Address{from}) 821 } 822 return nil 823 } 824 825 //如果一批事务有效,addtx将尝试对其进行排队。 826 func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error { 827 pool.mu.Lock() 828 defer pool.mu.Unlock() 829 830 return pool.addTxsLocked(txs, local) 831 } 832 833 //addtxtslocked尝试对一批事务进行排队,如果它们有效, 834 //同时假定事务池锁已被持有。 835 func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) []error { 836 //添加交易批次,跟踪接受的交易 837 dirty := make(map[common.Address]struct{}) 838 errs := make([]error, len(txs)) 839 840 for i, tx := range txs { 841 var replace bool 842 if replace, errs[i] = pool.add(tx, local); errs[i] == nil && !replace { 843 from, _ := types.Sender(pool.signer, tx) //已验证 844 dirty[from] = struct{}{} 845 } 846 } 847 //仅当实际添加了某些内容时才重新处理内部状态 848 if len(dirty) > 0 { 849 addrs := make([]common.Address, 0, len(dirty)) 850 for addr := range dirty { 851 addrs = append(addrs, addr) 852 } 853 pool.promoteExecutables(addrs) 854 } 855 return errs 856 } 857 858 //status返回一批事务的状态(未知/挂起/排队) 859 //通过散列标识。 860 func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { 861 pool.mu.RLock() 862 defer pool.mu.RUnlock() 863 864 status := make([]TxStatus, len(hashes)) 865 for i, hash := range hashes { 866 if tx := pool.all.Get(hash); tx != nil { 867 from, _ := types.Sender(pool.signer, tx) //已验证 868 if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil { 869 status[i] = TxStatusPending 870 } else { 871 status[i] = TxStatusQueued 872 } 873 } 874 } 875 return status 876 } 877 878 //get返回包含在池中的事务 879 //否则为零。 880 func (pool *TxPool) Get(hash common.Hash) *types.Transaction { 881 return pool.all.Get(hash) 882 } 883 884 //removetx从队列中删除单个事务,移动所有后续事务 885 //事务返回到未来队列。 886 func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { 887 //获取我们要删除的事务 888 tx := pool.all.Get(hash) 889 if tx == nil { 890 return 891 } 892 addr, _ := types.Sender(pool.signer, tx) //已在插入过程中验证 893 894 //将其从已知事务列表中删除 895 pool.all.Remove(hash) 896 if outofbound { 897 pool.priced.Removed() 898 } 899 //从挂起列表中删除该事务并立即重置帐户 900 if pending := pool.pending[addr]; pending != nil { 901 if removed, invalids := pending.Remove(tx); removed { 902 //如果没有剩余的挂起事务,请删除该列表 903 if pending.Empty() { 904 delete(pool.pending, addr) 905 delete(pool.beats, addr) 906 } 907 //推迟任何失效的交易 908 for _, tx := range invalids { 909 pool.enqueueTx(tx.Hash(), tx) 910 } 911 //如果需要,立即更新帐户 912 if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { 913 pool.pendingState.SetNonce(addr, nonce) 914 } 915 return 916 } 917 } 918 //事务在将来的队列中 919 if future := pool.queue[addr]; future != nil { 920 future.Remove(tx) 921 if future.Empty() { 922 delete(pool.queue, addr) 923 } 924 } 925 } 926 927 //PromoteeExecutables将可从 928 //对一组挂起事务的未来队列。在此过程中,所有 929 //已删除失效的事务(低nonce、低余额)。 930 func (pool *TxPool) promoteExecutables(accounts []common.Address) { 931 //跟踪已提升的事务以立即广播它们 932 var promoted []*types.Transaction 933 934 //收集所有可能需要更新的帐户 935 if accounts == nil { 936 accounts = make([]common.Address, 0, len(pool.queue)) 937 for addr := range pool.queue { 938 accounts = append(accounts, addr) 939 } 940 } 941 //遍历所有帐户并升级任何可执行事务 942 for _, addr := range accounts { 943 list := pool.queue[addr] 944 if list == nil { 945 continue //以防有人用不存在的帐户打电话 946 } 947 //删除所有被认为太旧的事务(低nonce) 948 for _, tx := range list.Forward(pool.currentState.GetNonce(addr)) { 949 hash := tx.Hash() 950 log.Trace("Removed old queued transaction", "hash", hash) 951 pool.all.Remove(hash) 952 pool.priced.Removed() 953 } 954 //放弃所有成本过高的交易(低余额或无天然气) 955 drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) 956 for _, tx := range drops { 957 hash := tx.Hash() 958 log.Trace("Removed unpayable queued transaction", "hash", hash) 959 pool.all.Remove(hash) 960 pool.priced.Removed() 961 queuedNofundsCounter.Inc(1) 962 } 963 //收集所有可执行事务并升级它们 964 for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) { 965 hash := tx.Hash() 966 if pool.promoteTx(addr, hash, tx) { 967 log.Trace("Promoting queued transaction", "hash", hash) 968 promoted = append(promoted, tx) 969 } 970 } 971 //删除超过允许限制的所有交易记录 972 if !pool.locals.contains(addr) { 973 for _, tx := range list.Cap(int(pool.config.AccountQueue)) { 974 hash := tx.Hash() 975 pool.all.Remove(hash) 976 pool.priced.Removed() 977 queuedRateLimitCounter.Inc(1) 978 log.Trace("Removed cap-exceeding queued transaction", "hash", hash) 979 } 980 } 981 //如果整个队列条目变为空,则将其删除。 982 if list.Empty() { 983 delete(pool.queue, addr) 984 } 985 } 986 //为新升级的事务通知子系统。 987 if len(promoted) > 0 { 988 go pool.txFeed.Send(NewTxsEvent{promoted}) 989 } 990 //如果待定限额溢出,开始均衡限额 991 pending := uint64(0) 992 for _, list := range pool.pending { 993 pending += uint64(list.Len()) 994 } 995 if pending > pool.config.GlobalSlots { 996 pendingBeforeCap := pending 997 //首先收集一个垃圾邮件命令来惩罚大型交易对手 998 spammers := prque.New() 999 for addr, list := range pool.pending { 1000 //仅从高收入者逐出交易 1001 if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { 1002 spammers.Push(addr, float32(list.Len())) 1003 } 1004 } 1005 //逐步取消罪犯的交易 1006 offenders := []common.Address{} 1007 for pending > pool.config.GlobalSlots && !spammers.Empty() { 1008 //如果不是本地地址,则检索下一个罪犯 1009 offender, _ := spammers.Pop() 1010 offenders = append(offenders, offender.(common.Address)) 1011 1012 //平衡平衡直到所有相同或低于阈值 1013 if len(offenders) > 1 { 1014 //计算当前所有罪犯的均衡阈值 1015 threshold := pool.pending[offender.(common.Address)].Len() 1016 1017 //反复减少所有违规者,直至达到限额或阈值以下。 1018 for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { 1019 for i := 0; i < len(offenders)-1; i++ { 1020 list := pool.pending[offenders[i]] 1021 for _, tx := range list.Cap(list.Len() - 1) { 1022 //也从全局池中删除事务 1023 hash := tx.Hash() 1024 pool.all.Remove(hash) 1025 pool.priced.Removed() 1026 1027 //将当前帐户更新为删除的交易记录 1028 if nonce := tx.Nonce(); pool.pendingState.GetNonce(offenders[i]) > nonce { 1029 pool.pendingState.SetNonce(offenders[i], nonce) 1030 } 1031 log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) 1032 } 1033 pending-- 1034 } 1035 } 1036 } 1037 } 1038 //如果仍高于临界值,则降低至极限或最小允许值 1039 if pending > pool.config.GlobalSlots && len(offenders) > 0 { 1040 for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots { 1041 for _, addr := range offenders { 1042 list := pool.pending[addr] 1043 for _, tx := range list.Cap(list.Len() - 1) { 1044 //也从全局池中删除事务 1045 hash := tx.Hash() 1046 pool.all.Remove(hash) 1047 pool.priced.Removed() 1048 1049 //将当前帐户更新为删除的交易记录 1050 if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { 1051 pool.pendingState.SetNonce(addr, nonce) 1052 } 1053 log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) 1054 } 1055 pending-- 1056 } 1057 } 1058 } 1059 pendingRateLimitCounter.Inc(int64(pendingBeforeCap - pending)) 1060 } 1061 //如果排队的事务超过了硬限制,请删除最旧的事务。 1062 queued := uint64(0) 1063 for _, list := range pool.queue { 1064 queued += uint64(list.Len()) 1065 } 1066 if queued > pool.config.GlobalQueue { 1067 //按心跳对所有具有排队事务的帐户排序 1068 addresses := make(addressesByHeartbeat, 0, len(pool.queue)) 1069 for addr := range pool.queue { 1070 if !pool.locals.contains(addr) { //不要删除本地变量 1071 addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) 1072 } 1073 } 1074 sort.Sort(addresses) 1075 1076 //删除事务,直到总数低于限制或只保留局部变量 1077 for drop := queued - pool.config.GlobalQueue; drop > 0 && len(addresses) > 0; { 1078 addr := addresses[len(addresses)-1] 1079 list := pool.queue[addr.address] 1080 1081 addresses = addresses[:len(addresses)-1] 1082 1083 //如果小于溢出,则删除所有事务 1084 if size := uint64(list.Len()); size <= drop { 1085 for _, tx := range list.Flatten() { 1086 pool.removeTx(tx.Hash(), true) 1087 } 1088 drop -= size 1089 queuedRateLimitCounter.Inc(int64(size)) 1090 continue 1091 } 1092 //否则只删除最后几个事务 1093 txs := list.Flatten() 1094 for i := len(txs) - 1; i >= 0 && drop > 0; i-- { 1095 pool.removeTx(txs[i].Hash(), true) 1096 drop-- 1097 queuedRateLimitCounter.Inc(1) 1098 } 1099 } 1100 } 1101 } 1102 1103 //DemoteNextExecutables从池中删除无效和已处理的事务 1104 //可执行/挂起队列以及任何无法执行的后续事务 1105 //将移回将来的队列。 1106 func (pool *TxPool) demoteUnexecutables() { 1107 //迭代所有帐户并降级任何不可执行的事务 1108 for addr, list := range pool.pending { 1109 nonce := pool.currentState.GetNonce(addr) 1110 1111 //删除所有被认为太旧的事务(低nonce) 1112 for _, tx := range list.Forward(nonce) { 1113 hash := tx.Hash() 1114 log.Trace("Removed old pending transaction", "hash", hash) 1115 pool.all.Remove(hash) 1116 pool.priced.Removed() 1117 } 1118 //删除所有成本过高的事务(余额不足或没有汽油),并将任何无效的事务排队等待稍后处理。 1119 drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) 1120 for _, tx := range drops { 1121 hash := tx.Hash() 1122 log.Trace("Removed unpayable pending transaction", "hash", hash) 1123 pool.all.Remove(hash) 1124 pool.priced.Removed() 1125 pendingNofundsCounter.Inc(1) 1126 } 1127 for _, tx := range invalids { 1128 hash := tx.Hash() 1129 log.Trace("Demoting pending transaction", "hash", hash) 1130 pool.enqueueTx(hash, tx) 1131 } 1132 //如果前面有空白,警告(不应该发生)并推迟所有交易 1133 if list.Len() > 0 && list.txs.Get(nonce) == nil { 1134 for _, tx := range list.Cap(0) { 1135 hash := tx.Hash() 1136 log.Error("Demoting invalidated transaction", "hash", hash) 1137 pool.enqueueTx(hash, tx) 1138 } 1139 } 1140 //如果整个队列条目变为空,则将其删除。 1141 if list.Empty() { 1142 delete(pool.pending, addr) 1143 delete(pool.beats, addr) 1144 } 1145 } 1146 } 1147 1148 //AddressByHeartbeat是用其最后一个活动时间戳标记的帐户地址。 1149 type addressByHeartbeat struct { 1150 address common.Address 1151 heartbeat time.Time 1152 } 1153 1154 type addressesByHeartbeat []addressByHeartbeat 1155 1156 func (a addressesByHeartbeat) Len() int { return len(a) } 1157 func (a addressesByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } 1158 func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 1159 1160 //accountset只是检查是否存在的一组地址,以及一个签名者 1161 //能够从交易中获得地址。 1162 type accountSet struct { 1163 accounts map[common.Address]struct{} 1164 signer types.Signer 1165 cache *[]common.Address 1166 } 1167 1168 //newaccountset创建一个新地址集,其中包含发送者的关联签名者 1169 //导子。 1170 func newAccountSet(signer types.Signer) *accountSet { 1171 return &accountSet{ 1172 accounts: make(map[common.Address]struct{}), 1173 signer: signer, 1174 } 1175 } 1176 1177 //包含检查给定地址是否包含在集合中。 1178 func (as *accountSet) contains(addr common.Address) bool { 1179 _, exist := as.accounts[addr] 1180 return exist 1181 } 1182 1183 //containstx检查给定Tx的发送方是否在集合内。如果发送者 1184 //无法派生,此方法返回false。 1185 func (as *accountSet) containsTx(tx *types.Transaction) bool { 1186 if addr, err := types.Sender(as.signer, tx); err == nil { 1187 return as.contains(addr) 1188 } 1189 return false 1190 } 1191 1192 //添加在要跟踪的集合中插入新地址。 1193 func (as *accountSet) add(addr common.Address) { 1194 as.accounts[addr] = struct{}{} 1195 as.cache = nil 1196 } 1197 1198 //flatten返回此集合中的地址列表,并将其缓存以备以后使用 1199 //重新使用。The returned slice should not be changed! 1200 func (as *accountSet) flatten() []common.Address { 1201 if as.cache == nil { 1202 accounts := make([]common.Address, 0, len(as.accounts)) 1203 for account := range as.accounts { 1204 accounts = append(accounts, account) 1205 } 1206 as.cache = &accounts 1207 } 1208 return *as.cache 1209 } 1210 1211 //TXLoopUp在TXPLE内部用于跟踪事务,同时允许查找 1212 //互斥争用。 1213 // 1214 //注意,尽管此类型受到适当的保护,以防并发访问,但它 1215 //是**不是**类型,应该在 1216 //事务池,因为它的内部状态与池紧密耦合 1217 //内部机制。该类型的唯一目的是允许出界 1218 //偷看txpool中的池。无需获取范围广泛的 1219 //txpool.mutex。 1220 type txLookup struct { 1221 all map[common.Hash]*types.Transaction 1222 lock sync.RWMutex 1223 } 1224 1225 //new txlookup返回新的txlookup结构。 1226 func newTxLookup() *txLookup { 1227 return &txLookup{ 1228 all: make(map[common.Hash]*types.Transaction), 1229 } 1230 } 1231 1232 //范围对地图中的每个键和值调用f。 1233 func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction) bool) { 1234 t.lock.RLock() 1235 defer t.lock.RUnlock() 1236 1237 for key, value := range t.all { 1238 if !f(key, value) { 1239 break 1240 } 1241 } 1242 } 1243 1244 //get返回查找中存在的事务,如果未找到则返回nil。 1245 func (t *txLookup) Get(hash common.Hash) *types.Transaction { 1246 t.lock.RLock() 1247 defer t.lock.RUnlock() 1248 1249 return t.all[hash] 1250 } 1251 1252 //count返回查找中的当前项目数。 1253 func (t *txLookup) Count() int { 1254 t.lock.RLock() 1255 defer t.lock.RUnlock() 1256 1257 return len(t.all) 1258 } 1259 1260 //添加将事务添加到查找中。 1261 func (t *txLookup) Add(tx *types.Transaction) { 1262 t.lock.Lock() 1263 defer t.lock.Unlock() 1264 1265 t.all[tx.Hash()] = tx 1266 } 1267 1268 //删除从查找中删除事务。 1269 func (t *txLookup) Remove(hash common.Hash) { 1270 t.lock.Lock() 1271 defer t.lock.Unlock() 1272 1273 delete(t.all, hash) 1274 }