diff --git a/.gitmodules b/.gitmodules
index 32bdb3b6e5a68a1a06d685b9fe830d242cae097d..90d1be0a3d1073e84007cb0d15872ad40a617c0b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
 [submodule "tests"]
 	path = tests/testdata
 	url = https://github.com/ethereum/tests
+	shallow = true
diff --git a/.travis.yml b/.travis.yml
index 038ee859601b6b8cbad78c6a95c3b66966ee1094..3fe40404e55b6e3fa4fab761074a8411af8d73f6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ jobs:
   allow_failures:
     - stage: build
       os: osx
-      go: 1.15.x
+      go: 1.17.x
       env:
         - azure-osx
         - azure-ios
@@ -16,7 +16,7 @@ jobs:
     - stage: lint
       os: linux
       dist: bionic
-      go: 1.16.x
+      go: 1.17.x
       env:
         - lint
       git:
@@ -31,7 +31,7 @@ jobs:
       os: linux
       arch: amd64
       dist: bionic
-      go: 1.16.x
+      go: 1.17.x
       env:
         - docker
       services:
@@ -48,7 +48,7 @@ jobs:
       os: linux
       arch: arm64
       dist: bionic
-      go: 1.16.x
+      go: 1.17.x
       env:
         - docker
       services:
@@ -65,7 +65,7 @@ jobs:
       if: type = push
       os: linux
       dist: bionic
-      go: 1.16.x
+      go: 1.17.x
       env:
         - ubuntu-ppa
         - GO111MODULE=on
@@ -90,7 +90,7 @@ jobs:
       os: linux
       dist: bionic
       sudo: required
-      go: 1.16.x
+      go: 1.17.x
       env:
         - azure-linux
         - GO111MODULE=on
@@ -127,7 +127,7 @@ jobs:
       dist: bionic
       services:
         - docker
-      go: 1.16.x
+      go: 1.17.x
       env:
         - azure-linux-mips
         - GO111MODULE=on
@@ -192,7 +192,7 @@ jobs:
     - stage: build
       if: type = push
       os: osx
-      go: 1.16.x
+      go: 1.17.x
       env:
         - azure-osx
         - azure-ios
@@ -224,7 +224,7 @@ jobs:
       os: linux
       arch: amd64
       dist: bionic
-      go: 1.16.x
+      go: 1.17.x
       env:
         - GO111MODULE=on
       script:
@@ -235,7 +235,7 @@ jobs:
       os: linux
       arch: arm64
       dist: bionic
-      go: 1.16.x
+      go: 1.17.x
       env:
         - GO111MODULE=on
       script:
@@ -244,7 +244,7 @@ jobs:
     - stage: build
       os: linux
       dist: bionic
-      go: 1.15.x
+      go: 1.16.x
       env:
         - GO111MODULE=on
       script:
@@ -255,7 +255,7 @@ jobs:
       if: type = cron
       os: linux
       dist: bionic
-      go: 1.16.x
+      go: 1.17.x
       env:
         - azure-purge
         - GO111MODULE=on
diff --git a/Dockerfile b/Dockerfile
index 8c6e02d56f026003cc3dd02ff57f898fb5c9954e..c03cfacad80655d22c6a5e54f6c1a524a47fb3e0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
 # Build Geth in a stock Go builder container
-FROM golang:1.16-alpine as builder
+FROM golang:1.17-alpine as builder
 
 RUN apk add --no-cache make gcc musl-dev linux-headers git bash
 
diff --git a/Dockerfile.alltools b/Dockerfile.alltools
index dc10a907c83e54f73fc4295f1ee5a6c1a241ec2e..10cf1392e7eb00c64adf476fbaba20e6d21a91d5 100644
--- a/Dockerfile.alltools
+++ b/Dockerfile.alltools
@@ -1,5 +1,5 @@
 # Build Geth in a stock Go builder container
-FROM golang:1.16-alpine as builder
+FROM golang:1.17-alpine as builder
 
 RUN apk add --no-cache make gcc musl-dev linux-headers git
 
diff --git a/accounts/keystore/watch.go b/accounts/keystore/watch.go
index d6ef53327d43eff48f180ce885085a097c7794de..ad176040d68c2f16109fc25bcb21bfef456652e4 100644
--- a/accounts/keystore/watch.go
+++ b/accounts/keystore/watch.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build (darwin && !ios && cgo) || freebsd || (linux && !arm64) || netbsd || solaris
 // +build darwin,!ios,cgo freebsd linux,!arm64 netbsd solaris
 
 package keystore
diff --git a/accounts/keystore/watch_fallback.go b/accounts/keystore/watch_fallback.go
index de0e87f8a5a7b9c3cd1319848f1cb6fea00c920d..e40eca42fe759f2cfe816ebdfd207954aaac89fb 100644
--- a/accounts/keystore/watch_fallback.go
+++ b/accounts/keystore/watch_fallback.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build (darwin && !cgo) || ios || (linux && arm64) || windows || (!darwin && !freebsd && !linux && !netbsd && !solaris)
 // +build darwin,!cgo ios linux,arm64 windows !darwin,!freebsd,!linux,!netbsd,!solaris
 
 // This is the fallback implementation of directory watching.
diff --git a/accounts/manager.go b/accounts/manager.go
index acf41ed8e9e2c3f88e5dc4b3f40f68602bd7a7ed..1e111d19487b71f840b5b678370045893c805108 100644
--- a/accounts/manager.go
+++ b/accounts/manager.go
@@ -25,6 +25,10 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 )
 
+// managerSubBufferSize determines how many incoming wallet events
+// the manager will buffer in its channel.
+const managerSubBufferSize = 50
+
 // Config contains the settings of the global account manager.
 //
 // TODO(rjl493456442, karalabe, holiman): Get rid of this when account management
@@ -33,18 +37,27 @@ type Config struct {
 	InsecureUnlockAllowed bool // Whether account unlocking in insecure environment is allowed
 }
 
+// newBackendEvent lets the manager know it should
+// track the given backend for wallet updates.
+type newBackendEvent struct {
+	backend   Backend
+	processed chan struct{} // Informs event emitter that backend has been integrated
+}
+
 // Manager is an overarching account manager that can communicate with various
 // backends for signing transactions.
 type Manager struct {
-	config   *Config                    // Global account manager configurations
-	backends map[reflect.Type][]Backend // Index of backends currently registered
-	updaters []event.Subscription       // Wallet update subscriptions for all backends
-	updates  chan WalletEvent           // Subscription sink for backend wallet changes
-	wallets  []Wallet                   // Cache of all wallets from all registered backends
+	config      *Config                    // Global account manager configurations
+	backends    map[reflect.Type][]Backend // Index of backends currently registered
+	updaters    []event.Subscription       // Wallet update subscriptions for all backends
+	updates     chan WalletEvent           // Subscription sink for backend wallet changes
+	newBackends chan newBackendEvent       // Incoming backends to be tracked by the manager
+	wallets     []Wallet                   // Cache of all wallets from all registered backends
 
 	feed event.Feed // Wallet feed notifying of arrivals/departures
 
 	quit chan chan error
+	term chan struct{} // Channel is closed upon termination of the update loop
 	lock sync.RWMutex
 }
 
@@ -57,7 +70,7 @@ func NewManager(config *Config, backends ...Backend) *Manager {
 		wallets = merge(wallets, backend.Wallets()...)
 	}
 	// Subscribe to wallet notifications from all backends
-	updates := make(chan WalletEvent, 4*len(backends))
+	updates := make(chan WalletEvent, managerSubBufferSize)
 
 	subs := make([]event.Subscription, len(backends))
 	for i, backend := range backends {
@@ -65,12 +78,14 @@ func NewManager(config *Config, backends ...Backend) *Manager {
 	}
 	// Assemble the account manager and return
 	am := &Manager{
-		config:   config,
-		backends: make(map[reflect.Type][]Backend),
-		updaters: subs,
-		updates:  updates,
-		wallets:  wallets,
-		quit:     make(chan chan error),
+		config:      config,
+		backends:    make(map[reflect.Type][]Backend),
+		updaters:    subs,
+		updates:     updates,
+		newBackends: make(chan newBackendEvent),
+		wallets:     wallets,
+		quit:        make(chan chan error),
+		term:        make(chan struct{}),
 	}
 	for _, backend := range backends {
 		kind := reflect.TypeOf(backend)
@@ -93,6 +108,14 @@ func (am *Manager) Config() *Config {
 	return am.config
 }
 
+// AddBackend starts the tracking of an additional backend for wallet updates.
+// cmd/geth assumes once this func returns the backends have been already integrated.
+func (am *Manager) AddBackend(backend Backend) {
+	done := make(chan struct{})
+	am.newBackends <- newBackendEvent{backend, done}
+	<-done
+}
+
 // update is the wallet event loop listening for notifications from the backends
 // and updating the cache of wallets.
 func (am *Manager) update() {
@@ -122,10 +145,22 @@ func (am *Manager) update() {
 
 			// Notify any listeners of the event
 			am.feed.Send(event)
-
+		case event := <-am.newBackends:
+			am.lock.Lock()
+			// Update caches
+			backend := event.backend
+			am.wallets = merge(am.wallets, backend.Wallets()...)
+			am.updaters = append(am.updaters, backend.Subscribe(am.updates))
+			kind := reflect.TypeOf(backend)
+			am.backends[kind] = append(am.backends[kind], backend)
+			am.lock.Unlock()
+			close(event.processed)
 		case errc := <-am.quit:
 			// Manager terminating, return
 			errc <- nil
+			// Signals event emitters the loop is not receiving values
+			// to prevent them from getting stuck.
+			close(am.term)
 			return
 		}
 	}
@@ -133,6 +168,9 @@ func (am *Manager) update() {
 
 // Backends retrieves the backend(s) with the given type from the account manager.
 func (am *Manager) Backends(kind reflect.Type) []Backend {
+	am.lock.RLock()
+	defer am.lock.RUnlock()
+
 	return am.backends[kind]
 }
 
diff --git a/build/checksums.txt b/build/checksums.txt
index e667b30ce67faa82df7df40f775aea615535f2b3..686e1604b63b33aa66c37205f134adfae2724914 100644
--- a/build/checksums.txt
+++ b/build/checksums.txt
@@ -1,33 +1,37 @@
 # This file contains sha256 checksums of optional build dependencies.
 
-ae4f6b6e2a1677d31817984655a762074b5356da50fb58722b99104870d43503  go1.16.4.src.tar.gz
-18fe94775763db3878717393b6d41371b0b45206055e49b3838328120c977d13  go1.16.4.darwin-amd64.tar.gz
-cb6b972cc42e669f3585c648198cd5b6f6d7a0811d413ad64b50c02ba06ccc3a  go1.16.4.darwin-arm64.tar.gz
-cd1b146ef6e9006f27dd99e9687773e7fef30e8c985b7d41bff33e955a3bb53a  go1.16.4.linux-386.tar.gz
-7154e88f5a8047aad4b80ebace58a059e36e7e2e4eb3b383127a28c711b4ff59  go1.16.4.linux-amd64.tar.gz
-8b18eb05ddda2652d69ab1b1dd1f40dd731799f43c6a58b512ad01ae5b5bba21  go1.16.4.linux-arm64.tar.gz
-a53391a800ddec749ee90d38992babb27b95cfb864027350c737b9aa8e069494  go1.16.4.linux-armv6l.tar.gz
-e75c0b114a09eb5499874162b208931dc260de0fedaeedac8621bf263c974605  go1.16.4.windows-386.zip
-d40139b7ade8a3008e3240a6f86fe8f899a9c465c917e11dac8758af216f5eb0  go1.16.4.windows-amd64.zip
-7cf2bc8a175d6d656861165bfc554f92dc78d2abf5afe5631db3579555d97409  go1.16.4.freebsd-386.tar.gz
-ccdd2b76de1941b60734408fda0d750aaa69330d8a07430eed4c56bdb3502f6f  go1.16.4.freebsd-amd64.tar.gz
-80cfac566e344096a8df8f37bbd21f89e76a6fbe601406565d71a87a665fc125  go1.16.4.linux-ppc64le.tar.gz
-d6431881b3573dc29ecc24fbeab5e5ec25d8c9273aa543769c86a1a3bbac1ddf  go1.16.4.linux-s390x.tar.gz
+3a70e5055509f347c0fb831ca07a2bf3b531068f349b14a3c652e9b5b67beb5d  go1.17.src.tar.gz
+355bd544ce08d7d484d9d7de05a71b5c6f5bc10aa4b316688c2192aeb3dacfd1  go1.17.darwin-amd64.tar.gz
+da4e3e3c194bf9eed081de8842a157120ef44a7a8d7c820201adae7b0e28b20b  go1.17.darwin-arm64.tar.gz
+6819a7a11b8351d5d5768f2fff666abde97577602394f132cb7f85b3a7151f05  go1.17.freebsd-386.tar.gz
+15c184c83d99441d719da201b26256455eee85a808747c404b4183e9aa6c64b4  go1.17.freebsd-amd64.tar.gz
+c19e3227a6ac6329db91d1af77bbf239ccd760a259c16e6b9c932d527ff14848  go1.17.linux-386.tar.gz
+6bf89fc4f5ad763871cf7eac80a2d594492de7a818303283f1366a7f6a30372d  go1.17.linux-amd64.tar.gz
+01a9af009ada22122d3fcb9816049c1d21842524b38ef5d5a0e2ee4b26d7c3e7  go1.17.linux-arm64.tar.gz
+ae89d33f4e4acc222bdb04331933d5ece4ae71039812f6ccd7493cb3e8ddfb4e  go1.17.linux-armv6l.tar.gz
+ee84350114d532bf15f096198c675aafae9ff091dc4cc69eb49e1817ff94dbd7  go1.17.linux-ppc64le.tar.gz
+a50aaecf054f393575f969a9105d5c6864dd91afc5287d772449033fbafcf7e3  go1.17.linux-s390x.tar.gz
+c5afdd2ea4969f2b44637e913b04f7c15265d7beb60924a28063722670a52feb  go1.17.windows-386.zip
+2a18bd65583e221be8b9b7c2fbe3696c40f6e27c2df689bbdcc939d49651d151  go1.17.windows-amd64.zip
+5256f92f643d9022394ddc84de5c74fe8660c2151daaa199b12e60e542d694ae  go1.17.windows-arm64.zip
 
-7e9a47ab540aa3e8472fbf8120d28bed3b9d9cf625b955818e8bc69628d7187c  golangci-lint-1.39.0-darwin-amd64.tar.gz
-574daa2c9c299b01672a6daeb1873b5f12e413cdb6dc0e30f2ff163956778064  golangci-lint-1.39.0-darwin-arm64.tar.gz
-6225f7014987324ab78e9b511f294e3f25be013728283c33918c67c8576d543e  golangci-lint-1.39.0-freebsd-386.tar.gz
-6b3e76e1e5eaf0159411c8e2727f8d533989d3bb19f10e9caa6e0b9619ee267d  golangci-lint-1.39.0-freebsd-amd64.tar.gz
-a301cacfff87ed9b00313d95278533c25a4527a06b040a17d969b4b7e1b8a90d  golangci-lint-1.39.0-freebsd-armv7.tar.gz
-25bfd96a29c3112f508d5e4fc860dbad7afce657233c343acfa20715717d51e7  golangci-lint-1.39.0-freebsd-armv6.tar.gz
-9687e4ff15545cfc722b0e46107a94195166a505023b48a316579af25ad09505  golangci-lint-1.39.0-linux-armv7.tar.gz
-a7fa7ab2bfc99cbe5e5bcbf5684f5a997f920afbbe2f253d2feb1001d5e3c8b3  golangci-lint-1.39.0-linux-armv6.tar.gz
-c8f9634115beddb4ed9129c1f7ecd4c97c99d07aeef33e3707234097eeb51b7b  golangci-lint-1.39.0-linux-mips64le.tar.gz
-d1234c213b74751f1af413302dde0e9a6d4d29aecef034af7abb07dc1b6e887f  golangci-lint-1.39.0-linux-arm64.tar.gz
-df25d9267168323b163147acb823ab0215a8a3bb6898a4a9320afdfedde66817  golangci-lint-1.39.0-linux-386.tar.gz
-1767e75fba357b7651b1a796d38453558f371c60af805505ec99e166908c04b5  golangci-lint-1.39.0-linux-ppc64le.tar.gz
-25fd75bf3186b3d930ecae10185689968fd18fd8fa6f9f555d6beb04348c20f6  golangci-lint-1.39.0-linux-s390x.tar.gz
-3a73aa7468087caa62673c8adea99b4e4dff846dc72707222db85f8679b40cbf  golangci-lint-1.39.0-linux-amd64.tar.gz
-578caceccf81739bda67dbfec52816709d03608c6878888ecdc0e186a094a41b  golangci-lint-1.39.0-linux-mips64.tar.gz
-494b66ba0e32c8ddf6c4f6b1d05729b110900f6017eda943057e43598c17d7a8  golangci-lint-1.39.0-windows-386.zip
-52ec2e13a3cbb47147244dff8cfc35103563deb76e0459133058086fc35fb2c7  golangci-lint-1.39.0-windows-amd64.zip
+d4bd25b9814eeaa2134197dd2c7671bb791eae786d42010d9d788af20dee4bfa  golangci-lint-1.42.0-darwin-amd64.tar.gz
+e56859c04a2ad5390c6a497b1acb1cc9329ecb1010260c6faae9b5a4c35b35ea  golangci-lint-1.42.0-darwin-arm64.tar.gz
+14d912a3fa856830339472fc4dc341933adf15f37bdb7130bbbfcf960ecf4809  golangci-lint-1.42.0-freebsd-386.tar.gz
+337257fccc9baeb5ee1cd7e70c153e9d9f59d3afde46d631659500048afbdf80  golangci-lint-1.42.0-freebsd-amd64.tar.gz
+6debcc266b629359fdd8eef4f4abb05a621604079d27016265afb5b4593b0eff  golangci-lint-1.42.0-freebsd-armv6.tar.gz
+878f0e190169db2ce9dde8cefbd99adc4fe28b90b68686bbfcfcc2085e6d693e  golangci-lint-1.42.0-freebsd-armv7.tar.gz
+42c78e31faf62b225363eff1b1d2aa74f9dbcb75686c8914aa3e90d6af65cece  golangci-lint-1.42.0-linux-386.tar.gz
+6937f62f8e2329e94822dc11c10b871ace5557ae1fcc4ee2f9980cd6aecbc159  golangci-lint-1.42.0-linux-amd64.tar.gz
+2cf8d23d96cd854a537b355dab2962b960b88a06b615232599f066afd233f246  golangci-lint-1.42.0-linux-arm64.tar.gz
+08b003d1ed61367473886defc957af5301066e62338e5d96a319c34dadc4c1d1  golangci-lint-1.42.0-linux-armv6.tar.gz
+c7c00ec4845e806a1f32685f5b150219e180bd6d6a9d584be8d27f0c41d7a1bf  golangci-lint-1.42.0-linux-armv7.tar.gz
+3650fcf29eb3d8ee326d77791a896b15259eb2d5bf77437dc72e7efe5af6bd40  golangci-lint-1.42.0-linux-mips64.tar.gz
+f51ae003fdbca4fef78ba73e2eb736a939c8eaa178cd452234213b489da5a420  golangci-lint-1.42.0-linux-mips64le.tar.gz
+1b0bb7b8b22cc4ea7da44fd5ad5faaf6111d0677e01cc6f961b62a96537de2c6  golangci-lint-1.42.0-linux-ppc64le.tar.gz
+8cb56927eb75e572450efbe0ff0f9cf3f56dc9faa81d9e8d30d6559fc1d06e6d  golangci-lint-1.42.0-linux-riscv64.tar.gz
+5ac41cd31825a176b21505a371a7b307cd9cdf17df0f35bbb3bf1466f9356ccc  golangci-lint-1.42.0-linux-s390x.tar.gz
+e1cebd2af621ac4b64c20937df92c3819264f2174c92f51e196db1e64ae097e0  golangci-lint-1.42.0-windows-386.zip
+7e70fcde8e87a17cae0455df07d257ebc86669f3968d568e12727fa24bbe9883  golangci-lint-1.42.0-windows-amd64.zip
+59da7ce1bda432616bfc28ae663e52c3675adee8d9bf5959fafd657c159576ab  golangci-lint-1.42.0-windows-armv6.zip
+65f62dda937bfcede0326ac77abe947ce1548931e6e13298ca036cb31f224db5  golangci-lint-1.42.0-windows-armv7.zip
diff --git a/build/ci.go b/build/ci.go
index d7d2ce72e06c70b97dd2410d7de5163f30159d8e..6f1e975a5167c395baf4d57344068f4fe5910292 100644
--- a/build/ci.go
+++ b/build/ci.go
@@ -129,19 +129,13 @@ var (
 
 	// Distros for which packages are created.
 	// Note: vivid is unsupported because there is no golang-1.6 package for it.
-	// Note: wily is unsupported because it was officially deprecated on Launchpad.
-	// Note: yakkety is unsupported because it was officially deprecated on Launchpad.
-	// Note: zesty is unsupported because it was officially deprecated on Launchpad.
-	// Note: artful is unsupported because it was officially deprecated on Launchpad.
-	// Note: cosmic is unsupported because it was officially deprecated on Launchpad.
-	// Note: disco is unsupported because it was officially deprecated on Launchpad.
-	// Note: eoan is unsupported because it was officially deprecated on Launchpad.
+	// Note: the following Ubuntu releases have been officially deprecated on Launchpad:
+	//   wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy
 	debDistroGoBoots = map[string]string{
 		"trusty":  "golang-1.11",
 		"xenial":  "golang-go",
 		"bionic":  "golang-go",
 		"focal":   "golang-go",
-		"groovy":  "golang-go",
 		"hirsute": "golang-go",
 	}
 
@@ -153,7 +147,7 @@ var (
 	// This is the version of go that will be downloaded by
 	//
 	//     go run ci.go install -dlgo
-	dlgoVersion = "1.16.4"
+	dlgoVersion = "1.17"
 )
 
 var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
@@ -330,7 +324,7 @@ func doLint(cmdline []string) {
 
 // downloadLinter downloads and unpacks golangci-lint.
 func downloadLinter(cachedir string) string {
-	const version = "1.39.0"
+	const version = "1.42.0"
 
 	csdb := build.MustLoadChecksums("build/checksums.txt")
 	base := fmt.Sprintf("golangci-lint-%s-%s-%s", version, runtime.GOOS, runtime.GOARCH)
diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go
index 34a20c515b2325478d211dcf11cdc787b894a4bc..7dcb412b53a8f8b3de30ba5e55fc5c820f327ed7 100644
--- a/cmd/devp2p/internal/ethtest/chain.go
+++ b/cmd/devp2p/internal/ethtest/chain.go
@@ -39,16 +39,6 @@ type Chain struct {
 	chainConfig *params.ChainConfig
 }
 
-func (c *Chain) WriteTo(writer io.Writer) error {
-	for _, block := range c.blocks {
-		if err := rlp.Encode(writer, block); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
 // Len returns the length of the chain.
 func (c *Chain) Len() int {
 	return len(c.blocks)
diff --git a/cmd/devp2p/internal/ethtest/suite_test.go b/cmd/devp2p/internal/ethtest/suite_test.go
index 6e3217151a52e9bd10c8eab76d202400b1d0cf47..6d14404e66249927c3394f9c8f4a2901e2b75a10 100644
--- a/cmd/devp2p/internal/ethtest/suite_test.go
+++ b/cmd/devp2p/internal/ethtest/suite_test.go
@@ -45,7 +45,7 @@ func TestEthSuite(t *testing.T) {
 	if err != nil {
 		t.Fatalf("could not create new test suite: %v", err)
 	}
-	for _, test := range suite.AllEthTests() {
+	for _, test := range suite.Eth66Tests() {
 		t.Run(test.Name, func(t *testing.T) {
 			result := utesting.RunTAP([]utesting.Test{{Name: test.Name, Fn: test.Fn}}, os.Stdout)
 			if result[0].Failed {
diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go
index 1ab2f001e267e05c02ac11dccd2efd280deaeedb..fae65767be7fdd8fff64cc69e55d272163c3485a 100644
--- a/cmd/evm/internal/t8ntool/execution.go
+++ b/cmd/evm/internal/t8ntool/execution.go
@@ -23,6 +23,7 @@ import (
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/consensus/misc"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/rawdb"
@@ -46,13 +47,14 @@ type Prestate struct {
 // ExecutionResult contains the execution status after running a state test, any
 // error that might have occurred and a dump of the final state if requested.
 type ExecutionResult struct {
-	StateRoot   common.Hash    `json:"stateRoot"`
-	TxRoot      common.Hash    `json:"txRoot"`
-	ReceiptRoot common.Hash    `json:"receiptRoot"`
-	LogsHash    common.Hash    `json:"logsHash"`
-	Bloom       types.Bloom    `json:"logsBloom"        gencodec:"required"`
-	Receipts    types.Receipts `json:"receipts"`
-	Rejected    []*rejectedTx  `json:"rejected,omitempty"`
+	StateRoot   common.Hash           `json:"stateRoot"`
+	TxRoot      common.Hash           `json:"txRoot"`
+	ReceiptRoot common.Hash           `json:"receiptRoot"`
+	LogsHash    common.Hash           `json:"logsHash"`
+	Bloom       types.Bloom           `json:"logsBloom"        gencodec:"required"`
+	Receipts    types.Receipts        `json:"receipts"`
+	Rejected    []*rejectedTx         `json:"rejected,omitempty"`
+	Difficulty  *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
 }
 
 type ommer struct {
@@ -62,23 +64,28 @@ type ommer struct {
 
 //go:generate gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
 type stEnv struct {
-	Coinbase    common.Address                      `json:"currentCoinbase"   gencodec:"required"`
-	Difficulty  *big.Int                            `json:"currentDifficulty" gencodec:"required"`
-	GasLimit    uint64                              `json:"currentGasLimit"   gencodec:"required"`
-	Number      uint64                              `json:"currentNumber"     gencodec:"required"`
-	Timestamp   uint64                              `json:"currentTimestamp"  gencodec:"required"`
-	BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
-	Ommers      []ommer                             `json:"ommers,omitempty"`
-	BaseFee     *big.Int                            `json:"currentBaseFee,omitempty"`
+	Coinbase         common.Address                      `json:"currentCoinbase"   gencodec:"required"`
+	Difficulty       *big.Int                            `json:"currentDifficulty"`
+	ParentDifficulty *big.Int                            `json:"parentDifficulty"`
+	GasLimit         uint64                              `json:"currentGasLimit"   gencodec:"required"`
+	Number           uint64                              `json:"currentNumber"     gencodec:"required"`
+	Timestamp        uint64                              `json:"currentTimestamp"  gencodec:"required"`
+	ParentTimestamp  uint64                              `json:"parentTimestamp,omitempty"`
+	BlockHashes      map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
+	Ommers           []ommer                             `json:"ommers,omitempty"`
+	BaseFee          *big.Int                            `json:"currentBaseFee,omitempty"`
+	ParentUncleHash  common.Hash                         `json:"parentUncleHash"`
 }
 
 type stEnvMarshaling struct {
-	Coinbase   common.UnprefixedAddress
-	Difficulty *math.HexOrDecimal256
-	GasLimit   math.HexOrDecimal64
-	Number     math.HexOrDecimal64
-	Timestamp  math.HexOrDecimal64
-	BaseFee    *math.HexOrDecimal256
+	Coinbase         common.UnprefixedAddress
+	Difficulty       *math.HexOrDecimal256
+	ParentDifficulty *math.HexOrDecimal256
+	GasLimit         math.HexOrDecimal64
+	Number           math.HexOrDecimal64
+	Timestamp        math.HexOrDecimal64
+	ParentTimestamp  math.HexOrDecimal64
+	BaseFee          *math.HexOrDecimal256
 }
 
 type rejectedTx struct {
@@ -247,6 +254,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
 		LogsHash:    rlpHash(statedb.Logs()),
 		Receipts:    receipts,
 		Rejected:    rejectedTxs,
+		Difficulty:  (*math.HexOrDecimal256)(vmContext.Difficulty),
 	}
 	return statedb, execRs, nil
 }
@@ -274,3 +282,23 @@ func rlpHash(x interface{}) (h common.Hash) {
 	hw.Sum(h[:0])
 	return h
 }
+
+// calcDifficulty is based on ethash.CalcDifficulty. This method is used in case
+// the caller does not provide an explicit difficulty, but instead provides only
+// parent timestamp + difficulty.
+// Note: this method only works for ethash engine.
+func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime uint64,
+	parentDifficulty *big.Int, parentUncleHash common.Hash) *big.Int {
+	uncleHash := parentUncleHash
+	if uncleHash == (common.Hash{}) {
+		uncleHash = types.EmptyUncleHash
+	}
+	parent := &types.Header{
+		ParentHash: common.Hash{},
+		UncleHash:  uncleHash,
+		Difficulty: parentDifficulty,
+		Number:     new(big.Int).SetUint64(number - 1),
+		Time:       parentTime,
+	}
+	return ethash.CalcDifficulty(config, currentTime, parent)
+}
diff --git a/cmd/evm/internal/t8ntool/gen_stenv.go b/cmd/evm/internal/t8ntool/gen_stenv.go
index c7f079c02f49c0a92ff856beb8d435f8db168599..1bb3c6a46b0c58ba2b84028a15cf2705c936b2f8 100644
--- a/cmd/evm/internal/t8ntool/gen_stenv.go
+++ b/cmd/evm/internal/t8ntool/gen_stenv.go
@@ -16,38 +16,47 @@ var _ = (*stEnvMarshaling)(nil)
 // MarshalJSON marshals as JSON.
 func (s stEnv) MarshalJSON() ([]byte, error) {
 	type stEnv struct {
-		Coinbase    common.UnprefixedAddress            `json:"currentCoinbase"   gencodec:"required"`
-		Difficulty  *math.HexOrDecimal256               `json:"currentDifficulty" gencodec:"required"`
-		GasLimit    math.HexOrDecimal64                 `json:"currentGasLimit"   gencodec:"required"`
-		Number      math.HexOrDecimal64                 `json:"currentNumber"     gencodec:"required"`
-		Timestamp   math.HexOrDecimal64                 `json:"currentTimestamp"  gencodec:"required"`
-		BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
-		Ommers      []ommer                             `json:"ommers,omitempty"`
-		BaseFee     *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"`
+		Coinbase         common.UnprefixedAddress            `json:"currentCoinbase"   gencodec:"required"`
+		Difficulty       *math.HexOrDecimal256               `json:"currentDifficulty"`
+		ParentDifficulty *math.HexOrDecimal256               `json:"parentDifficulty"`
+		GasLimit         math.HexOrDecimal64                 `json:"currentGasLimit"   gencodec:"required"`
+		Number           math.HexOrDecimal64                 `json:"currentNumber"     gencodec:"required"`
+		Timestamp        math.HexOrDecimal64                 `json:"currentTimestamp"  gencodec:"required"`
+		ParentTimestamp  math.HexOrDecimal64                 `json:"parentTimestamp,omitempty"`
+		BlockHashes      map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
+		Ommers           []ommer                             `json:"ommers,omitempty"`
+		BaseFee          *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"`
+		ParentUncleHash  common.Hash                         `json:"parentUncleHash"`
 	}
 	var enc stEnv
 	enc.Coinbase = common.UnprefixedAddress(s.Coinbase)
 	enc.Difficulty = (*math.HexOrDecimal256)(s.Difficulty)
+	enc.ParentDifficulty = (*math.HexOrDecimal256)(s.ParentDifficulty)
 	enc.GasLimit = math.HexOrDecimal64(s.GasLimit)
 	enc.Number = math.HexOrDecimal64(s.Number)
 	enc.Timestamp = math.HexOrDecimal64(s.Timestamp)
+	enc.ParentTimestamp = math.HexOrDecimal64(s.ParentTimestamp)
 	enc.BlockHashes = s.BlockHashes
 	enc.Ommers = s.Ommers
 	enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee)
+	enc.ParentUncleHash = s.ParentUncleHash
 	return json.Marshal(&enc)
 }
 
 // UnmarshalJSON unmarshals from JSON.
 func (s *stEnv) UnmarshalJSON(input []byte) error {
 	type stEnv struct {
-		Coinbase    *common.UnprefixedAddress           `json:"currentCoinbase"   gencodec:"required"`
-		Difficulty  *math.HexOrDecimal256               `json:"currentDifficulty" gencodec:"required"`
-		GasLimit    *math.HexOrDecimal64                `json:"currentGasLimit"   gencodec:"required"`
-		Number      *math.HexOrDecimal64                `json:"currentNumber"     gencodec:"required"`
-		Timestamp   *math.HexOrDecimal64                `json:"currentTimestamp"  gencodec:"required"`
-		BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
-		Ommers      []ommer                             `json:"ommers,omitempty"`
-		BaseFee     *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"`
+		Coinbase         *common.UnprefixedAddress           `json:"currentCoinbase"   gencodec:"required"`
+		Difficulty       *math.HexOrDecimal256               `json:"currentDifficulty"`
+		ParentDifficulty *math.HexOrDecimal256               `json:"parentDifficulty"`
+		GasLimit         *math.HexOrDecimal64                `json:"currentGasLimit"   gencodec:"required"`
+		Number           *math.HexOrDecimal64                `json:"currentNumber"     gencodec:"required"`
+		Timestamp        *math.HexOrDecimal64                `json:"currentTimestamp"  gencodec:"required"`
+		ParentTimestamp  *math.HexOrDecimal64                `json:"parentTimestamp,omitempty"`
+		BlockHashes      map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
+		Ommers           []ommer                             `json:"ommers,omitempty"`
+		BaseFee          *math.HexOrDecimal256               `json:"currentBaseFee,omitempty"`
+		ParentUncleHash  *common.Hash                        `json:"parentUncleHash"`
 	}
 	var dec stEnv
 	if err := json.Unmarshal(input, &dec); err != nil {
@@ -57,10 +66,12 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
 		return errors.New("missing required field 'currentCoinbase' for stEnv")
 	}
 	s.Coinbase = common.Address(*dec.Coinbase)
-	if dec.Difficulty == nil {
-		return errors.New("missing required field 'currentDifficulty' for stEnv")
+	if dec.Difficulty != nil {
+		s.Difficulty = (*big.Int)(dec.Difficulty)
+	}
+	if dec.ParentDifficulty != nil {
+		s.ParentDifficulty = (*big.Int)(dec.ParentDifficulty)
 	}
-	s.Difficulty = (*big.Int)(dec.Difficulty)
 	if dec.GasLimit == nil {
 		return errors.New("missing required field 'currentGasLimit' for stEnv")
 	}
@@ -73,6 +84,9 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
 		return errors.New("missing required field 'currentTimestamp' for stEnv")
 	}
 	s.Timestamp = uint64(*dec.Timestamp)
+	if dec.ParentTimestamp != nil {
+		s.ParentTimestamp = uint64(*dec.ParentTimestamp)
+	}
 	if dec.BlockHashes != nil {
 		s.BlockHashes = dec.BlockHashes
 	}
@@ -82,5 +96,8 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
 	if dec.BaseFee != nil {
 		s.BaseFee = (*big.Int)(dec.BaseFee)
 	}
+	if dec.ParentUncleHash != nil {
+		s.ParentUncleHash = *dec.ParentUncleHash
+	}
 	return nil
 }
diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go
index 8334aa01d4f9714631eef529d78073b5a00ed5dc..9fdbbe29cba02e8bb5a5321a5c345700e76baab0 100644
--- a/cmd/evm/internal/t8ntool/transition.go
+++ b/cmd/evm/internal/t8ntool/transition.go
@@ -252,6 +252,20 @@ func Main(ctx *cli.Context) error {
 			return NewError(ErrorVMConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section"))
 		}
 	}
+	if env := prestate.Env; env.Difficulty == nil {
+		// If difficulty was not provided by caller, we need to calculate it.
+		switch {
+		case env.ParentDifficulty == nil:
+			return NewError(ErrorVMConfig, errors.New("currentDifficulty was not provided, and cannot be calculated due to missing parentDifficulty"))
+		case env.Number == 0:
+			return NewError(ErrorVMConfig, errors.New("currentDifficulty needs to be provided for block number 0"))
+		case env.Timestamp <= env.ParentTimestamp:
+			return NewError(ErrorVMConfig, fmt.Errorf("currentDifficulty cannot be calculated -- currentTime (%d) needs to be after parent time (%d)",
+				env.Timestamp, env.ParentTimestamp))
+		}
+		prestate.Env.Difficulty = calcDifficulty(chainConfig, env.Number, env.Timestamp,
+			env.ParentTimestamp, env.ParentDifficulty, env.ParentUncleHash)
+	}
 	// Run the test and aggregate the result
 	s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer)
 	if err != nil {
diff --git a/cmd/evm/testdata/14/alloc.json b/cmd/evm/testdata/14/alloc.json
new file mode 100644
index 0000000000000000000000000000000000000000..cef1a25ff013735aac4e52e9beb1818f19b9af5d
--- /dev/null
+++ b/cmd/evm/testdata/14/alloc.json
@@ -0,0 +1,12 @@
+{
+  "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
+    "balance": "0x5ffd4878be161d74",
+    "code": "0x",
+    "nonce": "0xac",
+    "storage": {}
+  },
+  "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192":{
+    "balance": "0xfeedbead",
+    "nonce" : "0x00"
+  }
+}
\ No newline at end of file
diff --git a/cmd/evm/testdata/14/env.json b/cmd/evm/testdata/14/env.json
new file mode 100644
index 0000000000000000000000000000000000000000..6b7457ffdf18ff37ba6e9b9478ba49127438361f
--- /dev/null
+++ b/cmd/evm/testdata/14/env.json
@@ -0,0 +1,9 @@
+{
+  "currentCoinbase": "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b",
+  "currentGasLimit": "0x750a163df65e8a",
+  "currentBaseFee": "0x500",
+  "currentNumber": "12800000",
+  "currentTimestamp": "10015",
+  "parentTimestamp" : "99999",
+  "parentDifficulty" : "0x2000000000000"
+}
diff --git a/cmd/evm/testdata/14/env.uncles.json b/cmd/evm/testdata/14/env.uncles.json
new file mode 100644
index 0000000000000000000000000000000000000000..9c2149b39ee59e39e3079c4d41437f25db63bf30
--- /dev/null
+++ b/cmd/evm/testdata/14/env.uncles.json
@@ -0,0 +1,10 @@
+{
+  "currentCoinbase": "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b",
+  "currentGasLimit": "0x750a163df65e8a",
+  "currentBaseFee": "0x500",
+  "currentNumber": "12800000",
+  "currentTimestamp": "10035",
+  "parentTimestamp" : "99999",
+  "parentDifficulty" : "0x2000000000000",
+  "parentUncleHash" : "0x000000000000000000000000000000000000000000000000000000000000beef"
+}
diff --git a/cmd/evm/testdata/14/readme.md b/cmd/evm/testdata/14/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..ce31abb8023b1463297d8a8a84e355d60d71ae5e
--- /dev/null
+++ b/cmd/evm/testdata/14/readme.md
@@ -0,0 +1,41 @@
+## Difficulty calculation
+
+This test shows how the `evm t8n` can be used to calculate the (ethash) difficulty, if none is provided by the caller. 
+
+Calculating it (with an empty set of txs) using `London` rules (and no provided unclehash for the parent block):
+```
+[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.json --output.result=stdout --state.fork=London
+INFO [08-08|17:35:46.876] Trie dumping started                     root=6f0588..7f4bdc
+INFO [08-08|17:35:46.876] Trie dumping complete                    accounts=2 elapsed="89.313µs"
+INFO [08-08|17:35:46.877] Wrote file                               file=alloc.json
+{
+ "result": {
+  "stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
+  "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+  "receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+  "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+  "receipts": [],
+  "currentDifficulty": 3311729559732224
+ }
+}
+```
+Same thing, but this time providing a non-empty (and non-`emptyKeccak`) unclehash, which leads to a slightly different result:
+```
+[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.uncles.json --output.result=stdout --state.fork=London
+INFO [08-08|17:35:49.232] Trie dumping started                     root=6f0588..7f4bdc
+INFO [08-08|17:35:49.232] Trie dumping complete                    accounts=2 elapsed="83.069µs"
+INFO [08-08|17:35:49.233] Wrote file                               file=alloc.json
+{
+ "result": {
+  "stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
+  "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+  "receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+  "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+  "receipts": [],
+  "currentDifficulty": 3311179803918336
+ }
+}
+```
+
diff --git a/cmd/evm/testdata/14/txs.json b/cmd/evm/testdata/14/txs.json
new file mode 100644
index 0000000000000000000000000000000000000000..fe51488c7066f6687ef680d6bfaa4f7768ef205c
--- /dev/null
+++ b/cmd/evm/testdata/14/txs.json
@@ -0,0 +1 @@
+[]
diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go
index 6d45c88763cae2926d335a6ab153d776646cc434..e33b9eb0fb0f0c2858f04f3f7a9d9a6c52f43c26 100644
--- a/cmd/geth/accountcmd.go
+++ b/cmd/geth/accountcmd.go
@@ -268,11 +268,16 @@ func accountCreate(ctx *cli.Context) error {
 		}
 	}
 	utils.SetNodeConfig(ctx, &cfg.Node)
-	scryptN, scryptP, keydir, err := cfg.Node.AccountConfig()
-
+	keydir, err := cfg.Node.KeyDirConfig()
 	if err != nil {
 		utils.Fatalf("Failed to read configuration: %v", err)
 	}
+	scryptN := keystore.StandardScryptN
+	scryptP := keystore.StandardScryptP
+	if cfg.Node.UseLightweightKDF {
+		scryptN = keystore.LightScryptN
+		scryptP = keystore.LightScryptP
+	}
 
 	password := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
 
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 0686f3bc2ca6bc085ef76eadeb4fe5d8085de975..04b41b3483343cde90f5e79f7bd5f48d53e41eeb 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -27,6 +27,10 @@ import (
 
 	"gopkg.in/urfave/cli.v1"
 
+	"github.com/ethereum/go-ethereum/accounts/external"
+	"github.com/ethereum/go-ethereum/accounts/keystore"
+	"github.com/ethereum/go-ethereum/accounts/scwallet"
+	"github.com/ethereum/go-ethereum/accounts/usbwallet"
 	"github.com/ethereum/go-ethereum/cmd/utils"
 	"github.com/ethereum/go-ethereum/eth/catalyst"
 	"github.com/ethereum/go-ethereum/eth/ethconfig"
@@ -135,6 +139,11 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
 	if err != nil {
 		utils.Fatalf("Failed to create the protocol stack: %v", err)
 	}
+	// Node doesn't by default populate account manager backends
+	if err := setAccountManagerBackends(stack); err != nil {
+		utils.Fatalf("Failed to set account manager backends: %v", err)
+	}
+
 	utils.SetEthConfig(ctx, stack, &cfg.Eth)
 	if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) {
 		cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name)
@@ -260,3 +269,62 @@ func deprecated(field string) bool {
 		return false
 	}
 }
+
+func setAccountManagerBackends(stack *node.Node) error {
+	conf := stack.Config()
+	am := stack.AccountManager()
+	keydir := stack.KeyStoreDir()
+	scryptN := keystore.StandardScryptN
+	scryptP := keystore.StandardScryptP
+	if conf.UseLightweightKDF {
+		scryptN = keystore.LightScryptN
+		scryptP = keystore.LightScryptP
+	}
+
+	// Assemble the supported backends
+	if len(conf.ExternalSigner) > 0 {
+		log.Info("Using external signer", "url", conf.ExternalSigner)
+		if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil {
+			am.AddBackend(extapi)
+			return nil
+		} else {
+			return fmt.Errorf("error connecting to external signer: %v", err)
+		}
+	}
+
+	// For now, we're using EITHER external signer OR local signers.
+	// If/when we implement some form of lockfile for USB and keystore wallets,
+	// we can have both, but it's very confusing for the user to see the same
+	// accounts in both externally and locally, plus very racey.
+	am.AddBackend(keystore.NewKeyStore(keydir, scryptN, scryptP))
+	if conf.USB {
+		// Start a USB hub for Ledger hardware wallets
+		if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
+			log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
+		} else {
+			am.AddBackend(ledgerhub)
+		}
+		// Start a USB hub for Trezor hardware wallets (HID version)
+		if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil {
+			log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err))
+		} else {
+			am.AddBackend(trezorhub)
+		}
+		// Start a USB hub for Trezor hardware wallets (WebUSB version)
+		if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil {
+			log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err))
+		} else {
+			am.AddBackend(trezorhub)
+		}
+	}
+	if len(conf.SmartCardDaemonPath) > 0 {
+		// Start a smart card hub
+		if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil {
+			log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err))
+		} else {
+			am.AddBackend(schub)
+		}
+	}
+
+	return nil
+}
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index fe2fe441392fb712baa43a9346078760db8f9fc8..0954debff94c0301869ba5e0afa4be3a069681f3 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -126,7 +126,7 @@ var (
 		utils.MinerEtherbaseFlag,
 		utils.MinerExtraDataFlag,
 		utils.MinerRecommitIntervalFlag,
-		utils.MinerNoVerfiyFlag,
+		utils.MinerNoVerifyFlag,
 		utils.NATFlag,
 		utils.NoDiscoverFlag,
 		utils.DiscoveryV5Flag,
diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go
index 35d027fb16485e8983f58266e436d145bb127d36..9976db49f601673689394bb3d949b8728bdcbde6 100644
--- a/cmd/geth/snapshot.go
+++ b/cmd/geth/snapshot.go
@@ -232,7 +232,7 @@ func verifyState(ctx *cli.Context) error {
 		}
 	}
 	if err := snaptree.Verify(root); err != nil {
-		log.Error("Failed to verfiy state", "root", root, "err", err)
+		log.Error("Failed to verify state", "root", root, "err", err)
 		return err
 	}
 	log.Info("Verified the state", "root", root)
diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go
index 708edcc79325a57b6c8152e3eab9337575c0339e..f39e4f402fcaf97cf2763595830c4fc8e931d841 100644
--- a/cmd/geth/usage.go
+++ b/cmd/geth/usage.go
@@ -185,7 +185,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{
 			utils.MinerEtherbaseFlag,
 			utils.MinerExtraDataFlag,
 			utils.MinerRecommitIntervalFlag,
-			utils.MinerNoVerfiyFlag,
+			utils.MinerNoVerifyFlag,
 		},
 	},
 	{
diff --git a/cmd/utils/diskusage.go b/cmd/utils/diskusage.go
index c3d51765f8ec890628b2ff64b764371acc7b91b6..09844652ef979cc8c915a9605533d81f8aa52fe5 100644
--- a/cmd/utils/diskusage.go
+++ b/cmd/utils/diskusage.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build !windows && !openbsd
 // +build !windows,!openbsd
 
 package utils
diff --git a/cmd/utils/diskusage_openbsd.go b/cmd/utils/diskusage_openbsd.go
index 54f759d291933c4a6f5b0eeddeb3eaee15213500..52502d0cfa17057601df161999928617a0d125ae 100644
--- a/cmd/utils/diskusage_openbsd.go
+++ b/cmd/utils/diskusage_openbsd.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build openbsd
 // +build openbsd
 
 package utils
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index d394a579a60f8cc6d0becf16773517f7edfc4957..366be6db6560ee48b9b7ebc2cb592f475f79459a 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -464,7 +464,7 @@ var (
 		Usage: "Time interval to recreate the block being mined",
 		Value: ethconfig.Defaults.Miner.Recommit,
 	}
-	MinerNoVerfiyFlag = cli.BoolFlag{
+	MinerNoVerifyFlag = cli.BoolFlag{
 		Name:  "miner.noverify",
 		Usage: "Disable remote sealing verification",
 	}
@@ -1402,8 +1402,8 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) {
 	if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) {
 		cfg.Recommit = ctx.GlobalDuration(MinerRecommitIntervalFlag.Name)
 	}
-	if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
-		cfg.Noverify = ctx.GlobalBool(MinerNoVerfiyFlag.Name)
+	if ctx.GlobalIsSet(MinerNoVerifyFlag.Name) {
+		cfg.Noverify = ctx.GlobalBool(MinerNoVerifyFlag.Name)
 	}
 	if ctx.GlobalIsSet(LegacyMinerGasTargetFlag.Name) {
 		log.Warn("The generic --miner.gastarget flag is deprecated and will be removed in the future!")
diff --git a/common/fdlimit/fdlimit_bsd.go b/common/fdlimit/fdlimit_bsd.go
index 86181337a2d7197899ad80c24ad41dad6178e011..a3a6902c0925dd4360890551f3ad3f2c982a3b08 100644
--- a/common/fdlimit/fdlimit_bsd.go
+++ b/common/fdlimit/fdlimit_bsd.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build freebsd || dragonfly
 // +build freebsd dragonfly
 
 package fdlimit
diff --git a/common/fdlimit/fdlimit_unix.go b/common/fdlimit/fdlimit_unix.go
index e5a575f7a79d3c92dfb8fd5b312a78701884975c..a1f388ebb78d891b037c0abf8e16158e9d858134 100644
--- a/common/fdlimit/fdlimit_unix.go
+++ b/common/fdlimit/fdlimit_unix.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build linux || netbsd || openbsd || solaris
 // +build linux netbsd openbsd solaris
 
 package fdlimit
diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go
index 927232be01541141aedb22075eee3132264306db..f2a8bda17c55e242dbd1b84071cf2b979cda4c64 100644
--- a/core/bloombits/matcher.go
+++ b/core/bloombits/matcher.go
@@ -510,8 +510,9 @@ type MatcherSession struct {
 	closer sync.Once     // Sync object to ensure we only ever close once
 	quit   chan struct{} // Quit channel to request pipeline termination
 
-	ctx context.Context // Context used by the light client to abort filtering
-	err atomic.Value    // Global error to track retrieval failures deep in the chain
+	ctx     context.Context // Context used by the light client to abort filtering
+	err     error           // Global error to track retrieval failures deep in the chain
+	errLock sync.Mutex
 
 	pend sync.WaitGroup
 }
@@ -529,10 +530,10 @@ func (s *MatcherSession) Close() {
 
 // Error returns any failure encountered during the matching session.
 func (s *MatcherSession) Error() error {
-	if err := s.err.Load(); err != nil {
-		return err.(error)
-	}
-	return nil
+	s.errLock.Lock()
+	defer s.errLock.Unlock()
+
+	return s.err
 }
 
 // allocateRetrieval assigns a bloom bit index to a client process that can either
@@ -630,7 +631,9 @@ func (s *MatcherSession) Multiplex(batch int, wait time.Duration, mux chan chan
 
 			result := <-request
 			if result.Error != nil {
-				s.err.Store(result.Error)
+				s.errLock.Lock()
+				s.err = result.Error
+				s.errLock.Unlock()
 				s.Close()
 			}
 			s.deliverSections(result.Bit, result.Sections, result.Bitsets)
diff --git a/core/mkalloc.go b/core/mkalloc.go
index 5118a4fcb3279e1a3252ac735c332965d46fdb1c..df167d7082cd073b7243a5f2517d4666d7e5a0b8 100644
--- a/core/mkalloc.go
+++ b/core/mkalloc.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build none
 // +build none
 
 /*
diff --git a/core/state/database.go b/core/state/database.go
index 1a06e3340966c6aa086955982c66968f66f21594..e25d059c05b96491677af928eefecad0fdc46a31 100644
--- a/core/state/database.go
+++ b/core/state/database.go
@@ -86,7 +86,7 @@ type Trie interface {
 
 	// Commit writes all nodes to the trie's memory database, tracking the internal
 	// and external (for account tries) references.
-	Commit(onleaf trie.LeafCallback) (common.Hash, error)
+	Commit(onleaf trie.LeafCallback) (common.Hash, int, error)
 
 	// NodeIterator returns an iterator that returns nodes of the trie. Iteration
 	// starts at the key after the given start key.
diff --git a/core/state/metrics.go b/core/state/metrics.go
new file mode 100644
index 0000000000000000000000000000000000000000..7b40ff37aff0eff018003ac18e7b09481248d0a6
--- /dev/null
+++ b/core/state/metrics.go
@@ -0,0 +1,28 @@
+// Copyright 2021 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package state
+
+import "github.com/ethereum/go-ethereum/metrics"
+
+var (
+	accountUpdatedMeter   = metrics.NewRegisteredMeter("state/update/account", nil)
+	storageUpdatedMeter   = metrics.NewRegisteredMeter("state/update/storage", nil)
+	accountDeletedMeter   = metrics.NewRegisteredMeter("state/delete/account", nil)
+	storageDeletedMeter   = metrics.NewRegisteredMeter("state/delete/storage", nil)
+	accountCommittedMeter = metrics.NewRegisteredMeter("state/commit/account", nil)
+	storageCommittedMeter = metrics.NewRegisteredMeter("state/commit/storage", nil)
+)
diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go
index 7e29e51b2179a16fa5277a0b8083784de837270d..3e11b4ac6b94b07edf95c3b59247d051bcf16521 100644
--- a/core/state/snapshot/generate.go
+++ b/core/state/snapshot/generate.go
@@ -436,7 +436,7 @@ func (dl *diskLayer) generateRange(root common.Hash, prefix []byte, kind string,
 		for i, key := range result.keys {
 			snapTrie.Update(key, result.vals[i])
 		}
-		root, _ := snapTrie.Commit(nil)
+		root, _, _ := snapTrie.Commit(nil)
 		snapTrieDb.Commit(root, false, nil)
 	}
 	tr := result.tr
diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go
index a92517b3155fb76b27684ff668b678b38d9290cb..582da6a2e7e24d93bd4229531819510e010a075f 100644
--- a/core/state/snapshot/generate_test.go
+++ b/core/state/snapshot/generate_test.go
@@ -60,7 +60,7 @@ func TestGeneration(t *testing.T) {
 	acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
 	val, _ = rlp.EncodeToBytes(acc)
 	accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
-	root, _ := accTrie.Commit(nil)       // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd
+	root, _, _ := accTrie.Commit(nil)    // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd
 	triedb.Commit(root, false, nil)
 
 	if have, want := root, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"); have != want {
@@ -128,7 +128,7 @@ func TestGenerateExistentState(t *testing.T) {
 	rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-3")), hashData([]byte("key-2")), []byte("val-2"))
 	rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-3")), hashData([]byte("key-3")), []byte("val-3"))
 
-	root, _ := accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd
+	root, _, _ := accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd
 	triedb.Commit(root, false, nil)
 
 	snap := generateSnapshot(diskdb, triedb, 16, root)
@@ -215,12 +215,12 @@ func (t *testHelper) makeStorageTrie(keys []string, vals []string) []byte {
 	for i, k := range keys {
 		stTrie.Update([]byte(k), []byte(vals[i]))
 	}
-	root, _ := stTrie.Commit(nil)
+	root, _, _ := stTrie.Commit(nil)
 	return root.Bytes()
 }
 
 func (t *testHelper) Generate() (common.Hash, *diskLayer) {
-	root, _ := t.accTrie.Commit(nil)
+	root, _, _ := t.accTrie.Commit(nil)
 	t.triedb.Commit(root, false, nil)
 	snap := generateSnapshot(t.diskdb, t.triedb, 16, root)
 	return root, snap
@@ -575,7 +575,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) {
 		rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("b-key-2")), []byte("b-val-2"))
 		rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("b-key-3")), []byte("b-val-3"))
 	}
-	root, _ := accTrie.Commit(nil)
+	root, _, _ := accTrie.Commit(nil)
 	t.Logf("root: %x", root)
 	triedb.Commit(root, false, nil)
 	// To verify the test: If we now inspect the snap db, there should exist extraneous storage items
@@ -637,7 +637,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) {
 			rawdb.WriteAccountSnapshot(diskdb, key, val)
 		}
 	}
-	root, _ := accTrie.Commit(nil)
+	root, _, _ := accTrie.Commit(nil)
 	t.Logf("root: %x", root)
 	triedb.Commit(root, false, nil)
 
@@ -690,7 +690,7 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) {
 		rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x07"), val)
 	}
 
-	root, _ := accTrie.Commit(nil)
+	root, _, _ := accTrie.Commit(nil)
 	t.Logf("root: %x", root)
 	triedb.Commit(root, false, nil)
 
@@ -734,7 +734,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) {
 		rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x05"), junk)
 	}
 
-	root, _ := accTrie.Commit(nil)
+	root, _, _ := accTrie.Commit(nil)
 	t.Logf("root: %x", root)
 	triedb.Commit(root, false, nil)
 
diff --git a/core/state/state_object.go b/core/state/state_object.go
index 38621ffb6159c51edb520258c0e5972f362e1e98..7b366d64c74253ea74bf8ec2ad695f9d6e069986 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -329,7 +329,7 @@ func (s *stateObject) finalise(prefetch bool) {
 // It will return nil if the trie has not been loaded and no changes have been made
 func (s *stateObject) updateTrie(db Database) Trie {
 	// Make sure all dirty slots are finalized into the pending storage area
-	s.finalise(false) // Don't prefetch any more, pull directly if need be
+	s.finalise(false) // Don't prefetch anymore, pull directly if need be
 	if len(s.pendingStorage) == 0 {
 		return s.trie
 	}
@@ -354,10 +354,12 @@ func (s *stateObject) updateTrie(db Database) Trie {
 		var v []byte
 		if (value == common.Hash{}) {
 			s.setError(tr.TryDelete(key[:]))
+			s.db.StorageDeleted += 1
 		} else {
 			// Encoding []byte cannot fail, ok to ignore the error.
 			v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
 			s.setError(tr.TryUpdate(key[:], v))
+			s.db.StorageUpdated += 1
 		}
 		// If state snapshotting is active, cache the data til commit
 		if s.db.snap != nil {
@@ -368,7 +370,7 @@ func (s *stateObject) updateTrie(db Database) Trie {
 					s.db.snapStorage[s.addrHash] = storage
 				}
 			}
-			storage[crypto.HashData(hasher, key[:])] = v // v will be nil if value is 0x00
+			storage[crypto.HashData(hasher, key[:])] = v // v will be nil if it's deleted
 		}
 		usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure
 	}
@@ -396,23 +398,23 @@ func (s *stateObject) updateRoot(db Database) {
 
 // CommitTrie the storage trie of the object to db.
 // This updates the trie root.
-func (s *stateObject) CommitTrie(db Database) error {
+func (s *stateObject) CommitTrie(db Database) (int, error) {
 	// If nothing changed, don't bother with hashing anything
 	if s.updateTrie(db) == nil {
-		return nil
+		return 0, nil
 	}
 	if s.dbErr != nil {
-		return s.dbErr
+		return 0, s.dbErr
 	}
 	// Track the amount of time wasted on committing the storage trie
 	if metrics.EnabledExpensive {
 		defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now())
 	}
-	root, err := s.trie.Commit(nil)
+	root, committed, err := s.trie.Commit(nil)
 	if err == nil {
 		s.data.Root = root
 	}
-	return err
+	return committed, err
 }
 
 // AddBalance adds amount to s's balance.
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 61f0f5b9f6eb2a60549c479d8066cf0a916274ca..a6d47179ba80914c5d781e0cb1938dc27f6a6c0a 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -117,6 +117,11 @@ type StateDB struct {
 	SnapshotAccountReads time.Duration
 	SnapshotStorageReads time.Duration
 	SnapshotCommits      time.Duration
+
+	AccountUpdated int
+	StorageUpdated int
+	AccountDeleted int
+	StorageDeleted int
 }
 
 // New creates a new state from a given trie.
@@ -860,8 +865,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
 	for addr := range s.stateObjectsPending {
 		if obj := s.stateObjects[addr]; obj.deleted {
 			s.deleteStateObject(obj)
+			s.AccountDeleted += 1
 		} else {
 			s.updateStateObject(obj)
+			s.AccountUpdated += 1
 		}
 		usedAddrs = append(usedAddrs, common.CopyBytes(addr[:])) // Copy needed for closure
 	}
@@ -903,6 +910,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
 	s.IntermediateRoot(deleteEmptyObjects)
 
 	// Commit objects to the trie, measuring the elapsed time
+	var storageCommitted int
 	codeWriter := s.db.TrieDB().DiskDB().NewBatch()
 	for addr := range s.stateObjectsDirty {
 		if obj := s.stateObjects[addr]; !obj.deleted {
@@ -912,9 +920,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
 				obj.dirtyCode = false
 			}
 			// Write any storage changes in the state object to its storage trie
-			if err := obj.CommitTrie(s.db); err != nil {
+			committed, err := obj.CommitTrie(s.db)
+			if err != nil {
 				return common.Hash{}, err
 			}
+			storageCommitted += committed
 		}
 	}
 	if len(s.stateObjectsDirty) > 0 {
@@ -933,7 +943,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
 	// The onleaf func is called _serially_, so we can reuse the same account
 	// for unmarshalling every time.
 	var account Account
-	root, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash) error {
+	root, accountCommitted, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash) error {
 		if err := rlp.DecodeBytes(leaf, &account); err != nil {
 			return nil
 		}
@@ -942,8 +952,20 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
 		}
 		return nil
 	})
+	if err != nil {
+		return common.Hash{}, err
+	}
 	if metrics.EnabledExpensive {
 		s.AccountCommits += time.Since(start)
+
+		accountUpdatedMeter.Mark(int64(s.AccountUpdated))
+		storageUpdatedMeter.Mark(int64(s.StorageUpdated))
+		accountDeletedMeter.Mark(int64(s.AccountDeleted))
+		storageDeletedMeter.Mark(int64(s.StorageDeleted))
+		accountCommittedMeter.Mark(int64(accountCommitted))
+		storageCommittedMeter.Mark(int64(storageCommitted))
+		s.AccountUpdated, s.AccountDeleted = 0, 0
+		s.StorageUpdated, s.StorageDeleted = 0, 0
 	}
 	// If snapshotting is enabled, update the snapshot tree with this new version
 	if s.snap != nil {
diff --git a/core/tx_pool.go b/core/tx_pool.go
index f6228df2fad4bfa04d577c4f74dc31f69b62e3e6..ee56dae888d71a536cccb7aa12559a117bbba092 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -111,6 +111,14 @@ var (
 	invalidTxMeter     = metrics.NewRegisteredMeter("txpool/invalid", nil)
 	underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil)
 	overflowedTxMeter  = metrics.NewRegisteredMeter("txpool/overflowed", nil)
+	// throttleTxMeter counts how many transactions are rejected due to too-many-changes between
+	// txpool reorgs.
+	throttleTxMeter = metrics.NewRegisteredMeter("txpool/throttle", nil)
+	// reorgDurationTimer measures how long time a txpool reorg takes.
+	reorgDurationTimer = metrics.NewRegisteredTimer("txpool/reorgtime", nil)
+	// dropBetweenReorgHistogram counts how many drops we experience between two reorg runs. It is expected
+	// that this number is pretty low, since txpool reorgs happen very frequently.
+	dropBetweenReorgHistogram = metrics.NewRegisteredHistogram("txpool/dropbetweenreorg", nil, metrics.NewExpDecaySample(1028, 0.015))
 
 	pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil)
 	queuedGauge  = metrics.NewRegisteredGauge("txpool/queued", nil)
@@ -256,6 +264,8 @@ type TxPool struct {
 	reorgDoneCh     chan chan struct{}
 	reorgShutdownCh chan struct{}  // requests shutdown of scheduleReorgLoop
 	wg              sync.WaitGroup // tracks loop, scheduleReorgLoop
+
+	changesSinceReorg int // A counter for how many drops we've performed in-between reorg.
 }
 
 type txpoolResetRequest struct {
@@ -663,6 +673,15 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
 			underpricedTxMeter.Mark(1)
 			return false, ErrUnderpriced
 		}
+		// We're about to replace a transaction. The reorg does a more thorough
+		// analysis of what to remove and how, but it runs async. We don't want to
+		// do too many replacements between reorg-runs, so we cap the number of
+		// replacements to 25% of the slots
+		if pool.changesSinceReorg > int(pool.config.GlobalSlots/4) {
+			throttleTxMeter.Mark(1)
+			return false, ErrTxPoolOverflow
+		}
+
 		// New transaction is better than our worse ones, make room for it.
 		// If it's a local transaction, forcibly discard all available transactions.
 		// Otherwise if we can't make enough room for new one, abort the operation.
@@ -674,6 +693,8 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
 			overflowedTxMeter.Mark(1)
 			return false, ErrTxPoolOverflow
 		}
+		// Bump the counter of rejections-since-reorg
+		pool.changesSinceReorg += len(drop)
 		// Kick out the underpriced remote transactions.
 		for _, tx := range drop {
 			log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
@@ -1114,6 +1135,9 @@ func (pool *TxPool) scheduleReorgLoop() {
 
 // runReorg runs reset and promoteExecutables on behalf of scheduleReorgLoop.
 func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*txSortedMap) {
+	defer func(t0 time.Time) {
+		reorgDurationTimer.Update(time.Since(t0))
+	}(time.Now())
 	defer close(done)
 
 	var promoteAddrs []common.Address
@@ -1163,6 +1187,8 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
 		highestPending := list.LastElement()
 		pool.pendingNonces.set(addr, highestPending.Nonce()+1)
 	}
+	dropBetweenReorgHistogram.Update(int64(pool.changesSinceReorg))
+	pool.changesSinceReorg = 0 // Reset change counter
 	pool.mu.Unlock()
 
 	// Notify subsystems for newly added transactions
diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go
index e02096fe25ed680bd0b211513d91df34275d614d..f86f64bf2564771e76d32e18244340321bb39a4d 100644
--- a/core/tx_pool_test.go
+++ b/core/tx_pool_test.go
@@ -1946,20 +1946,20 @@ func TestDualHeapEviction(t *testing.T) {
 	}
 
 	add := func(urgent bool) {
-		txs := make([]*types.Transaction, 20)
-		for i := range txs {
+		for i := 0; i < 20; i++ {
+			var tx *types.Transaction
 			// Create a test accounts and fund it
 			key, _ := crypto.GenerateKey()
 			testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000000))
 			if urgent {
-				txs[i] = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+1+i)), big.NewInt(int64(1+i)), key)
-				highTip = txs[i]
+				tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+1+i)), big.NewInt(int64(1+i)), key)
+				highTip = tx
 			} else {
-				txs[i] = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+200+i)), big.NewInt(1), key)
-				highCap = txs[i]
+				tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+200+i)), big.NewInt(1), key)
+				highCap = tx
 			}
+			pool.AddRemotesSync([]*types.Transaction{tx})
 		}
-		pool.AddRemotes(txs)
 		pending, queued := pool.Stats()
 		if pending+queued != 20 {
 			t.Fatalf("transaction count mismatch: have %d, want %d", pending+queued, 10)
diff --git a/core/types/types_test.go b/core/types/types_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..1fb386d5deef2ce07bdb59097097cec1eb2b716e
--- /dev/null
+++ b/core/types/types_test.go
@@ -0,0 +1,148 @@
+// Copyright 2021 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package types
+
+import (
+	"math/big"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/rlp"
+)
+
+type devnull struct{ len int }
+
+func (d *devnull) Write(p []byte) (int, error) {
+	d.len += len(p)
+	return len(p), nil
+}
+
+func BenchmarkEncodeRLP(b *testing.B) {
+	benchRLP(b, true)
+}
+
+func BenchmarkDecodeRLP(b *testing.B) {
+	benchRLP(b, false)
+}
+
+func benchRLP(b *testing.B, encode bool) {
+	key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+	to := common.HexToAddress("0x00000000000000000000000000000000deadbeef")
+	signer := NewLondonSigner(big.NewInt(1337))
+	for _, tc := range []struct {
+		name string
+		obj  interface{}
+	}{
+		{
+			"legacy-header",
+			&Header{
+				Difficulty: big.NewInt(10000000000),
+				Number:     big.NewInt(1000),
+				GasLimit:   8_000_000,
+				GasUsed:    8_000_000,
+				Time:       555,
+				Extra:      make([]byte, 32),
+			},
+		},
+		{
+			"london-header",
+			&Header{
+				Difficulty: big.NewInt(10000000000),
+				Number:     big.NewInt(1000),
+				GasLimit:   8_000_000,
+				GasUsed:    8_000_000,
+				Time:       555,
+				Extra:      make([]byte, 32),
+				BaseFee:    big.NewInt(10000000000),
+			},
+		},
+		{
+			"receipt-for-storage",
+			&ReceiptForStorage{
+				Status:            ReceiptStatusSuccessful,
+				CumulativeGasUsed: 0x888888888,
+				Logs:              make([]*Log, 0),
+			},
+		},
+		{
+			"receipt-full",
+			&Receipt{
+				Status:            ReceiptStatusSuccessful,
+				CumulativeGasUsed: 0x888888888,
+				Logs:              make([]*Log, 0),
+			},
+		},
+		{
+			"legacy-transaction",
+			MustSignNewTx(key, signer,
+				&LegacyTx{
+					Nonce:    1,
+					GasPrice: big.NewInt(500),
+					Gas:      1000000,
+					To:       &to,
+					Value:    big.NewInt(1),
+				}),
+		},
+		{
+			"access-transaction",
+			MustSignNewTx(key, signer,
+				&AccessListTx{
+					Nonce:    1,
+					GasPrice: big.NewInt(500),
+					Gas:      1000000,
+					To:       &to,
+					Value:    big.NewInt(1),
+				}),
+		},
+		{
+			"1559-transaction",
+			MustSignNewTx(key, signer,
+				&DynamicFeeTx{
+					Nonce:     1,
+					Gas:       1000000,
+					To:        &to,
+					Value:     big.NewInt(1),
+					GasTipCap: big.NewInt(500),
+					GasFeeCap: big.NewInt(500),
+				}),
+		},
+	} {
+		if encode {
+			b.Run(tc.name, func(b *testing.B) {
+				b.ReportAllocs()
+				var null = &devnull{}
+				for i := 0; i < b.N; i++ {
+					rlp.Encode(null, tc.obj)
+				}
+				b.SetBytes(int64(null.len / b.N))
+			})
+		} else {
+			data, _ := rlp.EncodeToBytes(tc.obj)
+			// Test decoding
+			b.Run(tc.name, func(b *testing.B) {
+				b.ReportAllocs()
+				for i := 0; i < b.N; i++ {
+					if err := rlp.DecodeBytes(data, tc.obj); err != nil {
+						b.Fatal(err)
+					}
+				}
+				b.SetBytes(int64(len(data)))
+			})
+		}
+	}
+}
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index 944b6cf0a5df538c73cfa442ef7c468bfedef218..19d2198af6bd00f51e69b94de4d1a345f3d07099 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -60,7 +60,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
 // as argument:
 // CALLDATACOPY (stack position 2)
 // CODECOPY (stack position 2)
-// EXTCODECOPY (stack poition 3)
+// EXTCODECOPY (stack position 3)
 // RETURNDATACOPY (stack position 2)
 func memoryCopierGas(stackpos int) gasFunc {
 	return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
diff --git a/crypto/blake2b/blake2bAVX2_amd64.go b/crypto/blake2b/blake2bAVX2_amd64.go
index 0d52b186990b0065bda71ebfab79f2b96c665776..3a85d0e73a6bac61d03b11f2ddfc275d5c0e11c7 100644
--- a/crypto/blake2b/blake2bAVX2_amd64.go
+++ b/crypto/blake2b/blake2bAVX2_amd64.go
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build go1.7 && amd64 && !gccgo && !appengine
 // +build go1.7,amd64,!gccgo,!appengine
 
 package blake2b
diff --git a/crypto/blake2b/blake2b_amd64.go b/crypto/blake2b/blake2b_amd64.go
index 4dbe90da8f1ac478a8009284f2eede61188077eb..a318b2b61767733f87c647a2819d249645b89d48 100644
--- a/crypto/blake2b/blake2b_amd64.go
+++ b/crypto/blake2b/blake2b_amd64.go
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build !go1.7 && amd64 && !gccgo && !appengine
 // +build !go1.7,amd64,!gccgo,!appengine
 
 package blake2b
diff --git a/crypto/blake2b/blake2b_f_fuzz.go b/crypto/blake2b/blake2b_f_fuzz.go
index ab73342803f86c5314703297fe2f55b210d07daa..b2f4057074b78d707b346d43f3f6a457d8325c78 100644
--- a/crypto/blake2b/blake2b_f_fuzz.go
+++ b/crypto/blake2b/blake2b_f_fuzz.go
@@ -1,3 +1,4 @@
+//go:build gofuzz
 // +build gofuzz
 
 package blake2b
diff --git a/crypto/blake2b/blake2b_ref.go b/crypto/blake2b/blake2b_ref.go
index 9d0ade473a144294a11285426f6ac373513d1661..095c71a648c667c9f6f59e350fe342bcc2ee3f3e 100644
--- a/crypto/blake2b/blake2b_ref.go
+++ b/crypto/blake2b/blake2b_ref.go
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build !amd64 || appengine || gccgo
 // +build !amd64 appengine gccgo
 
 package blake2b
diff --git a/crypto/blake2b/register.go b/crypto/blake2b/register.go
index efd689af4b49cd22a4b42bf865998d3888670613..9d8633963cb6e16a26236c24535ee6c61f7b8aec 100644
--- a/crypto/blake2b/register.go
+++ b/crypto/blake2b/register.go
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build go1.9
 // +build go1.9
 
 package blake2b
diff --git a/crypto/bls12381/arithmetic_decl.go b/crypto/bls12381/arithmetic_decl.go
index ec0b21e8055465a39b2acb5103e1b0764d74ebc3..f6d232d658be505c10eb8cf2aabc9035c7f12f80 100644
--- a/crypto/bls12381/arithmetic_decl.go
+++ b/crypto/bls12381/arithmetic_decl.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build (amd64 && blsasm) || (amd64 && blsadx)
 // +build amd64,blsasm amd64,blsadx
 
 package bls12381
diff --git a/crypto/bls12381/arithmetic_fallback.go b/crypto/bls12381/arithmetic_fallback.go
index 91cabf4f3dcc9ec0647e3bcd8ba7f2a34951d2ef..c09ae0d91c72973366221a5d21ad41c9819d08df 100644
--- a/crypto/bls12381/arithmetic_fallback.go
+++ b/crypto/bls12381/arithmetic_fallback.go
@@ -31,6 +31,7 @@
 
 // Package bls (generated by goff) contains field arithmetics operations
 
+//go:build !amd64 || (!blsasm && !blsadx)
 // +build !amd64 !blsasm,!blsadx
 
 package bls12381
diff --git a/crypto/bls12381/arithmetic_x86_adx.go b/crypto/bls12381/arithmetic_x86_adx.go
index 9c30741e6af1d3c584c6e0d4208c1c7b25f02e1a..a40c7384eb57f205662f066fca2c3c300f7a723e 100644
--- a/crypto/bls12381/arithmetic_x86_adx.go
+++ b/crypto/bls12381/arithmetic_x86_adx.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build amd64 && blsadx
 // +build amd64,blsadx
 
 package bls12381
diff --git a/crypto/bls12381/arithmetic_x86_noadx.go b/crypto/bls12381/arithmetic_x86_noadx.go
index eaac4b45d7dc6babe07a0c320a3b2380ed29c642..679b30ec8c3a95f8252753971f928a77e7f2e93b 100644
--- a/crypto/bls12381/arithmetic_x86_noadx.go
+++ b/crypto/bls12381/arithmetic_x86_noadx.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build amd64 && blsasm
 // +build amd64,blsasm
 
 package bls12381
diff --git a/crypto/bn256/bn256_fast.go b/crypto/bn256/bn256_fast.go
index 14b5965393886ee84b7b7e068ef746de256d9378..e3c9b605184fdbd58da63a7414999135a2a7f5e2 100644
--- a/crypto/bn256/bn256_fast.go
+++ b/crypto/bn256/bn256_fast.go
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be found
 // in the LICENSE file.
 
+//go:build amd64 || arm64
 // +build amd64 arm64
 
 // Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
diff --git a/crypto/bn256/bn256_slow.go b/crypto/bn256/bn256_slow.go
index 49021082f5a33949f2835bd5d023aec4b224e192..4c0c351e2da791cb0dfdb3715927613c8d1da685 100644
--- a/crypto/bn256/bn256_slow.go
+++ b/crypto/bn256/bn256_slow.go
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be found
 // in the LICENSE file.
 
+//go:build !amd64 && !arm64
 // +build !amd64,!arm64
 
 // Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
diff --git a/crypto/bn256/cloudflare/bn256_test.go b/crypto/bn256/cloudflare/bn256_test.go
index 0c8016d86cccac4d1cf7e14b5376311f11cc5aaa..481e2f78c3b16320531426cb68c6f84b89a0cea0 100644
--- a/crypto/bn256/cloudflare/bn256_test.go
+++ b/crypto/bn256/cloudflare/bn256_test.go
@@ -92,6 +92,19 @@ func TestTripartiteDiffieHellman(t *testing.T) {
 	}
 }
 
+func TestG2SelfAddition(t *testing.T) {
+	s, _ := rand.Int(rand.Reader, Order)
+	p := new(G2).ScalarBaseMult(s)
+
+	if !p.p.IsOnCurve() {
+		t.Fatal("p isn't on curve")
+	}
+	m := p.Add(p, p).Marshal()
+	if _, err := p.Unmarshal(m); err != nil {
+		t.Fatalf("p.Add(p, p) ∉ G₂: %v", err)
+	}
+}
+
 func BenchmarkG1(b *testing.B) {
 	x, _ := rand.Int(rand.Reader, Order)
 	b.ResetTimer()
diff --git a/crypto/bn256/cloudflare/curve.go b/crypto/bn256/cloudflare/curve.go
index 18e9b38f3f5f0823dec2dd346b667da813e9bae7..16f0489e33af6fc4bb0abc2af79ee7d52da9c41b 100644
--- a/crypto/bn256/cloudflare/curve.go
+++ b/crypto/bn256/cloudflare/curve.go
@@ -171,15 +171,15 @@ func (c *curvePoint) Double(a *curvePoint) {
 	gfpAdd(t, d, d)
 	gfpSub(&c.x, f, t)
 
+	gfpMul(&c.z, &a.y, &a.z)
+	gfpAdd(&c.z, &c.z, &c.z)
+
 	gfpAdd(t, C, C)
 	gfpAdd(t2, t, t)
 	gfpAdd(t, t2, t2)
 	gfpSub(&c.y, d, &c.x)
 	gfpMul(t2, e, &c.y)
 	gfpSub(&c.y, t2, t)
-
-	gfpMul(t, &a.y, &a.z)
-	gfpAdd(&c.z, t, t)
 }
 
 func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
diff --git a/crypto/bn256/cloudflare/gfp.go b/crypto/bn256/cloudflare/gfp.go
index e8e84e7b3b581808d99c15ced865c04cb9fb2dbc..b15e1697e1c0c98b3038ddd6e978ad6ce0bd12b8 100644
--- a/crypto/bn256/cloudflare/gfp.go
+++ b/crypto/bn256/cloudflare/gfp.go
@@ -61,6 +61,7 @@ func (e *gfP) Marshal(out []byte) {
 func (e *gfP) Unmarshal(in []byte) error {
 	// Unmarshal the bytes into little endian form
 	for w := uint(0); w < 4; w++ {
+		e[3-w] = 0
 		for b := uint(0); b < 8; b++ {
 			e[3-w] += uint64(in[8*w+b]) << (56 - 8*b)
 		}
diff --git a/crypto/bn256/cloudflare/gfp_decl.go b/crypto/bn256/cloudflare/gfp_decl.go
index fdea5c11a5be4cb5b22b92ac464a2cf286b99078..ec4018e88a0c0ca47f38704afd93fcffaaaeec30 100644
--- a/crypto/bn256/cloudflare/gfp_decl.go
+++ b/crypto/bn256/cloudflare/gfp_decl.go
@@ -1,3 +1,4 @@
+//go:build (amd64 && !generic) || (arm64 && !generic)
 // +build amd64,!generic arm64,!generic
 
 package bn256
diff --git a/crypto/bn256/cloudflare/gfp_generic.go b/crypto/bn256/cloudflare/gfp_generic.go
index 8e6be959619410955234333ace2e18ce117dac00..7742dda4c9459b0811eac436504f57ba08e88822 100644
--- a/crypto/bn256/cloudflare/gfp_generic.go
+++ b/crypto/bn256/cloudflare/gfp_generic.go
@@ -1,3 +1,4 @@
+//go:build (!amd64 && !arm64) || generic
 // +build !amd64,!arm64 generic
 
 package bn256
diff --git a/crypto/bn256/cloudflare/twist.go b/crypto/bn256/cloudflare/twist.go
index 0c2f80d4eda70a41ed57d22a3986d99792b92964..2c7a69a4d751a96af6717a1c9552f89142d8a045 100644
--- a/crypto/bn256/cloudflare/twist.go
+++ b/crypto/bn256/cloudflare/twist.go
@@ -150,15 +150,15 @@ func (c *twistPoint) Double(a *twistPoint) {
 	t.Add(d, d)
 	c.x.Sub(f, t)
 
+	c.z.Mul(&a.y, &a.z)
+	c.z.Add(&c.z, &c.z)
+
 	t.Add(C, C)
 	t2.Add(t, t)
 	t.Add(t2, t2)
 	c.y.Sub(d, &c.x)
 	t2.Mul(e, &c.y)
 	c.y.Sub(t2, t)
-
-	t.Mul(&a.y, &a.z)
-	c.z.Add(t, t)
 }
 
 func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) {
diff --git a/crypto/secp256k1/dummy.go b/crypto/secp256k1/dummy.go
index c0f2ee52c0c9823bbc86b552641d1d818dac2459..65a75080f60a01f8b2c95da98f7a3b397debc4d7 100644
--- a/crypto/secp256k1/dummy.go
+++ b/crypto/secp256k1/dummy.go
@@ -1,3 +1,4 @@
+//go:build dummy
 // +build dummy
 
 // This file is part of a workaround for `go mod vendor` which won't vendor
diff --git a/crypto/secp256k1/panic_cb.go b/crypto/secp256k1/panic_cb.go
index 5da2bea376e47c88b2252c33daba24465efd6088..a30b04f51b4277cb27e8b0d25e4eb465a4d326d7 100644
--- a/crypto/secp256k1/panic_cb.go
+++ b/crypto/secp256k1/panic_cb.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be found in
 // the LICENSE file.
 
-// +build !gofuzz
-// +build cgo
+//go:build !gofuzz && cgo
+// +build !gofuzz,cgo
 
 package secp256k1
 
diff --git a/crypto/secp256k1/scalar_mult_cgo.go b/crypto/secp256k1/scalar_mult_cgo.go
index f28a1c7826877cfa9aea7d604b58eed1eba88791..8afa9d023b07b035e53628986632c7cedbc8f731 100644
--- a/crypto/secp256k1/scalar_mult_cgo.go
+++ b/crypto/secp256k1/scalar_mult_cgo.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be found in
 // the LICENSE file.
 
-// +build !gofuzz
-// +build cgo
+//go:build !gofuzz && cgo
+// +build !gofuzz,cgo
 
 package secp256k1
 
diff --git a/crypto/secp256k1/scalar_mult_nocgo.go b/crypto/secp256k1/scalar_mult_nocgo.go
index 55756b5be84929ce830ca848b80729c37e4f9245..22f53ac6ae65babe70a6a9e7b6ce69a78b0f8d4f 100644
--- a/crypto/secp256k1/scalar_mult_nocgo.go
+++ b/crypto/secp256k1/scalar_mult_nocgo.go
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be found in
 // the LICENSE file.
 
+//go:build gofuzz || !cgo
 // +build gofuzz !cgo
 
 package secp256k1
diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go
index a1bcf7796e9ede68a6a7d69681ab1ab98f7f935b..c9c01b3209afbd6b7cc8f6f53fa9a4e08002e278 100644
--- a/crypto/secp256k1/secp256.go
+++ b/crypto/secp256k1/secp256.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be found in
 // the LICENSE file.
 
-// +build !gofuzz
-// +build cgo
+//go:build !gofuzz && cgo
+// +build !gofuzz,cgo
 
 // Package secp256k1 wraps the bitcoin secp256k1 C library.
 package secp256k1
diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go
index 84336029801053411c5e1a6f42ba46dcbe3866de..bd72d97d3b62d2637b7b35ad8d17a0b7af55d3ae 100644
--- a/crypto/signature_cgo.go
+++ b/crypto/signature_cgo.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build !nacl && !js && cgo && !gofuzz
 // +build !nacl,!js,cgo,!gofuzz
 
 package crypto
diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go
index 77c8a1db0be24bcf6794ddeeb6a7089d067db0e2..fd1e66c7e6fa9ba8ed2dc4f88b694062fae5c6e3 100644
--- a/crypto/signature_nocgo.go
+++ b/crypto/signature_nocgo.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build nacl || js || !cgo || gofuzz
 // +build nacl js !cgo gofuzz
 
 package crypto
diff --git a/crypto/signify/signify_fuzz.go b/crypto/signify/signify_fuzz.go
index f9167900ad655bc0f78a7e843e0f73fbadd77515..2dc9b2102faa1ba45335a9d5795cc0a4e657aa49 100644
--- a/crypto/signify/signify_fuzz.go
+++ b/crypto/signify/signify_fuzz.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build gofuzz
 // +build gofuzz
 
 package signify
diff --git a/eth/api.go b/eth/api.go
index 0f57128d755b417ba09d41b73abc4084411ed4a3..8b96d1f316d79482347a43110a24c5d41e347570 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -342,7 +342,7 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs,
 		} else {
 			blockRlp = fmt.Sprintf("0x%x", rlpBytes)
 		}
-		if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.engine); err != nil {
+		if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true); err != nil {
 			blockJSON = map[string]interface{}{"error": err.Error()}
 		}
 		results = append(results, &BadBlockArgs{
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index 1767506a33e624fa0ac693340e4c7a86cfa1ad0d..a6bf87acbd222ea8773fc296307c480c25729432 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -448,8 +448,8 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I
 			d.mux.Post(DoneEvent{latest})
 		}
 	}()
-	if p.version < eth.ETH65 {
-		return fmt.Errorf("%w: advertized %d < required %d", errTooOld, p.version, eth.ETH65)
+	if p.version < eth.ETH66 {
+		return fmt.Errorf("%w: advertized %d < required %d", errTooOld, p.version, eth.ETH66)
 	}
 	mode := d.getMode()
 
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index 794160993bb002a0b143206ef3c51c3371ab9be0..17cd3630c98e0bdb88debd4230d2d8b337d66c36 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -522,10 +522,6 @@ func assertOwnForkedChain(t *testing.T, tester *downloadTester, common int, leng
 	}
 }
 
-func TestCanonicalSynchronisation65Full(t *testing.T)  { testCanonSync(t, eth.ETH65, FullSync) }
-func TestCanonicalSynchronisation65Fast(t *testing.T)  { testCanonSync(t, eth.ETH65, FastSync) }
-func TestCanonicalSynchronisation65Light(t *testing.T) { testCanonSync(t, eth.ETH65, LightSync) }
-
 func TestCanonicalSynchronisation66Full(t *testing.T)  { testCanonSync(t, eth.ETH66, FullSync) }
 func TestCanonicalSynchronisation66Fast(t *testing.T)  { testCanonSync(t, eth.ETH66, FastSync) }
 func TestCanonicalSynchronisation66Light(t *testing.T) { testCanonSync(t, eth.ETH66, LightSync) }
@@ -549,9 +545,6 @@ func testCanonSync(t *testing.T, protocol uint, mode SyncMode) {
 
 // Tests that if a large batch of blocks are being downloaded, it is throttled
 // until the cached blocks are retrieved.
-func TestThrottling65Full(t *testing.T) { testThrottling(t, eth.ETH65, FullSync) }
-func TestThrottling65Fast(t *testing.T) { testThrottling(t, eth.ETH65, FastSync) }
-
 func TestThrottling66Full(t *testing.T) { testThrottling(t, eth.ETH66, FullSync) }
 func TestThrottling66Fast(t *testing.T) { testThrottling(t, eth.ETH66, FastSync) }
 
@@ -634,10 +627,6 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) {
 // Tests that simple synchronization against a forked chain works correctly. In
 // this test common ancestor lookup should *not* be short circuited, and a full
 // binary search should be executed.
-func TestForkedSync65Full(t *testing.T)  { testForkedSync(t, eth.ETH65, FullSync) }
-func TestForkedSync65Fast(t *testing.T)  { testForkedSync(t, eth.ETH65, FastSync) }
-func TestForkedSync65Light(t *testing.T) { testForkedSync(t, eth.ETH65, LightSync) }
-
 func TestForkedSync66Full(t *testing.T)  { testForkedSync(t, eth.ETH66, FullSync) }
 func TestForkedSync66Fast(t *testing.T)  { testForkedSync(t, eth.ETH66, FastSync) }
 func TestForkedSync66Light(t *testing.T) { testForkedSync(t, eth.ETH66, LightSync) }
@@ -667,10 +656,6 @@ func testForkedSync(t *testing.T, protocol uint, mode SyncMode) {
 
 // Tests that synchronising against a much shorter but much heavyer fork works
 // corrently and is not dropped.
-func TestHeavyForkedSync65Full(t *testing.T)  { testHeavyForkedSync(t, eth.ETH65, FullSync) }
-func TestHeavyForkedSync65Fast(t *testing.T)  { testHeavyForkedSync(t, eth.ETH65, FastSync) }
-func TestHeavyForkedSync65Light(t *testing.T) { testHeavyForkedSync(t, eth.ETH65, LightSync) }
-
 func TestHeavyForkedSync66Full(t *testing.T)  { testHeavyForkedSync(t, eth.ETH66, FullSync) }
 func TestHeavyForkedSync66Fast(t *testing.T)  { testHeavyForkedSync(t, eth.ETH66, FastSync) }
 func TestHeavyForkedSync66Light(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, LightSync) }
@@ -702,10 +687,6 @@ func testHeavyForkedSync(t *testing.T, protocol uint, mode SyncMode) {
 // Tests that chain forks are contained within a certain interval of the current
 // chain head, ensuring that malicious peers cannot waste resources by feeding
 // long dead chains.
-func TestBoundedForkedSync65Full(t *testing.T)  { testBoundedForkedSync(t, eth.ETH65, FullSync) }
-func TestBoundedForkedSync65Fast(t *testing.T)  { testBoundedForkedSync(t, eth.ETH65, FastSync) }
-func TestBoundedForkedSync65Light(t *testing.T) { testBoundedForkedSync(t, eth.ETH65, LightSync) }
-
 func TestBoundedForkedSync66Full(t *testing.T)  { testBoundedForkedSync(t, eth.ETH66, FullSync) }
 func TestBoundedForkedSync66Fast(t *testing.T)  { testBoundedForkedSync(t, eth.ETH66, FastSync) }
 func TestBoundedForkedSync66Light(t *testing.T) { testBoundedForkedSync(t, eth.ETH66, LightSync) }
@@ -736,16 +717,6 @@ func testBoundedForkedSync(t *testing.T, protocol uint, mode SyncMode) {
 // Tests that chain forks are contained within a certain interval of the current
 // chain head for short but heavy forks too. These are a bit special because they
 // take different ancestor lookup paths.
-func TestBoundedHeavyForkedSync65Full(t *testing.T) {
-	testBoundedHeavyForkedSync(t, eth.ETH65, FullSync)
-}
-func TestBoundedHeavyForkedSync65Fast(t *testing.T) {
-	testBoundedHeavyForkedSync(t, eth.ETH65, FastSync)
-}
-func TestBoundedHeavyForkedSync65Light(t *testing.T) {
-	testBoundedHeavyForkedSync(t, eth.ETH65, LightSync)
-}
-
 func TestBoundedHeavyForkedSync66Full(t *testing.T) {
 	testBoundedHeavyForkedSync(t, eth.ETH66, FullSync)
 }
@@ -800,10 +771,6 @@ func TestInactiveDownloader63(t *testing.T) {
 }
 
 // Tests that a canceled download wipes all previously accumulated state.
-func TestCancel65Full(t *testing.T)  { testCancel(t, eth.ETH65, FullSync) }
-func TestCancel65Fast(t *testing.T)  { testCancel(t, eth.ETH65, FastSync) }
-func TestCancel65Light(t *testing.T) { testCancel(t, eth.ETH65, LightSync) }
-
 func TestCancel66Full(t *testing.T)  { testCancel(t, eth.ETH66, FullSync) }
 func TestCancel66Fast(t *testing.T)  { testCancel(t, eth.ETH66, FastSync) }
 func TestCancel66Light(t *testing.T) { testCancel(t, eth.ETH66, LightSync) }
@@ -833,10 +800,6 @@ func testCancel(t *testing.T, protocol uint, mode SyncMode) {
 }
 
 // Tests that synchronisation from multiple peers works as intended (multi thread sanity test).
-func TestMultiSynchronisation65Full(t *testing.T)  { testMultiSynchronisation(t, eth.ETH65, FullSync) }
-func TestMultiSynchronisation65Fast(t *testing.T)  { testMultiSynchronisation(t, eth.ETH65, FastSync) }
-func TestMultiSynchronisation65Light(t *testing.T) { testMultiSynchronisation(t, eth.ETH65, LightSync) }
-
 func TestMultiSynchronisation66Full(t *testing.T)  { testMultiSynchronisation(t, eth.ETH66, FullSync) }
 func TestMultiSynchronisation66Fast(t *testing.T)  { testMultiSynchronisation(t, eth.ETH66, FastSync) }
 func TestMultiSynchronisation66Light(t *testing.T) { testMultiSynchronisation(t, eth.ETH66, LightSync) }
@@ -863,10 +826,6 @@ func testMultiSynchronisation(t *testing.T, protocol uint, mode SyncMode) {
 
 // Tests that synchronisations behave well in multi-version protocol environments
 // and not wreak havoc on other nodes in the network.
-func TestMultiProtoSynchronisation65Full(t *testing.T)  { testMultiProtoSync(t, eth.ETH65, FullSync) }
-func TestMultiProtoSynchronisation65Fast(t *testing.T)  { testMultiProtoSync(t, eth.ETH65, FastSync) }
-func TestMultiProtoSynchronisation65Light(t *testing.T) { testMultiProtoSync(t, eth.ETH65, LightSync) }
-
 func TestMultiProtoSynchronisation66Full(t *testing.T)  { testMultiProtoSync(t, eth.ETH66, FullSync) }
 func TestMultiProtoSynchronisation66Fast(t *testing.T)  { testMultiProtoSync(t, eth.ETH66, FastSync) }
 func TestMultiProtoSynchronisation66Light(t *testing.T) { testMultiProtoSync(t, eth.ETH66, LightSync) }
@@ -881,8 +840,8 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) {
 	chain := testChainBase.shorten(blockCacheMaxItems - 15)
 
 	// Create peers of every type
-	tester.newPeer("peer 65", eth.ETH65, chain)
 	tester.newPeer("peer 66", eth.ETH66, chain)
+	//tester.newPeer("peer 65", eth.ETH67, chain)
 
 	// Synchronise with the requested peer and make sure all blocks were retrieved
 	if err := tester.sync(fmt.Sprintf("peer %d", protocol), nil, mode); err != nil {
@@ -891,7 +850,7 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) {
 	assertOwnChain(t, tester, chain.len())
 
 	// Check that no peers have been dropped off
-	for _, version := range []int{65, 66} {
+	for _, version := range []int{66} {
 		peer := fmt.Sprintf("peer %d", version)
 		if _, ok := tester.peers[peer]; !ok {
 			t.Errorf("%s dropped", peer)
@@ -901,10 +860,6 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) {
 
 // Tests that if a block is empty (e.g. header only), no body request should be
 // made, and instead the header should be assembled into a whole block in itself.
-func TestEmptyShortCircuit65Full(t *testing.T)  { testEmptyShortCircuit(t, eth.ETH65, FullSync) }
-func TestEmptyShortCircuit65Fast(t *testing.T)  { testEmptyShortCircuit(t, eth.ETH65, FastSync) }
-func TestEmptyShortCircuit65Light(t *testing.T) { testEmptyShortCircuit(t, eth.ETH65, LightSync) }
-
 func TestEmptyShortCircuit66Full(t *testing.T)  { testEmptyShortCircuit(t, eth.ETH66, FullSync) }
 func TestEmptyShortCircuit66Fast(t *testing.T)  { testEmptyShortCircuit(t, eth.ETH66, FastSync) }
 func TestEmptyShortCircuit66Light(t *testing.T) { testEmptyShortCircuit(t, eth.ETH66, LightSync) }
@@ -955,10 +910,6 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) {
 
 // Tests that headers are enqueued continuously, preventing malicious nodes from
 // stalling the downloader by feeding gapped header chains.
-func TestMissingHeaderAttack65Full(t *testing.T)  { testMissingHeaderAttack(t, eth.ETH65, FullSync) }
-func TestMissingHeaderAttack65Fast(t *testing.T)  { testMissingHeaderAttack(t, eth.ETH65, FastSync) }
-func TestMissingHeaderAttack65Light(t *testing.T) { testMissingHeaderAttack(t, eth.ETH65, LightSync) }
-
 func TestMissingHeaderAttack66Full(t *testing.T)  { testMissingHeaderAttack(t, eth.ETH66, FullSync) }
 func TestMissingHeaderAttack66Fast(t *testing.T)  { testMissingHeaderAttack(t, eth.ETH66, FastSync) }
 func TestMissingHeaderAttack66Light(t *testing.T) { testMissingHeaderAttack(t, eth.ETH66, LightSync) }
@@ -987,10 +938,6 @@ func testMissingHeaderAttack(t *testing.T, protocol uint, mode SyncMode) {
 
 // Tests that if requested headers are shifted (i.e. first is missing), the queue
 // detects the invalid numbering.
-func TestShiftedHeaderAttack65Full(t *testing.T)  { testShiftedHeaderAttack(t, eth.ETH65, FullSync) }
-func TestShiftedHeaderAttack65Fast(t *testing.T)  { testShiftedHeaderAttack(t, eth.ETH65, FastSync) }
-func TestShiftedHeaderAttack65Light(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH65, LightSync) }
-
 func TestShiftedHeaderAttack66Full(t *testing.T)  { testShiftedHeaderAttack(t, eth.ETH66, FullSync) }
 func TestShiftedHeaderAttack66Fast(t *testing.T)  { testShiftedHeaderAttack(t, eth.ETH66, FastSync) }
 func TestShiftedHeaderAttack66Light(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH66, LightSync) }
@@ -1024,7 +971,6 @@ func testShiftedHeaderAttack(t *testing.T, protocol uint, mode SyncMode) {
 // Tests that upon detecting an invalid header, the recent ones are rolled back
 // for various failure scenarios. Afterwards a full sync is attempted to make
 // sure no state was corrupted.
-func TestInvalidHeaderRollback65Fast(t *testing.T) { testInvalidHeaderRollback(t, eth.ETH65, FastSync) }
 func TestInvalidHeaderRollback66Fast(t *testing.T) { testInvalidHeaderRollback(t, eth.ETH66, FastSync) }
 
 func testInvalidHeaderRollback(t *testing.T, protocol uint, mode SyncMode) {
@@ -1115,16 +1061,6 @@ func testInvalidHeaderRollback(t *testing.T, protocol uint, mode SyncMode) {
 
 // Tests that a peer advertising a high TD doesn't get to stall the downloader
 // afterwards by not sending any useful hashes.
-func TestHighTDStarvationAttack65Full(t *testing.T) {
-	testHighTDStarvationAttack(t, eth.ETH65, FullSync)
-}
-func TestHighTDStarvationAttack65Fast(t *testing.T) {
-	testHighTDStarvationAttack(t, eth.ETH65, FastSync)
-}
-func TestHighTDStarvationAttack65Light(t *testing.T) {
-	testHighTDStarvationAttack(t, eth.ETH65, LightSync)
-}
-
 func TestHighTDStarvationAttack66Full(t *testing.T) {
 	testHighTDStarvationAttack(t, eth.ETH66, FullSync)
 }
@@ -1149,7 +1085,6 @@ func testHighTDStarvationAttack(t *testing.T, protocol uint, mode SyncMode) {
 }
 
 // Tests that misbehaving peers are disconnected, whilst behaving ones are not.
-func TestBlockHeaderAttackerDropping65(t *testing.T) { testBlockHeaderAttackerDropping(t, eth.ETH65) }
 func TestBlockHeaderAttackerDropping66(t *testing.T) { testBlockHeaderAttackerDropping(t, eth.ETH66) }
 
 func testBlockHeaderAttackerDropping(t *testing.T, protocol uint) {
@@ -1202,10 +1137,6 @@ func testBlockHeaderAttackerDropping(t *testing.T, protocol uint) {
 
 // Tests that synchronisation progress (origin block number, current block number
 // and highest block number) is tracked and updated correctly.
-func TestSyncProgress65Full(t *testing.T)  { testSyncProgress(t, eth.ETH65, FullSync) }
-func TestSyncProgress65Fast(t *testing.T)  { testSyncProgress(t, eth.ETH65, FastSync) }
-func TestSyncProgress65Light(t *testing.T) { testSyncProgress(t, eth.ETH65, LightSync) }
-
 func TestSyncProgress66Full(t *testing.T)  { testSyncProgress(t, eth.ETH66, FullSync) }
 func TestSyncProgress66Fast(t *testing.T)  { testSyncProgress(t, eth.ETH66, FastSync) }
 func TestSyncProgress66Light(t *testing.T) { testSyncProgress(t, eth.ETH66, LightSync) }
@@ -1286,10 +1217,6 @@ func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.Sync
 // Tests that synchronisation progress (origin block number and highest block
 // number) is tracked and updated correctly in case of a fork (or manual head
 // revertal).
-func TestForkedSyncProgress65Full(t *testing.T)  { testForkedSyncProgress(t, eth.ETH65, FullSync) }
-func TestForkedSyncProgress65Fast(t *testing.T)  { testForkedSyncProgress(t, eth.ETH65, FastSync) }
-func TestForkedSyncProgress65Light(t *testing.T) { testForkedSyncProgress(t, eth.ETH65, LightSync) }
-
 func TestForkedSyncProgress66Full(t *testing.T)  { testForkedSyncProgress(t, eth.ETH66, FullSync) }
 func TestForkedSyncProgress66Fast(t *testing.T)  { testForkedSyncProgress(t, eth.ETH66, FastSync) }
 func TestForkedSyncProgress66Light(t *testing.T) { testForkedSyncProgress(t, eth.ETH66, LightSync) }
@@ -1362,10 +1289,6 @@ func testForkedSyncProgress(t *testing.T, protocol uint, mode SyncMode) {
 // Tests that if synchronisation is aborted due to some failure, then the progress
 // origin is not updated in the next sync cycle, as it should be considered the
 // continuation of the previous sync and not a new instance.
-func TestFailedSyncProgress65Full(t *testing.T)  { testFailedSyncProgress(t, eth.ETH65, FullSync) }
-func TestFailedSyncProgress65Fast(t *testing.T)  { testFailedSyncProgress(t, eth.ETH65, FastSync) }
-func TestFailedSyncProgress65Light(t *testing.T) { testFailedSyncProgress(t, eth.ETH65, LightSync) }
-
 func TestFailedSyncProgress66Full(t *testing.T)  { testFailedSyncProgress(t, eth.ETH66, FullSync) }
 func TestFailedSyncProgress66Fast(t *testing.T)  { testFailedSyncProgress(t, eth.ETH66, FastSync) }
 func TestFailedSyncProgress66Light(t *testing.T) { testFailedSyncProgress(t, eth.ETH66, LightSync) }
@@ -1435,10 +1358,6 @@ func testFailedSyncProgress(t *testing.T, protocol uint, mode SyncMode) {
 
 // Tests that if an attacker fakes a chain height, after the attack is detected,
 // the progress height is successfully reduced at the next sync invocation.
-func TestFakedSyncProgress65Full(t *testing.T)  { testFakedSyncProgress(t, eth.ETH65, FullSync) }
-func TestFakedSyncProgress65Fast(t *testing.T)  { testFakedSyncProgress(t, eth.ETH65, FastSync) }
-func TestFakedSyncProgress65Light(t *testing.T) { testFakedSyncProgress(t, eth.ETH65, LightSync) }
-
 func TestFakedSyncProgress66Full(t *testing.T)  { testFakedSyncProgress(t, eth.ETH66, FullSync) }
 func TestFakedSyncProgress66Fast(t *testing.T)  { testFakedSyncProgress(t, eth.ETH66, FastSync) }
 func TestFakedSyncProgress66Light(t *testing.T) { testFakedSyncProgress(t, eth.ETH66, LightSync) }
@@ -1512,10 +1431,6 @@ func testFakedSyncProgress(t *testing.T, protocol uint, mode SyncMode) {
 
 // This test reproduces an issue where unexpected deliveries would
 // block indefinitely if they arrived at the right time.
-func TestDeliverHeadersHang65Full(t *testing.T)  { testDeliverHeadersHang(t, eth.ETH65, FullSync) }
-func TestDeliverHeadersHang65Fast(t *testing.T)  { testDeliverHeadersHang(t, eth.ETH65, FastSync) }
-func TestDeliverHeadersHang65Light(t *testing.T) { testDeliverHeadersHang(t, eth.ETH65, LightSync) }
-
 func TestDeliverHeadersHang66Full(t *testing.T)  { testDeliverHeadersHang(t, eth.ETH66, FullSync) }
 func TestDeliverHeadersHang66Fast(t *testing.T)  { testDeliverHeadersHang(t, eth.ETH66, FastSync) }
 func TestDeliverHeadersHang66Light(t *testing.T) { testDeliverHeadersHang(t, eth.ETH66, LightSync) }
@@ -1673,12 +1588,6 @@ func TestRemoteHeaderRequestSpan(t *testing.T) {
 
 // Tests that peers below a pre-configured checkpoint block are prevented from
 // being fast-synced from, avoiding potential cheap eclipse attacks.
-func TestCheckpointEnforcement65Full(t *testing.T) { testCheckpointEnforcement(t, eth.ETH65, FullSync) }
-func TestCheckpointEnforcement65Fast(t *testing.T) { testCheckpointEnforcement(t, eth.ETH65, FastSync) }
-func TestCheckpointEnforcement65Light(t *testing.T) {
-	testCheckpointEnforcement(t, eth.ETH65, LightSync)
-}
-
 func TestCheckpointEnforcement66Full(t *testing.T) { testCheckpointEnforcement(t, eth.ETH66, FullSync) }
 func TestCheckpointEnforcement66Fast(t *testing.T) { testCheckpointEnforcement(t, eth.ETH66, FastSync) }
 func TestCheckpointEnforcement66Light(t *testing.T) {
diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go
index 066a366315a7628798ac8e16600c05680e205677..863294832971114a2344751ebfe82c300e6a0c7a 100644
--- a/eth/downloader/peer.go
+++ b/eth/downloader/peer.go
@@ -413,7 +413,7 @@ func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) {
 	throughput := func(p *peerConnection) int {
 		return p.rates.Capacity(eth.BlockHeadersMsg, time.Second)
 	}
-	return ps.idlePeers(eth.ETH65, eth.ETH66, idle, throughput)
+	return ps.idlePeers(eth.ETH66, eth.ETH66, idle, throughput)
 }
 
 // BodyIdlePeers retrieves a flat list of all the currently body-idle peers within
@@ -425,7 +425,7 @@ func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) {
 	throughput := func(p *peerConnection) int {
 		return p.rates.Capacity(eth.BlockBodiesMsg, time.Second)
 	}
-	return ps.idlePeers(eth.ETH65, eth.ETH66, idle, throughput)
+	return ps.idlePeers(eth.ETH66, eth.ETH66, idle, throughput)
 }
 
 // ReceiptIdlePeers retrieves a flat list of all the currently receipt-idle peers
@@ -437,7 +437,7 @@ func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) {
 	throughput := func(p *peerConnection) int {
 		return p.rates.Capacity(eth.ReceiptsMsg, time.Second)
 	}
-	return ps.idlePeers(eth.ETH65, eth.ETH66, idle, throughput)
+	return ps.idlePeers(eth.ETH66, eth.ETH66, idle, throughput)
 }
 
 // NodeDataIdlePeers retrieves a flat list of all the currently node-data-idle
@@ -449,7 +449,7 @@ func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) {
 	throughput := func(p *peerConnection) int {
 		return p.rates.Capacity(eth.NodeDataMsg, time.Second)
 	}
-	return ps.idlePeers(eth.ETH65, eth.ETH66, idle, throughput)
+	return ps.idlePeers(eth.ETH66, eth.ETH66, idle, throughput)
 }
 
 // idlePeers retrieves a flat list of all currently idle peers satisfying the
diff --git a/eth/handler.go b/eth/handler.go
index aff4871afa42683033f300bcf19eaef374645e4e..06a8088bf07cc909fb00f311d0bb2b0cf5d164ae 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -117,7 +117,6 @@ type handler struct {
 	whitelist map[uint64]common.Hash
 
 	// channels for fetcher, syncer, txsyncLoop
-	txsyncCh chan *txsync
 	quitSync chan struct{}
 
 	chainSync *chainSyncer
@@ -140,7 +139,6 @@ func newHandler(config *handlerConfig) (*handler, error) {
 		chain:      config.Chain,
 		peers:      newPeerSet(),
 		whitelist:  config.Whitelist,
-		txsyncCh:   make(chan *txsync),
 		quitSync:   make(chan struct{}),
 	}
 	if config.Sync == downloader.FullSync {
@@ -408,9 +406,8 @@ func (h *handler) Start(maxPeers int) {
 	go h.minedBroadcastLoop()
 
 	// start sync handlers
-	h.wg.Add(2)
+	h.wg.Add(1)
 	go h.chainSync.loop()
-	go h.txsyncLoop64() // TODO(karalabe): Legacy initial tx echange, drop with eth/64.
 }
 
 func (h *handler) Stop() {
diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go
index 038de469908ecf5d17cc822beed64cf5be30470f..039091244fec59f0351cb4226b509387f84a62d7 100644
--- a/eth/handler_eth_test.go
+++ b/eth/handler_eth_test.go
@@ -80,7 +80,6 @@ func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error {
 
 // Tests that peers are correctly accepted (or rejected) based on the advertised
 // fork IDs in the protocol handshake.
-func TestForkIDSplit65(t *testing.T) { testForkIDSplit(t, eth.ETH65) }
 func TestForkIDSplit66(t *testing.T) { testForkIDSplit(t, eth.ETH66) }
 
 func testForkIDSplit(t *testing.T, protocol uint) {
@@ -236,7 +235,6 @@ func testForkIDSplit(t *testing.T, protocol uint) {
 }
 
 // Tests that received transactions are added to the local pool.
-func TestRecvTransactions65(t *testing.T) { testRecvTransactions(t, eth.ETH65) }
 func TestRecvTransactions66(t *testing.T) { testRecvTransactions(t, eth.ETH66) }
 
 func testRecvTransactions(t *testing.T, protocol uint) {
@@ -294,7 +292,6 @@ func testRecvTransactions(t *testing.T, protocol uint) {
 }
 
 // This test checks that pending transactions are sent.
-func TestSendTransactions65(t *testing.T) { testSendTransactions(t, eth.ETH65) }
 func TestSendTransactions66(t *testing.T) { testSendTransactions(t, eth.ETH66) }
 
 func testSendTransactions(t *testing.T, protocol uint) {
@@ -306,7 +303,7 @@ func testSendTransactions(t *testing.T, protocol uint) {
 
 	insert := make([]*types.Transaction, 100)
 	for nonce := range insert {
-		tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, txsyncPackSize/10))
+		tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, 10240))
 		tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
 
 		insert[nonce] = tx
@@ -380,7 +377,6 @@ func testSendTransactions(t *testing.T, protocol uint) {
 
 // Tests that transactions get propagated to all attached peers, either via direct
 // broadcasts or via announcements/retrievals.
-func TestTransactionPropagation65(t *testing.T) { testTransactionPropagation(t, eth.ETH65) }
 func TestTransactionPropagation66(t *testing.T) { testTransactionPropagation(t, eth.ETH66) }
 
 func testTransactionPropagation(t *testing.T, protocol uint) {
@@ -521,8 +517,8 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo
 	defer p2pLocal.Close()
 	defer p2pRemote.Close()
 
-	local := eth.NewPeer(eth.ETH65, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pLocal), p2pLocal, handler.txpool)
-	remote := eth.NewPeer(eth.ETH65, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pRemote), p2pRemote, handler.txpool)
+	local := eth.NewPeer(eth.ETH66, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pLocal), p2pLocal, handler.txpool)
+	remote := eth.NewPeer(eth.ETH66, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pRemote), p2pRemote, handler.txpool)
 	defer local.Close()
 	defer remote.Close()
 
@@ -543,30 +539,39 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo
 	if err := remote.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
 		t.Fatalf("failed to run protocol handshake")
 	}
-
 	// Connect a new peer and check that we receive the checkpoint challenge.
 	if checkpoint {
-		if err := remote.ExpectRequestHeadersByNumber(response.Number.Uint64(), 1, 0, false); err != nil {
-			t.Fatalf("challenge mismatch: %v", err)
+		msg, err := p2pRemote.ReadMsg()
+		if err != nil {
+			t.Fatalf("failed to read checkpoint challenge: %v", err)
+		}
+		request := new(eth.GetBlockHeadersPacket66)
+		if err := msg.Decode(request); err != nil {
+			t.Fatalf("failed to decode checkpoint challenge: %v", err)
+		}
+		query := request.GetBlockHeadersPacket
+		if query.Origin.Number != response.Number.Uint64() || query.Amount != 1 || query.Skip != 0 || query.Reverse {
+			t.Fatalf("challenge mismatch: have [%d, %d, %d, %v] want [%d, %d, %d, %v]",
+				query.Origin.Number, query.Amount, query.Skip, query.Reverse,
+				response.Number.Uint64(), 1, 0, false)
 		}
 		// Create a block to reply to the challenge if no timeout is simulated.
 		if !timeout {
 			if empty {
-				if err := remote.SendBlockHeaders([]*types.Header{}); err != nil {
+				if err := remote.ReplyBlockHeaders(request.RequestId, []*types.Header{}); err != nil {
 					t.Fatalf("failed to answer challenge: %v", err)
 				}
 			} else if match {
-				if err := remote.SendBlockHeaders([]*types.Header{response}); err != nil {
+				if err := remote.ReplyBlockHeaders(request.RequestId, []*types.Header{response}); err != nil {
 					t.Fatalf("failed to answer challenge: %v", err)
 				}
 			} else {
-				if err := remote.SendBlockHeaders([]*types.Header{{Number: response.Number}}); err != nil {
+				if err := remote.ReplyBlockHeaders(request.RequestId, []*types.Header{{Number: response.Number}}); err != nil {
 					t.Fatalf("failed to answer challenge: %v", err)
 				}
 			}
 		}
 	}
-
 	// Wait until the test timeout passes to ensure proper cleanup
 	time.Sleep(syncChallengeTimeout + 300*time.Millisecond)
 
@@ -619,8 +624,8 @@ func testBroadcastBlock(t *testing.T, peers, bcasts int) {
 		defer sourcePipe.Close()
 		defer sinkPipe.Close()
 
-		sourcePeer := eth.NewPeer(eth.ETH65, p2p.NewPeerPipe(enode.ID{byte(i)}, "", nil, sourcePipe), sourcePipe, nil)
-		sinkPeer := eth.NewPeer(eth.ETH65, p2p.NewPeerPipe(enode.ID{0}, "", nil, sinkPipe), sinkPipe, nil)
+		sourcePeer := eth.NewPeer(eth.ETH66, p2p.NewPeerPipe(enode.ID{byte(i)}, "", nil, sourcePipe), sourcePipe, nil)
+		sinkPeer := eth.NewPeer(eth.ETH66, p2p.NewPeerPipe(enode.ID{0}, "", nil, sinkPipe), sinkPipe, nil)
 		defer sourcePeer.Close()
 		defer sinkPeer.Close()
 
@@ -671,7 +676,6 @@ func testBroadcastBlock(t *testing.T, peers, bcasts int) {
 
 // Tests that a propagated malformed block (uncles or transactions don't match
 // with the hashes in the header) gets discarded and not broadcast forward.
-func TestBroadcastMalformedBlock65(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH65) }
 func TestBroadcastMalformedBlock66(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH66) }
 
 func testBroadcastMalformedBlock(t *testing.T, protocol uint) {
diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go
index 6bbaa2f555f16286fc83de1c15936bfe048d5b03..8289300141f09a685f5110a5434db2c1d85e49ee 100644
--- a/eth/protocols/eth/handler.go
+++ b/eth/protocols/eth/handler.go
@@ -171,39 +171,21 @@ type Decoder interface {
 	Time() time.Time
 }
 
-var eth65 = map[uint64]msgHandler{
-	GetBlockHeadersMsg:            handleGetBlockHeaders,
-	BlockHeadersMsg:               handleBlockHeaders,
-	GetBlockBodiesMsg:             handleGetBlockBodies,
-	BlockBodiesMsg:                handleBlockBodies,
-	GetNodeDataMsg:                handleGetNodeData,
-	NodeDataMsg:                   handleNodeData,
-	GetReceiptsMsg:                handleGetReceipts,
-	ReceiptsMsg:                   handleReceipts,
-	NewBlockHashesMsg:             handleNewBlockhashes,
-	NewBlockMsg:                   handleNewBlock,
-	TransactionsMsg:               handleTransactions,
-	NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes,
-	GetPooledTransactionsMsg:      handleGetPooledTransactions,
-	PooledTransactionsMsg:         handlePooledTransactions,
-}
-
 var eth66 = map[uint64]msgHandler{
 	NewBlockHashesMsg:             handleNewBlockhashes,
 	NewBlockMsg:                   handleNewBlock,
 	TransactionsMsg:               handleTransactions,
 	NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes,
-	// eth66 messages with request-id
-	GetBlockHeadersMsg:       handleGetBlockHeaders66,
-	BlockHeadersMsg:          handleBlockHeaders66,
-	GetBlockBodiesMsg:        handleGetBlockBodies66,
-	BlockBodiesMsg:           handleBlockBodies66,
-	GetNodeDataMsg:           handleGetNodeData66,
-	NodeDataMsg:              handleNodeData66,
-	GetReceiptsMsg:           handleGetReceipts66,
-	ReceiptsMsg:              handleReceipts66,
-	GetPooledTransactionsMsg: handleGetPooledTransactions66,
-	PooledTransactionsMsg:    handlePooledTransactions66,
+	GetBlockHeadersMsg:            handleGetBlockHeaders66,
+	BlockHeadersMsg:               handleBlockHeaders66,
+	GetBlockBodiesMsg:             handleGetBlockBodies66,
+	BlockBodiesMsg:                handleBlockBodies66,
+	GetNodeDataMsg:                handleGetNodeData66,
+	NodeDataMsg:                   handleNodeData66,
+	GetReceiptsMsg:                handleGetReceipts66,
+	ReceiptsMsg:                   handleReceipts66,
+	GetPooledTransactionsMsg:      handleGetPooledTransactions66,
+	PooledTransactionsMsg:         handlePooledTransactions66,
 }
 
 // handleMessage is invoked whenever an inbound message is received from a remote
@@ -219,10 +201,11 @@ func handleMessage(backend Backend, peer *Peer) error {
 	}
 	defer msg.Discard()
 
-	var handlers = eth65
-	if peer.Version() >= ETH66 {
-		handlers = eth66
-	}
+	var handlers = eth66
+	//if peer.Version() >= ETH67 { // Left in as a sample when new protocol is added
+	//	handlers = eth67
+	//}
+
 	// Track the amount of time it takes to serve the request and run the handler
 	if metrics.Enabled {
 		h := fmt.Sprintf("%s/%s/%d/%#02x", p2p.HandleHistName, ProtocolName, peer.Version(), msg.Code)
diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go
index 473be3f9b77e53732b6bf4e555efc396aaa19053..809f17e36cf5a5f4415650fbce1bbe35319dfb9b 100644
--- a/eth/protocols/eth/handler_test.go
+++ b/eth/protocols/eth/handler_test.go
@@ -110,7 +110,6 @@ func (b *testBackend) Handle(*Peer, Packet) error {
 }
 
 // Tests that block headers can be retrieved from a remote chain based on user queries.
-func TestGetBlockHeaders65(t *testing.T) { testGetBlockHeaders(t, ETH65) }
 func TestGetBlockHeaders66(t *testing.T) { testGetBlockHeaders(t, ETH66) }
 
 func testGetBlockHeaders(t *testing.T, protocol uint) {
@@ -254,44 +253,30 @@ func testGetBlockHeaders(t *testing.T, protocol uint) {
 			headers = append(headers, backend.chain.GetBlockByHash(hash).Header())
 		}
 		// Send the hash request and verify the response
-		if protocol <= ETH65 {
-			p2p.Send(peer.app, GetBlockHeadersMsg, tt.query)
-			if err := p2p.ExpectMsg(peer.app, BlockHeadersMsg, headers); err != nil {
-				t.Errorf("test %d: headers mismatch: %v", i, err)
-			}
-		} else {
-			p2p.Send(peer.app, GetBlockHeadersMsg, GetBlockHeadersPacket66{
-				RequestId:             123,
-				GetBlockHeadersPacket: tt.query,
-			})
-			if err := p2p.ExpectMsg(peer.app, BlockHeadersMsg, BlockHeadersPacket66{
-				RequestId:          123,
-				BlockHeadersPacket: headers,
-			}); err != nil {
-				t.Errorf("test %d: headers mismatch: %v", i, err)
-			}
+		p2p.Send(peer.app, GetBlockHeadersMsg, GetBlockHeadersPacket66{
+			RequestId:             123,
+			GetBlockHeadersPacket: tt.query,
+		})
+		if err := p2p.ExpectMsg(peer.app, BlockHeadersMsg, BlockHeadersPacket66{
+			RequestId:          123,
+			BlockHeadersPacket: headers,
+		}); err != nil {
+			t.Errorf("test %d: headers mismatch: %v", i, err)
 		}
 		// If the test used number origins, repeat with hashes as the too
 		if tt.query.Origin.Hash == (common.Hash{}) {
 			if origin := backend.chain.GetBlockByNumber(tt.query.Origin.Number); origin != nil {
 				tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0
 
-				if protocol <= ETH65 {
-					p2p.Send(peer.app, GetBlockHeadersMsg, tt.query)
-					if err := p2p.ExpectMsg(peer.app, BlockHeadersMsg, headers); err != nil {
-						t.Errorf("test %d: headers mismatch: %v", i, err)
-					}
-				} else {
-					p2p.Send(peer.app, GetBlockHeadersMsg, GetBlockHeadersPacket66{
-						RequestId:             456,
-						GetBlockHeadersPacket: tt.query,
-					})
-					if err := p2p.ExpectMsg(peer.app, BlockHeadersMsg, BlockHeadersPacket66{
-						RequestId:          456,
-						BlockHeadersPacket: headers,
-					}); err != nil {
-						t.Errorf("test %d: headers mismatch: %v", i, err)
-					}
+				p2p.Send(peer.app, GetBlockHeadersMsg, GetBlockHeadersPacket66{
+					RequestId:             456,
+					GetBlockHeadersPacket: tt.query,
+				})
+				if err := p2p.ExpectMsg(peer.app, BlockHeadersMsg, BlockHeadersPacket66{
+					RequestId:          456,
+					BlockHeadersPacket: headers,
+				}); err != nil {
+					t.Errorf("test %d: headers mismatch: %v", i, err)
 				}
 			}
 		}
@@ -299,7 +284,6 @@ func testGetBlockHeaders(t *testing.T, protocol uint) {
 }
 
 // Tests that block contents can be retrieved from a remote chain based on their hashes.
-func TestGetBlockBodies65(t *testing.T) { testGetBlockBodies(t, ETH65) }
 func TestGetBlockBodies66(t *testing.T) { testGetBlockBodies(t, ETH66) }
 
 func testGetBlockBodies(t *testing.T, protocol uint) {
@@ -369,28 +353,20 @@ func testGetBlockBodies(t *testing.T, protocol uint) {
 			}
 		}
 		// Send the hash request and verify the response
-		if protocol <= ETH65 {
-			p2p.Send(peer.app, GetBlockBodiesMsg, hashes)
-			if err := p2p.ExpectMsg(peer.app, BlockBodiesMsg, bodies); err != nil {
-				t.Errorf("test %d: bodies mismatch: %v", i, err)
-			}
-		} else {
-			p2p.Send(peer.app, GetBlockBodiesMsg, GetBlockBodiesPacket66{
-				RequestId:            123,
-				GetBlockBodiesPacket: hashes,
-			})
-			if err := p2p.ExpectMsg(peer.app, BlockBodiesMsg, BlockBodiesPacket66{
-				RequestId:         123,
-				BlockBodiesPacket: bodies,
-			}); err != nil {
-				t.Errorf("test %d: bodies mismatch: %v", i, err)
-			}
+		p2p.Send(peer.app, GetBlockBodiesMsg, GetBlockBodiesPacket66{
+			RequestId:            123,
+			GetBlockBodiesPacket: hashes,
+		})
+		if err := p2p.ExpectMsg(peer.app, BlockBodiesMsg, BlockBodiesPacket66{
+			RequestId:         123,
+			BlockBodiesPacket: bodies,
+		}); err != nil {
+			t.Errorf("test %d: bodies mismatch: %v", i, err)
 		}
 	}
 }
 
 // Tests that the state trie nodes can be retrieved based on hashes.
-func TestGetNodeData65(t *testing.T) { testGetNodeData(t, ETH65) }
 func TestGetNodeData66(t *testing.T) { testGetNodeData(t, ETH66) }
 
 func testGetNodeData(t *testing.T, protocol uint) {
@@ -449,14 +425,10 @@ func testGetNodeData(t *testing.T, protocol uint) {
 	}
 	it.Release()
 
-	if protocol <= ETH65 {
-		p2p.Send(peer.app, GetNodeDataMsg, hashes)
-	} else {
-		p2p.Send(peer.app, GetNodeDataMsg, GetNodeDataPacket66{
-			RequestId:         123,
-			GetNodeDataPacket: hashes,
-		})
-	}
+	p2p.Send(peer.app, GetNodeDataMsg, GetNodeDataPacket66{
+		RequestId:         123,
+		GetNodeDataPacket: hashes,
+	})
 	msg, err := peer.app.ReadMsg()
 	if err != nil {
 		t.Fatalf("failed to read node data response: %v", err)
@@ -464,18 +436,14 @@ func testGetNodeData(t *testing.T, protocol uint) {
 	if msg.Code != NodeDataMsg {
 		t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, NodeDataMsg)
 	}
-	var data [][]byte
-	if protocol <= ETH65 {
-		if err := msg.Decode(&data); err != nil {
-			t.Fatalf("failed to decode response node data: %v", err)
-		}
-	} else {
-		var res NodeDataPacket66
-		if err := msg.Decode(&res); err != nil {
-			t.Fatalf("failed to decode response node data: %v", err)
-		}
-		data = res.NodeDataPacket
+	var (
+		data [][]byte
+		res  NodeDataPacket66
+	)
+	if err := msg.Decode(&res); err != nil {
+		t.Fatalf("failed to decode response node data: %v", err)
 	}
+	data = res.NodeDataPacket
 	// Verify that all hashes correspond to the requested data, and reconstruct a state tree
 	for i, want := range hashes {
 		if hash := crypto.Keccak256Hash(data[i]); hash != want {
@@ -506,7 +474,6 @@ func testGetNodeData(t *testing.T, protocol uint) {
 }
 
 // Tests that the transaction receipts can be retrieved based on hashes.
-func TestGetBlockReceipts65(t *testing.T) { testGetBlockReceipts(t, ETH65) }
 func TestGetBlockReceipts66(t *testing.T) { testGetBlockReceipts(t, ETH66) }
 
 func testGetBlockReceipts(t *testing.T, protocol uint) {
@@ -566,21 +533,14 @@ func testGetBlockReceipts(t *testing.T, protocol uint) {
 		receipts = append(receipts, backend.chain.GetReceiptsByHash(block.Hash()))
 	}
 	// Send the hash request and verify the response
-	if protocol <= ETH65 {
-		p2p.Send(peer.app, GetReceiptsMsg, hashes)
-		if err := p2p.ExpectMsg(peer.app, ReceiptsMsg, receipts); err != nil {
-			t.Errorf("receipts mismatch: %v", err)
-		}
-	} else {
-		p2p.Send(peer.app, GetReceiptsMsg, GetReceiptsPacket66{
-			RequestId:         123,
-			GetReceiptsPacket: hashes,
-		})
-		if err := p2p.ExpectMsg(peer.app, ReceiptsMsg, ReceiptsPacket66{
-			RequestId:      123,
-			ReceiptsPacket: receipts,
-		}); err != nil {
-			t.Errorf("receipts mismatch: %v", err)
-		}
+	p2p.Send(peer.app, GetReceiptsMsg, GetReceiptsPacket66{
+		RequestId:         123,
+		GetReceiptsPacket: hashes,
+	})
+	if err := p2p.ExpectMsg(peer.app, ReceiptsMsg, ReceiptsPacket66{
+		RequestId:      123,
+		ReceiptsPacket: receipts,
+	}); err != nil {
+		t.Errorf("receipts mismatch: %v", err)
 	}
 }
diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go
index d7d993a23deef3e3b17e12f23be1695792ddbb87..e54838cbc56e2c217f089924f8561e31139b25fe 100644
--- a/eth/protocols/eth/handlers.go
+++ b/eth/protocols/eth/handlers.go
@@ -27,17 +27,6 @@ import (
 	"github.com/ethereum/go-ethereum/trie"
 )
 
-// handleGetBlockHeaders handles Block header query, collect the requested headers and reply
-func handleGetBlockHeaders(backend Backend, msg Decoder, peer *Peer) error {
-	// Decode the complex header query
-	var query GetBlockHeadersPacket
-	if err := msg.Decode(&query); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	response := answerGetBlockHeadersQuery(backend, &query, peer)
-	return peer.SendBlockHeaders(response)
-}
-
 // handleGetBlockHeaders66 is the eth/66 version of handleGetBlockHeaders
 func handleGetBlockHeaders66(backend Backend, msg Decoder, peer *Peer) error {
 	// Decode the complex header query
@@ -135,16 +124,6 @@ func answerGetBlockHeadersQuery(backend Backend, query *GetBlockHeadersPacket, p
 	return headers
 }
 
-func handleGetBlockBodies(backend Backend, msg Decoder, peer *Peer) error {
-	// Decode the block body retrieval message
-	var query GetBlockBodiesPacket
-	if err := msg.Decode(&query); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	response := answerGetBlockBodiesQuery(backend, query, peer)
-	return peer.SendBlockBodiesRLP(response)
-}
-
 func handleGetBlockBodies66(backend Backend, msg Decoder, peer *Peer) error {
 	// Decode the block body retrieval message
 	var query GetBlockBodiesPacket66
@@ -174,16 +153,6 @@ func answerGetBlockBodiesQuery(backend Backend, query GetBlockBodiesPacket, peer
 	return bodies
 }
 
-func handleGetNodeData(backend Backend, msg Decoder, peer *Peer) error {
-	// Decode the trie node data retrieval message
-	var query GetNodeDataPacket
-	if err := msg.Decode(&query); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	response := answerGetNodeDataQuery(backend, query, peer)
-	return peer.SendNodeData(response)
-}
-
 func handleGetNodeData66(backend Backend, msg Decoder, peer *Peer) error {
 	// Decode the trie node data retrieval message
 	var query GetNodeDataPacket66
@@ -223,16 +192,6 @@ func answerGetNodeDataQuery(backend Backend, query GetNodeDataPacket, peer *Peer
 	return nodes
 }
 
-func handleGetReceipts(backend Backend, msg Decoder, peer *Peer) error {
-	// Decode the block receipts retrieval message
-	var query GetReceiptsPacket
-	if err := msg.Decode(&query); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	response := answerGetReceiptsQuery(backend, query, peer)
-	return peer.SendReceiptsRLP(response)
-}
-
 func handleGetReceipts66(backend Backend, msg Decoder, peer *Peer) error {
 	// Decode the block receipts retrieval message
 	var query GetReceiptsPacket66
@@ -312,15 +271,6 @@ func handleNewBlock(backend Backend, msg Decoder, peer *Peer) error {
 	return backend.Handle(peer, ann)
 }
 
-func handleBlockHeaders(backend Backend, msg Decoder, peer *Peer) error {
-	// A batch of headers arrived to one of our previous requests
-	res := new(BlockHeadersPacket)
-	if err := msg.Decode(res); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	return backend.Handle(peer, res)
-}
-
 func handleBlockHeaders66(backend Backend, msg Decoder, peer *Peer) error {
 	// A batch of headers arrived to one of our previous requests
 	res := new(BlockHeadersPacket66)
@@ -332,15 +282,6 @@ func handleBlockHeaders66(backend Backend, msg Decoder, peer *Peer) error {
 	return backend.Handle(peer, &res.BlockHeadersPacket)
 }
 
-func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error {
-	// A batch of block bodies arrived to one of our previous requests
-	res := new(BlockBodiesPacket)
-	if err := msg.Decode(res); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	return backend.Handle(peer, res)
-}
-
 func handleBlockBodies66(backend Backend, msg Decoder, peer *Peer) error {
 	// A batch of block bodies arrived to one of our previous requests
 	res := new(BlockBodiesPacket66)
@@ -352,15 +293,6 @@ func handleBlockBodies66(backend Backend, msg Decoder, peer *Peer) error {
 	return backend.Handle(peer, &res.BlockBodiesPacket)
 }
 
-func handleNodeData(backend Backend, msg Decoder, peer *Peer) error {
-	// A batch of node state data arrived to one of our previous requests
-	res := new(NodeDataPacket)
-	if err := msg.Decode(res); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	return backend.Handle(peer, res)
-}
-
 func handleNodeData66(backend Backend, msg Decoder, peer *Peer) error {
 	// A batch of node state data arrived to one of our previous requests
 	res := new(NodeDataPacket66)
@@ -372,15 +304,6 @@ func handleNodeData66(backend Backend, msg Decoder, peer *Peer) error {
 	return backend.Handle(peer, &res.NodeDataPacket)
 }
 
-func handleReceipts(backend Backend, msg Decoder, peer *Peer) error {
-	// A batch of receipts arrived to one of our previous requests
-	res := new(ReceiptsPacket)
-	if err := msg.Decode(res); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	return backend.Handle(peer, res)
-}
-
 func handleReceipts66(backend Backend, msg Decoder, peer *Peer) error {
 	// A batch of receipts arrived to one of our previous requests
 	res := new(ReceiptsPacket66)
@@ -409,16 +332,6 @@ func handleNewPooledTransactionHashes(backend Backend, msg Decoder, peer *Peer)
 	return backend.Handle(peer, ann)
 }
 
-func handleGetPooledTransactions(backend Backend, msg Decoder, peer *Peer) error {
-	// Decode the pooled transactions retrieval message
-	var query GetPooledTransactionsPacket
-	if err := msg.Decode(&query); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	hashes, txs := answerGetPooledTransactions(backend, query, peer)
-	return peer.SendPooledTransactionsRLP(hashes, txs)
-}
-
 func handleGetPooledTransactions66(backend Backend, msg Decoder, peer *Peer) error {
 	// Decode the pooled transactions retrieval message
 	var query GetPooledTransactionsPacket66
@@ -477,26 +390,6 @@ func handleTransactions(backend Backend, msg Decoder, peer *Peer) error {
 	return backend.Handle(peer, &txs)
 }
 
-func handlePooledTransactions(backend Backend, msg Decoder, peer *Peer) error {
-	// Transactions arrived, make sure we have a valid and fresh chain to handle them
-	if !backend.AcceptTxs() {
-		return nil
-	}
-	// Transactions can be processed, parse all of them and deliver to the pool
-	var txs PooledTransactionsPacket
-	if err := msg.Decode(&txs); err != nil {
-		return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
-	}
-	for i, tx := range txs {
-		// Validate and mark the remote transaction
-		if tx == nil {
-			return fmt.Errorf("%w: transaction %d is nil", errDecode, i)
-		}
-		peer.markTransaction(tx.Hash())
-	}
-	return backend.Handle(peer, &txs)
-}
-
 func handlePooledTransactions66(backend Backend, msg Decoder, peer *Peer) error {
 	// Transactions arrived, make sure we have a valid and fresh chain to handle them
 	if !backend.AcceptTxs() {
diff --git a/eth/protocols/eth/handshake_test.go b/eth/protocols/eth/handshake_test.go
index 3bebda2dcc9b9479aaf97f018ced0bc1b13c2a90..05d473e057954c1fb8ef2ade8eea121584cbf175 100644
--- a/eth/protocols/eth/handshake_test.go
+++ b/eth/protocols/eth/handshake_test.go
@@ -27,7 +27,6 @@ import (
 )
 
 // Tests that handshake failures are detected and reported correctly.
-func TestHandshake65(t *testing.T) { testHandshake(t, ETH65) }
 func TestHandshake66(t *testing.T) { testHandshake(t, ETH66) }
 
 func testHandshake(t *testing.T, protocol uint) {
diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go
index e619c183ba2fac51431ac6223803fd1bc5308dfa..98273ccfc9dc5f017652ee419b128607a6625cab 100644
--- a/eth/protocols/eth/peer.go
+++ b/eth/protocols/eth/peer.go
@@ -108,9 +108,8 @@ func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter, txpool TxPool) *Pe
 	// Start up all the broadcasters
 	go peer.broadcastBlocks()
 	go peer.broadcastTransactions()
-	if version >= ETH65 {
-		go peer.announceTransactions()
-	}
+	go peer.announceTransactions()
+
 	return peer
 }
 
@@ -252,22 +251,6 @@ func (p *Peer) AsyncSendPooledTransactionHashes(hashes []common.Hash) {
 	}
 }
 
-// SendPooledTransactionsRLP sends requested transactions to the peer and adds the
-// hashes in its transaction hash set for future reference.
-//
-// Note, the method assumes the hashes are correct and correspond to the list of
-// transactions being sent.
-func (p *Peer) SendPooledTransactionsRLP(hashes []common.Hash, txs []rlp.RawValue) error {
-	// Mark all the transactions as known, but ensure we don't overflow our limits
-	for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) {
-		p.knownTxs.Pop()
-	}
-	for _, hash := range hashes {
-		p.knownTxs.Add(hash)
-	}
-	return p2p.Send(p.rw, PooledTransactionsMsg, txs) // Not packed into PooledTransactionsPacket to avoid RLP decoding
-}
-
 // ReplyPooledTransactionsRLP is the eth/66 version of SendPooledTransactionsRLP.
 func (p *Peer) ReplyPooledTransactionsRLP(id uint64, hashes []common.Hash, txs []rlp.RawValue) error {
 	// Mark all the transactions as known, but ensure we don't overflow our limits
@@ -346,11 +329,6 @@ func (p *Peer) AsyncSendNewBlock(block *types.Block, td *big.Int) {
 	}
 }
 
-// SendBlockHeaders sends a batch of block headers to the remote peer.
-func (p *Peer) SendBlockHeaders(headers []*types.Header) error {
-	return p2p.Send(p.rw, BlockHeadersMsg, BlockHeadersPacket(headers))
-}
-
 // ReplyBlockHeaders is the eth/66 version of SendBlockHeaders.
 func (p *Peer) ReplyBlockHeaders(id uint64, headers []*types.Header) error {
 	return p2p.Send(p.rw, BlockHeadersMsg, BlockHeadersPacket66{
@@ -359,12 +337,6 @@ func (p *Peer) ReplyBlockHeaders(id uint64, headers []*types.Header) error {
 	})
 }
 
-// SendBlockBodiesRLP sends a batch of block contents to the remote peer from
-// an already RLP encoded format.
-func (p *Peer) SendBlockBodiesRLP(bodies []rlp.RawValue) error {
-	return p2p.Send(p.rw, BlockBodiesMsg, bodies) // Not packed into BlockBodiesPacket to avoid RLP decoding
-}
-
 // ReplyBlockBodiesRLP is the eth/66 version of SendBlockBodiesRLP.
 func (p *Peer) ReplyBlockBodiesRLP(id uint64, bodies []rlp.RawValue) error {
 	// Not packed into BlockBodiesPacket to avoid RLP decoding
@@ -374,12 +346,6 @@ func (p *Peer) ReplyBlockBodiesRLP(id uint64, bodies []rlp.RawValue) error {
 	})
 }
 
-// SendNodeDataRLP sends a batch of arbitrary internal data, corresponding to the
-// hashes requested.
-func (p *Peer) SendNodeData(data [][]byte) error {
-	return p2p.Send(p.rw, NodeDataMsg, NodeDataPacket(data))
-}
-
 // ReplyNodeData is the eth/66 response to GetNodeData.
 func (p *Peer) ReplyNodeData(id uint64, data [][]byte) error {
 	return p2p.Send(p.rw, NodeDataMsg, NodeDataPacket66{
@@ -388,12 +354,6 @@ func (p *Peer) ReplyNodeData(id uint64, data [][]byte) error {
 	})
 }
 
-// SendReceiptsRLP sends a batch of transaction receipts, corresponding to the
-// ones requested from an already RLP encoded format.
-func (p *Peer) SendReceiptsRLP(receipts []rlp.RawValue) error {
-	return p2p.Send(p.rw, ReceiptsMsg, receipts) // Not packed into ReceiptsPacket to avoid RLP decoding
-}
-
 // ReplyReceiptsRLP is the eth/66 response to GetReceipts.
 func (p *Peer) ReplyReceiptsRLP(id uint64, receipts []rlp.RawValue) error {
 	return p2p.Send(p.rw, ReceiptsMsg, ReceiptsRLPPacket66{
@@ -406,138 +366,102 @@ func (p *Peer) ReplyReceiptsRLP(id uint64, receipts []rlp.RawValue) error {
 // single header. It is used solely by the fetcher.
 func (p *Peer) RequestOneHeader(hash common.Hash) error {
 	p.Log().Debug("Fetching single header", "hash", hash)
-	query := GetBlockHeadersPacket{
-		Origin:  HashOrNumber{Hash: hash},
-		Amount:  uint64(1),
-		Skip:    uint64(0),
-		Reverse: false,
-	}
-	if p.Version() >= ETH66 {
-		id := rand.Uint64()
-
-		requestTracker.Track(p.id, p.version, GetBlockHeadersMsg, BlockHeadersMsg, id)
-		return p2p.Send(p.rw, GetBlockHeadersMsg, &GetBlockHeadersPacket66{
-			RequestId:             id,
-			GetBlockHeadersPacket: &query,
-		})
-	}
-	return p2p.Send(p.rw, GetBlockHeadersMsg, &query)
+	id := rand.Uint64()
+
+	requestTracker.Track(p.id, p.version, GetBlockHeadersMsg, BlockHeadersMsg, id)
+	return p2p.Send(p.rw, GetBlockHeadersMsg, &GetBlockHeadersPacket66{
+		RequestId: id,
+		GetBlockHeadersPacket: &GetBlockHeadersPacket{
+			Origin:  HashOrNumber{Hash: hash},
+			Amount:  uint64(1),
+			Skip:    uint64(0),
+			Reverse: false,
+		},
+	})
 }
 
 // RequestHeadersByHash fetches a batch of blocks' headers corresponding to the
 // specified header query, based on the hash of an origin block.
 func (p *Peer) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error {
 	p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse)
-	query := GetBlockHeadersPacket{
-		Origin:  HashOrNumber{Hash: origin},
-		Amount:  uint64(amount),
-		Skip:    uint64(skip),
-		Reverse: reverse,
-	}
-	if p.Version() >= ETH66 {
-		id := rand.Uint64()
-
-		requestTracker.Track(p.id, p.version, GetBlockHeadersMsg, BlockHeadersMsg, id)
-		return p2p.Send(p.rw, GetBlockHeadersMsg, &GetBlockHeadersPacket66{
-			RequestId:             id,
-			GetBlockHeadersPacket: &query,
-		})
-	}
-	return p2p.Send(p.rw, GetBlockHeadersMsg, &query)
+	id := rand.Uint64()
+
+	requestTracker.Track(p.id, p.version, GetBlockHeadersMsg, BlockHeadersMsg, id)
+	return p2p.Send(p.rw, GetBlockHeadersMsg, &GetBlockHeadersPacket66{
+		RequestId: id,
+		GetBlockHeadersPacket: &GetBlockHeadersPacket{
+			Origin:  HashOrNumber{Hash: origin},
+			Amount:  uint64(amount),
+			Skip:    uint64(skip),
+			Reverse: reverse,
+		},
+	})
 }
 
 // RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the
 // specified header query, based on the number of an origin block.
 func (p *Peer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error {
 	p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse)
-	query := GetBlockHeadersPacket{
-		Origin:  HashOrNumber{Number: origin},
-		Amount:  uint64(amount),
-		Skip:    uint64(skip),
-		Reverse: reverse,
-	}
-	if p.Version() >= ETH66 {
-		id := rand.Uint64()
-
-		requestTracker.Track(p.id, p.version, GetBlockHeadersMsg, BlockHeadersMsg, id)
-		return p2p.Send(p.rw, GetBlockHeadersMsg, &GetBlockHeadersPacket66{
-			RequestId:             id,
-			GetBlockHeadersPacket: &query,
-		})
-	}
-	return p2p.Send(p.rw, GetBlockHeadersMsg, &query)
-}
-
-// ExpectRequestHeadersByNumber is a testing method to mirror the recipient side
-// of the RequestHeadersByNumber operation.
-func (p *Peer) ExpectRequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error {
-	req := &GetBlockHeadersPacket{
-		Origin:  HashOrNumber{Number: origin},
-		Amount:  uint64(amount),
-		Skip:    uint64(skip),
-		Reverse: reverse,
-	}
-	return p2p.ExpectMsg(p.rw, GetBlockHeadersMsg, req)
+	id := rand.Uint64()
+
+	requestTracker.Track(p.id, p.version, GetBlockHeadersMsg, BlockHeadersMsg, id)
+	return p2p.Send(p.rw, GetBlockHeadersMsg, &GetBlockHeadersPacket66{
+		RequestId: id,
+		GetBlockHeadersPacket: &GetBlockHeadersPacket{
+			Origin:  HashOrNumber{Number: origin},
+			Amount:  uint64(amount),
+			Skip:    uint64(skip),
+			Reverse: reverse,
+		},
+	})
 }
 
 // RequestBodies fetches a batch of blocks' bodies corresponding to the hashes
 // specified.
 func (p *Peer) RequestBodies(hashes []common.Hash) error {
 	p.Log().Debug("Fetching batch of block bodies", "count", len(hashes))
-	if p.Version() >= ETH66 {
-		id := rand.Uint64()
-
-		requestTracker.Track(p.id, p.version, GetBlockBodiesMsg, BlockBodiesMsg, id)
-		return p2p.Send(p.rw, GetBlockBodiesMsg, &GetBlockBodiesPacket66{
-			RequestId:            id,
-			GetBlockBodiesPacket: hashes,
-		})
-	}
-	return p2p.Send(p.rw, GetBlockBodiesMsg, GetBlockBodiesPacket(hashes))
+	id := rand.Uint64()
+
+	requestTracker.Track(p.id, p.version, GetBlockBodiesMsg, BlockBodiesMsg, id)
+	return p2p.Send(p.rw, GetBlockBodiesMsg, &GetBlockBodiesPacket66{
+		RequestId:            id,
+		GetBlockBodiesPacket: hashes,
+	})
 }
 
 // RequestNodeData fetches a batch of arbitrary data from a node's known state
 // data, corresponding to the specified hashes.
 func (p *Peer) RequestNodeData(hashes []common.Hash) error {
 	p.Log().Debug("Fetching batch of state data", "count", len(hashes))
-	if p.Version() >= ETH66 {
-		id := rand.Uint64()
-
-		requestTracker.Track(p.id, p.version, GetNodeDataMsg, NodeDataMsg, id)
-		return p2p.Send(p.rw, GetNodeDataMsg, &GetNodeDataPacket66{
-			RequestId:         id,
-			GetNodeDataPacket: hashes,
-		})
-	}
-	return p2p.Send(p.rw, GetNodeDataMsg, GetNodeDataPacket(hashes))
+	id := rand.Uint64()
+
+	requestTracker.Track(p.id, p.version, GetNodeDataMsg, NodeDataMsg, id)
+	return p2p.Send(p.rw, GetNodeDataMsg, &GetNodeDataPacket66{
+		RequestId:         id,
+		GetNodeDataPacket: hashes,
+	})
 }
 
 // RequestReceipts fetches a batch of transaction receipts from a remote node.
 func (p *Peer) RequestReceipts(hashes []common.Hash) error {
 	p.Log().Debug("Fetching batch of receipts", "count", len(hashes))
-	if p.Version() >= ETH66 {
-		id := rand.Uint64()
-
-		requestTracker.Track(p.id, p.version, GetReceiptsMsg, ReceiptsMsg, id)
-		return p2p.Send(p.rw, GetReceiptsMsg, &GetReceiptsPacket66{
-			RequestId:         id,
-			GetReceiptsPacket: hashes,
-		})
-	}
-	return p2p.Send(p.rw, GetReceiptsMsg, GetReceiptsPacket(hashes))
+	id := rand.Uint64()
+
+	requestTracker.Track(p.id, p.version, GetReceiptsMsg, ReceiptsMsg, id)
+	return p2p.Send(p.rw, GetReceiptsMsg, &GetReceiptsPacket66{
+		RequestId:         id,
+		GetReceiptsPacket: hashes,
+	})
 }
 
 // RequestTxs fetches a batch of transactions from a remote node.
 func (p *Peer) RequestTxs(hashes []common.Hash) error {
 	p.Log().Debug("Fetching batch of transactions", "count", len(hashes))
-	if p.Version() >= ETH66 {
-		id := rand.Uint64()
-
-		requestTracker.Track(p.id, p.version, GetPooledTransactionsMsg, PooledTransactionsMsg, id)
-		return p2p.Send(p.rw, GetPooledTransactionsMsg, &GetPooledTransactionsPacket66{
-			RequestId:                   id,
-			GetPooledTransactionsPacket: hashes,
-		})
-	}
-	return p2p.Send(p.rw, GetPooledTransactionsMsg, GetPooledTransactionsPacket(hashes))
+	id := rand.Uint64()
+
+	requestTracker.Track(p.id, p.version, GetPooledTransactionsMsg, PooledTransactionsMsg, id)
+	return p2p.Send(p.rw, GetPooledTransactionsMsg, &GetPooledTransactionsPacket66{
+		RequestId:                   id,
+		GetPooledTransactionsPacket: hashes,
+	})
 }
diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go
index de1b0ed1ee7f2cbd773e1ed1d3ac233fadc527c8..3c3da30fa50310309ff964401b56543331b28aca 100644
--- a/eth/protocols/eth/protocol.go
+++ b/eth/protocols/eth/protocol.go
@@ -30,7 +30,6 @@ import (
 
 // Constants to match up protocol versions and messages
 const (
-	ETH65 = 65
 	ETH66 = 66
 )
 
@@ -40,31 +39,28 @@ const ProtocolName = "eth"
 
 // ProtocolVersions are the supported versions of the `eth` protocol (first
 // is primary).
-var ProtocolVersions = []uint{ETH66, ETH65}
+var ProtocolVersions = []uint{ETH66}
 
 // protocolLengths are the number of implemented message corresponding to
 // different protocol versions.
-var protocolLengths = map[uint]uint64{ETH66: 17, ETH65: 17}
+var protocolLengths = map[uint]uint64{ETH66: 17}
 
 // maxMessageSize is the maximum cap on the size of a protocol message.
 const maxMessageSize = 10 * 1024 * 1024
 
 const (
-	// Protocol messages in eth/64
-	StatusMsg          = 0x00
-	NewBlockHashesMsg  = 0x01
-	TransactionsMsg    = 0x02
-	GetBlockHeadersMsg = 0x03
-	BlockHeadersMsg    = 0x04
-	GetBlockBodiesMsg  = 0x05
-	BlockBodiesMsg     = 0x06
-	NewBlockMsg        = 0x07
-	GetNodeDataMsg     = 0x0d
-	NodeDataMsg        = 0x0e
-	GetReceiptsMsg     = 0x0f
-	ReceiptsMsg        = 0x10
-
-	// Protocol messages overloaded in eth/65
+	StatusMsg                     = 0x00
+	NewBlockHashesMsg             = 0x01
+	TransactionsMsg               = 0x02
+	GetBlockHeadersMsg            = 0x03
+	BlockHeadersMsg               = 0x04
+	GetBlockBodiesMsg             = 0x05
+	BlockBodiesMsg                = 0x06
+	NewBlockMsg                   = 0x07
+	GetNodeDataMsg                = 0x0d
+	NodeDataMsg                   = 0x0e
+	GetReceiptsMsg                = 0x0f
+	ReceiptsMsg                   = 0x10
 	NewPooledTransactionHashesMsg = 0x08
 	GetPooledTransactionsMsg      = 0x09
 	PooledTransactionsMsg         = 0x0a
@@ -128,7 +124,7 @@ type GetBlockHeadersPacket struct {
 	Reverse bool         // Query direction (false = rising towards latest, true = falling towards genesis)
 }
 
-// GetBlockHeadersPacket represents a block header query over eth/66
+// GetBlockHeadersPacket66 represents a block header query over eth/66
 type GetBlockHeadersPacket66 struct {
 	RequestId uint64
 	*GetBlockHeadersPacket
diff --git a/eth/sync.go b/eth/sync.go
index ab114b59f3e1fa21a1f8a29b0d90fd67c12f1652..27941158f3dffdf3bfeef9bf59da62d348608db7 100644
--- a/eth/sync.go
+++ b/eth/sync.go
@@ -18,7 +18,6 @@ package eth
 
 import (
 	"math/big"
-	"math/rand"
 	"sync/atomic"
 	"time"
 
@@ -28,23 +27,13 @@ import (
 	"github.com/ethereum/go-ethereum/eth/downloader"
 	"github.com/ethereum/go-ethereum/eth/protocols/eth"
 	"github.com/ethereum/go-ethereum/log"
-	"github.com/ethereum/go-ethereum/p2p/enode"
 )
 
 const (
 	forceSyncCycle      = 10 * time.Second // Time interval to force syncs, even if few peers are available
 	defaultMinSyncPeers = 5                // Amount of peers desired to start syncing
-
-	// This is the target size for the packs of transactions sent by txsyncLoop64.
-	// A pack can get larger than this if a single transactions exceeds this size.
-	txsyncPackSize = 100 * 1024
 )
 
-type txsync struct {
-	p   *eth.Peer
-	txs []*types.Transaction
-}
-
 // syncTransactions starts sending all currently pending transactions to the given peer.
 func (h *handler) syncTransactions(p *eth.Peer) {
 	// Assemble the set of transaction to broadcast or announce to the remote
@@ -64,94 +53,11 @@ func (h *handler) syncTransactions(p *eth.Peer) {
 	// The eth/65 protocol introduces proper transaction announcements, so instead
 	// of dripping transactions across multiple peers, just send the entire list as
 	// an announcement and let the remote side decide what they need (likely nothing).
-	if p.Version() >= eth.ETH65 {
-		hashes := make([]common.Hash, len(txs))
-		for i, tx := range txs {
-			hashes[i] = tx.Hash()
-		}
-		p.AsyncSendPooledTransactionHashes(hashes)
-		return
-	}
-	// Out of luck, peer is running legacy protocols, drop the txs over
-	select {
-	case h.txsyncCh <- &txsync{p: p, txs: txs}:
-	case <-h.quitSync:
-	}
-}
-
-// txsyncLoop64 takes care of the initial transaction sync for each new
-// connection. When a new peer appears, we relay all currently pending
-// transactions. In order to minimise egress bandwidth usage, we send
-// the transactions in small packs to one peer at a time.
-func (h *handler) txsyncLoop64() {
-	defer h.wg.Done()
-
-	var (
-		pending = make(map[enode.ID]*txsync)
-		sending = false               // whether a send is active
-		pack    = new(txsync)         // the pack that is being sent
-		done    = make(chan error, 1) // result of the send
-	)
-
-	// send starts a sending a pack of transactions from the sync.
-	send := func(s *txsync) {
-		if s.p.Version() >= eth.ETH65 {
-			panic("initial transaction syncer running on eth/65+")
-		}
-		// Fill pack with transactions up to the target size.
-		size := common.StorageSize(0)
-		pack.p = s.p
-		pack.txs = pack.txs[:0]
-		for i := 0; i < len(s.txs) && size < txsyncPackSize; i++ {
-			pack.txs = append(pack.txs, s.txs[i])
-			size += s.txs[i].Size()
-		}
-		// Remove the transactions that will be sent.
-		s.txs = s.txs[:copy(s.txs, s.txs[len(pack.txs):])]
-		if len(s.txs) == 0 {
-			delete(pending, s.p.Peer.ID())
-		}
-		// Send the pack in the background.
-		s.p.Log().Trace("Sending batch of transactions", "count", len(pack.txs), "bytes", size)
-		sending = true
-		go func() { done <- pack.p.SendTransactions(pack.txs) }()
-	}
-	// pick chooses the next pending sync.
-	pick := func() *txsync {
-		if len(pending) == 0 {
-			return nil
-		}
-		n := rand.Intn(len(pending)) + 1
-		for _, s := range pending {
-			if n--; n == 0 {
-				return s
-			}
-		}
-		return nil
-	}
-
-	for {
-		select {
-		case s := <-h.txsyncCh:
-			pending[s.p.Peer.ID()] = s
-			if !sending {
-				send(s)
-			}
-		case err := <-done:
-			sending = false
-			// Stop tracking peers that cause send failures.
-			if err != nil {
-				pack.p.Log().Debug("Transaction send failed", "err", err)
-				delete(pending, pack.p.Peer.ID())
-			}
-			// Schedule the next send.
-			if s := pick(); s != nil {
-				send(s)
-			}
-		case <-h.quitSync:
-			return
-		}
+	hashes := make([]common.Hash, len(txs))
+	for i, tx := range txs {
+		hashes[i] = tx.Hash()
 	}
+	p.AsyncSendPooledTransactionHashes(hashes)
 }
 
 // chainSyncer coordinates blockchain sync components.
diff --git a/eth/sync_test.go b/eth/sync_test.go
index a0c6f8602327e6820d2b850ec30e747b0ccec4e4..e96b9ee81f6911e53b174201be42f8349052f847 100644
--- a/eth/sync_test.go
+++ b/eth/sync_test.go
@@ -28,7 +28,6 @@ import (
 )
 
 // Tests that fast sync is disabled after a successful sync cycle.
-func TestFastSyncDisabling65(t *testing.T) { testFastSyncDisabling(t, eth.ETH65) }
 func TestFastSyncDisabling66(t *testing.T) { testFastSyncDisabling(t, eth.ETH66) }
 
 // Tests that fast sync gets disabled as soon as a real block is successfully
diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go
index 5d19cc3577de402b5305f58932ab388e71786da2..9ff1a2ce1d68495dd9ad43ec9089042d9c738500 100644
--- a/ethdb/leveldb/leveldb.go
+++ b/ethdb/leveldb/leveldb.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build !js
 // +build !js
 
 // Package leveldb implements the key-value database layer based on LevelDB.
diff --git a/go.mod b/go.mod
index ecc1a957fea9a330048e08e6b6144811a909ddeb..56b0a97fd63b765562366671c8fca1abb31d1162 100644
--- a/go.mod
+++ b/go.mod
@@ -30,7 +30,7 @@ require (
 	github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
 	github.com/go-stack/stack v1.8.0
 	github.com/golang/protobuf v1.4.3
-	github.com/golang/snappy v0.0.3
+	github.com/golang/snappy v0.0.4
 	github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa
 	github.com/google/uuid v1.1.5
 	github.com/gorilla/websocket v1.4.2
@@ -59,7 +59,7 @@ require (
 	github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
 	github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
 	github.com/stretchr/testify v1.7.0
-	github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954
+	github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
 	github.com/tklauser/go-sysconf v0.3.5 // indirect
 	github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
 	github.com/xsleonard/go-merkle v1.1.0
diff --git a/go.sum b/go.sum
index fa1f86c9f4b8e58e3169c82e5ba8313bf2e807b8..bf559c27081432c6995b1b9111c055daea09c450 100644
--- a/go.sum
+++ b/go.sum
@@ -185,9 +185,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
 github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -390,8 +390,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
-github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
+github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
+github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
 github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
 github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4=
 github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
diff --git a/internal/debug/loudpanic.go b/internal/debug/loudpanic.go
index 572ebcefa14f5d366fe8242aca8a4e40f4efa8ad..86e6bc88f83f2df82e60975aa967c29674614121 100644
--- a/internal/debug/loudpanic.go
+++ b/internal/debug/loudpanic.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build go1.6
 // +build go1.6
 
 package debug
diff --git a/internal/debug/loudpanic_fallback.go b/internal/debug/loudpanic_fallback.go
index 4ce4985da7c9abd09150e6a122dc6c1083f85dfa..377490e5bee571fa18bd97e8bb9502a42990fe46 100644
--- a/internal/debug/loudpanic_fallback.go
+++ b/internal/debug/loudpanic_fallback.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build !go1.6
 // +build !go1.6
 
 package debug
diff --git a/internal/debug/trace.go b/internal/debug/trace.go
index cab5deaafd6cd32b8963c41ed7f18218eadaca8f..a273e4a9db84bf26f5b26be7fed9edc562035fca 100644
--- a/internal/debug/trace.go
+++ b/internal/debug/trace.go
@@ -14,7 +14,8 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-//+build go1.5
+//go:build go1.5
+// +build go1.5
 
 package debug
 
diff --git a/internal/debug/trace_fallback.go b/internal/debug/trace_fallback.go
index 4118ff4087ee63aff133f88f99cf222343235ed7..ec07d991efd62d43a0164d9a0c26723c4d7cb0e0 100644
--- a/internal/debug/trace_fallback.go
+++ b/internal/debug/trace_fallback.go
@@ -14,7 +14,8 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-//+build !go1.5
+//go:build !go1.5
+// +build !go1.5
 
 // no-op implementation of tracing methods for Go < 1.5.
 
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index 0c4e0170160823dddaf2605e75d0b68e37090db3..1587c5dc29fd2967e781208020ddcf3accc19d96 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -32,7 +32,6 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/common/math"
-	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/consensus/clique"
 	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/consensus/misc"
@@ -1264,8 +1263,7 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes {
 }
 
 // RPCMarshalHeader converts the given header to the RPC output .
-func RPCMarshalHeader(head *types.Header, engine consensus.Engine) map[string]interface{} {
-	miner, _ := engine.Author(head)
+func RPCMarshalHeader(head *types.Header) map[string]interface{} {
 	result := map[string]interface{}{
 		"number":           (*hexutil.Big)(head.Number),
 		"hash":             head.Hash(),
@@ -1275,7 +1273,7 @@ func RPCMarshalHeader(head *types.Header, engine consensus.Engine) map[string]in
 		"sha3Uncles":       head.UncleHash,
 		"logsBloom":        head.Bloom,
 		"stateRoot":        head.Root,
-		"miner":            miner,
+		"miner":            head.Coinbase,
 		"difficulty":       (*hexutil.Big)(head.Difficulty),
 		"extraData":        hexutil.Bytes(head.Extra),
 		"size":             hexutil.Uint64(head.Size()),
@@ -1296,8 +1294,8 @@ func RPCMarshalHeader(head *types.Header, engine consensus.Engine) map[string]in
 // RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
 // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
 // transaction hashes.
-func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, engine consensus.Engine) (map[string]interface{}, error) {
-	fields := RPCMarshalHeader(block.Header(), engine)
+func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
+	fields := RPCMarshalHeader(block.Header())
 	fields["size"] = hexutil.Uint64(block.Size())
 
 	if inclTx {
@@ -1332,7 +1330,7 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, engine consen
 // rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires
 // a `PublicBlockchainAPI`.
 func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} {
-	fields := RPCMarshalHeader(header, s.b.Engine())
+	fields := RPCMarshalHeader(header)
 	fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash()))
 	return fields
 }
@@ -1340,7 +1338,7 @@ func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *type
 // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires
 // a `PublicBlockchainAPI`.
 func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
-	fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.Engine())
+	fields, err := RPCMarshalBlock(b, inclTx, fullTx)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go
index 52811b2a9a216ab50851bbf5b4281b22ba0413ed..2d08d3008f38211e67d6bb44551f291503df03eb 100644
--- a/internal/ethapi/transaction_args.go
+++ b/internal/ethapi/transaction_args.go
@@ -146,6 +146,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
 	if args.Gas == nil {
 		// These fields are immutable during the estimation, safe to
 		// pass the pointer directly.
+		data := args.data()
 		callArgs := TransactionArgs{
 			From:                 args.From,
 			To:                   args.To,
@@ -153,7 +154,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
 			MaxFeePerGas:         args.MaxFeePerGas,
 			MaxPriorityFeePerGas: args.MaxPriorityFeePerGas,
 			Value:                args.Value,
-			Data:                 args.Data,
+			Data:                 (*hexutil.Bytes)(&data),
 			AccessList:           args.AccessList,
 		}
 		pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
diff --git a/les/client_handler.go b/les/client_handler.go
index e95996c51f6f65ccd8fd693c6c8c91e536ede468..4a550b20745c4466619ea47b70b11af279026ba1 100644
--- a/les/client_handler.go
+++ b/les/client_handler.go
@@ -100,11 +100,11 @@ func (h *clientHandler) runPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter)
 	defer peer.close()
 	h.wg.Add(1)
 	defer h.wg.Done()
-	err := h.handle(peer)
+	err := h.handle(peer, false)
 	return err
 }
 
-func (h *clientHandler) handle(p *serverPeer) error {
+func (h *clientHandler) handle(p *serverPeer, noInitAnnounce bool) error {
 	if h.backend.peers.len() >= h.backend.config.LightPeers && !p.Peer.Info().Network.Trusted {
 		return p2p.DiscTooManyPeers
 	}
@@ -143,8 +143,11 @@ func (h *clientHandler) handle(p *serverPeer) error {
 		connectionTimer.Update(time.Duration(mclock.Now() - connectedAt))
 		serverConnectionGauge.Update(int64(h.backend.peers.len()))
 	}()
-	h.fetcher.announce(p, &announceData{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td})
-
+	// It's mainly used in testing which requires discarding initial
+	// signal to prevent syncing.
+	if !noInitAnnounce {
+		h.fetcher.announce(p, &announceData{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td})
+	}
 	// Mark the peer starts to be served.
 	atomic.StoreUint32(&p.serving, 1)
 	defer atomic.StoreUint32(&p.serving, 0)
@@ -472,7 +475,7 @@ func (d *downloaderPeerNotify) registerPeer(p *serverPeer) {
 		handler: h,
 		peer:    p,
 	}
-	h.downloader.RegisterLightPeer(p.id, eth.ETH65, pc)
+	h.downloader.RegisterLightPeer(p.id, eth.ETH66, pc)
 }
 
 func (d *downloaderPeerNotify) unregisterPeer(p *serverPeer) {
diff --git a/les/fetcher.go b/les/fetcher.go
index a6d1c93c4b712a0b1f81a7300e5d95f59d359368..5eea9967487454923bcb760795b735002970182a 100644
--- a/les/fetcher.go
+++ b/les/fetcher.go
@@ -153,9 +153,7 @@ type lightFetcher struct {
 	synchronise func(peer *serverPeer)
 
 	// Test fields or hooks
-	noAnnounce  bool
 	newHeadHook func(*types.Header)
-	newAnnounce func(*serverPeer, *announceData)
 }
 
 // newLightFetcher creates a light fetcher instance.
@@ -474,12 +472,6 @@ func (f *lightFetcher) mainloop() {
 
 // announce processes a new announcement message received from a peer.
 func (f *lightFetcher) announce(p *serverPeer, head *announceData) {
-	if f.newAnnounce != nil {
-		f.newAnnounce(p, head)
-	}
-	if f.noAnnounce {
-		return
-	}
 	select {
 	case f.announceCh <- &announce{peerid: p.ID(), trust: p.trusted, data: head}:
 	case <-f.closeCh:
diff --git a/les/fetcher_test.go b/les/fetcher_test.go
index d3a74d25c287be8a51ccd39e1d363c2812268eef..ef700651e3bf02572a197bbef6011fe20c2e8921 100644
--- a/les/fetcher_test.go
+++ b/les/fetcher_test.go
@@ -74,14 +74,12 @@ func testSequentialAnnouncements(t *testing.T, protocol int) {
 	s, c, teardown := newClientServerEnv(t, netconfig)
 	defer teardown()
 
-	// Create connected peer pair.
-	c.handler.fetcher.noAnnounce = true // Ignore the first announce from peer which can trigger a resync.
-	p1, _, err := newTestPeerPair("peer", protocol, s.handler, c.handler)
+	// Create connected peer pair, the initial signal from LES server
+	// is discarded to prevent syncing.
+	p1, _, err := newTestPeerPair("peer", protocol, s.handler, c.handler, true)
 	if err != nil {
 		t.Fatalf("Failed to create peer pair %v", err)
 	}
-	c.handler.fetcher.noAnnounce = false
-
 	importCh := make(chan interface{})
 	c.handler.fetcher.newHeadHook = func(header *types.Header) {
 		importCh <- header
@@ -114,14 +112,12 @@ func testGappedAnnouncements(t *testing.T, protocol int) {
 	s, c, teardown := newClientServerEnv(t, netconfig)
 	defer teardown()
 
-	// Create connected peer pair.
-	c.handler.fetcher.noAnnounce = true // Ignore the first announce from peer which can trigger a resync.
-	peer, _, err := newTestPeerPair("peer", protocol, s.handler, c.handler)
+	// Create connected peer pair, the initial signal from LES server
+	// is discarded to prevent syncing.
+	peer, _, err := newTestPeerPair("peer", protocol, s.handler, c.handler, true)
 	if err != nil {
 		t.Fatalf("Failed to create peer pair %v", err)
 	}
-	c.handler.fetcher.noAnnounce = false
-
 	done := make(chan *types.Header, 1)
 	c.handler.fetcher.newHeadHook = func(header *types.Header) { done <- header }
 
@@ -141,29 +137,11 @@ func testGappedAnnouncements(t *testing.T, protocol int) {
 	verifyChainHeight(t, c.handler.fetcher, 4)
 
 	// Send a reorged announcement
-	var newAnno = make(chan struct{}, 1)
-	c.handler.fetcher.noAnnounce = true
-	c.handler.fetcher.newAnnounce = func(*serverPeer, *announceData) {
-		newAnno <- struct{}{}
-	}
 	blocks, _ := core.GenerateChain(rawdb.ReadChainConfig(s.db, s.backend.Blockchain().Genesis().Hash()), s.backend.Blockchain().GetBlockByNumber(3),
 		ethash.NewFaker(), s.db, 2, func(i int, gen *core.BlockGen) {
 			gen.OffsetTime(-9) // higher block difficulty
 		})
 	s.backend.Blockchain().InsertChain(blocks)
-	<-newAnno
-	c.handler.fetcher.noAnnounce = false
-	c.handler.fetcher.newAnnounce = nil
-
-	latest = blocks[len(blocks)-1].Header()
-	hash, number = latest.Hash(), latest.Number.Uint64()
-	td = rawdb.ReadTd(s.db, hash, number)
-
-	announce = announceData{hash, number, td, 1, nil}
-	if peer.cpeer.announceType == announceTypeSigned {
-		announce.sign(s.handler.server.privateKey)
-	}
-	peer.cpeer.sendAnnounce(announce)
 
 	<-done // Wait syncing
 	verifyChainHeight(t, c.handler.fetcher, 5)
@@ -206,20 +184,15 @@ func testTrustedAnnouncement(t *testing.T, protocol int) {
 			teardowns[i]()
 		}
 	}()
-
-	c.handler.fetcher.noAnnounce = true // Ignore the first announce from peer which can trigger a resync.
-
 	// Connect all server instances.
 	for i := 0; i < len(servers); i++ {
-		sp, cp, err := connect(servers[i].handler, nodes[i].ID(), c.handler, protocol)
+		sp, cp, err := connect(servers[i].handler, nodes[i].ID(), c.handler, protocol, true)
 		if err != nil {
 			t.Fatalf("connect server and client failed, err %s", err)
 		}
 		cpeers = append(cpeers, cp)
 		speers = append(speers, sp)
 	}
-	c.handler.fetcher.noAnnounce = false
-
 	newHead := make(chan *types.Header, 1)
 	c.handler.fetcher.newHeadHook = func(header *types.Header) { newHead <- header }
 
@@ -262,14 +235,12 @@ func testInvalidAnnounces(t *testing.T, protocol int) {
 	s, c, teardown := newClientServerEnv(t, netconfig)
 	defer teardown()
 
-	// Create connected peer pair.
-	c.handler.fetcher.noAnnounce = true // Ignore the first announce from peer which can trigger a resync.
-	peer, _, err := newTestPeerPair("peer", lpv3, s.handler, c.handler)
+	// Create connected peer pair, the initial signal from LES server
+	// is discarded to prevent syncing.
+	peer, _, err := newTestPeerPair("peer", lpv3, s.handler, c.handler, true)
 	if err != nil {
 		t.Fatalf("Failed to create peer pair %v", err)
 	}
-	c.handler.fetcher.noAnnounce = false
-
 	done := make(chan *types.Header, 1)
 	c.handler.fetcher.newHeadHook = func(header *types.Header) { done <- header }
 
diff --git a/les/odr_test.go b/les/odr_test.go
index ea88495d198d258eb0ff582533589159859386ab..ad77abf5b9b28b5d1ce624a4a32e57d50248fc4c 100644
--- a/les/odr_test.go
+++ b/les/odr_test.go
@@ -401,9 +401,9 @@ func testGetTxStatusFromUnindexedPeers(t *testing.T, protocol int) {
 			closeFns = append(closeFns, closePeer)
 
 			// Create a one-time routine for serving message
-			go func(i int, peer *testPeer) {
-				serveMsg(peer, testspec.txLookups[i])
-			}(i, peer)
+			go func(i int, peer *testPeer, lookup uint64) {
+				serveMsg(peer, lookup)
+			}(i, peer, testspec.txLookups[i])
 		}
 
 		// Send out the GetTxStatus requests, compare the result with
diff --git a/les/pruner.go b/les/pruner.go
index 622e648688ee46e81a1225bfc41822f5d5619dc3..a1bd51d86c5d6f2b7cf3b1c4e6299757df4f1cfc 100644
--- a/les/pruner.go
+++ b/les/pruner.go
@@ -62,6 +62,7 @@ func (p *pruner) loop() {
 
 	// cleanTicker is the ticker used to trigger a history clean 2 times a day.
 	var cleanTicker = time.NewTicker(12 * time.Hour)
+	defer cleanTicker.Stop()
 
 	// pruning finds the sections that have been processed by all indexers
 	// and deletes all historical chain data.
diff --git a/les/server_handler.go b/les/server_handler.go
index 80fcf1c44e168f88bced0f4375d7e5520af54ecc..fa20fd7b3b51b87c75752db845e24a6c0d68485c 100644
--- a/les/server_handler.go
+++ b/les/server_handler.go
@@ -28,7 +28,6 @@ import (
 	"github.com/ethereum/go-ethereum/core/forkid"
 	"github.com/ethereum/go-ethereum/core/rawdb"
 	"github.com/ethereum/go-ethereum/core/state"
-	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/les/flowcontrol"
 	"github.com/ethereum/go-ethereum/light"
@@ -408,7 +407,7 @@ func (h *serverHandler) broadcastLoop() {
 	defer headSub.Unsubscribe()
 
 	var (
-		lastHead *types.Header
+		lastHead = h.blockchain.CurrentHeader()
 		lastTd   = common.Big0
 	)
 	for {
diff --git a/les/sync_test.go b/les/sync_test.go
index d3bb90df0283fd4dfa00f4360ccf634e64aace68..3fc2a9c1546dd2e18979c7fef783d9bffee22140 100644
--- a/les/sync_test.go
+++ b/les/sync_test.go
@@ -116,7 +116,7 @@ func testCheckpointSyncing(t *testing.T, protocol int, syncMode int) {
 	}
 
 	// Create connected peer pair.
-	peer1, peer2, err := newTestPeerPair("peer", protocol, server.handler, client.handler)
+	peer1, peer2, err := newTestPeerPair("peer", protocol, server.handler, client.handler, false)
 	if err != nil {
 		t.Fatalf("Failed to connect testing peers %v", err)
 	}
@@ -218,7 +218,7 @@ func testMissOracleBackend(t *testing.T, hasCheckpoint bool, protocol int) {
 		}
 	}
 	// Create connected peer pair.
-	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil {
+	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil {
 		t.Fatalf("Failed to connect testing peers %v", err)
 	}
 	select {
@@ -291,7 +291,7 @@ func testSyncFromConfiguredCheckpoint(t *testing.T, protocol int) {
 		}
 	}
 	// Create connected peer pair.
-	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil {
+	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil {
 		t.Fatalf("Failed to connect testing peers %v", err)
 	}
 
@@ -364,7 +364,7 @@ func testSyncAll(t *testing.T, protocol int) {
 		}
 	}
 	// Create connected peer pair.
-	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil {
+	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil {
 		t.Fatalf("Failed to connect testing peers %v", err)
 	}
 
diff --git a/les/test_helper.go b/les/test_helper.go
index 9ff2583b9765ff501275335463f18ed64d7dbe98..21d0f191c98ad19be3c4b088b2faa0b075bfa1b7 100644
--- a/les/test_helper.go
+++ b/les/test_helper.go
@@ -398,7 +398,7 @@ func (p *testPeer) close() {
 	p.app.Close()
 }
 
-func newTestPeerPair(name string, version int, server *serverHandler, client *clientHandler) (*testPeer, *testPeer, error) {
+func newTestPeerPair(name string, version int, server *serverHandler, client *clientHandler, noInitAnnounce bool) (*testPeer, *testPeer, error) {
 	// Create a message pipe to communicate through
 	app, net := p2p.MsgPipe()
 
@@ -423,16 +423,16 @@ func newTestPeerPair(name string, version int, server *serverHandler, client *cl
 		select {
 		case <-client.closeCh:
 			errc2 <- p2p.DiscQuitting
-		case errc2 <- client.handle(peer2):
+		case errc2 <- client.handle(peer2, noInitAnnounce):
 		}
 	}()
 	// Ensure the connection is established or exits when any error occurs
 	for {
 		select {
 		case err := <-errc1:
-			return nil, nil, fmt.Errorf("Failed to establish protocol connection %v", err)
+			return nil, nil, fmt.Errorf("failed to establish protocol connection %v", err)
 		case err := <-errc2:
-			return nil, nil, fmt.Errorf("Failed to establish protocol connection %v", err)
+			return nil, nil, fmt.Errorf("failed to establish protocol connection %v", err)
 		default:
 		}
 		if atomic.LoadUint32(&peer1.serving) == 1 && atomic.LoadUint32(&peer2.serving) == 1 {
@@ -473,7 +473,7 @@ func (client *testClient) newRawPeer(t *testing.T, name string, version int, rec
 		select {
 		case <-client.handler.closeCh:
 			errCh <- p2p.DiscQuitting
-		case errCh <- client.handler.handle(peer):
+		case errCh <- client.handler.handle(peer, false):
 		}
 	}()
 	tp := &testPeer{
@@ -623,7 +623,7 @@ func newClientServerEnv(t *testing.T, config testnetConfig) (*testServer, *testC
 	if config.connect {
 		done := make(chan struct{})
 		client.syncEnd = func(_ *types.Header) { close(done) }
-		cpeer, speer, err = newTestPeerPair("peer", config.protocol, server, client)
+		cpeer, speer, err = newTestPeerPair("peer", config.protocol, server, client, false)
 		if err != nil {
 			t.Fatalf("Failed to connect testing peers %v", err)
 		}
diff --git a/les/ulc_test.go b/les/ulc_test.go
index d7308fa593c0ce9902efc5f8dfbd9fdc9c5578f9..ecef58d9791ee098b8925942c51c34595f69a089 100644
--- a/les/ulc_test.go
+++ b/les/ulc_test.go
@@ -20,6 +20,7 @@ import (
 	"crypto/rand"
 	"fmt"
 	"net"
+	"sync/atomic"
 	"testing"
 	"time"
 
@@ -65,7 +66,7 @@ func testULCAnnounceThreshold(t *testing.T, protocol int) {
 
 		// Connect all servers.
 		for i := 0; i < len(servers); i++ {
-			connect(servers[i].handler, nodes[i].ID(), c.handler, protocol)
+			connect(servers[i].handler, nodes[i].ID(), c.handler, protocol, false)
 		}
 		for i := 0; i < len(servers); i++ {
 			for j := 0; j < testcase.height[i]; j++ {
@@ -86,7 +87,7 @@ func testULCAnnounceThreshold(t *testing.T, protocol int) {
 	}
 }
 
-func connect(server *serverHandler, serverId enode.ID, client *clientHandler, protocol int) (*serverPeer, *clientPeer, error) {
+func connect(server *serverHandler, serverId enode.ID, client *clientHandler, protocol int, noInitAnnounce bool) (*serverPeer, *clientPeer, error) {
 	// Create a message pipe to communicate through
 	app, net := p2p.MsgPipe()
 
@@ -110,16 +111,22 @@ func connect(server *serverHandler, serverId enode.ID, client *clientHandler, pr
 		select {
 		case <-client.closeCh:
 			errc1 <- p2p.DiscQuitting
-		case errc1 <- client.handle(peer1):
+		case errc1 <- client.handle(peer1, noInitAnnounce):
 		}
 	}()
-
-	select {
-	case <-time.After(time.Millisecond * 100):
-	case err := <-errc1:
-		return nil, nil, fmt.Errorf("peerLight handshake error: %v", err)
-	case err := <-errc2:
-		return nil, nil, fmt.Errorf("peerFull handshake error: %v", err)
+	// Ensure the connection is established or exits when any error occurs
+	for {
+		select {
+		case err := <-errc1:
+			return nil, nil, fmt.Errorf("failed to establish protocol connection %v", err)
+		case err := <-errc2:
+			return nil, nil, fmt.Errorf("failed to establish protocol connection %v", err)
+		default:
+		}
+		if atomic.LoadUint32(&peer1.serving) == 1 && atomic.LoadUint32(&peer2.serving) == 1 {
+			break
+		}
+		time.Sleep(50 * time.Millisecond)
 	}
 	return peer1, peer2, nil
 }
diff --git a/light/postprocess.go b/light/postprocess.go
index 891c8a5869db680ee52f12332d19500ee8ab3a44..ce38d091e891a6a2a988b6a113f1c0f87dba20d2 100644
--- a/light/postprocess.go
+++ b/light/postprocess.go
@@ -217,7 +217,7 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e
 
 // Commit implements core.ChainIndexerBackend
 func (c *ChtIndexerBackend) Commit() error {
-	root, err := c.trie.Commit(nil)
+	root, _, err := c.trie.Commit(nil)
 	if err != nil {
 		return err
 	}
@@ -454,7 +454,7 @@ func (b *BloomTrieIndexerBackend) Commit() error {
 			b.trie.Delete(encKey[:])
 		}
 	}
-	root, err := b.trie.Commit(nil)
+	root, _, err := b.trie.Commit(nil)
 	if err != nil {
 		return err
 	}
diff --git a/light/trie.go b/light/trie.go
index 0516b944860d06c2d5bf87c3400a7b839ce6db2d..39e928bbe12c99a67c90fa34acc8dac2a6c18a15 100644
--- a/light/trie.go
+++ b/light/trie.go
@@ -125,9 +125,9 @@ func (t *odrTrie) TryDelete(key []byte) error {
 	})
 }
 
-func (t *odrTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) {
+func (t *odrTrie) Commit(onleaf trie.LeafCallback) (common.Hash, int, error) {
 	if t.trie == nil {
-		return t.id.Root, nil
+		return t.id.Root, 0, nil
 	}
 	return t.trie.Commit(onleaf)
 }
diff --git a/log/handler_go13.go b/log/handler_go13.go
index 0843ed0e5f388b60c82b15fb53a00f9aac069d8a..4df694debed86c78da1fbf9e84f45beca29688b9 100644
--- a/log/handler_go13.go
+++ b/log/handler_go13.go
@@ -1,3 +1,4 @@
+//go:build !go1.4
 // +build !go1.4
 
 package log
diff --git a/log/handler_go14.go b/log/handler_go14.go
index 05dedbf2a70e3aae9e54a0f6fc097dd5d50c9d4c..d0cb14aa063b2ff6f20e9f1eb1881fe776482c57 100644
--- a/log/handler_go14.go
+++ b/log/handler_go14.go
@@ -1,3 +1,4 @@
+//go:build go1.4
 // +build go1.4
 
 package log
diff --git a/log/syslog.go b/log/syslog.go
index 71a17b30b3e084553b07f89441c82e1b8271e317..451d831b6dd1711ea8096485d997c574db335c5f 100644
--- a/log/syslog.go
+++ b/log/syslog.go
@@ -1,3 +1,4 @@
+//go:build !windows && !plan9
 // +build !windows,!plan9
 
 package log
diff --git a/metrics/cpu_disabled.go b/metrics/cpu_disabled.go
index 6c3428993fb100712898380e06d2619181cdbf02..025d97aeb32af2f2e6df9932ccd2c7ec2917183b 100644
--- a/metrics/cpu_disabled.go
+++ b/metrics/cpu_disabled.go
@@ -14,7 +14,8 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-// +build ios
+//go:build ios || js
+// +build ios js
 
 package metrics
 
diff --git a/metrics/cpu_enabled.go b/metrics/cpu_enabled.go
index 02192928b70cc736a685997253689572a9402bd7..533d40b85a58ae385f3e5b15966b3a21d218b98a 100644
--- a/metrics/cpu_enabled.go
+++ b/metrics/cpu_enabled.go
@@ -14,7 +14,8 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-// +build !ios
+//go:build !ios && !js
+// +build !ios,!js
 
 package metrics
 
diff --git a/metrics/cpu_windows.go b/metrics/cputime_nop.go
similarity index 95%
rename from metrics/cpu_windows.go
rename to metrics/cputime_nop.go
index fb29a52a82c1d838881d1eafd2c42351c83f424f..0188735a783397c4e3f5e178085112ddc6243546 100644
--- a/metrics/cpu_windows.go
+++ b/metrics/cputime_nop.go
@@ -14,6 +14,9 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build windows || js
+// +build windows js
+
 package metrics
 
 // getProcessCPUTime returns 0 on Windows as there is no system call to resolve
diff --git a/metrics/cpu_syscall.go b/metrics/cputime_unix.go
similarity index 96%
rename from metrics/cpu_syscall.go
rename to metrics/cputime_unix.go
index 50e04ef1d34b834513148ae1319317591c4da639..3c56a75d0077cfb1e09351b72cc2edb080f64ebb 100644
--- a/metrics/cpu_syscall.go
+++ b/metrics/cputime_unix.go
@@ -14,7 +14,8 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-// +build !windows
+//go:build !windows && !js
+// +build !windows,!js
 
 package metrics
 
diff --git a/metrics/disk_nop.go b/metrics/disk_nop.go
index 4319f8b277f85f34483c278f9746756d1797b5eb..58fa4e02f8986f3b2af620b883e177412579a2de 100644
--- a/metrics/disk_nop.go
+++ b/metrics/disk_nop.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build !linux
 // +build !linux
 
 package metrics
diff --git a/metrics/runtime_cgo.go b/metrics/runtime_cgo.go
index e3391f4e89fa1c457ed83e3789bf559214ccbec8..4307ebdba689e4fdcd825f124ffe73888da273f1 100644
--- a/metrics/runtime_cgo.go
+++ b/metrics/runtime_cgo.go
@@ -1,5 +1,5 @@
-// +build cgo
-// +build !appengine
+//go:build cgo && !appengine && !js
+// +build cgo,!appengine,!js
 
 package metrics
 
diff --git a/metrics/runtime_gccpufraction.go b/metrics/runtime_gccpufraction.go
index ca12c05bac740b87c9963d6b4487b78959c4e6a0..28cd44752b45fa7fa1ff5f493b5606f5524ae419 100644
--- a/metrics/runtime_gccpufraction.go
+++ b/metrics/runtime_gccpufraction.go
@@ -1,3 +1,4 @@
+//go:build go1.5
 // +build go1.5
 
 package metrics
diff --git a/metrics/runtime_no_cgo.go b/metrics/runtime_no_cgo.go
index 616a3b4751be1bf288b909d2192851500eb010a7..1799bef63bfb3d9426aa738874959bae715d0fe3 100644
--- a/metrics/runtime_no_cgo.go
+++ b/metrics/runtime_no_cgo.go
@@ -1,4 +1,5 @@
-// +build !cgo appengine
+//go:build !cgo || appengine || js
+// +build !cgo appengine js
 
 package metrics
 
diff --git a/metrics/runtime_no_gccpufraction.go b/metrics/runtime_no_gccpufraction.go
index be96aa6f1be9edacaf73eac2444b7f15865a51aa..af1a4b63c8094ddcae02d053e6cd3c02db9a4efc 100644
--- a/metrics/runtime_no_gccpufraction.go
+++ b/metrics/runtime_no_gccpufraction.go
@@ -1,3 +1,4 @@
+//go:build !go1.5
 // +build !go1.5
 
 package metrics
diff --git a/metrics/syslog.go b/metrics/syslog.go
index a0ed4b1b2364910231e42a4b5141fef68de2919f..551a2bd0f072c930b7d6cdc328288abf772a9891 100644
--- a/metrics/syslog.go
+++ b/metrics/syslog.go
@@ -1,3 +1,4 @@
+//go:build !windows
 // +build !windows
 
 package metrics
diff --git a/mobile/geth_android.go b/mobile/geth_android.go
index 8e4ebe638f8c36ba5d91daf748e49882c3ec66a0..cfdf1c28c97f3d380f2a6a29f88c44a299c50aa5 100644
--- a/mobile/geth_android.go
+++ b/mobile/geth_android.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build android
 // +build android
 
 package geth
diff --git a/mobile/geth_ios.go b/mobile/geth_ios.go
index 307cd08580447606e6f875fcf140008a460b4e1f..aab839727fa5ebd4467fad7b45bec209c025a736 100644
--- a/mobile/geth_ios.go
+++ b/mobile/geth_ios.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build ios
 // +build ios
 
 package geth
diff --git a/mobile/geth_other.go b/mobile/geth_other.go
index 6f0c5dda683c20eb0e35d1d4ca6856a775d6834f..c5cad4a7ba8ee0a4a31fe9e63ffb9a14e8418c01 100644
--- a/mobile/geth_other.go
+++ b/mobile/geth_other.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build !android && !ios
 // +build !android,!ios
 
 package geth
diff --git a/node/config.go b/node/config.go
index ef1da15d7076f381b94f97e137f8885711c48292..26f00cd678abab8027e6f3879c226a0b5a7f2fb7 100644
--- a/node/config.go
+++ b/node/config.go
@@ -26,11 +26,6 @@ import (
 	"strings"
 	"sync"
 
-	"github.com/ethereum/go-ethereum/accounts"
-	"github.com/ethereum/go-ethereum/accounts/external"
-	"github.com/ethereum/go-ethereum/accounts/keystore"
-	"github.com/ethereum/go-ethereum/accounts/scwallet"
-	"github.com/ethereum/go-ethereum/accounts/usbwallet"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/log"
@@ -93,6 +88,7 @@ type Config struct {
 	InsecureUnlockAllowed bool `toml:",omitempty"`
 
 	// NoUSB disables hardware wallet monitoring and connectivity.
+	// Deprecated: USB monitoring is disabled by default and must be enabled explicitly.
 	NoUSB bool `toml:",omitempty"`
 
 	// USB enables hardware wallet monitoring and connectivity.
@@ -429,15 +425,8 @@ func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node {
 	return nodes
 }
 
-// AccountConfig determines the settings for scrypt and keydirectory
-func (c *Config) AccountConfig() (int, int, string, error) {
-	scryptN := keystore.StandardScryptN
-	scryptP := keystore.StandardScryptP
-	if c.UseLightweightKDF {
-		scryptN = keystore.LightScryptN
-		scryptP = keystore.LightScryptP
-	}
-
+// KeyDirConfig determines the settings for keydirectory
+func (c *Config) KeyDirConfig() (string, error) {
 	var (
 		keydir string
 		err    error
@@ -454,71 +443,31 @@ func (c *Config) AccountConfig() (int, int, string, error) {
 	case c.KeyStoreDir != "":
 		keydir, err = filepath.Abs(c.KeyStoreDir)
 	}
-	return scryptN, scryptP, keydir, err
+	return keydir, err
 }
 
-func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
-	scryptN, scryptP, keydir, err := conf.AccountConfig()
-	var ephemeral string
+// getKeyStoreDir retrieves the key directory and will create
+// and ephemeral one if necessary.
+func getKeyStoreDir(conf *Config) (string, bool, error) {
+	keydir, err := conf.KeyDirConfig()
+	if err != nil {
+		return "", false, err
+	}
+	isEphemeral := false
 	if keydir == "" {
 		// There is no datadir.
 		keydir, err = ioutil.TempDir("", "go-ethereum-keystore")
-		ephemeral = keydir
+		isEphemeral = true
 	}
 
 	if err != nil {
-		return nil, "", err
+		return "", false, err
 	}
 	if err := os.MkdirAll(keydir, 0700); err != nil {
-		return nil, "", err
-	}
-	// Assemble the account manager and supported backends
-	var backends []accounts.Backend
-	if len(conf.ExternalSigner) > 0 {
-		log.Info("Using external signer", "url", conf.ExternalSigner)
-		if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil {
-			backends = append(backends, extapi)
-		} else {
-			return nil, "", fmt.Errorf("error connecting to external signer: %v", err)
-		}
-	}
-	if len(backends) == 0 {
-		// For now, we're using EITHER external signer OR local signers.
-		// If/when we implement some form of lockfile for USB and keystore wallets,
-		// we can have both, but it's very confusing for the user to see the same
-		// accounts in both externally and locally, plus very racey.
-		backends = append(backends, keystore.NewKeyStore(keydir, scryptN, scryptP))
-		if conf.USB {
-			// Start a USB hub for Ledger hardware wallets
-			if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
-				log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
-			} else {
-				backends = append(backends, ledgerhub)
-			}
-			// Start a USB hub for Trezor hardware wallets (HID version)
-			if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil {
-				log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err))
-			} else {
-				backends = append(backends, trezorhub)
-			}
-			// Start a USB hub for Trezor hardware wallets (WebUSB version)
-			if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil {
-				log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err))
-			} else {
-				backends = append(backends, trezorhub)
-			}
-		}
-		if len(conf.SmartCardDaemonPath) > 0 {
-			// Start a smart card hub
-			if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil {
-				log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err))
-			} else {
-				backends = append(backends, schub)
-			}
-		}
+		return "", false, err
 	}
 
-	return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: conf.InsecureUnlockAllowed}, backends...), ephemeral, nil
+	return keydir, isEphemeral, nil
 }
 
 var warnLock sync.Mutex
diff --git a/node/node.go b/node/node.go
index 1e65fff1c271eef88d8ec20d30663cffc5994961..ceab1c90902b4134430d099cbe8f84bfef635f6d 100644
--- a/node/node.go
+++ b/node/node.go
@@ -42,7 +42,8 @@ type Node struct {
 	config        *Config
 	accman        *accounts.Manager
 	log           log.Logger
-	ephemKeystore string            // if non-empty, the key directory that will be removed by Stop
+	keyDir        string            // key store directory
+	keyDirTemp    bool              // If true, key directory will be removed by Stop
 	dirLock       fileutil.Releaser // prevents concurrent use of instance directory
 	stop          chan struct{}     // Channel to wait for termination notifications
 	server        *p2p.Server       // Currently running P2P networking layer
@@ -112,14 +113,15 @@ func New(conf *Config) (*Node, error) {
 	if err := node.openDataDir(); err != nil {
 		return nil, err
 	}
-	// Ensure that the AccountManager method works before the node has started. We rely on
-	// this in cmd/geth.
-	am, ephemeralKeystore, err := makeAccountManager(conf)
+	keyDir, isEphem, err := getKeyStoreDir(conf)
 	if err != nil {
 		return nil, err
 	}
-	node.accman = am
-	node.ephemKeystore = ephemeralKeystore
+	node.keyDir = keyDir
+	node.keyDirTemp = isEphem
+	// Creates an empty AccountManager with no backends. Callers (e.g. cmd/geth)
+	// are required to add the backends later on.
+	node.accman = accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: conf.InsecureUnlockAllowed})
 
 	// Initialize the p2p server. This creates the node key and discovery databases.
 	node.server.Config.PrivateKey = node.config.NodeKey()
@@ -233,8 +235,8 @@ func (n *Node) doClose(errs []error) error {
 	if err := n.accman.Close(); err != nil {
 		errs = append(errs, err)
 	}
-	if n.ephemKeystore != "" {
-		if err := os.RemoveAll(n.ephemKeystore); err != nil {
+	if n.keyDirTemp {
+		if err := os.RemoveAll(n.keyDir); err != nil {
 			errs = append(errs, err)
 		}
 	}
@@ -514,6 +516,11 @@ func (n *Node) InstanceDir() string {
 	return n.config.instanceDir()
 }
 
+// KeyStoreDir retrieves the key directory
+func (n *Node) KeyStoreDir() string {
+	return n.keyDir
+}
+
 // AccountManager retrieves the account manager used by the protocol stack.
 func (n *Node) AccountManager() *accounts.Manager {
 	return n.accman
diff --git a/p2p/dial.go b/p2p/dial.go
index 83ced3cb328082b3c489c679b78a82b67f6d9eb8..0d70e6f4a33b8c5993243163d78b29ca089f2483 100644
--- a/p2p/dial.go
+++ b/p2p/dial.go
@@ -107,7 +107,7 @@ type dialScheduler struct {
 	// Everything below here belongs to loop and
 	// should only be accessed by code on the loop goroutine.
 	dialing   map[enode.ID]*dialTask // active tasks
-	peers     map[enode.ID]connFlag  // all connected peers
+	peers     map[enode.ID]struct{}  // all connected peers
 	dialPeers int                    // current number of dialed peers
 
 	// The static map tracks all static dial tasks. The subset of usable static dial tasks
@@ -166,7 +166,7 @@ func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupF
 		setupFunc:   setupFunc,
 		dialing:     make(map[enode.ID]*dialTask),
 		static:      make(map[enode.ID]*dialTask),
-		peers:       make(map[enode.ID]connFlag),
+		peers:       make(map[enode.ID]struct{}),
 		doneCh:      make(chan *dialTask),
 		nodesIn:     make(chan *enode.Node),
 		addStaticCh: make(chan *enode.Node),
@@ -259,7 +259,7 @@ loop:
 				d.dialPeers++
 			}
 			id := c.node.ID()
-			d.peers[id] = c.flags
+			d.peers[id] = struct{}{}
 			// Remove from static pool because the node is now connected.
 			task := d.static[id]
 			if task != nil && task.staticPoolIndex >= 0 {
diff --git a/p2p/enode/iter_test.go b/p2p/enode/iter_test.go
index 6009661f3ce6f6a4c37706ac16fb7f9b71a301c9..5014346af465ffc8f2d41e0d13d0c20adca4e46a 100644
--- a/p2p/enode/iter_test.go
+++ b/p2p/enode/iter_test.go
@@ -268,7 +268,7 @@ func (s *genIter) Node() *Node {
 }
 
 func (s *genIter) Close() {
-	s.index = ^uint32(0)
+	atomic.StoreUint32(&s.index, ^uint32(0))
 }
 
 func testNode(id, seq uint64) *Node {
diff --git a/p2p/netutil/toobig_notwindows.go b/p2p/netutil/toobig_notwindows.go
index 47b64385723ce8c821e106390edab2bbba0e9b83..f9f936ae568cb5d4a22781c5081d2bf68eb7bb90 100644
--- a/p2p/netutil/toobig_notwindows.go
+++ b/p2p/netutil/toobig_notwindows.go
@@ -14,7 +14,8 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-//+build !windows
+//go:build !windows
+// +build !windows
 
 package netutil
 
diff --git a/p2p/netutil/toobig_windows.go b/p2p/netutil/toobig_windows.go
index dfbb6d44f0a5abb5a803f28821e091f0414ef63b..652903e83c30e582be9fa381d987c5ed69cc1e50 100644
--- a/p2p/netutil/toobig_windows.go
+++ b/p2p/netutil/toobig_windows.go
@@ -14,7 +14,8 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-//+build windows
+//go:build windows
+// +build windows
 
 package netutil
 
diff --git a/params/version.go b/params/version.go
index 8d222ac0470881244ea081e5ee0d93569f442412..dd629a100aa59626df7819e0971e1576e92f7d59 100644
--- a/params/version.go
+++ b/params/version.go
@@ -21,10 +21,10 @@ import (
 )
 
 const (
-	VersionMajor = 1        // Major version component of the current release
-	VersionMinor = 10       // Minor version component of the current release
-	VersionPatch = 8        // Patch version component of the current release
-	VersionMeta  = "stable" // Version metadata to append to the version string
+	VersionMajor = 1          // Major version component of the current release
+	VersionMinor = 10         // Minor version component of the current release
+	VersionPatch = 9          // Patch version component of the current release
+	VersionMeta  = "unstable" // Version metadata to append to the version string
 )
 
 // Version holds the textual version string.
diff --git a/rlp/decode.go b/rlp/decode.go
index ac04d5d56949f85d622517244487d21a6f4f73ce..5f2e5ad5fea028d65a0717a1dda8cc6ab92bdc2d 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -379,7 +379,7 @@ func decodeByteArray(s *Stream, val reflect.Value) error {
 	if err != nil {
 		return err
 	}
-	slice := byteArrayBytes(val)
+	slice := byteArrayBytes(val, val.Len())
 	switch kind {
 	case Byte:
 		if len(slice) == 0 {
diff --git a/rlp/encode.go b/rlp/encode.go
index 3348644342965ec2de14766b1cfed0ebe7d02edc..1623e97a3e9eac383bfe02db2639f006c8c3e4f0 100644
--- a/rlp/encode.go
+++ b/rlp/encode.go
@@ -432,7 +432,20 @@ func makeByteArrayWriter(typ reflect.Type) writer {
 	case 1:
 		return writeLengthOneByteArray
 	default:
-		return writeByteArray
+		length := typ.Len()
+		return func(val reflect.Value, w *encbuf) error {
+			if !val.CanAddr() {
+				// Getting the byte slice of val requires it to be addressable. Make it
+				// addressable by copying.
+				copy := reflect.New(val.Type()).Elem()
+				copy.Set(val)
+				val = copy
+			}
+			slice := byteArrayBytes(val, length)
+			w.encodeStringHeader(len(slice))
+			w.str = append(w.str, slice...)
+			return nil
+		}
 	}
 }
 
@@ -451,21 +464,6 @@ func writeLengthOneByteArray(val reflect.Value, w *encbuf) error {
 	return nil
 }
 
-func writeByteArray(val reflect.Value, w *encbuf) error {
-	if !val.CanAddr() {
-		// Getting the byte slice of val requires it to be addressable. Make it
-		// addressable by copying.
-		copy := reflect.New(val.Type()).Elem()
-		copy.Set(val)
-		val = copy
-	}
-
-	slice := byteArrayBytes(val)
-	w.encodeStringHeader(len(slice))
-	w.str = append(w.str, slice...)
-	return nil
-}
-
 func writeString(val reflect.Value, w *encbuf) error {
 	s := val.String()
 	if len(s) == 1 && s[0] <= 0x7f {
@@ -499,19 +497,39 @@ func makeSliceWriter(typ reflect.Type, ts tags) (writer, error) {
 	if etypeinfo.writerErr != nil {
 		return nil, etypeinfo.writerErr
 	}
-	writer := func(val reflect.Value, w *encbuf) error {
-		if !ts.tail {
-			defer w.listEnd(w.list())
+
+	var wfn writer
+	if ts.tail {
+		// This is for struct tail slices.
+		// w.list is not called for them.
+		wfn = func(val reflect.Value, w *encbuf) error {
+			vlen := val.Len()
+			for i := 0; i < vlen; i++ {
+				if err := etypeinfo.writer(val.Index(i), w); err != nil {
+					return err
+				}
+			}
+			return nil
 		}
-		vlen := val.Len()
-		for i := 0; i < vlen; i++ {
-			if err := etypeinfo.writer(val.Index(i), w); err != nil {
-				return err
+	} else {
+		// This is for regular slices and arrays.
+		wfn = func(val reflect.Value, w *encbuf) error {
+			vlen := val.Len()
+			if vlen == 0 {
+				w.str = append(w.str, 0xC0)
+				return nil
 			}
+			listOffset := w.list()
+			for i := 0; i < vlen; i++ {
+				if err := etypeinfo.writer(val.Index(i), w); err != nil {
+					return err
+				}
+			}
+			w.listEnd(listOffset)
+			return nil
 		}
-		return nil
 	}
-	return writer, nil
+	return wfn, nil
 }
 
 func makeStructWriter(typ reflect.Type) (writer, error) {
@@ -562,12 +580,8 @@ func makeStructWriter(typ reflect.Type) (writer, error) {
 	return writer, nil
 }
 
-func makePtrWriter(typ reflect.Type, ts tags) (writer, error) {
-	etypeinfo := theTC.infoWhileGenerating(typ.Elem(), tags{})
-	if etypeinfo.writerErr != nil {
-		return nil, etypeinfo.writerErr
-	}
-	// Determine how to encode nil pointers.
+// nilEncoding returns the encoded value of a nil pointer.
+func nilEncoding(typ reflect.Type, ts tags) uint8 {
 	var nilKind Kind
 	if ts.nilOK {
 		nilKind = ts.nilKind // use struct tag if provided
@@ -575,16 +589,29 @@ func makePtrWriter(typ reflect.Type, ts tags) (writer, error) {
 		nilKind = defaultNilKind(typ.Elem())
 	}
 
+	switch nilKind {
+	case String:
+		return 0x80
+	case List:
+		return 0xC0
+	default:
+		panic(fmt.Errorf("rlp: invalid nil kind %d", nilKind))
+	}
+}
+
+func makePtrWriter(typ reflect.Type, ts tags) (writer, error) {
+	etypeinfo := theTC.infoWhileGenerating(typ.Elem(), tags{})
+	if etypeinfo.writerErr != nil {
+		return nil, etypeinfo.writerErr
+	}
+	nilEncoding := nilEncoding(typ, ts)
+
 	writer := func(val reflect.Value, w *encbuf) error {
-		if val.IsNil() {
-			if nilKind == String {
-				w.str = append(w.str, 0x80)
-			} else {
-				w.listEnd(w.list())
-			}
-			return nil
+		if ev := val.Elem(); ev.IsValid() {
+			return etypeinfo.writer(ev, w)
 		}
-		return etypeinfo.writer(val.Elem(), w)
+		w.str = append(w.str, nilEncoding)
+		return nil
 	}
 	return writer, nil
 }
diff --git a/rlp/encode_test.go b/rlp/encode_test.go
index 25d4aac267264bf32834f58b9b431d8ab5ccd22f..a63743440d3952475ae0f1541a4080eb587b72bf 100644
--- a/rlp/encode_test.go
+++ b/rlp/encode_test.go
@@ -540,3 +540,31 @@ func BenchmarkEncodeByteArrayStruct(b *testing.B) {
 		}
 	}
 }
+
+type structSliceElem struct {
+	X uint64
+	Y uint64
+	Z uint64
+}
+
+type structPtrSlice []*structSliceElem
+
+func BenchmarkEncodeStructPtrSlice(b *testing.B) {
+	var out bytes.Buffer
+	var value = structPtrSlice{
+		&structSliceElem{1, 1, 1},
+		&structSliceElem{2, 2, 2},
+		&structSliceElem{3, 3, 3},
+		&structSliceElem{5, 5, 5},
+		&structSliceElem{6, 6, 6},
+		&structSliceElem{7, 7, 7},
+	}
+
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		out.Reset()
+		if err := Encode(&out, &value); err != nil {
+			b.Fatal(err)
+		}
+	}
+}
diff --git a/rlp/safe.go b/rlp/safe.go
index a80380aef473feaec3b3c6a51d63d125a7431ca8..3c910337b6a27808e8f95518e02853a01f431b4d 100644
--- a/rlp/safe.go
+++ b/rlp/safe.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build nacl || js || !cgo
 // +build nacl js !cgo
 
 package rlp
@@ -21,6 +22,6 @@ package rlp
 import "reflect"
 
 // byteArrayBytes returns a slice of the byte array v.
-func byteArrayBytes(v reflect.Value) []byte {
-	return v.Slice(0, v.Len()).Bytes()
+func byteArrayBytes(v reflect.Value, length int) []byte {
+	return v.Slice(0, length).Bytes()
 }
diff --git a/rlp/unsafe.go b/rlp/unsafe.go
index 94ed5405a8e4e21fc7ffa81bf41cd14f155540f3..2152ba35fc4a7e27ed115ed92667772dda3f18d8 100644
--- a/rlp/unsafe.go
+++ b/rlp/unsafe.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build !nacl && !js && cgo
 // +build !nacl,!js,cgo
 
 package rlp
@@ -24,12 +25,11 @@ import (
 )
 
 // byteArrayBytes returns a slice of the byte array v.
-func byteArrayBytes(v reflect.Value) []byte {
-	len := v.Len()
+func byteArrayBytes(v reflect.Value, length int) []byte {
 	var s []byte
 	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))
 	hdr.Data = v.UnsafeAddr()
-	hdr.Cap = len
-	hdr.Len = len
+	hdr.Cap = length
+	hdr.Len = length
 	return s
 }
diff --git a/rpc/constants_unix.go b/rpc/constants_unix.go
index 2f98d6499b7a0229f66044b10b1c6e1eb97f1f52..1f04d15d7fd9ae1a92d7ec20902996612e5885cb 100644
--- a/rpc/constants_unix.go
+++ b/rpc/constants_unix.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris
 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package rpc
diff --git a/rpc/constants_unix_nocgo.go b/rpc/constants_unix_nocgo.go
index ecb231f92714b41b41f91c507b62cf0a1683507b..a62e4ee529df512ede598e03d0d3c253f37474b2 100644
--- a/rpc/constants_unix_nocgo.go
+++ b/rpc/constants_unix_nocgo.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build !cgo && !windows
 // +build !cgo,!windows
 
 package rpc
diff --git a/rpc/ipc_js.go b/rpc/ipc_js.go
index 7e7554a768879b0ceb838e7ef7c06e4484421dc8..453a20bc1aeb30dba837067dc260d0648b2ee065 100644
--- a/rpc/ipc_js.go
+++ b/rpc/ipc_js.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build js
 // +build js
 
 package rpc
diff --git a/rpc/ipc_unix.go b/rpc/ipc_unix.go
index f4690cc0abb9fb41997dd5023dfec8d03a815079..249a9cf044dcc6973bc39524a97e45ea8b3696e3 100644
--- a/rpc/ipc_unix.go
+++ b/rpc/ipc_unix.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris
 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package rpc
diff --git a/rpc/ipc_windows.go b/rpc/ipc_windows.go
index ca56a3ce4313784df18cb1c58c9732756c3c4d16..adb1826f0c802f2657a0707857b52fe13b84c616 100644
--- a/rpc/ipc_windows.go
+++ b/rpc/ipc_windows.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build windows
 // +build windows
 
 package rpc
diff --git a/rpc/types.go b/rpc/types.go
index ad068defa8865f378ff8afddb2fb01e989748e11..d9c2317a78ce1305eb8f4e3104f1f60ea7260ff1 100644
--- a/rpc/types.go
+++ b/rpc/types.go
@@ -98,6 +98,22 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
+// MarshalText implements encoding.TextMarshaler. It marshals:
+// - "latest", "earliest" or "pending" as strings
+// - other numbers as hex
+func (bn BlockNumber) MarshalText() ([]byte, error) {
+	switch bn {
+	case EarliestBlockNumber:
+		return []byte("earliest"), nil
+	case LatestBlockNumber:
+		return []byte("latest"), nil
+	case PendingBlockNumber:
+		return []byte("pending"), nil
+	default:
+		return hexutil.Uint64(bn).MarshalText()
+	}
+}
+
 func (bn BlockNumber) Int64() int64 {
 	return (int64)(bn)
 }
diff --git a/rpc/types_test.go b/rpc/types_test.go
index 89b0c9171a14506821ddf6b363087b1ee2abd2fa..f110dee7c6ffe186161badef79d040b58ffa3ece 100644
--- a/rpc/types_test.go
+++ b/rpc/types_test.go
@@ -18,6 +18,7 @@ package rpc
 
 import (
 	"encoding/json"
+	"reflect"
 	"testing"
 
 	"github.com/ethereum/go-ethereum/common"
@@ -122,3 +123,33 @@ func TestBlockNumberOrHash_UnmarshalJSON(t *testing.T) {
 		}
 	}
 }
+
+func TestBlockNumberOrHash_WithNumber_MarshalAndUnmarshal(t *testing.T) {
+	tests := []struct {
+		name   string
+		number int64
+	}{
+		{"max", math.MaxInt64},
+		{"pending", int64(PendingBlockNumber)},
+		{"latest", int64(LatestBlockNumber)},
+		{"earliest", int64(EarliestBlockNumber)},
+	}
+	for _, test := range tests {
+		test := test
+		t.Run(test.name, func(t *testing.T) {
+			bnh := BlockNumberOrHashWithNumber(BlockNumber(test.number))
+			marshalled, err := json.Marshal(bnh)
+			if err != nil {
+				t.Fatal("cannot marshal:", err)
+			}
+			var unmarshalled BlockNumberOrHash
+			err = json.Unmarshal(marshalled, &unmarshalled)
+			if err != nil {
+				t.Fatal("cannot unmarshal:", err)
+			}
+			if !reflect.DeepEqual(bnh, unmarshalled) {
+				t.Fatalf("wrong result: expected %v, got %v", bnh, unmarshalled)
+			}
+		})
+	}
+}
diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go
index c0f452f3edd514c89c67967e326e07e73324604c..b283ed11fe395d8c4a0996ff8fa4e25a66b74bea 100644
--- a/tests/fuzzers/bls12381/bls12381_fuzz.go
+++ b/tests/fuzzers/bls12381/bls12381_fuzz.go
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
+//go:build gofuzz
 // +build gofuzz
 
 package bls
diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go
index 5cea7769c284e77b522107a4734662d6563cb63c..e73ef4851a9c28cd37d5792508396c23ecb1965b 100644
--- a/tests/fuzzers/stacktrie/trie_fuzzer.go
+++ b/tests/fuzzers/stacktrie/trie_fuzzer.go
@@ -173,7 +173,7 @@ func (f *fuzzer) fuzz() int {
 		return 0
 	}
 	// Flush trie -> database
-	rootA, err := trieA.Commit(nil)
+	rootA, _, err := trieA.Commit(nil)
 	if err != nil {
 		panic(err)
 	}
diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go
index 762ab5f3470a2f54d3035e8aa776bc16c86b3b7c..e993af47cf20cf9b3aa626b3c3ff2f9aadd45c17 100644
--- a/tests/fuzzers/trie/trie-fuzzer.go
+++ b/tests/fuzzers/trie/trie-fuzzer.go
@@ -69,7 +69,7 @@ func newDataSource(input []byte) *dataSource {
 		input, bytes.NewReader(input),
 	}
 }
-func (ds *dataSource) ReadByte() byte {
+func (ds *dataSource) readByte() byte {
 	if b, err := ds.reader.ReadByte(); err != nil {
 		return 0
 	} else {
@@ -89,22 +89,22 @@ func Generate(input []byte) randTest {
 	r := newDataSource(input)
 	genKey := func() []byte {
 
-		if len(allKeys) < 2 || r.ReadByte() < 0x0f {
+		if len(allKeys) < 2 || r.readByte() < 0x0f {
 			// new key
-			key := make([]byte, r.ReadByte()%50)
+			key := make([]byte, r.readByte()%50)
 			r.Read(key)
 			allKeys = append(allKeys, key)
 			return key
 		}
 		// use existing key
-		return allKeys[int(r.ReadByte())%len(allKeys)]
+		return allKeys[int(r.readByte())%len(allKeys)]
 	}
 
 	var steps randTest
 
 	for i := 0; !r.Ended(); i++ {
 
-		step := randTestStep{op: int(r.ReadByte()) % opMax}
+		step := randTestStep{op: int(r.readByte()) % opMax}
 		switch step.op {
 		case opUpdate:
 			step.key = genKey()
@@ -162,11 +162,11 @@ func runRandTest(rt randTest) error {
 				rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want)
 			}
 		case opCommit:
-			_, rt[i].err = tr.Commit(nil)
+			_, _, rt[i].err = tr.Commit(nil)
 		case opHash:
 			tr.Hash()
 		case opReset:
-			hash, err := tr.Commit(nil)
+			hash, _, err := tr.Commit(nil)
 			if err != nil {
 				return err
 			}
diff --git a/tests/state_test.go b/tests/state_test.go
index c2ca0e8d694861a4dff6fb61c30d2aae9c2bd18f..a7d9653a337e70182efdd39dd5704af4e42faec6 100644
--- a/tests/state_test.go
+++ b/tests/state_test.go
@@ -42,6 +42,7 @@ func TestState(t *testing.T) {
 
 	// Very time consuming
 	st.skipLoad(`^stTimeConsuming/`)
+	st.skipLoad(`.*vmPerformance/loop.*`)
 
 	// Uses 1GB RAM per tested fork
 	st.skipLoad(`^stStaticCall/static_Call1MB`)
diff --git a/trie/committer.go b/trie/committer.go
index ce4065f5fd126293c098c02ca7caff5c47829574..0721990a2179910846005f821ecca7ecffc6bc38 100644
--- a/trie/committer.go
+++ b/trie/committer.go
@@ -72,24 +72,24 @@ func returnCommitterToPool(h *committer) {
 	committerPool.Put(h)
 }
 
-// commit collapses a node down into a hash node and inserts it into the database
-func (c *committer) Commit(n node, db *Database) (hashNode, error) {
+// Commit collapses a node down into a hash node and inserts it into the database
+func (c *committer) Commit(n node, db *Database) (hashNode, int, error) {
 	if db == nil {
-		return nil, errors.New("no db provided")
+		return nil, 0, errors.New("no db provided")
 	}
-	h, err := c.commit(n, db)
+	h, committed, err := c.commit(n, db)
 	if err != nil {
-		return nil, err
+		return nil, 0, err
 	}
-	return h.(hashNode), nil
+	return h.(hashNode), committed, nil
 }
 
 // commit collapses a node down into a hash node and inserts it into the database
-func (c *committer) commit(n node, db *Database) (node, error) {
+func (c *committer) commit(n node, db *Database) (node, int, error) {
 	// if this path is clean, use available cached data
 	hash, dirty := n.cache()
 	if hash != nil && !dirty {
-		return hash, nil
+		return hash, 0, nil
 	}
 	// Commit children, then parent, and remove remove the dirty flag.
 	switch cn := n.(type) {
@@ -97,37 +97,38 @@ func (c *committer) commit(n node, db *Database) (node, error) {
 		// Commit child
 		collapsed := cn.copy()
 
-		// If the child is fullnode, recursively commit.
-		// Otherwise it can only be hashNode or valueNode.
+		// If the child is fullNode, recursively commit,
+		// otherwise it can only be hashNode or valueNode.
+		var childCommitted int
 		if _, ok := cn.Val.(*fullNode); ok {
-			childV, err := c.commit(cn.Val, db)
+			childV, committed, err := c.commit(cn.Val, db)
 			if err != nil {
-				return nil, err
+				return nil, 0, err
 			}
-			collapsed.Val = childV
+			collapsed.Val, childCommitted = childV, committed
 		}
 		// The key needs to be copied, since we're delivering it to database
 		collapsed.Key = hexToCompact(cn.Key)
 		hashedNode := c.store(collapsed, db)
 		if hn, ok := hashedNode.(hashNode); ok {
-			return hn, nil
+			return hn, childCommitted + 1, nil
 		}
-		return collapsed, nil
+		return collapsed, childCommitted, nil
 	case *fullNode:
-		hashedKids, err := c.commitChildren(cn, db)
+		hashedKids, childCommitted, err := c.commitChildren(cn, db)
 		if err != nil {
-			return nil, err
+			return nil, 0, err
 		}
 		collapsed := cn.copy()
 		collapsed.Children = hashedKids
 
 		hashedNode := c.store(collapsed, db)
 		if hn, ok := hashedNode.(hashNode); ok {
-			return hn, nil
+			return hn, childCommitted + 1, nil
 		}
-		return collapsed, nil
+		return collapsed, childCommitted, nil
 	case hashNode:
-		return cn, nil
+		return cn, 0, nil
 	default:
 		// nil, valuenode shouldn't be committed
 		panic(fmt.Sprintf("%T: invalid node: %v", n, n))
@@ -135,8 +136,11 @@ func (c *committer) commit(n node, db *Database) (node, error) {
 }
 
 // commitChildren commits the children of the given fullnode
-func (c *committer) commitChildren(n *fullNode, db *Database) ([17]node, error) {
-	var children [17]node
+func (c *committer) commitChildren(n *fullNode, db *Database) ([17]node, int, error) {
+	var (
+		committed int
+		children  [17]node
+	)
 	for i := 0; i < 16; i++ {
 		child := n.Children[i]
 		if child == nil {
@@ -144,25 +148,26 @@ func (c *committer) commitChildren(n *fullNode, db *Database) ([17]node, error)
 		}
 		// If it's the hashed child, save the hash value directly.
 		// Note: it's impossible that the child in range [0, 15]
-		// is a valuenode.
+		// is a valueNode.
 		if hn, ok := child.(hashNode); ok {
 			children[i] = hn
 			continue
 		}
 		// Commit the child recursively and store the "hashed" value.
 		// Note the returned node can be some embedded nodes, so it's
-		// possible the type is not hashnode.
-		hashed, err := c.commit(child, db)
+		// possible the type is not hashNode.
+		hashed, childCommitted, err := c.commit(child, db)
 		if err != nil {
-			return children, err
+			return children, 0, err
 		}
 		children[i] = hashed
+		committed += childCommitted
 	}
 	// For the 17th child, it's possible the type is valuenode.
 	if n.Children[16] != nil {
 		children[16] = n.Children[16]
 	}
-	return children, nil
+	return children, committed, nil
 }
 
 // store hashes the node n and if we have a storage layer specified, it writes
@@ -176,7 +181,7 @@ func (c *committer) store(n node, db *Database) node {
 	)
 	if hash == nil {
 		// This was not generated - must be a small node stored in the parent.
-		// In theory we should apply the leafCall here if it's not nil(embedded
+		// In theory, we should apply the leafCall here if it's not nil(embedded
 		// node usually contains value). But small value(less than 32bytes) is
 		// not our target.
 		return n
@@ -224,7 +229,7 @@ func (c *committer) commitLoop(db *Database) {
 				}
 			case *fullNode:
 				// For children in range [0, 15], it's impossible
-				// to contain valuenode. Only check the 17th child.
+				// to contain valueNode. Only check the 17th child.
 				if n.Children[16] != nil {
 					c.onleaf(nil, nil, n.Children[16].(valueNode), hash)
 				}
diff --git a/trie/iterator_test.go b/trie/iterator_test.go
index 2518f7bac849f4bacb2629e94244c07e456e3040..95cafdd3bdceb3c857df2be6f01efdc6b90e4b1e 100644
--- a/trie/iterator_test.go
+++ b/trie/iterator_test.go
@@ -393,7 +393,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) {
 	for _, val := range testdata1 {
 		ctr.Update([]byte(val.k), []byte(val.v))
 	}
-	root, _ := ctr.Commit(nil)
+	root, _, _ := ctr.Commit(nil)
 	if !memonly {
 		triedb.Commit(root, true, nil)
 	}
diff --git a/trie/secure_trie.go b/trie/secure_trie.go
index e38471c1b76f9b35f21abff805dbf8f5662c3820..4d0050bc59d23fab98c5056c4218e61035a0d395 100644
--- a/trie/secure_trie.go
+++ b/trie/secure_trie.go
@@ -144,7 +144,7 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte {
 //
 // Committing flushes nodes from memory. Subsequent Get calls will load nodes
 // from the database.
-func (t *SecureTrie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
+func (t *SecureTrie) Commit(onleaf LeafCallback) (common.Hash, int, error) {
 	// Write all the pre-images to the actual disk database
 	if len(t.getSecKeyCache()) > 0 {
 		if t.trie.db.preimages != nil { // Ugly direct check but avoids the below write lock
diff --git a/trie/sync_bloom.go b/trie/sync_bloom.go
index 49986fcf0a91f56f137389bf1cd4b8e64bf0d902..91e5e6711df4c4eda066f817944a195ff6bf0ac1 100644
--- a/trie/sync_bloom.go
+++ b/trie/sync_bloom.go
@@ -129,6 +129,8 @@ func (b *SyncBloom) init(database ethdb.Iteratee) {
 func (b *SyncBloom) meter() {
 	// check every second
 	tick := time.NewTicker(1 * time.Second)
+	defer tick.Stop()
+
 	for {
 		select {
 		case <-tick.C:
diff --git a/trie/trie.go b/trie/trie.go
index e492a532cb280e3140259cdb0829d66dbabf8785..7ea7efa835f88d8fbbb5a629f364a565ba0e7216 100644
--- a/trie/trie.go
+++ b/trie/trie.go
@@ -514,12 +514,12 @@ func (t *Trie) Hash() common.Hash {
 
 // Commit writes all nodes to the trie's memory database, tracking the internal
 // and external (for account tries) references.
-func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
+func (t *Trie) Commit(onleaf LeafCallback) (common.Hash, int, error) {
 	if t.db == nil {
 		panic("commit called on trie with nil database")
 	}
 	if t.root == nil {
-		return emptyRoot, nil
+		return emptyRoot, 0, nil
 	}
 	// Derive the hash for all dirty nodes first. We hold the assumption
 	// in the following procedure that all nodes are hashed.
@@ -531,7 +531,7 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
 	// up goroutines. This can happen e.g. if we load a trie for reading storage
 	// values, but don't write to it.
 	if _, dirty := t.root.cache(); !dirty {
-		return rootHash, nil
+		return rootHash, 0, nil
 	}
 	var wg sync.WaitGroup
 	if onleaf != nil {
@@ -543,8 +543,7 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
 			h.commitLoop(t.db)
 		}()
 	}
-	var newRoot hashNode
-	newRoot, err = h.Commit(t.root, t.db)
+	newRoot, committed, err := h.Commit(t.root, t.db)
 	if onleaf != nil {
 		// The leafch is created in newCommitter if there was an onleaf callback
 		// provided. The commitLoop only _reads_ from it, and the commit
@@ -554,10 +553,10 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
 		wg.Wait()
 	}
 	if err != nil {
-		return common.Hash{}, err
+		return common.Hash{}, 0, err
 	}
 	t.root = newRoot
-	return rootHash, nil
+	return rootHash, committed, nil
 }
 
 // hashRoot calculates the root hash of the given trie
diff --git a/trie/trie_test.go b/trie/trie_test.go
index 492b423c2ff0000739c757027c77b33e6a4d28ce..ae1871e42309e927d3a97e1cf98fbe47e10d3382 100644
--- a/trie/trie_test.go
+++ b/trie/trie_test.go
@@ -90,7 +90,7 @@ func testMissingNode(t *testing.T, memonly bool) {
 	trie, _ := New(common.Hash{}, triedb)
 	updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
 	updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
-	root, _ := trie.Commit(nil)
+	root, _, _ := trie.Commit(nil)
 	if !memonly {
 		triedb.Commit(root, true, nil)
 	}
@@ -172,7 +172,7 @@ func TestInsert(t *testing.T) {
 	updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
 
 	exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")
-	root, err := trie.Commit(nil)
+	root, _, err := trie.Commit(nil)
 	if err != nil {
 		t.Fatalf("commit error: %v", err)
 	}
@@ -270,7 +270,7 @@ func TestReplication(t *testing.T) {
 	for _, val := range vals {
 		updateString(trie, val.k, val.v)
 	}
-	exp, err := trie.Commit(nil)
+	exp, _, err := trie.Commit(nil)
 	if err != nil {
 		t.Fatalf("commit error: %v", err)
 	}
@@ -285,7 +285,7 @@ func TestReplication(t *testing.T) {
 			t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v)
 		}
 	}
-	hash, err := trie2.Commit(nil)
+	hash, _, err := trie2.Commit(nil)
 	if err != nil {
 		t.Fatalf("commit error: %v", err)
 	}
@@ -429,11 +429,11 @@ func runRandTest(rt randTest) bool {
 				rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want)
 			}
 		case opCommit:
-			_, rt[i].err = tr.Commit(nil)
+			_, _, rt[i].err = tr.Commit(nil)
 		case opHash:
 			tr.Hash()
 		case opReset:
-			hash, err := tr.Commit(nil)
+			hash, _, err := tr.Commit(nil)
 			if err != nil {
 				rt[i].err = err
 				return false
@@ -633,7 +633,7 @@ func TestCommitAfterHash(t *testing.T) {
 	if exp != root {
 		t.Errorf("got %x, exp %x", root, exp)
 	}
-	root, _ = trie.Commit(nil)
+	root, _, _ = trie.Commit(nil)
 	if exp != root {
 		t.Errorf("got %x, exp %x", root, exp)
 	}
@@ -740,7 +740,7 @@ func TestCommitSequence(t *testing.T) {
 			trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i])
 		}
 		// Flush trie -> database
-		root, _ := trie.Commit(nil)
+		root, _, _ := trie.Commit(nil)
 		// Flush memdb -> disk (sponge)
 		db.Commit(root, false, func(c common.Hash) {
 			// And spongify the callback-order
@@ -792,7 +792,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) {
 			trie.Update(key, val)
 		}
 		// Flush trie -> database
-		root, _ := trie.Commit(nil)
+		root, _, _ := trie.Commit(nil)
 		// Flush memdb -> disk (sponge)
 		db.Commit(root, false, func(c common.Hash) {
 			// And spongify the callback-order
@@ -834,7 +834,7 @@ func TestCommitSequenceStackTrie(t *testing.T) {
 			stTrie.TryUpdate(key, val)
 		}
 		// Flush trie -> database
-		root, _ := trie.Commit(nil)
+		root, _, _ := trie.Commit(nil)
 		// Flush memdb -> disk (sponge)
 		db.Commit(root, false, nil)
 		// And flush stacktrie -> disk
@@ -879,7 +879,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) {
 	trie.TryUpdate(key, []byte{0x1})
 	stTrie.TryUpdate(key, []byte{0x1})
 	// Flush trie -> database
-	root, _ := trie.Commit(nil)
+	root, _, _ := trie.Commit(nil)
 	// Flush memdb -> disk (sponge)
 	db.Commit(root, false, nil)
 	// And flush stacktrie -> disk