les: move protocol definition to separate package

This commit is contained in:
rjl493456442 2020-01-07 11:36:05 +08:00
parent 86d503ab15
commit 81aeba2798
20 changed files with 1021 additions and 867 deletions

View file

@ -38,6 +38,7 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/les"
lesproto "github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
@ -378,7 +379,7 @@ func (s *Service) login(conn *websocket.Conn) error {
protocol = fmt.Sprintf("eth/%d", eth.ProtocolVersions[0])
} else {
network = fmt.Sprintf("%d", infos.Protocols["les"].(*les.NodeInfo).Network)
protocol = fmt.Sprintf("les/%d", les.ClientProtocolVersions[0])
protocol = fmt.Sprintf("les/%d", lesproto.ClientProtocolVersions[0])
}
auth := &authMsg{
ID: s.node,

View file

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/les/utilities"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
@ -119,9 +120,9 @@ func (b *benchmarkProofsOrCode) request(peer *peer, index int) error {
key := make([]byte, 32)
rand.Read(key)
if b.code {
return peer.RequestCode(0, 0, []CodeReq{{BHash: b.headHash, AccKey: key}})
return peer.RequestCode(0, 0, []protocol.CodeRequest{{BlockHash: b.headHash, Account: key}})
} else {
return peer.RequestProofs(0, 0, []ProofReq{{BHash: b.headHash, Key: key}})
return peer.RequestProofs(0, 0, []protocol.TrieProofRequest{{BlockHash: b.headHash, Key: key}})
}
}
@ -146,7 +147,7 @@ func (b *benchmarkHelperTrie) init(h *serverHandler, count int) error {
}
func (b *benchmarkHelperTrie) request(peer *peer, index int) error {
reqs := make([]HelperTrieReq, b.reqCount)
reqs := make([]protocol.HelperTrieRequest, b.reqCount)
if b.bloom {
bitIdx := uint16(rand.Intn(2048))
@ -154,13 +155,22 @@ func (b *benchmarkHelperTrie) request(peer *peer, index int) error {
key := make([]byte, 10)
binary.BigEndian.PutUint16(key[:2], bitIdx)
binary.BigEndian.PutUint64(key[2:], uint64(rand.Int63n(int64(b.sectionCount))))
reqs[i] = HelperTrieReq{Type: htBloomBits, TrieIdx: b.sectionCount - 1, Key: key}
reqs[i] = protocol.HelperTrieRequest{
Type: protocol.HelperTrieBloomTrie,
TrieIndex: b.sectionCount - 1,
Key: key,
}
}
} else {
for i := range reqs {
key := make([]byte, 8)
binary.BigEndian.PutUint64(key[:], uint64(rand.Int63n(int64(b.headNum))))
reqs[i] = HelperTrieReq{Type: htCanonical, TrieIdx: b.sectionCount - 1, Key: key, AuxReq: auxHeader}
reqs[i] = protocol.HelperTrieRequest{
Type: protocol.HelperTrieCHT,
TrieIndex: b.sectionCount - 1,
Key: key,
AuxType: protocol.AuxHeader,
}
}
}
@ -284,13 +294,13 @@ func (h *serverHandler) measure(setup *benchmarkSetup, count int) error {
var id enode.ID
rand.Read(id[:])
clientPeer := newPeer(lpv2, NetworkId, false, p2p.NewPeer(id, "client", nil), clientMeteredPipe)
serverPeer := newPeer(lpv2, NetworkId, false, p2p.NewPeer(id, "server", nil), serverMeteredPipe)
clientPeer := newPeer(protocol.Lpv2, protocol.NetworkId, false, p2p.NewPeer(id, "client", nil), clientMeteredPipe)
serverPeer := newPeer(protocol.Lpv2, protocol.NetworkId, false, p2p.NewPeer(id, "server", nil), serverMeteredPipe)
serverPeer.sendQueue = utilities.NewExecQueue(count)
serverPeer.announceType = announceTypeNone
serverPeer.fcCosts = make(requestCostTable)
c := &requestCosts{}
for code := range requests {
serverPeer.fcCosts = make(protocol.RequestCostTable)
c := &protocol.RequestCost{}
for code := range protocol.LesRequests {
serverPeer.fcCosts[code] = c
}
serverPeer.fcParams = flowcontrol.ServerParams{BufLimit: 1, MinRecharge: 1}

View file

@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/les/checkpointoracle"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
@ -217,14 +218,14 @@ func (s *LightEthereum) ResetWithGenesisBlock(gb *types.Block) {
func (s *LightEthereum) BlockChain() *light.LightChain { return s.blockchain }
func (s *LightEthereum) TxPool() *light.TxPool { return s.txPool }
func (s *LightEthereum) Engine() consensus.Engine { return s.engine }
func (s *LightEthereum) LesVersion() int { return int(ClientProtocolVersions[0]) }
func (s *LightEthereum) LesVersion() int { return int(protocol.ClientProtocolVersions[0]) }
func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader }
func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux }
// Protocols implements node.Service, returning all the currently configured
// network protocols to start.
func (s *LightEthereum) Protocols() []p2p.Protocol {
return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
return s.makeProtocols(protocol.ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
if p := s.peers.Peer(peerIdToString(id)); p != nil {
return p.Info()
}
@ -244,8 +245,8 @@ func (s *LightEthereum) Start(srvr *p2p.Server) error {
s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.config.NetworkId)
// clients are searching for the first advertised protocol in the list
protocolVersion := AdvertiseProtocolVersions[0]
s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion))
protocolVersion := protocol.AdvertiseProtocolVersions[0]
s.serverPool.start(srvr, protocol.LesTopic(s.blockchain.Genesis().Hash(), protocolVersion))
return nil
}

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
@ -151,8 +152,8 @@ func (h *clientHandler) handleMsg(p *peer) error {
}
p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size)
if msg.Size > ProtocolMaxMsgSize {
return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
if msg.Size > protocol.ProtocolMaxMsgSize {
return protocol.ErrResp(protocol.ErrMsgTooLarge, "%v > %v", msg.Size, protocol.ProtocolMaxMsgSize)
}
defer msg.Discard()
@ -160,43 +161,43 @@ func (h *clientHandler) handleMsg(p *peer) error {
// Handle the message depending on its contents
switch msg.Code {
case AnnounceMsg:
case protocol.AnnounceMsg:
p.Log().Trace("Received announce message")
var req announceData
if err := msg.Decode(&req); err != nil {
return errResp(ErrDecode, "%v: %v", msg, err)
var anno protocol.Announcement
if err := msg.Decode(&anno); err != nil {
return protocol.ErrResp(protocol.ErrDecode, "%v: %v", msg, err)
}
if err := req.sanityCheck(); err != nil {
if err := anno.SanityCheck(); err != nil {
return err
}
update, size := req.Update.decode()
update, size := anno.Update.ToMap()
if p.rejectUpdate(size) {
return errResp(ErrRequestRejected, "")
return protocol.ErrResp(protocol.ErrRequestRejected, "")
}
p.updateFlowControl(update)
if req.Hash != (common.Hash{}) {
if anno.Hash != (common.Hash{}) {
if p.announceType == announceTypeNone {
return errResp(ErrUnexpectedResponse, "")
return protocol.ErrResp(protocol.ErrUnexpectedResponse, "")
}
if p.announceType == announceTypeSigned {
if err := req.checkSignature(p.ID(), update); err != nil {
if err := anno.CheckSignature(p.ID(), update); err != nil {
p.Log().Trace("Invalid announcement signature", "err", err)
return err
}
p.Log().Trace("Valid announcement signature")
}
p.Log().Trace("Announce message content", "number", req.Number, "hash", req.Hash, "td", req.Td, "reorg", req.ReorgDepth)
h.fetcher.announce(p, &req)
p.Log().Trace("Announce message content", "number", anno.Number, "hash", anno.Hash, "td", anno.Td, "reorg", anno.ReorgDepth)
h.fetcher.announce(p, &anno)
}
case BlockHeadersMsg:
case protocol.BlockHeadersMsg:
p.Log().Trace("Received block header response message")
var resp struct {
ReqID, BV uint64
Headers []*types.Header
}
if err := msg.Decode(&resp); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
if h.fetcher.requestedID(resp.ReqID) {
@ -206,14 +207,14 @@ func (h *clientHandler) handleMsg(p *peer) error {
log.Debug("Failed to deliver headers", "err", err)
}
}
case BlockBodiesMsg:
case protocol.BlockBodiesMsg:
p.Log().Trace("Received block bodies response")
var resp struct {
ReqID, BV uint64
Data []*types.Body
}
if err := msg.Decode(&resp); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
deliverMsg = &Msg{
@ -221,14 +222,14 @@ func (h *clientHandler) handleMsg(p *peer) error {
ReqID: resp.ReqID,
Obj: resp.Data,
}
case CodeMsg:
case protocol.CodeMsg:
p.Log().Trace("Received code response")
var resp struct {
ReqID, BV uint64
Data [][]byte
}
if err := msg.Decode(&resp); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
deliverMsg = &Msg{
@ -236,14 +237,14 @@ func (h *clientHandler) handleMsg(p *peer) error {
ReqID: resp.ReqID,
Obj: resp.Data,
}
case ReceiptsMsg:
case protocol.ReceiptsMsg:
p.Log().Trace("Received receipts response")
var resp struct {
ReqID, BV uint64
Receipts []types.Receipts
}
if err := msg.Decode(&resp); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
deliverMsg = &Msg{
@ -251,14 +252,14 @@ func (h *clientHandler) handleMsg(p *peer) error {
ReqID: resp.ReqID,
Obj: resp.Receipts,
}
case ProofsV2Msg:
case protocol.ProofsV2Msg:
p.Log().Trace("Received les/2 proofs response")
var resp struct {
ReqID, BV uint64
Data light.NodeList
}
if err := msg.Decode(&resp); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
deliverMsg = &Msg{
@ -266,14 +267,14 @@ func (h *clientHandler) handleMsg(p *peer) error {
ReqID: resp.ReqID,
Obj: resp.Data,
}
case HelperTrieProofsMsg:
case protocol.HelperTrieProofsMsg:
p.Log().Trace("Received helper trie proof response")
var resp struct {
ReqID, BV uint64
Data HelperTrieResps
Data protocol.HelperTrieResponse
}
if err := msg.Decode(&resp); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
deliverMsg = &Msg{
@ -281,14 +282,14 @@ func (h *clientHandler) handleMsg(p *peer) error {
ReqID: resp.ReqID,
Obj: resp.Data,
}
case TxStatusMsg:
case protocol.TxStatusMsg:
p.Log().Trace("Received tx status response")
var resp struct {
ReqID, BV uint64
Status []light.TxStatus
}
if err := msg.Decode(&resp); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
p.fcServer.ReceivedReply(resp.ReqID, resp.BV)
deliverMsg = &Msg{
@ -296,21 +297,21 @@ func (h *clientHandler) handleMsg(p *peer) error {
ReqID: resp.ReqID,
Obj: resp.Status,
}
case StopMsg:
case protocol.StopMsg:
p.freezeServer(true)
h.backend.retriever.frozen(p)
p.Log().Debug("Service stopped")
case ResumeMsg:
case protocol.ResumeMsg:
var bv uint64
if err := msg.Decode(&bv); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
p.fcServer.ResumeFreeze(bv)
p.freezeServer(false)
p.Log().Debug("Service resumed")
default:
p.Log().Trace("Received invalid message", "code", msg.Code)
return errResp(ErrInvalidMsgCode, "%v", msg.Code)
return protocol.ErrResp(protocol.ErrInvalidMsgCode, "%v", msg.Code)
}
// Deliver the received response to retriever.
if deliverMsg != nil {
@ -341,7 +342,7 @@ func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, s
rq := &distReq{
getCost: func(dp distPeer) uint64 {
peer := dp.(*peer)
return peer.GetRequestCost(GetBlockHeadersMsg, amount)
return peer.GetRequestCost(protocol.GetBlockHeadersMsg, amount)
},
canSend: func(dp distPeer) bool {
return dp.(*peer) == pc.peer
@ -349,7 +350,7 @@ func (pc *peerConnection) RequestHeadersByHash(origin common.Hash, amount int, s
request: func(dp distPeer) func() {
reqID := genReqID()
peer := dp.(*peer)
cost := peer.GetRequestCost(GetBlockHeadersMsg, amount)
cost := peer.GetRequestCost(protocol.GetBlockHeadersMsg, amount)
peer.fcServer.QueuedRequest(reqID, cost)
return func() { peer.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) }
},
@ -365,7 +366,7 @@ func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip
rq := &distReq{
getCost: func(dp distPeer) uint64 {
peer := dp.(*peer)
return peer.GetRequestCost(GetBlockHeadersMsg, amount)
return peer.GetRequestCost(protocol.GetBlockHeadersMsg, amount)
},
canSend: func(dp distPeer) bool {
return dp.(*peer) == pc.peer
@ -373,7 +374,7 @@ func (pc *peerConnection) RequestHeadersByNumber(origin uint64, amount int, skip
request: func(dp distPeer) func() {
reqID := genReqID()
peer := dp.(*peer)
cost := peer.GetRequestCost(GetBlockHeadersMsg, amount)
cost := peer.GetRequestCost(protocol.GetBlockHeadersMsg, amount)
peer.fcServer.QueuedRequest(reqID, cost)
return func() { peer.RequestHeadersByNumber(reqID, cost, origin, amount, skip, reverse) }
},

View file

@ -17,7 +17,6 @@
package les
import (
"fmt"
"math/big"
"sync"
@ -28,28 +27,13 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/les/checkpointoracle"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/params"
)
func errResp(code errCode, format string, v ...interface{}) error {
return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
}
func lesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic {
var name string
switch protocolVersion {
case lpv2:
name = "LES2"
default:
panic(nil)
}
return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8]))
}
type chainReader interface {
CurrentHeader() *types.Header
}
@ -89,7 +73,7 @@ func (c *lesCommons) makeProtocols(versions []uint, runPeer func(version uint, p
protos[i] = p2p.Protocol{
Name: "les",
Version: version,
Length: ProtocolLengths[version],
Length: protocol.ProtocolLengths[version],
NodeInfo: c.nodeInfo,
Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
return runPeer(version, peer, rw)

View file

@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
)
@ -35,48 +36,48 @@ const makeCostStats = false // make request cost statistics during operation
var (
// average request cost estimates based on serving time
reqAvgTimeCost = requestCostTable{
GetBlockHeadersMsg: {150000, 30000},
GetBlockBodiesMsg: {0, 700000},
GetReceiptsMsg: {0, 1000000},
GetCodeMsg: {0, 450000},
GetProofsV2Msg: {0, 600000},
GetHelperTrieProofsMsg: {0, 1000000},
SendTxV2Msg: {0, 450000},
GetTxStatusMsg: {0, 250000},
reqAvgTimeCost = protocol.RequestCostTable{
protocol.GetBlockHeadersMsg: {150000, 30000},
protocol.GetBlockBodiesMsg: {0, 700000},
protocol.GetReceiptsMsg: {0, 1000000},
protocol.GetCodeMsg: {0, 450000},
protocol.GetProofsV2Msg: {0, 600000},
protocol.GetHelperTrieProofsMsg: {0, 1000000},
protocol.SendTxV2Msg: {0, 450000},
protocol.GetTxStatusMsg: {0, 250000},
}
// maximum incoming message size estimates
reqMaxInSize = requestCostTable{
GetBlockHeadersMsg: {40, 0},
GetBlockBodiesMsg: {0, 40},
GetReceiptsMsg: {0, 40},
GetCodeMsg: {0, 80},
GetProofsV2Msg: {0, 80},
GetHelperTrieProofsMsg: {0, 20},
SendTxV2Msg: {0, 16500},
GetTxStatusMsg: {0, 50},
reqMaxInSize = protocol.RequestCostTable{
protocol.GetBlockHeadersMsg: {40, 0},
protocol.GetBlockBodiesMsg: {0, 40},
protocol.GetReceiptsMsg: {0, 40},
protocol.GetCodeMsg: {0, 80},
protocol.GetProofsV2Msg: {0, 80},
protocol.GetHelperTrieProofsMsg: {0, 20},
protocol.SendTxV2Msg: {0, 16500},
protocol.GetTxStatusMsg: {0, 50},
}
// maximum outgoing message size estimates
reqMaxOutSize = requestCostTable{
GetBlockHeadersMsg: {0, 556},
GetBlockBodiesMsg: {0, 100000},
GetReceiptsMsg: {0, 200000},
GetCodeMsg: {0, 50000},
GetProofsV2Msg: {0, 4000},
GetHelperTrieProofsMsg: {0, 4000},
SendTxV2Msg: {0, 100},
GetTxStatusMsg: {0, 100},
reqMaxOutSize = protocol.RequestCostTable{
protocol.GetBlockHeadersMsg: {0, 556},
protocol.GetBlockBodiesMsg: {0, 100000},
protocol.GetReceiptsMsg: {0, 200000},
protocol.GetCodeMsg: {0, 50000},
protocol.GetProofsV2Msg: {0, 4000},
protocol.GetHelperTrieProofsMsg: {0, 4000},
protocol.SendTxV2Msg: {0, 100},
protocol.GetTxStatusMsg: {0, 100},
}
// request amounts that have to fit into the minimum buffer size minBufferMultiplier times
minBufferReqAmount = map[uint64]uint64{
GetBlockHeadersMsg: 192,
GetBlockBodiesMsg: 1,
GetReceiptsMsg: 1,
GetCodeMsg: 1,
GetProofsV2Msg: 1,
GetHelperTrieProofsMsg: 16,
SendTxV2Msg: 8,
GetTxStatusMsg: 64,
protocol.GetBlockHeadersMsg: 192,
protocol.GetBlockBodiesMsg: 1,
protocol.GetReceiptsMsg: 1,
protocol.GetCodeMsg: 1,
protocol.GetProofsV2Msg: 1,
protocol.GetHelperTrieProofsMsg: 16,
protocol.SendTxV2Msg: 8,
protocol.GetTxStatusMsg: 64,
}
minBufferMultiplier = 3
)
@ -132,7 +133,7 @@ type costTracker struct {
// TestHooks
testing bool // Disable real cost evaluation for testing purpose.
testCostList RequestCostList // Customized cost table for testing purpose.
testCostList protocol.RequestCostList // Customized cost table for testing purpose.
}
// newCostTracker creates a cost tracker and loads the cost factor statistics from the database.
@ -182,7 +183,7 @@ func (ct *costTracker) stop() {
// makeCostList returns upper cost estimates based on the hardcoded cost estimate
// tables and the optionally specified incoming/outgoing bandwidth limits
func (ct *costTracker) makeCostList(globalFactor float64) RequestCostList {
func (ct *costTracker) makeCostList(globalFactor float64) protocol.RequestCostList {
maxCost := func(avgTimeCost, inSize, outSize uint64) uint64 {
cost := avgTimeCost * maxCostFactor
inSizeCost := uint64(float64(inSize) * ct.inSizeFactor * globalFactor)
@ -195,10 +196,10 @@ func (ct *costTracker) makeCostList(globalFactor float64) RequestCostList {
}
return cost
}
var list RequestCostList
var list protocol.RequestCostList
for code, data := range reqAvgTimeCost {
baseCost := maxCost(data.baseCost, reqMaxInSize[code].baseCost, reqMaxOutSize[code].baseCost)
reqCost := maxCost(data.reqCost, reqMaxInSize[code].reqCost, reqMaxOutSize[code].reqCost)
baseCost := maxCost(data.BaseCost, reqMaxInSize[code].BaseCost, reqMaxOutSize[code].BaseCost)
reqCost := maxCost(data.ReqCost, reqMaxInSize[code].ReqCost, reqMaxOutSize[code].ReqCost)
if ct.minBufLimit != 0 {
// if minBufLimit is set then always enforce maximum request cost <= minBufLimit
maxCost := baseCost + reqCost*minBufferReqAmount[code]
@ -209,7 +210,7 @@ func (ct *costTracker) makeCostList(globalFactor float64) RequestCostList {
}
}
list = append(list, requestCostListItem{
list = append(list, protocol.RequestCostListItem{
MsgCode: code,
BaseCost: baseCost,
ReqCost: reqCost,
@ -278,21 +279,21 @@ func (ct *costTracker) gfLoop() {
// Record more metrics if we are debugging
if metrics.EnabledExpensive {
switch r.msgCode {
case GetBlockHeadersMsg:
case protocol.GetBlockHeadersMsg:
relativeCostHeaderHistogram.Update(relCost)
case GetBlockBodiesMsg:
case protocol.GetBlockBodiesMsg:
relativeCostBodyHistogram.Update(relCost)
case GetReceiptsMsg:
case protocol.GetReceiptsMsg:
relativeCostReceiptHistogram.Update(relCost)
case GetCodeMsg:
case protocol.GetCodeMsg:
relativeCostCodeHistogram.Update(relCost)
case GetProofsV2Msg:
case protocol.GetProofsV2Msg:
relativeCostProofHistogram.Update(relCost)
case GetHelperTrieProofsMsg:
case protocol.GetHelperTrieProofsMsg:
relativeCostHelperProofHistogram.Update(relCost)
case SendTxV2Msg:
case protocol.SendTxV2Msg:
relativeCostSendTxHistogram.Update(relCost)
case GetTxStatusMsg:
case protocol.GetTxStatusMsg:
relativeCostTxStatusHistogram.Update(relCost)
}
}
@ -302,7 +303,7 @@ func (ct *costTracker) gfLoop() {
// requests involve txpool query, which is usually unstable.
//
// TODO(rjl493456442) fixes this.
if r.msgCode == SendTxV2Msg || r.msgCode == GetTxStatusMsg {
if r.msgCode == protocol.SendTxV2Msg || r.msgCode == protocol.GetTxStatusMsg {
continue
}
requestServedMeter.Mark(int64(r.servingTime))
@ -410,7 +411,7 @@ func (ct *costTracker) subscribeTotalRecharge(ch chan uint64) uint64 {
// average estimate statistics
func (ct *costTracker) updateStats(code, amount, servingTime, realCost uint64) {
avg := reqAvgTimeCost[code]
avgTimeCost := avg.baseCost + amount*avg.reqCost
avgTimeCost := avg.BaseCost + amount*avg.ReqCost
select {
case ct.reqInfoCh <- reqInfo{float64(avgTimeCost), float64(servingTime), code}:
default:
@ -457,46 +458,9 @@ func (ct *costTracker) printStats() {
}
}
type (
// requestCostTable assigns a cost estimate function to each request type
// which is a linear function of the requested amount
// (cost = baseCost + reqCost * amount)
requestCostTable map[uint64]*requestCosts
requestCosts struct {
baseCost, reqCost uint64
}
// RequestCostList is a list representation of request costs which is used for
// database storage and communication through the network
RequestCostList []requestCostListItem
requestCostListItem struct {
MsgCode, BaseCost, ReqCost uint64
}
)
// getMaxCost calculates the estimated cost for a given request type and amount
func (table requestCostTable) getMaxCost(code, amount uint64) uint64 {
costs := table[code]
return costs.baseCost + amount*costs.reqCost
}
// decode converts a cost list to a cost table
func (list RequestCostList) decode(protocolLength uint64) requestCostTable {
table := make(requestCostTable)
for _, e := range list {
if e.MsgCode < protocolLength {
table[e.MsgCode] = &requestCosts{
baseCost: e.BaseCost,
reqCost: e.ReqCost,
}
}
}
return table
}
// testCostList returns a dummy request cost list used by tests
func testCostList(testCost uint64) RequestCostList {
cl := make(RequestCostList, len(reqAvgTimeCost))
func testCostList(testCost uint64) protocol.RequestCostList {
cl := make(protocol.RequestCostList, len(reqAvgTimeCost))
var max uint64
for code := range reqAvgTimeCost {
if code > max {

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
)
@ -250,7 +251,7 @@ func (f *lightFetcher) unregisterPeer(p *peer) {
// announce processes a new announcement message received from a peer, adding new
// nodes to the peer's block tree and removing old nodes if necessary
func (f *lightFetcher) announce(p *peer, head *announceData) {
func (f *lightFetcher) announce(p *peer, head *protocol.Announcement) {
f.lock.Lock()
defer f.lock.Unlock()
p.Log().Debug("Received new announcement", "number", head.Number, "hash", head.Hash, "reorg", head.ReorgDepth)
@ -519,7 +520,7 @@ func (f *lightFetcher) newFetcherDistReq(bestHash common.Hash, reqID uint64, bes
return &distReq{
getCost: func(dp distPeer) uint64 {
p := dp.(*peer)
return p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount))
return p.GetRequestCost(protocol.GetBlockHeadersMsg, int(bestAmount))
},
canSend: func(dp distPeer) bool {
p := dp.(*peer)
@ -548,7 +549,7 @@ func (f *lightFetcher) newFetcherDistReq(bestHash common.Hash, reqID uint64, bes
}
f.lock.Unlock()
cost := p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount))
cost := p.GetRequestCost(protocol.GetBlockHeadersMsg, int(bestAmount))
p.fcServer.QueuedRequest(reqID, cost)
f.reqMu.Lock()
f.requested[reqID] = fetchRequest{hash: bestHash, amount: bestAmount, peer: p, sent: mclock.Now()}

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
@ -50,8 +51,8 @@ func expectResponse(r p2p.MsgReader, msgcode, reqID, bv uint64, data interface{}
func TestGetBlockHeadersLes2(t *testing.T) { testGetBlockHeaders(t, 2) }
func TestGetBlockHeadersLes3(t *testing.T) { testGetBlockHeaders(t, 3) }
func testGetBlockHeaders(t *testing.T, protocol int) {
server, tearDown := newServerEnv(t, downloader.MaxHashFetch+15, protocol, nil, false, true, 0)
func testGetBlockHeaders(t *testing.T, p int) {
server, tearDown := newServerEnv(t, downloader.MaxHashFetch+15, p, nil, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
@ -62,29 +63,29 @@ func testGetBlockHeaders(t *testing.T, protocol int) {
unknown[i] = byte(i)
}
// Create a batch of tests for various scenarios
limit := uint64(MaxHeaderFetch)
limit := uint64(protocol.MaxHeaderFetch)
tests := []struct {
query *getBlockHeadersData // The query to execute for header retrieval
query *protocol.GetBlockHeadersRequest // The query to execute for header retrieval
expect []common.Hash // The hashes of the block whose headers are expected
}{
// A single random block should be retrievable by hash and number too
{
&getBlockHeadersData{Origin: hashOrNumber{Hash: bc.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Hash: bc.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
[]common.Hash{bc.GetBlockByNumber(limit / 2).Hash()},
}, {
&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: limit / 2}, Amount: 1},
[]common.Hash{bc.GetBlockByNumber(limit / 2).Hash()},
},
// Multiple headers should be retrievable in both directions
{
&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: limit / 2}, Amount: 3},
[]common.Hash{
bc.GetBlockByNumber(limit / 2).Hash(),
bc.GetBlockByNumber(limit/2 + 1).Hash(),
bc.GetBlockByNumber(limit/2 + 2).Hash(),
},
}, {
&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
[]common.Hash{
bc.GetBlockByNumber(limit / 2).Hash(),
bc.GetBlockByNumber(limit/2 - 1).Hash(),
@ -93,14 +94,14 @@ func testGetBlockHeaders(t *testing.T, protocol int) {
},
// Multiple headers with skip lists should be retrievable
{
&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
[]common.Hash{
bc.GetBlockByNumber(limit / 2).Hash(),
bc.GetBlockByNumber(limit/2 + 4).Hash(),
bc.GetBlockByNumber(limit/2 + 8).Hash(),
},
}, {
&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
[]common.Hash{
bc.GetBlockByNumber(limit / 2).Hash(),
bc.GetBlockByNumber(limit/2 - 4).Hash(),
@ -109,26 +110,26 @@ func testGetBlockHeaders(t *testing.T, protocol int) {
},
// The chain endpoints should be retrievable
{
&getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: 0}, Amount: 1},
[]common.Hash{bc.GetBlockByNumber(0).Hash()},
}, {
&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64()}, Amount: 1},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: bc.CurrentBlock().NumberU64()}, Amount: 1},
[]common.Hash{bc.CurrentBlock().Hash()},
},
// Ensure protocol limits are honored
// Ensure p limits are honored
//{
// &getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
// &protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: bc.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
// []common.Hash{},
//},
// Check that requesting more than available is handled gracefully
{
&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
[]common.Hash{
bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 4).Hash(),
bc.GetBlockByNumber(bc.CurrentBlock().NumberU64()).Hash(),
},
}, {
&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
[]common.Hash{
bc.GetBlockByNumber(4).Hash(),
bc.GetBlockByNumber(0).Hash(),
@ -136,13 +137,13 @@ func testGetBlockHeaders(t *testing.T, protocol int) {
},
// Check that requesting more than available is handled gracefully, even if mid skip
{
&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
[]common.Hash{
bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 4).Hash(),
bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1).Hash(),
},
}, {
&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
[]common.Hash{
bc.GetBlockByNumber(4).Hash(),
bc.GetBlockByNumber(1).Hash(),
@ -150,10 +151,10 @@ func testGetBlockHeaders(t *testing.T, protocol int) {
},
// Check that non existing headers aren't returned
{
&getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Hash: unknown}, Amount: 1},
[]common.Hash{},
}, {
&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() + 1}, Amount: 1},
&protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: bc.CurrentBlock().NumberU64() + 1}, Amount: 1},
[]common.Hash{},
},
}
@ -168,9 +169,9 @@ func testGetBlockHeaders(t *testing.T, protocol int) {
// Send the hash request and verify the response
reqID++
cost := server.peer.peer.GetRequestCost(GetBlockHeadersMsg, int(tt.query.Amount))
sendRequest(server.peer.app, GetBlockHeadersMsg, reqID, cost, tt.query)
if err := expectResponse(server.peer.app, BlockHeadersMsg, reqID, testBufLimit, headers); err != nil {
cost := server.peer.peer.GetRequestCost(protocol.GetBlockHeadersMsg, int(tt.query.Amount))
sendRequest(server.peer.app, protocol.GetBlockHeadersMsg, reqID, cost, tt.query)
if err := expectResponse(server.peer.app, protocol.BlockHeadersMsg, reqID, testBufLimit, headers); err != nil {
t.Errorf("test %d: headers mismatch: %v", i, err)
}
}
@ -180,14 +181,14 @@ func testGetBlockHeaders(t *testing.T, protocol int) {
func TestGetBlockBodiesLes2(t *testing.T) { testGetBlockBodies(t, 2) }
func TestGetBlockBodiesLes3(t *testing.T) { testGetBlockBodies(t, 3) }
func testGetBlockBodies(t *testing.T, protocol int) {
server, tearDown := newServerEnv(t, downloader.MaxBlockFetch+15, protocol, nil, false, true, 0)
func testGetBlockBodies(t *testing.T, p int) {
server, tearDown := newServerEnv(t, downloader.MaxBlockFetch+15, p, nil, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
// Create a batch of tests for various scenarios
limit := MaxBodyFetch
limit := protocol.MaxBodyFetch
tests := []struct {
random int // Number of blocks to fetch randomly from the chain
explicit []common.Hash // Explicitly requested blocks
@ -246,9 +247,9 @@ func testGetBlockBodies(t *testing.T, protocol int) {
reqID++
// Send the hash request and verify the response
cost := server.peer.peer.GetRequestCost(GetBlockBodiesMsg, len(hashes))
sendRequest(server.peer.app, GetBlockBodiesMsg, reqID, cost, hashes)
if err := expectResponse(server.peer.app, BlockBodiesMsg, reqID, testBufLimit, bodies); err != nil {
cost := server.peer.peer.GetRequestCost(protocol.GetBlockBodiesMsg, len(hashes))
sendRequest(server.peer.app, protocol.GetBlockBodiesMsg, reqID, cost, hashes)
if err := expectResponse(server.peer.app, protocol.BlockBodiesMsg, reqID, testBufLimit, bodies); err != nil {
t.Errorf("test %d: bodies mismatch: %v", i, err)
}
}
@ -258,19 +259,19 @@ func testGetBlockBodies(t *testing.T, protocol int) {
func TestGetCodeLes2(t *testing.T) { testGetCode(t, 2) }
func TestGetCodeLes3(t *testing.T) { testGetCode(t, 3) }
func testGetCode(t *testing.T, protocol int) {
func testGetCode(t *testing.T, p int) {
// Assemble the test environment
server, tearDown := newServerEnv(t, 4, protocol, nil, false, true, 0)
server, tearDown := newServerEnv(t, 4, p, nil, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
var codereqs []*CodeReq
var codereqs []protocol.CodeRequest
var codes [][]byte
for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ {
header := bc.GetHeaderByNumber(i)
req := &CodeReq{
BHash: header.Hash(),
AccKey: crypto.Keccak256(testContractAddr[:]),
req := protocol.CodeRequest{
BlockHash: header.Hash(),
Account: crypto.Keccak256(testContractAddr[:]),
}
codereqs = append(codereqs, req)
if i >= testContractDeployed {
@ -278,9 +279,9 @@ func testGetCode(t *testing.T, protocol int) {
}
}
cost := server.peer.peer.GetRequestCost(GetCodeMsg, len(codereqs))
sendRequest(server.peer.app, GetCodeMsg, 42, cost, codereqs)
if err := expectResponse(server.peer.app, CodeMsg, 42, testBufLimit, codes); err != nil {
cost := server.peer.peer.GetRequestCost(protocol.GetCodeMsg, len(codereqs))
sendRequest(server.peer.app, protocol.GetCodeMsg, 42, cost, codereqs)
if err := expectResponse(server.peer.app, protocol.CodeMsg, 42, testBufLimit, codes); err != nil {
t.Errorf("codes mismatch: %v", err)
}
}
@ -289,19 +290,19 @@ func testGetCode(t *testing.T, protocol int) {
func TestGetStaleCodeLes2(t *testing.T) { testGetStaleCode(t, 2) }
func TestGetStaleCodeLes3(t *testing.T) { testGetStaleCode(t, 3) }
func testGetStaleCode(t *testing.T, protocol int) {
server, tearDown := newServerEnv(t, core.TriesInMemory+4, protocol, nil, false, true, 0)
func testGetStaleCode(t *testing.T, p int) {
server, tearDown := newServerEnv(t, core.TriesInMemory+4, p, nil, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
check := func(number uint64, expected [][]byte) {
req := &CodeReq{
BHash: bc.GetHeaderByNumber(number).Hash(),
AccKey: crypto.Keccak256(testContractAddr[:]),
req := protocol.CodeRequest{
BlockHash: bc.GetHeaderByNumber(number).Hash(),
Account: crypto.Keccak256(testContractAddr[:]),
}
cost := server.peer.peer.GetRequestCost(GetCodeMsg, 1)
sendRequest(server.peer.app, GetCodeMsg, 42, cost, []*CodeReq{req})
if err := expectResponse(server.peer.app, CodeMsg, 42, testBufLimit, expected); err != nil {
cost := server.peer.peer.GetRequestCost(protocol.GetCodeMsg, 1)
sendRequest(server.peer.app, protocol.GetCodeMsg, 42, cost, []protocol.CodeRequest{req})
if err := expectResponse(server.peer.app, protocol.CodeMsg, 42, testBufLimit, expected); err != nil {
t.Errorf("codes mismatch: %v", err)
}
}
@ -314,9 +315,9 @@ func testGetStaleCode(t *testing.T, protocol int) {
func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) }
func TestGetReceiptLes3(t *testing.T) { testGetReceipt(t, 3) }
func testGetReceipt(t *testing.T, protocol int) {
func testGetReceipt(t *testing.T, p int) {
// Assemble the test environment
server, tearDown := newServerEnv(t, 4, protocol, nil, false, true, 0)
server, tearDown := newServerEnv(t, 4, p, nil, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
@ -331,9 +332,9 @@ func testGetReceipt(t *testing.T, protocol int) {
receipts = append(receipts, rawdb.ReadRawReceipts(server.db, block.Hash(), block.NumberU64()))
}
// Send the hash request and verify the response
cost := server.peer.peer.GetRequestCost(GetReceiptsMsg, len(hashes))
sendRequest(server.peer.app, GetReceiptsMsg, 42, cost, hashes)
if err := expectResponse(server.peer.app, ReceiptsMsg, 42, testBufLimit, receipts); err != nil {
cost := server.peer.peer.GetRequestCost(protocol.GetReceiptsMsg, len(hashes))
sendRequest(server.peer.app, protocol.GetReceiptsMsg, 42, cost, hashes)
if err := expectResponse(server.peer.app, protocol.ReceiptsMsg, 42, testBufLimit, receipts); err != nil {
t.Errorf("receipts mismatch: %v", err)
}
}
@ -342,14 +343,14 @@ func testGetReceipt(t *testing.T, protocol int) {
func TestGetProofsLes2(t *testing.T) { testGetProofs(t, 2) }
func TestGetProofsLes3(t *testing.T) { testGetProofs(t, 3) }
func testGetProofs(t *testing.T, protocol int) {
func testGetProofs(t *testing.T, p int) {
// Assemble the test environment
server, tearDown := newServerEnv(t, 4, protocol, nil, false, true, 0)
server, tearDown := newServerEnv(t, 4, p, nil, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
var proofreqs []ProofReq
var proofreqs []protocol.TrieProofRequest
proofsV2 := light.NewNodeSet()
accounts := []common.Address{bankAddr, userAddr1, userAddr2, signerAddr, {}}
@ -358,8 +359,8 @@ func testGetProofs(t *testing.T, protocol int) {
trie, _ := trie.New(header.Root, trie.NewDatabase(server.db))
for _, acc := range accounts {
req := ProofReq{
BHash: header.Hash(),
req := protocol.TrieProofRequest{
BlockHash: header.Hash(),
Key: crypto.Keccak256(acc[:]),
}
proofreqs = append(proofreqs, req)
@ -367,9 +368,9 @@ func testGetProofs(t *testing.T, protocol int) {
}
}
// Send the proof request and verify the response
cost := server.peer.peer.GetRequestCost(GetProofsV2Msg, len(proofreqs))
sendRequest(server.peer.app, GetProofsV2Msg, 42, cost, proofreqs)
if err := expectResponse(server.peer.app, ProofsV2Msg, 42, testBufLimit, proofsV2.NodeList()); err != nil {
cost := server.peer.peer.GetRequestCost(protocol.GetProofsV2Msg, len(proofreqs))
sendRequest(server.peer.app, protocol.GetProofsV2Msg, 42, cost, proofreqs)
if err := expectResponse(server.peer.app, protocol.ProofsV2Msg, 42, testBufLimit, proofsV2.NodeList()); err != nil {
t.Errorf("proofs mismatch: %v", err)
}
}
@ -378,8 +379,8 @@ func testGetProofs(t *testing.T, protocol int) {
func TestGetStaleProofLes2(t *testing.T) { testGetStaleProof(t, 2) }
func TestGetStaleProofLes3(t *testing.T) { testGetStaleProof(t, 3) }
func testGetStaleProof(t *testing.T, protocol int) {
server, tearDown := newServerEnv(t, core.TriesInMemory+4, protocol, nil, false, true, 0)
func testGetStaleProof(t *testing.T, p int) {
server, tearDown := newServerEnv(t, core.TriesInMemory+4, p, nil, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
@ -388,12 +389,12 @@ func testGetStaleProof(t *testing.T, protocol int) {
header = bc.GetHeaderByNumber(number)
account = crypto.Keccak256(userAddr1.Bytes())
)
req := &ProofReq{
BHash: header.Hash(),
req := &protocol.TrieProofRequest{
BlockHash: header.Hash(),
Key: account,
}
cost := server.peer.peer.GetRequestCost(GetProofsV2Msg, 1)
sendRequest(server.peer.app, GetProofsV2Msg, 42, cost, []*ProofReq{req})
cost := server.peer.peer.GetRequestCost(protocol.GetProofsV2Msg, 1)
sendRequest(server.peer.app, protocol.GetProofsV2Msg, 42, cost, []*protocol.TrieProofRequest{req})
var expected []rlp.RawValue
if wantOK {
@ -402,7 +403,7 @@ func testGetStaleProof(t *testing.T, protocol int) {
t.Prove(account, 0, proofsV2)
expected = proofsV2.NodeList()
}
if err := expectResponse(server.peer.app, ProofsV2Msg, 42, testBufLimit, expected); err != nil {
if err := expectResponse(server.peer.app, protocol.ProofsV2Msg, 42, testBufLimit, expected); err != nil {
t.Errorf("codes mismatch: %v", err)
}
}
@ -415,7 +416,7 @@ func testGetStaleProof(t *testing.T, protocol int) {
func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) }
func TestGetCHTProofsLes3(t *testing.T) { testGetCHTProofs(t, 3) }
func testGetCHTProofs(t *testing.T, protocol int) {
func testGetCHTProofs(t *testing.T, p int) {
config := light.TestServerIndexerConfig
waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) {
@ -427,7 +428,7 @@ func testGetCHTProofs(t *testing.T, protocol int) {
time.Sleep(10 * time.Millisecond)
}
}
server, tearDown := newServerEnv(t, int(config.ChtSize+config.ChtConfirms), protocol, waitIndexers, false, true, 0)
server, tearDown := newServerEnv(t, int(config.ChtSize+config.ChtConfirms), p, waitIndexers, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
@ -439,23 +440,23 @@ func testGetCHTProofs(t *testing.T, protocol int) {
key := make([]byte, 8)
binary.BigEndian.PutUint64(key, config.ChtSize-1)
proofsV2 := HelperTrieResps{
proofsV2 := protocol.HelperTrieResponse{
AuxData: [][]byte{rlp},
}
root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(config.ChtSize-1).Hash())
trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix)))
trie.Prove(key, 0, &proofsV2.Proofs)
// Assemble the requests for the different protocols
requestsV2 := []HelperTrieReq{{
Type: htCanonical,
TrieIdx: 0,
requestsV2 := []protocol.HelperTrieRequest{{
Type: protocol.HelperTrieCHT,
TrieIndex: 0,
Key: key,
AuxReq: auxHeader,
AuxType: protocol.AuxHeader,
}}
// Send the proof request and verify the response
cost := server.peer.peer.GetRequestCost(GetHelperTrieProofsMsg, len(requestsV2))
sendRequest(server.peer.app, GetHelperTrieProofsMsg, 42, cost, requestsV2)
if err := expectResponse(server.peer.app, HelperTrieProofsMsg, 42, testBufLimit, proofsV2); err != nil {
cost := server.peer.peer.GetRequestCost(protocol.GetHelperTrieProofsMsg, len(requestsV2))
sendRequest(server.peer.app, protocol.GetHelperTrieProofsMsg, 42, cost, requestsV2)
if err := expectResponse(server.peer.app, protocol.HelperTrieProofsMsg, 42, testBufLimit, proofsV2); err != nil {
t.Errorf("proofs mismatch: %v", err)
}
}
@ -464,7 +465,7 @@ func TestGetBloombitsProofsLes2(t *testing.T) { testGetBloombitsProofs(t, 2) }
func TestGetBloombitsProofsLes3(t *testing.T) { testGetBloombitsProofs(t, 3) }
// Tests that bloombits proofs can be correctly retrieved.
func testGetBloombitsProofs(t *testing.T, protocol int) {
func testGetBloombitsProofs(t *testing.T, p int) {
config := light.TestServerIndexerConfig
waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) {
@ -476,7 +477,7 @@ func testGetBloombitsProofs(t *testing.T, protocol int) {
time.Sleep(10 * time.Millisecond)
}
}
server, tearDown := newServerEnv(t, int(config.BloomTrieSize+config.BloomTrieConfirms), protocol, waitIndexers, false, true, 0)
server, tearDown := newServerEnv(t, int(config.BloomTrieSize+config.BloomTrieConfirms), p, waitIndexers, false, true, 0)
defer tearDown()
bc := server.handler.blockchain
@ -490,21 +491,21 @@ func testGetBloombitsProofs(t *testing.T, protocol int) {
// Only the first bloom section has data.
binary.BigEndian.PutUint64(key[2:], 0)
requests := []HelperTrieReq{{
Type: htBloomBits,
TrieIdx: 0,
requests := []protocol.HelperTrieRequest{{
Type: protocol.HelperTrieBloomTrie,
TrieIndex: 0,
Key: key,
}}
var proofs HelperTrieResps
var proofs protocol.HelperTrieResponse
root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash())
trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.BloomTrieTablePrefix)))
trie.Prove(key, 0, &proofs.Proofs)
// Send the proof request and verify the response
cost := server.peer.peer.GetRequestCost(GetHelperTrieProofsMsg, len(requests))
sendRequest(server.peer.app, GetHelperTrieProofsMsg, 42, cost, requests)
if err := expectResponse(server.peer.app, HelperTrieProofsMsg, 42, testBufLimit, proofs); err != nil {
cost := server.peer.peer.GetRequestCost(protocol.GetHelperTrieProofsMsg, len(requests))
sendRequest(server.peer.app, protocol.GetHelperTrieProofsMsg, 42, cost, requests)
if err := expectResponse(server.peer.app, protocol.HelperTrieProofsMsg, 42, testBufLimit, proofs); err != nil {
t.Errorf("bit %d: proofs mismatch: %v", bit, err)
}
}
@ -513,8 +514,8 @@ func testGetBloombitsProofs(t *testing.T, protocol int) {
func TestTransactionStatusLes2(t *testing.T) { testTransactionStatus(t, 2) }
func TestTransactionStatusLes3(t *testing.T) { testTransactionStatus(t, 3) }
func testTransactionStatus(t *testing.T, protocol int) {
server, tearDown := newServerEnv(t, 0, protocol, nil, false, true, 0)
func testTransactionStatus(t *testing.T, p int) {
server, tearDown := newServerEnv(t, 0, p, nil, false, true, 0)
defer tearDown()
server.handler.addTxsSync = true
@ -525,13 +526,13 @@ func testTransactionStatus(t *testing.T, protocol int) {
test := func(tx *types.Transaction, send bool, expStatus light.TxStatus) {
reqID++
if send {
cost := server.peer.peer.GetRequestCost(SendTxV2Msg, 1)
sendRequest(server.peer.app, SendTxV2Msg, reqID, cost, types.Transactions{tx})
cost := server.peer.peer.GetRequestCost(protocol.SendTxV2Msg, 1)
sendRequest(server.peer.app, protocol.SendTxV2Msg, reqID, cost, types.Transactions{tx})
} else {
cost := server.peer.peer.GetRequestCost(GetTxStatusMsg, 1)
sendRequest(server.peer.app, GetTxStatusMsg, reqID, cost, []common.Hash{tx.Hash()})
cost := server.peer.peer.GetRequestCost(protocol.GetTxStatusMsg, 1)
sendRequest(server.peer.app, protocol.GetTxStatusMsg, reqID, cost, []common.Hash{tx.Hash()})
}
if err := expectResponse(server.peer.app, TxStatusMsg, reqID, testBufLimit, []light.TxStatus{expStatus}); err != nil {
if err := expectResponse(server.peer.app, protocol.TxStatusMsg, reqID, testBufLimit, []light.TxStatus{expStatus}); err != nil {
t.Errorf("transaction status mismatch")
}
}
@ -620,14 +621,14 @@ func TestStopResumeLes3(t *testing.T) {
header := server.handler.blockchain.CurrentHeader()
req := func() {
reqID++
sendRequest(server.peer.app, GetBlockHeadersMsg, reqID, testCost, &getBlockHeadersData{Origin: hashOrNumber{Hash: header.Hash()}, Amount: 1})
sendRequest(server.peer.app, protocol.GetBlockHeadersMsg, reqID, testCost, &protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Hash: header.Hash()}, Amount: 1})
}
for i := 1; i <= 5; i++ {
// send requests while we still have enough buffer and expect a response
for expBuf >= testCost {
req()
expBuf -= testCost
if err := expectResponse(server.peer.app, BlockHeadersMsg, reqID, expBuf, []*types.Header{header}); err != nil {
if err := expectResponse(server.peer.app, protocol.BlockHeadersMsg, reqID, expBuf, []*types.Header{header}); err != nil {
t.Errorf("expected response and failed: %v", err)
}
}
@ -637,7 +638,7 @@ func TestStopResumeLes3(t *testing.T) {
req()
c--
}
if err := p2p.ExpectMsg(server.peer.app, StopMsg, nil); err != nil {
if err := p2p.ExpectMsg(server.peer.app, protocol.StopMsg, nil); err != nil {
t.Errorf("expected StopMsg and failed: %v", err)
}
// wait until the buffer is recharged by half of the limit
@ -646,7 +647,7 @@ func TestStopResumeLes3(t *testing.T) {
// expect a ResumeMsg with the partially recharged buffer value
expBuf += testBufRecharge * wait
if err := p2p.ExpectMsg(server.peer.app, ResumeMsg, expBuf); err != nil {
if err := p2p.ExpectMsg(server.peer.app, protocol.ResumeMsg, expBuf); err != nil {
t.Errorf("expected ResumeMsg and failed: %v", err)
}
}

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
@ -79,7 +80,7 @@ type BlockRequest light.BlockRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
func (r *BlockRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetBlockBodiesMsg, 1)
return peer.GetRequestCost(protocol.GetBlockBodiesMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
@ -135,7 +136,7 @@ type ReceiptsRequest light.ReceiptsRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
func (r *ReceiptsRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetReceiptsMsg, 1)
return peer.GetRequestCost(protocol.GetReceiptsMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
@ -180,19 +181,13 @@ func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
return nil
}
type ProofReq struct {
BHash common.Hash
AccKey, Key []byte
FromLevel uint
}
// ODR request type for state/storage trie entries, see LesOdrRequest interface
type TrieRequest light.TrieRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
func (r *TrieRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetProofsV2Msg, 1)
return peer.GetRequestCost(protocol.GetProofsV2Msg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
@ -203,12 +198,12 @@ func (r *TrieRequest) CanSend(peer *peer) bool {
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
func (r *TrieRequest) Request(reqID uint64, peer *peer) error {
peer.Log().Debug("Requesting trie proof", "root", r.Id.Root, "key", r.Key)
req := ProofReq{
BHash: r.Id.BlockHash,
AccKey: r.Id.AccKey,
req := protocol.TrieProofRequest{
BlockHash: r.Id.BlockHash,
Account: r.Id.AccKey,
Key: r.Key,
}
return peer.RequestProofs(reqID, r.GetCost(peer), []ProofReq{req})
return peer.RequestProofs(reqID, r.GetCost(peer), []protocol.TrieProofRequest{req})
}
// Valid processes an ODR request reply message from the LES network
@ -235,18 +230,13 @@ func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
return nil
}
type CodeReq struct {
BHash common.Hash
AccKey []byte
}
// ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface
type CodeRequest light.CodeRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
func (r *CodeRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetCodeMsg, 1)
return peer.GetRequestCost(protocol.GetCodeMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
@ -257,11 +247,11 @@ func (r *CodeRequest) CanSend(peer *peer) bool {
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
func (r *CodeRequest) Request(reqID uint64, peer *peer) error {
peer.Log().Debug("Requesting code data", "hash", r.Hash)
req := CodeReq{
BHash: r.Id.BlockHash,
AccKey: r.Id.AccKey,
req := protocol.CodeRequest{
BlockHash: r.Id.BlockHash,
Account: r.Id.AccKey,
}
return peer.RequestCode(reqID, r.GetCost(peer), []CodeReq{req})
return peer.RequestCode(reqID, r.GetCost(peer), []protocol.CodeRequest{req})
}
// Valid processes an ODR request reply message from the LES network
@ -288,36 +278,13 @@ func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error {
return nil
}
const (
// helper trie type constants
htCanonical = iota // Canonical hash trie
htBloomBits // BloomBits trie
// applicable for all helper trie requests
auxRoot = 1
// applicable for htCanonical
auxHeader = 2
)
type HelperTrieReq struct {
Type uint
TrieIdx uint64
Key []byte
FromLevel, AuxReq uint
}
type HelperTrieResps struct { // describes all responses, not just a single one
Proofs light.NodeList
AuxData [][]byte
}
// ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
type ChtRequest light.ChtRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
func (r *ChtRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetHelperTrieProofsMsg, 1)
return peer.GetRequestCost(protocol.GetHelperTrieProofsMsg, 1)
}
// CanSend tells if a certain peer is suitable for serving the given request
@ -337,13 +304,13 @@ func (r *ChtRequest) Request(reqID uint64, peer *peer) error {
peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.BlockNum)
var encNum [8]byte
binary.BigEndian.PutUint64(encNum[:], r.BlockNum)
req := HelperTrieReq{
Type: htCanonical,
TrieIdx: r.ChtNum,
req := protocol.HelperTrieRequest{
Type: protocol.HelperTrieCHT,
TrieIndex: r.ChtNum,
Key: encNum[:],
AuxReq: auxHeader,
AuxType: protocol.AuxHeader,
}
return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req})
return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []protocol.HelperTrieRequest{req})
}
// Valid processes an ODR request reply message from the LES network
@ -355,7 +322,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
if msg.MsgType != MsgHelperTrieProofs {
return errInvalidMessageType
}
resp := msg.Obj.(HelperTrieResps)
resp := msg.Obj.(protocol.HelperTrieResponse)
if len(resp.AuxData) != 1 {
return errInvalidEntryCount
}
@ -404,17 +371,13 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
return nil
}
type BloomReq struct {
BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64
}
// ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
type BloomRequest light.BloomRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
func (r *BloomRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList))
return peer.GetRequestCost(protocol.GetHelperTrieProofsMsg, len(r.SectionIndexList))
}
// CanSend tells if a certain peer is suitable for serving the given request
@ -422,7 +385,7 @@ func (r *BloomRequest) CanSend(peer *peer) bool {
peer.lock.RLock()
defer peer.lock.RUnlock()
if peer.version < lpv2 {
if peer.version < protocol.Lpv2 {
return false
}
return peer.headInfo.Number >= r.Config.BloomTrieConfirms && r.BloomTrieNum <= (peer.headInfo.Number-r.Config.BloomTrieConfirms)/r.Config.BloomTrieSize
@ -431,16 +394,16 @@ func (r *BloomRequest) CanSend(peer *peer) bool {
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
reqs := make([]HelperTrieReq, len(r.SectionIndexList))
reqs := make([]protocol.HelperTrieRequest, len(r.SectionIndexList))
var encNumber [10]byte
binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx))
for i, sectionIdx := range r.SectionIndexList {
binary.BigEndian.PutUint64(encNumber[2:], sectionIdx)
reqs[i] = HelperTrieReq{
Type: htBloomBits,
TrieIdx: r.BloomTrieNum,
reqs[i] = protocol.HelperTrieRequest{
Type: protocol.HelperTrieBloomTrie,
TrieIndex: r.BloomTrieNum,
Key: common.CopyBytes(encNumber[:]),
}
}
@ -457,7 +420,7 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
if msg.MsgType != MsgHelperTrieProofs {
return errInvalidMessageType
}
resps := msg.Obj.(HelperTrieResps)
resps := msg.Obj.(protocol.HelperTrieResponse)
proofs := resps.Proofs
nodeSet := proofs.NodeSet()
reads := &readTraceDB{db: nodeSet}
@ -490,12 +453,12 @@ type TxStatusRequest light.TxStatusRequest
// GetCost returns the cost of the given ODR request according to the serving
// peer's cost table (implementation of LesOdrRequest)
func (r *TxStatusRequest) GetCost(peer *peer) uint64 {
return peer.GetRequestCost(GetTxStatusMsg, len(r.Hashes))
return peer.GetRequestCost(protocol.GetTxStatusMsg, len(r.Hashes))
}
// CanSend tells if a certain peer is suitable for serving the given request
func (r *TxStatusRequest) CanSend(peer *peer) bool {
return peer.version >= lpv2
return peer.version >= protocol.Lpv2
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/les/utilities"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/p2p"
@ -89,7 +90,7 @@ type peer struct {
id string
headInfo *announceData
headInfo *protocol.Announcement
lock sync.RWMutex
sendQueue *utilities.ExecQueue
@ -112,7 +113,7 @@ type peer struct {
fcClient *flowcontrol.ClientNode // nil if the peer is server only
fcServer *flowcontrol.ServerNode // nil if the peer is client only
fcParams flowcontrol.ServerParams
fcCosts requestCostTable
fcCosts protocol.RequestCostTable
trusted, server bool
onlyAnnounce bool
@ -179,7 +180,7 @@ func (p *peer) rejectUpdate(size uint64) bool {
// region. The client is also notified about being frozen/unfrozen with a Stop/Resume
// message.
func (p *peer) freezeClient() {
if p.version < lpv3 {
if p.version < protocol.Lpv3 {
// if Stop/Resume is not supported then just drop the peer after setting
// its frozen status permanently
atomic.StoreUint32(&p.frozen, 1)
@ -258,11 +259,11 @@ func (p *peer) HeadAndTd() (hash common.Hash, td *big.Int) {
return hash, p.headInfo.Td
}
func (p *peer) headBlockInfo() blockInfo {
func (p *peer) headBlockInfo() protocol.HeadHeader {
p.lock.RLock()
defer p.lock.RUnlock()
return blockInfo{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td}
return protocol.HeadHeader{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td}
}
// Td retrieves the current total difficulty of a peer.
@ -286,10 +287,10 @@ func (p *peer) updateCapacity(cap uint64) {
p.fcParams = flowcontrol.ServerParams{MinRecharge: cap, BufLimit: cap * bufLimitRatio}
p.fcClient.UpdateParams(p.fcParams)
var kvList keyValueList
kvList = kvList.add("flowControl/MRR", cap)
kvList = kvList.add("flowControl/BL", cap*bufLimitRatio)
p.queueSend(func() { p.SendAnnounce(announceData{Update: kvList}) })
var kvList protocol.KeyValueList
kvList = kvList.Add("flowControl/MRR", cap)
kvList = kvList.Add("flowControl/BL", cap*bufLimitRatio)
p.queueSend(func() { p.SendAnnounce(protocol.Announcement{Update: kvList}) })
}
func (p *peer) responseID() uint64 {
@ -336,7 +337,7 @@ func (p *peer) GetRequestCost(msgcode uint64, amount int) uint64 {
if costs == nil {
return 0
}
cost := costs.baseCost + costs.reqCost*uint64(amount)
cost := costs.BaseCost + costs.ReqCost*uint64(amount)
if cost > p.fcParams.BufLimit {
cost = p.fcParams.BufLimit
}
@ -347,12 +348,12 @@ func (p *peer) GetTxRelayCost(amount, size int) uint64 {
p.lock.RLock()
defer p.lock.RUnlock()
costs := p.fcCosts[SendTxV2Msg]
costs := p.fcCosts[protocol.SendTxV2Msg]
if costs == nil {
return 0
}
cost := costs.baseCost + costs.reqCost*uint64(amount)
sizeCost := costs.baseCost + costs.reqCost*uint64(size)/txSizeCostLimit
cost := costs.BaseCost + costs.ReqCost*uint64(amount)
sizeCost := costs.BaseCost + costs.ReqCost*uint64(size)/txSizeCostLimit
if sizeCost > cost {
cost = sizeCost
}
@ -385,185 +386,144 @@ func (p *peer) HasBlock(hash common.Hash, number uint64, hasState bool) bool {
// SendAnnounce announces the availability of a number of blocks through
// a hash notification.
func (p *peer) SendAnnounce(request announceData) error {
return p2p.Send(p.rw, AnnounceMsg, request)
func (p *peer) SendAnnounce(request protocol.Announcement) error {
return p2p.Send(p.rw, protocol.AnnounceMsg, request)
}
// SendStop notifies the client about being in frozen state
func (p *peer) SendStop() error {
return p2p.Send(p.rw, StopMsg, struct{}{})
return p2p.Send(p.rw, protocol.StopMsg, struct{}{})
}
// SendResume notifies the client about getting out of frozen state
func (p *peer) SendResume(bv uint64) error {
return p2p.Send(p.rw, ResumeMsg, bv)
return p2p.Send(p.rw, protocol.ResumeMsg, bv)
}
// ReplyBlockHeaders creates a reply with a batch of block headers
func (p *peer) ReplyBlockHeaders(reqID uint64, headers []*types.Header) *reply {
data, _ := rlp.EncodeToBytes(headers)
return &reply{p.rw, BlockHeadersMsg, reqID, data}
return &reply{p.rw, protocol.BlockHeadersMsg, reqID, data}
}
// ReplyBlockBodiesRLP creates a reply with a batch of block contents from
// an already RLP encoded format.
func (p *peer) ReplyBlockBodiesRLP(reqID uint64, bodies []rlp.RawValue) *reply {
data, _ := rlp.EncodeToBytes(bodies)
return &reply{p.rw, BlockBodiesMsg, reqID, data}
return &reply{p.rw, protocol.BlockBodiesMsg, reqID, data}
}
// ReplyCode creates a reply with a batch of arbitrary internal data, corresponding to the
// hashes requested.
func (p *peer) ReplyCode(reqID uint64, codes [][]byte) *reply {
data, _ := rlp.EncodeToBytes(codes)
return &reply{p.rw, CodeMsg, reqID, data}
return &reply{p.rw, protocol.CodeMsg, reqID, data}
}
// ReplyReceiptsRLP creates a reply with a batch of transaction receipts, corresponding to the
// ones requested from an already RLP encoded format.
func (p *peer) ReplyReceiptsRLP(reqID uint64, receipts []rlp.RawValue) *reply {
data, _ := rlp.EncodeToBytes(receipts)
return &reply{p.rw, ReceiptsMsg, reqID, data}
return &reply{p.rw, protocol.ReceiptsMsg, reqID, data}
}
// ReplyProofsV2 creates a reply with a batch of merkle proofs, corresponding to the ones requested.
func (p *peer) ReplyProofsV2(reqID uint64, proofs light.NodeList) *reply {
data, _ := rlp.EncodeToBytes(proofs)
return &reply{p.rw, ProofsV2Msg, reqID, data}
return &reply{p.rw, protocol.ProofsV2Msg, reqID, data}
}
// ReplyHelperTrieProofs creates a reply with a batch of HelperTrie proofs, corresponding to the ones requested.
func (p *peer) ReplyHelperTrieProofs(reqID uint64, resp HelperTrieResps) *reply {
func (p *peer) ReplyHelperTrieProofs(reqID uint64, resp protocol.HelperTrieResponse) *reply {
data, _ := rlp.EncodeToBytes(resp)
return &reply{p.rw, HelperTrieProofsMsg, reqID, data}
return &reply{p.rw, protocol.HelperTrieProofsMsg, reqID, data}
}
// ReplyTxStatus creates a reply with a batch of transaction status records, corresponding to the ones requested.
func (p *peer) ReplyTxStatus(reqID uint64, stats []light.TxStatus) *reply {
data, _ := rlp.EncodeToBytes(stats)
return &reply{p.rw, TxStatusMsg, reqID, data}
return &reply{p.rw, protocol.TxStatusMsg, reqID, data}
}
// RequestHeadersByHash fetches a batch of blocks' headers corresponding to the
// specified header query, based on the hash of an origin block.
func (p *peer) RequestHeadersByHash(reqID, cost uint64, origin common.Hash, amount int, skip int, reverse bool) error {
p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse)
return sendRequest(p.rw, GetBlockHeadersMsg, reqID, cost, &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse})
return sendRequest(p.rw, protocol.GetBlockHeadersMsg, reqID, cost, &protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse})
}
// RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the
// specified header query, based on the number of an origin block.
func (p *peer) RequestHeadersByNumber(reqID, cost, origin uint64, amount int, skip int, reverse bool) error {
p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse)
return sendRequest(p.rw, GetBlockHeadersMsg, reqID, cost, &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse})
return sendRequest(p.rw, protocol.GetBlockHeadersMsg, reqID, cost, &protocol.GetBlockHeadersRequest{Origin: protocol.HashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse})
}
// RequestBodies fetches a batch of blocks' bodies corresponding to the hashes
// specified.
func (p *peer) RequestBodies(reqID, cost uint64, hashes []common.Hash) error {
p.Log().Debug("Fetching batch of block bodies", "count", len(hashes))
return sendRequest(p.rw, GetBlockBodiesMsg, reqID, cost, hashes)
return sendRequest(p.rw, protocol.GetBlockBodiesMsg, reqID, cost, hashes)
}
// RequestCode fetches a batch of arbitrary data from a node's known state
// data, corresponding to the specified hashes.
func (p *peer) RequestCode(reqID, cost uint64, reqs []CodeReq) error {
func (p *peer) RequestCode(reqID, cost uint64, reqs []protocol.CodeRequest) error {
p.Log().Debug("Fetching batch of codes", "count", len(reqs))
return sendRequest(p.rw, GetCodeMsg, reqID, cost, reqs)
return sendRequest(p.rw, protocol.GetCodeMsg, reqID, cost, reqs)
}
// RequestReceipts fetches a batch of transaction receipts from a remote node.
func (p *peer) RequestReceipts(reqID, cost uint64, hashes []common.Hash) error {
p.Log().Debug("Fetching batch of receipts", "count", len(hashes))
return sendRequest(p.rw, GetReceiptsMsg, reqID, cost, hashes)
return sendRequest(p.rw, protocol.GetReceiptsMsg, reqID, cost, hashes)
}
// RequestProofs fetches a batch of merkle proofs from a remote node.
func (p *peer) RequestProofs(reqID, cost uint64, reqs []ProofReq) error {
func (p *peer) RequestProofs(reqID, cost uint64, reqs []protocol.TrieProofRequest) error {
p.Log().Debug("Fetching batch of proofs", "count", len(reqs))
return sendRequest(p.rw, GetProofsV2Msg, reqID, cost, reqs)
return sendRequest(p.rw, protocol.GetProofsV2Msg, reqID, cost, reqs)
}
// RequestHelperTrieProofs fetches a batch of HelperTrie merkle proofs from a remote node.
func (p *peer) RequestHelperTrieProofs(reqID, cost uint64, reqs []HelperTrieReq) error {
func (p *peer) RequestHelperTrieProofs(reqID, cost uint64, reqs []protocol.HelperTrieRequest) error {
p.Log().Debug("Fetching batch of HelperTrie proofs", "count", len(reqs))
return sendRequest(p.rw, GetHelperTrieProofsMsg, reqID, cost, reqs)
return sendRequest(p.rw, protocol.GetHelperTrieProofsMsg, reqID, cost, reqs)
}
// RequestTxStatus fetches a batch of transaction status records from a remote node.
func (p *peer) RequestTxStatus(reqID, cost uint64, txHashes []common.Hash) error {
p.Log().Debug("Requesting transaction status", "count", len(txHashes))
return sendRequest(p.rw, GetTxStatusMsg, reqID, cost, txHashes)
return sendRequest(p.rw, protocol.GetTxStatusMsg, reqID, cost, txHashes)
}
// SendTxStatus creates a reply with a batch of transactions to be added to the remote transaction pool.
func (p *peer) SendTxs(reqID, cost uint64, txs rlp.RawValue) error {
p.Log().Debug("Sending batch of transactions", "size", len(txs))
return sendRequest(p.rw, SendTxV2Msg, reqID, cost, txs)
return sendRequest(p.rw, protocol.SendTxV2Msg, reqID, cost, txs)
}
type keyValueEntry struct {
Key string
Value rlp.RawValue
}
type keyValueList []keyValueEntry
type keyValueMap map[string]rlp.RawValue
func (l keyValueList) add(key string, val interface{}) keyValueList {
var entry keyValueEntry
entry.Key = key
if val == nil {
val = uint64(0)
}
enc, err := rlp.EncodeToBytes(val)
if err == nil {
entry.Value = enc
}
return append(l, entry)
}
func (l keyValueList) decode() (keyValueMap, uint64) {
m := make(keyValueMap)
var size uint64
for _, entry := range l {
m[entry.Key] = entry.Value
size += uint64(len(entry.Key)) + uint64(len(entry.Value)) + 8
}
return m, size
}
func (m keyValueMap) get(key string, val interface{}) error {
enc, ok := m[key]
if !ok {
return errResp(ErrMissingKey, "%s", key)
}
if val == nil {
return nil
}
return rlp.DecodeBytes(enc, val)
}
func (p *peer) sendReceiveHandshake(sendList keyValueList) (keyValueList, error) {
func (p *peer) sendReceiveHandshake(sendList protocol.KeyValueList) (protocol.KeyValueList, error) {
// Send out own handshake in a new thread
errc := make(chan error, 1)
go func() {
errc <- p2p.Send(p.rw, StatusMsg, sendList)
errc <- p2p.Send(p.rw, protocol.StatusMsg, sendList)
}()
// In the mean time retrieve the remote status message
msg, err := p.rw.ReadMsg()
if err != nil {
return nil, err
}
if msg.Code != StatusMsg {
return nil, errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg)
if msg.Code != protocol.StatusMsg {
return nil, protocol.ErrResp(protocol.ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, protocol.StatusMsg)
}
if msg.Size > ProtocolMaxMsgSize {
return nil, errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
if msg.Size > protocol.ProtocolMaxMsgSize {
return nil, protocol.ErrResp(protocol.ErrMsgTooLarge, "%v > %v", msg.Size, protocol.ProtocolMaxMsgSize)
}
// Decode the handshake
var recvList keyValueList
var recvList protocol.KeyValueList
if err := msg.Decode(&recvList); err != nil {
return nil, errResp(ErrDecode, "msg %v: %v", msg, err)
return nil, protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
if err := <-errc; err != nil {
return nil, err
@ -577,21 +537,21 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
p.lock.Lock()
defer p.lock.Unlock()
var send keyValueList
var send protocol.KeyValueList
// Add some basic handshake fields
send = send.add("protocolVersion", uint64(p.version))
send = send.add("networkId", p.network)
send = send.add("headTd", td)
send = send.add("headHash", head)
send = send.add("headNum", headNum)
send = send.add("genesisHash", genesis)
send = send.Add("protocolVersion", uint64(p.version))
send = send.Add("networkId", p.network)
send = send.Add("headTd", td)
send = send.Add("headHash", head)
send = send.Add("headNum", headNum)
send = send.Add("genesisHash", genesis)
if server != nil {
// Add some information which services server can offer.
if !server.config.UltraLightOnlyAnnounce {
send = send.add("serveHeaders", nil)
send = send.add("serveChainSince", uint64(0))
send = send.add("serveStateSince", uint64(0))
send = send.Add("serveHeaders", nil)
send = send.Add("serveChainSince", uint64(0))
send = send.Add("serveStateSince", uint64(0))
// If local ethereum node is running in archive mode, advertise ourselves we have
// all version state data. Otherwise only recent state is available.
@ -599,20 +559,20 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
if server.archiveMode {
stateRecent = 0
}
send = send.add("serveRecentState", stateRecent)
send = send.add("txRelay", nil)
send = send.Add("serveRecentState", stateRecent)
send = send.Add("txRelay", nil)
}
send = send.add("flowControl/BL", server.defParams.BufLimit)
send = send.add("flowControl/MRR", server.defParams.MinRecharge)
send = send.Add("flowControl/BL", server.defParams.BufLimit)
send = send.Add("flowControl/MRR", server.defParams.MinRecharge)
var costList RequestCostList
var costList protocol.RequestCostList
if server.costTracker.testCostList != nil {
costList = server.costTracker.testCostList
} else {
costList = server.costTracker.makeCostList(server.costTracker.globalFactor())
}
send = send.add("flowControl/MRC", costList)
p.fcCosts = costList.decode(ProtocolLengths[uint(p.version)])
send = send.Add("flowControl/MRC", costList)
p.fcCosts = costList.ToTable(protocol.ProtocolLengths[uint(p.version)])
p.fcParams = server.defParams
// Add advertised checkpoint and register block height which
@ -620,8 +580,8 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
if server.oracle != nil && server.oracle.IsRunning() {
cp, height := server.oracle.StableCheckpoint()
if cp != nil {
send = send.add("checkpoint/value", cp)
send = send.add("checkpoint/registerHeight", height)
send = send.Add("checkpoint/value", cp)
send = send.Add("checkpoint/registerHeight", height)
}
}
} else {
@ -630,130 +590,136 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
if p.trusted {
p.announceType = announceTypeSigned
}
send = send.add("announceType", p.announceType)
send = send.Add("announceType", p.announceType)
}
recvList, err := p.sendReceiveHandshake(send)
if err != nil {
return err
}
recv, size := recvList.decode()
recv, size := recvList.ToMap()
if p.rejectUpdate(size) {
return errResp(ErrRequestRejected, "")
return protocol.ErrResp(protocol.ErrRequestRejected, "")
}
var rGenesis, rHash common.Hash
var rVersion, rNetwork, rNum uint64
var rTd *big.Int
if err := recv.get("protocolVersion", &rVersion); err != nil {
if err := recv.Get("protocolVersion", &rVersion); err != nil {
return err
}
if err := recv.get("networkId", &rNetwork); err != nil {
if err := recv.Get("networkId", &rNetwork); err != nil {
return err
}
if err := recv.get("headTd", &rTd); err != nil {
if err := recv.Get("headTd", &rTd); err != nil {
return err
}
if err := recv.get("headHash", &rHash); err != nil {
if err := recv.Get("headHash", &rHash); err != nil {
return err
}
if err := recv.get("headNum", &rNum); err != nil {
if err := recv.Get("headNum", &rNum); err != nil {
return err
}
if err := recv.get("genesisHash", &rGenesis); err != nil {
if err := recv.Get("genesisHash", &rGenesis); err != nil {
return err
}
if rGenesis != genesis {
return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", rGenesis[:8], genesis[:8])
return protocol.ErrResp(protocol.ErrGenesisBlockMismatch, "%x (!= %x)", rGenesis[:8], genesis[:8])
}
if rNetwork != p.network {
return errResp(ErrNetworkIdMismatch, "%d (!= %d)", rNetwork, p.network)
return protocol.ErrResp(protocol.ErrNetworkIdMismatch, "%d (!= %d)", rNetwork, p.network)
}
if int(rVersion) != p.version {
return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", rVersion, p.version)
return protocol.ErrResp(protocol.ErrProtocolVersionMismatch, "%d (!= %d)", rVersion, p.version)
}
if server != nil {
p.server = recv.get("flowControl/MRR", nil) == nil
p.server = recv.Get("flowControl/MRR", nil) == nil
if p.server {
p.announceType = announceTypeNone // connected to another server, send no messages
} else {
if recv.get("announceType", &p.announceType) != nil {
if recv.Get("announceType", &p.announceType) != nil {
// set default announceType on server side
p.announceType = announceTypeSimple
}
p.fcClient = flowcontrol.NewClientNode(server.fcManager, server.defParams)
}
} else {
if recv.get("serveChainSince", &p.chainSince) != nil {
if recv.Get("serveChainSince", &p.chainSince) != nil {
p.onlyAnnounce = true
}
if recv.get("serveRecentChain", &p.chainRecent) != nil {
if recv.Get("serveRecentChain", &p.chainRecent) != nil {
p.chainRecent = 0
}
if recv.get("serveStateSince", &p.stateSince) != nil {
if recv.Get("serveStateSince", &p.stateSince) != nil {
p.onlyAnnounce = true
}
if recv.get("serveRecentState", &p.stateRecent) != nil {
if recv.Get("serveRecentState", &p.stateRecent) != nil {
p.stateRecent = 0
}
if recv.get("txRelay", nil) != nil {
if recv.Get("txRelay", nil) != nil {
p.onlyAnnounce = true
}
if p.onlyAnnounce && !p.trusted {
return errResp(ErrUselessPeer, "peer cannot serve requests")
return protocol.ErrResp(protocol.ErrUselessPeer, "peer cannot serve requests")
}
var sParams flowcontrol.ServerParams
if err := recv.get("flowControl/BL", &sParams.BufLimit); err != nil {
if err := recv.Get("flowControl/BL", &sParams.BufLimit); err != nil {
return err
}
if err := recv.get("flowControl/MRR", &sParams.MinRecharge); err != nil {
if err := recv.Get("flowControl/MRR", &sParams.MinRecharge); err != nil {
return err
}
var MRC RequestCostList
if err := recv.get("flowControl/MRC", &MRC); err != nil {
var MRC protocol.RequestCostList
if err := recv.Get("flowControl/MRC", &MRC); err != nil {
return err
}
p.fcParams = sParams
p.fcServer = flowcontrol.NewServerNode(sParams, &mclock.System{})
p.fcCosts = MRC.decode(ProtocolLengths[uint(p.version)])
p.fcCosts = MRC.ToTable(protocol.ProtocolLengths[uint(p.version)])
recv.get("checkpoint/value", &p.checkpoint)
recv.get("checkpoint/registerHeight", &p.checkpointNumber)
recv.Get("checkpoint/value", &p.checkpoint)
recv.Get("checkpoint/registerHeight", &p.checkpointNumber)
if !p.onlyAnnounce {
for msgCode := range reqAvgTimeCost {
if p.fcCosts[msgCode] == nil {
return errResp(ErrUselessPeer, "peer does not support message %d", msgCode)
return protocol.ErrResp(protocol.ErrUselessPeer, "peer does not support message %d", msgCode)
}
}
}
p.server = true
}
p.headInfo = &announceData{Td: rTd, Hash: rHash, Number: rNum}
p.headInfo = &protocol.Announcement{
HeadHeader: protocol.HeadHeader{
Td: rTd,
Hash: rHash,
Number: rNum,
},
}
return nil
}
// updateFlowControl updates the flow control parameters belonging to the server
// node if the announced key/value set contains relevant fields
func (p *peer) updateFlowControl(update keyValueMap) {
func (p *peer) updateFlowControl(update protocol.KeyValueMap) {
if p.fcServer == nil {
return
}
// If any of the flow control params is nil, refuse to update.
var params flowcontrol.ServerParams
if update.get("flowControl/BL", &params.BufLimit) == nil && update.get("flowControl/MRR", &params.MinRecharge) == nil {
if update.Get("flowControl/BL", &params.BufLimit) == nil && update.Get("flowControl/MRR", &params.MinRecharge) == nil {
// todo can light client set a minimal acceptable flow control params?
p.fcParams = params
p.fcServer.UpdateParams(params)
}
var MRC RequestCostList
if update.get("flowControl/MRC", &MRC) == nil {
costUpdate := MRC.decode(ProtocolLengths[uint(p.version)])
var MRC protocol.RequestCostList
if update.Get("flowControl/MRC", &MRC) == nil {
costUpdate := MRC.ToTable(protocol.ProtocolLengths[uint(p.version)])
for code, cost := range costUpdate {
p.fcCosts[code] = cost
}

View file

@ -27,12 +27,13 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/rlp"
)
const protocolVersion = lpv2
const protocolVersion = protocol.Lpv2
var (
hash = common.HexToHash("deadbeef")
@ -59,10 +60,10 @@ func TestPeerHandshakeSetAnnounceTypeToAnnounceTypeSignedForTrustedPeer(t *testi
version: protocolVersion,
trusted: true,
rw: &rwStub{
WriteHook: func(recvList keyValueList) {
recv, _ := recvList.decode()
WriteHook: func(recvList protocol.KeyValueList) {
recv, _ := recvList.ToMap()
var reqType uint64
err := recv.get("announceType", &reqType)
err := recv.Get("announceType", &reqType)
if err != nil {
t.Fatal(err)
}
@ -70,18 +71,18 @@ func TestPeerHandshakeSetAnnounceTypeToAnnounceTypeSignedForTrustedPeer(t *testi
t.Fatal("Expected announceTypeSigned")
}
},
ReadHook: func(l keyValueList) keyValueList {
l = l.add("serveHeaders", nil)
l = l.add("serveChainSince", uint64(0))
l = l.add("serveStateSince", uint64(0))
l = l.add("txRelay", nil)
l = l.add("flowControl/BL", uint64(0))
l = l.add("flowControl/MRR", uint64(0))
l = l.add("flowControl/MRC", testCostList(0))
ReadHook: func(l protocol.KeyValueList) protocol.KeyValueList {
l = l.Add("serveHeaders", nil)
l = l.Add("serveChainSince", uint64(0))
l = l.Add("serveStateSince", uint64(0))
l = l.Add("txRelay", nil)
l = l.Add("flowControl/BL", uint64(0))
l = l.Add("flowControl/MRR", uint64(0))
l = l.Add("flowControl/MRC", testCostList(0))
return l
},
},
network: NetworkId,
network: protocol.NetworkId,
}
err := p.Handshake(td, hash, headNum, genesis, nil)
if err != nil {
@ -98,11 +99,11 @@ func TestPeerHandshakeAnnounceTypeSignedForTrustedPeersPeerNotInTrusted(t *testi
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocolVersion,
rw: &rwStub{
WriteHook: func(recvList keyValueList) {
WriteHook: func(recvList protocol.KeyValueList) {
// checking that ulc sends to peer allowedRequests=noRequests and announceType != announceTypeSigned
recv, _ := recvList.decode()
recv, _ := recvList.ToMap()
var reqType uint64
err := recv.get("announceType", &reqType)
err := recv.Get("announceType", &reqType)
if err != nil {
t.Fatal(err)
}
@ -110,18 +111,18 @@ func TestPeerHandshakeAnnounceTypeSignedForTrustedPeersPeerNotInTrusted(t *testi
t.Fatal("Expected not announceTypeSigned")
}
},
ReadHook: func(l keyValueList) keyValueList {
l = l.add("serveHeaders", nil)
l = l.add("serveChainSince", uint64(0))
l = l.add("serveStateSince", uint64(0))
l = l.add("txRelay", nil)
l = l.add("flowControl/BL", uint64(0))
l = l.add("flowControl/MRR", uint64(0))
l = l.add("flowControl/MRC", testCostList(0))
ReadHook: func(l protocol.KeyValueList) protocol.KeyValueList {
l = l.Add("serveHeaders", nil)
l = l.Add("serveChainSince", uint64(0))
l = l.Add("serveStateSince", uint64(0))
l = l.Add("txRelay", nil)
l = l.Add("flowControl/BL", uint64(0))
l = l.Add("flowControl/MRR", uint64(0))
l = l.Add("flowControl/MRC", testCostList(0))
return l
},
},
network: NetworkId,
network: protocol.NetworkId,
}
err := p.Handshake(td, hash, headNum, genesis, nil)
if err != nil {
@ -141,13 +142,13 @@ func TestPeerHandshakeDefaultAllRequests(t *testing.T) {
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocolVersion,
rw: &rwStub{
ReadHook: func(l keyValueList) keyValueList {
l = l.add("announceType", uint64(announceTypeSigned))
l = l.add("allowedRequests", uint64(0))
ReadHook: func(l protocol.KeyValueList) protocol.KeyValueList {
l = l.Add("announceType", uint64(announceTypeSigned))
l = l.Add("allowedRequests", uint64(0))
return l
},
},
network: NetworkId,
network: protocol.NetworkId,
}
err := p.Handshake(td, hash, headNum, genesis, s)
@ -170,11 +171,11 @@ func TestPeerHandshakeServerSendOnlyAnnounceRequestsHeaders(t *testing.T) {
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocolVersion,
rw: &rwStub{
ReadHook: func(l keyValueList) keyValueList {
l = l.add("announceType", uint64(announceTypeSigned))
ReadHook: func(l protocol.KeyValueList) protocol.KeyValueList {
l = l.Add("announceType", uint64(announceTypeSigned))
return l
},
WriteHook: func(l keyValueList) {
WriteHook: func(l protocol.KeyValueList) {
for _, v := range l {
if v.Key == "serveHeaders" ||
v.Key == "serveChainSince" ||
@ -185,7 +186,7 @@ func TestPeerHandshakeServerSendOnlyAnnounceRequestsHeaders(t *testing.T) {
}
},
},
network: NetworkId,
network: protocol.NetworkId,
}
err := p.Handshake(td, hash, headNum, genesis, s)
@ -200,17 +201,17 @@ func TestPeerHandshakeClientReceiveOnlyAnnounceRequestsHeaders(t *testing.T) {
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocolVersion,
rw: &rwStub{
ReadHook: func(l keyValueList) keyValueList {
l = l.add("flowControl/BL", uint64(0))
l = l.add("flowControl/MRR", uint64(0))
l = l.add("flowControl/MRC", RequestCostList{})
ReadHook: func(l protocol.KeyValueList) protocol.KeyValueList {
l = l.Add("flowControl/BL", uint64(0))
l = l.Add("flowControl/MRR", uint64(0))
l = l.Add("flowControl/MRC", protocol.RequestCostList{})
l = l.add("announceType", uint64(announceTypeSigned))
l = l.Add("announceType", uint64(announceTypeSigned))
return l
},
},
network: NetworkId,
network: protocol.NetworkId,
trusted: true,
}
@ -231,15 +232,15 @@ func TestPeerHandshakeClientReturnErrorOnUselessPeer(t *testing.T) {
Peer: p2p.NewPeer(id, "test peer", []p2p.Cap{}),
version: protocolVersion,
rw: &rwStub{
ReadHook: func(l keyValueList) keyValueList {
l = l.add("flowControl/BL", uint64(0))
l = l.add("flowControl/MRR", uint64(0))
l = l.add("flowControl/MRC", RequestCostList{})
l = l.add("announceType", uint64(announceTypeSigned))
ReadHook: func(l protocol.KeyValueList) protocol.KeyValueList {
l = l.Add("flowControl/BL", uint64(0))
l = l.Add("flowControl/MRR", uint64(0))
l = l.Add("flowControl/MRC", protocol.RequestCostList{})
l = l.Add("announceType", uint64(announceTypeSigned))
return l
},
},
network: NetworkId,
network: protocol.NetworkId,
}
err := p.Handshake(td, hash, headNum, genesis, nil)
@ -264,18 +265,18 @@ func generateLesServer() *LesServer {
}
type rwStub struct {
ReadHook func(l keyValueList) keyValueList
WriteHook func(l keyValueList)
ReadHook func(l protocol.KeyValueList) protocol.KeyValueList
WriteHook func(l protocol.KeyValueList)
}
func (s *rwStub) ReadMsg() (p2p.Msg, error) {
payload := keyValueList{}
payload = payload.add("protocolVersion", uint64(protocolVersion))
payload = payload.add("networkId", uint64(NetworkId))
payload = payload.add("headTd", td)
payload = payload.add("headHash", hash)
payload = payload.add("headNum", headNum)
payload = payload.add("genesisHash", genesis)
payload := protocol.KeyValueList{}
payload = payload.Add("protocolVersion", uint64(protocolVersion))
payload = payload.Add("networkId", uint64(protocol.NetworkId))
payload = payload.Add("headTd", td)
payload = payload.Add("headHash", hash)
payload = payload.Add("headNum", headNum)
payload = payload.Add("genesisHash", genesis)
if s.ReadHook != nil {
payload = s.ReadHook(payload)
@ -291,7 +292,7 @@ func (s *rwStub) ReadMsg() (p2p.Msg, error) {
}
func (s *rwStub) WriteMsg(m p2p.Msg) error {
recvList := keyValueList{}
recvList := protocol.KeyValueList{}
if err := m.Decode(&recvList); err != nil {
return err
}

View file

@ -1,237 +0,0 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package les
import (
"crypto/ecdsa"
"errors"
"fmt"
"io"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/rlp"
)
// Constants to match up protocol versions and messages
const (
lpv2 = 2
lpv3 = 3
)
// Supported versions of the les protocol (first is primary)
var (
ClientProtocolVersions = []uint{lpv2, lpv3}
ServerProtocolVersions = []uint{lpv2, lpv3}
AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list
)
// Number of implemented message corresponding to different protocol versions.
var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24}
const (
NetworkId = 1
ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message
)
// les protocol message codes
const (
// Protocol messages inherited from LPV1
StatusMsg = 0x00
AnnounceMsg = 0x01
GetBlockHeadersMsg = 0x02
BlockHeadersMsg = 0x03
GetBlockBodiesMsg = 0x04
BlockBodiesMsg = 0x05
GetReceiptsMsg = 0x06
ReceiptsMsg = 0x07
GetCodeMsg = 0x0a
CodeMsg = 0x0b
// Protocol messages introduced in LPV2
GetProofsV2Msg = 0x0f
ProofsV2Msg = 0x10
GetHelperTrieProofsMsg = 0x11
HelperTrieProofsMsg = 0x12
SendTxV2Msg = 0x13
GetTxStatusMsg = 0x14
TxStatusMsg = 0x15
// Protocol messages introduced in LPV3
StopMsg = 0x16
ResumeMsg = 0x17
)
type requestInfo struct {
name string
maxCount uint64
}
var requests = map[uint64]requestInfo{
GetBlockHeadersMsg: {"GetBlockHeaders", MaxHeaderFetch},
GetBlockBodiesMsg: {"GetBlockBodies", MaxBodyFetch},
GetReceiptsMsg: {"GetReceipts", MaxReceiptFetch},
GetCodeMsg: {"GetCode", MaxCodeFetch},
GetProofsV2Msg: {"GetProofsV2", MaxProofsFetch},
GetHelperTrieProofsMsg: {"GetHelperTrieProofs", MaxHelperTrieProofsFetch},
SendTxV2Msg: {"SendTxV2", MaxTxSend},
GetTxStatusMsg: {"GetTxStatus", MaxTxStatus},
}
type errCode int
const (
ErrMsgTooLarge = iota
ErrDecode
ErrInvalidMsgCode
ErrProtocolVersionMismatch
ErrNetworkIdMismatch
ErrGenesisBlockMismatch
ErrNoStatusMsg
ErrExtraStatusMsg
ErrSuspendedPeer
ErrUselessPeer
ErrRequestRejected
ErrUnexpectedResponse
ErrInvalidResponse
ErrTooManyTimeouts
ErrMissingKey
)
func (e errCode) String() string {
return errorToString[int(e)]
}
// XXX change once legacy code is out
var errorToString = map[int]string{
ErrMsgTooLarge: "Message too long",
ErrDecode: "Invalid message",
ErrInvalidMsgCode: "Invalid message code",
ErrProtocolVersionMismatch: "Protocol version mismatch",
ErrNetworkIdMismatch: "NetworkId mismatch",
ErrGenesisBlockMismatch: "Genesis block mismatch",
ErrNoStatusMsg: "No status message",
ErrExtraStatusMsg: "Extra status message",
ErrSuspendedPeer: "Suspended peer",
ErrRequestRejected: "Request rejected",
ErrUnexpectedResponse: "Unexpected response",
ErrInvalidResponse: "Invalid response",
ErrTooManyTimeouts: "Too many request timeouts",
ErrMissingKey: "Key missing from list",
}
type announceBlock struct {
Hash common.Hash // Hash of one particular block being announced
Number uint64 // Number of one particular block being announced
Td *big.Int // Total difficulty of one particular block being announced
}
// announceData is the network packet for the block announcements.
type announceData struct {
Hash common.Hash // Hash of one particular block being announced
Number uint64 // Number of one particular block being announced
Td *big.Int // Total difficulty of one particular block being announced
ReorgDepth uint64
Update keyValueList
}
// sanityCheck verifies that the values are reasonable, as a DoS protection
func (a *announceData) sanityCheck() error {
if tdlen := a.Td.BitLen(); tdlen > 100 {
return fmt.Errorf("too large block TD: bitlen %d", tdlen)
}
return nil
}
// sign adds a signature to the block announcement by the given privKey
func (a *announceData) sign(privKey *ecdsa.PrivateKey) {
rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey)
a.Update = a.Update.add("sign", sig)
}
// checkSignature verifies if the block announcement has a valid signature by the given pubKey
func (a *announceData) checkSignature(id enode.ID, update keyValueMap) error {
var sig []byte
if err := update.get("sign", &sig); err != nil {
return err
}
rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
recPubkey, err := crypto.SigToPub(crypto.Keccak256(rlp), sig)
if err != nil {
return err
}
if id == enode.PubkeyToIDV4(recPubkey) {
return nil
}
return errors.New("wrong signature")
}
type blockInfo struct {
Hash common.Hash // Hash of one particular block being announced
Number uint64 // Number of one particular block being announced
Td *big.Int // Total difficulty of one particular block being announced
}
// getBlockHeadersData represents a block header query.
type getBlockHeadersData struct {
Origin hashOrNumber // Block from which to retrieve headers
Amount uint64 // Maximum number of headers to retrieve
Skip uint64 // Blocks to skip between consecutive headers
Reverse bool // Query direction (false = rising towards latest, true = falling towards genesis)
}
// hashOrNumber is a combined field for specifying an origin block.
type hashOrNumber struct {
Hash common.Hash // Block hash from which to retrieve headers (excludes Number)
Number uint64 // Block hash from which to retrieve headers (excludes Hash)
}
// EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the
// two contained union fields.
func (hn *hashOrNumber) EncodeRLP(w io.Writer) error {
if hn.Hash == (common.Hash{}) {
return rlp.Encode(w, hn.Number)
}
if hn.Number != 0 {
return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
}
return rlp.Encode(w, hn.Hash)
}
// DecodeRLP is a specialized decoder for hashOrNumber to decode the contents
// into either a block hash or a block number.
func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error {
_, size, _ := s.Kind()
origin, err := s.Raw()
if err == nil {
switch {
case size == 32:
err = rlp.DecodeBytes(origin, &hn.Hash)
case size <= 8:
err = rlp.DecodeBytes(origin, &hn.Number)
default:
err = fmt.Errorf("invalid input size %d for origin", size)
}
}
return err
}
// CodeData is the network response packet for a node data retrieval.
type CodeData []struct {
Value []byte
}

View file

@ -0,0 +1,86 @@
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package protocol
import (
"errors"
"github.com/ethereum/go-ethereum/rlp"
)
// ErrNonexistentEntry is returned if the specified key is non-existent.
var ErrNonexistentEntry = errors.New("the entry is non-existent")
// KeyValueEntry is the entry contained in a List or Map
// which can be extended with no limitaion.
type KeyValueEntry struct {
Key string
Value rlp.RawValue
}
// KeyValueList is a set of entries in list format.
//
// Usually KeyValueList is used as the container for
// protocol handshake.
type KeyValueList []KeyValueEntry
// KeyValueMap is a set of entires in map format.
// All entires is identified with its key and saved
// in RLP-encoded format.
//
// Usually KeyValueMap is used as the container for
// protocol handshake.
type KeyValueMap map[string]rlp.RawValue
// Add adds a new entry with specified key and value into list.
func (l KeyValueList) Add(key string, val interface{}) KeyValueList {
var entry KeyValueEntry
entry.Key = key
if val == nil {
val = uint64(0) // Use empty uint64 as default value
}
enc, err := rlp.EncodeToBytes(val)
if err == nil {
entry.Value = enc
}
return append(l, entry)
}
// ToMap converts list format to map format. Also returns
// the total size of converted map.
func (l KeyValueList) ToMap() (KeyValueMap, uint64) {
m := make(KeyValueMap)
var size uint64
for _, entry := range l {
m[entry.Key] = entry.Value
size += uint64(len(entry.Key)) + uint64(len(entry.Value)) + 8
}
return m, size
}
// Get retrieves contained entry with specified key, decode the
// retrieved data in the provided container(interface).
func (m KeyValueMap) Get(key string, val interface{}) error {
enc, ok := m[key]
if !ok {
return ErrNonexistentEntry
}
if val == nil {
return nil
}
return rlp.DecodeBytes(enc, val)
}

View file

@ -0,0 +1,47 @@
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package protocol
import (
"testing"
"github.com/ethereum/go-ethereum/rlp"
)
func TestKeyValueSet(t *testing.T) {
var cases = []struct {
key string
value interface{}
}{
// {"key1", uint64(10)},
{"key2", false},
{"key3", nil},
}
var list KeyValueList
for _, c := range cases {
list = list.Add(c.key, c.value)
}
blob, err := rlp.EncodeToBytes(list)
if err != nil {
t.Fatalf("Failed to encode keyvalue list: %v", err)
}
var dec KeyValueList
err = rlp.DecodeBytes(blob, &dec)
if err != nil {
t.Fatalf("Failed to decode keyvalue list: %v", err)
}
}

362
les/protocol/protocol.go Normal file
View file

@ -0,0 +1,362 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package protocol defines all protocol related structures which will be
// used in both server side and client side.
package protocol
import (
"crypto/ecdsa"
"errors"
"fmt"
"io"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/rlp"
)
// Constants to match up protocol versions and messages
const (
Lpv2 = 2
Lpv3 = 3
)
// Supported versions of the les protocol (first is primary)
var (
ClientProtocolVersions = []uint{Lpv2, Lpv3}
ServerProtocolVersions = []uint{Lpv2, Lpv3}
AdvertiseProtocolVersions = []uint{Lpv2} // clients are searching for the first advertised protocol in the list
)
// Number of implemented message corresponding to different protocol versions.
var ProtocolLengths = map[uint]uint64{Lpv2: 22, Lpv3: 24}
const (
NetworkId = 1 // Default ethereum mainnet network ID
ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message
)
// les protocol message codes
const (
// Protocol messages inherited from LPV1
StatusMsg = 0x00
AnnounceMsg = 0x01
GetBlockHeadersMsg = 0x02
BlockHeadersMsg = 0x03
GetBlockBodiesMsg = 0x04
BlockBodiesMsg = 0x05
GetReceiptsMsg = 0x06
ReceiptsMsg = 0x07
GetCodeMsg = 0x0a
CodeMsg = 0x0b
// Protocol messages introduced in LPV2
GetProofsV2Msg = 0x0f
ProofsV2Msg = 0x10
GetHelperTrieProofsMsg = 0x11
HelperTrieProofsMsg = 0x12
SendTxV2Msg = 0x13
GetTxStatusMsg = 0x14
TxStatusMsg = 0x15
// Protocol messages introduced in LPV3
StopMsg = 0x16
ResumeMsg = 0x17
)
// The maxmium amount of data requested per retrieval request.
const (
MaxHeaderFetch = 192 // Amount of block headers to be fetched per retrieval request
MaxBodyFetch = 32 // Amount of block bodies to be fetched per retrieval request
MaxReceiptFetch = 128 // Amount of transaction receipts to allow fetching per request
MaxCodeFetch = 64 // Amount of contract codes to allow fetching per request
MaxProofsFetch = 64 // Amount of merkle proofs to be fetched per retrieval request
MaxHelperTrieProofsFetch = 64 // Amount of helper tries to be fetched per retrieval request
MaxTxSend = 64 // Amount of transactions to be send per request
MaxTxStatus = 256 // Amount of transactions to queried per request
)
type RequestInfo struct {
Name string
MaxCount uint64
}
var LesRequests = map[uint64]RequestInfo{
GetBlockHeadersMsg: {"GetBlockHeaders", MaxHeaderFetch},
GetBlockBodiesMsg: {"GetBlockBodies", MaxBodyFetch},
GetReceiptsMsg: {"GetReceipts", MaxReceiptFetch},
GetCodeMsg: {"GetCode", MaxCodeFetch},
GetProofsV2Msg: {"GetProofsV2", MaxProofsFetch},
GetHelperTrieProofsMsg: {"GetHelperTrieProofs", MaxHelperTrieProofsFetch},
SendTxV2Msg: {"SendTxV2", MaxTxSend},
GetTxStatusMsg: {"GetTxStatus", MaxTxStatus},
}
type ErrCode int
const (
ErrMsgTooLarge = iota
ErrDecode
ErrInvalidMsgCode
ErrProtocolVersionMismatch
ErrNetworkIdMismatch
ErrGenesisBlockMismatch
ErrNoStatusMsg
ErrExtraStatusMsg
ErrSuspendedPeer
ErrUselessPeer
ErrRequestRejected
ErrUnexpectedResponse
ErrInvalidResponse
ErrTooManyTimeouts
ErrMissingKey
)
func (e ErrCode) String() string {
return errorToString[int(e)]
}
// XXX change once legacy code is out
var errorToString = map[int]string{
ErrMsgTooLarge: "Message too long",
ErrDecode: "Invalid message",
ErrInvalidMsgCode: "Invalid message code",
ErrProtocolVersionMismatch: "Protocol version mismatch",
ErrNetworkIdMismatch: "NetworkId mismatch",
ErrGenesisBlockMismatch: "Genesis block mismatch",
ErrNoStatusMsg: "No status message",
ErrExtraStatusMsg: "Extra status message",
ErrSuspendedPeer: "Suspended peer",
ErrRequestRejected: "Request rejected",
ErrUnexpectedResponse: "Unexpected response",
ErrInvalidResponse: "Invalid response",
ErrTooManyTimeouts: "Too many request timeouts",
ErrMissingKey: "Key missing from list",
}
// HeadHeader is the a part of announcement sent by the LES server to the
// LES client when a new block is generated in the network.
//
// HeadHeader can also be used to represent the head info of peer(both server
// and client).
type HeadHeader struct {
Hash common.Hash // Hash of one particular block being announced
Number uint64 // Number of one particular block being announced
Td *big.Int // Total difficulty of one particular block being announced
}
// Announcement is a network packet sent by the LES server to the LES client
// when a new block is generated in the network or the server has protocol
// parameters that need to be updated.
type Announcement struct {
HeadHeader // The data of new arrival header
ReorgDepth uint64 // The reorg depth of new arrival header
Update KeyValueList // Updated protocol parameters
}
// SanityCheck verifies that the values are reasonable, as a DoS protection
func (a *Announcement) SanityCheck() error {
if tdlen := a.Td.BitLen(); tdlen > 100 {
return fmt.Errorf("too large block TD: bitlen %d", tdlen)
}
return nil
}
// Sign adds a signature to the block announcement by the given privKey
func (a *Announcement) Sign(privKey *ecdsa.PrivateKey) {
rlp, _ := rlp.EncodeToBytes(HeadHeader{a.Hash, a.Number, a.Td})
sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey)
a.Update = a.Update.Add("sign", sig)
}
// CheckSignature verifies if the block announcement has a valid signature
// by the given pubKey.
func (a *Announcement) CheckSignature(id enode.ID, update KeyValueMap) error {
var sig []byte
if err := update.Get("sign", &sig); err != nil {
return err
}
rlp, _ := rlp.EncodeToBytes(HeadHeader{a.Hash, a.Number, a.Td})
recPubkey, err := crypto.SigToPub(crypto.Keccak256(rlp), sig)
if err != nil {
return err
}
if id == enode.PubkeyToIDV4(recPubkey) {
return nil
}
return errors.New("wrong signature")
}
// GetBlockHeadersRequest represents a block header query sent by les client.
type GetBlockHeadersRequest struct {
Origin HashOrNumber // Block from which to retrieve headers
Amount uint64 // Maximum number of headers to retrieve
Skip uint64 // Blocks to skip between consecutive headers
Reverse bool // Query direction (false = rising towards latest, true = falling towards genesis)
}
// HashOrNumber is a combined field for specifying an origin block.
type HashOrNumber struct {
Hash common.Hash // Block hash from which to retrieve headers (excludes Number)
Number uint64 // Block hash from which to retrieve headers (excludes Hash)
}
// EncodeRLP is a specialized encoder for HashOrNumber to encode only one of the
// two contained union fields.
func (hn *HashOrNumber) EncodeRLP(w io.Writer) error {
if hn.Hash == (common.Hash{}) {
return rlp.Encode(w, hn.Number)
}
if hn.Number != 0 {
return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
}
return rlp.Encode(w, hn.Hash)
}
// DecodeRLP is a specialized decoder for HashOrNumber to decode the contents
// into either a block hash or a block number.
func (hn *HashOrNumber) DecodeRLP(s *rlp.Stream) error {
_, size, _ := s.Kind()
origin, err := s.Raw()
if err == nil {
switch {
case size == 32:
err = rlp.DecodeBytes(origin, &hn.Hash)
case size <= 8:
err = rlp.DecodeBytes(origin, &hn.Number)
default:
err = fmt.Errorf("invalid input size %d for origin", size)
}
}
return err
}
// TrieProofRequest represents a state/storage trie proof query
// sent by les client.
type TrieProofRequest struct {
BlockHash common.Hash // The corresponding block hash of state
Account []byte // The address of target account, nil if it's a global state trie proof request
Key []byte // The key of target storage slot or account
FromLevel uint // The node level beyond which all trie nodes are contained in the proof
}
// CodeRequest represents a contract code query sent by les client.
type CodeRequest struct {
BlockHash common.Hash // The corresponding block hash of state
Account []byte // The address of target account
}
const (
// HelperTrieCHT is the indicator of canonical hash trie, check
// https://github.com/ethereum/devp2p/blob/master/caps/les.md#canonical-hash-trie
// for more details.
HelperTrieCHT = iota
// HelperTrieBloomTrie is the indicator of bloom trie, check
// https://github.com/ethereum/devp2p/blob/master/caps/les.md#bloombits-trie
// for more details
HelperTrieBloomTrie
// The auxiliary data type of helperTrie request which is available for
// all helperTrie request.
AuxRoot = 1
// The auxiliary data type of CHT request - corresponding block header
// which is only avaiable for CHT request.
AuxHeader = 2
)
// HelperTrieRequest represents a helper trie query sent by les client.
// HelperTrie includes: CHT and bloom trie. It's a shared structure between
// these two kinds of request.
//
// Except the helperTrie proof of requested entry will be returned, caller
// can specify more additional auxiliary data to be returned via `AuxType`.
type HelperTrieRequest struct {
Type uint // Indicator of request type, 0 represents CHT, 1 represents Bloom trie
TrieIndex uint64 // The index(section index) of requested trie
Key []byte // The list of entry keys, caller can request a batch of entries in a single request.
FromLevel uint // The node level beyond which all trie nodes are contained in the proof
AuxType uint // The type of auxiliary data requested
}
// HelperTrieResponse represents the response of corresponding helperTrie
// request. A single response contains a batch of requested proofs and
// corresponding auxiliary data.
type HelperTrieResponse struct {
Proofs light.NodeList // The container for storing all requested proofs
AuxData [][]byte // The batch of requested auxiliary data
}
// ErrResp returns an protocol error with given error code and additional
// error message.
func ErrResp(code ErrCode, format string, v ...interface{}) error {
return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
}
// LesTopic constructs the discovery v5 topic for LES protocol.
func LesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic {
var name string
switch protocolVersion {
case Lpv2:
name = "LES2"
default:
panic(nil)
}
return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8]))
}
type (
// RequestCost represents a cost policy of a specified request type.
RequestCost struct {
BaseCost, ReqCost uint64
}
// RequestCostTable assigns a cost estimate function to each request type
// which is a linear function of the requested amount
// (cost = BaseCost + ReqCost * amount)
RequestCostTable map[uint64]*RequestCost
// RequestCostList is a list representation of request costs which is used for
// database storage and communication through the network
RequestCostList []RequestCostListItem
RequestCostListItem struct {
MsgCode, BaseCost, ReqCost uint64
}
)
// GetMaxCost calculates the estimated cost for a given request type and amount
func (table RequestCostTable) GetMaxCost(code, amount uint64) uint64 {
costs := table[code]
return costs.BaseCost + amount*costs.ReqCost
}
// ToTable converts a cost list to a cost table
func (list RequestCostList) ToTable(protocolLength uint64) RequestCostTable {
table := make(RequestCostTable)
for _, e := range list {
if e.MsgCode < protocolLength {
table[e.MsgCode] = &RequestCost{
BaseCost: e.BaseCost,
ReqCost: e.ReqCost,
}
}
}
return table
}

View file

@ -25,6 +25,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
)
@ -171,7 +172,7 @@ func (rm *retrieveManager) deliver(peer distPeer, msg *Msg) error {
if ok {
return req.deliver(peer, msg)
}
return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID)
return protocol.ErrResp(protocol.ErrUnexpectedResponse, "reqID = %v", msg.ReqID)
}
// frozen is called by the LES protocol manager when a server has suspended its service and we
@ -389,7 +390,7 @@ func (r *sentReq) deliver(peer distPeer, msg *Msg) error {
s, ok := r.sentTo[peer]
if !ok || s.delivered {
return errResp(ErrUnexpectedResponse, "reqID = %v", msg.ReqID)
return protocol.ErrResp(protocol.ErrUnexpectedResponse, "reqID = %v", msg.ReqID)
}
if s.frozen {
return nil
@ -402,7 +403,7 @@ func (r *sentReq) deliver(peer distPeer, msg *Msg) error {
s.event <- rpDeliveredInvalid
}
if !valid {
return errResp(ErrInvalidResponse, "reqID = %v", msg.ReqID)
return protocol.ErrResp(protocol.ErrInvalidResponse, "reqID = %v", msg.ReqID)
}
return nil
}

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les/checkpointoracle"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
@ -58,9 +59,9 @@ type LesServer struct {
func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) {
// Collect les protocol version information supported by local node.
lesTopics := make([]discv5.Topic, len(AdvertiseProtocolVersions))
for i, pv := range AdvertiseProtocolVersions {
lesTopics[i] = lesTopic(e.BlockChain().Genesis().Hash(), pv)
lesTopics := make([]discv5.Topic, len(protocol.AdvertiseProtocolVersions))
for i, pv := range protocol.AdvertiseProtocolVersions {
lesTopics[i] = protocol.LesTopic(e.BlockChain().Genesis().Hash(), pv)
}
// Calculate the number of threads used to service the light client
// requests based on the user-specified value.
@ -151,7 +152,7 @@ func (s *LesServer) APIs() []rpc.API {
}
func (s *LesServer) Protocols() []p2p.Protocol {
ps := s.makeProtocols(ServerProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
ps := s.makeProtocols(protocol.ServerProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
if p := s.peers.Peer(peerIdToString(id)); p != nil {
return p.Info()
}

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
@ -43,15 +44,6 @@ 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
ethVersion = 63 // equivalent eth version for the downloader
MaxHeaderFetch = 192 // Amount of block headers to be fetched per retrieval request
MaxBodyFetch = 32 // Amount of block bodies to be fetched per retrieval request
MaxReceiptFetch = 128 // Amount of transaction receipts to allow fetching per request
MaxCodeFetch = 64 // Amount of contract codes to allow fetching per request
MaxProofsFetch = 64 // Amount of merkle proofs to be fetched per retrieval request
MaxHelperTrieProofsFetch = 64 // Amount of helper tries to be fetched per retrieval request
MaxTxSend = 64 // Amount of transactions to be send per request
MaxTxStatus = 256 // Amount of transactions to queried per request
)
var (
@ -182,9 +174,9 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
p.Log().Trace("Light Ethereum message arrived", "code", msg.Code, "bytes", msg.Size)
// Discard large message which exceeds the limitation.
if msg.Size > ProtocolMaxMsgSize {
if msg.Size > protocol.ProtocolMaxMsgSize {
clientErrorMeter.Mark(1)
return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
return protocol.ErrResp(protocol.ErrMsgTooLarge, "%v > %v", msg.Size, protocol.ProtocolMaxMsgSize)
}
defer msg.Discard()
@ -204,7 +196,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
return false
}
// Prepaid max cost units before request been serving.
maxCost = p.fcCosts.getMaxCost(msg.Code, reqCnt)
maxCost = p.fcCosts.GetMaxCost(msg.Code, reqCnt)
accepted, bufShort, priority := p.fcClient.AcceptRequest(reqID, responseCount, maxCost)
if !accepted {
p.freezeClient()
@ -268,7 +260,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
}
switch msg.Code {
case GetBlockHeadersMsg:
case protocol.GetBlockHeadersMsg:
p.Log().Trace("Received block header request")
if metrics.EnabledExpensive {
miscInHeaderPacketsMeter.Mark(1)
@ -277,14 +269,14 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
var req struct {
ReqID uint64
Query getBlockHeadersData
Query protocol.GetBlockHeadersRequest
}
if err := msg.Decode(&req); err != nil {
clientErrorMeter.Mark(1)
return errResp(ErrDecode, "%v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "%v: %v", msg, err)
}
query := req.Query
if accept(req.ReqID, query.Amount, MaxHeaderFetch) {
if accept(req.ReqID, query.Amount, protocol.MaxHeaderFetch) {
wg.Add(1)
go func() {
defer wg.Done()
@ -381,7 +373,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}()
}
case GetBlockBodiesMsg:
case protocol.GetBlockBodiesMsg:
p.Log().Trace("Received block bodies request")
if metrics.EnabledExpensive {
miscInBodyPacketsMeter.Mark(1)
@ -394,14 +386,14 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
if err := msg.Decode(&req); err != nil {
clientErrorMeter.Mark(1)
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
var (
bytes int
bodies []rlp.RawValue
)
reqCnt := len(req.Hashes)
if accept(req.ReqID, uint64(reqCnt), MaxBodyFetch) {
if accept(req.ReqID, uint64(reqCnt), protocol.MaxBodyFetch) {
wg.Add(1)
go func() {
defer wg.Done()
@ -430,7 +422,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}()
}
case GetCodeMsg:
case protocol.GetCodeMsg:
p.Log().Trace("Received code request")
if metrics.EnabledExpensive {
miscInCodePacketsMeter.Mark(1)
@ -439,18 +431,18 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
var req struct {
ReqID uint64
Reqs []CodeReq
Reqs []protocol.CodeRequest
}
if err := msg.Decode(&req); err != nil {
clientErrorMeter.Mark(1)
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
var (
bytes int
data [][]byte
)
reqCnt := len(req.Reqs)
if accept(req.ReqID, uint64(reqCnt), MaxCodeFetch) {
if accept(req.ReqID, uint64(reqCnt), protocol.MaxCodeFetch) {
wg.Add(1)
go func() {
defer wg.Done()
@ -460,9 +452,9 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
return
}
// Look up the root hash belonging to the request
header := h.blockchain.GetHeaderByHash(request.BHash)
header := h.blockchain.GetHeaderByHash(request.BlockHash)
if header == nil {
p.Log().Warn("Failed to retrieve associate header for code", "hash", request.BHash)
p.Log().Warn("Failed to retrieve associate header for code", "hash", request.BlockHash)
atomic.AddUint32(&p.invalidCount, 1)
continue
}
@ -476,15 +468,15 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
triedb := h.blockchain.StateCache().TrieDB()
account, err := h.getAccount(triedb, header.Root, common.BytesToHash(request.AccKey))
account, err := h.getAccount(triedb, header.Root, common.BytesToHash(request.Account))
if err != nil {
p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err)
p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.Account), "err", err)
atomic.AddUint32(&p.invalidCount, 1)
continue
}
code, err := triedb.Node(common.BytesToHash(account.CodeHash))
if err != nil {
p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "codehash", common.BytesToHash(account.CodeHash), "err", err)
p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.Account), "codehash", common.BytesToHash(account.CodeHash), "err", err)
continue
}
// Accumulate the code and abort if enough data was retrieved
@ -502,7 +494,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}()
}
case GetReceiptsMsg:
case protocol.GetReceiptsMsg:
p.Log().Trace("Received receipts request")
if metrics.EnabledExpensive {
miscInReceiptPacketsMeter.Mark(1)
@ -515,14 +507,14 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
if err := msg.Decode(&req); err != nil {
clientErrorMeter.Mark(1)
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
var (
bytes int
receipts []rlp.RawValue
)
reqCnt := len(req.Hashes)
if accept(req.ReqID, uint64(reqCnt), MaxReceiptFetch) {
if accept(req.ReqID, uint64(reqCnt), protocol.MaxReceiptFetch) {
wg.Add(1)
go func() {
defer wg.Done()
@ -559,7 +551,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}()
}
case GetProofsV2Msg:
case protocol.GetProofsV2Msg:
p.Log().Trace("Received les/2 proofs request")
if metrics.EnabledExpensive {
miscInTrieProofPacketsMeter.Mark(1)
@ -568,11 +560,11 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
var req struct {
ReqID uint64
Reqs []ProofReq
Reqs []protocol.TrieProofRequest
}
if err := msg.Decode(&req); err != nil {
clientErrorMeter.Mark(1)
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
// Gather state data until the fetch or network limits is reached
var (
@ -580,7 +572,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
root common.Hash
)
reqCnt := len(req.Reqs)
if accept(req.ReqID, uint64(reqCnt), MaxProofsFetch) {
if accept(req.ReqID, uint64(reqCnt), protocol.MaxProofsFetch) {
wg.Add(1)
go func() {
defer wg.Done()
@ -596,11 +588,11 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
header *types.Header
trie state.Trie
)
if request.BHash != lastBHash {
root, lastBHash = common.Hash{}, request.BHash
if request.BlockHash != lastBHash {
root, lastBHash = common.Hash{}, request.BlockHash
if header = h.blockchain.GetHeaderByHash(request.BHash); header == nil {
p.Log().Warn("Failed to retrieve header for proof", "hash", request.BHash)
if header = h.blockchain.GetHeaderByHash(request.BlockHash); header == nil {
p.Log().Warn("Failed to retrieve header for proof", "hash", request.BlockHash)
atomic.AddUint32(&p.invalidCount, 1)
continue
}
@ -622,7 +614,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
// Open the account or storage trie for the request
statedb := h.blockchain.StateCache()
switch len(request.AccKey) {
switch len(request.Account) {
case 0:
// No account key specified, open an account trie
trie, err = statedb.OpenTrie(root)
@ -632,15 +624,15 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
default:
// Account key specified, open a storage trie
account, err := h.getAccount(statedb.TrieDB(), root, common.BytesToHash(request.AccKey))
account, err := h.getAccount(statedb.TrieDB(), root, common.BytesToHash(request.Account))
if err != nil {
p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err)
p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.Account), "err", err)
atomic.AddUint32(&p.invalidCount, 1)
continue
}
trie, err = statedb.OpenStorageTrie(common.BytesToHash(request.AccKey), account.Root)
trie, err = statedb.OpenStorageTrie(common.BytesToHash(request.Account), account.Root)
if trie == nil || err != nil {
p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "root", account.Root, "err", err)
p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.Account), "root", account.Root, "err", err)
continue
}
}
@ -662,7 +654,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}()
}
case GetHelperTrieProofsMsg:
case protocol.GetHelperTrieProofsMsg:
p.Log().Trace("Received helper trie proof request")
if metrics.EnabledExpensive {
miscInHelperTriePacketsMeter.Mark(1)
@ -671,11 +663,11 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
var req struct {
ReqID uint64
Reqs []HelperTrieReq
Reqs []protocol.HelperTrieRequest
}
if err := msg.Decode(&req); err != nil {
clientErrorMeter.Mark(1)
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
// Gather state data until the fetch or network limits is reached
var (
@ -683,7 +675,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
auxData [][]byte
)
reqCnt := len(req.Reqs)
if accept(req.ReqID, uint64(reqCnt), MaxHelperTrieProofsFetch) {
if accept(req.ReqID, uint64(reqCnt), protocol.MaxHelperTrieProofsFetch) {
wg.Add(1)
go func() {
defer wg.Done()
@ -699,15 +691,15 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
sendResponse(req.ReqID, 0, nil, task.servingTime)
return
}
if auxTrie == nil || request.Type != lastType || request.TrieIdx != lastIdx {
auxTrie, lastType, lastIdx = nil, request.Type, request.TrieIdx
if auxTrie == nil || request.Type != lastType || request.TrieIndex != lastIdx {
auxTrie, lastType, lastIdx = nil, request.Type, request.TrieIndex
var prefix string
if root, prefix = h.getHelperTrie(request.Type, request.TrieIdx); root != (common.Hash{}) {
if root, prefix = h.getHelperTrie(request.Type, request.TrieIndex); root != (common.Hash{}) {
auxTrie, _ = trie.New(root, trie.NewDatabase(rawdb.NewTable(h.chainDb, prefix)))
}
}
if request.AuxReq == auxRoot {
if request.AuxType == protocol.AuxRoot {
var data []byte
if root != (common.Hash{}) {
data = root[:]
@ -718,7 +710,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
if auxTrie != nil {
auxTrie.Prove(request.Key, request.FromLevel, nodes)
}
if request.AuxReq != 0 {
if request.AuxType != 0 {
data := h.getAuxiliaryHeaders(request)
auxData = append(auxData, data)
auxBytes += len(data)
@ -728,7 +720,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
break
}
}
reply := p.ReplyHelperTrieProofs(req.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData})
reply := p.ReplyHelperTrieProofs(req.ReqID, protocol.HelperTrieResponse{Proofs: nodes.NodeList(), AuxData: auxData})
sendResponse(req.ReqID, uint64(reqCnt), reply, task.done())
if metrics.EnabledExpensive {
miscOutHelperTriePacketsMeter.Mark(1)
@ -737,7 +729,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}()
}
case SendTxV2Msg:
case protocol.SendTxV2Msg:
p.Log().Trace("Received new transactions")
if metrics.EnabledExpensive {
miscInTxsPacketsMeter.Mark(1)
@ -750,10 +742,10 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
if err := msg.Decode(&req); err != nil {
clientErrorMeter.Mark(1)
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
reqCnt := len(req.Txs)
if accept(req.ReqID, uint64(reqCnt), MaxTxSend) {
if accept(req.ReqID, uint64(reqCnt), protocol.MaxTxSend) {
wg.Add(1)
go func() {
defer wg.Done()
@ -786,7 +778,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}()
}
case GetTxStatusMsg:
case protocol.GetTxStatusMsg:
p.Log().Trace("Received transaction status query request")
if metrics.EnabledExpensive {
miscInTxStatusPacketsMeter.Mark(1)
@ -799,10 +791,10 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
}
if err := msg.Decode(&req); err != nil {
clientErrorMeter.Mark(1)
return errResp(ErrDecode, "msg %v: %v", msg, err)
return protocol.ErrResp(protocol.ErrDecode, "msg %v: %v", msg, err)
}
reqCnt := len(req.Hashes)
if accept(req.ReqID, uint64(reqCnt), MaxTxStatus) {
if accept(req.ReqID, uint64(reqCnt), protocol.MaxTxStatus) {
wg.Add(1)
go func() {
defer wg.Done()
@ -826,7 +818,7 @@ func (h *serverHandler) handleMsg(p *peer, wg *sync.WaitGroup) error {
default:
p.Log().Trace("Received invalid message", "code", msg.Code)
clientErrorMeter.Mark(1)
return errResp(ErrInvalidMsgCode, "%v", msg.Code)
return protocol.ErrResp(protocol.ErrInvalidMsgCode, "%v", msg.Code)
}
// If the client has made too much invalid request(e.g. request a non-exist data),
// reject them to prevent SPAM attack.
@ -857,10 +849,10 @@ func (h *serverHandler) getAccount(triedb *trie.Database, root, hash common.Hash
// getHelperTrie returns the post-processed trie root for the given trie ID and section index
func (h *serverHandler) getHelperTrie(typ uint, index uint64) (common.Hash, string) {
switch typ {
case htCanonical:
case protocol.HelperTrieCHT:
sectionHead := rawdb.ReadCanonicalHash(h.chainDb, (index+1)*h.server.iConfig.ChtSize-1)
return light.GetChtRoot(h.chainDb, index, sectionHead), light.ChtTablePrefix
case htBloomBits:
case protocol.HelperTrieBloomTrie:
sectionHead := rawdb.ReadCanonicalHash(h.chainDb, (index+1)*h.server.iConfig.BloomTrieSize-1)
return light.GetBloomTrieRoot(h.chainDb, index, sectionHead), light.BloomTrieTablePrefix
}
@ -868,8 +860,8 @@ func (h *serverHandler) getHelperTrie(typ uint, index uint64) (common.Hash, stri
}
// getAuxiliaryHeaders returns requested auxiliary headers for the CHT request.
func (h *serverHandler) getAuxiliaryHeaders(req HelperTrieReq) []byte {
if req.Type == htCanonical && req.AuxReq == auxHeader && len(req.Key) == 8 {
func (h *serverHandler) getAuxiliaryHeaders(req protocol.HelperTrieRequest) []byte {
if req.Type == protocol.HelperTrieCHT && req.AuxType == protocol.AuxHeader && len(req.Key) == 8 {
blockNum := binary.BigEndian.Uint64(req.Key)
hash := rawdb.ReadCanonicalHash(h.chainDb, blockNum)
return rawdb.ReadHeaderRLP(h.chainDb, hash, blockNum)
@ -931,9 +923,16 @@ func (h *serverHandler) broadcastHeaders() {
log.Debug("Announcing block to peers", "number", number, "hash", hash, "td", td, "reorg", reorg)
var (
signed bool
signedAnnounce announceData
signedAnnounce protocol.Announcement
)
announce := announceData{Hash: hash, Number: number, Td: td, ReorgDepth: reorg}
announce := protocol.Announcement{
HeadHeader: protocol.HeadHeader{
Hash: hash,
Number: number,
Td: td,
},
ReorgDepth: reorg,
}
for _, p := range peers {
p := p
switch p.announceType {
@ -942,7 +941,7 @@ func (h *serverHandler) broadcastHeaders() {
case announceTypeSigned:
if !signed {
signedAnnounce = announce
signedAnnounce.sign(h.server.privateKey)
signedAnnounce.Sign(h.server.privateKey)
signed = true
}
p.queueSend(func() { p.SendAnnounce(signedAnnounce) })

View file

@ -41,6 +41,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/les/checkpointoracle"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
@ -200,7 +201,7 @@ func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, index
client := &LightEthereum{
lesCommons: lesCommons{
genesis: genesis.Hash(),
config: &eth.Config{LightPeers: 100, NetworkId: NetworkId},
config: &eth.Config{LightPeers: 100, NetworkId: protocol.NetworkId},
chainConfig: params.AllEthashProtocolChanges,
iConfig: light.TestClientIndexerConfig,
chainDb: db,
@ -263,7 +264,7 @@ func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db ethdb.Da
server := &LesServer{
lesCommons: lesCommons{
genesis: genesis.Hash(),
config: &eth.Config{LightPeers: 100, NetworkId: NetworkId},
config: &eth.Config{LightPeers: 100, NetworkId: protocol.NetworkId},
chainConfig: params.AllEthashProtocolChanges,
iConfig: light.TestServerIndexerConfig,
chainDb: db,
@ -308,7 +309,7 @@ func newTestPeer(t *testing.T, name string, version int, handler *serverHandler,
// Generate a random id and create the peer
var id enode.ID
rand.Read(id[:])
peer := newPeer(version, NetworkId, false, p2p.NewPeer(id, name, nil), net)
peer := newPeer(version, protocol.NetworkId, false, p2p.NewPeer(id, name, nil), net)
// Start the peer on a new thread
errCh := make(chan error, 1)
@ -354,8 +355,8 @@ func newTestPeerPair(name string, version int, server *serverHandler, client *cl
var id enode.ID
rand.Read(id[:])
peer1 := newPeer(version, NetworkId, false, p2p.NewPeer(id, name, nil), net)
peer2 := newPeer(version, NetworkId, false, p2p.NewPeer(id, name, nil), app)
peer1 := newPeer(version, protocol.NetworkId, false, p2p.NewPeer(id, name, nil), net)
peer2 := newPeer(version, protocol.NetworkId, false, p2p.NewPeer(id, name, nil), app)
// Start the peer on a new thread
errc1 := make(chan error, 1)
@ -379,29 +380,29 @@ func newTestPeerPair(name string, version int, server *serverHandler, client *cl
// handshake simulates a trivial handshake that expects the same state from the
// remote side as we are simulating locally.
func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, costList RequestCostList) {
var expList keyValueList
expList = expList.add("protocolVersion", uint64(p.peer.version))
expList = expList.add("networkId", uint64(NetworkId))
expList = expList.add("headTd", td)
expList = expList.add("headHash", head)
expList = expList.add("headNum", headNum)
expList = expList.add("genesisHash", genesis)
sendList := make(keyValueList, len(expList))
func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, costList protocol.RequestCostList) {
var expList protocol.KeyValueList
expList = expList.Add("protocolVersion", uint64(p.peer.version))
expList = expList.Add("networkId", uint64(protocol.NetworkId))
expList = expList.Add("headTd", td)
expList = expList.Add("headHash", head)
expList = expList.Add("headNum", headNum)
expList = expList.Add("genesisHash", genesis)
sendList := make(protocol.KeyValueList, len(expList))
copy(sendList, expList)
expList = expList.add("serveHeaders", nil)
expList = expList.add("serveChainSince", uint64(0))
expList = expList.add("serveStateSince", uint64(0))
expList = expList.add("serveRecentState", uint64(core.TriesInMemory-4))
expList = expList.add("txRelay", nil)
expList = expList.add("flowControl/BL", testBufLimit)
expList = expList.add("flowControl/MRR", testBufRecharge)
expList = expList.add("flowControl/MRC", costList)
expList = expList.Add("serveHeaders", nil)
expList = expList.Add("serveChainSince", uint64(0))
expList = expList.Add("serveStateSince", uint64(0))
expList = expList.Add("serveRecentState", uint64(core.TriesInMemory-4))
expList = expList.Add("txRelay", nil)
expList = expList.Add("flowControl/BL", testBufLimit)
expList = expList.Add("flowControl/MRR", testBufRecharge)
expList = expList.Add("flowControl/MRC", costList)
if err := p2p.ExpectMsg(p.app, StatusMsg, expList); err != nil {
if err := p2p.ExpectMsg(p.app, protocol.StatusMsg, expList); err != nil {
t.Fatalf("status recv: %v", err)
}
if err := p2p.Send(p.app, StatusMsg, sendList); err != nil {
if err := p2p.Send(p.app, protocol.StatusMsg, sendList); err != nil {
t.Fatalf("status send: %v", err)
}
p.peer.fcParams = flowcontrol.ServerParams{

View file

@ -24,6 +24,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/les/protocol"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
)
@ -86,15 +87,15 @@ func testULCAnnounceThreshold(t *testing.T, protocol int) {
}
}
func connect(server *serverHandler, serverId enode.ID, client *clientHandler, protocol int) (*peer, *peer, error) {
func connect(server *serverHandler, serverId enode.ID, client *clientHandler, p int) (*peer, *peer, error) {
// Create a message pipe to communicate through
app, net := p2p.MsgPipe()
var id enode.ID
rand.Read(id[:])
peer1 := newPeer(protocol, NetworkId, true, p2p.NewPeer(serverId, "", nil), net) // Mark server as trusted
peer2 := newPeer(protocol, NetworkId, false, p2p.NewPeer(id, "", nil), app)
peer1 := newPeer(p, protocol.NetworkId, true, p2p.NewPeer(serverId, "", nil), net) // Mark server as trusted
peer2 := newPeer(p, protocol.NetworkId, false, p2p.NewPeer(id, "", nil), app)
// Start the peerLight on a new thread
errc1 := make(chan error, 1)