Skip to content

Commit

Permalink
Merge branch 'fix/light-txpool-reorg'
Browse files Browse the repository at this point in the history
  • Loading branch information
meowsbits committed Mar 13, 2020
2 parents cb7bc59 + 687e626 commit 7662eae
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 12 deletions.
6 changes: 6 additions & 0 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ type WhCallback func(*types.Header) error
func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
// Do a sanity check that the provided chain is actually ordered and linked
for i := 1; i < len(chain); i++ {
if chain[i] == nil {
return 0, fmt.Errorf("header was nil")
}
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
// Chain broke ancestry, log a message (programming error) and skip insertion
log.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(),
Expand Down Expand Up @@ -291,6 +294,9 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCa
log.Debug("Premature abort during headers import")
return i, errors.New("aborted")
}
if header == nil {
return i, fmt.Errorf("nil header")
}
// If the header's already known, skip it, otherwise store
hash := header.Hash()
if hc.HasHeader(hash, header.Number.Uint64()) {
Expand Down
19 changes: 18 additions & 1 deletion light/txpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,15 @@ func (pool *TxPool) rollbackTxs(hash common.Hash, txc txStateChanges) {
func (pool *TxPool) reorgOnNewHead(ctx context.Context, newHeader *types.Header) (txStateChanges, error) {
txc := make(txStateChanges)
oldh := pool.chain.GetHeaderByHash(pool.head)
if oldh == nil {
current := pool.chain.CurrentHeader()
if current.Number.Uint64() > 0 {
oldh = pool.chain.GetHeaderByHash(current.ParentHash)
} else {
oldh = current
}
pool.head = oldh.Hash()
}
newh := newHeader
// find common ancestor, create list of rolled back and new block hashes
var oldHashes, newHashes []common.Hash
Expand Down Expand Up @@ -308,7 +317,15 @@ func (pool *TxPool) setNewHead(head *types.Header) {
ctx, cancel := context.WithTimeout(context.Background(), blockCheckTimeout)
defer cancel()

txc, _ := pool.reorgOnNewHead(ctx, head)
if head == nil {
return
}

txc, err := pool.reorgOnNewHead(ctx, head)
if err != nil {
log.Info("light.txpool reorg failed", "error", err)
return
}
m, r := txc.getLists()
pool.relay.NewHead(pool.head, m, r)
pool.eip2f = pool.config.IsEnabled(pool.config.GetEthashEIP2Transition, head.Number)
Expand Down
41 changes: 30 additions & 11 deletions light/txpool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,33 +53,33 @@ func (self *testTxRelay) Discard(hashes []common.Hash) {
self.discard <- len(hashes)
}

const poolTestTxs = 1000
const poolTestBlocks = 100
const poolTestTxsN = 1000
const poolTestBlocksN = 100

// test tx 0..n-1
var testTx [poolTestTxs]*types.Transaction
var testTxSet [poolTestTxsN]*types.Transaction

// txs sent before block i
func sentTx(i int) int {
return int(math.Pow(float64(i)/float64(poolTestBlocks), 0.9) * poolTestTxs)
return int(math.Pow(float64(i)/float64(poolTestBlocksN), 0.9) * poolTestTxsN)
}

// txs included in block i or before that (minedTx(i) <= sentTx(i))
func minedTx(i int) int {
return int(math.Pow(float64(i)/float64(poolTestBlocks), 1.1) * poolTestTxs)
return int(math.Pow(float64(i)/float64(poolTestBlocksN), 1.1) * poolTestTxsN)
}

func txPoolTestChainGen(i int, block *core.BlockGen) {
s := minedTx(i)
e := minedTx(i + 1)
for i := s; i < e; i++ {
block.AddTx(testTx[i])
block.AddTx(testTxSet[i])
}
}

func TestTxPool(t *testing.T) {
for i := range testTx {
testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), vars.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
for i := range testTxSet {
testTxSet[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), vars.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
}

var (
Expand All @@ -91,7 +91,7 @@ func TestTxPool(t *testing.T) {
core.MustCommitGenesis(ldb, &gspec)
// Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil)
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocksN, txPoolTestChainGen)
if _, err := blockchain.InsertChain(gchain); err != nil {
panic(err)
}
Expand All @@ -113,16 +113,35 @@ func TestTxPool(t *testing.T) {
s := sentTx(i - 1)
e := sentTx(i)
for i := s; i < e; i++ {
pool.Add(ctx, testTx[i])
pool.Add(ctx, testTxSet[i])
got := <-relay.send
exp := 1
if got != exp {
t.Errorf("relay.Send expected len = %d, got %d", exp, got)
}
}
if ii == len(gchain)/4 {
// Fuck up pool head
// This is an edge case that I'm not sure could really happen (hopefully not),
// but checking anyways. Call it sanity.
t.Log("Setting pool head to empty hash")
pool.head = common.Hash{}
}

if ii == len(gchain)/2 {
// Attempt to insert a nil header into the headerchain
t.Log("Inserting nil header into header chain")
if _, err := lightchain.InsertHeaderChain([]*types.Header{nil}, 1); err == nil {
t.Fatal("insert nil header error should not be errorless")
}
}
if ii == len(gchain)/4*3 {
var h *types.Header
t.Log("Setting pool head to a nil header", h.Hash().Hex())
pool.setNewHead(h)
}
if _, err := lightchain.InsertHeaderChain([]*types.Header{block.Header()}, 1); err != nil {
panic(err)
t.Fatal(err)
}

got := <-relay.mined
Expand Down

0 comments on commit 7662eae

Please sign in to comment.