fix CalculateTD so shorter forks don't take over

This commit is contained in:
Ethan Buchman 2014-11-22 23:11:04 -05:00
parent d7985fa3b0
commit 6ef0f67b9f
2 changed files with 51 additions and 50 deletions

View file

@ -3,7 +3,7 @@ package chain
import ( import (
"bytes" "bytes"
"container/list" "container/list"
"errors" // "errors"
"fmt" "fmt"
"math/big" "math/big"
"sync" "sync"
@ -266,11 +266,15 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
sm.transState = state.Copy() sm.transState = state.Copy()
// XXX: the only reference to the eth object
// if this could be moved to BlockManager, testing wouldn't require
// the eth object
sm.eth.TxPool().RemoveSet(block.Transactions()) sm.eth.TxPool().RemoveSet(block.Transactions())
return td, messages, nil return td, messages, nil
} else { } else {
return nil, nil, errors.New("total diff failed") // this is a fork, so return the td
return td, nil, nil
} }
} }
@ -288,16 +292,12 @@ func (sm *BlockManager) ApplyDiff(state *state.State, parent, block *types.Block
} }
func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) { func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
uncleDiff := new(big.Int) td, err := sm.bc.CalcTotalDiff(block)
for _, uncle := range block.Uncles { if err != nil {
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) fmt.Println(err)
return nil, false
} }
// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
td := new(big.Int)
td = td.Add(sm.bc.TD, uncleDiff)
td = td.Add(td, block.Difficulty)
// The new TD will only be accepted if the new difficulty is // The new TD will only be accepted if the new difficulty is
// is greater than the previous. // is greater than the previous.
if td.Cmp(sm.bc.TD) > 0 { if td.Cmp(sm.bc.TD) > 0 {
@ -307,7 +307,7 @@ func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
//sm.bc.SetTotalDifficulty(td) //sm.bc.SetTotalDifficulty(td)
} }
return nil, false return td, false
} }
// Validates the current block. Returns an error if the block was invalid, // Validates the current block. Returns an error if the block was invalid,

View file

@ -1,19 +1,19 @@
package chain package chain
import ( import (
"container/list"
"fmt" "fmt"
"math/big" "math/big"
"testing" "testing"
"time" "time"
"container/list"
"github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/chain/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/wire" "github.com/ethereum/go-ethereum/wire"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/crypto"
) )
// In these tests, TD = block.Number // In these tests, TD = block.Number
@ -33,27 +33,28 @@ func (self fakeproc) ProcessWithParent(a, b *types.Block) (*big.Int, state.Messa
} }
// So we can generate blocks easily // So we can generate blocks easily
type fakePow struct {} type fakePow struct{}
func (f fakePow) Search(block *types.Block, stop <-chan struct{}) []byte{return nil}
func (f fakePow) Verify(hash []byte, diff *big.Int, nonce []byte) bool {return true} func (f fakePow) Search(block *types.Block, stop <-chan struct{}) []byte { return nil }
func (f fakePow) GetHashrate() int64 {return 0} func (f fakePow) Verify(hash []byte, diff *big.Int, nonce []byte) bool { return true }
func (f fakePow) Turbo(bool){} func (f fakePow) GetHashrate() int64 { return 0 }
func (f fakePow) Turbo(bool) {}
// We need this guy because ProcessWithParent clears txs from the pool // We need this guy because ProcessWithParent clears txs from the pool
type fakeEth struct{} type fakeEth struct{}
func (e *fakeEth) BlockManager() *BlockManager{ return nil }
func (e *fakeEth) ChainManager() *ChainManager{ return nil }
func (e *fakeEth) TxPool() *TxPool{ return &TxPool{} }
func (e *fakeEth) Broadcast(msgType wire.MsgType, data []interface{}){}
func (e *fakeEth) PeerCount() int {return 0}
func (e *fakeEth) IsMining() bool { return false }
func (e *fakeEth) IsListening() bool { return false }
func (e *fakeEth) Peers() *list.List { return nil }
func (e *fakeEth) KeyManager() *crypto.KeyManager { return nil }
func (e *fakeEth) ClientIdentity() wire.ClientIdentity { return nil }
func (e *fakeEth) Db() ethutil.Database { return nil }
func (e *fakeEth) EventMux() *event.TypeMux { return nil }
func (e *fakeEth) BlockManager() *BlockManager { return nil }
func (e *fakeEth) ChainManager() *ChainManager { return nil }
func (e *fakeEth) TxPool() *TxPool { return &TxPool{} }
func (e *fakeEth) Broadcast(msgType wire.MsgType, data []interface{}) {}
func (e *fakeEth) PeerCount() int { return 0 }
func (e *fakeEth) IsMining() bool { return false }
func (e *fakeEth) IsListening() bool { return false }
func (e *fakeEth) Peers() *list.List { return nil }
func (e *fakeEth) KeyManager() *crypto.KeyManager { return nil }
func (e *fakeEth) ClientIdentity() wire.ClientIdentity { return nil }
func (e *fakeEth) Db() ethutil.Database { return nil }
func (e *fakeEth) EventMux() *event.TypeMux { return nil }
func makechain(cman *ChainManager, max int) *BlockChain { func makechain(cman *ChainManager, max int) *BlockChain {
blocks := make(types.Blocks, max) blocks := make(types.Blocks, max)
@ -69,49 +70,49 @@ func makechain(cman *ChainManager, max int) *BlockChain {
} }
func makechain2(bman *BlockManager, max int) *BlockChain { func makechain2(bman *BlockManager, max int) *BlockChain {
parent := bman.bc.CurrentBlock parent := bman.bc.CurrentBlock
blocks := make(types.Blocks, max) blocks := make(types.Blocks, max)
for i := 0; i < max; i++ { for i := 0; i < max; i++ {
addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20)
block := bman.bc.NewBlock(addr) block := bman.bc.NewBlock(addr)
cbase := block.State().GetOrNewStateObject(addr) cbase := block.State().GetOrNewStateObject(addr)
cbase.SetGasPool(block.CalcGasLimit(parent)) cbase.SetGasPool(block.CalcGasLimit(parent))
receipts, txs, _, _, _ := bman.ProcessTransactions(cbase, block.State(), block, block, types.Transactions{}) receipts, txs, _, _, _ := bman.ProcessTransactions(cbase, block.State(), block, block, types.Transactions{})
block.SetTransactions(txs) block.SetTransactions(txs)
block.SetReceipts(receipts) block.SetReceipts(receipts)
bman.AccumelateRewards(block.State(), block, parent) bman.AccumelateRewards(block.State(), block, parent)
block.State().Update() block.State().Update()
lchain := NewChain(types.Blocks{block}) lchain := NewChain(types.Blocks{block})
_, err := bman.bc.TestChain(lchain) _, err := bman.bc.TestChain(lchain)
if err != nil{ if err != nil {
fmt.Println("failed to run test chain!:", err) fmt.Println("failed to run test chain!:", err)
} }
bman.bc.InsertChain(lchain, func(block *types.Block, _ state.Messages){}) bman.bc.InsertChain(lchain, func(block *types.Block, _ state.Messages) {})
blocks[i] = block blocks[i] = block
parent = block parent = block
} }
return NewChain(blocks) return NewChain(blocks)
} }
func TestShorterFork(t *testing.T) { func TestShorterFork(t *testing.T) {
cman := NewChainManager() cman := NewChainManager()
bman := &BlockManager{bc: cman, Pow: fakePow{}, eth:&fakeEth{}} bman := &BlockManager{bc: cman, Pow: fakePow{}, eth: &fakeEth{}}
bman.bc.SetProcessor(bman) bman.bc.SetProcessor(bman)
makechain2(bman, 5) makechain2(bman, 5)
cman2 := NewChainManager() cman2 := NewChainManager()
cman2.Reset() // so we don't end up with last block of cman1 cman2.Reset() // so we don't end up with last block of cman1
bman2 := &BlockManager{bc: cman2, Pow: fakePow{}, eth:&fakeEth{}} bman2 := &BlockManager{bc: cman2, Pow: fakePow{}, eth: &fakeEth{}}
bman2.bc.SetProcessor(bman2) bman2.bc.SetProcessor(bman2)
chainB := makechain2(bman2, 3) chainB := makechain2(bman2, 3)
td2, err := bman.bc.TestChain(chainB) td2, err := bman.bc.TestChain(chainB)
if err != nil && !IsTDError(err){ if err != nil && !IsTDError(err) {
t.Error("expected chainB not to give errors:", err) t.Error("expected chainB not to give errors:", err)
} }