From 0fafc0e4a6eea4d32f17403b6367c9b6070dc022 Mon Sep 17 00:00:00 2001 From: Zsolt Felfoldi Date: Thu, 26 Nov 2020 19:27:03 +0100 Subject: [PATCH 1/4] les: allow tx unindexing in les/4 light server mode --- cmd/utils/flags.go | 4 ---- les/odr_requests.go | 2 +- les/peer.go | 10 ++++++++++ les/protocol.go | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 051bdd630841..ef0e69e395e5 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1491,10 +1491,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { CheckExclusive(ctx, LegacyLightServFlag, LightServeFlag, SyncModeFlag, "light") CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer CheckExclusive(ctx, GCModeFlag, "archive", TxLookupLimitFlag) - // todo(rjl493456442) make it available for les server - // Ancient tx indices pruning is not available for les server now - // since light client relies on the server for transaction status query. - CheckExclusive(ctx, LegacyLightServFlag, LightServeFlag, TxLookupLimitFlag) var ks *keystore.KeyStore if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { ks = keystores[0].(*keystore.KeyStore) diff --git a/les/odr_requests.go b/les/odr_requests.go index eb1d3602e080..a8cf8f50a97a 100644 --- a/les/odr_requests.go +++ b/les/odr_requests.go @@ -488,7 +488,7 @@ func (r *TxStatusRequest) GetCost(peer *serverPeer) uint64 { // CanSend tells if a certain peer is suitable for serving the given request func (r *TxStatusRequest) CanSend(peer *serverPeer) bool { - return peer.version >= lpv2 + return peer.serveTxLookup } // Request sends an ODR request to the LES network (implementation of LesOdrRequest) diff --git a/les/peer.go b/les/peer.go index 31ee8f7f0429..16fa8c9765f3 100644 --- a/les/peer.go +++ b/les/peer.go @@ -334,6 +334,7 @@ type serverPeer struct { onlyAnnounce bool // The flag whether the server sends announcement only. chainSince, chainRecent uint64 // The range of chain server peer can serve. stateSince, stateRecent uint64 // The range of state server peer can serve. + serveTxLookup bool // The server peer can serve tx lookups. // Advertised checkpoint fields checkpointNumber uint64 // The block height which the checkpoint is registered. @@ -621,6 +622,8 @@ func (p *serverPeer) Handshake(genesis common.Hash, forkid forkid.ID, forkFilter if recv.get("txRelay", nil) != nil { p.onlyAnnounce = true } + p.serveTxLookup = recv.get("disableTxLookup", nil) != nil + if p.onlyAnnounce && !p.trusted { return errResp(ErrUselessPeer, "peer cannot serve requests") } @@ -962,6 +965,10 @@ func (p *clientPeer) freezeClient() { // Handshake executes the les protocol handshake, negotiating version number, // network IDs, difficulties, head and genesis blocks. func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter, server *LesServer) error { + disableTxLookup := server.handler.blockchain.TxLookupLimit() != 0 + if disableTxLookup && p.version < lpv4 { + return errors.New("Cannot serve old clients without a complete tx index") + } // Note: clientPeer.headInfo should contain the last head announced to the client by us. // The values announced in the handshake are dummy values for compatibility reasons and should be ignored. p.headInfo = blockInfo{Hash: head, Number: headNum, Td: td} @@ -981,6 +988,9 @@ func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, ge *lists = (*lists).add("serveRecentState", stateRecent) *lists = (*lists).add("txRelay", nil) } + if disableTxLookup || server.config.UltraLightOnlyAnnounce { + *lists = (*lists).add("disableTxLookup", nil) + } *lists = (*lists).add("flowControl/BL", server.defParams.BufLimit) *lists = (*lists).add("flowControl/MRR", server.defParams.MinRecharge) diff --git a/les/protocol.go b/les/protocol.go index aebe0f2c04eb..d06bc21e1717 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -39,8 +39,8 @@ const ( // Supported versions of the les protocol (first is primary) var ( - ClientProtocolVersions = []uint{lpv2, lpv3} - ServerProtocolVersions = []uint{lpv2, lpv3} + ClientProtocolVersions = []uint{lpv2, lpv3, lpv4} + ServerProtocolVersions = []uint{lpv2, lpv3, lpv4} AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list ) From 07b32967b35ebd0a826289a23e25b6061edf5cd0 Mon Sep 17 00:00:00 2001 From: Zsolt Felfoldi Date: Thu, 10 Dec 2020 15:43:31 +0100 Subject: [PATCH 2/4] les: minor fixes --- cmd/utils/flags.go | 3 +++ les/peer.go | 21 ++++++++++++++++----- les/protocol.go | 4 ++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ef0e69e395e5..e955ef78b299 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1491,6 +1491,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { CheckExclusive(ctx, LegacyLightServFlag, LightServeFlag, SyncModeFlag, "light") CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer CheckExclusive(ctx, GCModeFlag, "archive", TxLookupLimitFlag) + if (ctx.GlobalIsSet(LegacyLightServFlag.Name) || ctx.GlobalIsSet(LightServeFlag.Name)) && ctx.GlobalIsSet(TxLookupLimitFlag.Name) { + log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") + } var ks *keystore.KeyStore if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { ks = keystores[0].(*keystore.KeyStore) diff --git a/les/peer.go b/les/peer.go index 16fa8c9765f3..7a54e16ea153 100644 --- a/les/peer.go +++ b/les/peer.go @@ -622,7 +622,8 @@ func (p *serverPeer) Handshake(genesis common.Hash, forkid forkid.ID, forkFilter if recv.get("txRelay", nil) != nil { p.onlyAnnounce = true } - p.serveTxLookup = recv.get("disableTxLookup", nil) != nil + var recentTx uint + p.serveTxLookup = recv.get("recentTxLookup", &recentTx) != nil || recentTx == 0 if p.onlyAnnounce && !p.trusted { return errResp(ErrUselessPeer, "peer cannot serve requests") @@ -965,8 +966,18 @@ func (p *clientPeer) freezeClient() { // Handshake executes the les protocol handshake, negotiating version number, // network IDs, difficulties, head and genesis blocks. func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter, server *LesServer) error { - disableTxLookup := server.handler.blockchain.TxLookupLimit() != 0 - if disableTxLookup && p.version < lpv4 { + recentTx := server.handler.blockchain.TxLookupLimit() + if recentTx > 0 { // 0 means no limit (all txs available) + if recentTx <= 3 { + recentTx = 1 // 1 means tx lookup is not served at all + } else { + recentTx -= 3 // safety margin + } + } + if server.config.UltraLightOnlyAnnounce { + recentTx = 1 + } + if recentTx != 0 && p.version < lpv4 { return errors.New("Cannot serve old clients without a complete tx index") } // Note: clientPeer.headInfo should contain the last head announced to the client by us. @@ -988,8 +999,8 @@ func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, ge *lists = (*lists).add("serveRecentState", stateRecent) *lists = (*lists).add("txRelay", nil) } - if disableTxLookup || server.config.UltraLightOnlyAnnounce { - *lists = (*lists).add("disableTxLookup", nil) + if p.version >= lpv4 { + *lists = (*lists).add("recentTxLookup", recentTx) } *lists = (*lists).add("flowControl/BL", server.defParams.BufLimit) *lists = (*lists).add("flowControl/MRR", server.defParams.MinRecharge) diff --git a/les/protocol.go b/les/protocol.go index d06bc21e1717..aebe0f2c04eb 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -39,8 +39,8 @@ const ( // Supported versions of the les protocol (first is primary) var ( - ClientProtocolVersions = []uint{lpv2, lpv3, lpv4} - ServerProtocolVersions = []uint{lpv2, lpv3, lpv4} + ClientProtocolVersions = []uint{lpv2, lpv3} + ServerProtocolVersions = []uint{lpv2, lpv3} AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list ) From 5b6fe05797b036498a0fa9e5456f8ea96365f861 Mon Sep 17 00:00:00 2001 From: Zsolt Felfoldi Date: Thu, 10 Dec 2020 22:48:20 +0100 Subject: [PATCH 3/4] les: more small fixes --- les/peer.go | 17 ++++++++++++----- les/protocol.go | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/les/peer.go b/les/peer.go index 7a54e16ea153..8541d437aa28 100644 --- a/les/peer.go +++ b/les/peer.go @@ -622,8 +622,15 @@ func (p *serverPeer) Handshake(genesis common.Hash, forkid forkid.ID, forkFilter if recv.get("txRelay", nil) != nil { p.onlyAnnounce = true } - var recentTx uint - p.serveTxLookup = recv.get("recentTxLookup", &recentTx) != nil || recentTx == 0 + if p.version >= lpv4 { + var recentTx uint + if err := recv.get("recentTxLookup", &recentTx); err != nil { + return err + } + p.serveTxLookup = recentTx == 0 + } else { + p.serveTxLookup = true + } if p.onlyAnnounce && !p.trusted { return errResp(ErrUselessPeer, "peer cannot serve requests") @@ -968,10 +975,10 @@ func (p *clientPeer) freezeClient() { func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter, server *LesServer) error { recentTx := server.handler.blockchain.TxLookupLimit() if recentTx > 0 { // 0 means no limit (all txs available) - if recentTx <= 3 { + if recentTx <= blockSafetyMargin { recentTx = 1 // 1 means tx lookup is not served at all } else { - recentTx -= 3 // safety margin + recentTx -= blockSafetyMargin } } if server.config.UltraLightOnlyAnnounce { @@ -992,7 +999,7 @@ func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, ge // If local ethereum node is running in archive mode, advertise ourselves we have // all version state data. Otherwise only recent state is available. - stateRecent := uint64(core.TriesInMemory - 4) + stateRecent := uint64(core.TriesInMemory - blockSafetyMargin) if server.archiveMode { stateRecent = 0 } diff --git a/les/protocol.go b/les/protocol.go index aebe0f2c04eb..03aad3283ab0 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -50,6 +50,7 @@ var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24, lpv4: 24} const ( NetworkId = 1 ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message + blockSafetyMargin = 4 // safety margin applied to block ranges specified relative to head block ) // les protocol message codes From c6f93c314c7be4f60d01efd009456c8e2560023e Mon Sep 17 00:00:00 2001 From: Zsolt Felfoldi Date: Tue, 15 Dec 2020 10:45:56 +0100 Subject: [PATCH 4/4] les: add meaningful constants for recentTxIndex handshake field --- les/peer.go | 16 +++++++++------- les/protocol.go | 4 ++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/les/peer.go b/les/peer.go index 8541d437aa28..2729e917d6aa 100644 --- a/les/peer.go +++ b/les/peer.go @@ -627,7 +627,9 @@ func (p *serverPeer) Handshake(genesis common.Hash, forkid forkid.ID, forkFilter if err := recv.get("recentTxLookup", &recentTx); err != nil { return err } - p.serveTxLookup = recentTx == 0 + // Note: in the current version we only consider the tx index service useful + // if it is unlimited. This can be made configurable in the future. + p.serveTxLookup = recentTx == txIndexUnlimited } else { p.serveTxLookup = true } @@ -974,17 +976,17 @@ func (p *clientPeer) freezeClient() { // network IDs, difficulties, head and genesis blocks. func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter, server *LesServer) error { recentTx := server.handler.blockchain.TxLookupLimit() - if recentTx > 0 { // 0 means no limit (all txs available) - if recentTx <= blockSafetyMargin { - recentTx = 1 // 1 means tx lookup is not served at all + if recentTx != txIndexUnlimited { + if recentTx < blockSafetyMargin { + recentTx = txIndexDisabled } else { - recentTx -= blockSafetyMargin + recentTx -= blockSafetyMargin - txIndexRecentOffset } } if server.config.UltraLightOnlyAnnounce { - recentTx = 1 + recentTx = txIndexDisabled } - if recentTx != 0 && p.version < lpv4 { + if recentTx != txIndexUnlimited && p.version < lpv4 { return errors.New("Cannot serve old clients without a complete tx index") } // Note: clientPeer.headInfo should contain the last head announced to the client by us. diff --git a/les/protocol.go b/les/protocol.go index 03aad3283ab0..39d9f5152fd8 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -51,6 +51,10 @@ const ( NetworkId = 1 ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message blockSafetyMargin = 4 // safety margin applied to block ranges specified relative to head block + + txIndexUnlimited = 0 // this value in the "recentTxLookup" handshake field means the entire tx index history is served + txIndexDisabled = 1 // this value means tx index is not served at all + txIndexRecentOffset = 1 // txIndexRecentOffset + N in the handshake field means then tx index of the last N blocks is supported ) // les protocol message codes