aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2016-03-08 01:11:52 +0800
committerJeffrey Wilcke <jeffrey@ethereum.org>2016-03-08 23:12:48 +0800
commitba3fb9e6f4c47edbb0ff99285a0b48dc4bd3f37c (patch)
tree33f5381f85d0ae776bf14dd25141021598df3d6b
parentd45f01d5f782857c6a65f65fdc67b630a8f028bd (diff)
downloaddexon-ba3fb9e6f4c47edbb0ff99285a0b48dc4bd3f37c.tar
dexon-ba3fb9e6f4c47edbb0ff99285a0b48dc4bd3f37c.tar.gz
dexon-ba3fb9e6f4c47edbb0ff99285a0b48dc4bd3f37c.tar.bz2
dexon-ba3fb9e6f4c47edbb0ff99285a0b48dc4bd3f37c.tar.lz
dexon-ba3fb9e6f4c47edbb0ff99285a0b48dc4bd3f37c.tar.xz
dexon-ba3fb9e6f4c47edbb0ff99285a0b48dc4bd3f37c.tar.zst
dexon-ba3fb9e6f4c47edbb0ff99285a0b48dc4bd3f37c.zip
core: announce ChainSideEvent during reorg
Previously all blocks that were already in our chain were never re announced as potential uncle block (e.g. ChainSideEvent). This is problematic during mining where you want to gather as much possible uncles as possible increasing the profit. This is now addressed in this PR where during reorganisations of chains the old chain is regarded as uncles. Fixed #2298
-rw-r--r--core/blockchain.go27
-rw-r--r--core/blockchain_test.go80
2 files changed, 101 insertions, 6 deletions
diff --git a/core/blockchain.go b/core/blockchain.go
index 2c6ff24f9..79648869c 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -1268,12 +1268,14 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// event about them
func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
var (
- newChain types.Blocks
- commonBlock *types.Block
- oldStart = oldBlock
- newStart = newBlock
- deletedTxs types.Transactions
- deletedLogs vm.Logs
+ newChain types.Blocks
+ oldChain types.Blocks
+ commonBlock *types.Block
+ oldStart = oldBlock
+ newStart = newBlock
+ deletedTxs types.Transactions
+ deletedLogs vm.Logs
+ deletedLogsByHash = make(map[common.Hash]vm.Logs)
// collectLogs collects the logs that were generated during the
// processing of the block that corresponds with the given hash.
// 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)
for _, receipt := range receipts {
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() {
// reduce old chain
for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) {
+ oldChain = append(oldChain, oldBlock)
deletedTxs = append(deletedTxs, oldBlock.Transactions()...)
collectLogs(oldBlock.Hash())
@@ -1313,6 +1318,8 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
commonBlock = oldBlock
break
}
+
+ oldChain = append(oldChain, oldBlock)
newChain = append(newChain, newBlock)
deletedTxs = append(deletedTxs, oldBlock.Transactions()...)
collectLogs(oldBlock.Hash())
@@ -1369,6 +1376,14 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
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
}
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 1bb5f646d..a7d3ea56e 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -25,6 +25,7 @@ import (
"runtime"
"strconv"
"testing"
+ "time"
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/common"
@@ -1006,3 +1007,82 @@ func TestLogReorgs(t *testing.T) {
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):
+ }
+
+}