mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
eth, les: share code that serves GetBlockHeadersMsg
This commit is contained in:
parent
591cef17d4
commit
cf059f15cb
2 changed files with 87 additions and 162 deletions
164
eth/handler.go
164
eth/handler.go
|
|
@ -339,85 +339,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
if err := msg.Decode(&query); err != nil {
|
if err := msg.Decode(&query); err != nil {
|
||||||
return errResp(ErrDecode, "%v: %v", msg, err)
|
return errResp(ErrDecode, "%v: %v", msg, err)
|
||||||
}
|
}
|
||||||
hashMode := query.Origin.Hash != (common.Hash{})
|
headers := ServeBlockHeaders(pm.blockchain, p.Peer, query.Origin.Hash, query.Origin.Number, query.Amount, query.Skip, query.Reverse)
|
||||||
first := true
|
|
||||||
maxNonCanonical := uint64(100)
|
|
||||||
|
|
||||||
// Gather headers until the fetch or network limits is reached
|
|
||||||
var (
|
|
||||||
bytes common.StorageSize
|
|
||||||
headers []*types.Header
|
|
||||||
unknown bool
|
|
||||||
)
|
|
||||||
for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit && len(headers) < downloader.MaxHeaderFetch {
|
|
||||||
// Retrieve the next header satisfying the query
|
|
||||||
var origin *types.Header
|
|
||||||
if hashMode {
|
|
||||||
if first {
|
|
||||||
first = false
|
|
||||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
|
||||||
if origin != nil {
|
|
||||||
query.Origin.Number = origin.Number.Uint64()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
|
|
||||||
}
|
|
||||||
if origin == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
headers = append(headers, origin)
|
|
||||||
bytes += estHeaderRlpSize
|
|
||||||
|
|
||||||
// Advance to the next header of the query
|
|
||||||
switch {
|
|
||||||
case hashMode && query.Reverse:
|
|
||||||
// Hash based traversal towards the genesis block
|
|
||||||
ancestor := query.Skip + 1
|
|
||||||
if ancestor == 0 {
|
|
||||||
unknown = true
|
|
||||||
} else {
|
|
||||||
query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical)
|
|
||||||
unknown = (query.Origin.Hash == common.Hash{})
|
|
||||||
}
|
|
||||||
case hashMode && !query.Reverse:
|
|
||||||
// Hash based traversal towards the leaf block
|
|
||||||
var (
|
|
||||||
current = origin.Number.Uint64()
|
|
||||||
next = current + query.Skip + 1
|
|
||||||
)
|
|
||||||
if next <= current {
|
|
||||||
infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ")
|
|
||||||
p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos)
|
|
||||||
unknown = true
|
|
||||||
} else {
|
|
||||||
if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
|
|
||||||
nextHash := header.Hash()
|
|
||||||
expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical)
|
|
||||||
if expOldHash == query.Origin.Hash {
|
|
||||||
query.Origin.Hash, query.Origin.Number = nextHash, next
|
|
||||||
} else {
|
|
||||||
unknown = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unknown = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case query.Reverse:
|
|
||||||
// Number based traversal towards the genesis block
|
|
||||||
if query.Origin.Number >= query.Skip+1 {
|
|
||||||
query.Origin.Number -= query.Skip + 1
|
|
||||||
} else {
|
|
||||||
unknown = true
|
|
||||||
}
|
|
||||||
|
|
||||||
case !query.Reverse:
|
|
||||||
// Number based traversal towards the leaf block
|
|
||||||
query.Origin.Number += query.Skip + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p.SendBlockHeaders(headers)
|
return p.SendBlockHeaders(headers)
|
||||||
|
|
||||||
case msg.Code == BlockHeadersMsg:
|
case msg.Code == BlockHeadersMsg:
|
||||||
|
|
@ -688,6 +610,90 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServeBlockHeaders collects the block headers for serving a GetBlockHeadersMsg
|
||||||
|
func ServeBlockHeaders(blockchain *core.BlockChain, peer *p2p.Peer, originHash common.Hash, originNumber, amount, skip uint64, reverse bool) []*types.Header {
|
||||||
|
hashMode := originHash != (common.Hash{})
|
||||||
|
first := true
|
||||||
|
maxNonCanonical := uint64(100)
|
||||||
|
|
||||||
|
// Gather headers until the fetch or network limits is reached
|
||||||
|
var (
|
||||||
|
bytes common.StorageSize
|
||||||
|
headers []*types.Header
|
||||||
|
unknown bool
|
||||||
|
)
|
||||||
|
for !unknown && len(headers) < int(amount) && bytes < softResponseLimit && len(headers) < downloader.MaxHeaderFetch {
|
||||||
|
// Retrieve the next header satisfying the query
|
||||||
|
var origin *types.Header
|
||||||
|
if hashMode {
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
origin = blockchain.GetHeaderByHash(originHash)
|
||||||
|
if origin != nil {
|
||||||
|
originNumber = origin.Number.Uint64()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
origin = blockchain.GetHeader(originHash, originNumber)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
origin = blockchain.GetHeaderByNumber(originNumber)
|
||||||
|
}
|
||||||
|
if origin == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
headers = append(headers, origin)
|
||||||
|
bytes += estHeaderRlpSize
|
||||||
|
|
||||||
|
// Advance to the next header of the query
|
||||||
|
switch {
|
||||||
|
case hashMode && reverse:
|
||||||
|
// Hash based traversal towards the genesis block
|
||||||
|
ancestor := skip + 1
|
||||||
|
if ancestor == 0 {
|
||||||
|
unknown = true
|
||||||
|
} else {
|
||||||
|
originHash, originNumber = blockchain.GetAncestor(originHash, originNumber, ancestor, &maxNonCanonical)
|
||||||
|
unknown = (originHash == common.Hash{})
|
||||||
|
}
|
||||||
|
case hashMode && !reverse:
|
||||||
|
// Hash based traversal towards the leaf block
|
||||||
|
var (
|
||||||
|
current = origin.Number.Uint64()
|
||||||
|
next = current + skip + 1
|
||||||
|
)
|
||||||
|
if next <= current {
|
||||||
|
infos, _ := json.MarshalIndent(peer.Info(), "", " ")
|
||||||
|
peer.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", skip, "next", next, "attacker", infos)
|
||||||
|
unknown = true
|
||||||
|
} else {
|
||||||
|
if header := blockchain.GetHeaderByNumber(next); header != nil {
|
||||||
|
nextHash := header.Hash()
|
||||||
|
expOldHash, _ := blockchain.GetAncestor(nextHash, next, skip+1, &maxNonCanonical)
|
||||||
|
if expOldHash == originHash {
|
||||||
|
originHash, originNumber = nextHash, next
|
||||||
|
} else {
|
||||||
|
unknown = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unknown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reverse:
|
||||||
|
// Number based traversal towards the genesis block
|
||||||
|
if originNumber >= skip+1 {
|
||||||
|
originNumber -= skip + 1
|
||||||
|
} else {
|
||||||
|
unknown = true
|
||||||
|
}
|
||||||
|
|
||||||
|
case !reverse:
|
||||||
|
// Number based traversal towards the leaf block
|
||||||
|
originNumber += skip + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
|
||||||
// BroadcastBlock will either propagate a block to a subset of it's peers, or
|
// BroadcastBlock will either propagate a block to a subset of it's peers, or
|
||||||
// will only announce it's availability (depending what's requested).
|
// will only announce it's availability (depending what's requested).
|
||||||
func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
|
func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package les
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -33,6 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
|
@ -412,92 +412,11 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return errResp(ErrDecode, "%v: %v", msg, err)
|
return errResp(ErrDecode, "%v: %v", msg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
query := req.Query
|
query := req.Query
|
||||||
if reject(query.Amount, MaxHeaderFetch) {
|
if reject(query.Amount, MaxHeaderFetch) {
|
||||||
return errResp(ErrRequestRejected, "")
|
return errResp(ErrRequestRejected, "")
|
||||||
}
|
}
|
||||||
|
headers := eth.ServeBlockHeaders(pm.blockchain.(*core.BlockChain), p.Peer, query.Origin.Hash, query.Origin.Number, query.Amount, query.Skip, query.Reverse)
|
||||||
hashMode := query.Origin.Hash != (common.Hash{})
|
|
||||||
first := true
|
|
||||||
maxNonCanonical := uint64(100)
|
|
||||||
|
|
||||||
// Gather headers until the fetch or network limits is reached
|
|
||||||
var (
|
|
||||||
bytes common.StorageSize
|
|
||||||
headers []*types.Header
|
|
||||||
unknown bool
|
|
||||||
)
|
|
||||||
for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit {
|
|
||||||
// Retrieve the next header satisfying the query
|
|
||||||
var origin *types.Header
|
|
||||||
if hashMode {
|
|
||||||
if first {
|
|
||||||
first = false
|
|
||||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
|
||||||
if origin != nil {
|
|
||||||
query.Origin.Number = origin.Number.Uint64()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
|
|
||||||
}
|
|
||||||
if origin == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
headers = append(headers, origin)
|
|
||||||
bytes += estHeaderRlpSize
|
|
||||||
|
|
||||||
// Advance to the next header of the query
|
|
||||||
switch {
|
|
||||||
case hashMode && query.Reverse:
|
|
||||||
// Hash based traversal towards the genesis block
|
|
||||||
ancestor := query.Skip + 1
|
|
||||||
if ancestor == 0 {
|
|
||||||
unknown = true
|
|
||||||
} else {
|
|
||||||
query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical)
|
|
||||||
unknown = (query.Origin.Hash == common.Hash{})
|
|
||||||
}
|
|
||||||
case hashMode && !query.Reverse:
|
|
||||||
// Hash based traversal towards the leaf block
|
|
||||||
var (
|
|
||||||
current = origin.Number.Uint64()
|
|
||||||
next = current + query.Skip + 1
|
|
||||||
)
|
|
||||||
if next <= current {
|
|
||||||
infos, _ := json.MarshalIndent(p.Peer.Info(), "", " ")
|
|
||||||
p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", query.Skip, "next", next, "attacker", infos)
|
|
||||||
unknown = true
|
|
||||||
} else {
|
|
||||||
if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
|
|
||||||
nextHash := header.Hash()
|
|
||||||
expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical)
|
|
||||||
if expOldHash == query.Origin.Hash {
|
|
||||||
query.Origin.Hash, query.Origin.Number = nextHash, next
|
|
||||||
} else {
|
|
||||||
unknown = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unknown = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case query.Reverse:
|
|
||||||
// Number based traversal towards the genesis block
|
|
||||||
if query.Origin.Number >= query.Skip+1 {
|
|
||||||
query.Origin.Number -= query.Skip + 1
|
|
||||||
} else {
|
|
||||||
unknown = true
|
|
||||||
}
|
|
||||||
|
|
||||||
case !query.Reverse:
|
|
||||||
// Number based traversal towards the leaf block
|
|
||||||
query.Origin.Number += query.Skip + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + query.Amount*costs.reqCost)
|
bv, rcost := p.fcClient.RequestProcessed(costs.baseCost + query.Amount*costs.reqCost)
|
||||||
pm.server.fcCostStats.update(msg.Code, query.Amount, rcost)
|
pm.server.fcCostStats.update(msg.Code, query.Amount, rcost)
|
||||||
return p.SendBlockHeaders(req.ReqID, bv, headers)
|
return p.SendBlockHeaders(req.ReqID, bv, headers)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue