From 7f1d2c252bae82a8fd0fa433427cc3ad006dfaff Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 13:06:40 -0800 Subject: [PATCH 01/46] remove legacy gossip sender --- plugin/evm/gossiper.go | 431 ----------------------------------------- plugin/evm/vm.go | 1 + 2 files changed, 1 insertion(+), 431 deletions(-) diff --git a/plugin/evm/gossiper.go b/plugin/evm/gossiper.go index b3f08d8c0f..6b782ea0cc 100644 --- a/plugin/evm/gossiper.go +++ b/plugin/evm/gossiper.go @@ -4,447 +4,16 @@ package evm import ( - "container/heap" - "context" - "math/big" - "sync" - "time" - - "github.com/ava-labs/avalanchego/codec" - "github.com/ava-labs/avalanchego/network/p2p/gossip" - - "github.com/ava-labs/coreth/peer" - - "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/snow" - "github.com/ava-labs/avalanchego/utils/wrappers" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" - "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/state" "github.com/ava-labs/coreth/core/txpool" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/plugin/evm/message" ) -const ( - // We allow [recentCacheSize] to be fairly large because we only store hashes - // in the cache, not entire transactions. - recentCacheSize = 512 - - // [ethTxsGossipInterval] is how often we attempt to gossip newly seen - // transactions to other nodes. - ethTxsGossipInterval = 500 * time.Millisecond - - // [minGossipBatchInterval] is the minimum amount of time that must pass - // before our last gossip to peers. - minGossipBatchInterval = 50 * time.Millisecond -) - -// Gossiper handles outgoing gossip of transactions -type Gossiper interface { - // GossipAtomicTxs sends AppGossip message containing the given [txs] - GossipAtomicTxs(txs []*Tx) error - // GossipEthTxs sends AppGossip message containing the given [txs] - GossipEthTxs(txs []*types.Transaction) error -} - -// pushGossiper is used to gossip transactions to the network -type pushGossiper struct { - ctx *snow.Context - config Config - - client peer.NetworkClient - blockchain *core.BlockChain - txPool *txpool.TxPool - atomicMempool *Mempool - ethTxGossiper gossip.Accumulator[*GossipEthTx] - atomicTxGossiper gossip.Accumulator[*GossipAtomicTx] - - // We attempt to batch transactions we need to gossip to avoid runaway - // amplification of mempol chatter. - ethTxsToGossipChan chan []*types.Transaction - ethTxsToGossip map[common.Hash]*types.Transaction - lastGossiped time.Time - shutdownChan chan struct{} - shutdownWg *sync.WaitGroup - - // [recentAtomicTxs] and [recentEthTxs] prevent us from over-gossiping the - // same transaction in a short period of time. - recentAtomicTxs *cache.LRU[ids.ID, interface{}] - recentEthTxs *cache.LRU[common.Hash, interface{}] - - codec codec.Manager - stats GossipSentStats -} - -// createGossiper constructs and returns a pushGossiper or noopGossiper -// based on whether vm.chainConfig.ApricotPhase4BlockTimestamp is set -func (vm *VM) createGossiper( - stats GossipStats, - ethTxGossiper gossip.Accumulator[*GossipEthTx], - atomicTxGossiper gossip.Accumulator[*GossipAtomicTx], -) Gossiper { - net := &pushGossiper{ - ctx: vm.ctx, - config: vm.config, - client: vm.client, - blockchain: vm.blockChain, - txPool: vm.txPool, - atomicMempool: vm.mempool, - ethTxsToGossipChan: make(chan []*types.Transaction), - ethTxsToGossip: make(map[common.Hash]*types.Transaction), - shutdownChan: vm.shutdownChan, - shutdownWg: &vm.shutdownWg, - recentAtomicTxs: &cache.LRU[ids.ID, interface{}]{Size: recentCacheSize}, - recentEthTxs: &cache.LRU[common.Hash, interface{}]{Size: recentCacheSize}, - codec: vm.networkCodec, - stats: stats, - ethTxGossiper: ethTxGossiper, - atomicTxGossiper: atomicTxGossiper, - } - - net.awaitEthTxGossip() - return net -} - -// queueExecutableTxs attempts to select up to [maxTxs] from the tx pool for -// regossiping. -// -// We assume that [txs] contains an array of nonce-ordered transactions for a given -// account. This array of transactions can have gaps and start at a nonce lower -// than the current state of an account. -func (n *pushGossiper) queueExecutableTxs( - state *state.StateDB, - baseFee *big.Int, - txs map[common.Address]types.Transactions, - maxTxs int, -) types.Transactions { - // Setup heap for transactions - heads := make(types.TxByPriceAndTime, 0, len(txs)) - for addr, accountTxs := range txs { - // Short-circuit here to avoid performing an unnecessary state lookup - if len(accountTxs) == 0 { - continue - } - - // Ensure any transactions regossiped are immediately executable - var ( - currentNonce = state.GetNonce(addr) - tx *types.Transaction - ) - for _, accountTx := range accountTxs { - // The tx pool may be out of sync with current state, so we iterate - // through the account transactions until we get to one that is - // executable. - if accountTx.Nonce() == currentNonce { - tx = accountTx - break - } - // There may be gaps in the tx pool and we could jump past the nonce we'd - // like to execute. - if accountTx.Nonce() > currentNonce { - break - } - } - if tx == nil { - continue - } - - // Don't try to regossip a transaction too frequently - if time.Since(tx.FirstSeen()) < n.config.RegossipFrequency.Duration { - continue - } - - // Ensure the fee the transaction pays is valid at tip - wrapped, err := types.NewTxWithMinerFee(tx, baseFee) - if err != nil { - log.Debug( - "not queuing tx for regossip", - "tx", tx.Hash(), - "err", err, - ) - continue - } - - heads = append(heads, wrapped) - } - heap.Init(&heads) - - // Add up to [maxTxs] transactions to be gossiped - queued := make([]*types.Transaction, 0, maxTxs) - for len(heads) > 0 && len(queued) < maxTxs { - tx := heads[0].Tx - queued = append(queued, tx) - heap.Pop(&heads) - } - - return queued -} - -// queueRegossipTxs finds the best transactions in the mempool and adds up to -// [TxRegossipMaxSize] of them to [ethTxsToGossip]. -func (n *pushGossiper) queueRegossipTxs() types.Transactions { - // Fetch all pending transactions - pending := n.txPool.Pending(true) - - // Split the pending transactions into locals and remotes - localTxs := make(map[common.Address]types.Transactions) - remoteTxs := pending - for _, account := range n.txPool.Locals() { - if txs := remoteTxs[account]; len(txs) > 0 { - delete(remoteTxs, account) - localTxs[account] = txs - } - } - - // Add best transactions to be gossiped (preferring local txs) - tip := n.blockchain.CurrentBlock() - state, err := n.blockchain.StateAt(tip.Root) - if err != nil || state == nil { - log.Debug( - "could not get state at tip", - "tip", tip.Hash(), - "err", err, - ) - return nil - } - localQueued := n.queueExecutableTxs(state, tip.BaseFee, localTxs, n.config.RegossipMaxTxs) - localCount := len(localQueued) - n.stats.IncEthTxsRegossipQueuedLocal(localCount) - if localCount >= n.config.RegossipMaxTxs { - n.stats.IncEthTxsRegossipQueued() - return localQueued - } - remoteQueued := n.queueExecutableTxs(state, tip.BaseFee, remoteTxs, n.config.RegossipMaxTxs-localCount) - n.stats.IncEthTxsRegossipQueuedRemote(len(remoteQueued)) - if localCount+len(remoteQueued) > 0 { - // only increment the regossip stat when there are any txs queued - n.stats.IncEthTxsRegossipQueued() - } - return append(localQueued, remoteQueued...) -} - -// awaitEthTxGossip periodically gossips transactions that have been queued for -// gossip at least once every [ethTxsGossipInterval]. -func (n *pushGossiper) awaitEthTxGossip() { - n.shutdownWg.Add(1) - go n.ctx.Log.RecoverAndPanic(func() { - var ( - gossipTicker = time.NewTicker(ethTxsGossipInterval) - regossipTicker = time.NewTicker(n.config.RegossipFrequency.Duration) - ) - defer func() { - gossipTicker.Stop() - regossipTicker.Stop() - n.shutdownWg.Done() - }() - - for { - select { - case <-gossipTicker.C: - if attempted, err := n.gossipEthTxs(false); err != nil { - log.Warn( - "failed to send eth transactions", - "len(txs)", attempted, - "err", err, - ) - } - if err := n.ethTxGossiper.Gossip(context.TODO()); err != nil { - log.Warn( - "failed to send eth transactions", - "err", err, - ) - } - case <-regossipTicker.C: - for _, tx := range n.queueRegossipTxs() { - n.ethTxsToGossip[tx.Hash()] = tx - } - if attempted, err := n.gossipEthTxs(true); err != nil { - log.Warn( - "failed to send eth transactions", - "len(txs)", attempted, - "err", err, - ) - } - case txs := <-n.ethTxsToGossipChan: - for _, tx := range txs { - n.ethTxsToGossip[tx.Hash()] = tx - } - if attempted, err := n.gossipEthTxs(false); err != nil { - log.Warn( - "failed to send eth transactions", - "len(txs)", attempted, - "err", err, - ) - } - - gossipTxs := make([]*GossipEthTx, 0, len(txs)) - for _, tx := range txs { - gossipTxs = append(gossipTxs, &GossipEthTx{Tx: tx}) - } - - n.ethTxGossiper.Add(gossipTxs...) - if err := n.ethTxGossiper.Gossip(context.TODO()); err != nil { - log.Warn( - "failed to send eth transactions", - "len(txs)", len(txs), - "err", err, - ) - } - - case <-n.shutdownChan: - return - } - } - }) -} - -func (n *pushGossiper) GossipAtomicTxs(txs []*Tx) error { - errs := wrappers.Errs{} - for _, tx := range txs { - errs.Add(n.gossipAtomicTx(tx)) - } - return errs.Err -} - -func (n *pushGossiper) gossipAtomicTx(tx *Tx) error { - txID := tx.ID() - // Don't gossip transaction if it has been recently gossiped. - if _, has := n.recentAtomicTxs.Get(txID); has { - return nil - } - // If the transaction is not pending according to the mempool - // then there is no need to gossip it further. - if _, pending := n.atomicMempool.GetPendingTx(txID); !pending { - return nil - } - n.recentAtomicTxs.Put(txID, nil) - - msg := message.AtomicTxGossip{ - Tx: tx.SignedBytes(), - } - msgBytes, err := message.BuildGossipMessage(n.codec, msg) - if err != nil { - return err - } - - log.Trace( - "gossiping atomic tx", - "txID", txID, - ) - n.stats.IncAtomicGossipSent() - n.atomicTxGossiper.Add(&GossipAtomicTx{Tx: tx}) - if err := n.atomicTxGossiper.Gossip(context.TODO()); err != nil { - return err - } - - return n.client.Gossip(msgBytes) -} - -func (n *pushGossiper) sendEthTxs(txs []*types.Transaction) error { - if len(txs) == 0 { - return nil - } - - txBytes, err := rlp.EncodeToBytes(txs) - if err != nil { - return err - } - msg := message.EthTxsGossip{ - Txs: txBytes, - } - msgBytes, err := message.BuildGossipMessage(n.codec, msg) - if err != nil { - return err - } - - log.Trace( - "gossiping eth txs", - "len(txs)", len(txs), - "size(txs)", len(msg.Txs), - ) - n.stats.IncEthTxsGossipSent() - return n.client.Gossip(msgBytes) -} - -func (n *pushGossiper) gossipEthTxs(force bool) (int, error) { - if (!force && time.Since(n.lastGossiped) < minGossipBatchInterval) || len(n.ethTxsToGossip) == 0 { - return 0, nil - } - n.lastGossiped = time.Now() - txs := make([]*types.Transaction, 0, len(n.ethTxsToGossip)) - for _, tx := range n.ethTxsToGossip { - txs = append(txs, tx) - delete(n.ethTxsToGossip, tx.Hash()) - } - - selectedTxs := make([]*types.Transaction, 0) - for _, tx := range txs { - txHash := tx.Hash() - txStatus := n.txPool.Status([]common.Hash{txHash})[0] - if txStatus != txpool.TxStatusPending { - continue - } - - if n.config.RemoteGossipOnlyEnabled && n.txPool.HasLocal(txHash) { - continue - } - - // We check [force] outside of the if statement to avoid an unnecessary - // cache lookup. - if !force { - if _, has := n.recentEthTxs.Get(txHash); has { - continue - } - } - n.recentEthTxs.Put(txHash, nil) - - selectedTxs = append(selectedTxs, tx) - } - - if len(selectedTxs) == 0 { - return 0, nil - } - - // Attempt to gossip [selectedTxs] - msgTxs := make([]*types.Transaction, 0) - msgTxsSize := uint64(0) - for _, tx := range selectedTxs { - size := tx.Size() - if msgTxsSize+size > message.EthMsgSoftCapSize { - if err := n.sendEthTxs(msgTxs); err != nil { - return len(selectedTxs), err - } - msgTxs = msgTxs[:0] - msgTxsSize = 0 - } - msgTxs = append(msgTxs, tx) - msgTxsSize += size - } - - // Send any remaining [msgTxs] - return len(selectedTxs), n.sendEthTxs(msgTxs) -} - -// GossipEthTxs enqueues the provided [txs] for gossiping. At some point, the -// [pushGossiper] will attempt to gossip the provided txs to other nodes -// (usually right away if not under load). -// -// NOTE: We never return a non-nil error from this function but retain the -// option to do so in case it becomes useful. -func (n *pushGossiper) GossipEthTxs(txs []*types.Transaction) error { - select { - case n.ethTxsToGossipChan <- txs: - case <-n.shutdownChan: - } - return nil -} - // GossipHandler handles incoming gossip messages type GossipHandler struct { vm *VM diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 401fca1823..2ae71add2c 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -1178,6 +1178,7 @@ func (vm *VM) initBlockBuilding() error { } } + // TODO: run push gossip.Every here vm.shutdownWg.Add(1) go func() { gossip.Every(ctx, vm.ctx.Log, vm.ethTxPullGossiper, gossipFrequency) From ae975327faa6d542f632dc972068b6d935e55118 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 13:22:46 -0800 Subject: [PATCH 02/46] simplify block builder (no gossip) --- core/txpool/txpool.go | 2 +- plugin/evm/block_builder.go | 29 +++-------------------------- plugin/evm/mempool.go | 1 + 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 479967aef3..d075e0a2a9 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -1053,7 +1053,7 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T // This method is used to add transactions from the RPC API and performs synchronous pool // reorganization and event propagation. func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { - return pool.addTxs(txs, !pool.config.NoLocals, true) + errs := pool.addTxs(txs, !pool.config.NoLocals, true) } // AddLocal enqueues a single local transaction into the pool if it is valid. This is diff --git a/plugin/evm/block_builder.go b/plugin/evm/block_builder.go index 522c911a49..3daf33c009 100644 --- a/plugin/evm/block_builder.go +++ b/plugin/evm/block_builder.go @@ -27,9 +27,8 @@ type blockBuilder struct { ctx *snow.Context chainConfig *params.ChainConfig - txPool *txpool.TxPool - mempool *Mempool - gossiper Gossiper + txPool *txpool.TxPool + mempool *Mempool shutdownChan <-chan struct{} shutdownWg *sync.WaitGroup @@ -58,7 +57,6 @@ func (vm *VM) NewBlockBuilder(notifyBuildBlockChan chan<- commonEng.Message) *bl chainConfig: vm.chainConfig, txPool: vm.txPool, mempool: vm.mempool, - gossiper: vm.gossiper, shutdownChan: vm.shutdownChan, shutdownWg: &vm.shutdownWg, notifyBuildBlockChan: notifyBuildBlockChan, @@ -154,33 +152,12 @@ func (b *blockBuilder) awaitSubmittedTxs() { for { select { - case ethTxsEvent := <-txSubmitChan: + case <-txSubmitChan: log.Trace("New tx detected, trying to generate a block") b.signalTxsReady() - - if b.gossiper != nil && len(ethTxsEvent.Txs) > 0 { - // [GossipEthTxs] will block unless [gossiper.ethTxsToGossipChan] (an - // unbuffered channel) is listened on - if err := b.gossiper.GossipEthTxs(ethTxsEvent.Txs); err != nil { - log.Warn( - "failed to gossip new eth transactions", - "err", err, - ) - } - } case <-b.mempool.Pending: log.Trace("New atomic Tx detected, trying to generate a block") b.signalTxsReady() - - newTxs := b.mempool.GetNewTxs() - if b.gossiper != nil && len(newTxs) > 0 { - if err := b.gossiper.GossipAtomicTxs(newTxs); err != nil { - log.Warn( - "failed to gossip new atomic transactions", - "err", err, - ) - } - } case <-b.shutdownChan: b.buildBlockTimer.Stop() return diff --git a/plugin/evm/mempool.go b/plugin/evm/mempool.go index bab9bccf61..e8b86027d8 100644 --- a/plugin/evm/mempool.go +++ b/plugin/evm/mempool.go @@ -201,6 +201,7 @@ func (m *Mempool) AddLocalTx(tx *Tx) error { return nil } + // TODO: Add to tx gossiper return err } From 327f701f6e6a19a78fd454485e3e1419859af1a3 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 13:31:28 -0800 Subject: [PATCH 03/46] add handling on atomic submit --- plugin/evm/service.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/plugin/evm/service.go b/plugin/evm/service.go index d079648f90..fc6c3d43ab 100644 --- a/plugin/evm/service.go +++ b/plugin/evm/service.go @@ -225,7 +225,11 @@ func (service *AvaxAPI) Import(_ *http.Request, args *ImportArgs, response *api. } response.TxID = tx.ID() - return service.vm.mempool.AddLocalTx(tx) + if err := service.vm.mempool.AddLocalTx(tx); err != nil { + return err + } + service.vm.atomicTxPushGossiper.Add(&GossipAtomicTx{tx}) + return nil } // ExportAVAXArgs are the arguments to ExportAVAX @@ -331,7 +335,11 @@ func (service *AvaxAPI) Export(_ *http.Request, args *ExportArgs, response *api. } response.TxID = tx.ID() - return service.vm.mempool.AddLocalTx(tx) + if err := service.vm.mempool.AddLocalTx(tx); err != nil { + return err + } + service.vm.atomicTxPushGossiper.Add(&GossipAtomicTx{tx}) + return nil } // GetUTXOs gets all utxos for passed in addresses @@ -437,7 +445,11 @@ func (service *AvaxAPI) IssueTx(r *http.Request, args *api.FormattedTx, response service.vm.ctx.Lock.Lock() defer service.vm.ctx.Lock.Unlock() - return service.vm.mempool.AddLocalTx(tx) + if err := service.vm.mempool.AddLocalTx(tx); err != nil { + return err + } + service.vm.atomicTxPushGossiper.Add(&GossipAtomicTx{tx}) + return nil } // GetAtomicTxStatusReply defines the GetAtomicTxStatus replies returned from the API From 4b11d5b65d00408c181a22323fdc50af1011b9ae Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 13:43:30 -0800 Subject: [PATCH 04/46] spiking on simpler integration --- eth/api_backend.go | 6 +++++- eth/backend.go | 7 +++++++ plugin/evm/vm.go | 21 +++++++++++++++------ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index f8854809ff..e313104a95 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -324,7 +324,11 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) if err := ctx.Err(); err != nil { return err } - return b.eth.txPool.AddLocal(signedTx) + if err := b.eth.txPool.AddLocal(signedTx); err != nil { + return err + } + b.eth.vm.SendPushGossip(signedTx) + return nil } func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) { diff --git a/eth/backend.go b/eth/backend.go index 55d674d9d6..383eb8c155 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -70,6 +70,10 @@ type Settings struct { MaxBlocksPerRequest int64 // Maximum number of blocks to serve per getLogs request } +type VM interface { + SendPushGossip(*types.Transaction) +} + // Ethereum implements the Ethereum full node service. type Ethereum struct { config *Config @@ -77,6 +81,7 @@ type Ethereum struct { // Handlers txPool *txpool.TxPool blockchain *core.BlockChain + vm VM // DB interfaces chainDb ethdb.Database // Block chain database @@ -118,6 +123,7 @@ func New( stack *node.Node, config *Config, cb dummy.ConsensusCallbacks, + vmi VM, chainDb ethdb.Database, settings Settings, lastAcceptedHash common.Hash, @@ -151,6 +157,7 @@ func New( eth := &Ethereum{ config: config, + vm: vmi, chainDb: chainDb, eventMux: new(event.TypeMux), accountManager: stack.AccountManager(), diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 2ae71add2c..f4e4cf33e4 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -293,8 +293,6 @@ type VM struct { builder *blockBuilder - gossiper Gossiper - baseCodec codec.Registry codec codec.Manager clock mockable.Clock @@ -691,6 +689,10 @@ func (vm *VM) initializeMetrics() error { return nil } +func (vm *VM) SendPushGossip(tx *types.Transaction) { + vm.ethTxPushGossiper.Add(&GossipEthTx{tx}) +} + func (vm *VM) initializeChain(lastAcceptedHash common.Hash) error { nodecfg := &node.Config{ CorethVersion: Version, @@ -706,6 +708,7 @@ func (vm *VM) initializeChain(lastAcceptedHash common.Hash) error { node, &vm.ethConfig, vm.createConsensusCallbacks(), + vm, vm.chaindb, vm.config.EthBackendSettings(), lastAcceptedHash, @@ -1112,7 +1115,6 @@ func (vm *VM) initBlockBuilding() error { // NOTE: gossip network must be initialized first otherwise ETH tx gossip will not work. gossipStats := NewGossipStats() - vm.gossiper = vm.createGossiper(gossipStats, vm.ethTxPushGossiper, vm.atomicTxPushGossiper) vm.builder = vm.NewBlockBuilder(vm.toEngine) vm.builder.awaitSubmittedTxs() vm.Network.SetGossipHandler(NewGossipHandler(vm, gossipStats)) @@ -1178,8 +1180,11 @@ func (vm *VM) initBlockBuilding() error { } } - // TODO: run push gossip.Every here - vm.shutdownWg.Add(1) + vm.shutdownWg.Add(2) + go func() { + gossip.Every(ctx, vm.ctx.Log, vm.ethTxPushGossiper, gossipFrequency) + vm.shutdownWg.Done() + }() go func() { gossip.Every(ctx, vm.ctx.Log, vm.ethTxPullGossiper, gossipFrequency) vm.shutdownWg.Done() @@ -1202,7 +1207,11 @@ func (vm *VM) initBlockBuilding() error { } } - vm.shutdownWg.Add(1) + vm.shutdownWg.Add(2) + go func() { + gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPushGossiper, gossipFrequency) + vm.shutdownWg.Done() + }() go func() { gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPullGossiper, gossipFrequency) vm.shutdownWg.Done() From e4a30bd54e9d041590b19c5b8ff28eb1620840c4 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 13:44:34 -0800 Subject: [PATCH 05/46] cleanup naming --- eth/api_backend.go | 2 +- eth/backend.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index e313104a95..d5b904188f 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -327,7 +327,7 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) if err := b.eth.txPool.AddLocal(signedTx); err != nil { return err } - b.eth.vm.SendPushGossip(signedTx) + b.eth.gossiper.SendPushGossip(signedTx) return nil } diff --git a/eth/backend.go b/eth/backend.go index 383eb8c155..da4bf62292 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -70,7 +70,7 @@ type Settings struct { MaxBlocksPerRequest int64 // Maximum number of blocks to serve per getLogs request } -type VM interface { +type Gossiper interface { SendPushGossip(*types.Transaction) } @@ -81,7 +81,7 @@ type Ethereum struct { // Handlers txPool *txpool.TxPool blockchain *core.BlockChain - vm VM + gossiper Gossiper // DB interfaces chainDb ethdb.Database // Block chain database @@ -123,7 +123,7 @@ func New( stack *node.Node, config *Config, cb dummy.ConsensusCallbacks, - vmi VM, + gossiper Gossiper, chainDb ethdb.Database, settings Settings, lastAcceptedHash common.Hash, @@ -157,7 +157,7 @@ func New( eth := &Ethereum{ config: config, - vm: vmi, + gossiper: gossiper, chainDb: chainDb, eventMux: new(event.TypeMux), accountManager: stack.AccountManager(), From 309e3522a7f9b033a408006142acaef219da123b Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 13:46:09 -0800 Subject: [PATCH 06/46] cleanup consts --- plugin/evm/vm.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index f4e4cf33e4..66f2fd5cb0 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -144,6 +144,7 @@ const ( atomicTxGossipProtocol = 0x1 // gossip constants + pushGossipFrequency = 100 * time.Millisecond txGossipBloomMinTargetElements = 8 * 1024 txGossipBloomTargetFalsePositiveRate = 0.01 txGossipBloomResetFalsePositiveRate = 0.05 @@ -152,7 +153,7 @@ const ( maxValidatorSetStaleness = time.Minute txGossipThrottlingPeriod = 10 * time.Second txGossipThrottlingLimit = 2 - gossipFrequency = 10 * time.Second + pullGossipFrequency = 10 * time.Second txGossipPollSize = 10 ) @@ -1182,11 +1183,11 @@ func (vm *VM) initBlockBuilding() error { vm.shutdownWg.Add(2) go func() { - gossip.Every(ctx, vm.ctx.Log, vm.ethTxPushGossiper, gossipFrequency) + gossip.Every(ctx, vm.ctx.Log, vm.ethTxPushGossiper, pushGossipFrequency) vm.shutdownWg.Done() }() go func() { - gossip.Every(ctx, vm.ctx.Log, vm.ethTxPullGossiper, gossipFrequency) + gossip.Every(ctx, vm.ctx.Log, vm.ethTxPullGossiper, pullGossipFrequency) vm.shutdownWg.Done() }() @@ -1209,11 +1210,11 @@ func (vm *VM) initBlockBuilding() error { vm.shutdownWg.Add(2) go func() { - gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPushGossiper, gossipFrequency) + gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPushGossiper, pushGossipFrequency) vm.shutdownWg.Done() }() go func() { - gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPullGossiper, gossipFrequency) + gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPullGossiper, pullGossipFrequency) vm.shutdownWg.Done() }() From b33835212b4c1aeb10a65d3ab6ade7d9497e8652 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 13:46:31 -0800 Subject: [PATCH 07/46] remove gossip logic from tx pool --- core/txpool/txpool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index d075e0a2a9..479967aef3 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -1053,7 +1053,7 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T // This method is used to add transactions from the RPC API and performs synchronous pool // reorganization and event propagation. func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { - errs := pool.addTxs(txs, !pool.config.NoLocals, true) + return pool.addTxs(txs, !pool.config.NoLocals, true) } // AddLocal enqueues a single local transaction into the pool if it is valid. This is From 1612eca9e263ef12adc26322634edba8b739f898 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 13:49:16 -0800 Subject: [PATCH 08/46] nit --- plugin/evm/mempool.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/evm/mempool.go b/plugin/evm/mempool.go index e8b86027d8..bab9bccf61 100644 --- a/plugin/evm/mempool.go +++ b/plugin/evm/mempool.go @@ -201,7 +201,6 @@ func (m *Mempool) AddLocalTx(tx *Tx) error { return nil } - // TODO: Add to tx gossiper return err } From dab0718b0435763ffa0e9b3ed354c8fb08dd517b Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 19:27:06 -0800 Subject: [PATCH 09/46] remove unused newTxs --- plugin/evm/mempool.go | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/plugin/evm/mempool.go b/plugin/evm/mempool.go index bab9bccf61..0d597aa04c 100644 --- a/plugin/evm/mempool.go +++ b/plugin/evm/mempool.go @@ -37,19 +37,16 @@ type mempoolMetrics struct { addedTxs metrics.Counter // Count of all transactions added to the mempool discardedTxs metrics.Counter // Count of all discarded transactions - - newTxsReturned metrics.Counter // Count of transactions returned from GetNewTxs } // newMempoolMetrics constructs metrics for the atomic mempool func newMempoolMetrics() *mempoolMetrics { return &mempoolMetrics{ - pendingTxs: metrics.GetOrRegisterGauge("atomic_mempool_pending_txs", nil), - currentTxs: metrics.GetOrRegisterGauge("atomic_mempool_current_txs", nil), - issuedTxs: metrics.GetOrRegisterGauge("atomic_mempool_issued_txs", nil), - addedTxs: metrics.GetOrRegisterCounter("atomic_mempool_added_txs", nil), - discardedTxs: metrics.GetOrRegisterCounter("atomic_mempool_discarded_txs", nil), - newTxsReturned: metrics.GetOrRegisterCounter("atomic_mempool_new_txs_returned", nil), + pendingTxs: metrics.GetOrRegisterGauge("atomic_mempool_pending_txs", nil), + currentTxs: metrics.GetOrRegisterGauge("atomic_mempool_current_txs", nil), + issuedTxs: metrics.GetOrRegisterGauge("atomic_mempool_issued_txs", nil), + addedTxs: metrics.GetOrRegisterCounter("atomic_mempool_added_txs", nil), + discardedTxs: metrics.GetOrRegisterCounter("atomic_mempool_discarded_txs", nil), } } @@ -70,8 +67,6 @@ type Mempool struct { // Pending is a channel of length one, which the mempool ensures has an item on // it as long as there is an unissued transaction remaining in [txs] Pending chan struct{} - // newTxs is an array of [Tx] that are ready to be gossiped. - newTxs []*Tx // txHeap is a sorted record of all txs in the mempool by [gasPrice] // NOTE: [txHeap] ONLY contains pending txs txHeap *txHeap @@ -359,7 +354,6 @@ func (m *Mempool) addTx(tx *Tx, force bool) error { // been set to something other than [dontBuild], this will be ignored and won't be // reset until the engine calls BuildBlock. This case is handled in IssueCurrentTx // and CancelCurrentTx. - m.newTxs = append(m.newTxs, tx) m.addPending() return nil @@ -594,14 +588,3 @@ func (m *Mempool) addPending() { default: } } - -// GetNewTxs returns the array of [newTxs] and replaces it with an empty array. -func (m *Mempool) GetNewTxs() []*Tx { - m.lock.Lock() - defer m.lock.Unlock() - - cpy := m.newTxs - m.newTxs = nil - m.metrics.newTxsReturned.Inc(int64(len(cpy))) // Increment the number of newTxs - return cpy -} From 3bad7ac16e60c76a84dcd8e9ee8ce43aaeecf8e7 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Sun, 25 Feb 2024 19:28:52 -0800 Subject: [PATCH 10/46] add TODO for moving --- plugin/evm/vm.go | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 66f2fd5cb0..61ae46dce9 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -690,6 +690,7 @@ func (vm *VM) initializeMetrics() error { return nil } +// TODO: move somewhere else func (vm *VM) SendPushGossip(tx *types.Transaction) { vm.ethTxPushGossiper.Add(&GossipEthTx{tx}) } From 36a381c5be8240e05e97a4d1474467f5c37b1047 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 10:56:17 -0800 Subject: [PATCH 11/46] import avalanchego sdk changes --- go.mod | 47 +++++++++++---------- go.sum | 127 +++++++++++++++++++++++---------------------------------- 2 files changed, 73 insertions(+), 101 deletions(-) diff --git a/go.mod b/go.mod index a091fa2925..d6affc97bc 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/VictoriaMetrics/fastcache v1.10.0 - github.com/ava-labs/avalanchego v1.11.1 + github.com/ava-labs/avalanchego v1.11.1-0.20240227184630-35fc54b9c0ef github.com/cespare/cp v0.1.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 @@ -13,7 +13,7 @@ require ( github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/gorilla/rpc v1.2.0 github.com/gorilla/websocket v1.4.2 github.com/hashicorp/go-bexpr v0.1.10 @@ -34,15 +34,15 @@ require ( github.com/stretchr/testify v1.8.4 github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa - go.uber.org/goleak v1.2.1 + go.uber.org/goleak v1.3.0 go.uber.org/mock v0.4.0 - golang.org/x/crypto v0.17.0 + golang.org/x/crypto v0.18.0 golang.org/x/exp v0.0.0-20231127185646-65229373498e - golang.org/x/sync v0.5.0 - golang.org/x/sys v0.15.0 + golang.org/x/sync v0.6.0 + golang.org/x/sys v0.16.0 golang.org/x/text v0.14.0 golang.org/x/time v0.0.0-20220922220347-f3bd1da661af - google.golang.org/protobuf v1.31.0 + google.golang.org/protobuf v1.32.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 ) @@ -52,7 +52,7 @@ require ( github.com/bits-and-blooms/bitset v1.7.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect @@ -67,7 +67,7 @@ require ( github.com/dlclark/regexp2 v1.7.0 // indirect github.com/ethereum/c-kzg-4844 v0.2.0 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect @@ -81,7 +81,7 @@ require ( github.com/google/renameio/v2 v2.0.0 // indirect github.com/graph-gophers/graphql-go v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huin/goupnp v1.0.3 // indirect github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect @@ -119,23 +119,22 @@ require ( github.com/tklauser/numcpus v0.2.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect - go.opentelemetry.io/otel v1.11.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.0 // indirect - go.opentelemetry.io/otel/sdk v1.11.0 // indirect - go.opentelemetry.io/otel/trace v1.11.0 // indirect - go.opentelemetry.io/proto/otlp v0.19.0 // indirect + go.opentelemetry.io/otel v1.22.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect + go.opentelemetry.io/otel/metric v1.22.0 // indirect + go.opentelemetry.io/otel/sdk v1.22.0 // indirect + go.opentelemetry.io/otel/trace v1.22.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/term v0.16.0 // indirect gonum.org/v1/gonum v0.11.0 // indirect - google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/grpc v1.58.3 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/grpc v1.62.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 1cd704f7ca..48fb659a34 100644 --- a/go.sum +++ b/go.sum @@ -46,7 +46,6 @@ github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMd github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= @@ -54,10 +53,9 @@ github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBA github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= 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.11.1 h1:NSelfZ/Di8uGCsRoFK32HOR262eHlpUFmAu8pbfg0Jo= -github.com/ava-labs/avalanchego v1.11.1/go.mod h1:+UpgT8X2fNN93+iE100efkZL7ePfBRfRdmpJ/i3YnyY= +github.com/ava-labs/avalanchego v1.11.1-0.20240227184630-35fc54b9c0ef h1:9fKOGMYwCElOrDK0w2XAt2X+S4NKiubqlUUWMtpIOus= +github.com/ava-labs/avalanchego v1.11.1-0.20240227184630-35fc54b9c0ef/go.mod h1:X1KT5ukTfCzkI0+AFGOPa+wp/8AYzn2hoXbp75nRTJE= 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= @@ -87,13 +85,11 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -107,11 +103,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= @@ -174,8 +165,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/c-kzg-4844 v0.2.0 h1:+cUvymlnoDDQgMInp25Bo3OmLajmmY8mLJ/tLjqd77Q= @@ -213,8 +202,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= @@ -242,9 +231,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -290,7 +278,6 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -316,8 +303,8 @@ github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qA github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -332,10 +319,8 @@ github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY4 github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 h1:kr3j8iIMR4ywO/O0rvksXaJvauGGCMg2zAZIiNZ9uIQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -513,7 +498,6 @@ github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8u github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= @@ -535,7 +519,6 @@ github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMT github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= @@ -617,25 +600,24 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/otel v1.11.0 h1:kfToEGMDq6TrVrJ9Vht84Y8y9enykSZzDDZglV0kIEk= -go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.0 h1:0dly5et1i/6Th3WHn0M6kYiJfFNzhhxanrJ0bOfnjEo= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.0/go.mod h1:+Lq4/WkdCkjbGcBMVHHg2apTbv8oMBf29QCnyCCJjNQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.0 h1:eyJ6njZmH16h9dOKCi7lMswAnGsSOwgTqWzfxqcuNr8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.0/go.mod h1:FnDp7XemjN3oZ3xGunnfOUTVwd2XcvLbtRAuOSU3oc8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.0 h1:j2RFV0Qdt38XQ2Jvi4WIsQ56w8T7eSirYbMw19VXRDg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.0/go.mod h1:pILgiTEtrqvZpoiuGdblDgS5dbIaTgDrkIuKfEFkt+A= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.0 h1:v29I/NbVp7LXQYMFZhU6q17D0jSEbYOAVONlrO1oH5s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.0/go.mod h1:/RpLsmbQLDO1XCbWAM4S6TSwj8FKwwgyKKyqtvVfAnw= -go.opentelemetry.io/otel/sdk v1.11.0 h1:ZnKIL9V9Ztaq+ME43IUi/eo22mNsb6a7tGfzaOWB5fo= -go.opentelemetry.io/otel/sdk v1.11.0/go.mod h1:REusa8RsyKaq0OlyangWXaw97t2VogoO4SSEeKkSTAk= -go.opentelemetry.io/otel/trace v1.11.0 h1:20U/Vj42SX+mASlXLmSGBg6jpI1jQtv682lZtTAOVFI= -go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFgRcGiyHg7H7bwcwaQJYrNFqCqrbTQ8K4p1OvDu8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0/go.mod h1:WfCWp1bGoYK8MeULtI15MmQVczfR+bFkk0DF3h06QmQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= @@ -657,8 +639,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -742,8 +724,8 @@ golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -753,7 +735,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -766,8 +747,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -835,13 +816,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -973,7 +954,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -988,13 +968,12 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1009,16 +988,12 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= +google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1031,9 +1006,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1055,7 +1029,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 21bc6122e3d35590ed07141c7eceed1ac79ea137 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 11:25:10 -0800 Subject: [PATCH 12/46] add Has to GossipEthTxPool --- plugin/evm/gossip.go | 9 +++++++-- plugin/evm/vm.go | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index 3664b12a6e..b359c0f149 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/prometheus/client_golang/prometheus" @@ -46,8 +47,6 @@ func newTxGossipHandler[T gossip.Gossipable]( handler := gossip.NewHandler[T]( log, marshaller, - // Don't forward gossip to avoid double-forwarding - gossip.NoOpAccumulator[T]{}, mempool, metrics, maxMessageSize, @@ -170,6 +169,12 @@ func (g *GossipEthTxPool) Add(tx *GossipEthTx) error { return g.mempool.AddRemotes([]*types.Transaction{tx.Tx})[0] } +// Has should just return whether or not the [txID] is still in the mempool, +// not whether it is in the mempool AND pending. +func (g *GossipEthTxPool) Has(txID ids.ID) bool { + return g.mempool.Has(common.Hash(txID[:])) +} + func (g *GossipEthTxPool) Iterate(f func(tx *GossipEthTx) bool) { g.mempool.IteratePending(func(tx *types.Transaction) bool { return f(&GossipEthTx{Tx: tx}) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 61ae46dce9..320fe66cd7 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -333,11 +333,11 @@ type VM struct { // Initialize only sets these if nil so they can be overridden in tests p2pSender commonEng.AppSender ethTxGossipHandler p2p.Handler - atomicTxGossipHandler p2p.Handler + ethTxPushGossiper *gossip.PushGossiper[*GossipEthTx] ethTxPullGossiper gossip.Gossiper + atomicTxGossipHandler p2p.Handler + atomicTxPushGossiper *gossip.PushGossiper[*GossipAtomicTx] atomicTxPullGossiper gossip.Gossiper - ethTxPushGossiper gossip.Accumulator[*GossipEthTx] - atomicTxPushGossiper gossip.Accumulator[*GossipAtomicTx] } // Codec implements the secp256k1fx interface From 5f603071fefbe7105a644abff6ea869dad952dc3 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 11:28:42 -0800 Subject: [PATCH 13/46] update interfaces --- eth/api_backend.go | 5 ++++- eth/backend.go | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index d5b904188f..ae22abbf55 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -327,7 +327,10 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) if err := b.eth.txPool.AddLocal(signedTx); err != nil { return err } - b.eth.gossiper.SendPushGossip(signedTx) + + // We only enqueue transactions for push gossip if they were submitted over the RPC and + // added to the mempool. + b.eth.gossiper.Add(signedTx) return nil } diff --git a/eth/backend.go b/eth/backend.go index da4bf62292..299f15405e 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -70,8 +70,8 @@ type Settings struct { MaxBlocksPerRequest int64 // Maximum number of blocks to serve per getLogs request } -type Gossiper interface { - SendPushGossip(*types.Transaction) +type PushGossiper interface { + Add(*types.Transaction) } // Ethereum implements the Ethereum full node service. @@ -81,7 +81,7 @@ type Ethereum struct { // Handlers txPool *txpool.TxPool blockchain *core.BlockChain - gossiper Gossiper + gossiper PushGossiper // DB interfaces chainDb ethdb.Database // Block chain database @@ -123,7 +123,7 @@ func New( stack *node.Node, config *Config, cb dummy.ConsensusCallbacks, - gossiper Gossiper, + gossiper PushGossiper, chainDb ethdb.Database, settings Settings, lastAcceptedHash common.Hash, From e5c96a3baf81d400035606548048464867237980 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 11:32:24 -0800 Subject: [PATCH 14/46] add shim for push gossiper --- plugin/evm/gossip.go | 8 ++++++++ plugin/evm/vm.go | 7 +------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index b359c0f149..bf0d1c9802 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -209,3 +209,11 @@ type GossipEthTx struct { func (tx *GossipEthTx) GossipID() ids.ID { return ids.ID(tx.Tx.Hash()) } + +type ETHBackendPushGossiper struct { + vm *VM +} + +func (e *ETHBackendPushGossiper) Add(tx *types.Transaction) { + e.vm.ethTxPushGossiper.Add(&GossipEthTx{tx}) +} diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 320fe66cd7..e2851b5af6 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -690,11 +690,6 @@ func (vm *VM) initializeMetrics() error { return nil } -// TODO: move somewhere else -func (vm *VM) SendPushGossip(tx *types.Transaction) { - vm.ethTxPushGossiper.Add(&GossipEthTx{tx}) -} - func (vm *VM) initializeChain(lastAcceptedHash common.Hash) error { nodecfg := &node.Config{ CorethVersion: Version, @@ -710,7 +705,7 @@ func (vm *VM) initializeChain(lastAcceptedHash common.Hash) error { node, &vm.ethConfig, vm.createConsensusCallbacks(), - vm, + ÐBackendPushGossiper{vm}, vm.chaindb, vm.config.EthBackendSettings(), lastAcceptedHash, From 5866ae6b1f2c1e5615db145870d1f784221ed452 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 11:38:00 -0800 Subject: [PATCH 15/46] enforce interface --- eth/backend.go | 2 ++ plugin/evm/gossip.go | 9 +++++++-- plugin/evm/vm.go | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 299f15405e..aa1ef9d91c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -70,6 +70,8 @@ type Settings struct { MaxBlocksPerRequest int64 // Maximum number of blocks to serve per getLogs request } +// PushGossiper sends pushes pending transactions to peers until they are +// removed from the mempool. type PushGossiper interface { Add(*types.Transaction) } diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index bf0d1c9802..77d0f176dd 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -21,6 +21,7 @@ import ( "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/core/txpool" "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/eth" ) var ( @@ -31,6 +32,8 @@ var ( _ gossip.Marshaller[*GossipAtomicTx] = (*GossipAtomicTxMarshaller)(nil) _ gossip.Marshaller[*GossipEthTx] = (*GossipEthTxMarshaller)(nil) _ gossip.Set[*GossipEthTx] = (*GossipEthTxPool)(nil) + + _ eth.PushGossiper = (*EthPushGossiper)(nil) ) func newTxGossipHandler[T gossip.Gossipable]( @@ -210,10 +213,12 @@ func (tx *GossipEthTx) GossipID() ids.ID { return ids.ID(tx.Tx.Hash()) } -type ETHBackendPushGossiper struct { +// EthPushGossiper is used by the ETH backend to push transactions +// issued over the RPC and added to the mempool to peers. +type EthPushGossiper struct { vm *VM } -func (e *ETHBackendPushGossiper) Add(tx *types.Transaction) { +func (e *EthPushGossiper) Add(tx *types.Transaction) { e.vm.ethTxPushGossiper.Add(&GossipEthTx{tx}) } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index e2851b5af6..506891cb6a 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -705,7 +705,7 @@ func (vm *VM) initializeChain(lastAcceptedHash common.Hash) error { node, &vm.ethConfig, vm.createConsensusCallbacks(), - ÐBackendPushGossiper{vm}, + &EthPushGossiper{vm}, vm.chaindb, vm.config.EthBackendSettings(), lastAcceptedHash, From f0dee817265faa00b7c6f5015463263da89ee0af Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 11:40:28 -0800 Subject: [PATCH 16/46] add has to mempool --- plugin/evm/mempool.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugin/evm/mempool.go b/plugin/evm/mempool.go index 0d597aa04c..25b787754c 100644 --- a/plugin/evm/mempool.go +++ b/plugin/evm/mempool.go @@ -428,6 +428,14 @@ func (m *Mempool) GetTx(txID ids.ID) (*Tx, bool, bool) { return nil, false, false } +// Has returns true if the mempool contains [txID] or it was issued. +func (m *Mempool) Has(txID ids.ID) bool { + m.lock.RLock() + defer m.lock.RUnlock() + + return m.has(txID) +} + // IssueCurrentTx marks [currentTx] as issued if there is one func (m *Mempool) IssueCurrentTxs() { m.lock.Lock() From 18c9996c1b0cb24cd3661bfc1185af9930f4e9bf Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 11:45:57 -0800 Subject: [PATCH 17/46] resolve vm errors --- plugin/evm/vm.go | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 506891cb6a..0b44812761 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -145,6 +145,8 @@ const ( // gossip constants pushGossipFrequency = 100 * time.Millisecond + pushGossipDiscardedSize = 4096 + pushRegossipFrequency = 10 * time.Second txGossipBloomMinTargetElements = 8 * 1024 txGossipBloomTargetFalsePositiveRate = 0.01 txGossipBloomResetFalsePositiveRate = 0.05 @@ -1077,16 +1079,23 @@ func (vm *VM) initBlockBuilding() error { vm.cancel = cancel ethTxGossipMarshaller := GossipEthTxMarshaller{} - atomicTxGossipMarshaller := GossipAtomicTxMarshaller{} - ethTxGossipClient := vm.Network.NewClient(ethTxGossipProtocol, p2p.WithValidatorSampling(vm.validators)) - atomicTxGossipClient := vm.Network.NewClient(atomicTxGossipProtocol, p2p.WithValidatorSampling(vm.validators)) - ethTxGossipMetrics, err := gossip.NewMetrics(vm.sdkMetrics, ethTxGossipNamespace) if err != nil { return fmt.Errorf("failed to initialize eth tx gossip metrics: %w", err) } + ethTxPool, err := NewGossipEthTxPool(vm.txPool, vm.sdkMetrics) + if err != nil { + return err + } + vm.shutdownWg.Add(1) + go func() { + ethTxPool.Subscribe(ctx) + vm.shutdownWg.Done() + }() + atomicTxGossipMarshaller := GossipAtomicTxMarshaller{} + atomicTxGossipClient := vm.Network.NewClient(atomicTxGossipProtocol, p2p.WithValidatorSampling(vm.validators)) atomicTxGossipMetrics, err := gossip.NewMetrics(vm.sdkMetrics, atomicTxGossipNamespace) if err != nil { return fmt.Errorf("failed to initialize atomic tx gossip metrics: %w", err) @@ -1095,18 +1104,24 @@ func (vm *VM) initBlockBuilding() error { if vm.ethTxPushGossiper == nil { vm.ethTxPushGossiper = gossip.NewPushGossiper[*GossipEthTx]( ethTxGossipMarshaller, + ethTxPool, ethTxGossipClient, ethTxGossipMetrics, + pushGossipDiscardedSize, txGossipTargetMessageSize, + pushRegossipFrequency, ) } if vm.atomicTxPushGossiper == nil { vm.atomicTxPushGossiper = gossip.NewPushGossiper[*GossipAtomicTx]( atomicTxGossipMarshaller, + vm.mempool, atomicTxGossipClient, atomicTxGossipMetrics, + pushGossipDiscardedSize, txGossipTargetMessageSize, + pushRegossipFrequency, ) } @@ -1116,16 +1131,6 @@ func (vm *VM) initBlockBuilding() error { vm.builder.awaitSubmittedTxs() vm.Network.SetGossipHandler(NewGossipHandler(vm, gossipStats)) - ethTxPool, err := NewGossipEthTxPool(vm.txPool, vm.sdkMetrics) - if err != nil { - return err - } - vm.shutdownWg.Add(1) - go func() { - ethTxPool.Subscribe(ctx) - vm.shutdownWg.Done() - }() - if vm.ethTxGossipHandler == nil { vm.ethTxGossipHandler = newTxGossipHandler[*GossipEthTx]( vm.ctx.Log, From ed5ae955af93a96cfdd4fb1846fd5ad7772d857f Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 12:10:52 -0800 Subject: [PATCH 18/46] remove gossiper tests for now --- plugin/evm/gossiper_atomic_gossiping_test.go | 258 ------------- plugin/evm/gossiper_eth_gossiping_test.go | 383 ------------------- plugin/evm/{gossiper.go => handler.go} | 0 3 files changed, 641 deletions(-) delete mode 100644 plugin/evm/gossiper_atomic_gossiping_test.go delete mode 100644 plugin/evm/gossiper_eth_gossiping_test.go rename plugin/evm/{gossiper.go => handler.go} (100%) diff --git a/plugin/evm/gossiper_atomic_gossiping_test.go b/plugin/evm/gossiper_atomic_gossiping_test.go deleted file mode 100644 index 267aaf73e2..0000000000 --- a/plugin/evm/gossiper_atomic_gossiping_test.go +++ /dev/null @@ -1,258 +0,0 @@ -// (c) 2019-2021, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package evm - -import ( - "context" - "os" - "sync" - "testing" - "time" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/snow" - "github.com/ava-labs/avalanchego/utils/set" - "github.com/stretchr/testify/assert" - - "github.com/ava-labs/coreth/plugin/evm/message" -) - -// locally issued txs should be gossiped -func TestMempoolAtmTxsIssueTxAndGossiping(t *testing.T) { - assert := assert.New(t) - - _, vm, _, sharedMemory, sender := GenesisVM(t, false, "", "", "") - defer func() { - assert.NoError(vm.Shutdown(context.Background())) - }() - assert.NoError(vm.Connected(context.Background(), ids.GenerateTestNodeID(), nil)) - - // Create conflicting transactions - importTxs := createImportTxOptions(t, vm, sharedMemory) - tx, conflictingTx := importTxs[0], importTxs[1] - - var gossiped int - var gossipedLock sync.Mutex // needed to prevent race - sender.CantSendAppGossip = false - sender.SendAppGossipF = func(_ context.Context, gossipedBytes []byte) error { - gossipedLock.Lock() - defer gossipedLock.Unlock() - - notifyMsgIntf, err := message.ParseGossipMessage(vm.networkCodec, gossipedBytes) - assert.NoError(err) - - requestMsg, ok := notifyMsgIntf.(message.AtomicTxGossip) - assert.NotEmpty(requestMsg.Tx) - assert.True(ok) - - txg := Tx{} - _, err = Codec.Unmarshal(requestMsg.Tx, &txg) - assert.NoError(err) - unsignedBytes, err := Codec.Marshal(codecVersion, &txg.UnsignedAtomicTx) - assert.NoError(err) - txg.Initialize(unsignedBytes, requestMsg.Tx) - assert.Equal(tx.ID(), txg.ID()) - gossiped++ - return nil - } - - assert.NoError(vm.SetState(context.Background(), snow.NormalOp)) - - // Optimistically gossip raw tx - assert.NoError(vm.mempool.AddLocalTx(tx)) - time.Sleep(500 * time.Millisecond) - gossipedLock.Lock() - assert.Equal(1, gossiped) - gossipedLock.Unlock() - assert.True(vm.mempool.bloom.Has(&GossipAtomicTx{Tx: tx})) - - // Test hash on retry - assert.NoError(vm.gossiper.GossipAtomicTxs([]*Tx{tx})) - gossipedLock.Lock() - assert.Equal(1, gossiped) - gossipedLock.Unlock() - - // Attempt to gossip conflicting tx - assert.ErrorIs(vm.mempool.AddLocalTx(conflictingTx), errConflictingAtomicTx) - gossipedLock.Lock() - assert.Equal(1, gossiped) - gossipedLock.Unlock() -} - -// show that a txID discovered from gossip is requested to the same node only if -// the txID is unknown -func TestMempoolAtmTxsAppGossipHandling(t *testing.T) { - assert := assert.New(t) - - _, vm, _, sharedMemory, sender := GenesisVM(t, true, "", "", "") - defer func() { - assert.NoError(vm.Shutdown(context.Background())) - }() - - nodeID := ids.GenerateTestNodeID() - - var ( - txGossiped int - txGossipedLock sync.Mutex - txRequested bool - ) - sender.CantSendAppGossip = false - sender.SendAppGossipF = func(context.Context, []byte) error { - txGossipedLock.Lock() - defer txGossipedLock.Unlock() - - txGossiped++ - return nil - } - sender.SendAppRequestF = func(context.Context, set.Set[ids.NodeID], uint32, []byte) error { - txRequested = true - return nil - } - - // Create conflicting transactions - importTxs := createImportTxOptions(t, vm, sharedMemory) - tx, conflictingTx := importTxs[0], importTxs[1] - - // gossip tx and check it is accepted and gossiped - msg := message.AtomicTxGossip{ - Tx: tx.SignedBytes(), - } - msgBytes, err := message.BuildGossipMessage(vm.networkCodec, msg) - assert.NoError(err) - - vm.ctx.Lock.Unlock() - - // show that no txID is requested - assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) - time.Sleep(500 * time.Millisecond) - - vm.ctx.Lock.Lock() - - assert.False(txRequested, "tx should not have been requested") - txGossipedLock.Lock() - assert.Equal(1, txGossiped, "tx should have been gossiped") - txGossipedLock.Unlock() - assert.True(vm.mempool.has(tx.ID())) - - vm.ctx.Lock.Unlock() - - // show that tx is not re-gossiped - assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) - - vm.ctx.Lock.Lock() - - txGossipedLock.Lock() - assert.Equal(1, txGossiped, "tx should have only been gossiped once") - txGossipedLock.Unlock() - - // show that conflicting tx is not added to mempool - msg = message.AtomicTxGossip{ - Tx: conflictingTx.SignedBytes(), - } - msgBytes, err = message.BuildGossipMessage(vm.networkCodec, msg) - assert.NoError(err) - - vm.ctx.Lock.Unlock() - - assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) - - vm.ctx.Lock.Lock() - - assert.False(txRequested, "tx should not have been requested") - txGossipedLock.Lock() - assert.Equal(1, txGossiped, "tx should not have been gossiped") - txGossipedLock.Unlock() - assert.False(vm.mempool.has(conflictingTx.ID()), "conflicting tx should not be in the atomic mempool") -} - -// show that txs already marked as invalid are not re-requested on gossiping -func TestMempoolAtmTxsAppGossipHandlingDiscardedTx(t *testing.T) { - if os.Getenv("RUN_FLAKY_TESTS") != "true" { - t.Skip("FLAKY") - } - assert := assert.New(t) - - _, vm, _, sharedMemory, sender := GenesisVM(t, true, "", "", "") - defer func() { - assert.NoError(vm.Shutdown(context.Background())) - }() - mempool := vm.mempool - - var ( - txGossiped int - txGossipedLock sync.Mutex - txRequested bool - ) - sender.CantSendAppGossip = false - sender.SendAppGossipF = func(context.Context, []byte) error { - txGossipedLock.Lock() - defer txGossipedLock.Unlock() - - txGossiped++ - return nil - } - sender.SendAppRequestF = func(context.Context, set.Set[ids.NodeID], uint32, []byte) error { - txRequested = true - return nil - } - - // Create a transaction and mark it as invalid by discarding it - importTxs := createImportTxOptions(t, vm, sharedMemory) - tx, conflictingTx := importTxs[0], importTxs[1] - txID := tx.ID() - - mempool.AddTx(tx) - mempool.NextTx() - mempool.DiscardCurrentTx(txID) - - // Check the mempool does not contain the discarded transaction - assert.False(mempool.has(txID)) - - // Gossip the transaction to the VM and ensure that it is not added to the mempool - // and is not re-gossipped. - nodeID := ids.GenerateTestNodeID() - msg := message.AtomicTxGossip{ - Tx: tx.SignedBytes(), - } - msgBytes, err := message.BuildGossipMessage(vm.networkCodec, msg) - assert.NoError(err) - - vm.ctx.Lock.Unlock() - - assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) - - vm.ctx.Lock.Lock() - - assert.False(txRequested, "tx shouldn't be requested") - txGossipedLock.Lock() - assert.Zero(txGossiped, "tx should not have been gossiped") - txGossipedLock.Unlock() - - assert.False(mempool.has(txID)) - - // Gossip the transaction that conflicts with the originally - // discarded tx and ensure it is accepted into the mempool and gossipped - // to the network. - nodeID = ids.GenerateTestNodeID() - msg = message.AtomicTxGossip{ - Tx: conflictingTx.SignedBytes(), - } - msgBytes, err = message.BuildGossipMessage(vm.networkCodec, msg) - assert.NoError(err) - - vm.ctx.Lock.Unlock() - - assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) - time.Sleep(500 * time.Millisecond) - - vm.ctx.Lock.Lock() - - assert.False(txRequested, "tx shouldn't be requested") - txGossipedLock.Lock() - assert.Equal(1, txGossiped, "conflicting tx should have been gossiped") - txGossipedLock.Unlock() - - assert.False(mempool.has(txID)) - assert.True(mempool.has(conflictingTx.ID())) -} diff --git a/plugin/evm/gossiper_eth_gossiping_test.go b/plugin/evm/gossiper_eth_gossiping_test.go deleted file mode 100644 index 97e7b831f1..0000000000 --- a/plugin/evm/gossiper_eth_gossiping_test.go +++ /dev/null @@ -1,383 +0,0 @@ -// (c) 2019-2021, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package evm - -import ( - "context" - "crypto/ecdsa" - "encoding/json" - "math/big" - "os" - "strings" - "sync" - "testing" - "time" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/set" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" - - "github.com/stretchr/testify/assert" - - "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/message" -) - -func fundAddressByGenesis(addrs []common.Address) (string, error) { - balance := big.NewInt(0xffffffffffffff) - genesis := &core.Genesis{ - Difficulty: common.Big0, - GasLimit: uint64(5000000), - } - funds := make(map[common.Address]core.GenesisAccount) - for _, addr := range addrs { - funds[addr] = core.GenesisAccount{ - Balance: balance, - } - } - genesis.Alloc = funds - genesis.Config = params.TestChainConfig - - bytes, err := json.Marshal(genesis) - return string(bytes), err -} - -func getValidEthTxs(key *ecdsa.PrivateKey, count int, gasPrice *big.Int) []*types.Transaction { - res := make([]*types.Transaction, count) - - to := common.Address{} - amount := big.NewInt(0) - gasLimit := uint64(37000) - - for i := 0; i < count; i++ { - tx, _ := types.SignTx( - types.NewTransaction( - uint64(i), - to, - amount, - gasLimit, - gasPrice, - []byte(strings.Repeat("aaaaaaaaaa", 100))), - types.HomesteadSigner{}, key) - tx.SetFirstSeen(time.Now().Add(-1 * time.Minute)) - res[i] = tx - } - return res -} - -// show that locally issued eth txs are gossiped -// Note: channel through which coreth mempool push txs to vm is injected here -// to ease up UT, which target only VM behaviors in response to coreth mempool -// signals -func TestMempoolEthTxsAddedTxsGossipedAfterActivation(t *testing.T) { - if os.Getenv("RUN_FLAKY_TESTS") != "true" { - t.Skip("FLAKY") - } - assert := assert.New(t) - - key, err := crypto.GenerateKey() - assert.NoError(err) - - addr := crypto.PubkeyToAddress(key.PublicKey) - - genesisJSON, err := fundAddressByGenesis([]common.Address{addr}) - assert.NoError(err) - - _, vm, _, _, sender := GenesisVM(t, true, genesisJSON, "", "") - defer func() { - err := vm.Shutdown(context.Background()) - assert.NoError(err) - }() - vm.txPool.SetGasPrice(common.Big1) - vm.txPool.SetMinFee(common.Big0) - - // create eth txes - ethTxs := getValidEthTxs(key, 3, common.Big1) - - var wg sync.WaitGroup - wg.Add(2) - sender.CantSendAppGossip = false - signal1 := make(chan struct{}) - seen := 0 - sender.SendAppGossipF = func(_ context.Context, gossipedBytes []byte) error { - if seen == 0 { - notifyMsgIntf, err := message.ParseGossipMessage(vm.networkCodec, gossipedBytes) - assert.NoError(err) - - requestMsg, ok := notifyMsgIntf.(message.EthTxsGossip) - assert.True(ok) - assert.NotEmpty(requestMsg.Txs) - - txs := make([]*types.Transaction, 0) - assert.NoError(rlp.DecodeBytes(requestMsg.Txs, &txs)) - assert.Len(txs, 2) - assert.ElementsMatch( - []common.Hash{ethTxs[0].Hash(), ethTxs[1].Hash()}, - []common.Hash{txs[0].Hash(), txs[1].Hash()}, - ) - seen++ - close(signal1) - } else if seen == 1 { - notifyMsgIntf, err := message.ParseGossipMessage(vm.networkCodec, gossipedBytes) - assert.NoError(err) - - requestMsg, ok := notifyMsgIntf.(message.EthTxsGossip) - assert.True(ok) - assert.NotEmpty(requestMsg.Txs) - - txs := make([]*types.Transaction, 0) - assert.NoError(rlp.DecodeBytes(requestMsg.Txs, &txs)) - assert.Len(txs, 1) - assert.Equal(ethTxs[2].Hash(), txs[0].Hash()) - - seen++ - } else { - t.Fatal("should not be seen 3 times") - } - wg.Done() - return nil - } - - // Notify VM about eth txs - errs := vm.txPool.AddRemotesSync(ethTxs[:2]) - for _, err := range errs { - assert.NoError(err, "failed adding coreth tx to mempool") - } - - // Gossip txs again (shouldn't gossip hashes) - <-signal1 // wait until reorg processed - assert.NoError(vm.gossiper.GossipEthTxs(ethTxs[:2])) - - errs = vm.txPool.AddRemotesSync(ethTxs) - assert.Contains(errs[0].Error(), "already known") - assert.Contains(errs[1].Error(), "already known") - assert.NoError(errs[2], "failed adding coreth tx to mempool") - - attemptAwait(t, &wg, 5*time.Second) -} - -// show that locally issued eth txs are chunked correctly -func TestMempoolEthTxsAddedTxsGossipedAfterActivationChunking(t *testing.T) { - if os.Getenv("RUN_FLAKY_TESTS") != "true" { - t.Skip("FLAKY") - } - assert := assert.New(t) - - key, err := crypto.GenerateKey() - assert.NoError(err) - - addr := crypto.PubkeyToAddress(key.PublicKey) - - genesisJSON, err := fundAddressByGenesis([]common.Address{addr}) - assert.NoError(err) - - _, vm, _, _, sender := GenesisVM(t, true, genesisJSON, "", "") - defer func() { - err := vm.Shutdown(context.Background()) - assert.NoError(err) - }() - vm.txPool.SetGasPrice(common.Big1) - vm.txPool.SetMinFee(common.Big0) - - // create eth txes - ethTxs := getValidEthTxs(key, 100, common.Big1) - - var wg sync.WaitGroup - wg.Add(2) - sender.CantSendAppGossip = false - seen := map[common.Hash]struct{}{} - sender.SendAppGossipF = func(_ context.Context, gossipedBytes []byte) error { - notifyMsgIntf, err := message.ParseGossipMessage(vm.networkCodec, gossipedBytes) - assert.NoError(err) - - requestMsg, ok := notifyMsgIntf.(message.EthTxsGossip) - assert.True(ok) - assert.NotEmpty(requestMsg.Txs) - - txs := make([]*types.Transaction, 0) - assert.NoError(rlp.DecodeBytes(requestMsg.Txs, &txs)) - for _, tx := range txs { - seen[tx.Hash()] = struct{}{} - } - wg.Done() - return nil - } - - // Notify VM about eth txs - errs := vm.txPool.AddRemotesSync(ethTxs) - for _, err := range errs { - assert.NoError(err, "failed adding coreth tx to mempool") - } - - attemptAwait(t, &wg, 5*time.Second) - - for _, tx := range ethTxs { - _, ok := seen[tx.Hash()] - assert.True(ok, "missing hash: %v", tx.Hash()) - } -} - -// show that a geth tx discovered from gossip is requested to the same node that -// gossiped it -func TestMempoolEthTxsAppGossipHandling(t *testing.T) { - if os.Getenv("RUN_FLAKY_TESTS") != "true" { - t.Skip("FLAKY") - } - assert := assert.New(t) - - key, err := crypto.GenerateKey() - assert.NoError(err) - - addr := crypto.PubkeyToAddress(key.PublicKey) - - genesisJSON, err := fundAddressByGenesis([]common.Address{addr}) - assert.NoError(err) - - _, vm, _, _, sender := GenesisVM(t, true, genesisJSON, "", "") - defer func() { - err := vm.Shutdown(context.Background()) - assert.NoError(err) - }() - vm.txPool.SetGasPrice(common.Big1) - vm.txPool.SetMinFee(common.Big0) - - var ( - wg sync.WaitGroup - txRequested bool - ) - sender.CantSendAppGossip = false - sender.SendAppRequestF = func(context.Context, set.Set[ids.NodeID], uint32, []byte) error { - txRequested = true - return nil - } - wg.Add(1) - sender.SendAppGossipF = func(context.Context, []byte) error { - wg.Done() - return nil - } - - // prepare a tx - tx := getValidEthTxs(key, 1, common.Big1)[0] - - // show that unknown coreth hashes is requested - txBytes, err := rlp.EncodeToBytes([]*types.Transaction{tx}) - assert.NoError(err) - msg := message.EthTxsGossip{ - Txs: txBytes, - } - msgBytes, err := message.BuildGossipMessage(vm.networkCodec, msg) - assert.NoError(err) - - nodeID := ids.GenerateTestNodeID() - err = vm.AppGossip(context.Background(), nodeID, msgBytes) - assert.NoError(err) - assert.False(txRequested, "tx should not be requested") - - // wait for transaction to be re-gossiped - attemptAwait(t, &wg, 5*time.Second) -} - -func TestMempoolEthTxsRegossipSingleAccount(t *testing.T) { - assert := assert.New(t) - - key, err := crypto.GenerateKey() - assert.NoError(err) - - addr := crypto.PubkeyToAddress(key.PublicKey) - - genesisJSON, err := fundAddressByGenesis([]common.Address{addr}) - assert.NoError(err) - - _, vm, _, _, _ := GenesisVM(t, true, genesisJSON, `{"local-txs-enabled":true}`, "") - defer func() { - err := vm.Shutdown(context.Background()) - assert.NoError(err) - }() - vm.txPool.SetGasPrice(common.Big1) - vm.txPool.SetMinFee(common.Big0) - - // create eth txes - ethTxs := getValidEthTxs(key, 10, big.NewInt(226*params.GWei)) - - // Notify VM about eth txs - errs := vm.txPool.AddRemotesSync(ethTxs) - for _, err := range errs { - assert.NoError(err, "failed adding coreth tx to remote mempool") - } - - // Only 1 transaction will be regossiped for an address (should be lowest - // nonce) - pushNetwork := vm.gossiper.(*pushGossiper) - queued := pushNetwork.queueRegossipTxs() - assert.Len(queued, 1, "unexpected length of queued txs") - assert.Equal(ethTxs[0].Hash(), queued[0].Hash()) -} - -func TestMempoolEthTxsRegossip(t *testing.T) { - assert := assert.New(t) - - keys := make([]*ecdsa.PrivateKey, 20) - addrs := make([]common.Address, 20) - for i := 0; i < 20; i++ { - key, err := crypto.GenerateKey() - assert.NoError(err) - keys[i] = key - addrs[i] = crypto.PubkeyToAddress(key.PublicKey) - } - - genesisJSON, err := fundAddressByGenesis(addrs) - assert.NoError(err) - - _, vm, _, _, _ := GenesisVM(t, true, genesisJSON, `{"local-txs-enabled":true}`, "") - defer func() { - err := vm.Shutdown(context.Background()) - assert.NoError(err) - }() - vm.txPool.SetGasPrice(common.Big1) - vm.txPool.SetMinFee(common.Big0) - - // create eth txes - ethTxs := make([]*types.Transaction, 20) - ethTxHashes := make([]common.Hash, 20) - for i := 0; i < 20; i++ { - txs := getValidEthTxs(keys[i], 1, big.NewInt(226*params.GWei)) - tx := txs[0] - ethTxs[i] = tx - ethTxHashes[i] = tx.Hash() - } - - // Notify VM about eth txs - errs := vm.txPool.AddRemotesSync(ethTxs[:10]) - for _, err := range errs { - assert.NoError(err, "failed adding coreth tx to remote mempool") - } - errs = vm.txPool.AddLocals(ethTxs[10:]) - for _, err := range errs { - assert.NoError(err, "failed adding coreth tx to local mempool") - } - - // We expect 15 transactions (the default max number of transactions to - // regossip) comprised of 10 local txs and 5 remote txs (we prioritize local - // txs over remote). - pushNetwork := vm.gossiper.(*pushGossiper) - queued := pushNetwork.queueRegossipTxs() - assert.Len(queued, 15, "unexpected length of queued txs") - - // Confirm queued transactions (should be ordered based on - // timestamp submitted, with local priorized over remote) - queuedTxHashes := make([]common.Hash, 15) - for i, tx := range queued { - queuedTxHashes[i] = tx.Hash() - } - assert.ElementsMatch(queuedTxHashes[:10], ethTxHashes[10:], "missing local transactions") - - // NOTE: We don't care which remote transactions are included in this test - // (due to the non-deterministic way pending transactions are surfaced, this can be difficult - // to assert as well). -} diff --git a/plugin/evm/gossiper.go b/plugin/evm/handler.go similarity index 100% rename from plugin/evm/gossiper.go rename to plugin/evm/handler.go From 4b9b68c9c82406df42d50b3a9b15637a8ebd9de0 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 12:15:48 -0800 Subject: [PATCH 19/46] re-add getValidEthTxs --- plugin/evm/gossip_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/plugin/evm/gossip_test.go b/plugin/evm/gossip_test.go index 9c924a0034..2d810d8b18 100644 --- a/plugin/evm/gossip_test.go +++ b/plugin/evm/gossip_test.go @@ -5,7 +5,9 @@ package evm import ( "context" + "crypto/ecdsa" "math/big" + "strings" "testing" "time" @@ -27,6 +29,29 @@ import ( "github.com/stretchr/testify/require" ) +func getValidEthTxs(key *ecdsa.PrivateKey, count int, gasPrice *big.Int) []*types.Transaction { + res := make([]*types.Transaction, count) + + to := common.Address{} + amount := big.NewInt(0) + gasLimit := uint64(37000) + + for i := 0; i < count; i++ { + tx, _ := types.SignTx( + types.NewTransaction( + uint64(i), + to, + amount, + gasLimit, + gasPrice, + []byte(strings.Repeat("aaaaaaaaaa", 100))), + types.HomesteadSigner{}, key) + tx.SetFirstSeen(time.Now().Add(-1 * time.Minute)) + res[i] = tx + } + return res +} + func TestGossipAtomicTxMarshaller(t *testing.T) { require := require.New(t) From 4103f53c9f597da1033c664f9f12d1476ed50919 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 12:21:07 -0800 Subject: [PATCH 20/46] update avalanchego --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d6affc97bc..d9959e82d6 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/VictoriaMetrics/fastcache v1.10.0 - github.com/ava-labs/avalanchego v1.11.1-0.20240227184630-35fc54b9c0ef + github.com/ava-labs/avalanchego v1.11.1-0.20240227201848-5de194a57144 github.com/cespare/cp v0.1.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 diff --git a/go.sum b/go.sum index 48fb659a34..8a12c437fe 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.11.1-0.20240227184630-35fc54b9c0ef h1:9fKOGMYwCElOrDK0w2XAt2X+S4NKiubqlUUWMtpIOus= -github.com/ava-labs/avalanchego v1.11.1-0.20240227184630-35fc54b9c0ef/go.mod h1:X1KT5ukTfCzkI0+AFGOPa+wp/8AYzn2hoXbp75nRTJE= +github.com/ava-labs/avalanchego v1.11.1-0.20240227201848-5de194a57144 h1:zKl3KmjO5pP8ycYcNZ9+W29MQo7mhlMOnufGcivuseY= +github.com/ava-labs/avalanchego v1.11.1-0.20240227201848-5de194a57144/go.mod h1:X1KT5ukTfCzkI0+AFGOPa+wp/8AYzn2hoXbp75nRTJE= 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= From 501a4269004eb48ad67b9ef28c222de91d46d0f0 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 12:27:17 -0800 Subject: [PATCH 21/46] fix err --- plugin/evm/tx_gossip_test.go | 2 ++ plugin/evm/vm.go | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index 6e6f6eca74..17b2d52b3a 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -332,6 +332,7 @@ func TestEthTxPushGossipOutbound(t *testing.T) { // issue a tx require.NoError(vm.txPool.AddLocal(signedTx)) + vm.ethTxPushGossiper.Add(&GossipEthTx{signedTx}) sent := <-sender.SentAppGossip got := &sdk.PushGossip{} @@ -476,6 +477,7 @@ func TestAtomicTxPushGossipOutbound(t *testing.T) { tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) require.NoError(err) require.NoError(vm.mempool.AddLocalTx(tx)) + vm.atomicTxPushGossiper.Add(&GossipAtomicTx{tx}) gossipedBytes := <-sender.SentAppGossip require.Equal(byte(atomicTxGossipProtocol), gossipedBytes[0]) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 0b44812761..1f5d92f8b5 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -145,7 +145,7 @@ const ( // gossip constants pushGossipFrequency = 100 * time.Millisecond - pushGossipDiscardedSize = 4096 + pushGossipDiscardedSize = 16_384 pushRegossipFrequency = 10 * time.Second txGossipBloomMinTargetElements = 8 * 1024 txGossipBloomTargetFalsePositiveRate = 0.01 @@ -1102,7 +1102,7 @@ func (vm *VM) initBlockBuilding() error { } if vm.ethTxPushGossiper == nil { - vm.ethTxPushGossiper = gossip.NewPushGossiper[*GossipEthTx]( + vm.ethTxPushGossiper, err = gossip.NewPushGossiper[*GossipEthTx]( ethTxGossipMarshaller, ethTxPool, ethTxGossipClient, @@ -1111,10 +1111,13 @@ func (vm *VM) initBlockBuilding() error { txGossipTargetMessageSize, pushRegossipFrequency, ) + if err != nil { + return fmt.Errorf("failed to initialize eth tx push gossiper: %w", err) + } } if vm.atomicTxPushGossiper == nil { - vm.atomicTxPushGossiper = gossip.NewPushGossiper[*GossipAtomicTx]( + vm.atomicTxPushGossiper, err = gossip.NewPushGossiper[*GossipAtomicTx]( atomicTxGossipMarshaller, vm.mempool, atomicTxGossipClient, @@ -1123,6 +1126,9 @@ func (vm *VM) initBlockBuilding() error { txGossipTargetMessageSize, pushRegossipFrequency, ) + if err != nil { + return fmt.Errorf("failed to initialize atomic tx push gossiper: %w", err) + } } // NOTE: gossip network must be initialized first otherwise ETH tx gossip will not work. From 4cabbbe35784672972cd77e3a09778d1558cf4f5 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 12:34:00 -0800 Subject: [PATCH 22/46] update version file to match --- scripts/versions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/versions.sh b/scripts/versions.sh index 698cd4b7e6..30a208d0c9 100644 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -6,4 +6,4 @@ set -euo pipefail # Don't export them as they're used in the context of other calls -avalanche_version=${AVALANCHE_VERSION:-'v1.11.1'} +avalanche_version=${AVALANCHE_VERSION:-'5de194a571442da6960c6da2ea1dce291249291c'} From c0d271b9e813639501feba7248750644b4b6f6a6 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 12:38:57 -0800 Subject: [PATCH 23/46] re-add legacy handling tests --- plugin/evm/gossiper_atomic_gossiping_test.go | 195 +++++++++++++++++++ plugin/evm/gossiper_eth_gossiping_test.go | 107 ++++++++++ 2 files changed, 302 insertions(+) create mode 100644 plugin/evm/gossiper_atomic_gossiping_test.go create mode 100644 plugin/evm/gossiper_eth_gossiping_test.go diff --git a/plugin/evm/gossiper_atomic_gossiping_test.go b/plugin/evm/gossiper_atomic_gossiping_test.go new file mode 100644 index 0000000000..4323d3ebf9 --- /dev/null +++ b/plugin/evm/gossiper_atomic_gossiping_test.go @@ -0,0 +1,195 @@ +// (c) 2019-2021, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + "os" + "sync" + "testing" + "time" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/stretchr/testify/assert" + + "github.com/ava-labs/coreth/plugin/evm/message" +) + +// show that a txID discovered from gossip is requested to the same node only if +// the txID is unknown +func TestMempoolAtmTxsAppGossipHandling(t *testing.T) { + assert := assert.New(t) + + _, vm, _, sharedMemory, sender := GenesisVM(t, true, "", "", "") + defer func() { + assert.NoError(vm.Shutdown(context.Background())) + }() + + nodeID := ids.GenerateTestNodeID() + + var ( + txGossiped int + txGossipedLock sync.Mutex + txRequested bool + ) + sender.CantSendAppGossip = false + sender.SendAppGossipF = func(context.Context, []byte) error { + txGossipedLock.Lock() + defer txGossipedLock.Unlock() + + txGossiped++ + return nil + } + sender.SendAppRequestF = func(context.Context, set.Set[ids.NodeID], uint32, []byte) error { + txRequested = true + return nil + } + + // Create conflicting transactions + importTxs := createImportTxOptions(t, vm, sharedMemory) + tx, conflictingTx := importTxs[0], importTxs[1] + + // gossip tx and check it is accepted and gossiped + msg := message.AtomicTxGossip{ + Tx: tx.SignedBytes(), + } + msgBytes, err := message.BuildGossipMessage(vm.networkCodec, msg) + assert.NoError(err) + + vm.ctx.Lock.Unlock() + + // show that no txID is requested + assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) + time.Sleep(500 * time.Millisecond) + + vm.ctx.Lock.Lock() + + assert.False(txRequested, "tx should not have been requested") + txGossipedLock.Lock() + assert.Equal(1, txGossiped, "tx should have been gossiped") + txGossipedLock.Unlock() + assert.True(vm.mempool.has(tx.ID())) + + vm.ctx.Lock.Unlock() + + // show that tx is not re-gossiped + assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) + + vm.ctx.Lock.Lock() + + txGossipedLock.Lock() + assert.Equal(1, txGossiped, "tx should have only been gossiped once") + txGossipedLock.Unlock() + + // show that conflicting tx is not added to mempool + msg = message.AtomicTxGossip{ + Tx: conflictingTx.SignedBytes(), + } + msgBytes, err = message.BuildGossipMessage(vm.networkCodec, msg) + assert.NoError(err) + + vm.ctx.Lock.Unlock() + + assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) + + vm.ctx.Lock.Lock() + + assert.False(txRequested, "tx should not have been requested") + txGossipedLock.Lock() + assert.Equal(1, txGossiped, "tx should not have been gossiped") + txGossipedLock.Unlock() + assert.False(vm.mempool.has(conflictingTx.ID()), "conflicting tx should not be in the atomic mempool") +} + +// show that txs already marked as invalid are not re-requested on gossiping +func TestMempoolAtmTxsAppGossipHandlingDiscardedTx(t *testing.T) { + if os.Getenv("RUN_FLAKY_TESTS") != "true" { + t.Skip("FLAKY") + } + assert := assert.New(t) + + _, vm, _, sharedMemory, sender := GenesisVM(t, true, "", "", "") + defer func() { + assert.NoError(vm.Shutdown(context.Background())) + }() + mempool := vm.mempool + + var ( + txGossiped int + txGossipedLock sync.Mutex + txRequested bool + ) + sender.CantSendAppGossip = false + sender.SendAppGossipF = func(context.Context, []byte) error { + txGossipedLock.Lock() + defer txGossipedLock.Unlock() + + txGossiped++ + return nil + } + sender.SendAppRequestF = func(context.Context, set.Set[ids.NodeID], uint32, []byte) error { + txRequested = true + return nil + } + + // Create a transaction and mark it as invalid by discarding it + importTxs := createImportTxOptions(t, vm, sharedMemory) + tx, conflictingTx := importTxs[0], importTxs[1] + txID := tx.ID() + + mempool.AddTx(tx) + mempool.NextTx() + mempool.DiscardCurrentTx(txID) + + // Check the mempool does not contain the discarded transaction + assert.False(mempool.has(txID)) + + // Gossip the transaction to the VM and ensure that it is not added to the mempool + // and is not re-gossipped. + nodeID := ids.GenerateTestNodeID() + msg := message.AtomicTxGossip{ + Tx: tx.SignedBytes(), + } + msgBytes, err := message.BuildGossipMessage(vm.networkCodec, msg) + assert.NoError(err) + + vm.ctx.Lock.Unlock() + + assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) + + vm.ctx.Lock.Lock() + + assert.False(txRequested, "tx shouldn't be requested") + txGossipedLock.Lock() + assert.Zero(txGossiped, "tx should not have been gossiped") + txGossipedLock.Unlock() + + assert.False(mempool.has(txID)) + + // Gossip the transaction that conflicts with the originally + // discarded tx and ensure it is accepted into the mempool and gossipped + // to the network. + nodeID = ids.GenerateTestNodeID() + msg = message.AtomicTxGossip{ + Tx: conflictingTx.SignedBytes(), + } + msgBytes, err = message.BuildGossipMessage(vm.networkCodec, msg) + assert.NoError(err) + + vm.ctx.Lock.Unlock() + + assert.NoError(vm.AppGossip(context.Background(), nodeID, msgBytes)) + time.Sleep(500 * time.Millisecond) + + vm.ctx.Lock.Lock() + + assert.False(txRequested, "tx shouldn't be requested") + txGossipedLock.Lock() + assert.Equal(1, txGossiped, "conflicting tx should have been gossiped") + txGossipedLock.Unlock() + + assert.False(mempool.has(txID)) + assert.True(mempool.has(conflictingTx.ID())) +} diff --git a/plugin/evm/gossiper_eth_gossiping_test.go b/plugin/evm/gossiper_eth_gossiping_test.go new file mode 100644 index 0000000000..ba082e357c --- /dev/null +++ b/plugin/evm/gossiper_eth_gossiping_test.go @@ -0,0 +1,107 @@ +// (c) 2019-2021, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + "encoding/json" + "math/big" + "os" + "sync" + "testing" + "time" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/set" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" + + "github.com/stretchr/testify/assert" + + "github.com/ava-labs/coreth/core" + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/plugin/evm/message" +) + +func fundAddressByGenesis(addrs []common.Address) (string, error) { + balance := big.NewInt(0xffffffffffffff) + genesis := &core.Genesis{ + Difficulty: common.Big0, + GasLimit: uint64(5000000), + } + funds := make(map[common.Address]core.GenesisAccount) + for _, addr := range addrs { + funds[addr] = core.GenesisAccount{ + Balance: balance, + } + } + genesis.Alloc = funds + genesis.Config = params.TestChainConfig + + bytes, err := json.Marshal(genesis) + return string(bytes), err +} + +// show that a geth tx discovered from gossip is requested to the same node that +// gossiped it +func TestMempoolEthTxsAppGossipHandling(t *testing.T) { + if os.Getenv("RUN_FLAKY_TESTS") != "true" { + t.Skip("FLAKY") + } + assert := assert.New(t) + + key, err := crypto.GenerateKey() + assert.NoError(err) + + addr := crypto.PubkeyToAddress(key.PublicKey) + + genesisJSON, err := fundAddressByGenesis([]common.Address{addr}) + assert.NoError(err) + + _, vm, _, _, sender := GenesisVM(t, true, genesisJSON, "", "") + defer func() { + err := vm.Shutdown(context.Background()) + assert.NoError(err) + }() + vm.txPool.SetGasPrice(common.Big1) + vm.txPool.SetMinFee(common.Big0) + + var ( + wg sync.WaitGroup + txRequested bool + ) + sender.CantSendAppGossip = false + sender.SendAppRequestF = func(context.Context, set.Set[ids.NodeID], uint32, []byte) error { + txRequested = true + return nil + } + wg.Add(1) + sender.SendAppGossipF = func(context.Context, []byte) error { + wg.Done() + return nil + } + + // prepare a tx + tx := getValidEthTxs(key, 1, common.Big1)[0] + + // show that unknown coreth hashes is requested + txBytes, err := rlp.EncodeToBytes([]*types.Transaction{tx}) + assert.NoError(err) + msg := message.EthTxsGossip{ + Txs: txBytes, + } + msgBytes, err := message.BuildGossipMessage(vm.networkCodec, msg) + assert.NoError(err) + + nodeID := ids.GenerateTestNodeID() + err = vm.AppGossip(context.Background(), nodeID, msgBytes) + assert.NoError(err) + assert.False(txRequested, "tx should not be requested") + + // wait for transaction to be re-gossiped + attemptAwait(t, &wg, 5*time.Second) +} From ae5607a960019da5c7b0599bc7c877014c87d0b6 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 12:42:07 -0800 Subject: [PATCH 24/46] revert unnecessary changes to the test files --- plugin/evm/gossip_test.go | 25 ----------------------- plugin/evm/gossiper_eth_gossiping_test.go | 25 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/plugin/evm/gossip_test.go b/plugin/evm/gossip_test.go index 2d810d8b18..9c924a0034 100644 --- a/plugin/evm/gossip_test.go +++ b/plugin/evm/gossip_test.go @@ -5,9 +5,7 @@ package evm import ( "context" - "crypto/ecdsa" "math/big" - "strings" "testing" "time" @@ -29,29 +27,6 @@ import ( "github.com/stretchr/testify/require" ) -func getValidEthTxs(key *ecdsa.PrivateKey, count int, gasPrice *big.Int) []*types.Transaction { - res := make([]*types.Transaction, count) - - to := common.Address{} - amount := big.NewInt(0) - gasLimit := uint64(37000) - - for i := 0; i < count; i++ { - tx, _ := types.SignTx( - types.NewTransaction( - uint64(i), - to, - amount, - gasLimit, - gasPrice, - []byte(strings.Repeat("aaaaaaaaaa", 100))), - types.HomesteadSigner{}, key) - tx.SetFirstSeen(time.Now().Add(-1 * time.Minute)) - res[i] = tx - } - return res -} - func TestGossipAtomicTxMarshaller(t *testing.T) { require := require.New(t) diff --git a/plugin/evm/gossiper_eth_gossiping_test.go b/plugin/evm/gossiper_eth_gossiping_test.go index ba082e357c..f45cf0d9d4 100644 --- a/plugin/evm/gossiper_eth_gossiping_test.go +++ b/plugin/evm/gossiper_eth_gossiping_test.go @@ -5,9 +5,11 @@ package evm import ( "context" + "crypto/ecdsa" "encoding/json" "math/big" "os" + "strings" "sync" "testing" "time" @@ -46,6 +48,29 @@ func fundAddressByGenesis(addrs []common.Address) (string, error) { return string(bytes), err } +func getValidEthTxs(key *ecdsa.PrivateKey, count int, gasPrice *big.Int) []*types.Transaction { + res := make([]*types.Transaction, count) + + to := common.Address{} + amount := big.NewInt(0) + gasLimit := uint64(37000) + + for i := 0; i < count; i++ { + tx, _ := types.SignTx( + types.NewTransaction( + uint64(i), + to, + amount, + gasLimit, + gasPrice, + []byte(strings.Repeat("aaaaaaaaaa", 100))), + types.HomesteadSigner{}, key) + tx.SetFirstSeen(time.Now().Add(-1 * time.Minute)) + res[i] = tx + } + return res +} + // show that a geth tx discovered from gossip is requested to the same node that // gossiped it func TestMempoolEthTxsAppGossipHandling(t *testing.T) { From 3df79d9df8019088928eab2e3ce7901d4bb12e15 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 13:08:58 -0800 Subject: [PATCH 25/46] non-commented out tests are passing --- plugin/evm/gossiper_atomic_gossiping_test.go | 6 +- plugin/evm/tx_gossip_test.go | 1156 +++++++++--------- scripts/build_test.sh | 2 +- 3 files changed, 582 insertions(+), 582 deletions(-) diff --git a/plugin/evm/gossiper_atomic_gossiping_test.go b/plugin/evm/gossiper_atomic_gossiping_test.go index 4323d3ebf9..4ddda14b68 100644 --- a/plugin/evm/gossiper_atomic_gossiping_test.go +++ b/plugin/evm/gossiper_atomic_gossiping_test.go @@ -68,7 +68,7 @@ func TestMempoolAtmTxsAppGossipHandling(t *testing.T) { assert.False(txRequested, "tx should not have been requested") txGossipedLock.Lock() - assert.Equal(1, txGossiped, "tx should have been gossiped") + assert.Equal(0, txGossiped, "tx should not have been gossiped") txGossipedLock.Unlock() assert.True(vm.mempool.has(tx.ID())) @@ -80,7 +80,7 @@ func TestMempoolAtmTxsAppGossipHandling(t *testing.T) { vm.ctx.Lock.Lock() txGossipedLock.Lock() - assert.Equal(1, txGossiped, "tx should have only been gossiped once") + assert.Equal(0, txGossiped, "tx should not have been gossiped") txGossipedLock.Unlock() // show that conflicting tx is not added to mempool @@ -98,7 +98,7 @@ func TestMempoolAtmTxsAppGossipHandling(t *testing.T) { assert.False(txRequested, "tx should not have been requested") txGossipedLock.Lock() - assert.Equal(1, txGossiped, "tx should not have been gossiped") + assert.Equal(0, txGossiped, "tx should not have been gossiped") txGossipedLock.Unlock() assert.False(vm.mempool.has(conflictingTx.ID()), "conflicting tx should not be in the atomic mempool") } diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index 17b2d52b3a..5bd48726b9 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -3,581 +3,581 @@ package evm -import ( - "context" - "encoding/binary" - "math/big" - "sync" - "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" - agoUtils "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/prometheus/client_golang/prometheus" - "github.com/stretchr/testify/require" - - "github.com/ava-labs/avalanchego/vms/components/avax" - "github.com/ava-labs/avalanchego/vms/secp256k1fx" - - "google.golang.org/protobuf/proto" - - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/utils" -) - -func TestEthTxGossip(t *testing.T) { - require := require.New(t) - ctx := context.Background() - snowCtx := utils.TestSnowContext() - validatorState := &validators.TestState{} - snowCtx.ValidatorState = validatorState - - 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 := &common.FakeSender{ - SentAppResponse: make(chan []byte, 1), - } - vm := &VM{ - p2pSender: responseSender, - atomicTxGossipHandler: &p2p.NoOpHandler{}, - atomicTxPullGossiper: &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.FakeSender{ - SentAppRequest: make(chan []byte, 1), - } - - 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() - 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) - require.NoError(err) - emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() - request := &sdk.PullGossipRequest{ - Filter: emptyBloomFilterBytes, - Salt: agoUtils.RandomBytes(32), - } - - requestBytes, err := proto.Marshal(request) - require.NoError(err) - - wg := &sync.WaitGroup{} - wg.Add(1) - onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { - require.NoError(err) - - response := &sdk.PullGossipResponse{} - require.NoError(proto.Unmarshal(responseBytes, response)) - require.Empty(response.Gossip) - wg.Done() - } - 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 - tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) - signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) - require.NoError(err) - - errs := vm.txPool.AddLocals([]*types.Transaction{signedTx}) - require.Len(errs, 1) - require.Nil(errs[0]) - - // wait so we aren't throttled by the vm - time.Sleep(5 * time.Second) - - marshaller := GossipEthTxMarshaller{} - // Ask the VM for new transactions. We should get the newly issued tx. - wg.Add(1) - onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { - require.NoError(err) - - response := &sdk.PullGossipResponse{} - require.NoError(proto.Unmarshal(responseBytes, response)) - require.Len(response.Gossip, 1) - - gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) - require.NoError(err) - require.Equal(signedTx.Hash(), gotTx.Tx.Hash()) - - wg.Done() - } - 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 := utils.TestSnowContext() - 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) - - 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 := &common.FakeSender{ - SentAppResponse: make(chan []byte, 1), - } - vm := &VM{ - p2pSender: responseSender, - ethTxGossipHandler: &p2p.NoOpHandler{}, - ethTxPullGossiper: &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.FakeSender{ - SentAppRequest: make(chan []byte, 1), - } - 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() - 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) - require.NoError(err) - emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() - request := &sdk.PullGossipRequest{ - Filter: emptyBloomFilterBytes, - Salt: agoUtils.RandomBytes(32), - } - - requestBytes, err := proto.Marshal(request) - require.NoError(err) - - wg := &sync.WaitGroup{} - wg.Add(1) - onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { - require.NoError(err) - - response := &sdk.PullGossipResponse{} - require.NoError(proto.Unmarshal(responseBytes, response)) - require.Empty(response.Gossip) - wg.Done() - } - 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 - utxo, err := addUTXO( - memory, - snowCtx, - ids.GenerateTestID(), - 0, - snowCtx.AVAXAssetID, - 100_000_000_000, - pk.PublicKey().Address(), - ) - require.NoError(err) - 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) - - // Ask the VM for new transactions. We should get the newly issued tx. - wg.Add(1) - - marshaller := GossipAtomicTxMarshaller{} - onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { - require.NoError(err) - - response := &sdk.PullGossipResponse{} - require.NoError(proto.Unmarshal(responseBytes, response)) - require.Len(response.Gossip, 1) - - gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) - require.NoError(err) - require.Equal(tx.ID(), gotTx.GossipID()) - - wg.Done() - } - 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() -} - -// Tests that a tx is gossiped when it is issued -func TestEthTxPushGossipOutbound(t *testing.T) { - require := require.New(t) - ctx := context.Background() - snowCtx := utils.TestSnowContext() - sender := &common.FakeSender{ - SentAppGossip: make(chan []byte, 1), - } - - vm := &VM{ - p2pSender: sender, - ethTxPullGossiper: gossip.NoOpGossiper{}, - atomicTxPullGossiper: gossip.NoOpGossiper{}, - } - - 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) - - require.NoError(vm.Initialize( - ctx, - snowCtx, - memdb.New(), - genesisBytes, - nil, - nil, - make(chan common.Message), - nil, - &common.FakeSender{}, - )) - require.NoError(vm.SetState(ctx, snow.NormalOp)) - - tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) - signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) - require.NoError(err) - - // issue a tx - require.NoError(vm.txPool.AddLocal(signedTx)) - vm.ethTxPushGossiper.Add(&GossipEthTx{signedTx}) - - sent := <-sender.SentAppGossip - got := &sdk.PushGossip{} - - // we should get a message that has the protocol prefix and the gossip - // message - require.Equal(byte(ethTxGossipProtocol), sent[0]) - require.NoError(proto.Unmarshal(sent[1:], got)) - - marshaller := GossipEthTxMarshaller{} - require.Len(got.Gossip, 1) - gossipedTx, err := marshaller.UnmarshalGossip(got.Gossip[0]) - require.NoError(err) - require.Equal(ids.ID(signedTx.Hash()), gossipedTx.GossipID()) -} - -// Tests that a gossiped tx is added to the mempool and forwarded -func TestEthTxPushGossipInbound(t *testing.T) { - require := require.New(t) - ctx := context.Background() - snowCtx := utils.TestSnowContext() - - sender := &common.FakeSender{ - SentAppGossip: make(chan []byte, 1), - } - vm := &VM{ - p2pSender: sender, - ethTxPullGossiper: gossip.NoOpGossiper{}, - atomicTxPullGossiper: gossip.NoOpGossiper{}, - } - - 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) - - require.NoError(vm.Initialize( - ctx, - snowCtx, - memdb.New(), - genesisBytes, - nil, - nil, - make(chan common.Message), - nil, - &common.FakeSender{}, - )) - require.NoError(vm.SetState(ctx, snow.NormalOp)) - - tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) - signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) - require.NoError(err) - - marshaller := GossipEthTxMarshaller{} - gossipedTx := &GossipEthTx{ - Tx: signedTx, - } - gossipedTxBytes, err := marshaller.MarshalGossip(gossipedTx) - require.NoError(err) - - inboundGossip := &sdk.PushGossip{ - Gossip: [][]byte{gossipedTxBytes}, - } - - inboundGossipBytes, err := proto.Marshal(inboundGossip) - require.NoError(err) - - inboundGossipMsg := append(binary.AppendUvarint(nil, ethTxGossipProtocol), inboundGossipBytes...) - require.NoError(vm.AppGossip(ctx, ids.EmptyNodeID, inboundGossipMsg)) - - forwardedMsg := &sdk.PushGossip{} - outboundGossipBytes := <-sender.SentAppGossip - - require.Equal(byte(ethTxGossipProtocol), outboundGossipBytes[0]) - require.NoError(proto.Unmarshal(outboundGossipBytes[1:], forwardedMsg)) - require.Len(forwardedMsg.Gossip, 1) - - forwardedTx, err := marshaller.UnmarshalGossip(forwardedMsg.Gossip[0]) - require.NoError(err) - require.Equal(gossipedTx.GossipID(), forwardedTx.GossipID()) - require.True(vm.txPool.Has(signedTx.Hash())) -} - -// Tests that a tx is gossiped when it is issued -func TestAtomicTxPushGossipOutbound(t *testing.T) { - require := require.New(t) - ctx := context.Background() - snowCtx := utils.TestSnowContext() - 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) - - 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) - - sender := &common.FakeSender{ - SentAppGossip: make(chan []byte, 1), - } - vm := &VM{ - p2pSender: sender, - ethTxPullGossiper: gossip.NoOpGossiper{}, - atomicTxPullGossiper: gossip.NoOpGossiper{}, - } - - require.NoError(vm.Initialize( - ctx, - snowCtx, - memdb.New(), - genesisBytes, - nil, - nil, - make(chan common.Message), - nil, - &common.FakeSender{}, - )) - require.NoError(vm.SetState(ctx, snow.NormalOp)) - - // 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) - tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) - require.NoError(err) - require.NoError(vm.mempool.AddLocalTx(tx)) - vm.atomicTxPushGossiper.Add(&GossipAtomicTx{tx}) - - gossipedBytes := <-sender.SentAppGossip - require.Equal(byte(atomicTxGossipProtocol), gossipedBytes[0]) - - outboundGossipMsg := &sdk.PushGossip{} - require.NoError(proto.Unmarshal(gossipedBytes[1:], outboundGossipMsg)) - require.Len(outboundGossipMsg.Gossip, 1) - - marshaller := GossipAtomicTxMarshaller{} - gossipedTx, err := marshaller.UnmarshalGossip(outboundGossipMsg.Gossip[0]) - require.NoError(err) - require.Equal(tx.ID(), gossipedTx.Tx.ID()) -} - -// Tests that a tx is gossiped when it is issued -func TestAtomicTxPushGossipInbound(t *testing.T) { - require := require.New(t) - ctx := context.Background() - snowCtx := utils.TestSnowContext() - 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) - - 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) - - sender := &common.FakeSender{ - SentAppGossip: make(chan []byte, 1), - } - vm := &VM{ - p2pSender: sender, - ethTxPullGossiper: gossip.NoOpGossiper{}, - atomicTxPullGossiper: gossip.NoOpGossiper{}, - } - - require.NoError(vm.Initialize( - ctx, - snowCtx, - memdb.New(), - genesisBytes, - nil, - nil, - make(chan common.Message), - nil, - &common.FakeSender{}, - )) - require.NoError(vm.SetState(ctx, snow.NormalOp)) - - // 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) - tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) - require.NoError(err) - require.NoError(vm.mempool.AddLocalTx(tx)) - - marshaller := GossipAtomicTxMarshaller{} - gossipedTx := &GossipAtomicTx{ - Tx: tx, - } - gossipBytes, err := marshaller.MarshalGossip(gossipedTx) - require.NoError(err) - - inboundGossip := &sdk.PushGossip{ - Gossip: [][]byte{gossipBytes}, - } - inboundGossipBytes, err := proto.Marshal(inboundGossip) - require.NoError(err) - - inboundGossipMsg := append(binary.AppendUvarint(nil, atomicTxGossipProtocol), inboundGossipBytes...) - - require.NoError(vm.AppGossip(ctx, ids.EmptyNodeID, inboundGossipMsg)) - - forwardedBytes := <-sender.SentAppGossip - require.Equal(byte(atomicTxGossipProtocol), forwardedBytes[0]) - - forwardedGossipMsg := &sdk.PushGossip{} - require.NoError(proto.Unmarshal(forwardedBytes[1:], forwardedGossipMsg)) - require.Len(forwardedGossipMsg.Gossip, 1) - - forwardedTx, err := marshaller.UnmarshalGossip(forwardedGossipMsg.Gossip[0]) - require.NoError(err) - require.Equal(tx.ID(), forwardedTx.Tx.ID()) - require.True(vm.mempool.has(tx.ID())) -} +// import ( +// "context" +// "encoding/binary" +// "math/big" +// "sync" +// "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" +// agoUtils "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/prometheus/client_golang/prometheus" +// "github.com/stretchr/testify/require" +// +// "github.com/ava-labs/avalanchego/vms/components/avax" +// "github.com/ava-labs/avalanchego/vms/secp256k1fx" +// +// "google.golang.org/protobuf/proto" +// +// "github.com/ava-labs/coreth/core/types" +// "github.com/ava-labs/coreth/params" +// "github.com/ava-labs/coreth/utils" +// ) +// +// func TestEthTxGossip(t *testing.T) { +// require := require.New(t) +// ctx := context.Background() +// snowCtx := utils.TestSnowContext() +// validatorState := &validators.TestState{} +// snowCtx.ValidatorState = validatorState +// +// 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 := &common.FakeSender{ +// SentAppResponse: make(chan []byte, 1), +// } +// vm := &VM{ +// p2pSender: responseSender, +// atomicTxGossipHandler: &p2p.NoOpHandler{}, +// atomicTxPullGossiper: &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.FakeSender{ +// SentAppRequest: make(chan []byte, 1), +// } +// +// 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() +// 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) +// require.NoError(err) +// emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() +// request := &sdk.PullGossipRequest{ +// Filter: emptyBloomFilterBytes, +// Salt: agoUtils.RandomBytes(32), +// } +// +// requestBytes, err := proto.Marshal(request) +// require.NoError(err) +// +// wg := &sync.WaitGroup{} +// wg.Add(1) +// onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { +// require.NoError(err) +// +// response := &sdk.PullGossipResponse{} +// require.NoError(proto.Unmarshal(responseBytes, response)) +// require.Empty(response.Gossip) +// wg.Done() +// } +// 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 +// tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) +// signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) +// require.NoError(err) +// +// errs := vm.txPool.AddLocals([]*types.Transaction{signedTx}) +// require.Len(errs, 1) +// require.Nil(errs[0]) +// +// // wait so we aren't throttled by the vm +// time.Sleep(5 * time.Second) +// +// marshaller := GossipEthTxMarshaller{} +// // Ask the VM for new transactions. We should get the newly issued tx. +// wg.Add(1) +// onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { +// require.NoError(err) +// +// response := &sdk.PullGossipResponse{} +// require.NoError(proto.Unmarshal(responseBytes, response)) +// require.Len(response.Gossip, 1) +// +// gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) +// require.NoError(err) +// require.Equal(signedTx.Hash(), gotTx.Tx.Hash()) +// +// wg.Done() +// } +// 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 := utils.TestSnowContext() +// 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) +// +// 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 := &common.FakeSender{ +// SentAppResponse: make(chan []byte, 1), +// } +// vm := &VM{ +// p2pSender: responseSender, +// ethTxGossipHandler: &p2p.NoOpHandler{}, +// ethTxPullGossiper: &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.FakeSender{ +// SentAppRequest: make(chan []byte, 1), +// } +// 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() +// 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) +// require.NoError(err) +// emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() +// request := &sdk.PullGossipRequest{ +// Filter: emptyBloomFilterBytes, +// Salt: agoUtils.RandomBytes(32), +// } +// +// requestBytes, err := proto.Marshal(request) +// require.NoError(err) +// +// wg := &sync.WaitGroup{} +// wg.Add(1) +// onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { +// require.NoError(err) +// +// response := &sdk.PullGossipResponse{} +// require.NoError(proto.Unmarshal(responseBytes, response)) +// require.Empty(response.Gossip) +// wg.Done() +// } +// 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 +// utxo, err := addUTXO( +// memory, +// snowCtx, +// ids.GenerateTestID(), +// 0, +// snowCtx.AVAXAssetID, +// 100_000_000_000, +// pk.PublicKey().Address(), +// ) +// require.NoError(err) +// 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) +// +// // Ask the VM for new transactions. We should get the newly issued tx. +// wg.Add(1) +// +// marshaller := GossipAtomicTxMarshaller{} +// onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { +// require.NoError(err) +// +// response := &sdk.PullGossipResponse{} +// require.NoError(proto.Unmarshal(responseBytes, response)) +// require.Len(response.Gossip, 1) +// +// gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) +// require.NoError(err) +// require.Equal(tx.ID(), gotTx.GossipID()) +// +// wg.Done() +// } +// 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() +// } +// +// // Tests that a tx is gossiped when it is issued +// func TestEthTxPushGossipOutbound(t *testing.T) { +// require := require.New(t) +// ctx := context.Background() +// snowCtx := utils.TestSnowContext() +// sender := &common.FakeSender{ +// SentAppGossip: make(chan []byte, 1), +// } +// +// vm := &VM{ +// p2pSender: sender, +// ethTxPullGossiper: gossip.NoOpGossiper{}, +// atomicTxPullGossiper: gossip.NoOpGossiper{}, +// } +// +// 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) +// +// require.NoError(vm.Initialize( +// ctx, +// snowCtx, +// memdb.New(), +// genesisBytes, +// nil, +// nil, +// make(chan common.Message), +// nil, +// &common.FakeSender{}, +// )) +// require.NoError(vm.SetState(ctx, snow.NormalOp)) +// +// tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) +// signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) +// require.NoError(err) +// +// // issue a tx +// require.NoError(vm.txPool.AddLocal(signedTx)) +// vm.ethTxPushGossiper.Add(&GossipEthTx{signedTx}) +// +// sent := <-sender.SentAppGossip +// got := &sdk.PushGossip{} +// +// // we should get a message that has the protocol prefix and the gossip +// // message +// require.Equal(byte(ethTxGossipProtocol), sent[0]) +// require.NoError(proto.Unmarshal(sent[1:], got)) +// +// marshaller := GossipEthTxMarshaller{} +// require.Len(got.Gossip, 1) +// gossipedTx, err := marshaller.UnmarshalGossip(got.Gossip[0]) +// require.NoError(err) +// require.Equal(ids.ID(signedTx.Hash()), gossipedTx.GossipID()) +// } +// +// // Tests that a gossiped tx is added to the mempool and forwarded +// func TestEthTxPushGossipInbound(t *testing.T) { +// require := require.New(t) +// ctx := context.Background() +// snowCtx := utils.TestSnowContext() +// +// sender := &common.FakeSender{ +// SentAppGossip: make(chan []byte, 1), +// } +// vm := &VM{ +// p2pSender: sender, +// ethTxPullGossiper: gossip.NoOpGossiper{}, +// atomicTxPullGossiper: gossip.NoOpGossiper{}, +// } +// +// 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) +// +// require.NoError(vm.Initialize( +// ctx, +// snowCtx, +// memdb.New(), +// genesisBytes, +// nil, +// nil, +// make(chan common.Message), +// nil, +// &common.FakeSender{}, +// )) +// require.NoError(vm.SetState(ctx, snow.NormalOp)) +// +// tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) +// signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) +// require.NoError(err) +// +// marshaller := GossipEthTxMarshaller{} +// gossipedTx := &GossipEthTx{ +// Tx: signedTx, +// } +// gossipedTxBytes, err := marshaller.MarshalGossip(gossipedTx) +// require.NoError(err) +// +// inboundGossip := &sdk.PushGossip{ +// Gossip: [][]byte{gossipedTxBytes}, +// } +// +// inboundGossipBytes, err := proto.Marshal(inboundGossip) +// require.NoError(err) +// +// inboundGossipMsg := append(binary.AppendUvarint(nil, ethTxGossipProtocol), inboundGossipBytes...) +// require.NoError(vm.AppGossip(ctx, ids.EmptyNodeID, inboundGossipMsg)) +// +// forwardedMsg := &sdk.PushGossip{} +// outboundGossipBytes := <-sender.SentAppGossip +// +// require.Equal(byte(ethTxGossipProtocol), outboundGossipBytes[0]) +// require.NoError(proto.Unmarshal(outboundGossipBytes[1:], forwardedMsg)) +// require.Len(forwardedMsg.Gossip, 1) +// +// forwardedTx, err := marshaller.UnmarshalGossip(forwardedMsg.Gossip[0]) +// require.NoError(err) +// require.Equal(gossipedTx.GossipID(), forwardedTx.GossipID()) +// require.True(vm.txPool.Has(signedTx.Hash())) +// } +// +// // Tests that a tx is gossiped when it is issued +// func TestAtomicTxPushGossipOutbound(t *testing.T) { +// require := require.New(t) +// ctx := context.Background() +// snowCtx := utils.TestSnowContext() +// 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) +// +// 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) +// +// sender := &common.FakeSender{ +// SentAppGossip: make(chan []byte, 1), +// } +// vm := &VM{ +// p2pSender: sender, +// ethTxPullGossiper: gossip.NoOpGossiper{}, +// atomicTxPullGossiper: gossip.NoOpGossiper{}, +// } +// +// require.NoError(vm.Initialize( +// ctx, +// snowCtx, +// memdb.New(), +// genesisBytes, +// nil, +// nil, +// make(chan common.Message), +// nil, +// &common.FakeSender{}, +// )) +// require.NoError(vm.SetState(ctx, snow.NormalOp)) +// +// // 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) +// tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) +// require.NoError(err) +// require.NoError(vm.mempool.AddLocalTx(tx)) +// vm.atomicTxPushGossiper.Add(&GossipAtomicTx{tx}) +// +// gossipedBytes := <-sender.SentAppGossip +// require.Equal(byte(atomicTxGossipProtocol), gossipedBytes[0]) +// +// outboundGossipMsg := &sdk.PushGossip{} +// require.NoError(proto.Unmarshal(gossipedBytes[1:], outboundGossipMsg)) +// require.Len(outboundGossipMsg.Gossip, 1) +// +// marshaller := GossipAtomicTxMarshaller{} +// gossipedTx, err := marshaller.UnmarshalGossip(outboundGossipMsg.Gossip[0]) +// require.NoError(err) +// require.Equal(tx.ID(), gossipedTx.Tx.ID()) +// } +// +// // Tests that a tx is gossiped when it is issued +// func TestAtomicTxPushGossipInbound(t *testing.T) { +// require := require.New(t) +// ctx := context.Background() +// snowCtx := utils.TestSnowContext() +// 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) +// +// 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) +// +// sender := &common.FakeSender{ +// SentAppGossip: make(chan []byte, 1), +// } +// vm := &VM{ +// p2pSender: sender, +// ethTxPullGossiper: gossip.NoOpGossiper{}, +// atomicTxPullGossiper: gossip.NoOpGossiper{}, +// } +// +// require.NoError(vm.Initialize( +// ctx, +// snowCtx, +// memdb.New(), +// genesisBytes, +// nil, +// nil, +// make(chan common.Message), +// nil, +// &common.FakeSender{}, +// )) +// require.NoError(vm.SetState(ctx, snow.NormalOp)) +// +// // 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) +// tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) +// require.NoError(err) +// require.NoError(vm.mempool.AddLocalTx(tx)) +// +// marshaller := GossipAtomicTxMarshaller{} +// gossipedTx := &GossipAtomicTx{ +// Tx: tx, +// } +// gossipBytes, err := marshaller.MarshalGossip(gossipedTx) +// require.NoError(err) +// +// inboundGossip := &sdk.PushGossip{ +// Gossip: [][]byte{gossipBytes}, +// } +// inboundGossipBytes, err := proto.Marshal(inboundGossip) +// require.NoError(err) +// +// inboundGossipMsg := append(binary.AppendUvarint(nil, atomicTxGossipProtocol), inboundGossipBytes...) +// +// require.NoError(vm.AppGossip(ctx, ids.EmptyNodeID, inboundGossipMsg)) +// +// forwardedBytes := <-sender.SentAppGossip +// require.Equal(byte(atomicTxGossipProtocol), forwardedBytes[0]) +// +// forwardedGossipMsg := &sdk.PushGossip{} +// require.NoError(proto.Unmarshal(forwardedBytes[1:], forwardedGossipMsg)) +// require.Len(forwardedGossipMsg.Gossip, 1) +// +// forwardedTx, err := marshaller.UnmarshalGossip(forwardedGossipMsg.Gossip[0]) +// require.NoError(err) +// require.Equal(tx.ID(), forwardedTx.Tx.ID()) +// require.True(vm.mempool.has(tx.ID())) +// } diff --git a/scripts/build_test.sh b/scripts/build_test.sh index f6af943445..9316c97152 100755 --- a/scripts/build_test.sh +++ b/scripts/build_test.sh @@ -17,4 +17,4 @@ source "$CORETH_PATH"/scripts/constants.sh # We pass in the arguments to this script directly to enable easily passing parameters such as enabling race detection, # parallelism, and test coverage. -go test -coverprofile=coverage.out -covermode=atomic -timeout="30m" ./... "$@" +go test -coverprofile=coverage.out -covermode=atomic -timeout="3m" ./... "$@" From 3191f0f748fef34b687c24dad5231de32c76d812 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 13:11:41 -0800 Subject: [PATCH 26/46] revert timeout --- scripts/build_test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_test.sh b/scripts/build_test.sh index 9316c97152..f6af943445 100755 --- a/scripts/build_test.sh +++ b/scripts/build_test.sh @@ -17,4 +17,4 @@ source "$CORETH_PATH"/scripts/constants.sh # We pass in the arguments to this script directly to enable easily passing parameters such as enabling race detection, # parallelism, and test coverage. -go test -coverprofile=coverage.out -covermode=atomic -timeout="3m" ./... "$@" +go test -coverprofile=coverage.out -covermode=atomic -timeout="30m" ./... "$@" From 6b78c3e8a52a26d1e550c00158f048d423a29d5f Mon Sep 17 00:00:00 2001 From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:19:23 -0500 Subject: [PATCH 27/46] fix most tests Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com> --- plugin/evm/tx_gossip_test.go | 1131 +++++++++++++++++----------------- 1 file changed, 553 insertions(+), 578 deletions(-) diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index 5bd48726b9..0471a3b108 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -3,581 +3,556 @@ package evm -// import ( -// "context" -// "encoding/binary" -// "math/big" -// "sync" -// "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" -// agoUtils "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/prometheus/client_golang/prometheus" -// "github.com/stretchr/testify/require" -// -// "github.com/ava-labs/avalanchego/vms/components/avax" -// "github.com/ava-labs/avalanchego/vms/secp256k1fx" -// -// "google.golang.org/protobuf/proto" -// -// "github.com/ava-labs/coreth/core/types" -// "github.com/ava-labs/coreth/params" -// "github.com/ava-labs/coreth/utils" -// ) -// -// func TestEthTxGossip(t *testing.T) { -// require := require.New(t) -// ctx := context.Background() -// snowCtx := utils.TestSnowContext() -// validatorState := &validators.TestState{} -// snowCtx.ValidatorState = validatorState -// -// 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 := &common.FakeSender{ -// SentAppResponse: make(chan []byte, 1), -// } -// vm := &VM{ -// p2pSender: responseSender, -// atomicTxGossipHandler: &p2p.NoOpHandler{}, -// atomicTxPullGossiper: &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.FakeSender{ -// SentAppRequest: make(chan []byte, 1), -// } -// -// 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() -// 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) -// require.NoError(err) -// emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() -// request := &sdk.PullGossipRequest{ -// Filter: emptyBloomFilterBytes, -// Salt: agoUtils.RandomBytes(32), -// } -// -// requestBytes, err := proto.Marshal(request) -// require.NoError(err) -// -// wg := &sync.WaitGroup{} -// wg.Add(1) -// onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { -// require.NoError(err) -// -// response := &sdk.PullGossipResponse{} -// require.NoError(proto.Unmarshal(responseBytes, response)) -// require.Empty(response.Gossip) -// wg.Done() -// } -// 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 -// tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) -// signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) -// require.NoError(err) -// -// errs := vm.txPool.AddLocals([]*types.Transaction{signedTx}) -// require.Len(errs, 1) -// require.Nil(errs[0]) -// -// // wait so we aren't throttled by the vm -// time.Sleep(5 * time.Second) -// -// marshaller := GossipEthTxMarshaller{} -// // Ask the VM for new transactions. We should get the newly issued tx. -// wg.Add(1) -// onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { -// require.NoError(err) -// -// response := &sdk.PullGossipResponse{} -// require.NoError(proto.Unmarshal(responseBytes, response)) -// require.Len(response.Gossip, 1) -// -// gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) -// require.NoError(err) -// require.Equal(signedTx.Hash(), gotTx.Tx.Hash()) -// -// wg.Done() -// } -// 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 := utils.TestSnowContext() -// 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) -// -// 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 := &common.FakeSender{ -// SentAppResponse: make(chan []byte, 1), -// } -// vm := &VM{ -// p2pSender: responseSender, -// ethTxGossipHandler: &p2p.NoOpHandler{}, -// ethTxPullGossiper: &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.FakeSender{ -// SentAppRequest: make(chan []byte, 1), -// } -// 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() -// 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) -// require.NoError(err) -// emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() -// request := &sdk.PullGossipRequest{ -// Filter: emptyBloomFilterBytes, -// Salt: agoUtils.RandomBytes(32), -// } -// -// requestBytes, err := proto.Marshal(request) -// require.NoError(err) -// -// wg := &sync.WaitGroup{} -// wg.Add(1) -// onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { -// require.NoError(err) -// -// response := &sdk.PullGossipResponse{} -// require.NoError(proto.Unmarshal(responseBytes, response)) -// require.Empty(response.Gossip) -// wg.Done() -// } -// 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 -// utxo, err := addUTXO( -// memory, -// snowCtx, -// ids.GenerateTestID(), -// 0, -// snowCtx.AVAXAssetID, -// 100_000_000_000, -// pk.PublicKey().Address(), -// ) -// require.NoError(err) -// 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) -// -// // Ask the VM for new transactions. We should get the newly issued tx. -// wg.Add(1) -// -// marshaller := GossipAtomicTxMarshaller{} -// onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { -// require.NoError(err) -// -// response := &sdk.PullGossipResponse{} -// require.NoError(proto.Unmarshal(responseBytes, response)) -// require.Len(response.Gossip, 1) -// -// gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) -// require.NoError(err) -// require.Equal(tx.ID(), gotTx.GossipID()) -// -// wg.Done() -// } -// 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() -// } -// -// // Tests that a tx is gossiped when it is issued -// func TestEthTxPushGossipOutbound(t *testing.T) { -// require := require.New(t) -// ctx := context.Background() -// snowCtx := utils.TestSnowContext() -// sender := &common.FakeSender{ -// SentAppGossip: make(chan []byte, 1), -// } -// -// vm := &VM{ -// p2pSender: sender, -// ethTxPullGossiper: gossip.NoOpGossiper{}, -// atomicTxPullGossiper: gossip.NoOpGossiper{}, -// } -// -// 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) -// -// require.NoError(vm.Initialize( -// ctx, -// snowCtx, -// memdb.New(), -// genesisBytes, -// nil, -// nil, -// make(chan common.Message), -// nil, -// &common.FakeSender{}, -// )) -// require.NoError(vm.SetState(ctx, snow.NormalOp)) -// -// tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) -// signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) -// require.NoError(err) -// -// // issue a tx -// require.NoError(vm.txPool.AddLocal(signedTx)) -// vm.ethTxPushGossiper.Add(&GossipEthTx{signedTx}) -// -// sent := <-sender.SentAppGossip -// got := &sdk.PushGossip{} -// -// // we should get a message that has the protocol prefix and the gossip -// // message -// require.Equal(byte(ethTxGossipProtocol), sent[0]) -// require.NoError(proto.Unmarshal(sent[1:], got)) -// -// marshaller := GossipEthTxMarshaller{} -// require.Len(got.Gossip, 1) -// gossipedTx, err := marshaller.UnmarshalGossip(got.Gossip[0]) -// require.NoError(err) -// require.Equal(ids.ID(signedTx.Hash()), gossipedTx.GossipID()) -// } -// -// // Tests that a gossiped tx is added to the mempool and forwarded -// func TestEthTxPushGossipInbound(t *testing.T) { -// require := require.New(t) -// ctx := context.Background() -// snowCtx := utils.TestSnowContext() -// -// sender := &common.FakeSender{ -// SentAppGossip: make(chan []byte, 1), -// } -// vm := &VM{ -// p2pSender: sender, -// ethTxPullGossiper: gossip.NoOpGossiper{}, -// atomicTxPullGossiper: gossip.NoOpGossiper{}, -// } -// -// 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) -// -// require.NoError(vm.Initialize( -// ctx, -// snowCtx, -// memdb.New(), -// genesisBytes, -// nil, -// nil, -// make(chan common.Message), -// nil, -// &common.FakeSender{}, -// )) -// require.NoError(vm.SetState(ctx, snow.NormalOp)) -// -// tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) -// signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) -// require.NoError(err) -// -// marshaller := GossipEthTxMarshaller{} -// gossipedTx := &GossipEthTx{ -// Tx: signedTx, -// } -// gossipedTxBytes, err := marshaller.MarshalGossip(gossipedTx) -// require.NoError(err) -// -// inboundGossip := &sdk.PushGossip{ -// Gossip: [][]byte{gossipedTxBytes}, -// } -// -// inboundGossipBytes, err := proto.Marshal(inboundGossip) -// require.NoError(err) -// -// inboundGossipMsg := append(binary.AppendUvarint(nil, ethTxGossipProtocol), inboundGossipBytes...) -// require.NoError(vm.AppGossip(ctx, ids.EmptyNodeID, inboundGossipMsg)) -// -// forwardedMsg := &sdk.PushGossip{} -// outboundGossipBytes := <-sender.SentAppGossip -// -// require.Equal(byte(ethTxGossipProtocol), outboundGossipBytes[0]) -// require.NoError(proto.Unmarshal(outboundGossipBytes[1:], forwardedMsg)) -// require.Len(forwardedMsg.Gossip, 1) -// -// forwardedTx, err := marshaller.UnmarshalGossip(forwardedMsg.Gossip[0]) -// require.NoError(err) -// require.Equal(gossipedTx.GossipID(), forwardedTx.GossipID()) -// require.True(vm.txPool.Has(signedTx.Hash())) -// } -// -// // Tests that a tx is gossiped when it is issued -// func TestAtomicTxPushGossipOutbound(t *testing.T) { -// require := require.New(t) -// ctx := context.Background() -// snowCtx := utils.TestSnowContext() -// 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) -// -// 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) -// -// sender := &common.FakeSender{ -// SentAppGossip: make(chan []byte, 1), -// } -// vm := &VM{ -// p2pSender: sender, -// ethTxPullGossiper: gossip.NoOpGossiper{}, -// atomicTxPullGossiper: gossip.NoOpGossiper{}, -// } -// -// require.NoError(vm.Initialize( -// ctx, -// snowCtx, -// memdb.New(), -// genesisBytes, -// nil, -// nil, -// make(chan common.Message), -// nil, -// &common.FakeSender{}, -// )) -// require.NoError(vm.SetState(ctx, snow.NormalOp)) -// -// // 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) -// tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) -// require.NoError(err) -// require.NoError(vm.mempool.AddLocalTx(tx)) -// vm.atomicTxPushGossiper.Add(&GossipAtomicTx{tx}) -// -// gossipedBytes := <-sender.SentAppGossip -// require.Equal(byte(atomicTxGossipProtocol), gossipedBytes[0]) -// -// outboundGossipMsg := &sdk.PushGossip{} -// require.NoError(proto.Unmarshal(gossipedBytes[1:], outboundGossipMsg)) -// require.Len(outboundGossipMsg.Gossip, 1) -// -// marshaller := GossipAtomicTxMarshaller{} -// gossipedTx, err := marshaller.UnmarshalGossip(outboundGossipMsg.Gossip[0]) -// require.NoError(err) -// require.Equal(tx.ID(), gossipedTx.Tx.ID()) -// } -// -// // Tests that a tx is gossiped when it is issued -// func TestAtomicTxPushGossipInbound(t *testing.T) { -// require := require.New(t) -// ctx := context.Background() -// snowCtx := utils.TestSnowContext() -// 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) -// -// 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) -// -// sender := &common.FakeSender{ -// SentAppGossip: make(chan []byte, 1), -// } -// vm := &VM{ -// p2pSender: sender, -// ethTxPullGossiper: gossip.NoOpGossiper{}, -// atomicTxPullGossiper: gossip.NoOpGossiper{}, -// } -// -// require.NoError(vm.Initialize( -// ctx, -// snowCtx, -// memdb.New(), -// genesisBytes, -// nil, -// nil, -// make(chan common.Message), -// nil, -// &common.FakeSender{}, -// )) -// require.NoError(vm.SetState(ctx, snow.NormalOp)) -// -// // 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) -// tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) -// require.NoError(err) -// require.NoError(vm.mempool.AddLocalTx(tx)) -// -// marshaller := GossipAtomicTxMarshaller{} -// gossipedTx := &GossipAtomicTx{ -// Tx: tx, -// } -// gossipBytes, err := marshaller.MarshalGossip(gossipedTx) -// require.NoError(err) -// -// inboundGossip := &sdk.PushGossip{ -// Gossip: [][]byte{gossipBytes}, -// } -// inboundGossipBytes, err := proto.Marshal(inboundGossip) -// require.NoError(err) -// -// inboundGossipMsg := append(binary.AppendUvarint(nil, atomicTxGossipProtocol), inboundGossipBytes...) -// -// require.NoError(vm.AppGossip(ctx, ids.EmptyNodeID, inboundGossipMsg)) -// -// forwardedBytes := <-sender.SentAppGossip -// require.Equal(byte(atomicTxGossipProtocol), forwardedBytes[0]) -// -// forwardedGossipMsg := &sdk.PushGossip{} -// require.NoError(proto.Unmarshal(forwardedBytes[1:], forwardedGossipMsg)) -// require.Len(forwardedGossipMsg.Gossip, 1) -// -// forwardedTx, err := marshaller.UnmarshalGossip(forwardedGossipMsg.Gossip[0]) -// require.NoError(err) -// require.Equal(tx.ID(), forwardedTx.Tx.ID()) -// require.True(vm.mempool.has(tx.ID())) -// } +import ( + "context" + "encoding/binary" + "math/big" + "sync" + "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" + agoUtils "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/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + + "google.golang.org/protobuf/proto" + + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/utils" +) + +func TestEthTxGossip(t *testing.T) { + require := require.New(t) + ctx := context.Background() + snowCtx := utils.TestSnowContext() + validatorState := &validators.TestState{} + snowCtx.ValidatorState = validatorState + + 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 := &common.FakeSender{ + SentAppResponse: make(chan []byte, 1), + } + vm := &VM{ + p2pSender: responseSender, + atomicTxGossipHandler: &p2p.NoOpHandler{}, + atomicTxPullGossiper: &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.FakeSender{ + SentAppRequest: make(chan []byte, 1), + } + + 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() + 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) + require.NoError(err) + emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() + request := &sdk.PullGossipRequest{ + Filter: emptyBloomFilterBytes, + Salt: agoUtils.RandomBytes(32), + } + + requestBytes, err := proto.Marshal(request) + require.NoError(err) + + wg := &sync.WaitGroup{} + wg.Add(1) + onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { + require.NoError(err) + + response := &sdk.PullGossipResponse{} + require.NoError(proto.Unmarshal(responseBytes, response)) + require.Empty(response.Gossip) + wg.Done() + } + 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 + tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) + signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) + require.NoError(err) + + errs := vm.txPool.AddLocals([]*types.Transaction{signedTx}) + require.Len(errs, 1) + require.Nil(errs[0]) + + // wait so we aren't throttled by the vm + time.Sleep(5 * time.Second) + + marshaller := GossipEthTxMarshaller{} + // Ask the VM for new transactions. We should get the newly issued tx. + wg.Add(1) + onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { + require.NoError(err) + + response := &sdk.PullGossipResponse{} + require.NoError(proto.Unmarshal(responseBytes, response)) + require.Len(response.Gossip, 1) + + gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) + require.NoError(err) + require.Equal(signedTx.Hash(), gotTx.Tx.Hash()) + + wg.Done() + } + 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 := utils.TestSnowContext() +// 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) +// +// 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 := &common.FakeSender{ +// SentAppResponse: make(chan []byte, 1), +// } +// vm := &VM{ +// p2pSender: responseSender, +// ethTxGossipHandler: &p2p.NoOpHandler{}, +// ethTxPullGossiper: &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.FakeSender{ +// SentAppRequest: make(chan []byte, 1), +// } +// 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() +// 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) +// require.NoError(err) +// emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() +// request := &sdk.PullGossipRequest{ +// Filter: emptyBloomFilterBytes, +// Salt: agoUtils.RandomBytes(32), +// } +// +// requestBytes, err := proto.Marshal(request) +// require.NoError(err) +// +// wg := &sync.WaitGroup{} +// wg.Add(1) +// onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { +// require.NoError(err) +// +// response := &sdk.PullGossipResponse{} +// require.NoError(proto.Unmarshal(responseBytes, response)) +// require.Empty(response.Gossip) +// wg.Done() +// } +// 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 +// utxo, err := addUTXO( +// memory, +// snowCtx, +// ids.GenerateTestID(), +// 0, +// snowCtx.AVAXAssetID, +// 100_000_000_000, +// pk.PublicKey().Address(), +// ) +// require.NoError(err) +// 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) +// +// // Ask the VM for new transactions. We should get the newly issued tx. +// wg.Add(1) +// +// marshaller := GossipAtomicTxMarshaller{} +// onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { +// require.NoError(err) +// +// response := &sdk.PullGossipResponse{} +// require.NoError(proto.Unmarshal(responseBytes, response)) +// require.Len(response.Gossip, 1) +// +// gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) +// require.NoError(err) +// require.Equal(tx.ID(), gotTx.GossipID()) +// +// wg.Done() +// } +// 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() +//} + +// Tests that a tx is gossiped when it is issued +func TestEthTxPushGossipOutbound(t *testing.T) { + require := require.New(t) + ctx := context.Background() + snowCtx := utils.TestSnowContext() + sender := &common.FakeSender{ + SentAppGossip: make(chan []byte, 1), + } + + vm := &VM{ + p2pSender: sender, + ethTxPullGossiper: gossip.NoOpGossiper{}, + atomicTxPullGossiper: gossip.NoOpGossiper{}, + } + + 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) + + require.NoError(vm.Initialize( + ctx, + snowCtx, + memdb.New(), + genesisBytes, + nil, + nil, + make(chan common.Message), + nil, + &common.FakeSender{}, + )) + require.NoError(vm.SetState(ctx, snow.NormalOp)) + + tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) + signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) + require.NoError(err) + + // issue a tx + require.NoError(vm.txPool.AddLocal(signedTx)) + vm.ethTxPushGossiper.Add(&GossipEthTx{signedTx}) + + sent := <-sender.SentAppGossip + got := &sdk.PushGossip{} + + // we should get a message that has the protocol prefix and the gossip + // message + require.Equal(byte(ethTxGossipProtocol), sent[0]) + require.NoError(proto.Unmarshal(sent[1:], got)) + + marshaller := GossipEthTxMarshaller{} + require.Len(got.Gossip, 1) + gossipedTx, err := marshaller.UnmarshalGossip(got.Gossip[0]) + require.NoError(err) + require.Equal(ids.ID(signedTx.Hash()), gossipedTx.GossipID()) +} + +// Tests that a gossiped tx is added to the mempool and forwarded +func TestEthTxPushGossipInbound(t *testing.T) { + require := require.New(t) + ctx := context.Background() + snowCtx := utils.TestSnowContext() + + sender := &common.SenderTest{} + vm := &VM{ + p2pSender: sender, + ethTxPullGossiper: gossip.NoOpGossiper{}, + atomicTxPullGossiper: gossip.NoOpGossiper{}, + } + + 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) + + require.NoError(vm.Initialize( + ctx, + snowCtx, + memdb.New(), + genesisBytes, + nil, + nil, + make(chan common.Message), + nil, + &common.FakeSender{}, + )) + require.NoError(vm.SetState(ctx, snow.NormalOp)) + + tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) + signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) + require.NoError(err) + + marshaller := GossipEthTxMarshaller{} + gossipedTx := &GossipEthTx{ + Tx: signedTx, + } + gossipedTxBytes, err := marshaller.MarshalGossip(gossipedTx) + require.NoError(err) + + inboundGossip := &sdk.PushGossip{ + Gossip: [][]byte{gossipedTxBytes}, + } + + inboundGossipBytes, err := proto.Marshal(inboundGossip) + require.NoError(err) + + inboundGossipMsg := append(binary.AppendUvarint(nil, ethTxGossipProtocol), inboundGossipBytes...) + require.NoError(vm.AppGossip(ctx, ids.EmptyNodeID, inboundGossipMsg)) + + require.True(vm.txPool.Has(signedTx.Hash())) +} + +// Tests that a tx is gossiped when it is issued +func TestAtomicTxPushGossipOutbound(t *testing.T) { + require := require.New(t) + ctx := context.Background() + snowCtx := utils.TestSnowContext() + 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) + + 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) + + sender := &common.FakeSender{ + SentAppGossip: make(chan []byte, 1), + } + vm := &VM{ + p2pSender: sender, + ethTxPullGossiper: gossip.NoOpGossiper{}, + atomicTxPullGossiper: gossip.NoOpGossiper{}, + } + + require.NoError(vm.Initialize( + ctx, + snowCtx, + memdb.New(), + genesisBytes, + nil, + nil, + make(chan common.Message), + nil, + &common.FakeSender{}, + )) + require.NoError(vm.SetState(ctx, snow.NormalOp)) + + // 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) + tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) + require.NoError(err) + require.NoError(vm.mempool.AddLocalTx(tx)) + vm.atomicTxPushGossiper.Add(&GossipAtomicTx{tx}) + + gossipedBytes := <-sender.SentAppGossip + require.Equal(byte(atomicTxGossipProtocol), gossipedBytes[0]) + + outboundGossipMsg := &sdk.PushGossip{} + require.NoError(proto.Unmarshal(gossipedBytes[1:], outboundGossipMsg)) + require.Len(outboundGossipMsg.Gossip, 1) + + marshaller := GossipAtomicTxMarshaller{} + gossipedTx, err := marshaller.UnmarshalGossip(outboundGossipMsg.Gossip[0]) + require.NoError(err) + require.Equal(tx.ID(), gossipedTx.Tx.ID()) +} + +// Tests that a tx is gossiped when it is issued +func TestAtomicTxPushGossipInbound(t *testing.T) { + require := require.New(t) + ctx := context.Background() + snowCtx := utils.TestSnowContext() + 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) + + 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) + + sender := &common.SenderTest{} + vm := &VM{ + p2pSender: sender, + ethTxPullGossiper: gossip.NoOpGossiper{}, + atomicTxPullGossiper: gossip.NoOpGossiper{}, + } + + require.NoError(vm.Initialize( + ctx, + snowCtx, + memdb.New(), + genesisBytes, + nil, + nil, + make(chan common.Message), + nil, + &common.FakeSender{}, + )) + require.NoError(vm.SetState(ctx, snow.NormalOp)) + + // 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) + tx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, address, initialBaseFee, secp256k1fx.NewKeychain(pk), []*avax.UTXO{utxo}) + require.NoError(err) + require.NoError(vm.mempool.AddLocalTx(tx)) + + marshaller := GossipAtomicTxMarshaller{} + gossipedTx := &GossipAtomicTx{ + Tx: tx, + } + gossipBytes, err := marshaller.MarshalGossip(gossipedTx) + require.NoError(err) + + inboundGossip := &sdk.PushGossip{ + Gossip: [][]byte{gossipBytes}, + } + inboundGossipBytes, err := proto.Marshal(inboundGossip) + require.NoError(err) + + inboundGossipMsg := append(binary.AppendUvarint(nil, atomicTxGossipProtocol), inboundGossipBytes...) + + require.NoError(vm.AppGossip(ctx, ids.EmptyNodeID, inboundGossipMsg)) + require.True(vm.mempool.has(tx.ID())) +} From bfcae19e98651fb97c907e017a0d0a8ac010f9a7 Mon Sep 17 00:00:00 2001 From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:25:08 -0500 Subject: [PATCH 28/46] this test was already fine Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com> --- plugin/evm/tx_gossip_test.go | 266 +++++++++++++++++------------------ 1 file changed, 133 insertions(+), 133 deletions(-) diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index 0471a3b108..ac0da6f83c 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -157,139 +157,139 @@ func TestEthTxGossip(t *testing.T) { wg.Wait() } -//func TestAtomicTxGossip(t *testing.T) { -// require := require.New(t) -// ctx := context.Background() -// snowCtx := utils.TestSnowContext() -// 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) -// -// 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 := &common.FakeSender{ -// SentAppResponse: make(chan []byte, 1), -// } -// vm := &VM{ -// p2pSender: responseSender, -// ethTxGossipHandler: &p2p.NoOpHandler{}, -// ethTxPullGossiper: &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.FakeSender{ -// SentAppRequest: make(chan []byte, 1), -// } -// 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() -// 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) -// require.NoError(err) -// emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() -// request := &sdk.PullGossipRequest{ -// Filter: emptyBloomFilterBytes, -// Salt: agoUtils.RandomBytes(32), -// } -// -// requestBytes, err := proto.Marshal(request) -// require.NoError(err) -// -// wg := &sync.WaitGroup{} -// wg.Add(1) -// onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { -// require.NoError(err) -// -// response := &sdk.PullGossipResponse{} -// require.NoError(proto.Unmarshal(responseBytes, response)) -// require.Empty(response.Gossip) -// wg.Done() -// } -// 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 -// utxo, err := addUTXO( -// memory, -// snowCtx, -// ids.GenerateTestID(), -// 0, -// snowCtx.AVAXAssetID, -// 100_000_000_000, -// pk.PublicKey().Address(), -// ) -// require.NoError(err) -// 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) -// -// // Ask the VM for new transactions. We should get the newly issued tx. -// wg.Add(1) -// -// marshaller := GossipAtomicTxMarshaller{} -// onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { -// require.NoError(err) -// -// response := &sdk.PullGossipResponse{} -// require.NoError(proto.Unmarshal(responseBytes, response)) -// require.Len(response.Gossip, 1) -// -// gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) -// require.NoError(err) -// require.Equal(tx.ID(), gotTx.GossipID()) -// -// wg.Done() -// } -// 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 := utils.TestSnowContext() + 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) + + 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 := &common.FakeSender{ + SentAppResponse: make(chan []byte, 1), + } + vm := &VM{ + p2pSender: responseSender, + ethTxGossipHandler: &p2p.NoOpHandler{}, + ethTxPullGossiper: &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.FakeSender{ + SentAppRequest: make(chan []byte, 1), + } + 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() + 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(prometheus.NewRegistry(), "", txGossipBloomMinTargetElements, txGossipBloomTargetFalsePositiveRate, txGossipBloomResetFalsePositiveRate) + require.NoError(err) + emptyBloomFilterBytes, _ := emptyBloomFilter.Marshal() + request := &sdk.PullGossipRequest{ + Filter: emptyBloomFilterBytes, + Salt: agoUtils.RandomBytes(32), + } + + requestBytes, err := proto.Marshal(request) + require.NoError(err) + + wg := &sync.WaitGroup{} + wg.Add(1) + onResponse := func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { + require.NoError(err) + + response := &sdk.PullGossipResponse{} + require.NoError(proto.Unmarshal(responseBytes, response)) + require.Empty(response.Gossip) + wg.Done() + } + 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 + utxo, err := addUTXO( + memory, + snowCtx, + ids.GenerateTestID(), + 0, + snowCtx.AVAXAssetID, + 100_000_000_000, + pk.PublicKey().Address(), + ) + require.NoError(err) + 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) + + // Ask the VM for new transactions. We should get the newly issued tx. + wg.Add(1) + + marshaller := GossipAtomicTxMarshaller{} + onResponse = func(_ context.Context, nodeID ids.NodeID, responseBytes []byte, err error) { + require.NoError(err) + + response := &sdk.PullGossipResponse{} + require.NoError(proto.Unmarshal(responseBytes, response)) + require.Len(response.Gossip, 1) + + gotTx, err := marshaller.UnmarshalGossip(response.Gossip[0]) + require.NoError(err) + require.Equal(tx.ID(), gotTx.GossipID()) + + wg.Done() + } + 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() +} // Tests that a tx is gossiped when it is issued func TestEthTxPushGossipOutbound(t *testing.T) { From f7e3ac36400006fca9e0513db9d41d9020016347 Mon Sep 17 00:00:00 2001 From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:58:59 -0500 Subject: [PATCH 29/46] removing sent + regossip stats Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com> --- plugin/evm/gossip_stats.go | 43 -------------------------------------- plugin/evm/handler.go | 4 ++-- 2 files changed, 2 insertions(+), 45 deletions(-) diff --git a/plugin/evm/gossip_stats.go b/plugin/evm/gossip_stats.go index ce15bd87c7..9805c7f1ff 100644 --- a/plugin/evm/gossip_stats.go +++ b/plugin/evm/gossip_stats.go @@ -9,12 +9,6 @@ var _ GossipStats = &gossipStats{} // GossipStats contains methods for updating incoming and outgoing gossip stats. type GossipStats interface { - GossipReceivedStats - GossipSentStats -} - -// GossipReceivedStats groups functions for incoming gossip stats. -type GossipReceivedStats interface { IncAtomicGossipReceived() IncEthTxsGossipReceived() @@ -28,30 +22,12 @@ type GossipReceivedStats interface { IncEthTxsGossipReceivedNew() } -// GossipSentStats groups functions for outgoing gossip stats. -type GossipSentStats interface { - IncAtomicGossipSent() - IncEthTxsGossipSent() - - // regossip - IncEthTxsRegossipQueued() - IncEthTxsRegossipQueuedLocal(count int) - IncEthTxsRegossipQueuedRemote(count int) -} - // gossipStats implements stats for incoming and outgoing gossip stats. type gossipStats struct { // messages - atomicGossipSent metrics.Counter atomicGossipReceived metrics.Counter - ethTxsGossipSent metrics.Counter ethTxsGossipReceived metrics.Counter - // regossip - ethTxsRegossipQueued metrics.Counter - ethTxsRegossipQueuedLocal metrics.Counter - ethTxsRegossipQueuedRemote metrics.Counter - // new vs. known txs received atomicGossipReceivedDropped metrics.Counter atomicGossipReceivedError metrics.Counter @@ -64,15 +40,9 @@ type gossipStats struct { func NewGossipStats() GossipStats { return &gossipStats{ - atomicGossipSent: metrics.GetOrRegisterCounter("gossip_atomic_sent", nil), atomicGossipReceived: metrics.GetOrRegisterCounter("gossip_atomic_received", nil), - ethTxsGossipSent: metrics.GetOrRegisterCounter("gossip_eth_txs_sent", nil), ethTxsGossipReceived: metrics.GetOrRegisterCounter("gossip_eth_txs_received", nil), - ethTxsRegossipQueued: metrics.GetOrRegisterCounter("regossip_eth_txs_queued_attempts", nil), - ethTxsRegossipQueuedLocal: metrics.GetOrRegisterCounter("regossip_eth_txs_queued_local_tx_count", nil), - ethTxsRegossipQueuedRemote: metrics.GetOrRegisterCounter("regossip_eth_txs_queued_remote_tx_count", nil), - atomicGossipReceivedDropped: metrics.GetOrRegisterCounter("gossip_atomic_received_dropped", nil), atomicGossipReceivedError: metrics.GetOrRegisterCounter("gossip_atomic_received_error", nil), atomicGossipReceivedKnown: metrics.GetOrRegisterCounter("gossip_atomic_received_known", nil), @@ -95,16 +65,3 @@ func (g *gossipStats) IncAtomicGossipReceivedNew() { g.atomicGossipReceivedN func (g *gossipStats) IncEthTxsGossipReceivedError() { g.ethTxsGossipReceivedError.Inc(1) } func (g *gossipStats) IncEthTxsGossipReceivedKnown() { g.ethTxsGossipReceivedKnown.Inc(1) } func (g *gossipStats) IncEthTxsGossipReceivedNew() { g.ethTxsGossipReceivedNew.Inc(1) } - -// outgoing messages -func (g *gossipStats) IncAtomicGossipSent() { g.atomicGossipSent.Inc(1) } -func (g *gossipStats) IncEthTxsGossipSent() { g.ethTxsGossipSent.Inc(1) } - -// regossip -func (g *gossipStats) IncEthTxsRegossipQueued() { g.ethTxsRegossipQueued.Inc(1) } -func (g *gossipStats) IncEthTxsRegossipQueuedLocal(count int) { - g.ethTxsRegossipQueuedLocal.Inc(int64(count)) -} -func (g *gossipStats) IncEthTxsRegossipQueuedRemote(count int) { - g.ethTxsRegossipQueuedRemote.Inc(int64(count)) -} diff --git a/plugin/evm/handler.go b/plugin/evm/handler.go index 6b782ea0cc..85b4721c5b 100644 --- a/plugin/evm/handler.go +++ b/plugin/evm/handler.go @@ -19,10 +19,10 @@ type GossipHandler struct { vm *VM atomicMempool *Mempool txPool *txpool.TxPool - stats GossipReceivedStats + stats GossipStats } -func NewGossipHandler(vm *VM, stats GossipReceivedStats) *GossipHandler { +func NewGossipHandler(vm *VM, stats GossipStats) *GossipHandler { return &GossipHandler{ vm: vm, atomicMempool: vm.mempool, From 72cc8219c86e10e442c14b7ddb4357b99a601de9 Mon Sep 17 00:00:00 2001 From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:30:09 -0500 Subject: [PATCH 30/46] nit 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 1f5d92f8b5..6618c95f52 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -145,7 +145,7 @@ const ( // gossip constants pushGossipFrequency = 100 * time.Millisecond - pushGossipDiscardedSize = 16_384 + pushGossipDiscardedSize = 16 * units.KiB pushRegossipFrequency = 10 * time.Second txGossipBloomMinTargetElements = 8 * 1024 txGossipBloomTargetFalsePositiveRate = 0.01 From da09bfb8babc26ee5e16fcdcb464ca2786b5a7bb Mon Sep 17 00:00:00 2001 From: Joshua Kim <20001595+joshua-kim@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:30:53 -0500 Subject: [PATCH 31/46] nit 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 6618c95f52..e49aa32d98 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -707,7 +707,7 @@ func (vm *VM) initializeChain(lastAcceptedHash common.Hash) error { node, &vm.ethConfig, vm.createConsensusCallbacks(), - &EthPushGossiper{vm}, + &EthPushGossiper{vm: vm}, vm.chaindb, vm.config.EthBackendSettings(), lastAcceptedHash, From 6fc6036fd6e9df9c7ebd5df2bf2888fbf5d759b5 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 14:58:40 -0800 Subject: [PATCH 32/46] linting --- plugin/evm/gossip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index 77d0f176dd..29f2645956 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -47,7 +47,7 @@ func newTxGossipHandler[T gossip.Gossipable]( validators *p2p.Validators, ) txGossipHandler { // push gossip messages can be handled from any peer - handler := gossip.NewHandler[T]( + handler := gossip.NewHandler( log, marshaller, mempool, From 96ef8ad7461f8575e9ea546fba8ea08d1a7a7ce3 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 15:06:31 -0800 Subject: [PATCH 33/46] remove unused configs --- plugin/evm/config.go | 20 +++----------------- plugin/evm/vm.go | 5 ++--- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/plugin/evm/config.go b/plugin/evm/config.go index 9bf2d0c885..1c678f1caa 100644 --- a/plugin/evm/config.go +++ b/plugin/evm/config.go @@ -35,8 +35,7 @@ const ( defaultMaxBlocksPerRequest = 0 // Default to no maximum on the number of blocks per getLogs request defaultContinuousProfilerFrequency = 15 * time.Minute defaultContinuousProfilerMaxFiles = 5 - defaultTxRegossipFrequency = 1 * time.Minute - defaultTxRegossipMaxSize = 15 + defaultTxRegossipFrequency = 10 * time.Second defaultOfflinePruningBloomFilterSize uint64 = 512 // Default size (MB) for the offline pruner to use defaultLogLevel = "info" defaultLogJSONFormat = false @@ -151,12 +150,8 @@ type Config struct { KeystoreInsecureUnlockAllowed bool `json:"keystore-insecure-unlock-allowed"` // Gossip Settings - RemoteGossipOnlyEnabled bool `json:"remote-gossip-only-enabled"` - RegossipFrequency Duration `json:"regossip-frequency"` - RegossipMaxTxs int `json:"regossip-max-txs"` - RemoteTxGossipOnlyEnabled bool `json:"remote-tx-gossip-only-enabled"` // Deprecated: use RemoteGossipOnlyEnabled instead - TxRegossipFrequency Duration `json:"tx-regossip-frequency"` // Deprecated: use RegossipFrequency instead - TxRegossipMaxSize int `json:"tx-regossip-max-size"` // Deprecated: use RegossipMaxTxs instead + RegossipFrequency Duration `json:"regossip-frequency"` + TxRegossipFrequency Duration `json:"tx-regossip-frequency"` // Deprecated: use RegossipFrequency instead // Log LogLevel string `json:"log-level"` @@ -254,7 +249,6 @@ func (c *Config) SetDefaults() { c.CommitInterval = defaultCommitInterval c.SnapshotWait = defaultSnapshotWait c.RegossipFrequency.Duration = defaultTxRegossipFrequency - c.RegossipMaxTxs = defaultTxRegossipMaxSize c.OfflinePruningBloomFilterSize = defaultOfflinePruningBloomFilterSize c.LogLevel = defaultLogLevel c.LogJSONFormat = defaultLogJSONFormat @@ -319,18 +313,10 @@ func (c *Config) Deprecate() string { msg += "coreth-admin-api-dir is deprecated, use admin-api-dir instead. " c.AdminAPIDir = c.CorethAdminAPIDir } - if c.RemoteTxGossipOnlyEnabled { - msg += "remote-tx-gossip-only-enabled is deprecated, use tx-gossip-enabled instead. " - c.RemoteGossipOnlyEnabled = c.RemoteTxGossipOnlyEnabled - } if c.TxRegossipFrequency != (Duration{}) { msg += "tx-regossip-frequency is deprecated, use regossip-frequency instead. " c.RegossipFrequency = c.TxRegossipFrequency } - if c.TxRegossipMaxSize != 0 { - msg += "tx-regossip-max-size is deprecated, use regossip-max-txs instead. " - c.RegossipMaxTxs = c.TxRegossipMaxSize - } return msg } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index e49aa32d98..f292fb7a5b 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -146,7 +146,6 @@ const ( // gossip constants pushGossipFrequency = 100 * time.Millisecond pushGossipDiscardedSize = 16 * units.KiB - pushRegossipFrequency = 10 * time.Second txGossipBloomMinTargetElements = 8 * 1024 txGossipBloomTargetFalsePositiveRate = 0.01 txGossipBloomResetFalsePositiveRate = 0.05 @@ -1109,7 +1108,7 @@ func (vm *VM) initBlockBuilding() error { ethTxGossipMetrics, pushGossipDiscardedSize, txGossipTargetMessageSize, - pushRegossipFrequency, + vm.config.TxRegossipFrequency.Duration, ) if err != nil { return fmt.Errorf("failed to initialize eth tx push gossiper: %w", err) @@ -1124,7 +1123,7 @@ func (vm *VM) initBlockBuilding() error { atomicTxGossipMetrics, pushGossipDiscardedSize, txGossipTargetMessageSize, - pushRegossipFrequency, + vm.config.TxRegossipFrequency.Duration, ) if err != nil { return fmt.Errorf("failed to initialize atomic tx push gossiper: %w", err) From 06e7ae512eadd87955e4d2657782871157c7932c Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 15:11:19 -0800 Subject: [PATCH 34/46] cleanup config use --- plugin/evm/config.go | 6 ++++++ plugin/evm/vm.go | 10 ++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/plugin/evm/config.go b/plugin/evm/config.go index 1c678f1caa..4c299cb168 100644 --- a/plugin/evm/config.go +++ b/plugin/evm/config.go @@ -35,6 +35,8 @@ const ( defaultMaxBlocksPerRequest = 0 // Default to no maximum on the number of blocks per getLogs request defaultContinuousProfilerFrequency = 15 * time.Minute defaultContinuousProfilerMaxFiles = 5 + defaultPushGossipFrequency = 250 * time.Millisecond + defaultPullGossipFrequency = 10 * time.Second defaultTxRegossipFrequency = 10 * time.Second defaultOfflinePruningBloomFilterSize uint64 = 512 // Default size (MB) for the offline pruner to use defaultLogLevel = "info" @@ -150,6 +152,8 @@ type Config struct { KeystoreInsecureUnlockAllowed bool `json:"keystore-insecure-unlock-allowed"` // Gossip Settings + PushGossipFrequency Duration `json:"push-gossip-frequency"` + PullGossipFrequency Duration `json:"pull-gossip-frequency"` RegossipFrequency Duration `json:"regossip-frequency"` TxRegossipFrequency Duration `json:"tx-regossip-frequency"` // Deprecated: use RegossipFrequency instead @@ -249,6 +253,8 @@ func (c *Config) SetDefaults() { c.CommitInterval = defaultCommitInterval c.SnapshotWait = defaultSnapshotWait c.RegossipFrequency.Duration = defaultTxRegossipFrequency + c.PushGossipFrequency.Duration = defaultPushGossipFrequency + c.PullGossipFrequency.Duration = defaultPullGossipFrequency c.OfflinePruningBloomFilterSize = defaultOfflinePruningBloomFilterSize c.LogLevel = defaultLogLevel c.LogJSONFormat = defaultLogJSONFormat diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index f292fb7a5b..ee7f14b602 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -144,7 +144,6 @@ const ( atomicTxGossipProtocol = 0x1 // gossip constants - pushGossipFrequency = 100 * time.Millisecond pushGossipDiscardedSize = 16 * units.KiB txGossipBloomMinTargetElements = 8 * 1024 txGossipBloomTargetFalsePositiveRate = 0.01 @@ -154,7 +153,6 @@ const ( maxValidatorSetStaleness = time.Minute txGossipThrottlingPeriod = 10 * time.Second txGossipThrottlingLimit = 2 - pullGossipFrequency = 10 * time.Second txGossipPollSize = 10 ) @@ -1189,11 +1187,11 @@ func (vm *VM) initBlockBuilding() error { vm.shutdownWg.Add(2) go func() { - gossip.Every(ctx, vm.ctx.Log, vm.ethTxPushGossiper, pushGossipFrequency) + gossip.Every(ctx, vm.ctx.Log, vm.ethTxPushGossiper, vm.config.PushGossipFrequency.Duration) vm.shutdownWg.Done() }() go func() { - gossip.Every(ctx, vm.ctx.Log, vm.ethTxPullGossiper, pullGossipFrequency) + gossip.Every(ctx, vm.ctx.Log, vm.ethTxPullGossiper, vm.config.PullGossipFrequency.Duration) vm.shutdownWg.Done() }() @@ -1216,11 +1214,11 @@ func (vm *VM) initBlockBuilding() error { vm.shutdownWg.Add(2) go func() { - gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPushGossiper, pushGossipFrequency) + gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPushGossiper, vm.config.PushGossipFrequency.Duration) vm.shutdownWg.Done() }() go func() { - gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPullGossiper, pullGossipFrequency) + gossip.Every(ctx, vm.ctx.Log, vm.atomicTxPullGossiper, vm.config.PullGossipFrequency.Duration) vm.shutdownWg.Done() }() From a2bed847362ac9b2d9f9cf2735a599cab1342851 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 15:16:03 -0800 Subject: [PATCH 35/46] remove KiB --- plugin/evm/vm.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index ee7f14b602..5acebff536 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -144,7 +144,7 @@ const ( atomicTxGossipProtocol = 0x1 // gossip constants - pushGossipDiscardedSize = 16 * units.KiB + pushGossipDiscardedElements = 16_384 txGossipBloomMinTargetElements = 8 * 1024 txGossipBloomTargetFalsePositiveRate = 0.01 txGossipBloomResetFalsePositiveRate = 0.05 @@ -1104,7 +1104,7 @@ func (vm *VM) initBlockBuilding() error { ethTxPool, ethTxGossipClient, ethTxGossipMetrics, - pushGossipDiscardedSize, + pushGossipDiscardedElements, txGossipTargetMessageSize, vm.config.TxRegossipFrequency.Duration, ) @@ -1119,7 +1119,7 @@ func (vm *VM) initBlockBuilding() error { vm.mempool, atomicTxGossipClient, atomicTxGossipMetrics, - pushGossipDiscardedSize, + pushGossipDiscardedElements, txGossipTargetMessageSize, vm.config.TxRegossipFrequency.Duration, ) From 0dae3e2b41a2ea265706f08d746b849ce3b148d4 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 15:18:57 -0800 Subject: [PATCH 36/46] set back to 100ms --- plugin/evm/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/evm/config.go b/plugin/evm/config.go index 4c299cb168..31e059da98 100644 --- a/plugin/evm/config.go +++ b/plugin/evm/config.go @@ -35,7 +35,7 @@ const ( defaultMaxBlocksPerRequest = 0 // Default to no maximum on the number of blocks per getLogs request defaultContinuousProfilerFrequency = 15 * time.Minute defaultContinuousProfilerMaxFiles = 5 - defaultPushGossipFrequency = 250 * time.Millisecond + defaultPushGossipFrequency = 100 * time.Millisecond defaultPullGossipFrequency = 10 * time.Second defaultTxRegossipFrequency = 10 * time.Second defaultOfflinePruningBloomFilterSize uint64 = 512 // Default size (MB) for the offline pruner to use From 3d1b239947e9ddb02d8c2a7541f27ceb2e9ffe37 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 15:27:16 -0800 Subject: [PATCH 37/46] use correct config --- plugin/evm/vm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 5acebff536..f0ea88e131 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -1106,7 +1106,7 @@ func (vm *VM) initBlockBuilding() error { ethTxGossipMetrics, pushGossipDiscardedElements, txGossipTargetMessageSize, - vm.config.TxRegossipFrequency.Duration, + vm.config.RegossipFrequency.Duration, ) if err != nil { return fmt.Errorf("failed to initialize eth tx push gossiper: %w", err) @@ -1121,7 +1121,7 @@ func (vm *VM) initBlockBuilding() error { atomicTxGossipMetrics, pushGossipDiscardedElements, txGossipTargetMessageSize, - vm.config.TxRegossipFrequency.Duration, + vm.config.RegossipFrequency.Duration, ) if err != nil { return fmt.Errorf("failed to initialize atomic tx push gossiper: %w", err) From 5dd1f58c0e54edfec61104b9d33be39cd3ba0ae3 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 16:00:51 -0800 Subject: [PATCH 38/46] Update plugin/evm/gossip.go Co-authored-by: Stephen Buttolph Signed-off-by: Patrick O'Grady --- plugin/evm/gossip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index 29f2645956..e82d2f096a 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -175,7 +175,7 @@ func (g *GossipEthTxPool) Add(tx *GossipEthTx) error { // Has should just return whether or not the [txID] is still in the mempool, // not whether it is in the mempool AND pending. func (g *GossipEthTxPool) Has(txID ids.ID) bool { - return g.mempool.Has(common.Hash(txID[:])) + return g.mempool.Has(common.Hash(txID)) } func (g *GossipEthTxPool) Iterate(f func(tx *GossipEthTx) bool) { From f3d4a47bc4475a71350163b1330c58cb1dc02c3b Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Tue, 27 Feb 2024 16:04:21 -0800 Subject: [PATCH 39/46] handle nil push gossiper --- plugin/evm/gossip.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index e82d2f096a..e602aa1d75 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -220,5 +220,10 @@ type EthPushGossiper struct { } func (e *EthPushGossiper) Add(tx *types.Transaction) { + // eth.Backend is initialized before the [ethTxPushGossiper] is created, so + // we just ignore any gossip requests until it is set. + if e.vm.ethTxPushGossiper == nil { + return + } e.vm.ethTxPushGossiper.Add(&GossipEthTx{tx}) } From cffa2fc1c69ea83757f3b5ac173c74210531f92a Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Tue, 27 Feb 2024 19:13:03 -0500 Subject: [PATCH 40/46] update avalanchego version --- go.mod | 2 +- go.sum | 4 ++-- scripts/versions.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index d9959e82d6..802590a031 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/VictoriaMetrics/fastcache v1.10.0 - github.com/ava-labs/avalanchego v1.11.1-0.20240227201848-5de194a57144 + github.com/ava-labs/avalanchego v1.11.2-rc.0 github.com/cespare/cp v0.1.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 diff --git a/go.sum b/go.sum index 8a12c437fe..ce6346c2af 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.11.1-0.20240227201848-5de194a57144 h1:zKl3KmjO5pP8ycYcNZ9+W29MQo7mhlMOnufGcivuseY= -github.com/ava-labs/avalanchego v1.11.1-0.20240227201848-5de194a57144/go.mod h1:X1KT5ukTfCzkI0+AFGOPa+wp/8AYzn2hoXbp75nRTJE= +github.com/ava-labs/avalanchego v1.11.2-rc.0 h1:V48scthqolX2iz/AS90ZsyuDTYDTrhiv2N+T6Atl4iY= +github.com/ava-labs/avalanchego v1.11.2-rc.0/go.mod h1:4C0opqUFh50CuYIXpYAylL7SigscY0MPv6aODCFCC4E= 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/scripts/versions.sh b/scripts/versions.sh index 30a208d0c9..ffe5e0066a 100644 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -6,4 +6,4 @@ set -euo pipefail # Don't export them as they're used in the context of other calls -avalanche_version=${AVALANCHE_VERSION:-'5de194a571442da6960c6da2ea1dce291249291c'} +avalanche_version=${AVALANCHE_VERSION:-'v1.11.2-rc.0'} From 53a989408607e5f1269c0eef163e8ab0e40a486f Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Tue, 27 Feb 2024 18:36:07 -0800 Subject: [PATCH 41/46] Gossip cleanup test race (#499) --- plugin/evm/tx_gossip_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index ac0da6f83c..a2bd9ac8c8 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -326,6 +326,10 @@ func TestEthTxPushGossipOutbound(t *testing.T) { )) require.NoError(vm.SetState(ctx, snow.NormalOp)) + defer func() { + require.NoError(vm.Shutdown(ctx)) + }() + tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) require.NoError(err) @@ -382,6 +386,10 @@ func TestEthTxPushGossipInbound(t *testing.T) { )) require.NoError(vm.SetState(ctx, snow.NormalOp)) + defer func() { + require.NoError(vm.Shutdown(ctx)) + }() + tx := types.NewTransaction(0, address, big.NewInt(10), 100_000, big.NewInt(params.LaunchMinGasPrice), nil) signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), pk.ToECDSA()) require.NoError(err) @@ -451,6 +459,10 @@ func TestAtomicTxPushGossipOutbound(t *testing.T) { )) require.NoError(vm.SetState(ctx, snow.NormalOp)) + defer func() { + require.NoError(vm.Shutdown(ctx)) + }() + // Issue a tx to the VM utxo, err := addUTXO( memory, @@ -523,6 +535,10 @@ func TestAtomicTxPushGossipInbound(t *testing.T) { )) require.NoError(vm.SetState(ctx, snow.NormalOp)) + defer func() { + require.NoError(vm.Shutdown(ctx)) + }() + // issue a tx to the vm utxo, err := addUTXO( memory, From 3b80fe2b3026f269a9f4b424763ee138bce0eb48 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 28 Feb 2024 16:08:41 -0500 Subject: [PATCH 42/46] nit --- plugin/evm/gossip.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index e602aa1d75..eadcdc3246 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -213,17 +213,15 @@ func (tx *GossipEthTx) GossipID() ids.ID { return ids.ID(tx.Tx.Hash()) } -// EthPushGossiper is used by the ETH backend to push transactions -// issued over the RPC and added to the mempool to peers. +// EthPushGossiper is used by the ETH backend to push transactions issued over +// the RPC and added to the mempool to peers. type EthPushGossiper struct { vm *VM } func (e *EthPushGossiper) Add(tx *types.Transaction) { - // eth.Backend is initialized before the [ethTxPushGossiper] is created, so - // we just ignore any gossip requests until it is set. - if e.vm.ethTxPushGossiper == nil { - return - } + // eth.Backend is initialized before [ethTxPushGossiper] is created. Because + // the RPC doesn't allow requests before bootstrapping has finished, + // [ethTxPushGossiper] will be initialized before this function is called. e.vm.ethTxPushGossiper.Add(&GossipEthTx{tx}) } From 035d78de72cce7ed0e1d895ade6cc0d2f7e5497e Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 28 Feb 2024 19:09:14 -0500 Subject: [PATCH 43/46] move push gossiper behind an atomic --- plugin/evm/gossip.go | 11 +++++++---- plugin/evm/tx_gossip_test.go | 2 +- plugin/evm/vm.go | 11 +++++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index eadcdc3246..9bdeafb9d8 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -220,8 +220,11 @@ type EthPushGossiper struct { } func (e *EthPushGossiper) Add(tx *types.Transaction) { - // eth.Backend is initialized before [ethTxPushGossiper] is created. Because - // the RPC doesn't allow requests before bootstrapping has finished, - // [ethTxPushGossiper] will be initialized before this function is called. - e.vm.ethTxPushGossiper.Add(&GossipEthTx{tx}) + // eth.Backend is initialized before the [ethTxPushGossiper] is created, so + // we just ignore any gossip requests until it is set. + ethTxPushGossiper := e.vm.ethTxPushGossiper.Get() + if ethTxPushGossiper == nil { + return + } + ethTxPushGossiper.Add(&GossipEthTx{tx}) } diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index a2bd9ac8c8..c3be73962a 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -336,7 +336,7 @@ func TestEthTxPushGossipOutbound(t *testing.T) { // issue a tx require.NoError(vm.txPool.AddLocal(signedTx)) - vm.ethTxPushGossiper.Add(&GossipEthTx{signedTx}) + vm.ethTxPushGossiper.Get().Add(&GossipEthTx{signedTx}) sent := <-sender.SentAppGossip got := &sdk.PushGossip{} diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 715716b0a9..a7f89b66ce 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -94,6 +94,7 @@ import ( commonEng "github.com/ava-labs/avalanchego/snow/engine/common" + avalancheUtils "github.com/ava-labs/avalanchego/utils" avalancheJSON "github.com/ava-labs/avalanchego/utils/json" ) @@ -332,7 +333,7 @@ type VM struct { // Initialize only sets these if nil so they can be overridden in tests p2pSender commonEng.AppSender ethTxGossipHandler p2p.Handler - ethTxPushGossiper *gossip.PushGossiper[*GossipEthTx] + ethTxPushGossiper avalancheUtils.Atomic[*gossip.PushGossiper[*GossipEthTx]] ethTxPullGossiper gossip.Gossiper atomicTxGossipHandler p2p.Handler atomicTxPushGossiper *gossip.PushGossiper[*GossipAtomicTx] @@ -1096,8 +1097,9 @@ func (vm *VM) initBlockBuilding() error { return fmt.Errorf("failed to initialize atomic tx gossip metrics: %w", err) } - if vm.ethTxPushGossiper == nil { - vm.ethTxPushGossiper, err = gossip.NewPushGossiper[*GossipEthTx]( + ethTxPushGossiper := vm.ethTxPushGossiper.Get() + if ethTxPushGossiper == nil { + ethTxPushGossiper, err = gossip.NewPushGossiper[*GossipEthTx]( ethTxGossipMarshaller, ethTxPool, ethTxGossipClient, @@ -1109,6 +1111,7 @@ func (vm *VM) initBlockBuilding() error { if err != nil { return fmt.Errorf("failed to initialize eth tx push gossiper: %w", err) } + vm.ethTxPushGossiper.Set(ethTxPushGossiper) } if vm.atomicTxPushGossiper == nil { @@ -1185,7 +1188,7 @@ func (vm *VM) initBlockBuilding() error { vm.shutdownWg.Add(2) go func() { - gossip.Every(ctx, vm.ctx.Log, vm.ethTxPushGossiper, vm.config.PushGossipFrequency.Duration) + gossip.Every(ctx, vm.ctx.Log, ethTxPushGossiper, vm.config.PushGossipFrequency.Duration) vm.shutdownWg.Done() }() go func() { From ae5c02b64f3b160dbd5ca91128d2ea084659b7a7 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 28 Feb 2024 19:59:51 -0500 Subject: [PATCH 44/46] Buffer pendingTxs channel --- plugin/evm/gossip.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index 9bdeafb9d8..d82e180e1b 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -24,6 +24,8 @@ import ( "github.com/ava-labs/coreth/eth" ) +const pendingTxsBuffer = 10 + var ( _ p2p.Handler = (*txGossipHandler)(nil) @@ -119,7 +121,7 @@ func NewGossipEthTxPool(mempool *txpool.TxPool, registerer prometheus.Registerer return &GossipEthTxPool{ mempool: mempool, - pendingTxs: make(chan core.NewTxsEvent), + pendingTxs: make(chan core.NewTxsEvent, pendingTxsBuffer), bloom: bloom, }, nil } From a41708770437ada5d615990982457f3d895d59cb Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 28 Feb 2024 20:03:28 -0500 Subject: [PATCH 45/46] update avalanchego version --- go.mod | 2 +- go.sum | 4 ++-- scripts/versions.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 802590a031..c0e69c2056 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/VictoriaMetrics/fastcache v1.10.0 - github.com/ava-labs/avalanchego v1.11.2-rc.0 + github.com/ava-labs/avalanchego v1.11.2-rc.3 github.com/cespare/cp v0.1.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 diff --git a/go.sum b/go.sum index ce6346c2af..86dde9ecfc 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.11.2-rc.0 h1:V48scthqolX2iz/AS90ZsyuDTYDTrhiv2N+T6Atl4iY= -github.com/ava-labs/avalanchego v1.11.2-rc.0/go.mod h1:4C0opqUFh50CuYIXpYAylL7SigscY0MPv6aODCFCC4E= +github.com/ava-labs/avalanchego v1.11.2-rc.3 h1:lT9J/c7cmeO385cXB2sJrpw9jimhmuVOs2HSj6sinOo= +github.com/ava-labs/avalanchego v1.11.2-rc.3/go.mod h1:JOReTq7ttmsbImxlXZ/Fm5Ccf7a/pYMULkX7kzy3MNY= 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/scripts/versions.sh b/scripts/versions.sh index ffe5e0066a..d88871cb46 100644 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -6,4 +6,4 @@ set -euo pipefail # Don't export them as they're used in the context of other calls -avalanche_version=${AVALANCHE_VERSION:-'v1.11.2-rc.0'} +avalanche_version=${AVALANCHE_VERSION:-'v1.11.2-rc.3'} From c3e7c7c3774510afa7602999780bfec0f0275486 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 28 Feb 2024 20:24:23 -0500 Subject: [PATCH 46/46] remove dead code --- peer/client.go | 7 ------- peer/network.go | 12 ------------ peer/network_test.go | 43 ------------------------------------------- 3 files changed, 62 deletions(-) diff --git a/peer/client.go b/peer/client.go index 41ebc7d6d9..d40e1a268a 100644 --- a/peer/client.go +++ b/peer/client.go @@ -34,9 +34,6 @@ type NetworkClient interface { // Returns response bytes, and ErrRequestFailed if the request failed. SendCrossChainRequest(ctx context.Context, chainID ids.ID, request []byte) ([]byte, error) - // Gossip sends given gossip message to peers - Gossip(gossip []byte) error - // TrackBandwidth should be called for each valid request with the bandwidth // (length of response divided by request time), and with 0 if the response is invalid. TrackBandwidth(nodeID ids.NodeID, bandwidth float64) @@ -90,10 +87,6 @@ func (c *client) SendCrossChainRequest(ctx context.Context, chainID ids.ID, requ return waitingHandler.WaitForResult(ctx) } -func (c *client) Gossip(gossip []byte) error { - return c.network.Gossip(gossip) -} - func (c *client) TrackBandwidth(nodeID ids.NodeID, bandwidth float64) { c.network.TrackBandwidth(nodeID, bandwidth) } diff --git a/peer/network.go b/peer/network.go index 1def7f8b5e..8ea20c9945 100644 --- a/peer/network.go +++ b/peer/network.go @@ -51,9 +51,6 @@ type Network interface { // SendAppRequest sends message to given nodeID, notifying handler when there's a response or timeout SendAppRequest(ctx context.Context, nodeID ids.NodeID, message []byte, handler message.ResponseHandler) error - // Gossip sends given gossip message to peers - Gossip(gossip []byte) error - // SendCrossChainRequest sends a message to given chainID notifying handler when there's a response or timeout SendCrossChainRequest(ctx context.Context, chainID ids.ID, message []byte, handler message.ResponseHandler) error @@ -437,15 +434,6 @@ func (n *network) markRequestFulfilled(requestID uint32) (message.ResponseHandle return handler, true } -// Gossip sends given gossip message to peers -func (n *network) Gossip(gossip []byte) error { - if n.closed.Get() { - return nil - } - - return n.appSender.SendAppGossip(context.TODO(), gossip) -} - // AppGossip is called by avalanchego -> VM when there is an incoming AppGossip // from a peer. An error returned by this function is treated as fatal by the // engine. diff --git a/peer/network_test.go b/peer/network_test.go index bcf49e24cb..164637ba55 100644 --- a/peer/network_test.go +++ b/peer/network_test.go @@ -503,49 +503,6 @@ func TestOnRequestHonoursDeadline(t *testing.T) { assert.EqualValues(t, requestHandler.calls, 1) } -func TestGossip(t *testing.T) { - codecManager := buildCodec(t, HelloGossip{}) - crossChainCodecManager := buildCodec(t, ExampleCrossChainRequest{}, ExampleCrossChainResponse{}) - - nodeID := ids.GenerateTestNodeID() - var clientNetwork Network - wg := &sync.WaitGroup{} - sentGossip := false - wg.Add(1) - sender := testAppSender{ - sendAppGossipFn: func(msg []byte) error { - go func() { - defer wg.Done() - err := clientNetwork.AppGossip(context.Background(), nodeID, msg) - assert.NoError(t, err) - }() - sentGossip = true - return nil - }, - } - - gossipHandler := &testGossipHandler{} - 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)) - - client := NewNetworkClient(clientNetwork) - defer clientNetwork.Shutdown() - - b, err := buildGossip(codecManager, HelloGossip{Msg: "hello there!"}) - assert.NoError(t, err) - - err = client.Gossip(b) - assert.NoError(t, err) - - wg.Wait() - assert.True(t, sentGossip) - assert.True(t, gossipHandler.received) -} - func TestHandleInvalidMessages(t *testing.T) { codecManager := buildCodec(t, HelloGossip{}, TestMessage{}) crossChainCodecManager := buildCodec(t, ExampleCrossChainRequest{}, ExampleCrossChainResponse{})