From bb628f9562dc66eb4fe71bd292771d3768263392 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Tue, 12 Dec 2023 03:26:19 -0500
Subject: [PATCH 01/11] refactor unit tests

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 go.mod                       |   2 +-
 go.sum                       |   4 +-
 peer/network_test.go         |  10 +-
 plugin/evm/tx_gossip_test.go | 247 ++++++++++++++++++++---------------
 plugin/evm/vm.go             | 141 +++++++++++---------
 plugin/evm/vm_test.go        |  18 +++
 scripts/versions.sh          |   2 +-
 7 files changed, 240 insertions(+), 184 deletions(-)

diff --git a/go.mod b/go.mod
index 9cd0967481..ad84ba1477 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.20
 
 require (
 	github.com/VictoriaMetrics/fastcache v1.10.0
-	github.com/ava-labs/avalanchego v1.10.18-rc.0
+	github.com/ava-labs/avalanchego v1.10.18-0.20231212085650-4df2d3f2f052
 	github.com/cespare/cp v0.1.0
 	github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811
 	github.com/davecgh/go-spew v1.1.1
diff --git a/go.sum b/go.sum
index a6e1835c60..aa0c899210 100644
--- a/go.sum
+++ b/go.sum
@@ -55,8 +55,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah
 github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/ava-labs/avalanchego v1.10.18-rc.0 h1:8tsu5qB/Fp5NFZuJQR48q6wMHGJxGfzvlGxvxdnjg6o=
-github.com/ava-labs/avalanchego v1.10.18-rc.0/go.mod h1:ZbZteX1xINA3U31/akSGO/ZrcVAA7V6tDle0ENJ3DPI=
+github.com/ava-labs/avalanchego v1.10.18-0.20231212085650-4df2d3f2f052 h1:JQTyutUtLRairI/DI99LG9dJNcfM7v0nn2+qg9718gM=
+github.com/ava-labs/avalanchego v1.10.18-0.20231212085650-4df2d3f2f052/go.mod h1:npeYlspwYFUNHgCcm7vEjvsHQilLy3ymtSGJ4iZSRto=
 github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
diff --git a/peer/network_test.go b/peer/network_test.go
index c077e7736a..5c4820cb08 100644
--- a/peer/network_test.go
+++ b/peer/network_test.go
@@ -814,17 +814,9 @@ func TestNetworkCrossChainAppRequestAfterShutdown(t *testing.T) {
 
 func TestNetworkRouting(t *testing.T) {
 	require := require.New(t)
-	sender := &testAppSender{
-		sendAppRequestFn: func(_ context.Context, s set.Set[ids.NodeID], u uint32, bytes []byte) error {
-			return nil
-		},
-		sendAppResponseFn: func(id ids.NodeID, u uint32, bytes []byte) error {
-			return nil
-		},
-	}
 	protocol := 0
 	handler := &testSDKHandler{}
-	p2pNetwork := p2p.NewNetwork(logging.NoLog{}, sender, prometheus.NewRegistry(), "")
+	p2pNetwork := p2p.NewNetwork(logging.NoLog{}, &p2p.FakeSender{}, prometheus.NewRegistry(), "")
 	_, err := p2pNetwork.NewAppProtocol(uint64(protocol), handler)
 	require.NoError(err)
 
diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go
index 92bd3951a0..cabc7dfde9 100644
--- a/plugin/evm/tx_gossip_test.go
+++ b/plugin/evm/tx_gossip_test.go
@@ -10,62 +10,90 @@ import (
 	"testing"
 	"time"
 
+	"github.com/ava-labs/avalanchego/chains/atomic"
+	"github.com/ava-labs/avalanchego/database/memdb"
 	"github.com/ava-labs/avalanchego/ids"
 	"github.com/ava-labs/avalanchego/network/p2p"
 	"github.com/ava-labs/avalanchego/network/p2p/gossip"
 	"github.com/ava-labs/avalanchego/proto/pb/sdk"
+	"github.com/ava-labs/avalanchego/snow"
 	"github.com/ava-labs/avalanchego/snow/engine/common"
 	"github.com/ava-labs/avalanchego/snow/validators"
 	"github.com/ava-labs/avalanchego/utils"
 	"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
 	"github.com/ava-labs/avalanchego/utils/logging"
 	"github.com/ava-labs/avalanchego/utils/set"
+	"github.com/ava-labs/avalanchego/vms/components/avax"
+	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/stretchr/testify/require"
 
 	"google.golang.org/protobuf/proto"
 
-	"github.com/ava-labs/coreth/core"
 	"github.com/ava-labs/coreth/core/types"
 	"github.com/ava-labs/coreth/params"
 )
 
 func TestEthTxGossip(t *testing.T) {
 	require := require.New(t)
+	ctx := context.Background()
+	snowCtx := snow.DefaultContextTest()
+	validatorState := &validators.TestState{}
+	snowCtx.ValidatorState = validatorState
 
-	// set up prefunded address
-	importAmount := uint64(1_000_000_000)
-	issuer, vm, _, _, sender := GenesisVMWithUTXOs(t, true, genesisJSONLatest, "", "", map[ids.ShortID]uint64{
-		testShortIDAddrs[0]: importAmount,
-	})
-	defer func() {
-		require.NoError(vm.Shutdown(context.Background()))
-	}()
-
-	txPoolNewHeads := make(chan core.NewTxPoolHeadEvent)
-	vm.txPool.SubscribeNewHeadEvent(txPoolNewHeads)
-
-	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*secp256k1.PrivateKey{testKeys[0]})
+	pk, err := secp256k1.NewPrivateKey()
 	require.NoError(err)
-	require.NoError(vm.mempool.AddLocalTx(importTx))
-	<-issuer
-
-	blk, err := vm.BuildBlock(context.Background())
+	address := GetEthAddress(pk)
+	genesis := newPrefundedGenesis(100_000_000_000_000_000, address)
+	genesisBytes, err := genesis.MarshalJSON()
 	require.NoError(err)
 
-	require.NoError(blk.Verify(context.Background()))
-	require.NoError(vm.SetPreference(context.Background(), blk.ID()))
-	require.NoError(blk.Accept(context.Background()))
-	<-txPoolNewHeads
+	responseSender := &p2p.FakeSender{
+		SentAppResponse: make(chan []byte, 1),
+	}
+	vm := &VM{
+		p2pSender:             responseSender,
+		atomicTxGossipHandler: &p2p.NoOpHandler{},
+		atomicTxGossiper:      &gossip.NoOpGossiper{},
+	}
+
+	require.NoError(vm.Initialize(
+		ctx,
+		snowCtx,
+		memdb.New(),
+		genesisBytes,
+		nil,
+		nil,
+		make(chan common.Message),
+		nil,
+		&common.SenderTest{},
+	))
+	require.NoError(vm.SetState(ctx, snow.NormalOp))
+
+	defer func() {
+		require.NoError(vm.Shutdown(ctx))
+	}()
 
 	// sender for the peer requesting gossip from [vm]
-	peerSender := &common.SenderTest{}
-	router := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
+	peerSender := &p2p.FakeSender{
+		SentAppRequest: make(chan []byte, 1),
+	}
+	network := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
 
-	// we're only making client requests, so we don't need a server handler
-	client, err := router.NewAppProtocol(ethTxGossipProtocol, nil)
+	client, err := network.NewAppProtocol(ethTxGossipProtocol, &p2p.NoOpHandler{})
 	require.NoError(err)
 
+	// we only accept gossip requests from validators
+	requestingNodeID := ids.GenerateTestNodeID()
+	require.NoError(vm.Network.Connected(ctx, requestingNodeID, nil))
+	validatorState.GetCurrentHeightF = func(context.Context) (uint64, error) {
+		return 0, nil
+	}
+	validatorState.GetValidatorSetF = func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) {
+		return map[ids.NodeID]*validators.GetValidatorOutput{requestingNodeID: nil}, nil
+	}
+
+	// Ask the VM for any new transactions. We should get nothing at first.
 	emptyBloomFilter, err := gossip.NewBloomFilter(txGossipBloomMaxItems, txGossipBloomFalsePositiveRate)
 	require.NoError(err)
 	emptyBloomFilterBytes, err := emptyBloomFilter.Bloom.MarshalBinary()
@@ -79,34 +107,6 @@ func TestEthTxGossip(t *testing.T) {
 	require.NoError(err)
 
 	wg := &sync.WaitGroup{}
-
-	requestingNodeID := ids.GenerateTestNodeID()
-	peerSender.SendAppRequestF = func(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, appRequestBytes []byte) error {
-		go func() {
-			require.NoError(vm.AppRequest(ctx, requestingNodeID, requestID, time.Time{}, appRequestBytes))
-		}()
-		return nil
-	}
-
-	sender.SendAppResponseF = func(ctx context.Context, nodeID ids.NodeID, requestID uint32, appResponseBytes []byte) error {
-		go func() {
-			require.NoError(router.AppResponse(ctx, nodeID, requestID, appResponseBytes))
-		}()
-		return nil
-	}
-
-	// we only accept gossip requests from validators
-	require.NoError(vm.Network.Connected(context.Background(), requestingNodeID, nil))
-	mockValidatorSet, ok := vm.ctx.ValidatorState.(*validators.TestState)
-	require.True(ok)
-	mockValidatorSet.GetCurrentHeightF = func(context.Context) (uint64, error) {
-		return 0, nil
-	}
-	mockValidatorSet.GetValidatorSetF = func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) {
-		return map[ids.NodeID]*validators.GetValidatorOutput{requestingNodeID: nil}, nil
-	}
-
-	// Ask the VM for any new transactions. We should get nothing at first.
 	wg.Add(1)
 	onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) {
 		require.NoError(err)
@@ -116,14 +116,14 @@ func TestEthTxGossip(t *testing.T) {
 		require.Empty(response.Gossip)
 		wg.Done()
 	}
-	require.NoError(client.AppRequest(context.Background(), set.Set[ids.NodeID]{vm.ctx.NodeID: struct{}{}}, requestBytes, onResponse))
+	require.NoError(client.AppRequest(ctx, set.Of(vm.ctx.NodeID), requestBytes, onResponse))
+	require.NoError(vm.AppRequest(ctx, requestingNodeID, 1, time.Time{}, <-peerSender.SentAppRequest))
+	require.NoError(network.AppResponse(ctx, snowCtx.NodeID, 1, <-responseSender.SentAppResponse))
 	wg.Wait()
 
 	// Issue a tx to the VM
-	address := testEthAddrs[0]
-	key := testKeys[0].ToECDSA()
 	tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil)
-	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), key)
+	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA())
 	require.NoError(err)
 
 	errs := vm.txPool.AddLocals([]*types.Transaction{signedTx})
@@ -148,70 +148,93 @@ func TestEthTxGossip(t *testing.T) {
 
 		wg.Done()
 	}
-	require.NoError(client.AppRequest(context.Background(), set.Set[ids.NodeID]{vm.ctx.NodeID: struct{}{}}, requestBytes, onResponse))
+	require.NoError(client.AppRequest(ctx, set.Of(vm.ctx.NodeID), requestBytes, onResponse))
+	require.NoError(vm.AppRequest(ctx, requestingNodeID, 3, time.Time{}, <-peerSender.SentAppRequest))
+	require.NoError(network.AppResponse(ctx, snowCtx.NodeID, 3, <-responseSender.SentAppResponse))
 	wg.Wait()
 }
 
 func TestAtomicTxGossip(t *testing.T) {
 	require := require.New(t)
+	ctx := context.Background()
+	snowCtx := snow.DefaultContextTest()
+	snowCtx.AVAXAssetID = ids.GenerateTestID()
+	snowCtx.XChainID = ids.GenerateTestID()
+	validatorState := &validators.TestState{
+		GetSubnetIDF: func(context.Context, ids.ID) (ids.ID, error) {
+			return ids.Empty, nil
+		},
+	}
+	snowCtx.ValidatorState = validatorState
+	memory := atomic.NewMemory(memdb.New())
+	snowCtx.SharedMemory = memory.NewSharedMemory(ids.Empty)
 
-	// set up prefunded address
-	importAmount := uint64(1_000_000_000)
-	issuer, vm, _, _, sender := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
-		testShortIDAddrs[0]: importAmount,
-	})
+	pk, err := secp256k1.NewPrivateKey()
+	require.NoError(err)
+	address := GetEthAddress(pk)
+	genesis := newPrefundedGenesis(100_000_000_000_000_000, address)
+	genesisBytes, err := genesis.MarshalJSON()
+	require.NoError(err)
+
+	responseSender := &p2p.FakeSender{
+		SentAppResponse: make(chan []byte, 1),
+	}
+	vm := &VM{
+		p2pSender:          responseSender,
+		ethTxGossipHandler: &p2p.NoOpHandler{},
+		ethTxGossiper:      &gossip.NoOpGossiper{},
+	}
+
+	require.NoError(vm.Initialize(
+		ctx,
+		snowCtx,
+		memdb.New(),
+		genesisBytes,
+		nil,
+		nil,
+		make(chan common.Message),
+		nil,
+		&common.SenderTest{},
+	))
+	require.NoError(vm.SetState(ctx, snow.NormalOp))
 
 	defer func() {
-		require.NoError(vm.Shutdown(context.Background()))
+		require.NoError(vm.Shutdown(ctx))
 	}()
 
 	// sender for the peer requesting gossip from [vm]
-	peerSender := &common.SenderTest{}
+	peerSender := &p2p.FakeSender{
+		SentAppRequest: make(chan []byte, 1),
+	}
 	network := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
 
-	// we're only making client requests, so we don't need a server handler
-	client, err := network.NewAppProtocol(atomicTxGossipProtocol, nil)
+	client, err := network.NewAppProtocol(atomicTxGossipProtocol, &p2p.NoOpHandler{})
 	require.NoError(err)
 
+	// we only accept gossip requests from validators
+	requestingNodeID := ids.GenerateTestNodeID()
+	require.NoError(vm.Network.Connected(ctx, requestingNodeID, nil))
+	validatorState.GetCurrentHeightF = func(context.Context) (uint64, error) {
+		return 0, nil
+	}
+	validatorState.GetValidatorSetF = func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) {
+		return map[ids.NodeID]*validators.GetValidatorOutput{requestingNodeID: nil}, nil
+	}
+
+	// Ask the VM for any new transactions. We should get nothing at first.
 	emptyBloomFilter, err := gossip.NewBloomFilter(txGossipBloomMaxItems, txGossipBloomFalsePositiveRate)
 	require.NoError(err)
-	bloomBytes, err := emptyBloomFilter.Bloom.MarshalBinary()
+	emptyBloomFilterBytes, err := emptyBloomFilter.Bloom.MarshalBinary()
 	require.NoError(err)
 	request := &sdk.PullGossipRequest{
-		Filter: bloomBytes,
-		Salt:   emptyBloomFilter.Salt[:],
+		Filter: emptyBloomFilterBytes,
+		Salt:   utils.RandomBytes(32),
 	}
+
 	requestBytes, err := proto.Marshal(request)
 	require.NoError(err)
 
-	requestingNodeID := ids.GenerateTestNodeID()
 	wg := &sync.WaitGroup{}
-	peerSender.SendAppRequestF = func(ctx context.Context, _ set.Set[ids.NodeID], requestID uint32, appRequestBytes []byte) error {
-		go func() {
-			require.NoError(vm.AppRequest(ctx, requestingNodeID, requestID, time.Time{}, appRequestBytes))
-		}()
-		return nil
-	}
-
-	sender.SendAppResponseF = func(ctx context.Context, nodeID ids.NodeID, requestID uint32, appResponseBytes []byte) error {
-		go func() {
-			require.NoError(network.AppResponse(ctx, nodeID, requestID, appResponseBytes))
-		}()
-		return nil
-	}
-
-	// we only accept gossip requests from validators
-	require.NoError(vm.Network.Connected(context.Background(), requestingNodeID, nil))
-	mockValidatorSet, ok := vm.ctx.ValidatorState.(*validators.TestState)
-	require.True(ok)
-	mockValidatorSet.GetCurrentHeightF = func(context.Context) (uint64, error) {
-		return 0, nil
-	}
-	mockValidatorSet.GetValidatorSetF = func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) {
-		return map[ids.NodeID]*validators.GetValidatorOutput{requestingNodeID: nil}, nil
-	}
-
-	// Ask the VM for any new transactions. We should get nothing at first.
 	wg.Add(1)
 	onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) {
 		require.NoError(err)
@@ -221,15 +244,25 @@ func TestAtomicTxGossip(t *testing.T) {
 		require.Empty(response.Gossip)
 		wg.Done()
 	}
-	require.NoError(client.AppRequest(context.Background(), set.Set[ids.NodeID]{vm.ctx.NodeID: struct{}{}}, requestBytes, onResponse))
+	require.NoError(client.AppRequest(ctx, set.Of(vm.ctx.NodeID), requestBytes, onResponse))
+	require.NoError(vm.AppRequest(ctx, requestingNodeID, 1, time.Time{}, <-peerSender.SentAppRequest))
+	require.NoError(network.AppResponse(ctx, snowCtx.NodeID, 1, <-responseSender.SentAppResponse))
 	wg.Wait()
 
-	// issue a new tx to the vm
-	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*secp256k1.PrivateKey{testKeys[0]})
+	// Issue a tx to the VM
+	utxo, err := addUTXO(
+		memory,
+		snowCtx,
+		ids.GenerateTestID(),
+		0,
+		snowCtx.AVAXAssetID,
+		100_000_000_000,
+		pk.PublicKey().Address(),
+	)
 	require.NoError(err)
-
-	require.NoError(vm.mempool.AddLocalTx(importTx))
-	<-issuer
+	tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo})
+	require.NoError(err)
+	require.NoError(vm.mempool.AddLocalTx(tx))
 
 	// wait so we aren't throttled by the vm
 	time.Sleep(5 * time.Second)
@@ -245,10 +278,12 @@ func TestAtomicTxGossip(t *testing.T) {
 
 		gotTx := &GossipAtomicTx{}
 		require.NoError(gotTx.Unmarshal(response.Gossip[0]))
-		require.Equal(importTx.InputUTXOs(), gotTx.Tx.InputUTXOs())
+		require.Equal(tx.ID(), gotTx.GetID())
 
 		wg.Done()
 	}
-	require.NoError(client.AppRequest(context.Background(), set.Set[ids.NodeID]{vm.ctx.NodeID: struct{}{}}, requestBytes, onResponse))
+	require.NoError(client.AppRequest(ctx, set.Of(vm.ctx.NodeID), requestBytes, onResponse))
+	require.NoError(vm.AppRequest(ctx, requestingNodeID, 3, time.Time{}, <-peerSender.SentAppRequest))
+	require.NoError(network.AppResponse(ctx, snowCtx.NodeID, 3, <-responseSender.SentAppResponse))
 	wg.Wait()
 }
diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go
index 8049a8ef84..fcc26e1c78 100644
--- a/plugin/evm/vm.go
+++ b/plugin/evm/vm.go
@@ -343,6 +343,12 @@ type VM struct {
 	// Avalanche Warp Messaging backend
 	// Used to serve BLS signatures of warp messages over RPC
 	warpBackend warp.Backend
+
+	p2pSender             p2p.AppSender
+	ethTxGossipHandler    p2p.Handler
+	atomicTxGossipHandler p2p.Handler
+	ethTxGossiper         gossip.Gossiper
+	atomicTxGossiper      gossip.Gossiper
 }
 
 // Codec implements the secp256k1fx interface
@@ -584,7 +590,11 @@ func (vm *VM) Initialize(
 	}
 
 	// initialize peer network
-	p2pNetwork := p2p.NewNetwork(vm.ctx.Log, appSender, vm.sdkMetrics, "p2p")
+	if vm.p2pSender == nil {
+		vm.p2pSender = p2p.NewSender(appSender)
+	}
+
+	p2pNetwork := p2p.NewNetwork(vm.ctx.Log, vm.p2pSender, vm.sdkMetrics, "p2p")
 	vm.validators = p2p.NewValidators(p2pNetwork.Peers, vm.ctx.Log, vm.ctx.SubnetID, vm.ctx.ValidatorState, maxValidatorSetStaleness)
 	vm.networkCodec = message.Codec
 	vm.Network = peer.NewNetwork(p2pNetwork, appSender, vm.networkCodec, message.CrossChainCodec, chainCtx.NodeID, vm.config.MaxOutboundActiveRequests, vm.config.MaxOutboundActiveCrossChainRequests)
@@ -1068,94 +1078,95 @@ func (vm *VM) initBlockBuilding() error {
 		vm.shutdownWg.Done()
 	}()
 
-	var (
-		ethTxGossipHandler    p2p.Handler
-		atomicTxGossipHandler p2p.Handler
-	)
+	if vm.ethTxGossipHandler == nil {
+		vm.ethTxGossipHandler, err = gossip.NewHandler[*GossipEthTx](ethTxPool, ethTxGossipHandlerConfig, vm.sdkMetrics)
+		if err != nil {
+			return err
+		}
 
-	ethTxGossipHandler, err = gossip.NewHandler[*GossipEthTx](ethTxPool, ethTxGossipHandlerConfig, vm.sdkMetrics)
-	if err != nil {
-		return err
-	}
-	ethTxGossipHandler = &p2p.ValidatorHandler{
-		ValidatorSet: vm.validators,
-		Handler: &p2p.ThrottlerHandler{
-			Handler:   ethTxGossipHandler,
-			Throttler: p2p.NewSlidingWindowThrottler(throttlingPeriod, throttlingLimit),
-			Log:       vm.ctx.Log,
-		},
-		Log: vm.ctx.Log,
+		vm.ethTxGossipHandler = &p2p.ValidatorHandler{
+			ValidatorSet: vm.validators,
+			Handler: &p2p.ThrottlerHandler{
+				Handler:   vm.ethTxGossipHandler,
+				Throttler: p2p.NewSlidingWindowThrottler(throttlingPeriod, throttlingLimit),
+				Log:       vm.ctx.Log,
+			},
+			Log: vm.ctx.Log,
+		}
 	}
-	ethTxGossipClient, err := vm.Network.NewAppProtocol(ethTxGossipProtocol, ethTxGossipHandler, p2p.WithValidatorSampling(vm.validators))
+	ethTxGossipClient, err := vm.Network.NewAppProtocol(ethTxGossipProtocol, vm.ethTxGossipHandler, p2p.WithValidatorSampling(vm.validators))
 	if err != nil {
 		return err
 	}
 
-	atomicTxGossipHandler, err = gossip.NewHandler[*GossipAtomicTx](vm.mempool, atomicTxGossipHandlerConfig, vm.sdkMetrics)
-	if err != nil {
-		return err
-	}
+	if vm.atomicTxGossipHandler == nil {
+		vm.atomicTxGossipHandler, err = gossip.NewHandler[*GossipAtomicTx](vm.mempool, atomicTxGossipHandlerConfig, vm.sdkMetrics)
+		if err != nil {
+			return err
+		}
 
-	atomicTxGossipHandler = &p2p.ValidatorHandler{
-		ValidatorSet: vm.validators,
-		Handler: &p2p.ThrottlerHandler{
-			Throttler: p2p.NewSlidingWindowThrottler(throttlingPeriod, throttlingLimit),
-			Handler:   atomicTxGossipHandler,
-			Log:       vm.ctx.Log,
-		},
-		Log: vm.ctx.Log,
+		vm.atomicTxGossipHandler = &p2p.ValidatorHandler{
+			ValidatorSet: vm.validators,
+			Handler: &p2p.ThrottlerHandler{
+				Throttler: p2p.NewSlidingWindowThrottler(throttlingPeriod, throttlingLimit),
+				Handler:   vm.atomicTxGossipHandler,
+				Log:       vm.ctx.Log,
+			},
+			Log: vm.ctx.Log,
+		}
 	}
 
-	atomicTxGossipClient, err := vm.Network.NewAppProtocol(atomicTxGossipProtocol, atomicTxGossipHandler, p2p.WithValidatorSampling(vm.validators))
+	atomicTxGossipClient, err := vm.Network.NewAppProtocol(atomicTxGossipProtocol, vm.atomicTxGossipHandler, p2p.WithValidatorSampling(vm.validators))
 	if err != nil {
 		return err
 	}
 
-	var (
-		ethTxGossiper    gossip.Gossiper
-		atomicTxGossiper gossip.Gossiper
-	)
-	ethTxGossiper, err = gossip.NewPullGossiper[GossipEthTx, *GossipEthTx](
-		ethTxGossipConfig,
-		vm.ctx.Log,
-		ethTxPool,
-		ethTxGossipClient,
-		vm.sdkMetrics,
-	)
-	if err != nil {
-		return err
-	}
-	ethTxGossiper = gossip.ValidatorGossiper{
-		Gossiper:   ethTxGossiper,
-		NodeID:     vm.ctx.NodeID,
-		Validators: vm.validators,
+	if vm.ethTxGossiper == nil {
+		vm.ethTxGossiper, err = gossip.NewPullGossiper[GossipEthTx, *GossipEthTx](
+			ethTxGossipConfig,
+			vm.ctx.Log,
+			ethTxPool,
+			ethTxGossipClient,
+			vm.sdkMetrics,
+		)
+		if err != nil {
+			return err
+		}
+
+		vm.ethTxGossiper = gossip.ValidatorGossiper{
+			Gossiper:   vm.ethTxGossiper,
+			NodeID:     vm.ctx.NodeID,
+			Validators: vm.validators,
+		}
 	}
 
 	vm.shutdownWg.Add(1)
 	go func() {
-		gossip.Every(ctx, vm.ctx.Log, ethTxGossiper, gossipFrequency)
+		gossip.Every(ctx, vm.ctx.Log, vm.ethTxGossiper, gossipFrequency)
 		vm.shutdownWg.Done()
 	}()
 
-	atomicTxGossiper, err = gossip.NewPullGossiper[GossipAtomicTx, *GossipAtomicTx](
-		atomicTxGossipConfig,
-		vm.ctx.Log,
-		vm.mempool,
-		atomicTxGossipClient,
-		vm.sdkMetrics,
-	)
-	if err != nil {
-		return err
-	}
-	atomicTxGossiper = gossip.ValidatorGossiper{
-		Gossiper:   atomicTxGossiper,
-		NodeID:     vm.ctx.NodeID,
-		Validators: vm.validators,
+	if vm.atomicTxGossiper == nil {
+		vm.atomicTxGossiper, err = gossip.NewPullGossiper[GossipAtomicTx, *GossipAtomicTx](
+			atomicTxGossipConfig,
+			vm.ctx.Log,
+			vm.mempool,
+			atomicTxGossipClient,
+			vm.sdkMetrics,
+		)
+		if err != nil {
+			return err
+		}
+		vm.atomicTxGossiper = gossip.ValidatorGossiper{
+			Gossiper:   vm.atomicTxGossiper,
+			NodeID:     vm.ctx.NodeID,
+			Validators: vm.validators,
+		}
 	}
 
 	vm.shutdownWg.Add(1)
 	go func() {
-		gossip.Every(ctx, vm.ctx.Log, atomicTxGossiper, gossipFrequency)
+		gossip.Every(ctx, vm.ctx.Log, vm.atomicTxGossiper, gossipFrequency)
 		vm.shutdownWg.Done()
 	}()
 
diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go
index 0ba3b17c87..0f4dea63e9 100644
--- a/plugin/evm/vm_test.go
+++ b/plugin/evm/vm_test.go
@@ -126,6 +126,24 @@ func init() {
 	}
 }
 
+func newPrefundedGenesis(
+	balance int,
+	addresses ...common.Address,
+) *core.Genesis {
+	alloc := core.GenesisAlloc{}
+	for _, address := range addresses {
+		alloc[address] = core.GenesisAccount{
+			Balance: big.NewInt(int64(balance)),
+		}
+	}
+
+	return &core.Genesis{
+		Config:     params.TestChainConfig,
+		Difficulty: big.NewInt(0),
+		Alloc:      alloc,
+	}
+}
+
 // BuildGenesisTest returns the genesis bytes for Coreth VM to be used in testing
 func BuildGenesisTest(t *testing.T, genesisJSON string) []byte {
 	ss := StaticService{}
diff --git a/scripts/versions.sh b/scripts/versions.sh
index 89f15a1d24..76fbe3a455 100644
--- a/scripts/versions.sh
+++ b/scripts/versions.sh
@@ -1,4 +1,4 @@
 #!/usr/bin/env bash
 
 # Don't export them as they're used in the context of other calls
-avalanche_version=${AVALANCHE_VERSION:-'v1.10.18-rc.0'}
+avalanche_version=${AVALANCHE_VERSION:-'sender-refactor'}

From c936826875a21e0de3090f358bd2bd9d15ef0550 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Tue, 12 Dec 2023 13:46:00 -0500
Subject: [PATCH 02/11] nit

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 go.mod                       | 2 +-
 go.sum                       | 4 ++--
 peer/network_test.go         | 2 +-
 plugin/evm/tx_gossip_test.go | 8 ++++----
 plugin/evm/vm.go             | 4 ++--
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/go.mod b/go.mod
index ad84ba1477..abe6f0a38a 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.20
 
 require (
 	github.com/VictoriaMetrics/fastcache v1.10.0
-	github.com/ava-labs/avalanchego v1.10.18-0.20231212085650-4df2d3f2f052
+	github.com/ava-labs/avalanchego v1.10.18-0.20231212183827-1578bb29776c
 	github.com/cespare/cp v0.1.0
 	github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811
 	github.com/davecgh/go-spew v1.1.1
diff --git a/go.sum b/go.sum
index aa0c899210..f5838abe1b 100644
--- a/go.sum
+++ b/go.sum
@@ -55,8 +55,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah
 github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/ava-labs/avalanchego v1.10.18-0.20231212085650-4df2d3f2f052 h1:JQTyutUtLRairI/DI99LG9dJNcfM7v0nn2+qg9718gM=
-github.com/ava-labs/avalanchego v1.10.18-0.20231212085650-4df2d3f2f052/go.mod h1:npeYlspwYFUNHgCcm7vEjvsHQilLy3ymtSGJ4iZSRto=
+github.com/ava-labs/avalanchego v1.10.18-0.20231212183827-1578bb29776c h1:ZD58N48KMzpPzhtVCp8h8kxS93XxlkDXmxIO4+I+mrc=
+github.com/ava-labs/avalanchego v1.10.18-0.20231212183827-1578bb29776c/go.mod h1:npeYlspwYFUNHgCcm7vEjvsHQilLy3ymtSGJ4iZSRto=
 github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
diff --git a/peer/network_test.go b/peer/network_test.go
index 5c4820cb08..b50bcac6a7 100644
--- a/peer/network_test.go
+++ b/peer/network_test.go
@@ -816,7 +816,7 @@ func TestNetworkRouting(t *testing.T) {
 	require := require.New(t)
 	protocol := 0
 	handler := &testSDKHandler{}
-	p2pNetwork := p2p.NewNetwork(logging.NoLog{}, &p2p.FakeSender{}, prometheus.NewRegistry(), "")
+	p2pNetwork := p2p.NewNetwork(logging.NoLog{}, &common.FakeSender{}, prometheus.NewRegistry(), "")
 	_, err := p2pNetwork.NewAppProtocol(uint64(protocol), handler)
 	require.NoError(err)
 
diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go
index cabc7dfde9..99390ee299 100644
--- a/plugin/evm/tx_gossip_test.go
+++ b/plugin/evm/tx_gossip_test.go
@@ -48,7 +48,7 @@ func TestEthTxGossip(t *testing.T) {
 	genesisBytes, err := genesis.MarshalJSON()
 	require.NoError(err)
 
-	responseSender := &p2p.FakeSender{
+	responseSender := &common.FakeSender{
 		SentAppResponse: make(chan []byte, 1),
 	}
 	vm := &VM{
@@ -75,7 +75,7 @@ func TestEthTxGossip(t *testing.T) {
 	}()
 
 	// sender for the peer requesting gossip from [vm]
-	peerSender := &p2p.FakeSender{
+	peerSender := &common.FakeSender{
 		SentAppRequest: make(chan []byte, 1),
 	}
 	network := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
@@ -176,7 +176,7 @@ func TestAtomicTxGossip(t *testing.T) {
 	genesisBytes, err := genesis.MarshalJSON()
 	require.NoError(err)
 
-	responseSender := &p2p.FakeSender{
+	responseSender := &common.FakeSender{
 		SentAppResponse: make(chan []byte, 1),
 	}
 	vm := &VM{
@@ -203,7 +203,7 @@ func TestAtomicTxGossip(t *testing.T) {
 	}()
 
 	// sender for the peer requesting gossip from [vm]
-	peerSender := &p2p.FakeSender{
+	peerSender := &common.FakeSender{
 		SentAppRequest: make(chan []byte, 1),
 	}
 	network := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go
index fcc26e1c78..837c940891 100644
--- a/plugin/evm/vm.go
+++ b/plugin/evm/vm.go
@@ -344,7 +344,7 @@ type VM struct {
 	// Used to serve BLS signatures of warp messages over RPC
 	warpBackend warp.Backend
 
-	p2pSender             p2p.AppSender
+	p2pSender             commonEng.AppSender
 	ethTxGossipHandler    p2p.Handler
 	atomicTxGossipHandler p2p.Handler
 	ethTxGossiper         gossip.Gossiper
@@ -591,7 +591,7 @@ func (vm *VM) Initialize(
 
 	// initialize peer network
 	if vm.p2pSender == nil {
-		vm.p2pSender = p2p.NewSender(appSender)
+		vm.p2pSender = appSender
 	}
 
 	p2pNetwork := p2p.NewNetwork(vm.ctx.Log, vm.p2pSender, vm.sdkMetrics, "p2p")

From d8cab34563a93d81dc53ea80a5ed509681ce0d0e Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Tue, 12 Dec 2023 13:50:14 -0500
Subject: [PATCH 03/11] nit

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 peer/network_test.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/peer/network_test.go b/peer/network_test.go
index b50bcac6a7..5f2d7318e6 100644
--- a/peer/network_test.go
+++ b/peer/network_test.go
@@ -425,6 +425,7 @@ func TestRequestMinVersion(t *testing.T) {
 	responseBytes, _, err := client.SendAppRequestAny(
 		context.Background(),
 		&version.Application{
+			Name:  "avalanche",
 			Major: 2,
 			Minor: 0,
 			Patch: 0,

From 7cc3b6864db9e8d5937e47bb7a7c0fd6ef410451 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Tue, 12 Dec 2023 13:50:42 -0500
Subject: [PATCH 04/11] nit

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 scripts/versions.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/versions.sh b/scripts/versions.sh
index 76fbe3a455..acdcddf94f 100644
--- a/scripts/versions.sh
+++ b/scripts/versions.sh
@@ -1,4 +1,4 @@
 #!/usr/bin/env bash
 
 # Don't export them as they're used in the context of other calls
-avalanche_version=${AVALANCHE_VERSION:-'sender-refactor'}
+avalanche_version=${AVALANCHE_VERSION:-'1578bb2'}

From 55f9a36953e250f50b3fa9cad281d2a6e6b2b3b7 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Tue, 12 Dec 2023 16:19:59 -0500
Subject: [PATCH 05/11] nit

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 plugin/evm/vm.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go
index 837c940891..2c3f9a33fb 100644
--- a/plugin/evm/vm.go
+++ b/plugin/evm/vm.go
@@ -344,6 +344,7 @@ type VM struct {
 	// Used to serve BLS signatures of warp messages over RPC
 	warpBackend warp.Backend
 
+	// Can be overridden in unit tests
 	p2pSender             commonEng.AppSender
 	ethTxGossipHandler    p2p.Handler
 	atomicTxGossipHandler p2p.Handler

From f9ec2ecc2714cd8870745b954f31920e074167a3 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Tue, 12 Dec 2023 17:04:37 -0500
Subject: [PATCH 06/11] nit

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 go.mod                      | 2 +-
 go.sum                      | 4 ++--
 peer/network.go             | 6 +++---
 peer/network_test.go        | 2 +-
 plugin/evm/syncervm_test.go | 2 +-
 scripts/versions.sh         | 2 +-
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/go.mod b/go.mod
index abe6f0a38a..e478779e0e 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.20
 
 require (
 	github.com/VictoriaMetrics/fastcache v1.10.0
-	github.com/ava-labs/avalanchego v1.10.18-0.20231212183827-1578bb29776c
+	github.com/ava-labs/avalanchego v1.10.18-0.20231212215606-cb0f72d18f35
 	github.com/cespare/cp v0.1.0
 	github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811
 	github.com/davecgh/go-spew v1.1.1
diff --git a/go.sum b/go.sum
index f5838abe1b..52546947ca 100644
--- a/go.sum
+++ b/go.sum
@@ -55,8 +55,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah
 github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/ava-labs/avalanchego v1.10.18-0.20231212183827-1578bb29776c h1:ZD58N48KMzpPzhtVCp8h8kxS93XxlkDXmxIO4+I+mrc=
-github.com/ava-labs/avalanchego v1.10.18-0.20231212183827-1578bb29776c/go.mod h1:npeYlspwYFUNHgCcm7vEjvsHQilLy3ymtSGJ4iZSRto=
+github.com/ava-labs/avalanchego v1.10.18-0.20231212215606-cb0f72d18f35 h1:arKzZnblbQiFWUZ9QDiVxLtDQkkgCiXJknw09NYOaJk=
+github.com/ava-labs/avalanchego v1.10.18-0.20231212215606-cb0f72d18f35/go.mod h1:Nipo+jZEKDO8DgE5Z2IytDeplsT61DzvYQHhZoBqCG4=
 github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
diff --git a/peer/network.go b/peer/network.go
index f59783b751..dfad0bd790 100644
--- a/peer/network.go
+++ b/peer/network.go
@@ -280,7 +280,7 @@ func (n *network) CrossChainAppRequest(ctx context.Context, requestingChainID id
 // - request times out before a response is provided
 // If [requestID] is not known, this function will emit a log and return a nil error.
 // If the response handler returns an error it is propagated as a fatal error.
-func (n *network) CrossChainAppRequestFailed(ctx context.Context, respondingChainID ids.ID, requestID uint32) error {
+func (n *network) CrossChainAppRequestFailed(ctx context.Context, respondingChainID ids.ID, requestID uint32, _ *common.AppError) error {
 	log.Debug("received CrossChainAppRequestFailed from chain", "respondingChainID", respondingChainID, "requestID", requestID)
 
 	handler, exists := n.markRequestFulfilled(requestID)
@@ -382,13 +382,13 @@ func (n *network) AppResponse(ctx context.Context, nodeID ids.NodeID, requestID
 // - request times out before a response is provided
 // error returned by this function is expected to be treated as fatal by the engine
 // returns error only when the response handler returns an error
-func (n *network) AppRequestFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32) error {
+func (n *network) AppRequestFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32, appErr *common.AppError) error {
 	log.Debug("received AppRequestFailed from peer", "nodeID", nodeID, "requestID", requestID)
 
 	handler, exists := n.markRequestFulfilled(requestID)
 	if !exists {
 		log.Debug("forwarding AppRequestFailed to SDK network", "nodeID", nodeID, "requestID", requestID)
-		return n.network.AppRequestFailed(ctx, nodeID, requestID)
+		return n.network.AppRequestFailed(ctx, nodeID, requestID, appErr)
 	}
 
 	// We must release the slot
diff --git a/peer/network_test.go b/peer/network_test.go
index 5f2d7318e6..fec3d10144 100644
--- a/peer/network_test.go
+++ b/peer/network_test.go
@@ -843,7 +843,7 @@ func TestNetworkRouting(t *testing.T) {
 	err = network.AppResponse(context.Background(), ids.GenerateTestNodeID(), 0, foobar)
 	require.ErrorIs(err, p2p.ErrUnrequestedResponse)
 
-	err = network.AppRequestFailed(context.Background(), nodeID, 0)
+	err = network.AppRequestFailed(context.Background(), nodeID, 0, common.ErrTimeout)
 	require.ErrorIs(err, p2p.ErrUnrequestedResponse)
 }
 
diff --git a/plugin/evm/syncervm_test.go b/plugin/evm/syncervm_test.go
index 66923153fb..dd35759a3c 100644
--- a/plugin/evm/syncervm_test.go
+++ b/plugin/evm/syncervm_test.go
@@ -91,7 +91,7 @@ func TestStateSyncToggleEnabledToDisabled(t *testing.T) {
 			reqCount++
 			// Fail all requests after number 50 to interrupt the sync
 			if reqCount > 50 {
-				if err := syncerVM.AppRequestFailed(context.Background(), nodeID, requestID); err != nil {
+				if err := syncerVM.AppRequestFailed(context.Background(), nodeID, requestID, commonEng.ErrTimeout); err != nil {
 					panic(err)
 				}
 				cancel := syncerVM.StateSyncClient.(*stateSyncerClient).cancel
diff --git a/scripts/versions.sh b/scripts/versions.sh
index acdcddf94f..3fe865b03c 100644
--- a/scripts/versions.sh
+++ b/scripts/versions.sh
@@ -1,4 +1,4 @@
 #!/usr/bin/env bash
 
 # Don't export them as they're used in the context of other calls
-avalanche_version=${AVALANCHE_VERSION:-'1578bb2'}
+avalanche_version=${AVALANCHE_VERSION:-'cb0f72d'}

From 1c67c383292a173589aa2c8ef1b30247e5838a51 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Tue, 12 Dec 2023 19:46:14 -0500
Subject: [PATCH 07/11] nit

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 peer/network_test.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/peer/network_test.go b/peer/network_test.go
index fec3d10144..8484ae9dc1 100644
--- a/peer/network_test.go
+++ b/peer/network_test.go
@@ -425,7 +425,7 @@ func TestRequestMinVersion(t *testing.T) {
 	responseBytes, _, err := client.SendAppRequestAny(
 		context.Background(),
 		&version.Application{
-			Name:  "avalanche",
+			Name:  version.LegacyAppName,
 			Major: 2,
 			Minor: 0,
 			Patch: 0,

From ce28e4973b4d8c43dfbc34d3ed9f63e97e852adb Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Wed, 13 Dec 2023 09:44:19 -0500
Subject: [PATCH 08/11] Squashed commit of the following:

commit 056800c7179e7c87818e294659f1735caffff97f
Author: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date:   Wed Dec 13 00:28:59 2023 -0500

    Update to new SDK API (#421)

commit 42db2c2b17b4b6de75610cb7157695d8959b530f
Author: Ceyhun Onur <ceyhun.onur@avalabs.org>
Date:   Tue Dec 12 19:05:37 2023 +0300

    show strings in pointers (#414)

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 go.mod                       |  2 +-
 go.sum                       |  4 +-
 params/config.go             | 33 ++++++++++-------
 peer/network.go              | 29 +++++++++------
 peer/network_test.go         | 71 ++++++++++++++++++++++++++----------
 plugin/evm/tx_gossip_test.go | 10 ++---
 plugin/evm/vm.go             | 70 +++++++++++++++++++----------------
 scripts/versions.sh          |  2 +-
 8 files changed, 134 insertions(+), 87 deletions(-)

diff --git a/go.mod b/go.mod
index e478779e0e..6709bd2e0f 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.20
 
 require (
 	github.com/VictoriaMetrics/fastcache v1.10.0
-	github.com/ava-labs/avalanchego v1.10.18-0.20231212215606-cb0f72d18f35
+	github.com/ava-labs/avalanchego v1.10.18-rc.2
 	github.com/cespare/cp v0.1.0
 	github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811
 	github.com/davecgh/go-spew v1.1.1
diff --git a/go.sum b/go.sum
index 52546947ca..e0f2a4960c 100644
--- a/go.sum
+++ b/go.sum
@@ -55,8 +55,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah
 github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/ava-labs/avalanchego v1.10.18-0.20231212215606-cb0f72d18f35 h1:arKzZnblbQiFWUZ9QDiVxLtDQkkgCiXJknw09NYOaJk=
-github.com/ava-labs/avalanchego v1.10.18-0.20231212215606-cb0f72d18f35/go.mod h1:Nipo+jZEKDO8DgE5Z2IytDeplsT61DzvYQHhZoBqCG4=
+github.com/ava-labs/avalanchego v1.10.18-rc.2 h1:fjks/pUp7HmGzjupl+f3MfGo5cLkCrDnoCarL8NyqlA=
+github.com/ava-labs/avalanchego v1.10.18-rc.2/go.mod h1:D0tP5nGZtGb/vNOzvROUGUER+Gcar73l9qP97vbEarY=
 github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
diff --git a/params/config.go b/params/config.go
index 6b362c14de..c62aa40652 100644
--- a/params/config.go
+++ b/params/config.go
@@ -581,18 +581,18 @@ func (c *ChainConfig) Description() string {
 	if c.MuirGlacierBlock != nil {
 		banner += fmt.Sprintf(" - Muir Glacier:                #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md)\n", c.MuirGlacierBlock)
 	}
-	banner += fmt.Sprintf(" - Apricot Phase 1 Timestamp:        #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.3.0)\n", c.ApricotPhase1BlockTimestamp)
-	banner += fmt.Sprintf(" - Apricot Phase 2 Timestamp:        #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.4.0)\n", c.ApricotPhase2BlockTimestamp)
-	banner += fmt.Sprintf(" - Apricot Phase 3 Timestamp:        #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.5.0)\n", c.ApricotPhase3BlockTimestamp)
-	banner += fmt.Sprintf(" - Apricot Phase 4 Timestamp:        #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.6.0)\n", c.ApricotPhase4BlockTimestamp)
-	banner += fmt.Sprintf(" - Apricot Phase 5 Timestamp:        #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.7.0)\n", c.ApricotPhase5BlockTimestamp)
-	banner += fmt.Sprintf(" - Apricot Phase P6 Timestamp        #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.8.0)\n", c.ApricotPhasePre6BlockTimestamp)
-	banner += fmt.Sprintf(" - Apricot Phase 6 Timestamp:        #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.8.0)\n", c.ApricotPhase6BlockTimestamp)
-	banner += fmt.Sprintf(" - Apricot Phase Post-6 Timestamp:   #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.8.0\n", c.ApricotPhasePost6BlockTimestamp)
-	banner += fmt.Sprintf(" - Banff Timestamp:                  #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.9.0)\n", c.BanffBlockTimestamp)
-	banner += fmt.Sprintf(" - Cortina Timestamp:                #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.10.0)\n", c.CortinaBlockTimestamp)
-	banner += fmt.Sprintf(" - DUpgrade Timestamp:               #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.11.0)\n", c.DUpgradeBlockTimestamp)
-	banner += fmt.Sprintf(" - Cancun Timestamp:                 #%-8v (https://github.com/ava-labs/avalanchego/releases/tag/v1.12.0)\n", c.CancunTime)
+	banner += fmt.Sprintf(" - Apricot Phase 1 Timestamp:        @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.3.0)\n", ptrToString(c.ApricotPhase1BlockTimestamp))
+	banner += fmt.Sprintf(" - Apricot Phase 2 Timestamp:        @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.4.0)\n", ptrToString(c.ApricotPhase2BlockTimestamp))
+	banner += fmt.Sprintf(" - Apricot Phase 3 Timestamp:        @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.5.0)\n", ptrToString(c.ApricotPhase3BlockTimestamp))
+	banner += fmt.Sprintf(" - Apricot Phase 4 Timestamp:        @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.6.0)\n", ptrToString(c.ApricotPhase4BlockTimestamp))
+	banner += fmt.Sprintf(" - Apricot Phase 5 Timestamp:        @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.7.0)\n", ptrToString(c.ApricotPhase5BlockTimestamp))
+	banner += fmt.Sprintf(" - Apricot Phase P6 Timestamp        @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.8.0)\n", ptrToString(c.ApricotPhasePre6BlockTimestamp))
+	banner += fmt.Sprintf(" - Apricot Phase 6 Timestamp:        @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.8.0)\n", ptrToString(c.ApricotPhase6BlockTimestamp))
+	banner += fmt.Sprintf(" - Apricot Phase Post-6 Timestamp:   @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.8.0\n", ptrToString(c.ApricotPhasePost6BlockTimestamp))
+	banner += fmt.Sprintf(" - Banff Timestamp:                  @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.9.0)\n", ptrToString(c.BanffBlockTimestamp))
+	banner += fmt.Sprintf(" - Cortina Timestamp:                @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.10.0)\n", ptrToString(c.CortinaBlockTimestamp))
+	banner += fmt.Sprintf(" - DUpgrade Timestamp:               @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.11.0)\n", ptrToString(c.DUpgradeBlockTimestamp))
+	banner += fmt.Sprintf(" - Cancun Timestamp:                 @%-10v (https://github.com/ava-labs/avalanchego/releases/tag/v1.12.0)\n", ptrToString(c.CancunTime))
 	banner += "\n"
 	return banner
 }
@@ -1042,7 +1042,14 @@ func (err *ConfigCompatError) Error() string {
 	if err.StoredBlock != nil {
 		return fmt.Sprintf("mismatching %s in database (have block %d, want block %d, rewindto block %d)", err.What, err.StoredBlock, err.NewBlock, err.RewindToBlock)
 	}
-	return fmt.Sprintf("mismatching %s in database (have timestamp %d, want timestamp %d, rewindto timestamp %d)", err.What, err.StoredTime, err.NewTime, err.RewindToTime)
+	return fmt.Sprintf("mismatching %s in database (have timestamp %s, want timestamp %s, rewindto timestamp %d)", err.What, ptrToString(err.StoredTime), ptrToString(err.NewTime), err.RewindToTime)
+}
+
+func ptrToString(val *uint64) string {
+	if val == nil {
+		return "nil"
+	}
+	return fmt.Sprintf("%d", *val)
 }
 
 // Rules wraps ChainConfig and is merely syntactic sugar or can be used for functions
diff --git a/peer/network.go b/peer/network.go
index dfad0bd790..904001b106 100644
--- a/peer/network.go
+++ b/peer/network.go
@@ -78,9 +78,10 @@ type Network interface {
 	// (length of response divided by request time), and with 0 if the response is invalid.
 	TrackBandwidth(nodeID ids.NodeID, bandwidth float64)
 
-	// NewAppProtocol reserves a protocol identifier and returns a corresponding
-	// client to send messages with
-	NewAppProtocol(protocol uint64, handler p2p.Handler, options ...p2p.ClientOption) (*p2p.Client, error)
+	// NewClient returns a client to send messages with for the given protocol
+	NewClient(protocol uint64, options ...p2p.ClientOption) *p2p.Client
+	// AddHandler registers a server handler for an application protocol
+	AddHandler(protocol uint64, handler p2p.Handler) error
 }
 
 // network is an implementation of Network that processes message requests for
@@ -92,7 +93,7 @@ type network struct {
 	outstandingRequestHandlers map[uint32]message.ResponseHandler // maps avalanchego requestID => message.ResponseHandler
 	activeAppRequests          *semaphore.Weighted                // controls maximum number of active outbound requests
 	activeCrossChainRequests   *semaphore.Weighted                // controls maximum number of active outbound cross chain requests
-	network                    *p2p.Network
+	p2pNetwork                 *p2p.Network
 	appSender                  common.AppSender                 // avalanchego AppSender for sending messages
 	codec                      codec.Manager                    // Codec used for parsing messages
 	crossChainCodec            codec.Manager                    // Codec used for parsing cross chain messages
@@ -123,7 +124,7 @@ func NewNetwork(p2pNetwork *p2p.Network, appSender common.AppSender, codec codec
 		outstandingRequestHandlers: make(map[uint32]message.ResponseHandler),
 		activeAppRequests:          semaphore.NewWeighted(maxActiveAppRequests),
 		activeCrossChainRequests:   semaphore.NewWeighted(maxActiveCrossChainRequests),
-		network:                    p2pNetwork,
+		p2pNetwork:                 p2pNetwork,
 		gossipHandler:              message.NoopMempoolGossipHandler{},
 		appRequestHandler:          message.NoopRequestHandler{},
 		crossChainRequestHandler:   message.NoopCrossChainRequestHandler{},
@@ -331,7 +332,7 @@ func (n *network) AppRequest(ctx context.Context, nodeID ids.NodeID, requestID u
 	var req message.Request
 	if _, err := n.codec.Unmarshal(request, &req); err != nil {
 		log.Debug("forwarding AppRequest to SDK network", "nodeID", nodeID, "requestID", requestID, "requestLen", len(request), "err", err)
-		return n.network.AppRequest(ctx, nodeID, requestID, deadline, request)
+		return n.p2pNetwork.AppRequest(ctx, nodeID, requestID, deadline, request)
 	}
 
 	bufferedDeadline, err := calculateTimeUntilDeadline(deadline, n.appStats)
@@ -367,7 +368,7 @@ func (n *network) AppResponse(ctx context.Context, nodeID ids.NodeID, requestID
 	handler, exists := n.markRequestFulfilled(requestID)
 	if !exists {
 		log.Debug("forwarding AppResponse to SDK network", "nodeID", nodeID, "requestID", requestID, "responseLen", len(response))
-		return n.network.AppResponse(ctx, nodeID, requestID, response)
+		return n.p2pNetwork.AppResponse(ctx, nodeID, requestID, response)
 	}
 
 	// We must release the slot
@@ -388,7 +389,7 @@ func (n *network) AppRequestFailed(ctx context.Context, nodeID ids.NodeID, reque
 	handler, exists := n.markRequestFulfilled(requestID)
 	if !exists {
 		log.Debug("forwarding AppRequestFailed to SDK network", "nodeID", nodeID, "requestID", requestID)
-		return n.network.AppRequestFailed(ctx, nodeID, requestID, appErr)
+		return n.p2pNetwork.AppRequestFailed(ctx, nodeID, requestID, appErr)
 	}
 
 	// We must release the slot
@@ -476,7 +477,7 @@ func (n *network) Connected(ctx context.Context, nodeID ids.NodeID, nodeVersion
 	}
 
 	n.peers.Connected(nodeID, nodeVersion)
-	return n.network.Connected(ctx, nodeID, nodeVersion)
+	return n.p2pNetwork.Connected(ctx, nodeID, nodeVersion)
 }
 
 // Disconnected removes given [nodeID] from the peer list
@@ -490,7 +491,7 @@ func (n *network) Disconnected(ctx context.Context, nodeID ids.NodeID) error {
 	}
 
 	n.peers.Disconnected(nodeID)
-	return n.network.Disconnected(ctx, nodeID)
+	return n.p2pNetwork.Disconnected(ctx, nodeID)
 }
 
 // Shutdown disconnects all peers
@@ -543,8 +544,12 @@ func (n *network) TrackBandwidth(nodeID ids.NodeID, bandwidth float64) {
 	n.peers.TrackBandwidth(nodeID, bandwidth)
 }
 
-func (n *network) NewAppProtocol(protocol uint64, handler p2p.Handler, options ...p2p.ClientOption) (*p2p.Client, error) {
-	return n.network.NewAppProtocol(protocol, handler, options...)
+func (n *network) NewClient(protocol uint64, options ...p2p.ClientOption) *p2p.Client {
+	return n.p2pNetwork.NewClient(protocol, options...)
+}
+
+func (n *network) AddHandler(protocol uint64, handler p2p.Handler) error {
+	return n.p2pNetwork.AddHandler(protocol, handler)
 }
 
 // invariant: peer/network must use explicitly even request ids.
diff --git a/peer/network_test.go b/peer/network_test.go
index 8484ae9dc1..75ec24b76d 100644
--- a/peer/network_test.go
+++ b/peer/network_test.go
@@ -58,7 +58,9 @@ var (
 
 func TestNetworkDoesNotConnectToItself(t *testing.T) {
 	selfNodeID := ids.GenerateTestNodeID()
-	n := NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), nil, nil, nil, selfNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	n := NewNetwork(p2pNetwork, nil, nil, nil, selfNodeID, 1, 1)
 	assert.NoError(t, n.Connected(context.Background(), selfNodeID, defaultPeerVersion))
 	assert.EqualValues(t, 0, n.Size())
 }
@@ -94,7 +96,9 @@ func TestRequestAnyRequestsRoutingAndResponse(t *testing.T) {
 
 	codecManager := buildCodec(t, HelloRequest{}, HelloResponse{})
 	crossChainCodecManager := buildCodec(t, ExampleCrossChainRequest{}, ExampleCrossChainResponse{})
-	net = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 16, 16)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 16, 16)
 	net.SetRequestHandler(&HelloGreetingRequestHandler{codec: codecManager})
 	client := NewNetworkClient(net)
 	nodeID := ids.GenerateTestNodeID()
@@ -146,7 +150,9 @@ func TestAppRequestOnCtxCancellation(t *testing.T) {
 		},
 	}
 
-	net := NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net := NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	net.SetRequestHandler(&HelloGreetingRequestHandler{codec: codecManager})
 
 	requestMessage := HelloRequest{Message: "this is a request"}
@@ -198,7 +204,9 @@ func TestRequestRequestsRoutingAndResponse(t *testing.T) {
 
 	codecManager := buildCodec(t, HelloRequest{}, HelloResponse{})
 	crossChainCodecManager := buildCodec(t, ExampleCrossChainRequest{}, ExampleCrossChainResponse{})
-	net = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 16, 16)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 16, 16)
 	net.SetRequestHandler(&HelloGreetingRequestHandler{codec: codecManager})
 	client := NewNetworkClient(net)
 
@@ -252,7 +260,7 @@ func TestRequestRequestsRoutingAndResponse(t *testing.T) {
 	}
 
 	// ensure empty nodeID is not allowed
-	_, err := client.SendAppRequest(context.Background(), ids.EmptyNodeID, []byte("hello there"))
+	_, err = client.SendAppRequest(context.Background(), ids.EmptyNodeID, []byte("hello there"))
 	assert.Error(t, err)
 	assert.Contains(t, err.Error(), "cannot send request to empty nodeID")
 }
@@ -278,7 +286,9 @@ func TestAppRequestOnShutdown(t *testing.T) {
 
 	codecManager := buildCodec(t, HelloRequest{}, HelloResponse{})
 	crossChainCodecManager := buildCodec(t, ExampleCrossChainRequest{}, ExampleCrossChainResponse{})
-	net = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	client := NewNetworkClient(net)
 	nodeID := ids.GenerateTestNodeID()
 	require.NoError(t, net.Connected(context.Background(), nodeID, defaultPeerVersion))
@@ -327,7 +337,9 @@ func TestAppRequestAnyOnCtxCancellation(t *testing.T) {
 		},
 	}
 
-	net := NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net := NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	net.SetRequestHandler(&HelloGreetingRequestHandler{codec: codecManager})
 	assert.NoError(t,
 		net.Connected(
@@ -404,7 +416,9 @@ func TestRequestMinVersion(t *testing.T) {
 	}
 
 	// passing nil as codec works because the net.AppRequest is never called
-	net = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 16)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 16)
 	client := NewNetworkClient(net)
 	requestMessage := TestMessage{Message: "this is a request"}
 	requestBytes, err := message.RequestToBytes(codecManager, requestMessage)
@@ -414,6 +428,7 @@ func TestRequestMinVersion(t *testing.T) {
 			context.Background(),
 			nodeID,
 			&version.Application{
+				Name:  version.Client,
 				Major: 1,
 				Minor: 7,
 				Patch: 1,
@@ -425,14 +440,14 @@ func TestRequestMinVersion(t *testing.T) {
 	responseBytes, _, err := client.SendAppRequestAny(
 		context.Background(),
 		&version.Application{
-			Name:  version.LegacyAppName,
+			Name:  version.Client,
 			Major: 2,
 			Minor: 0,
 			Patch: 0,
 		},
 		requestBytes,
 	)
-	assert.Equal(t, err.Error(), "no peers found matching version avalanche/2.0.0 out of 1 peers")
+	assert.Equal(t, err.Error(), "no peers found matching version avalanchego/2.0.0 out of 1 peers")
 	assert.Nil(t, responseBytes)
 
 	// ensure version matches and the request goes through
@@ -469,7 +484,9 @@ func TestOnRequestHonoursDeadline(t *testing.T) {
 		processingDuration: 500 * time.Millisecond,
 	}
 
-	net = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	net.SetRequestHandler(requestHandler)
 	nodeID := ids.GenerateTestNodeID()
 
@@ -509,7 +526,9 @@ func TestGossip(t *testing.T) {
 	}
 
 	gossipHandler := &testGossipHandler{}
-	clientNetwork = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	clientNetwork = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	clientNetwork.SetGossipHandler(gossipHandler)
 
 	assert.NoError(t, clientNetwork.Connected(context.Background(), nodeID, defaultPeerVersion))
@@ -536,7 +555,9 @@ func TestHandleInvalidMessages(t *testing.T) {
 	requestID := uint32(1)
 	sender := testAppSender{}
 
-	clientNetwork := NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	clientNetwork := NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	clientNetwork.SetGossipHandler(message.NoopMempoolGossipHandler{})
 	clientNetwork.SetRequestHandler(&testRequestHandler{})
 
@@ -585,7 +606,9 @@ func TestNetworkPropagatesRequestHandlerError(t *testing.T) {
 	requestID := uint32(1)
 	sender := testAppSender{}
 
-	clientNetwork := NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	clientNetwork := NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	clientNetwork.SetGossipHandler(message.NoopMempoolGossipHandler{})
 	clientNetwork.SetRequestHandler(&testRequestHandler{err: errors.New("fail")}) // Return an error from the request handler
 
@@ -625,7 +648,9 @@ func TestCrossChainAppRequest(t *testing.T) {
 		},
 	}
 
-	net = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	net.SetCrossChainRequestHandler(&testCrossChainHandler{codec: crossChainCodecManager})
 	client := NewNetworkClient(net)
 
@@ -660,7 +685,9 @@ func TestCrossChainAppRequestOnCtxCancellation(t *testing.T) {
 		},
 	}
 
-	net := NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net := NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	net.SetCrossChainRequestHandler(&testCrossChainHandler{codec: crossChainCodecManager})
 
 	exampleCrossChainRequest := ExampleCrossChainRequest{
@@ -712,7 +739,9 @@ func TestCrossChainRequestRequestsRoutingAndResponse(t *testing.T) {
 
 	codecManager := buildCodec(t, TestMessage{})
 	crossChainCodecManager := buildCodec(t, ExampleCrossChainRequest{}, ExampleCrossChainResponse{})
-	net = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	net.SetCrossChainRequestHandler(&testCrossChainHandler{codec: crossChainCodecManager})
 	client := NewNetworkClient(net)
 
@@ -772,7 +801,9 @@ func TestCrossChainRequestOnShutdown(t *testing.T) {
 	}
 	codecManager := buildCodec(t, TestMessage{})
 	crossChainCodecManager := buildCodec(t, ExampleCrossChainRequest{}, ExampleCrossChainResponse{})
-	net = NewNetwork(p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), ""), sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, nil, prometheus.NewRegistry(), "")
+	require.NoError(t, err)
+	net = NewNetwork(p2pNetwork, sender, codecManager, crossChainCodecManager, ids.EmptyNodeID, 1, 1)
 	client := NewNetworkClient(net)
 
 	exampleCrossChainRequest := ExampleCrossChainRequest{
@@ -817,9 +848,9 @@ func TestNetworkRouting(t *testing.T) {
 	require := require.New(t)
 	protocol := 0
 	handler := &testSDKHandler{}
-	p2pNetwork := p2p.NewNetwork(logging.NoLog{}, &common.FakeSender{}, prometheus.NewRegistry(), "")
-	_, err := p2pNetwork.NewAppProtocol(uint64(protocol), handler)
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, sender, prometheus.NewRegistry(), "")
 	require.NoError(err)
+	require.NoError(p2pNetwork.AddHandler(uint64(protocol), handler))
 
 	networkCodec := codec.NewManager(0)
 	crossChainCodec := codec.NewManager(0)
diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go
index 99390ee299..15c00e0d63 100644
--- a/plugin/evm/tx_gossip_test.go
+++ b/plugin/evm/tx_gossip_test.go
@@ -78,10 +78,9 @@ func TestEthTxGossip(t *testing.T) {
 	peerSender := &common.FakeSender{
 		SentAppRequest: make(chan []byte, 1),
 	}
-	network := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
-
-	client, err := network.NewAppProtocol(ethTxGossipProtocol, &p2p.NoOpHandler{})
+	network, err := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
 	require.NoError(err)
+	client := network.NewClient(ethTxGossipProtocol)
 
 	// we only accept gossip requests from validators
 	requestingNodeID := ids.GenerateTestNodeID()
@@ -206,10 +205,9 @@ func TestAtomicTxGossip(t *testing.T) {
 	peerSender := &common.FakeSender{
 		SentAppRequest: make(chan []byte, 1),
 	}
-	network := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
-
-	client, err := network.NewAppProtocol(atomicTxGossipProtocol, &p2p.NoOpHandler{})
+	network, err := p2p.NewNetwork(logging.NoLog{}, peerSender, prometheus.NewRegistry(), "")
 	require.NoError(err)
+	client := network.NewClient(atomicTxGossipProtocol)
 
 	// we only accept gossip requests from validators
 	requestingNodeID := ids.GenerateTestNodeID()
diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go
index 2c3f9a33fb..1c0e2d617d 100644
--- a/plugin/evm/vm.go
+++ b/plugin/evm/vm.go
@@ -595,7 +595,10 @@ func (vm *VM) Initialize(
 		vm.p2pSender = appSender
 	}
 
-	p2pNetwork := p2p.NewNetwork(vm.ctx.Log, vm.p2pSender, vm.sdkMetrics, "p2p")
+	p2pNetwork, err := p2p.NewNetwork(vm.ctx.Log, appSender, vm.sdkMetrics, "p2p")
+	if err != nil {
+		return fmt.Errorf("failed to initialize p2p network: %w", err)
+	}
 	vm.validators = p2p.NewValidators(p2pNetwork.Peers, vm.ctx.Log, vm.ctx.SubnetID, vm.ctx.ValidatorState, maxValidatorSetStaleness)
 	vm.networkCodec = message.Codec
 	vm.Network = peer.NewNetwork(p2pNetwork, appSender, vm.networkCodec, message.CrossChainCodec, chainCtx.NodeID, vm.config.MaxOutboundActiveRequests, vm.config.MaxOutboundActiveCrossChainRequests)
@@ -1080,50 +1083,48 @@ func (vm *VM) initBlockBuilding() error {
 	}()
 
 	if vm.ethTxGossipHandler == nil {
-		vm.ethTxGossipHandler, err = gossip.NewHandler[*GossipEthTx](ethTxPool, ethTxGossipHandlerConfig, vm.sdkMetrics)
+		ethTxGossipHandler, err = gossip.NewHandler[*GossipEthTx](ethTxPool, ethTxGossipHandlerConfig, vm.sdkMetrics)
 		if err != nil {
 			return err
 		}
 
-		vm.ethTxGossipHandler = &p2p.ValidatorHandler{
-			ValidatorSet: vm.validators,
-			Handler: &p2p.ThrottlerHandler{
-				Handler:   vm.ethTxGossipHandler,
-				Throttler: p2p.NewSlidingWindowThrottler(throttlingPeriod, throttlingLimit),
-				Log:       vm.ctx.Log,
-			},
-			Log: vm.ctx.Log,
-		}
+		ethTxGossipHandler = p2p.NewThrottlerHandler(
+			ethTxGossipHandler,
+			p2p.NewSlidingWindowThrottler(throttlingPeriod, throttlingLimit),
+			vm.ctx.Log,
+		)
+
+		ethTxGossipHandler = p2p.NewValidatorHandler(ethTxGossipHandler, vm.validators, vm.ctx.Log)
+		vm.ethTxGossipHandler = vm.ethTxGossipHandler
 	}
-	ethTxGossipClient, err := vm.Network.NewAppProtocol(ethTxGossipProtocol, vm.ethTxGossipHandler, p2p.WithValidatorSampling(vm.validators))
-	if err != nil {
+
+	if err := vm.Network.AddHandler(ethTxGossipProtocol, vm.ethTxGossipHandler); err != nil {
 		return err
 	}
 
 	if vm.atomicTxGossipHandler == nil {
-		vm.atomicTxGossipHandler, err = gossip.NewHandler[*GossipAtomicTx](vm.mempool, atomicTxGossipHandlerConfig, vm.sdkMetrics)
-		if err != nil {
+		atomicTxGossipHandler := p2p.NewThrottlerHandler(
+			atomicTxGossipHandler,
+			p2p.NewSlidingWindowThrottler(throttlingLimit, throttlingLimit),
+			vm.ctx.Log,
+		)
+
+		atomicTxGossipHandler = p2p.NewValidatorHandler(atomicTxGossipHandler, vm.validators, vm.ctx.Log)
+
+		if err := vm.Network.AddHandler(atomicTxGossipProtocol, atomicTxGossipHandler); err != nil {
 			return err
 		}
 
-		vm.atomicTxGossipHandler = &p2p.ValidatorHandler{
-			ValidatorSet: vm.validators,
-			Handler: &p2p.ThrottlerHandler{
-				Throttler: p2p.NewSlidingWindowThrottler(throttlingPeriod, throttlingLimit),
-				Handler:   vm.atomicTxGossipHandler,
-				Log:       vm.ctx.Log,
-			},
-			Log: vm.ctx.Log,
-		}
+		vm.atomicTxGossipHandler = atomicTxGossipHandler
 	}
 
-	atomicTxGossipClient, err := vm.Network.NewAppProtocol(atomicTxGossipProtocol, vm.atomicTxGossipHandler, p2p.WithValidatorSampling(vm.validators))
-	if err != nil {
+	if err := vm.Network.AddHandler(atomicTxGossipProtocol, vm.atomicTxGossipHandler); err != nil {
 		return err
 	}
 
 	if vm.ethTxGossiper == nil {
-		vm.ethTxGossiper, err = gossip.NewPullGossiper[GossipEthTx, *GossipEthTx](
+		ethTxGossipClient := vm.Network.NewClient(ethTxGossipProtocol, p2p.WithValidatorSampling(vm.validators))
+		ethTxGossiper, err := gossip.NewPullGossiper[GossipEthTx, *GossipEthTx](
 			ethTxGossipConfig,
 			vm.ctx.Log,
 			ethTxPool,
@@ -1134,11 +1135,13 @@ func (vm *VM) initBlockBuilding() error {
 			return err
 		}
 
-		vm.ethTxGossiper = gossip.ValidatorGossiper{
-			Gossiper:   vm.ethTxGossiper,
+		ethTxGossiper = gossip.ValidatorGossiper{
+			Gossiper:   ethTxGossiper,
 			NodeID:     vm.ctx.NodeID,
 			Validators: vm.validators,
 		}
+
+		vm.ethTxGossiper = ethTxGossiper
 	}
 
 	vm.shutdownWg.Add(1)
@@ -1148,7 +1151,8 @@ func (vm *VM) initBlockBuilding() error {
 	}()
 
 	if vm.atomicTxGossiper == nil {
-		vm.atomicTxGossiper, err = gossip.NewPullGossiper[GossipAtomicTx, *GossipAtomicTx](
+		atomicTxGossipClient := vm.Network.NewClient(atomicTxGossipProtocol, p2p.WithValidatorSampling(vm.validators))
+		atomicTxGossiper, err := gossip.NewPullGossiper[GossipAtomicTx, *GossipAtomicTx](
 			atomicTxGossipConfig,
 			vm.ctx.Log,
 			vm.mempool,
@@ -1158,11 +1162,13 @@ func (vm *VM) initBlockBuilding() error {
 		if err != nil {
 			return err
 		}
-		vm.atomicTxGossiper = gossip.ValidatorGossiper{
-			Gossiper:   vm.atomicTxGossiper,
+		atomicTxGossiper = gossip.ValidatorGossiper{
+			Gossiper:   atomicTxGossiper,
 			NodeID:     vm.ctx.NodeID,
 			Validators: vm.validators,
 		}
+
+		vm.atomicTxGossiper = atomicTxGossiper
 	}
 
 	vm.shutdownWg.Add(1)
diff --git a/scripts/versions.sh b/scripts/versions.sh
index 3fe865b03c..a74887d206 100644
--- a/scripts/versions.sh
+++ b/scripts/versions.sh
@@ -1,4 +1,4 @@
 #!/usr/bin/env bash
 
 # Don't export them as they're used in the context of other calls
-avalanche_version=${AVALANCHE_VERSION:-'cb0f72d'}
+avalanche_version=${AVALANCHE_VERSION:-'v1.10.18-rc.2'}

From bfc85104e3cd8ffb6574073eaea84b6b4eb81aa8 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Wed, 13 Dec 2023 09:51:08 -0500
Subject: [PATCH 09/11] nit

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 peer/network_test.go |  1 +
 plugin/evm/vm.go     | 29 +++++++++++++----------------
 2 files changed, 14 insertions(+), 16 deletions(-)

diff --git a/peer/network_test.go b/peer/network_test.go
index 75ec24b76d..d3f065b242 100644
--- a/peer/network_test.go
+++ b/peer/network_test.go
@@ -848,6 +848,7 @@ func TestNetworkRouting(t *testing.T) {
 	require := require.New(t)
 	protocol := 0
 	handler := &testSDKHandler{}
+	sender := &common.SenderTest{}
 	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, sender, prometheus.NewRegistry(), "")
 	require.NoError(err)
 	require.NoError(p2pNetwork.AddHandler(uint64(protocol), handler))
diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go
index 1c0e2d617d..d85a097eee 100644
--- a/plugin/evm/vm.go
+++ b/plugin/evm/vm.go
@@ -1083,6 +1083,7 @@ func (vm *VM) initBlockBuilding() error {
 	}()
 
 	if vm.ethTxGossipHandler == nil {
+		var ethTxGossipHandler p2p.Handler
 		ethTxGossipHandler, err = gossip.NewHandler[*GossipEthTx](ethTxPool, ethTxGossipHandlerConfig, vm.sdkMetrics)
 		if err != nil {
 			return err
@@ -1094,8 +1095,7 @@ func (vm *VM) initBlockBuilding() error {
 			vm.ctx.Log,
 		)
 
-		ethTxGossipHandler = p2p.NewValidatorHandler(ethTxGossipHandler, vm.validators, vm.ctx.Log)
-		vm.ethTxGossipHandler = vm.ethTxGossipHandler
+		vm.ethTxGossipHandler = p2p.NewValidatorHandler(ethTxGossipHandler, vm.validators, vm.ctx.Log)
 	}
 
 	if err := vm.Network.AddHandler(ethTxGossipProtocol, vm.ethTxGossipHandler); err != nil {
@@ -1103,19 +1103,19 @@ func (vm *VM) initBlockBuilding() error {
 	}
 
 	if vm.atomicTxGossipHandler == nil {
-		atomicTxGossipHandler := p2p.NewThrottlerHandler(
+		var atomicTxGossipHandler p2p.Handler
+		atomicTxGossipHandler, err = gossip.NewHandler[*GossipAtomicTx](vm.mempool, atomicTxGossipHandlerConfig, vm.sdkMetrics)
+		if err != nil {
+			return err
+		}
+
+		atomicTxGossipHandler = p2p.NewThrottlerHandler(
 			atomicTxGossipHandler,
 			p2p.NewSlidingWindowThrottler(throttlingLimit, throttlingLimit),
 			vm.ctx.Log,
 		)
 
-		atomicTxGossipHandler = p2p.NewValidatorHandler(atomicTxGossipHandler, vm.validators, vm.ctx.Log)
-
-		if err := vm.Network.AddHandler(atomicTxGossipProtocol, atomicTxGossipHandler); err != nil {
-			return err
-		}
-
-		vm.atomicTxGossipHandler = atomicTxGossipHandler
+		vm.atomicTxGossipHandler = p2p.NewValidatorHandler(atomicTxGossipHandler, vm.validators, vm.ctx.Log)
 	}
 
 	if err := vm.Network.AddHandler(atomicTxGossipProtocol, vm.atomicTxGossipHandler); err != nil {
@@ -1135,13 +1135,11 @@ func (vm *VM) initBlockBuilding() error {
 			return err
 		}
 
-		ethTxGossiper = gossip.ValidatorGossiper{
+		vm.ethTxGossiper = &gossip.ValidatorGossiper{
 			Gossiper:   ethTxGossiper,
 			NodeID:     vm.ctx.NodeID,
 			Validators: vm.validators,
 		}
-
-		vm.ethTxGossiper = ethTxGossiper
 	}
 
 	vm.shutdownWg.Add(1)
@@ -1162,13 +1160,12 @@ func (vm *VM) initBlockBuilding() error {
 		if err != nil {
 			return err
 		}
-		atomicTxGossiper = gossip.ValidatorGossiper{
+
+		vm.atomicTxGossiper = &gossip.ValidatorGossiper{
 			Gossiper:   atomicTxGossiper,
 			NodeID:     vm.ctx.NodeID,
 			Validators: vm.validators,
 		}
-
-		vm.atomicTxGossiper = atomicTxGossiper
 	}
 
 	vm.shutdownWg.Add(1)

From 08cda51a3cd353a4234723ab461c28f7976d1388 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Wed, 13 Dec 2023 09:55:14 -0500
Subject: [PATCH 10/11] nit

Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 peer/network_test.go | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/peer/network_test.go b/peer/network_test.go
index eaa708e045..073beb897d 100644
--- a/peer/network_test.go
+++ b/peer/network_test.go
@@ -846,9 +846,17 @@ func TestNetworkCrossChainAppRequestAfterShutdown(t *testing.T) {
 
 func TestNetworkRouting(t *testing.T) {
 	require := require.New(t)
+	sender := &testAppSender{
+		sendAppRequestFn: func(_ context.Context, s set.Set[ids.NodeID], u uint32, bytes []byte) error {
+			return nil
+		},
+		sendAppResponseFn: func(id ids.NodeID, u uint32, bytes []byte) error {
+			return nil
+		},
+	}
 	protocol := 0
 	handler := &testSDKHandler{}
-  p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, &common.SenderTest{}, prometheus.NewRegistry(), "")
+	p2pNetwork, err := p2p.NewNetwork(logging.NoLog{}, sender, prometheus.NewRegistry(), "")
 	require.NoError(err)
 	require.NoError(p2pNetwork.AddHandler(uint64(protocol), handler))
 

From 5e1c5a703159dc8537f31ef14a513b13ac7dd9d7 Mon Sep 17 00:00:00 2001
From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
Date: Wed, 13 Dec 2023 11:03:16 -0500
Subject: [PATCH 11/11] Update plugin/evm/vm.go

Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>
Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
---
 plugin/evm/vm.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go
index 382846b3b5..4ae8bea834 100644
--- a/plugin/evm/vm.go
+++ b/plugin/evm/vm.go
@@ -344,7 +344,7 @@ type VM struct {
 	// Used to serve BLS signatures of warp messages over RPC
 	warpBackend warp.Backend
 
-	// Can be overridden in unit tests
+	// Initialize only sets these if nil so they can be overridden in tests
 	p2pSender             commonEng.AppSender
 	ethTxGossipHandler    p2p.Handler
 	atomicTxGossipHandler p2p.Handler