aboutsummaryrefslogtreecommitdiffstats
path: root/eth
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2015-09-08 01:43:01 +0800
committerPéter Szilágyi <peterke@gmail.com>2015-09-11 22:42:25 +0800
commitcdc2662c4098d68a7b450b9b9ff2688acbffcee4 (patch)
tree2dfb3b7365895203132bd6d1aa650b5a239b01eb /eth
parent2b339cbbd8bb475d2195d54a71dcced700003430 (diff)
downloaddexon-cdc2662c4098d68a7b450b9b9ff2688acbffcee4.tar.gz
dexon-cdc2662c4098d68a7b450b9b9ff2688acbffcee4.tar.zst
dexon-cdc2662c4098d68a7b450b9b9ff2688acbffcee4.zip
core: split out TD from database and all internals
Diffstat (limited to 'eth')
-rw-r--r--eth/backend.go18
-rw-r--r--eth/downloader/downloader.go11
-rw-r--r--eth/downloader/downloader_test.go44
-rw-r--r--eth/handler.go19
-rw-r--r--eth/peer.go5
-rw-r--r--eth/protocol.go16
6 files changed, 66 insertions, 47 deletions
diff --git a/eth/backend.go b/eth/backend.go
index 59f2ab01a..deb6d3d0f 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -316,9 +316,13 @@ func New(config *Config) (*Ethereum, error) {
if err != nil {
return nil, err
}
- case config.GenesisBlock != nil: // This is for testing only.
+ }
+ // This is for testing only.
+ if config.GenesisBlock != nil {
+ core.WriteTd(chainDb, config.GenesisBlock.Hash(), config.GenesisBlock.Difficulty())
core.WriteBlock(chainDb, config.GenesisBlock)
- core.WriteHead(chainDb, config.GenesisBlock)
+ core.WriteCanonicalHash(chainDb, config.GenesisBlock.Hash(), config.GenesisBlock.NumberU64())
+ core.WriteHeadBlockHash(chainDb, config.GenesisBlock.Hash())
}
if !config.SkipBcVersionCheck {
@@ -752,7 +756,10 @@ func upgradeChainDatabase(db common.Database) error {
// Load the block, split and serialize (order!)
block := core.GetBlockByHashOld(db, common.BytesToHash(bytes.TrimPrefix(it.Key(), blockPrefix)))
- if err := core.WriteBody(db, block); err != nil {
+ if err := core.WriteTd(db, block.Hash(), block.DeprecatedTd()); err != nil {
+ return err
+ }
+ if err := core.WriteBody(db, block.Hash(), &types.Body{block.Transactions(), block.Uncles()}); err != nil {
return err
}
if err := core.WriteHeader(db, block.Header()); err != nil {
@@ -765,7 +772,10 @@ func upgradeChainDatabase(db common.Database) error {
// Lastly, upgrade the head block, disabling the upgrade mechanism
current := core.GetBlockByHashOld(db, head)
- if err := core.WriteBody(db, current); err != nil {
+ if err := core.WriteTd(db, current.Hash(), current.DeprecatedTd()); err != nil {
+ return err
+ }
+ if err := core.WriteBody(db, current.Hash(), &types.Body{current.Transactions(), current.Uncles()}); err != nil {
return err
}
if err := core.WriteHeader(db, current.Header()); err != nil {
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index 73f95bf64..d28985b3e 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -87,6 +87,9 @@ type blockRetrievalFn func(common.Hash) *types.Block
// headRetrievalFn is a callback type for retrieving the head block from the local chain.
type headRetrievalFn func() *types.Block
+// tdRetrievalFn is a callback type for retrieving the total difficulty of a local block.
+type tdRetrievalFn func(common.Hash) *big.Int
+
// chainInsertFn is a callback type to insert a batch of blocks into the local chain.
type chainInsertFn func(types.Blocks) (int, error)
@@ -136,6 +139,7 @@ type Downloader struct {
hasBlock hashCheckFn // Checks if a block is present in the chain
getBlock blockRetrievalFn // Retrieves a block from the chain
headBlock headRetrievalFn // Retrieves the head block from the chain
+ getTd tdRetrievalFn // Retrieves the TD of a block from the chain
insertChain chainInsertFn // Injects a batch of blocks into the chain
dropPeer peerDropFn // Drops a peer for misbehaving
@@ -168,7 +172,7 @@ type Block struct {
}
// New creates a new downloader to fetch hashes and blocks from remote peers.
-func New(mux *event.TypeMux, hasBlock hashCheckFn, getBlock blockRetrievalFn, headBlock headRetrievalFn, insertChain chainInsertFn, dropPeer peerDropFn) *Downloader {
+func New(mux *event.TypeMux, hasBlock hashCheckFn, getBlock blockRetrievalFn, headBlock headRetrievalFn, getTd tdRetrievalFn, insertChain chainInsertFn, dropPeer peerDropFn) *Downloader {
return &Downloader{
mux: mux,
queue: newQueue(),
@@ -176,6 +180,7 @@ func New(mux *event.TypeMux, hasBlock hashCheckFn, getBlock blockRetrievalFn, he
hasBlock: hasBlock,
getBlock: getBlock,
headBlock: headBlock,
+ getTd: getTd,
insertChain: insertChain,
dropPeer: dropPeer,
newPeerCh: make(chan *peer, 1),
@@ -582,7 +587,7 @@ func (d *Downloader) fetchHashes61(p *peer, td *big.Int, from uint64) error {
// L: Sync begins, and finds common ancestor at 11
// L: Request new hashes up from 11 (R's TD was higher, it must have something)
// R: Nothing to give
- if !gotHashes && td.Cmp(d.headBlock().Td) > 0 {
+ if !gotHashes && td.Cmp(d.getTd(d.headBlock().Hash())) > 0 {
return errStallingPeer
}
return nil
@@ -958,7 +963,7 @@ func (d *Downloader) fetchHeaders(p *peer, td *big.Int, from uint64) error {
// L: Sync begins, and finds common ancestor at 11
// L: Request new headers up from 11 (R's TD was higher, it must have something)
// R: Nothing to give
- if !gotHeaders && td.Cmp(d.headBlock().Td) > 0 {
+ if !gotHeaders && td.Cmp(d.getTd(d.headBlock().Hash())) > 0 {
return errStallingPeer
}
return nil
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index 8d009b671..dbcf93607 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -93,21 +93,25 @@ func makeChainFork(n, f int, parent *types.Block) (h1, h2 []common.Hash, b1, b2
type downloadTester struct {
downloader *Downloader
- ownHashes []common.Hash // Hash chain belonging to the tester
- ownBlocks map[common.Hash]*types.Block // Blocks belonging to the tester
- peerHashes map[string][]common.Hash // Hash chain belonging to different test peers
- peerBlocks map[string]map[common.Hash]*types.Block // Blocks belonging to different test peers
+ ownHashes []common.Hash // Hash chain belonging to the tester
+ ownBlocks map[common.Hash]*types.Block // Blocks belonging to the tester
+ ownChainTd map[common.Hash]*big.Int // Total difficulties of the blocks in the local chain
+ peerHashes map[string][]common.Hash // Hash chain belonging to different test peers
+ peerBlocks map[string]map[common.Hash]*types.Block // Blocks belonging to different test peers
+ peerChainTds map[string]map[common.Hash]*big.Int // Total difficulties of the blocks in the peer chains
}
// newTester creates a new downloader test mocker.
func newTester() *downloadTester {
tester := &downloadTester{
- ownHashes: []common.Hash{genesis.Hash()},
- ownBlocks: map[common.Hash]*types.Block{genesis.Hash(): genesis},
- peerHashes: make(map[string][]common.Hash),
- peerBlocks: make(map[string]map[common.Hash]*types.Block),
+ ownHashes: []common.Hash{genesis.Hash()},
+ ownBlocks: map[common.Hash]*types.Block{genesis.Hash(): genesis},
+ ownChainTd: map[common.Hash]*big.Int{genesis.Hash(): genesis.Difficulty()},
+ peerHashes: make(map[string][]common.Hash),
+ peerBlocks: make(map[string]map[common.Hash]*types.Block),
+ peerChainTds: make(map[string]map[common.Hash]*big.Int),
}
- tester.downloader = New(new(event.TypeMux), tester.hasBlock, tester.getBlock, tester.headBlock, tester.insertChain, tester.dropPeer)
+ tester.downloader = New(new(event.TypeMux), tester.hasBlock, tester.getBlock, tester.headBlock, tester.getTd, tester.insertChain, tester.dropPeer)
return tester
}
@@ -119,8 +123,8 @@ func (dl *downloadTester) sync(id string, td *big.Int) error {
// If no particular TD was requested, load from the peer's blockchain
if td == nil {
td = big.NewInt(1)
- if block, ok := dl.peerBlocks[id][hash]; ok {
- td = block.Td
+ if diff, ok := dl.peerChainTds[id][hash]; ok {
+ td = diff
}
}
err := dl.downloader.synchronise(id, hash, td)
@@ -152,6 +156,11 @@ func (dl *downloadTester) headBlock() *types.Block {
return dl.getBlock(dl.ownHashes[len(dl.ownHashes)-1])
}
+// getTd retrieves the block's total difficulty from the canonical chain.
+func (dl *downloadTester) getTd(hash common.Hash) *big.Int {
+ return dl.ownChainTd[hash]
+}
+
// insertChain injects a new batch of blocks into the simulated chain.
func (dl *downloadTester) insertChain(blocks types.Blocks) (int, error) {
for i, block := range blocks {
@@ -160,6 +169,7 @@ func (dl *downloadTester) insertChain(blocks types.Blocks) (int, error) {
}
dl.ownHashes = append(dl.ownHashes, block.Hash())
dl.ownBlocks[block.Hash()] = block
+ dl.ownChainTd[block.Hash()] = dl.ownChainTd[block.ParentHash()]
}
return len(blocks), nil
}
@@ -180,9 +190,16 @@ func (dl *downloadTester) newSlowPeer(id string, version int, hashes []common.Ha
// Assign the owned hashes and blocks to the peer (deep copy)
dl.peerHashes[id] = make([]common.Hash, len(hashes))
copy(dl.peerHashes[id], hashes)
+
dl.peerBlocks[id] = make(map[common.Hash]*types.Block)
- for hash, block := range blocks {
- dl.peerBlocks[id][hash] = block
+ dl.peerChainTds[id] = make(map[common.Hash]*big.Int)
+ for _, hash := range hashes {
+ if block, ok := blocks[hash]; ok {
+ dl.peerBlocks[id][hash] = block
+ if parent, ok := dl.peerBlocks[id][block.ParentHash()]; ok {
+ dl.peerChainTds[id][hash] = new(big.Int).Add(block.Difficulty(), dl.peerChainTds[id][parent.Hash()])
+ }
+ }
}
}
return err
@@ -192,6 +209,7 @@ func (dl *downloadTester) newSlowPeer(id string, version int, hashes []common.Ha
func (dl *downloadTester) dropPeer(id string) {
delete(dl.peerHashes, id)
delete(dl.peerBlocks, id)
+ delete(dl.peerChainTds, id)
dl.downloader.UnregisterPeer(id)
}
diff --git a/eth/handler.go b/eth/handler.go
index 95f4e8ce2..4aef69043 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -36,8 +36,10 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
-// This is the target maximum size of returned blocks, headers or node data.
-const softResponseLimit = 2 * 1024 * 1024
+const (
+ softResponseLimit = 2 * 1024 * 1024 // Target maximum size of returned blocks, headers or node data.
+ estHeaderRlpSize = 500 // Approximate size of an RLP encoded block header
+)
func errResp(code errCode, format string, v ...interface{}) error {
return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
@@ -113,7 +115,7 @@ func NewProtocolManager(networkId int, mux *event.TypeMux, txpool txPool, pow po
}
}
// Construct the different synchronisation mechanisms
- manager.downloader = downloader.New(manager.eventMux, manager.chainman.HasBlock, manager.chainman.GetBlock, manager.chainman.CurrentBlock, manager.chainman.InsertChain, manager.removePeer)
+ manager.downloader = downloader.New(manager.eventMux, manager.chainman.HasBlock, manager.chainman.GetBlock, manager.chainman.CurrentBlock, manager.chainman.GetTd, manager.chainman.InsertChain, manager.removePeer)
validator := func(block *types.Block, parent *types.Block) error {
return core.ValidateHeader(pow, block.Header(), parent, true, false)
@@ -363,7 +365,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
break
}
headers = append(headers, origin)
- bytes += 500 // Approximate, should be good enough estimate
+ bytes += estHeaderRlpSize
// Advance to the next header of the query
switch {
@@ -453,7 +455,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
var (
hash common.Hash
bytes int
- bodies []*blockBodyRLP
+ bodies []rlp.RawValue
)
for bytes < softResponseLimit && len(bodies) < downloader.MaxBlockFetch {
// Retrieve the hash of the next block
@@ -464,9 +466,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
}
// Retrieve the requested block body, stopping if enough was found
if data := pm.chainman.GetBodyRLP(hash); len(data) != 0 {
- body := blockBodyRLP(data)
- bodies = append(bodies, &body)
- bytes += len(body)
+ bodies = append(bodies, data)
+ bytes += len(data)
}
}
return p.SendBlockBodiesRLP(bodies)
@@ -644,7 +645,7 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
// Calculate the TD of the block (it's not imported yet, so block.Td is not valid)
var td *big.Int
if parent := pm.chainman.GetBlock(block.ParentHash()); parent != nil {
- td = new(big.Int).Add(parent.Td, block.Difficulty())
+ td = new(big.Int).Add(block.Difficulty(), pm.chainman.GetTd(block.ParentHash()))
} else {
glog.V(logger.Error).Infof("propagating dangling block #%d [%x]", block.NumberU64(), hash[:4])
return
diff --git a/eth/peer.go b/eth/peer.go
index f1ddd9726..603b49b88 100644
--- a/eth/peer.go
+++ b/eth/peer.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rlp"
"gopkg.in/fatih/set.v0"
)
@@ -186,8 +187,8 @@ func (p *peer) SendBlockBodies(bodies []*blockBody) error {
// SendBlockBodiesRLP sends a batch of block contents to the remote peer from
// an already RLP encoded format.
-func (p *peer) SendBlockBodiesRLP(bodies []*blockBodyRLP) error {
- return p2p.Send(p.rw, BlockBodiesMsg, blockBodiesRLPData(bodies))
+func (p *peer) SendBlockBodiesRLP(bodies []rlp.RawValue) error {
+ return p2p.Send(p.rw, BlockBodiesMsg, bodies)
}
// SendNodeData sends a batch of arbitrary internal data, corresponding to the
diff --git a/eth/protocol.go b/eth/protocol.go
index 24007bbb5..49f096a3b 100644
--- a/eth/protocol.go
+++ b/eth/protocol.go
@@ -213,22 +213,6 @@ type blockBody struct {
// blockBodiesData is the network packet for block content distribution.
type blockBodiesData []*blockBody
-// blockBodyRLP represents the RLP encoded data content of a single block.
-type blockBodyRLP []byte
-
-// EncodeRLP is a specialized encoder for a block body to pass the already
-// encoded body RLPs from the database on, without double encoding.
-func (b *blockBodyRLP) EncodeRLP(w io.Writer) error {
- if _, err := w.Write([]byte(*b)); err != nil {
- return err
- }
- return nil
-}
-
-// blockBodiesRLPData is the network packet for block content distribution
-// based on original RLP formatting (i.e. skip the db-decode/proto-encode).
-type blockBodiesRLPData []*blockBodyRLP
-
// nodeDataData is the network response packet for a node data retrieval.
type nodeDataData []struct {
Value []byte