Skip to content

Commit 0045410

Browse files
authored
les: introduce forkID (#21974)
* les: introduce forkID * les: address comment
1 parent b44f24e commit 0045410

File tree

5 files changed

+68
-21
lines changed

5 files changed

+68
-21
lines changed

les/client_handler.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
"github.com/ethereum/go-ethereum/common"
2727
"github.com/ethereum/go-ethereum/common/mclock"
28+
"github.com/ethereum/go-ethereum/core/forkid"
2829
"github.com/ethereum/go-ethereum/core/types"
2930
"github.com/ethereum/go-ethereum/eth/downloader"
3031
"github.com/ethereum/go-ethereum/light"
@@ -37,6 +38,7 @@ import (
3738
// responses.
3839
type clientHandler struct {
3940
ulc *ulc
41+
forkFilter forkid.Filter
4042
checkpoint *params.TrustedCheckpoint
4143
fetcher *lightFetcher
4244
downloader *downloader.Downloader
@@ -49,6 +51,7 @@ type clientHandler struct {
4951

5052
func newClientHandler(ulcServers []string, ulcFraction int, checkpoint *params.TrustedCheckpoint, backend *LightEthereum) *clientHandler {
5153
handler := &clientHandler{
54+
forkFilter: forkid.NewFilter(backend.blockchain),
5255
checkpoint: checkpoint,
5356
backend: backend,
5457
closeCh: make(chan struct{}),
@@ -103,7 +106,8 @@ func (h *clientHandler) handle(p *serverPeer) error {
103106
p.Log().Debug("Light Ethereum peer connected", "name", p.Name())
104107

105108
// Execute the LES handshake
106-
if err := p.Handshake(h.backend.blockchain.Genesis().Hash()); err != nil {
109+
forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.genesis, h.backend.blockchain.CurrentHeader().Number.Uint64())
110+
if err := p.Handshake(h.backend.blockchain.Genesis().Hash(), forkid, h.forkFilter); err != nil {
107111
p.Log().Debug("Light Ethereum handshake failed", "err", err)
108112
return err
109113
}
@@ -154,8 +158,8 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
154158
var deliverMsg *Msg
155159

156160
// Handle the message depending on its contents
157-
switch msg.Code {
158-
case AnnounceMsg:
161+
switch {
162+
case msg.Code == AnnounceMsg:
159163
p.Log().Trace("Received announce message")
160164
var req announceData
161165
if err := msg.Decode(&req); err != nil {
@@ -188,7 +192,7 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
188192
p.updateHead(req.Hash, req.Number, req.Td)
189193
h.fetcher.announce(p, &req)
190194
}
191-
case BlockHeadersMsg:
195+
case msg.Code == BlockHeadersMsg:
192196
p.Log().Trace("Received block header response message")
193197
var resp struct {
194198
ReqID, BV uint64
@@ -220,7 +224,7 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
220224
}
221225
}
222226
}
223-
case BlockBodiesMsg:
227+
case msg.Code == BlockBodiesMsg:
224228
p.Log().Trace("Received block bodies response")
225229
var resp struct {
226230
ReqID, BV uint64
@@ -236,7 +240,7 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
236240
ReqID: resp.ReqID,
237241
Obj: resp.Data,
238242
}
239-
case CodeMsg:
243+
case msg.Code == CodeMsg:
240244
p.Log().Trace("Received code response")
241245
var resp struct {
242246
ReqID, BV uint64
@@ -252,7 +256,7 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
252256
ReqID: resp.ReqID,
253257
Obj: resp.Data,
254258
}
255-
case ReceiptsMsg:
259+
case msg.Code == ReceiptsMsg:
256260
p.Log().Trace("Received receipts response")
257261
var resp struct {
258262
ReqID, BV uint64
@@ -268,7 +272,7 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
268272
ReqID: resp.ReqID,
269273
Obj: resp.Receipts,
270274
}
271-
case ProofsV2Msg:
275+
case msg.Code == ProofsV2Msg:
272276
p.Log().Trace("Received les/2 proofs response")
273277
var resp struct {
274278
ReqID, BV uint64
@@ -284,7 +288,7 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
284288
ReqID: resp.ReqID,
285289
Obj: resp.Data,
286290
}
287-
case HelperTrieProofsMsg:
291+
case msg.Code == HelperTrieProofsMsg:
288292
p.Log().Trace("Received helper trie proof response")
289293
var resp struct {
290294
ReqID, BV uint64
@@ -300,7 +304,7 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
300304
ReqID: resp.ReqID,
301305
Obj: resp.Data,
302306
}
303-
case TxStatusMsg:
307+
case msg.Code == TxStatusMsg:
304308
p.Log().Trace("Received tx status response")
305309
var resp struct {
306310
ReqID, BV uint64
@@ -316,11 +320,11 @@ func (h *clientHandler) handleMsg(p *serverPeer) error {
316320
ReqID: resp.ReqID,
317321
Obj: resp.Status,
318322
}
319-
case StopMsg:
323+
case msg.Code == StopMsg && p.version >= lpv3:
320324
p.freeze()
321325
h.backend.retriever.frozen(p)
322326
p.Log().Debug("Service stopped")
323-
case ResumeMsg:
327+
case msg.Code == ResumeMsg && p.version >= lpv3:
324328
var bv uint64
325329
if err := msg.Decode(&bv); err != nil {
326330
return errResp(ErrDecode, "msg %v: %v", msg, err)

les/peer.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/ethereum/go-ethereum/common"
3030
"github.com/ethereum/go-ethereum/common/mclock"
3131
"github.com/ethereum/go-ethereum/core"
32+
"github.com/ethereum/go-ethereum/core/forkid"
3233
"github.com/ethereum/go-ethereum/core/types"
3334
"github.com/ethereum/go-ethereum/eth"
3435
"github.com/ethereum/go-ethereum/les/flowcontrol"
@@ -246,7 +247,7 @@ func (p *peerCommons) sendReceiveHandshake(sendList keyValueList) (keyValueList,
246247
// network IDs, difficulties, head and genesis blocks. Besides the basic handshake
247248
// fields, server and client can exchange and resolve some specified fields through
248249
// two callback functions.
249-
func (p *peerCommons) handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, sendCallback func(*keyValueList), recvCallback func(keyValueMap) error) error {
250+
func (p *peerCommons) handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter, sendCallback func(*keyValueList), recvCallback func(keyValueMap) error) error {
250251
p.lock.Lock()
251252
defer p.lock.Unlock()
252253

@@ -262,6 +263,12 @@ func (p *peerCommons) handshake(td *big.Int, head common.Hash, headNum uint64, g
262263
send = send.add("headNum", headNum)
263264
send = send.add("genesisHash", genesis)
264265

266+
// If the protocol version is beyond les4, then pass the forkID
267+
// as well. Check http://eips.ethereum.org/EIPS/eip-2124 for more
268+
// spec detail.
269+
if p.version >= lpv4 {
270+
send = send.add("forkID", forkID)
271+
}
265272
// Add client-specified or server-specified fields
266273
if sendCallback != nil {
267274
sendCallback(&send)
@@ -295,6 +302,16 @@ func (p *peerCommons) handshake(td *big.Int, head common.Hash, headNum uint64, g
295302
if int(rVersion) != p.version {
296303
return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", rVersion, p.version)
297304
}
305+
// Check forkID if the protocol version is beyond the les4
306+
if p.version >= lpv4 {
307+
var forkID forkid.ID
308+
if err := recv.get("forkID", &forkID); err != nil {
309+
return err
310+
}
311+
if err := forkFilter(forkID); err != nil {
312+
return errResp(ErrForkIDRejected, "%v", err)
313+
}
314+
}
298315
if recvCallback != nil {
299316
return recvCallback(recv)
300317
}
@@ -561,10 +578,10 @@ func (p *serverPeer) updateHead(hash common.Hash, number uint64, td *big.Int) {
561578

562579
// Handshake executes the les protocol handshake, negotiating version number,
563580
// network IDs and genesis blocks.
564-
func (p *serverPeer) Handshake(genesis common.Hash) error {
581+
func (p *serverPeer) Handshake(genesis common.Hash, forkid forkid.ID, forkFilter forkid.Filter) error {
565582
// Note: there is no need to share local head with a server but older servers still
566583
// require these fields so we announce zero values.
567-
return p.handshake(common.Big0, common.Hash{}, 0, genesis, func(lists *keyValueList) {
584+
return p.handshake(common.Big0, common.Hash{}, 0, genesis, forkid, forkFilter, func(lists *keyValueList) {
568585
// Add some client-specific handshake fields
569586
//
570587
// Enable signed announcement randomly even the server is not trusted.
@@ -944,11 +961,11 @@ func (p *clientPeer) freezeClient() {
944961

945962
// Handshake executes the les protocol handshake, negotiating version number,
946963
// network IDs, difficulties, head and genesis blocks.
947-
func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, server *LesServer) error {
964+
func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter, server *LesServer) error {
948965
// Note: clientPeer.headInfo should contain the last head announced to the client by us.
949966
// The values announced in the handshake are dummy values for compatibility reasons and should be ignored.
950967
p.headInfo = blockInfo{Hash: head, Number: headNum, Td: td}
951-
return p.handshake(td, head, headNum, genesis, func(lists *keyValueList) {
968+
return p.handshake(td, head, headNum, genesis, forkID, forkFilter, func(lists *keyValueList) {
952969
// Add some information which services server can offer.
953970
if !server.config.UltraLightOnlyAnnounce {
954971
*lists = (*lists).add("serveHeaders", nil)

les/peer_test.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ import (
2626
"time"
2727

2828
"github.com/ethereum/go-ethereum/common"
29+
"github.com/ethereum/go-ethereum/core"
30+
"github.com/ethereum/go-ethereum/core/forkid"
31+
"github.com/ethereum/go-ethereum/core/rawdb"
32+
"github.com/ethereum/go-ethereum/core/types"
2933
"github.com/ethereum/go-ethereum/p2p"
3034
"github.com/ethereum/go-ethereum/p2p/enode"
35+
"github.com/ethereum/go-ethereum/params"
3136
)
3237

3338
type testServerPeerSub struct {
@@ -91,6 +96,14 @@ func TestPeerSubscription(t *testing.T) {
9196
checkPeers(sub.unregCh)
9297
}
9398

99+
type fakeChain struct{}
100+
101+
func (f *fakeChain) Config() *params.ChainConfig { return params.MainnetChainConfig }
102+
func (f *fakeChain) Genesis() *types.Block {
103+
return core.DefaultGenesisBlock().ToBlock(rawdb.NewMemoryDatabase())
104+
}
105+
func (f *fakeChain) CurrentHeader() *types.Header { return &types.Header{Number: big.NewInt(10000000)} }
106+
94107
func TestHandshake(t *testing.T) {
95108
// Create a message pipe to communicate through
96109
app, net := p2p.MsgPipe()
@@ -110,15 +123,21 @@ func TestHandshake(t *testing.T) {
110123
head = common.HexToHash("deadbeef")
111124
headNum = uint64(10)
112125
genesis = common.HexToHash("cafebabe")
126+
127+
chain1, chain2 = &fakeChain{}, &fakeChain{}
128+
forkID1 = forkid.NewID(chain1.Config(), chain1.Genesis().Hash(), chain1.CurrentHeader().Number.Uint64())
129+
forkID2 = forkid.NewID(chain2.Config(), chain2.Genesis().Hash(), chain2.CurrentHeader().Number.Uint64())
130+
filter1, filter2 = forkid.NewFilter(chain1), forkid.NewFilter(chain2)
113131
)
132+
114133
go func() {
115-
errCh1 <- peer1.handshake(td, head, headNum, genesis, func(list *keyValueList) {
134+
errCh1 <- peer1.handshake(td, head, headNum, genesis, forkID1, filter1, func(list *keyValueList) {
116135
var announceType uint64 = announceTypeSigned
117136
*list = (*list).add("announceType", announceType)
118137
}, nil)
119138
}()
120139
go func() {
121-
errCh2 <- peer2.handshake(td, head, headNum, genesis, nil, func(recv keyValueMap) error {
140+
errCh2 <- peer2.handshake(td, head, headNum, genesis, forkID2, filter2, nil, func(recv keyValueMap) error {
122141
var reqType uint64
123142
err := recv.get("announceType", &reqType)
124143
if err != nil {

les/protocol.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
const (
3535
lpv2 = 2
3636
lpv3 = 3
37+
lpv4 = 4
3738
)
3839

3940
// Supported versions of the les protocol (first is primary)
@@ -44,7 +45,7 @@ var (
4445
)
4546

4647
// Number of implemented message corresponding to different protocol versions.
47-
var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24}
48+
var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24, lpv4: 24}
4849

4950
const (
5051
NetworkId = 1
@@ -150,6 +151,7 @@ const (
150151
ErrInvalidResponse
151152
ErrTooManyTimeouts
152153
ErrMissingKey
154+
ErrForkIDRejected
153155
)
154156

155157
func (e errCode) String() string {
@@ -172,6 +174,7 @@ var errorToString = map[int]string{
172174
ErrInvalidResponse: "Invalid response",
173175
ErrTooManyTimeouts: "Too many request timeouts",
174176
ErrMissingKey: "Key missing from list",
177+
ErrForkIDRejected: "ForkID rejected",
175178
}
176179

177180
// announceData is the network packet for the block announcements.

les/server_handler.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/ethereum/go-ethereum/common"
2929
"github.com/ethereum/go-ethereum/common/mclock"
3030
"github.com/ethereum/go-ethereum/core"
31+
"github.com/ethereum/go-ethereum/core/forkid"
3132
"github.com/ethereum/go-ethereum/core/rawdb"
3233
"github.com/ethereum/go-ethereum/core/state"
3334
"github.com/ethereum/go-ethereum/core/types"
@@ -66,6 +67,7 @@ var (
6667
// serverHandler is responsible for serving light client and process
6768
// all incoming light requests.
6869
type serverHandler struct {
70+
forkFilter forkid.Filter
6971
blockchain *core.BlockChain
7072
chainDb ethdb.Database
7173
txpool *core.TxPool
@@ -81,6 +83,7 @@ type serverHandler struct {
8183

8284
func newServerHandler(server *LesServer, blockchain *core.BlockChain, chainDb ethdb.Database, txpool *core.TxPool, synced func() bool) *serverHandler {
8385
handler := &serverHandler{
86+
forkFilter: forkid.NewFilter(blockchain),
8487
server: server,
8588
blockchain: blockchain,
8689
chainDb: chainDb,
@@ -121,8 +124,9 @@ func (h *serverHandler) handle(p *clientPeer) error {
121124
hash = head.Hash()
122125
number = head.Number.Uint64()
123126
td = h.blockchain.GetTd(hash, number)
127+
forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis().Hash(), h.blockchain.CurrentBlock().NumberU64())
124128
)
125-
if err := p.Handshake(td, hash, number, h.blockchain.Genesis().Hash(), h.server); err != nil {
129+
if err := p.Handshake(td, hash, number, h.blockchain.Genesis().Hash(), forkID, h.forkFilter, h.server); err != nil {
126130
p.Log().Debug("Light Ethereum handshake failed", "err", err)
127131
return err
128132
}

0 commit comments

Comments
 (0)