From 14c15cba433dddec363f9423cbba97a43c6e6df8 Mon Sep 17 00:00:00 2001
From: Alex Sharov <AskAlexSharov@gmail.com>
Date: Sat, 22 May 2021 17:00:13 +0700
Subject: [PATCH] Check version of remote services (#1989)

* save

* save

* Squashed 'interfaces/' content from commit 08c32a09e

git-subtree-dir: interfaces
git-subtree-split: 08c32a09e40b1e6fcb5922e723191c9477545356

* Revert "Squashed 'interfaces/' content from commit 08c32a09e"

This reverts commit 8393d9fd

* save

* seve

* Squashed 'interfaces/' content from commit dd6a42724

git-subtree-dir: interfaces
git-subtree-split: dd6a42724401f34c21662ca1aa1718effb92320d

* ensure versions compatibility of all remote services

* Revert "Squashed 'interfaces/' content from commit dd6a42724"

This reverts commit 2a764bf9

* Squashed 'interfaces/' content from commit dd6a42724

git-subtree-dir: interfaces
git-subtree-split: dd6a42724401f34c21662ca1aa1718effb92320d

* Revert "Squashed 'interfaces/' content from commit dd6a42724"

This reverts commit 52621846

* Squashed 'interfaces/' content from commit dd6a42724

git-subtree-dir: interfaces
git-subtree-split: dd6a42724401f34c21662ca1aa1718effb92320d

* a

* a

* a

* a

* a

Co-authored-by: Alex Sharp <alexsharp@Alexs-MacBook-Pro.local>
---
 cmd/headers/download/downloader.go            |   5 +-
 cmd/rpcdaemon/cli/config.go                   |  32 ++--
 cmd/rpcdaemon/commands/daemon.go              |   4 +-
 cmd/rpcdaemon/commands/eth_api.go             |   6 +-
 cmd/rpcdaemon/commands/net_api.go             |   6 +-
 cmd/rpcdaemon/commands/web3_api.go            |   6 +-
 cmd/rpcdaemon/filters/filters.go              |   4 +-
 .../rpcdaemon/services}/eth_backend.go        |  32 +++-
 cmd/rpcdaemon/services/eth_mining.go          |  43 ++++++
 cmd/rpcdaemon/services/eth_txpool.go          |  43 ++++++
 ethdb/kv_abstract_test.go                     |  36 ++---
 ethdb/kv_remote.go                            |  66 ++++-----
 ethdb/remote/remotedbserver/ethbackend.go     |  18 ++-
 ethdb/remote/remotedbserver/mining.go         |  19 ++-
 ethdb/remote/remotedbserver/server.go         |   9 +-
 ethdb/remote/remotedbserver/txpool.go         |   9 ++
 gointerfaces/remote/ethbackend.pb.go          | 140 ++++++++++--------
 gointerfaces/remote/ethbackend_grpc.pb.go     |  40 +++++
 gointerfaces/txpool/txpool.pb.go              | 135 +++++++++--------
 gointerfaces/txpool/txpool_grpc.pb.go         |  40 +++++
 gointerfaces/version.go                       |  30 ++++
 interfaces/README.md                          |   9 +-
 interfaces/build.rs                           |   5 +
 interfaces/consensus_engine/consensus.proto   |  88 ++++++++---
 interfaces/remote/ethbackend.proto            |   4 +
 interfaces/txpool/txpool.proto                |   3 +
 p2p/discover/v4_udp_test.go                   |   4 +
 27 files changed, 578 insertions(+), 258 deletions(-)
 rename {core => cmd/rpcdaemon/services}/eth_backend.go (73%)
 create mode 100644 cmd/rpcdaemon/services/eth_mining.go
 create mode 100644 cmd/rpcdaemon/services/eth_txpool.go
 create mode 100644 gointerfaces/version.go

diff --git a/cmd/headers/download/downloader.go b/cmd/headers/download/downloader.go
index ad67c65340..1f814e79f0 100644
--- a/cmd/headers/download/downloader.go
+++ b/cmd/headers/download/downloader.go
@@ -39,8 +39,11 @@ import (
 func GrpcSentryClient(ctx context.Context, sentryAddr string) (proto_sentry.SentryClient, error) {
 	// creating grpc client connection
 	var dialOpts []grpc.DialOption
+
+	backoffCfg := backoff.DefaultConfig
+	backoffCfg.MaxDelay = 30 * time.Second
 	dialOpts = []grpc.DialOption{
-		grpc.WithConnectParams(grpc.ConnectParams{Backoff: backoff.DefaultConfig, MinConnectTimeout: 10 * time.Minute}),
+		grpc.WithConnectParams(grpc.ConnectParams{Backoff: backoffCfg, MinConnectTimeout: 10 * time.Minute}),
 		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(int(16 * datasize.MB))),
 		grpc.WithKeepaliveParams(keepalive.ClientParameters{}),
 	}
diff --git a/cmd/rpcdaemon/cli/config.go b/cmd/rpcdaemon/cli/config.go
index c1cdf59048..8495be23d5 100644
--- a/cmd/rpcdaemon/cli/config.go
+++ b/cmd/rpcdaemon/cli/config.go
@@ -8,13 +8,13 @@ import (
 	"path"
 	"time"
 
+	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/services"
 	"github.com/ledgerwatch/erigon/cmd/utils"
 	"github.com/ledgerwatch/erigon/common/dbutils"
 	"github.com/ledgerwatch/erigon/common/paths"
-	"github.com/ledgerwatch/erigon/core"
 	"github.com/ledgerwatch/erigon/ethdb"
 	"github.com/ledgerwatch/erigon/ethdb/remote/remotedbserver"
-	"github.com/ledgerwatch/erigon/gointerfaces/txpool"
+	"github.com/ledgerwatch/erigon/gointerfaces"
 	"github.com/ledgerwatch/erigon/gointerfaces/types"
 	"github.com/ledgerwatch/erigon/internal/debug"
 	"github.com/ledgerwatch/erigon/log"
@@ -162,7 +162,7 @@ func checkDbCompatibility(db ethdb.RoKV, mdbx bool) error {
 	return nil
 }
 
-func RemoteServices(cfg Flags, rootCancel context.CancelFunc) (kv ethdb.RoKV, eth core.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, err error) {
+func RemoteServices(cfg Flags, rootCancel context.CancelFunc) (kv ethdb.RoKV, eth services.ApiBackend, txPool *services.TxPoolService, mining *services.MiningService, err error) {
 	if !cfg.SingleNodeMode && cfg.PrivateApiAddr == "" {
 		return nil, nil, nil, nil, fmt.Errorf("either remote db or lmdb must be specified")
 	}
@@ -201,19 +201,31 @@ func RemoteServices(cfg Flags, rootCancel context.CancelFunc) (kv ethdb.RoKV, et
 		}
 	}
 	if cfg.PrivateApiAddr != "" {
-		remoteKv, err := ethdb.NewRemote(
-			remotedbserver.KvServiceAPIVersion.Major,
-			remotedbserver.KvServiceAPIVersion.Minor,
-			remotedbserver.KvServiceAPIVersion.Patch).Path(cfg.PrivateApiAddr).Open(cfg.TLSCertfile, cfg.TLSKeyFile, cfg.TLSCACert, rootCancel)
+		remoteKv, err := ethdb.NewRemote(gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion)).Path(cfg.PrivateApiAddr).Open(cfg.TLSCertfile, cfg.TLSKeyFile, cfg.TLSCACert)
 		if err != nil {
 			return nil, nil, nil, nil, fmt.Errorf("could not connect to remoteKv: %w", err)
 		}
-		eth = core.NewRemoteBackend(remoteKv.GrpcConn())
-		mining = txpool.NewMiningClient(remoteKv.GrpcConn())
-		txPool = txpool.NewTxpoolClient(remoteKv.GrpcConn())
+		remoteEth := services.NewRemoteBackend(remoteKv.GrpcConn())
+		mining = services.NewMiningService(remoteKv.GrpcConn())
+		txPool = services.NewTxPoolService(remoteKv.GrpcConn())
 		if kv == nil {
 			kv = remoteKv
 		}
+		eth = remoteEth
+		go func() {
+			if !remoteKv.EnsureVersionCompatibility() {
+				rootCancel()
+			}
+			if !remoteEth.EnsureVersionCompatibility() {
+				rootCancel()
+			}
+			if !mining.EnsureVersionCompatibility() {
+				rootCancel()
+			}
+			if !txPool.EnsureVersionCompatibility() {
+				rootCancel()
+			}
+		}()
 	}
 	return kv, eth, txPool, mining, err
 }
diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go
index d172565476..7eb04f17ca 100644
--- a/cmd/rpcdaemon/commands/daemon.go
+++ b/cmd/rpcdaemon/commands/daemon.go
@@ -5,14 +5,14 @@ import (
 
 	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli"
 	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters"
-	"github.com/ledgerwatch/erigon/core"
+	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/services"
 	"github.com/ledgerwatch/erigon/ethdb"
 	"github.com/ledgerwatch/erigon/gointerfaces/txpool"
 	"github.com/ledgerwatch/erigon/rpc"
 )
 
 // APIList describes the list of available RPC apis
-func APIList(ctx context.Context, db ethdb.RoKV, eth core.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, filters *filters.Filters, cfg cli.Flags, customAPIList []rpc.API) []rpc.API {
+func APIList(ctx context.Context, db ethdb.RoKV, eth services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, filters *filters.Filters, cfg cli.Flags, customAPIList []rpc.API) []rpc.API {
 	var defaultAPIList []rpc.API
 
 	base := NewBaseApi(filters)
diff --git a/cmd/rpcdaemon/commands/eth_api.go b/cmd/rpcdaemon/commands/eth_api.go
index c641827d02..4ad9f43eb4 100644
--- a/cmd/rpcdaemon/commands/eth_api.go
+++ b/cmd/rpcdaemon/commands/eth_api.go
@@ -7,10 +7,10 @@ import (
 	"sync"
 
 	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters"
+	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/services"
 	"github.com/ledgerwatch/erigon/common"
 	"github.com/ledgerwatch/erigon/common/hexutil"
 	"github.com/ledgerwatch/erigon/common/math"
-	"github.com/ledgerwatch/erigon/core"
 	"github.com/ledgerwatch/erigon/core/rawdb"
 	"github.com/ledgerwatch/erigon/core/types"
 	ethFilters "github.com/ledgerwatch/erigon/eth/filters"
@@ -158,7 +158,7 @@ func (api *BaseAPI) getBlockByNumber(number rpc.BlockNumber, tx ethdb.Tx) (*type
 // APIImpl is implementation of the EthAPI interface based on remote Db access
 type APIImpl struct {
 	*BaseAPI
-	ethBackend core.ApiBackend
+	ethBackend services.ApiBackend
 	txPool     txpool.TxpoolClient
 	mining     txpool.MiningClient
 	db         ethdb.RoKV
@@ -166,7 +166,7 @@ type APIImpl struct {
 }
 
 // NewEthAPI returns APIImpl instance
-func NewEthAPI(base *BaseAPI, db ethdb.RoKV, eth core.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, gascap uint64) *APIImpl {
+func NewEthAPI(base *BaseAPI, db ethdb.RoKV, eth services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, gascap uint64) *APIImpl {
 	if gascap == 0 {
 		gascap = uint64(math.MaxUint64 / 2)
 	}
diff --git a/cmd/rpcdaemon/commands/net_api.go b/cmd/rpcdaemon/commands/net_api.go
index 737cbbaf18..9931a7c879 100644
--- a/cmd/rpcdaemon/commands/net_api.go
+++ b/cmd/rpcdaemon/commands/net_api.go
@@ -5,8 +5,8 @@ import (
 	"fmt"
 	"strconv"
 
+	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/services"
 	"github.com/ledgerwatch/erigon/common/hexutil"
-	"github.com/ledgerwatch/erigon/core"
 )
 
 // NetAPI the interface for the net_ RPC commands
@@ -18,11 +18,11 @@ type NetAPI interface {
 
 // NetAPIImpl data structure to store things needed for net_ commands
 type NetAPIImpl struct {
-	ethBackend core.ApiBackend
+	ethBackend services.ApiBackend
 }
 
 // NewNetAPIImpl returns NetAPIImplImpl instance
-func NewNetAPIImpl(eth core.ApiBackend) *NetAPIImpl {
+func NewNetAPIImpl(eth services.ApiBackend) *NetAPIImpl {
 	return &NetAPIImpl{
 		ethBackend: eth,
 	}
diff --git a/cmd/rpcdaemon/commands/web3_api.go b/cmd/rpcdaemon/commands/web3_api.go
index 4b66daba7e..5ad8cc9a73 100644
--- a/cmd/rpcdaemon/commands/web3_api.go
+++ b/cmd/rpcdaemon/commands/web3_api.go
@@ -3,8 +3,8 @@ package commands
 import (
 	"context"
 
+	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/services"
 	"github.com/ledgerwatch/erigon/common/hexutil"
-	"github.com/ledgerwatch/erigon/core"
 	"github.com/ledgerwatch/erigon/crypto"
 )
 
@@ -16,11 +16,11 @@ type Web3API interface {
 
 type Web3APIImpl struct {
 	*BaseAPI
-	ethBackend core.ApiBackend
+	ethBackend services.ApiBackend
 }
 
 // NewWeb3APIImpl returns Web3APIImpl instance
-func NewWeb3APIImpl(ethBackend core.ApiBackend) *Web3APIImpl {
+func NewWeb3APIImpl(ethBackend services.ApiBackend) *Web3APIImpl {
 	return &Web3APIImpl{
 		BaseAPI:    &BaseAPI{},
 		ethBackend: ethBackend,
diff --git a/cmd/rpcdaemon/filters/filters.go b/cmd/rpcdaemon/filters/filters.go
index d9e41705d8..29dad30eea 100644
--- a/cmd/rpcdaemon/filters/filters.go
+++ b/cmd/rpcdaemon/filters/filters.go
@@ -10,7 +10,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/ledgerwatch/erigon/core"
+	"github.com/ledgerwatch/erigon/cmd/rpcdaemon/services"
 	"github.com/ledgerwatch/erigon/core/types"
 	"github.com/ledgerwatch/erigon/gointerfaces/remote"
 	"github.com/ledgerwatch/erigon/gointerfaces/txpool"
@@ -39,7 +39,7 @@ type Filters struct {
 	pendingTxsSubs   map[PendingTxsSubID]chan []types.Transaction
 }
 
-func New(ctx context.Context, ethBackend core.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient) *Filters {
+func New(ctx context.Context, ethBackend services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient) *Filters {
 	log.Info("rpc filters: subscribing to tg events")
 
 	ff := &Filters{
diff --git a/core/eth_backend.go b/cmd/rpcdaemon/services/eth_backend.go
similarity index 73%
rename from core/eth_backend.go
rename to cmd/rpcdaemon/services/eth_backend.go
index 5b05a61e31..a7f1419140 100644
--- a/core/eth_backend.go
+++ b/cmd/rpcdaemon/services/eth_backend.go
@@ -1,16 +1,19 @@
-package core
+package services
 
 import (
 	"context"
 	"errors"
+	"fmt"
 	"io"
 
 	"github.com/ledgerwatch/erigon/common"
+	"github.com/ledgerwatch/erigon/ethdb/remote/remotedbserver"
 	"github.com/ledgerwatch/erigon/gointerfaces"
 	"github.com/ledgerwatch/erigon/gointerfaces/remote"
 	"github.com/ledgerwatch/erigon/log"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/types/known/emptypb"
 )
 
 // ApiBackend - interface which must be used by API layer
@@ -24,22 +27,35 @@ type ApiBackend interface {
 	Subscribe(ctx context.Context, cb func(*remote.SubscribeReply)) error
 }
 
-type EthBackend interface {
-	Etherbase() (common.Address, error)
-	NetVersion() (uint64, error)
-	IsMining() bool
-}
-
 type RemoteBackend struct {
 	remoteEthBackend remote.ETHBACKENDClient
 	log              log.Logger
+	version          gointerfaces.Version
 }
 
 func NewRemoteBackend(cc grpc.ClientConnInterface) *RemoteBackend {
 	return &RemoteBackend{
 		remoteEthBackend: remote.NewETHBACKENDClient(cc),
-		log:              log.New("remote_db"),
+		version:          gointerfaces.VersionFromProto(remotedbserver.EthBackendAPIVersion),
+		log:              log.New("remote_service", "eth_backend"),
+	}
+}
+
+func (back *RemoteBackend) EnsureVersionCompatibility() bool {
+	versionReply, err := back.remoteEthBackend.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true))
+	if err != nil {
+
+		back.log.Error("getting Version", "error", err)
+		return false
+	}
+	if !gointerfaces.EnsureVersion(back.version, versionReply) {
+		back.log.Error("incompatible interface versions", "client", back.version.String(),
+			"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
+		return false
 	}
+	back.log.Info("interfaces compatible", "client", back.version.String(),
+		"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
+	return true
 }
 
 func (back *RemoteBackend) Etherbase(ctx context.Context) (common.Address, error) {
diff --git a/cmd/rpcdaemon/services/eth_mining.go b/cmd/rpcdaemon/services/eth_mining.go
new file mode 100644
index 0000000000..5d5407ea4e
--- /dev/null
+++ b/cmd/rpcdaemon/services/eth_mining.go
@@ -0,0 +1,43 @@
+package services
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/ledgerwatch/erigon/ethdb/remote/remotedbserver"
+	"github.com/ledgerwatch/erigon/gointerfaces"
+	"github.com/ledgerwatch/erigon/gointerfaces/txpool"
+	"github.com/ledgerwatch/erigon/log"
+	"google.golang.org/grpc"
+	"google.golang.org/protobuf/types/known/emptypb"
+)
+
+type MiningService struct {
+	txpool.MiningClient
+	log     log.Logger
+	version gointerfaces.Version
+}
+
+func NewMiningService(cc grpc.ClientConnInterface) *MiningService {
+	return &MiningService{
+		MiningClient: txpool.NewMiningClient(cc),
+		version:      gointerfaces.VersionFromProto(remotedbserver.MiningAPIVersion),
+		log:          log.New("remote_service", "mining"),
+	}
+}
+
+func (s *MiningService) EnsureVersionCompatibility() bool {
+	versionReply, err := s.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true))
+	if err != nil {
+		s.log.Error("getting Version", "error", err)
+		return false
+	}
+	if !gointerfaces.EnsureVersion(s.version, versionReply) {
+		s.log.Error("incompatible interface versions", "client", s.version.String(),
+			"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
+		return false
+	}
+	s.log.Info("interfaces compatible", "client", s.version.String(),
+		"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
+	return true
+}
diff --git a/cmd/rpcdaemon/services/eth_txpool.go b/cmd/rpcdaemon/services/eth_txpool.go
new file mode 100644
index 0000000000..fb12583b74
--- /dev/null
+++ b/cmd/rpcdaemon/services/eth_txpool.go
@@ -0,0 +1,43 @@
+package services
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/ledgerwatch/erigon/ethdb/remote/remotedbserver"
+	"github.com/ledgerwatch/erigon/gointerfaces"
+	"github.com/ledgerwatch/erigon/gointerfaces/txpool"
+	"github.com/ledgerwatch/erigon/log"
+	"google.golang.org/grpc"
+	"google.golang.org/protobuf/types/known/emptypb"
+)
+
+type TxPoolService struct {
+	txpool.TxpoolClient
+	log     log.Logger
+	version gointerfaces.Version
+}
+
+func NewTxPoolService(cc grpc.ClientConnInterface) *TxPoolService {
+	return &TxPoolService{
+		TxpoolClient: txpool.NewTxpoolClient(cc),
+		version:      gointerfaces.VersionFromProto(remotedbserver.TxPoolAPIVersion),
+		log:          log.New("remote_service", "tx_pool"),
+	}
+}
+
+func (s *TxPoolService) EnsureVersionCompatibility() bool {
+	versionReply, err := s.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true))
+	if err != nil {
+		s.log.Error("ensure version", "error", err)
+		return false
+	}
+	if !gointerfaces.EnsureVersion(s.version, versionReply) {
+		s.log.Error("incompatible interface versions", "client", s.version.String(),
+			"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
+		return false
+	}
+	s.log.Info("interfaces compatible", "client", s.version.String(),
+		"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
+	return true
+}
diff --git a/ethdb/kv_abstract_test.go b/ethdb/kv_abstract_test.go
index e19adbbe16..4a1576656b 100644
--- a/ethdb/kv_abstract_test.go
+++ b/ethdb/kv_abstract_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/ledgerwatch/erigon/common/dbutils"
 	"github.com/ledgerwatch/erigon/ethdb"
 	"github.com/ledgerwatch/erigon/ethdb/remote/remotedbserver"
+	"github.com/ledgerwatch/erigon/gointerfaces"
 	"github.com/ledgerwatch/erigon/gointerfaces/remote"
 	"github.com/ledgerwatch/erigon/log"
 	"github.com/stretchr/testify/assert"
@@ -148,36 +149,31 @@ func TestRemoteKvVersion(t *testing.T) {
 			log.Error("private RPC server fail", "err", err)
 		}
 	}()
+	v := gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion)
 	// Different Major versions
-	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
-	_, err := ethdb.NewRemote(remotedbserver.KvServiceAPIVersion.Major+1, remotedbserver.KvServiceAPIVersion.Minor, remotedbserver.KvServiceAPIVersion.Patch).InMem(conn).Open("", "", "", cancel)
+	v1 := v
+	v1.Major++
+	a, err := ethdb.NewRemote(v1).InMem(conn).Open("", "", "")
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
-	<-ctx.Done()
-	if !errors.Is(ctx.Err(), context.Canceled) {
-		t.Errorf("Should have failed due to incompatibitity")
-	}
+	require.False(t, a.EnsureVersionCompatibility())
 	// Different Minor versions
-	ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
-	_, err = ethdb.NewRemote(remotedbserver.KvServiceAPIVersion.Major, remotedbserver.KvServiceAPIVersion.Minor+1, remotedbserver.KvServiceAPIVersion.Patch).InMem(conn).Open("", "", "", cancel)
+	v2 := v
+	v2.Minor++
+	_, err = ethdb.NewRemote(v2).InMem(conn).Open("", "", "")
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
-	<-ctx.Done()
-	if !errors.Is(ctx.Err(), context.Canceled) {
-		t.Errorf("Should have failed due to incompatibitity")
-	}
+	require.False(t, a.EnsureVersionCompatibility())
 	// Different Patch versions
-	ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
-	_, err = ethdb.NewRemote(remotedbserver.KvServiceAPIVersion.Major, remotedbserver.KvServiceAPIVersion.Minor, remotedbserver.KvServiceAPIVersion.Patch+1).InMem(conn).Open("", "", "", cancel)
+	v3 := v
+	v3.Patch++
+	_, err = ethdb.NewRemote(v3).InMem(conn).Open("", "", "")
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
-	<-ctx.Done()
-	if !errors.Is(ctx.Err(), context.DeadlineExceeded) {
-		t.Errorf("Should not have failed due to incompatibitity: %v", ctx.Err())
-	}
+	require.False(t, a.EnsureVersionCompatibility())
 }
 
 func setupDatabases(t *testing.T, f ethdb.BucketConfigsFunc) (writeDBs []ethdb.RwKV, readDBs []ethdb.RwKV) {
@@ -196,8 +192,8 @@ func setupDatabases(t *testing.T, f ethdb.BucketConfigsFunc) (writeDBs []ethdb.R
 			log.Error("private RPC server fail", "err", err)
 		}
 	}()
-
-	rdb := ethdb.NewRemote(remotedbserver.KvServiceAPIVersion.Major, remotedbserver.KvServiceAPIVersion.Minor, remotedbserver.KvServiceAPIVersion.Patch).InMem(conn).MustOpen()
+	v := gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion)
+	rdb := ethdb.NewRemote(v).InMem(conn).MustOpen()
 	readDBs = []ethdb.RwKV{
 		writeDBs[0],
 		writeDBs[1],
diff --git a/ethdb/kv_remote.go b/ethdb/kv_remote.go
index 7dd2be9a9b..1f0926397c 100644
--- a/ethdb/kv_remote.go
+++ b/ethdb/kv_remote.go
@@ -15,6 +15,7 @@ import (
 
 	"github.com/c2h5oh/datasize"
 	"github.com/ledgerwatch/erigon/common/dbutils"
+	"github.com/ledgerwatch/erigon/gointerfaces"
 	"github.com/ledgerwatch/erigon/gointerfaces/remote"
 	"github.com/ledgerwatch/erigon/log"
 	"google.golang.org/grpc"
@@ -29,12 +30,11 @@ import (
 //go:generate protoc --proto_path=../interfaces --go_out=. --go-grpc_out=. "remote/kv.proto" -I=. -I=./../build/include/google
 //go:generate protoc --proto_path=../interfaces --go_out=. --go-grpc_out=. "remote/db.proto" -I=. -I=./../build/include/google
 //go:generate protoc --proto_path=../interfaces --go_out=. --go-grpc_out=. "remote/ethbackend.proto" -I=. -I=./../build/include/google
-
 type remoteOpts struct {
-	DialAddress                              string
-	inMemConn                                *bufconn.Listener // for tests
-	bucketsCfg                               BucketConfigsFunc
-	versionMajor, versionMinor, versionPatch uint32 // KV interface version of the client - to perform compatibility check when opening
+	DialAddress string
+	inMemConn   *bufconn.Listener // for tests
+	bucketsCfg  BucketConfigsFunc
+	version     gointerfaces.Version
 }
 
 type RemoteKV struct {
@@ -87,10 +87,13 @@ func (opts remoteOpts) InMem(listener *bufconn.Listener) remoteOpts {
 	return opts
 }
 
-func (opts remoteOpts) Open(certFile, keyFile, caCert string, cancelFn context.CancelFunc) (*RemoteKV, error) {
+func (opts remoteOpts) Open(certFile, keyFile, caCert string) (*RemoteKV, error) {
 	var dialOpts []grpc.DialOption
+
+	backoffCfg := backoff.DefaultConfig
+	backoffCfg.MaxDelay = 30 * time.Second
 	dialOpts = []grpc.DialOption{
-		grpc.WithConnectParams(grpc.ConnectParams{Backoff: backoff.DefaultConfig, MinConnectTimeout: 10 * time.Minute}),
+		grpc.WithConnectParams(grpc.ConnectParams{Backoff: backoffCfg, MinConnectTimeout: 10 * time.Minute}),
 		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(int(5 * datasize.MB))),
 		grpc.WithKeepaliveParams(keepalive.ClientParameters{}),
 	}
@@ -146,31 +149,6 @@ func (opts remoteOpts) Open(certFile, keyFile, caCert string, cancelFn context.C
 	}
 
 	kvClient := remote.NewKVClient(conn)
-	// Perform compatibility check
-	go func() {
-		versionReply, err := kvClient.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true))
-		if err != nil {
-			log.Error("getting Version info from remove KV", "error", err)
-			cancelFn()
-			return
-		}
-		var compatible bool
-		if versionReply.Major != opts.versionMajor {
-			compatible = false
-		} else if versionReply.Minor != opts.versionMinor {
-			compatible = false
-		} else {
-			compatible = true
-		}
-		if !compatible {
-			log.Error("incompatible KV interface versions", "client", fmt.Sprintf("%d.%d.%d", opts.versionMajor, opts.versionMinor, opts.versionPatch),
-				"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
-			cancelFn()
-			return
-		}
-		log.Info("KV interfaces compatible", "client", fmt.Sprintf("%d.%d.%d", opts.versionMajor, opts.versionMinor, opts.versionPatch),
-			"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
-	}()
 	db := &RemoteKV{
 		opts:     opts,
 		conn:     conn,
@@ -187,7 +165,7 @@ func (opts remoteOpts) Open(certFile, keyFile, caCert string, cancelFn context.C
 }
 
 func (opts remoteOpts) MustOpen() RwKV {
-	db, err := opts.Open("", "", "", func() {})
+	db, err := opts.Open("", "", "")
 	if err != nil {
 		panic(err)
 	}
@@ -197,8 +175,8 @@ func (opts remoteOpts) MustOpen() RwKV {
 // NewRemote defines new remove KV connection (without actually opening it)
 // version parameters represent the version the KV client is expecting,
 // compatibility check will be performed when the KV connection opens
-func NewRemote(versionMajor, versionMinor, versionPatch uint32) remoteOpts {
-	return remoteOpts{bucketsCfg: DefaultBucketConfigs, versionMajor: versionMajor, versionMinor: versionMinor, versionPatch: versionPatch}
+func NewRemote(v gointerfaces.Version) remoteOpts {
+	return remoteOpts{bucketsCfg: DefaultBucketConfigs, version: v}
 }
 
 func (db *RemoteKV) AllBuckets() dbutils.BucketsCfg {
@@ -209,8 +187,22 @@ func (db *RemoteKV) GrpcConn() *grpc.ClientConn {
 	return db.conn
 }
 
-// Close
-// All transactions must be closed before closing the database.
+func (db *RemoteKV) EnsureVersionCompatibility() bool {
+	versionReply, err := db.remoteKV.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true))
+	if err != nil {
+		db.log.Error("getting Version", "error", err)
+		return false
+	}
+	if !gointerfaces.EnsureVersion(db.opts.version, versionReply) {
+		db.log.Error("incompatible interface versions", "client", db.opts.version.String(),
+			"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
+		return false
+	}
+	db.log.Info("interfaces compatible", "client", db.opts.version.String(),
+		"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
+	return true
+}
+
 func (db *RemoteKV) Close() {
 	if db.conn != nil {
 		if err := db.conn.Close(); err != nil {
diff --git a/ethdb/remote/remotedbserver/ethbackend.go b/ethdb/remote/remotedbserver/ethbackend.go
index 82bbd24cc5..a499d6963f 100644
--- a/ethdb/remote/remotedbserver/ethbackend.go
+++ b/ethdb/remote/remotedbserver/ethbackend.go
@@ -5,7 +5,6 @@ import (
 	"context"
 
 	"github.com/ledgerwatch/erigon/common"
-	"github.com/ledgerwatch/erigon/core"
 	"github.com/ledgerwatch/erigon/core/types"
 	"github.com/ledgerwatch/erigon/gointerfaces"
 	"github.com/ledgerwatch/erigon/gointerfaces/remote"
@@ -16,22 +15,29 @@ import (
 	"google.golang.org/protobuf/types/known/emptypb"
 )
 
+// EthBackendAPIVersion
+// 2.0.0 - move all mining-related methods to 'txpool/mining' server
+var EthBackendAPIVersion = &types2.VersionReply{Major: 2, Minor: 0, Patch: 0}
+
 type EthBackendServer struct {
 	remote.UnimplementedETHBACKENDServer // must be embedded to have forward compatible implementations.
 
-	eth       core.EthBackend
+	eth       EthBackend
 	events    *Events
 	gitCommit string
 }
 
-func NewEthBackendServer(eth core.EthBackend, events *Events, gitCommit string) *EthBackendServer {
+type EthBackend interface {
+	Etherbase() (common.Address, error)
+	NetVersion() (uint64, error)
+}
+
+func NewEthBackendServer(eth EthBackend, events *Events, gitCommit string) *EthBackendServer {
 	return &EthBackendServer{eth: eth, events: events, gitCommit: gitCommit}
 }
 
-// Version
-// 2.0.0 - move all mining-related methods to 'txpool/mining' server
 func (s *EthBackendServer) Version(context.Context, *emptypb.Empty) (*types2.VersionReply, error) {
-	return &types2.VersionReply{Major: 2, Minor: 0, Patch: 0}, nil
+	return EthBackendAPIVersion, nil
 }
 
 func (s *EthBackendServer) Etherbase(_ context.Context, _ *remote.EtherbaseRequest) (*remote.EtherbaseReply, error) {
diff --git a/ethdb/remote/remotedbserver/mining.go b/ethdb/remote/remotedbserver/mining.go
index 5a06fdc7ff..aea712eb59 100644
--- a/ethdb/remote/remotedbserver/mining.go
+++ b/ethdb/remote/remotedbserver/mining.go
@@ -9,7 +9,6 @@ import (
 	"github.com/ledgerwatch/erigon/common"
 	"github.com/ledgerwatch/erigon/common/hexutil"
 	"github.com/ledgerwatch/erigon/consensus/ethash"
-	"github.com/ledgerwatch/erigon/core"
 	"github.com/ledgerwatch/erigon/core/types"
 	proto_txpool "github.com/ledgerwatch/erigon/gointerfaces/txpool"
 	types2 "github.com/ledgerwatch/erigon/gointerfaces/types"
@@ -18,6 +17,10 @@ import (
 	"google.golang.org/protobuf/types/known/emptypb"
 )
 
+// EthBackendServiceAPIVersion
+// 2.0.0 - move all mining-related methods to 'txpool/mining' server
+var MiningAPIVersion = &types2.VersionReply{Major: 1, Minor: 0, Patch: 0}
+
 type MiningServer struct {
 	proto_txpool.UnimplementedMiningServer
 	ctx                 context.Context
@@ -25,15 +28,19 @@ type MiningServer struct {
 	pendingBlockStreams PendingBlockStreams
 	minedBlockStreams   MinedBlockStreams
 	ethash              *ethash.API
-	eth                 core.EthBackend
+	isMining            IsMining
+}
+
+type IsMining interface {
+	IsMining() bool
 }
 
-func NewMiningServer(ctx context.Context, eth core.EthBackend, ethashApi *ethash.API) *MiningServer {
-	return &MiningServer{ctx: ctx, eth: eth, ethash: ethashApi}
+func NewMiningServer(ctx context.Context, isMining IsMining, ethashApi *ethash.API) *MiningServer {
+	return &MiningServer{ctx: ctx, isMining: isMining, ethash: ethashApi}
 }
 
 func (s *MiningServer) Version(context.Context, *emptypb.Empty) (*types2.VersionReply, error) {
-	return &types2.VersionReply{Major: 1, Minor: 0, Patch: 0}, nil
+	return MiningAPIVersion, nil
 }
 
 func (s *MiningServer) GetWork(context.Context, *proto_txpool.GetWorkRequest) (*proto_txpool.GetWorkReply, error) {
@@ -76,7 +83,7 @@ func (s *MiningServer) Mining(_ context.Context, req *proto_txpool.MiningRequest
 	if s.ethash == nil {
 		return nil, errors.New("not supported, consensus engine is not ethash")
 	}
-	return &proto_txpool.MiningReply{Enabled: s.eth.IsMining(), Running: true}, nil
+	return &proto_txpool.MiningReply{Enabled: s.isMining.IsMining(), Running: true}, nil
 }
 
 func (s *MiningServer) OnPendingLogs(req *proto_txpool.OnPendingLogsRequest, reply proto_txpool.Mining_OnPendingLogsServer) error {
diff --git a/ethdb/remote/remotedbserver/server.go b/ethdb/remote/remotedbserver/server.go
index cf4f3b88a8..8d204a8a65 100644
--- a/ethdb/remote/remotedbserver/server.go
+++ b/ethdb/remote/remotedbserver/server.go
@@ -29,7 +29,7 @@ const MaxTxTTL = 30 * time.Second
 // KvServiceAPIVersion - use it to track changes in API
 // 1.1.0 - added pending transactions, add methods eth_getRawTransactionByHash, eth_retRawTransactionByBlockHashAndIndex, eth_retRawTransactionByBlockNumberAndIndex| Yes     |                                            |
 // 1.2.0 - Added separated services for mining and txpool methods
-var KvServiceAPIVersion = types.VersionReply{Major: 1, Minor: 2, Patch: 0}
+var KvServiceAPIVersion = &types.VersionReply{Major: 1, Minor: 2, Patch: 0}
 
 type KvServer struct {
 	remote.UnimplementedKVServer // must be embedded to have forward compatible implementations.
@@ -110,20 +110,17 @@ func (s *KvServer) Version(context.Context, *emptypb.Empty) (*types.VersionReply
 		dbSchemaVersion = &dbutils.DBSchemaVersionLMDB
 	}
 	if KvServiceAPIVersion.Major > dbSchemaVersion.Major {
-		return &KvServiceAPIVersion, nil
+		return KvServiceAPIVersion, nil
 	}
 	if dbSchemaVersion.Major > KvServiceAPIVersion.Major {
 		return dbSchemaVersion, nil
 	}
 	if KvServiceAPIVersion.Minor > dbSchemaVersion.Minor {
-		return &KvServiceAPIVersion, nil
+		return KvServiceAPIVersion, nil
 	}
 	if dbSchemaVersion.Minor > KvServiceAPIVersion.Minor {
 		return dbSchemaVersion, nil
 	}
-	if KvServiceAPIVersion.Minor > dbSchemaVersion.Minor {
-		return &KvServiceAPIVersion, nil
-	}
 	return dbSchemaVersion, nil
 }
 
diff --git a/ethdb/remote/remotedbserver/txpool.go b/ethdb/remote/remotedbserver/txpool.go
index b4700ac639..25b3d00920 100644
--- a/ethdb/remote/remotedbserver/txpool.go
+++ b/ethdb/remote/remotedbserver/txpool.go
@@ -11,9 +11,14 @@ import (
 	"github.com/ledgerwatch/erigon/event"
 	"github.com/ledgerwatch/erigon/gointerfaces"
 	proto_txpool "github.com/ledgerwatch/erigon/gointerfaces/txpool"
+	types2 "github.com/ledgerwatch/erigon/gointerfaces/types"
 	"github.com/ledgerwatch/erigon/log"
+	"google.golang.org/protobuf/types/known/emptypb"
 )
 
+// TxPoolAPIVersion
+var TxPoolAPIVersion = &types2.VersionReply{Major: 1, Minor: 0, Patch: 0}
+
 type txPool interface {
 	Get(hash common.Hash) types.Transaction
 	AddLocals(txs []types.Transaction) []error
@@ -30,6 +35,10 @@ func NewTxPoolServer(ctx context.Context, txPool txPool) *TxPoolServer {
 	return &TxPoolServer{ctx: ctx, txPool: txPool}
 }
 
+func (s *TxPoolServer) Version(context.Context, *emptypb.Empty) (*types2.VersionReply, error) {
+	return MiningAPIVersion, nil
+}
+
 func (s *TxPoolServer) FindUnknown(ctx context.Context, in *proto_txpool.TxHashes) (*proto_txpool.TxHashes, error) {
 	return nil, fmt.Errorf("unimplemented")
 	/*
diff --git a/gointerfaces/remote/ethbackend.pb.go b/gointerfaces/remote/ethbackend.pb.go
index 54ad7beb4c..d46a630db0 100644
--- a/gointerfaces/remote/ethbackend.pb.go
+++ b/gointerfaces/remote/ethbackend.pb.go
@@ -10,6 +10,7 @@ import (
 	types "github.com/ledgerwatch/erigon/gointerfaces/types"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
 	reflect "reflect"
 	sync "sync"
 )
@@ -517,61 +518,66 @@ var File_remote_ethbackend_proto protoreflect.FileDescriptor
 var file_remote_ethbackend_proto_rawDesc = []byte{
 	0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x65, 0x74, 0x68, 0x62, 0x61, 0x63, 0x6b,
 	0x65, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x74,
-	0x65, 0x1a, 0x11, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x12, 0x0a, 0x10, 0x45, 0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73,
-	0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x37, 0x0a, 0x0e, 0x45, 0x74, 0x68, 0x65,
-	0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x25, 0x0a, 0x07, 0x61, 0x64,
-	0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79,
-	0x70, 0x65, 0x73, 0x2e, 0x48, 0x31, 0x36, 0x30, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
-	0x73, 0x22, 0x13, 0x0a, 0x11, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x21, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72,
-	0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x50, 0x72, 0x6f,
-	0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x22, 0x26, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56,
-	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69,
-	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x43,
-	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x22, 0x30, 0x0a, 0x12, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72,
-	0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x6f, 0x64,
-	0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64,
-	0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x35, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
-	0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x79, 0x70,
-	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
-	0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x47, 0x0a, 0x0e,
-	0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x21,
-	0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72,
-	0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x74, 0x79, 0x70,
-	0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
-	0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x38, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0a,
-	0x0a, 0x06, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45,
-	0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4c, 0x4f, 0x47, 0x53, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d,
-	0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x32,
-	0xea, 0x02, 0x0a, 0x0a, 0x45, 0x54, 0x48, 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x12, 0x3d,
-	0x0a, 0x09, 0x45, 0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x12, 0x18, 0x2e, 0x72, 0x65,
-	0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45,
-	0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x40, 0x0a,
-	0x0a, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x72, 0x65,
-	0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e,
-	0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
-	0x4f, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69,
-	0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74,
-	0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74,
-	0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79,
-	0x12, 0x49, 0x0a, 0x0d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
-	0x6e, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e,
-	0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
-	0x1a, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56,
-	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3f, 0x0a, 0x09, 0x53,
-	0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74,
-	0x65, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x73,
-	0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x30, 0x01, 0x42, 0x11, 0x5a, 0x0f,
-	0x2e, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x3b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x65, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+	0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11,
+	0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x22, 0x12, 0x0a, 0x10, 0x45, 0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x37, 0x0a, 0x0e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x62, 0x61,
+	0x73, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x25, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
+	0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73,
+	0x2e, 0x48, 0x31, 0x36, 0x30, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x13,
+	0x0a, 0x11, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x22, 0x21, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x22, 0x26, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x22, 0x30, 0x0a, 0x12, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61,
+	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61,
+	0x6d, 0x65, 0x22, 0x35, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x76,
+	0x65, 0x6e, 0x74, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x53, 0x75, 0x62,
+	0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x04, 0x74,
+	0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, 0x6f,
+	0x74, 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12,
+	0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61,
+	0x74, 0x61, 0x2a, 0x38, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0a, 0x0a, 0x06, 0x48,
+	0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x4e, 0x44, 0x49,
+	0x4e, 0x47, 0x5f, 0x4c, 0x4f, 0x47, 0x53, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x45, 0x4e,
+	0x44, 0x49, 0x4e, 0x47, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x32, 0xa2, 0x03, 0x0a,
+	0x0a, 0x45, 0x54, 0x48, 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x12, 0x3d, 0x0a, 0x09, 0x45,
+	0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74,
+	0x65, 0x2e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x74, 0x68, 0x65,
+	0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x40, 0x0a, 0x0a, 0x4e, 0x65,
+	0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74,
+	0x65, 0x2e, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x4e, 0x65, 0x74,
+	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x36, 0x0a, 0x07,
+	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
+	0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
+	0x65, 0x70, 0x6c, 0x79, 0x12, 0x4f, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
+	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
+	0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
+	0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x49, 0x0a, 0x0d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56,
+	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e,
+	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79,
+	0x12, 0x3f, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x18, 0x2e,
+	0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
+	0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x30,
+	0x01, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x3b, 0x72, 0x65,
+	0x6d, 0x6f, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -601,6 +607,8 @@ var file_remote_ethbackend_proto_goTypes = []interface{}{
 	(*SubscribeRequest)(nil),       // 9: remote.SubscribeRequest
 	(*SubscribeReply)(nil),         // 10: remote.SubscribeReply
 	(*types.H160)(nil),             // 11: types.H160
+	(*emptypb.Empty)(nil),          // 12: google.protobuf.Empty
+	(*types.VersionReply)(nil),     // 13: types.VersionReply
 }
 var file_remote_ethbackend_proto_depIdxs = []int32{
 	11, // 0: remote.EtherbaseReply.address:type_name -> types.H160
@@ -608,16 +616,18 @@ var file_remote_ethbackend_proto_depIdxs = []int32{
 	0,  // 2: remote.SubscribeReply.type:type_name -> remote.Event
 	1,  // 3: remote.ETHBACKEND.Etherbase:input_type -> remote.EtherbaseRequest
 	3,  // 4: remote.ETHBACKEND.NetVersion:input_type -> remote.NetVersionRequest
-	5,  // 5: remote.ETHBACKEND.ProtocolVersion:input_type -> remote.ProtocolVersionRequest
-	7,  // 6: remote.ETHBACKEND.ClientVersion:input_type -> remote.ClientVersionRequest
-	9,  // 7: remote.ETHBACKEND.Subscribe:input_type -> remote.SubscribeRequest
-	2,  // 8: remote.ETHBACKEND.Etherbase:output_type -> remote.EtherbaseReply
-	4,  // 9: remote.ETHBACKEND.NetVersion:output_type -> remote.NetVersionReply
-	6,  // 10: remote.ETHBACKEND.ProtocolVersion:output_type -> remote.ProtocolVersionReply
-	8,  // 11: remote.ETHBACKEND.ClientVersion:output_type -> remote.ClientVersionReply
-	10, // 12: remote.ETHBACKEND.Subscribe:output_type -> remote.SubscribeReply
-	8,  // [8:13] is the sub-list for method output_type
-	3,  // [3:8] is the sub-list for method input_type
+	12, // 5: remote.ETHBACKEND.Version:input_type -> google.protobuf.Empty
+	5,  // 6: remote.ETHBACKEND.ProtocolVersion:input_type -> remote.ProtocolVersionRequest
+	7,  // 7: remote.ETHBACKEND.ClientVersion:input_type -> remote.ClientVersionRequest
+	9,  // 8: remote.ETHBACKEND.Subscribe:input_type -> remote.SubscribeRequest
+	2,  // 9: remote.ETHBACKEND.Etherbase:output_type -> remote.EtherbaseReply
+	4,  // 10: remote.ETHBACKEND.NetVersion:output_type -> remote.NetVersionReply
+	13, // 11: remote.ETHBACKEND.Version:output_type -> types.VersionReply
+	6,  // 12: remote.ETHBACKEND.ProtocolVersion:output_type -> remote.ProtocolVersionReply
+	8,  // 13: remote.ETHBACKEND.ClientVersion:output_type -> remote.ClientVersionReply
+	10, // 14: remote.ETHBACKEND.Subscribe:output_type -> remote.SubscribeReply
+	9,  // [9:15] is the sub-list for method output_type
+	3,  // [3:9] is the sub-list for method input_type
 	3,  // [3:3] is the sub-list for extension type_name
 	3,  // [3:3] is the sub-list for extension extendee
 	0,  // [0:3] is the sub-list for field type_name
diff --git a/gointerfaces/remote/ethbackend_grpc.pb.go b/gointerfaces/remote/ethbackend_grpc.pb.go
index 2c793ea488..05a7cd8bec 100644
--- a/gointerfaces/remote/ethbackend_grpc.pb.go
+++ b/gointerfaces/remote/ethbackend_grpc.pb.go
@@ -4,9 +4,11 @@ package remote
 
 import (
 	context "context"
+	types "github.com/ledgerwatch/erigon/gointerfaces/types"
 	grpc "google.golang.org/grpc"
 	codes "google.golang.org/grpc/codes"
 	status "google.golang.org/grpc/status"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
 )
 
 // This is a compile-time assertion to ensure that this generated file
@@ -20,6 +22,8 @@ const _ = grpc.SupportPackageIsVersion7
 type ETHBACKENDClient interface {
 	Etherbase(ctx context.Context, in *EtherbaseRequest, opts ...grpc.CallOption) (*EtherbaseReply, error)
 	NetVersion(ctx context.Context, in *NetVersionRequest, opts ...grpc.CallOption) (*NetVersionReply, error)
+	// Version returns the service version number
+	Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*types.VersionReply, error)
 	// ProtocolVersion returns the Ethereum protocol version number (e.g. 66 for ETH66).
 	ProtocolVersion(ctx context.Context, in *ProtocolVersionRequest, opts ...grpc.CallOption) (*ProtocolVersionReply, error)
 	// ClientVersion returns the Ethereum client version string using node name convention (e.g. TurboGeth/v2021.03.2-alpha/Linux).
@@ -53,6 +57,15 @@ func (c *eTHBACKENDClient) NetVersion(ctx context.Context, in *NetVersionRequest
 	return out, nil
 }
 
+func (c *eTHBACKENDClient) Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*types.VersionReply, error) {
+	out := new(types.VersionReply)
+	err := c.cc.Invoke(ctx, "/remote.ETHBACKEND/Version", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *eTHBACKENDClient) ProtocolVersion(ctx context.Context, in *ProtocolVersionRequest, opts ...grpc.CallOption) (*ProtocolVersionReply, error) {
 	out := new(ProtocolVersionReply)
 	err := c.cc.Invoke(ctx, "/remote.ETHBACKEND/ProtocolVersion", in, out, opts...)
@@ -109,6 +122,8 @@ func (x *eTHBACKENDSubscribeClient) Recv() (*SubscribeReply, error) {
 type ETHBACKENDServer interface {
 	Etherbase(context.Context, *EtherbaseRequest) (*EtherbaseReply, error)
 	NetVersion(context.Context, *NetVersionRequest) (*NetVersionReply, error)
+	// Version returns the service version number
+	Version(context.Context, *emptypb.Empty) (*types.VersionReply, error)
 	// ProtocolVersion returns the Ethereum protocol version number (e.g. 66 for ETH66).
 	ProtocolVersion(context.Context, *ProtocolVersionRequest) (*ProtocolVersionReply, error)
 	// ClientVersion returns the Ethereum client version string using node name convention (e.g. TurboGeth/v2021.03.2-alpha/Linux).
@@ -127,6 +142,9 @@ func (UnimplementedETHBACKENDServer) Etherbase(context.Context, *EtherbaseReques
 func (UnimplementedETHBACKENDServer) NetVersion(context.Context, *NetVersionRequest) (*NetVersionReply, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method NetVersion not implemented")
 }
+func (UnimplementedETHBACKENDServer) Version(context.Context, *emptypb.Empty) (*types.VersionReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Version not implemented")
+}
 func (UnimplementedETHBACKENDServer) ProtocolVersion(context.Context, *ProtocolVersionRequest) (*ProtocolVersionReply, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method ProtocolVersion not implemented")
 }
@@ -185,6 +203,24 @@ func _ETHBACKEND_NetVersion_Handler(srv interface{}, ctx context.Context, dec fu
 	return interceptor(ctx, in, info, handler)
 }
 
+func _ETHBACKEND_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(emptypb.Empty)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ETHBACKENDServer).Version(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/remote.ETHBACKEND/Version",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ETHBACKENDServer).Version(ctx, req.(*emptypb.Empty))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _ETHBACKEND_ProtocolVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(ProtocolVersionRequest)
 	if err := dec(in); err != nil {
@@ -257,6 +293,10 @@ var ETHBACKEND_ServiceDesc = grpc.ServiceDesc{
 			MethodName: "NetVersion",
 			Handler:    _ETHBACKEND_NetVersion_Handler,
 		},
+		{
+			MethodName: "Version",
+			Handler:    _ETHBACKEND_Version_Handler,
+		},
 		{
 			MethodName: "ProtocolVersion",
 			Handler:    _ETHBACKEND_ProtocolVersion_Handler,
diff --git a/gointerfaces/txpool/txpool.pb.go b/gointerfaces/txpool/txpool.pb.go
index 5c94a70701..881e76c881 100644
--- a/gointerfaces/txpool/txpool.pb.go
+++ b/gointerfaces/txpool/txpool.pb.go
@@ -10,6 +10,7 @@ import (
 	types "github.com/ledgerwatch/erigon/gointerfaces/types"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
 	reflect "reflect"
 	sync "sync"
 )
@@ -411,52 +412,58 @@ var File_txpool_txpool_proto protoreflect.FileDescriptor
 
 var file_txpool_txpool_proto_rawDesc = []byte{
 	0x0a, 0x13, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2f, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x1a, 0x11, 0x74,
-	0x79, 0x70, 0x65, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x22, 0x2f, 0x0a, 0x08, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x06,
-	0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74,
-	0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65,
-	0x73, 0x22, 0x24, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
-	0x16, 0x0a, 0x06, 0x72, 0x6c, 0x70, 0x54, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52,
-	0x06, 0x72, 0x6c, 0x70, 0x54, 0x78, 0x73, 0x22, 0x54, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x52, 0x65,
-	0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x08, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18,
-	0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x49,
-	0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x69, 0x6d, 0x70,
-	0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18,
-	0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x3a, 0x0a,
-	0x13, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35,
-	0x36, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x2b, 0x0a, 0x11, 0x54, 0x72, 0x61,
-	0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16,
-	0x0a, 0x06, 0x72, 0x6c, 0x70, 0x54, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06,
-	0x72, 0x6c, 0x70, 0x54, 0x78, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x4f, 0x6e, 0x41, 0x64, 0x64, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x24, 0x0a, 0x0a, 0x4f, 0x6e, 0x41, 0x64, 0x64, 0x52,
-	0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x70, 0x6c, 0x54, 0x78, 0x73, 0x18, 0x01,
-	0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x70, 0x6c, 0x54, 0x78, 0x73, 0x2a, 0x6c, 0x0a, 0x0c,
-	0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0b, 0x0a, 0x07,
-	0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x4c, 0x52,
-	0x45, 0x41, 0x44, 0x59, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x53, 0x10, 0x01, 0x12, 0x0f, 0x0a,
-	0x0b, 0x46, 0x45, 0x45, 0x5f, 0x54, 0x4f, 0x4f, 0x5f, 0x4c, 0x4f, 0x57, 0x10, 0x02, 0x12, 0x09,
-	0x0a, 0x05, 0x53, 0x54, 0x41, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56,
-	0x41, 0x4c, 0x49, 0x44, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e,
-	0x41, 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x32, 0xe5, 0x01, 0x0a, 0x06, 0x54,
-	0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x6e, 0x6b,
-	0x6e, 0x6f, 0x77, 0x6e, 0x12, 0x10, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x54, 0x78,
-	0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x1a, 0x10, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e,
-	0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x12,
-	0x12, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64,
-	0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x46, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
-	0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x54,
-	0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x54, 0x72, 0x61, 0x6e,
-	0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x33, 0x0a,
-	0x05, 0x4f, 0x6e, 0x41, 0x64, 0x64, 0x12, 0x14, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e,
-	0x4f, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x74,
-	0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x4f, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79,
-	0x30, 0x01, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x2f, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x3b, 0x74,
-	0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x1a, 0x1b, 0x67,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65,
+	0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x74, 0x79, 0x70, 0x65,
+	0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2f, 0x0a,
+	0x08, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x06, 0x68, 0x61, 0x73,
+	0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65,
+	0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x24,
+	0x0a, 0x0a, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06,
+	0x72, 0x6c, 0x70, 0x54, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x6c,
+	0x70, 0x54, 0x78, 0x73, 0x22, 0x54, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79,
+	0x12, 0x30, 0x0a, 0x08, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03,
+	0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x49, 0x6d, 0x70, 0x6f,
+	0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74,
+	0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x3a, 0x0a, 0x13, 0x54, 0x72,
+	0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x23, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x52, 0x06,
+	0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x2b, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61,
+	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x72,
+	0x6c, 0x70, 0x54, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x6c, 0x70,
+	0x54, 0x78, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x4f, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x22, 0x24, 0x0a, 0x0a, 0x4f, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c,
+	0x79, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x70, 0x6c, 0x54, 0x78, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0c, 0x52, 0x06, 0x72, 0x70, 0x6c, 0x54, 0x78, 0x73, 0x2a, 0x6c, 0x0a, 0x0c, 0x49, 0x6d, 0x70,
+	0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43,
+	0x43, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x4c, 0x52, 0x45, 0x41, 0x44,
+	0x59, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x53, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x45,
+	0x45, 0x5f, 0x54, 0x4f, 0x4f, 0x5f, 0x4c, 0x4f, 0x57, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x53,
+	0x54, 0x41, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49,
+	0x44, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f,
+	0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x32, 0x9d, 0x02, 0x0a, 0x06, 0x54, 0x78, 0x70, 0x6f,
+	0x6f, 0x6c, 0x12, 0x36, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x56, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x46, 0x69,
+	0x6e, 0x64, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x12, 0x10, 0x2e, 0x74, 0x78, 0x70, 0x6f,
+	0x6f, 0x6c, 0x2e, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x1a, 0x10, 0x2e, 0x74, 0x78,
+	0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x2b, 0x0a,
+	0x03, 0x41, 0x64, 0x64, 0x12, 0x12, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x41, 0x64,
+	0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f,
+	0x6c, 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x46, 0x0a, 0x0c, 0x54, 0x72,
+	0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x78, 0x70,
+	0x6f, 0x6f, 0x6c, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c,
+	0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70,
+	0x6c, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x4f, 0x6e, 0x41, 0x64, 0x64, 0x12, 0x14, 0x2e, 0x74, 0x78,
+	0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x4f, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x12, 0x2e, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x4f, 0x6e, 0x41, 0x64, 0x64,
+	0x52, 0x65, 0x70, 0x6c, 0x79, 0x30, 0x01, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x2f, 0x74, 0x78, 0x70,
+	0x6f, 0x6f, 0x6c, 0x3b, 0x74, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x33,
 }
 
 var (
@@ -483,24 +490,28 @@ var file_txpool_txpool_proto_goTypes = []interface{}{
 	(*OnAddRequest)(nil),        // 6: txpool.OnAddRequest
 	(*OnAddReply)(nil),          // 7: txpool.OnAddReply
 	(*types.H256)(nil),          // 8: types.H256
+	(*emptypb.Empty)(nil),       // 9: google.protobuf.Empty
+	(*types.VersionReply)(nil),  // 10: types.VersionReply
 }
 var file_txpool_txpool_proto_depIdxs = []int32{
-	8, // 0: txpool.TxHashes.hashes:type_name -> types.H256
-	0, // 1: txpool.AddReply.imported:type_name -> txpool.ImportResult
-	8, // 2: txpool.TransactionsRequest.hashes:type_name -> types.H256
-	1, // 3: txpool.Txpool.FindUnknown:input_type -> txpool.TxHashes
-	2, // 4: txpool.Txpool.Add:input_type -> txpool.AddRequest
-	4, // 5: txpool.Txpool.Transactions:input_type -> txpool.TransactionsRequest
-	6, // 6: txpool.Txpool.OnAdd:input_type -> txpool.OnAddRequest
-	1, // 7: txpool.Txpool.FindUnknown:output_type -> txpool.TxHashes
-	3, // 8: txpool.Txpool.Add:output_type -> txpool.AddReply
-	5, // 9: txpool.Txpool.Transactions:output_type -> txpool.TransactionsReply
-	7, // 10: txpool.Txpool.OnAdd:output_type -> txpool.OnAddReply
-	7, // [7:11] is the sub-list for method output_type
-	3, // [3:7] is the sub-list for method input_type
-	3, // [3:3] is the sub-list for extension type_name
-	3, // [3:3] is the sub-list for extension extendee
-	0, // [0:3] is the sub-list for field type_name
+	8,  // 0: txpool.TxHashes.hashes:type_name -> types.H256
+	0,  // 1: txpool.AddReply.imported:type_name -> txpool.ImportResult
+	8,  // 2: txpool.TransactionsRequest.hashes:type_name -> types.H256
+	9,  // 3: txpool.Txpool.Version:input_type -> google.protobuf.Empty
+	1,  // 4: txpool.Txpool.FindUnknown:input_type -> txpool.TxHashes
+	2,  // 5: txpool.Txpool.Add:input_type -> txpool.AddRequest
+	4,  // 6: txpool.Txpool.Transactions:input_type -> txpool.TransactionsRequest
+	6,  // 7: txpool.Txpool.OnAdd:input_type -> txpool.OnAddRequest
+	10, // 8: txpool.Txpool.Version:output_type -> types.VersionReply
+	1,  // 9: txpool.Txpool.FindUnknown:output_type -> txpool.TxHashes
+	3,  // 10: txpool.Txpool.Add:output_type -> txpool.AddReply
+	5,  // 11: txpool.Txpool.Transactions:output_type -> txpool.TransactionsReply
+	7,  // 12: txpool.Txpool.OnAdd:output_type -> txpool.OnAddReply
+	8,  // [8:13] is the sub-list for method output_type
+	3,  // [3:8] is the sub-list for method input_type
+	3,  // [3:3] is the sub-list for extension type_name
+	3,  // [3:3] is the sub-list for extension extendee
+	0,  // [0:3] is the sub-list for field type_name
 }
 
 func init() { file_txpool_txpool_proto_init() }
diff --git a/gointerfaces/txpool/txpool_grpc.pb.go b/gointerfaces/txpool/txpool_grpc.pb.go
index 068dcdb542..f4040510b9 100644
--- a/gointerfaces/txpool/txpool_grpc.pb.go
+++ b/gointerfaces/txpool/txpool_grpc.pb.go
@@ -4,9 +4,11 @@ package txpool
 
 import (
 	context "context"
+	types "github.com/ledgerwatch/erigon/gointerfaces/types"
 	grpc "google.golang.org/grpc"
 	codes "google.golang.org/grpc/codes"
 	status "google.golang.org/grpc/status"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
 )
 
 // This is a compile-time assertion to ensure that this generated file
@@ -18,6 +20,8 @@ const _ = grpc.SupportPackageIsVersion7
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
 type TxpoolClient interface {
+	// Version returns the service version number
+	Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*types.VersionReply, error)
 	// preserves incoming order, changes amount, unknown hashes will be omitted
 	FindUnknown(ctx context.Context, in *TxHashes, opts ...grpc.CallOption) (*TxHashes, error)
 	// Expecting signed transactions. Preserves incoming order and amount
@@ -37,6 +41,15 @@ func NewTxpoolClient(cc grpc.ClientConnInterface) TxpoolClient {
 	return &txpoolClient{cc}
 }
 
+func (c *txpoolClient) Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*types.VersionReply, error) {
+	out := new(types.VersionReply)
+	err := c.cc.Invoke(ctx, "/txpool.Txpool/Version", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *txpoolClient) FindUnknown(ctx context.Context, in *TxHashes, opts ...grpc.CallOption) (*TxHashes, error) {
 	out := new(TxHashes)
 	err := c.cc.Invoke(ctx, "/txpool.Txpool/FindUnknown", in, out, opts...)
@@ -100,6 +113,8 @@ func (x *txpoolOnAddClient) Recv() (*OnAddReply, error) {
 // All implementations must embed UnimplementedTxpoolServer
 // for forward compatibility
 type TxpoolServer interface {
+	// Version returns the service version number
+	Version(context.Context, *emptypb.Empty) (*types.VersionReply, error)
 	// preserves incoming order, changes amount, unknown hashes will be omitted
 	FindUnknown(context.Context, *TxHashes) (*TxHashes, error)
 	// Expecting signed transactions. Preserves incoming order and amount
@@ -116,6 +131,9 @@ type TxpoolServer interface {
 type UnimplementedTxpoolServer struct {
 }
 
+func (UnimplementedTxpoolServer) Version(context.Context, *emptypb.Empty) (*types.VersionReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Version not implemented")
+}
 func (UnimplementedTxpoolServer) FindUnknown(context.Context, *TxHashes) (*TxHashes, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method FindUnknown not implemented")
 }
@@ -141,6 +159,24 @@ func RegisterTxpoolServer(s grpc.ServiceRegistrar, srv TxpoolServer) {
 	s.RegisterService(&Txpool_ServiceDesc, srv)
 }
 
+func _Txpool_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(emptypb.Empty)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(TxpoolServer).Version(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/txpool.Txpool/Version",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(TxpoolServer).Version(ctx, req.(*emptypb.Empty))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Txpool_FindUnknown_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(TxHashes)
 	if err := dec(in); err != nil {
@@ -223,6 +259,10 @@ var Txpool_ServiceDesc = grpc.ServiceDesc{
 	ServiceName: "txpool.Txpool",
 	HandlerType: (*TxpoolServer)(nil),
 	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Version",
+			Handler:    _Txpool_Version_Handler,
+		},
 		{
 			MethodName: "FindUnknown",
 			Handler:    _Txpool_FindUnknown_Handler,
diff --git a/gointerfaces/version.go b/gointerfaces/version.go
new file mode 100644
index 0000000000..e10b5ebf83
--- /dev/null
+++ b/gointerfaces/version.go
@@ -0,0 +1,30 @@
+package gointerfaces
+
+import (
+	"fmt"
+
+	"github.com/ledgerwatch/erigon/gointerfaces/types"
+)
+
+type Version struct {
+	Major, Minor, Patch uint32 // interface Version of the client - to perform compatibility check when opening
+}
+
+func VersionFromProto(r *types.VersionReply) Version {
+	return Version{Major: r.Major, Minor: r.Minor, Patch: r.Patch}
+}
+
+// EnsureVersion - Default policy: allow only patch difference
+func EnsureVersion(local Version, remote *types.VersionReply) bool {
+	if remote.Major != local.Major {
+		return false
+	}
+	if remote.Minor != local.Minor {
+		return false
+	}
+	return true
+}
+
+func (v Version) String() string {
+	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
+}
diff --git a/interfaces/README.md b/interfaces/README.md
index 8f97f47713..68ac4cf0f9 100644
--- a/interfaces/README.md
+++ b/interfaces/README.md
@@ -15,8 +15,13 @@ NOTE: You are free to ignore provided wrappers and use the .proto files directly
 git subtree add --prefix interfaces --squash https://github.com/ledgerwatch/interfaces master
 ```
 
-When you need to update the subtree to a specific commit or tag, you can use this command:
+When you need to update the subtree to a specific commit or tag, you can use these commands:
 
 ```
-git subtree pull --prefix interfaces --squash https://github.com/ledgerwatch/interfaces <tag_or_commit>
+git rm -rf interfaces
+git commit -m"Remove interfaces for replacement"
+git subtree add --prefix interfaces --squash https://github.com/ledgerwatch/interfaces <tag_or_commit>
 ```
+
+Unfortunately `git subtree pull` does not work if we use Squash-Merge for pull requests in this repository
+and also automatically delete merged branches.
diff --git a/interfaces/build.rs b/interfaces/build.rs
index 5dc717169c..0818fb1b17 100644
--- a/interfaces/build.rs
+++ b/interfaces/build.rs
@@ -7,6 +7,7 @@ fn config() -> prost_build::Config {
 
 fn make_protos(protos: &[&str]) {
     tonic_build::configure()
+        .format(false)
         .compile_with_config(config(), &protos, &["."])
         .unwrap();
 }
@@ -36,5 +37,9 @@ fn main() {
         protos.push("txpool/txpool_control.proto");
     }
 
+    if cfg!(feature = "consensus") {
+        protos.push("consensus_engine/consensus.proto");
+    }
+
     make_protos(&protos);
 }
diff --git a/interfaces/consensus_engine/consensus.proto b/interfaces/consensus_engine/consensus.proto
index 90e6d7baa5..2bb7d1703f 100644
--- a/interfaces/consensus_engine/consensus.proto
+++ b/interfaces/consensus_engine/consensus.proto
@@ -1,11 +1,30 @@
 syntax = "proto3";
 
+import "google/protobuf/empty.proto";
 import "types/types.proto";
 
 package consensus;
 
 option go_package = "./consensus;consensus";
 
+message ChainSpecMessage {
+    string mechanism = 1;       // Name of consensus mechanism, e.g. ethash, clique, aura
+    bytes mechanism_config = 2; // Configuration of specific consensus mechanism - format is specific to the mechanism
+    Genesis genesis = 3;        // Description of genesis block
+    repeated Fork forks = 4;    // Description of forks (upgrades)
+}
+
+message Genesis {
+    types.H256 chain_id = 1; // Chain id starting from genesis block and until the first fork
+    Template template = 2;   // Genesis header without values like "uncle hash", "tx hash" and "state root" calculated
+}
+
+message Fork {
+    string name = 1;         // Code name of the fork
+    uint64 number = 2;       // First block number at which rules of the fork activate
+    types.H256 chain_id = 3; // Chain id starting from this fork until the next fork
+}
+
 message Error {
     uint32 code = 1;
     string description = 2;
@@ -16,22 +35,26 @@ message Result {
     optional Error error = 2;
 }
 
-message BlockHeader {
+message Template {
     types.H256 parent_hash = 1;
+    types.H160 coinbase = 2;
+    types.H256 difficulty = 3;
+    uint64 number = 4;
+    uint64 gas_limit = 5;
+    uint64 time = 6;
+    bytes extra = 7;
+    uint64 nonce = 8;    
+}
+
+message BlockHeader {
+    Template template = 1;
     types.H256 uncle_hash = 2;
-    bytes coinbase = 3;
-    types.H256 root_hash = 4;
-    types.H256 tx_hash = 5;
-    types.H256 receipt_hash = 6;
-    bytes bloom = 7;
-    types.H256 difficulty = 8;
-    uint64 number = 9;
-    uint64 gas_limit = 10;
-    uint64 gas_used = 11;
-    uint64 time = 12;
-    bytes extra = 13;
-    types.H256 mix_digest = 14;
-    uint64 nonce = 15;
+    types.H256 root_hash = 3;
+    types.H256 tx_hash = 4;
+    types.H256 receipt_hash = 5;
+    bytes bloom = 6;
+    uint64 gas_used = 7;
+    types.H256 mix_digest = 8;
 }
 
 message Transaction {
@@ -59,16 +82,18 @@ message VerifyHeaderRequest {
 }
 
 message VerifyHeaderResponse {
-    Result result = 1;
+    types.H256 hash = 1;
+    Result result = 2;
+    bytes finaliseCode = 3; // Code (in TEVM to execute at the end of the block to finalise it according to the consensus engine rules)
 }
 
-message VerifyHeadersRequest {
-    repeated BlockHeader headers = 1;
-    repeated bool seal = 2;
+message HeadersRequest {
+    types.H256 hash = 1; // Hash of the highest header requested
+    uint32 amount = 2;   // Number of headers requested
 }
 
-message VerifyHeadersResponse {
-    Result result = 1;
+message HeadersResponse {
+    BlockHeader header = 1;
 }
 
 message VerifyUnclesRequest {
@@ -110,10 +135,29 @@ message FinalizeResponse {
 
 service ConsensusEngine {
     rpc GetAuthor(GetAuthorRequest) returns(GetAuthorResponse);
-    rpc VerifyHeader(stream VerifyHeaderRequest) returns(stream VerifyHeaderResponse);
-    rpc VerifyHeaders(stream VerifyHeadersRequest) returns(stream VerifyHeadersResponse);
+
+    rpc ChainSpec(google.protobuf.Empty) returns(ChainSpecMessage);
+
+    // Core requests verifications from the Consensus Engine via this function
+    rpc VerifyHeaders(stream VerifyHeaderRequest) returns(stream VerifyHeaderResponse);
+
+    // Consensis Engine may ask for extra informaton (more headers) from the core, and these requests are coming through the stream
+    // returned by the ProvideHeaders function
+    rpc ProvideHeaders(stream HeadersResponse) returns(stream HeadersRequest);
+
     rpc VerifyUncles(stream VerifyUnclesRequest) returns(stream VerifyUnclesResponse);
     rpc Prepare(stream PrepareRequest) returns(stream PrepareResponse);
     rpc Finalize(stream FinalizeRequest) returns(stream FinalizeResponse);
     rpc Seal(SealBlockRequest) returns(stream SealBlockResponse);
 }
+
+message StartTestCaseMessage {
+    string mechanism = 1; // Consensus mechanism used in the test case
+    bytes config = 2;      // Configuration specific to the consensus engine tested
+}
+
+// Test is only run by consensus engine in the testing mode, and allows the test driver to inject the Configuration
+// (which includes chain spec) into the Consensus Engine and reset it's state
+service Test {
+    rpc StartTestCase(StartTestCaseMessage) returns(google.protobuf.Empty);
+}
\ No newline at end of file
diff --git a/interfaces/remote/ethbackend.proto b/interfaces/remote/ethbackend.proto
index ad509e39fe..f5997a5f5d 100644
--- a/interfaces/remote/ethbackend.proto
+++ b/interfaces/remote/ethbackend.proto
@@ -1,5 +1,6 @@
 syntax = "proto3";
 
+import "google/protobuf/empty.proto";
 import "types/types.proto";
 
 package remote;
@@ -11,6 +12,9 @@ service ETHBACKEND {
 
   rpc NetVersion(NetVersionRequest) returns (NetVersionReply);
 
+  // Version returns the service version number
+  rpc Version(google.protobuf.Empty) returns (types.VersionReply);
+
   // ProtocolVersion returns the Ethereum protocol version number (e.g. 66 for ETH66).
   rpc ProtocolVersion(ProtocolVersionRequest) returns (ProtocolVersionReply);
 
diff --git a/interfaces/txpool/txpool.proto b/interfaces/txpool/txpool.proto
index 58031c3e28..fa07321e4a 100644
--- a/interfaces/txpool/txpool.proto
+++ b/interfaces/txpool/txpool.proto
@@ -1,5 +1,6 @@
 syntax = "proto3";
 
+import "google/protobuf/empty.proto";
 import "types/types.proto";
 
 package txpool;
@@ -30,6 +31,8 @@ message OnAddReply {
 }
 
 service Txpool {
+  // Version returns the service version number
+  rpc Version(google.protobuf.Empty) returns (types.VersionReply);
   // preserves incoming order, changes amount, unknown hashes will be omitted
   rpc FindUnknown(TxHashes) returns (TxHashes);
   // Expecting signed transactions. Preserves incoming order and amount
diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go
index c98d876869..beae9237f4 100644
--- a/p2p/discover/v4_udp_test.go
+++ b/p2p/discover/v4_udp_test.go
@@ -27,6 +27,7 @@ import (
 	"math/rand"
 	"net"
 	"reflect"
+	"runtime"
 	"sync"
 	"testing"
 	"time"
@@ -500,6 +501,9 @@ func TestUDPv4_EIP868(t *testing.T) {
 
 // This test verifies that a small network of nodes can boot up into a healthy state.
 func TestUDPv4_smallNetConvergence(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("fix me on win please")
+	}
 	t.Parallel()
 
 	// Start the network.
-- 
GitLab