mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
fix CalculateTD so shorter forks don't take over
This commit is contained in:
parent
d7985fa3b0
commit
6ef0f67b9f
2 changed files with 51 additions and 50 deletions
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue