(addTxReq *types.AddTxReq)
| 495 | } |
| 496 | |
| 497 | func (c *Chain) processAddTxReq(addTxReq *types.AddTxReq) { |
| 498 | // Nil check |
| 499 | if addTxReq == nil || addTxReq.Tx == nil { |
| 500 | log.Warn("empty add tx request") |
| 501 | return |
| 502 | } |
| 503 | |
| 504 | var ( |
| 505 | ttl = addTxReq.TTL |
| 506 | tx = addTxReq.Tx |
| 507 | |
| 508 | txhash = tx.Hash() |
| 509 | addr = tx.GetAccountAddress() |
| 510 | nonce = tx.GetAccountNonce() |
| 511 | |
| 512 | le = log.WithFields(log.Fields{ |
| 513 | "hash": txhash.Short(4), |
| 514 | "address": addr, |
| 515 | "nonce": nonce, |
| 516 | "type": tx.GetTransactionType(), |
| 517 | }) |
| 518 | |
| 519 | base pi.AccountNonce |
| 520 | err error |
| 521 | ) |
| 522 | |
| 523 | // Existense check |
| 524 | if ok := func() (ok bool) { |
| 525 | c.RLock() |
| 526 | defer c.RUnlock() |
| 527 | _, ok = c.txPool[txhash] |
| 528 | return |
| 529 | }(); ok { |
| 530 | le.Debug("tx already exists, abort processing") |
| 531 | return |
| 532 | } |
| 533 | |
| 534 | // Verify transaction |
| 535 | if err = tx.Verify(); err != nil { |
| 536 | le.WithError(err).Warn("failed to verify transaction") |
| 537 | return |
| 538 | } |
| 539 | if base, err = c.immutableNextNonce(addr); err != nil { |
| 540 | le.WithError(err).Warn("failed to load base nonce of transaction account") |
| 541 | return |
| 542 | } |
| 543 | if nonce < base || nonce >= base+conf.MaxPendingTxsPerAccount { |
| 544 | // TODO(leventeliu): should persist to somewhere for tx query? |
| 545 | le.WithFields(log.Fields{ |
| 546 | "base_nonce": base, |
| 547 | "pending_limit": conf.MaxPendingTxsPerAccount, |
| 548 | }).Warn("invalid transaction nonce") |
| 549 | return |
| 550 | } |
| 551 | |
| 552 | // Broadcast to other block producers |
| 553 | if ttl > conf.MaxTxBroadcastTTL { |
| 554 | ttl = conf.MaxTxBroadcastTTL |
no test coverage detected