Merge pull request #2301 from obscuren/uncle-fix

core: announce ChainSideEvent during reorg
This commit is contained in:
Jeffrey Wilcke 2016-03-10 14:21:41 +01:00
commit bff9ceb6b8
2 changed files with 101 additions and 6 deletions

View File

@ -1269,11 +1269,13 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
var ( var (
newChain types.Blocks newChain types.Blocks
oldChain types.Blocks
commonBlock *types.Block commonBlock *types.Block
oldStart = oldBlock oldStart = oldBlock
newStart = newBlock newStart = newBlock
deletedTxs types.Transactions deletedTxs types.Transactions
deletedLogs vm.Logs deletedLogs vm.Logs
deletedLogsByHash = make(map[common.Hash]vm.Logs)
// collectLogs collects the logs that were generated during the // collectLogs collects the logs that were generated during the
// processing of the block that corresponds with the given hash. // processing of the block that corresponds with the given hash.
// These logs are later announced as deleted. // These logs are later announced as deleted.
@ -1282,6 +1284,8 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
receipts := GetBlockReceipts(self.chainDb, h) receipts := GetBlockReceipts(self.chainDb, h)
for _, receipt := range receipts { for _, receipt := range receipts {
deletedLogs = append(deletedLogs, receipt.Logs...) deletedLogs = append(deletedLogs, receipt.Logs...)
deletedLogsByHash[h] = receipt.Logs
} }
} }
) )
@ -1290,6 +1294,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
if oldBlock.NumberU64() > newBlock.NumberU64() { if oldBlock.NumberU64() > newBlock.NumberU64() {
// reduce old chain // reduce old chain
for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) { for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) {
oldChain = append(oldChain, oldBlock)
deletedTxs = append(deletedTxs, oldBlock.Transactions()...) deletedTxs = append(deletedTxs, oldBlock.Transactions()...)
collectLogs(oldBlock.Hash()) collectLogs(oldBlock.Hash())
@ -1313,6 +1318,8 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
commonBlock = oldBlock commonBlock = oldBlock
break break
} }
oldChain = append(oldChain, oldBlock)
newChain = append(newChain, newBlock) newChain = append(newChain, newBlock)
deletedTxs = append(deletedTxs, oldBlock.Transactions()...) deletedTxs = append(deletedTxs, oldBlock.Transactions()...)
collectLogs(oldBlock.Hash()) collectLogs(oldBlock.Hash())
@ -1369,6 +1376,14 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
go self.eventMux.Post(RemovedLogsEvent{deletedLogs}) go self.eventMux.Post(RemovedLogsEvent{deletedLogs})
} }
if len(oldChain) > 0 {
go func() {
for _, block := range oldChain {
self.eventMux.Post(ChainSideEvent{Block: block, Logs: deletedLogsByHash[block.Hash()]})
}
}()
}
return nil return nil
} }

View File

@ -25,6 +25,7 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"testing" "testing"
"time"
"github.com/ethereum/ethash" "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -1006,3 +1007,82 @@ func TestLogReorgs(t *testing.T) {
t.Error("expected logs") t.Error("expected logs")
} }
} }
func TestReorgSideEvent(t *testing.T) {
var (
db, _ = ethdb.NewMemDatabase()
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
)
evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, FakePow{}, evmux)
chain, _ := GenerateChain(genesis, db, 3, func(i int, gen *BlockGen) {
if i == 2 {
gen.OffsetTime(9)
}
})
if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert chain: %v", err)
}
replacementBlocks, _ := GenerateChain(genesis, db, 4, func(i int, gen *BlockGen) {
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(key1)
if err != nil {
t.Fatalf("failed to create tx: %v", err)
}
gen.AddTx(tx)
})
subs := evmux.Subscribe(ChainSideEvent{})
if _, err := blockchain.InsertChain(replacementBlocks); err != nil {
t.Fatalf("failed to insert chain: %v", err)
}
// first two block of the secondary chain are for a brief moment considered
// side chains because up to that point the first one is considered the
// heavier chain.
expectedSideHashes := map[common.Hash]bool{
replacementBlocks[0].Hash(): true,
replacementBlocks[1].Hash(): true,
chain[0].Hash(): true,
chain[1].Hash(): true,
chain[2].Hash(): true,
}
i := 0
const timeoutDura = 10 * time.Second
timeout := time.NewTimer(timeoutDura)
done:
for {
select {
case ev := <-subs.Chan():
block := ev.Data.(ChainSideEvent).Block
if _, ok := expectedSideHashes[block.Hash()]; !ok {
t.Errorf("%d: didn't expect %x to be in side chain", i, block.Hash())
}
i++
if i == len(expectedSideHashes) {
timeout.Stop()
break done
}
timeout.Reset(timeoutDura)
case <-timeout.C:
t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent")
}
}
// make sure no more events are fired
select {
case e := <-subs.Chan():
t.Errorf("unexectped event fired: %v", e)
case <-time.After(250 * time.Millisecond):
}
}