diff --git a/vms/platformvm/block/builder/builder.go b/vms/platformvm/block/builder/builder.go index 13a1c7902b6d..8923857d579e 100644 --- a/vms/platformvm/block/builder/builder.go +++ b/vms/platformvm/block/builder/builder.go @@ -270,7 +270,7 @@ func buildBlock( } // Clean out the mempool's transactions with invalid timestamps. - droppedStakerTxIDs := mempool.DropExpiredStakerTxs(builder.Mempool, timestamp.Add(txexecutor.SyncBound)) + droppedStakerTxIDs := builder.Mempool.DropExpiredStakerTxs(timestamp.Add(txexecutor.SyncBound)) for _, txID := range droppedStakerTxIDs { builder.txExecutorBackend.Ctx.Log.Debug("dropping tx", zap.Stringer("txID", txID), diff --git a/vms/platformvm/block/builder/builder_test.go b/vms/platformvm/block/builder/builder_test.go index 2bf97a8c8ef2..04abf5d65b71 100644 --- a/vms/platformvm/block/builder/builder_test.go +++ b/vms/platformvm/block/builder/builder_test.go @@ -401,7 +401,7 @@ func TestBuildBlock(t *testing.T) { mempool := mempool.NewMockMempool(ctrl) // There are txs. - mempool.EXPECT().HasStakerTx().Return(false) + mempool.EXPECT().DropExpiredStakerTxs(gomock.Any()).Return([]ids.ID{}) mempool.EXPECT().HasTxs().Return(true) mempool.EXPECT().PeekTxs(targetBlockSize).Return(transactions) return &builder{ @@ -448,7 +448,7 @@ func TestBuildBlock(t *testing.T) { mempool := mempool.NewMockMempool(ctrl) // There are no txs. - mempool.EXPECT().HasStakerTx().Return(false) + mempool.EXPECT().DropExpiredStakerTxs(gomock.Any()).Return([]ids.ID{}) mempool.EXPECT().HasTxs().Return(false) clk := &mockable.Clock{} @@ -496,7 +496,7 @@ func TestBuildBlock(t *testing.T) { mempool := mempool.NewMockMempool(ctrl) // There are no txs. - mempool.EXPECT().HasStakerTx().Return(false) + mempool.EXPECT().DropExpiredStakerTxs(gomock.Any()).Return([]ids.ID{}) mempool.EXPECT().HasTxs().Return(false) mempool.EXPECT().PeekTxs(targetBlockSize).Return(nil) @@ -551,7 +551,7 @@ func TestBuildBlock(t *testing.T) { mempool := mempool.NewMockMempool(ctrl) // There is a tx. - mempool.EXPECT().HasStakerTx().Return(false) + mempool.EXPECT().DropExpiredStakerTxs(gomock.Any()).Return([]ids.ID{}) mempool.EXPECT().HasTxs().Return(true) mempool.EXPECT().PeekTxs(targetBlockSize).Return([]*txs.Tx{transactions[0]}) @@ -605,7 +605,7 @@ func TestBuildBlock(t *testing.T) { // There are no decision txs // There is a staker tx. - mempool.EXPECT().HasStakerTx().Return(false) + mempool.EXPECT().DropExpiredStakerTxs(gomock.Any()).Return([]ids.ID{}) mempool.EXPECT().HasTxs().Return(true) mempool.EXPECT().PeekTxs(targetBlockSize).Return([]*txs.Tx{transactions[0]}) diff --git a/vms/platformvm/txs/mempool/issuer.go b/vms/platformvm/txs/mempool/issuer.go deleted file mode 100644 index b56c10190cf8..000000000000 --- a/vms/platformvm/txs/mempool/issuer.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package mempool - -import ( - "errors" - - "github.com/ava-labs/avalanchego/vms/platformvm/txs" -) - -var ( - _ txs.Visitor = (*issuer)(nil) - - errCantIssueAdvanceTimeTx = errors.New("can not issue an advance time tx") - errCantIssueRewardValidatorTx = errors.New("can not issue a reward validator tx") -) - -type issuer struct { - m *mempool - tx *txs.Tx -} - -func (*issuer) AdvanceTimeTx(*txs.AdvanceTimeTx) error { - return errCantIssueAdvanceTimeTx -} - -func (*issuer) RewardValidatorTx(*txs.RewardValidatorTx) error { - return errCantIssueRewardValidatorTx -} - -func (i *issuer) AddValidatorTx(*txs.AddValidatorTx) error { - i.m.addStakerTx(i.tx) - return nil -} - -func (i *issuer) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { - i.m.addStakerTx(i.tx) - return nil -} - -func (i *issuer) AddDelegatorTx(*txs.AddDelegatorTx) error { - i.m.addStakerTx(i.tx) - return nil -} - -func (i *issuer) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { - i.m.addDecisionTx(i.tx) - return nil -} - -func (i *issuer) CreateChainTx(*txs.CreateChainTx) error { - i.m.addDecisionTx(i.tx) - return nil -} - -func (i *issuer) CreateSubnetTx(*txs.CreateSubnetTx) error { - i.m.addDecisionTx(i.tx) - return nil -} - -func (i *issuer) ImportTx(*txs.ImportTx) error { - i.m.addDecisionTx(i.tx) - return nil -} - -func (i *issuer) ExportTx(*txs.ExportTx) error { - i.m.addDecisionTx(i.tx) - return nil -} - -func (i *issuer) TransformSubnetTx(*txs.TransformSubnetTx) error { - i.m.addDecisionTx(i.tx) - return nil -} - -func (i *issuer) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { - i.m.addDecisionTx(i.tx) - return nil -} - -func (i *issuer) BaseTx(*txs.BaseTx) error { - i.m.addDecisionTx(i.tx) - return nil -} - -func (i *issuer) AddPermissionlessValidatorTx(*txs.AddPermissionlessValidatorTx) error { - i.m.addStakerTx(i.tx) - return nil -} - -func (i *issuer) AddPermissionlessDelegatorTx(*txs.AddPermissionlessDelegatorTx) error { - i.m.addStakerTx(i.tx) - return nil -} diff --git a/vms/platformvm/txs/mempool/mempool.go b/vms/platformvm/txs/mempool/mempool.go index 91b547cf5414..e7a2018b7e71 100644 --- a/vms/platformvm/txs/mempool/mempool.go +++ b/vms/platformvm/txs/mempool/mempool.go @@ -12,10 +12,10 @@ import ( "github.com/ava-labs/avalanchego/cache" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/linkedhashmap" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/platformvm/txs/txheap" ) const ( @@ -35,10 +35,12 @@ const ( var ( _ Mempool = (*mempool)(nil) - errDuplicateTx = errors.New("duplicate tx") - errTxTooLarge = errors.New("tx too large") - errMempoolFull = errors.New("mempool is full") - errConflictsWithOtherTx = errors.New("tx conflicts with other tx") + errDuplicateTx = errors.New("duplicate tx") + errTxTooLarge = errors.New("tx too large") + errMempoolFull = errors.New("mempool is full") + errConflictsWithOtherTx = errors.New("tx conflicts with other tx") + errCantIssueAdvanceTimeTx = errors.New("can not issue an advance time tx") + errCantIssueRewardValidatorTx = errors.New("can not issue a reward validator tx") ) type BlockTimer interface { @@ -67,11 +69,11 @@ type Mempool interface { // up to maxTxsBytes without removing them from the mempool. PeekTxs(maxTxsBytes int) []*txs.Tx - HasStakerTx() bool - // PeekStakerTx returns the next stakerTx without removing it from mempool. - // It returns nil if !HasStakerTx(). - // It's guaranteed that the returned tx, if not nil, is a StakerTx. - PeekStakerTx() *txs.Tx + // Drops all [txs.Staker] transactions whose [StartTime] is before + // [minStartTime] from [mempool]. The dropped tx ids are returned. + // + // TODO: Remove once [StartTime] field is ignored in staker txs + DropExpiredStakerTxs(minStartTime time.Time) []ids.ID // Note: dropped txs are added to droppedTxIDs but are not evicted from // unissued decision/staker txs. This allows previously dropped txs to be @@ -89,8 +91,8 @@ type mempool struct { bytesAvailableMetric prometheus.Gauge bytesAvailable int - unissuedDecisionTxs txheap.Heap - unissuedStakerTxs txheap.Heap + unissuedTxs linkedhashmap.LinkedHashmap[ids.ID, *txs.Tx] + numTxs prometheus.Gauge // Key: Tx ID // Value: Verification error @@ -115,21 +117,12 @@ func New( return nil, err } - unissuedDecisionTxs, err := txheap.NewWithMetrics( - txheap.NewByAge(), - fmt.Sprintf("%s_decision_txs", namespace), - registerer, - ) - if err != nil { - return nil, err - } - - unissuedStakerTxs, err := txheap.NewWithMetrics( - txheap.NewByStartTime(), - fmt.Sprintf("%s_staker_txs", namespace), - registerer, - ) - if err != nil { + numTxs := prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: namespace, + Name: "txs", + Help: "Number of decision/staker transactions in the mempool", + }) + if err := registerer.Register(numTxs); err != nil { return nil, err } @@ -137,12 +130,14 @@ func New( return &mempool{ bytesAvailableMetric: bytesAvailableMetric, bytesAvailable: maxMempoolSize, - unissuedDecisionTxs: unissuedDecisionTxs, - unissuedStakerTxs: unissuedStakerTxs, - droppedTxIDs: &cache.LRU[ids.ID, error]{Size: droppedTxIDsCacheSize}, - consumedUTXOs: set.NewSet[ids.ID](initialConsumedUTXOsSize), - dropIncoming: false, // enable tx adding by default - blkTimer: blkTimer, + + unissuedTxs: linkedhashmap.New[ids.ID, *txs.Tx](), + numTxs: numTxs, + + droppedTxIDs: &cache.LRU[ids.ID, error]{Size: droppedTxIDsCacheSize}, + consumedUTXOs: set.NewSet[ids.ID](initialConsumedUTXOsSize), + dropIncoming: false, // enable tx adding by default + blkTimer: blkTimer, }, nil } @@ -159,6 +154,14 @@ func (m *mempool) Add(tx *txs.Tx) error { return fmt.Errorf("tx %s not added because mempool is closed", tx.ID()) } + switch tx.Unsigned.(type) { + case *txs.AdvanceTimeTx: + return errCantIssueAdvanceTimeTx + case *txs.RewardValidatorTx: + return errCantIssueRewardValidatorTx + default: + } + // Note: a previously dropped tx can be re-added txID := tx.ID() if m.Has(txID) { @@ -188,12 +191,9 @@ func (m *mempool) Add(tx *txs.Tx) error { return fmt.Errorf("%w: %s", errConflictsWithOtherTx, txID) } - if err := tx.Unsigned.Visit(&issuer{ - m: m, - tx: tx, - }); err != nil { - return err - } + m.unissuedTxs.Put(tx.ID(), tx) + m.bytesAvailable -= txSize + m.bytesAvailableMetric.Set(float64(m.bytesAvailable)) // Mark these UTXOs as consumed in the mempool m.consumedUTXOs.Union(inputs) @@ -210,79 +210,46 @@ func (m *mempool) Has(txID ids.ID) bool { } func (m *mempool) Get(txID ids.ID) *txs.Tx { - if tx := m.unissuedDecisionTxs.Get(txID); tx != nil { - return tx - } - return m.unissuedStakerTxs.Get(txID) + tx, _ := m.unissuedTxs.Get(txID) + return tx } func (m *mempool) Remove(txsToRemove []*txs.Tx) { - remover := &remover{ - m: m, - } - for _, tx := range txsToRemove { - remover.tx = tx - _ = tx.Unsigned.Visit(remover) + txID := tx.ID() + if !m.unissuedTxs.Delete(txID) { + continue + } + + m.bytesAvailable += len(tx.Bytes()) + m.bytesAvailableMetric.Set(float64(m.bytesAvailable)) + + m.numTxs.Dec() + + inputs := tx.Unsigned.InputIDs() + m.consumedUTXOs.Difference(inputs) } } func (m *mempool) HasTxs() bool { - return m.unissuedDecisionTxs.Len() > 0 || m.unissuedStakerTxs.Len() > 0 + return m.unissuedTxs.Len() > 0 } func (m *mempool) PeekTxs(maxTxsBytes int) []*txs.Tx { - txs := m.unissuedDecisionTxs.List() - txs = append(txs, m.unissuedStakerTxs.List()...) - + var txs []*txs.Tx + txIter := m.unissuedTxs.NewIterator() size := 0 - for i, tx := range txs { + for txIter.Next() { + tx := txIter.Value() size += len(tx.Bytes()) if size > maxTxsBytes { - return txs[:i] + return txs } + txs = append(txs, tx) } return txs } -func (m *mempool) addDecisionTx(tx *txs.Tx) { - m.unissuedDecisionTxs.Add(tx) - m.register(tx) -} - -func (m *mempool) addStakerTx(tx *txs.Tx) { - m.unissuedStakerTxs.Add(tx) - m.register(tx) -} - -func (m *mempool) HasStakerTx() bool { - return m.unissuedStakerTxs.Len() > 0 -} - -func (m *mempool) removeDecisionTxs(txs []*txs.Tx) { - for _, tx := range txs { - txID := tx.ID() - if m.unissuedDecisionTxs.Remove(txID) != nil { - m.deregister(tx) - } - } -} - -func (m *mempool) removeStakerTx(tx *txs.Tx) { - txID := tx.ID() - if m.unissuedStakerTxs.Remove(txID) != nil { - m.deregister(tx) - } -} - -func (m *mempool) PeekStakerTx() *txs.Tx { - if m.unissuedStakerTxs.Len() == 0 { - return nil - } - - return m.unissuedStakerTxs.Peek() -} - func (m *mempool) MarkDropped(txID ids.ID, reason error) { m.droppedTxIDs.Put(txID, reason) } @@ -292,35 +259,24 @@ func (m *mempool) GetDropReason(txID ids.ID) error { return err } -func (m *mempool) register(tx *txs.Tx) { - txBytes := tx.Bytes() - m.bytesAvailable -= len(txBytes) - m.bytesAvailableMetric.Set(float64(m.bytesAvailable)) -} - -func (m *mempool) deregister(tx *txs.Tx) { - txBytes := tx.Bytes() - m.bytesAvailable += len(txBytes) - m.bytesAvailableMetric.Set(float64(m.bytesAvailable)) - - inputs := tx.Unsigned.InputIDs() - m.consumedUTXOs.Difference(inputs) -} - // Drops all [txs.Staker] transactions whose [StartTime] is before // [minStartTime] from [mempool]. The dropped tx ids are returned. // // TODO: Remove once [StartTime] field is ignored in staker txs -func DropExpiredStakerTxs(mempool Mempool, minStartTime time.Time) []ids.ID { +func (m *mempool) DropExpiredStakerTxs(minStartTime time.Time) []ids.ID { var droppedTxIDs []ids.ID - for mempool.HasStakerTx() { - tx := mempool.PeekStakerTx() - startTime := tx.Unsigned.(txs.Staker).StartTime() + txIter := m.unissuedTxs.NewIterator() + for txIter.Next() { + tx := txIter.Value() + stakerTx, ok := tx.Unsigned.(txs.Staker) + if !ok { + continue + } + + startTime := stakerTx.StartTime() if !startTime.Before(minStartTime) { - // The next proposal tx in the mempool starts sufficiently far in - // the future. - break + continue } txID := tx.ID() @@ -330,8 +286,8 @@ func DropExpiredStakerTxs(mempool Mempool, minStartTime time.Time) []ids.ID { startTime, ) - mempool.Remove([]*txs.Tx{tx}) - mempool.MarkDropped(txID, err) // cache tx as dropped + m.Remove([]*txs.Tx{tx}) + m.MarkDropped(txID, err) // cache tx as dropped droppedTxIDs = append(droppedTxIDs, txID) } diff --git a/vms/platformvm/txs/mempool/mempool_test.go b/vms/platformvm/txs/mempool/mempool_test.go index dbfe895f9d9b..a56ae4702155 100644 --- a/vms/platformvm/txs/mempool/mempool_test.go +++ b/vms/platformvm/txs/mempool/mempool_test.go @@ -20,14 +20,16 @@ import ( "github.com/ava-labs/avalanchego/vms/secp256k1fx" ) -var _ BlockTimer = (*noopBlkTimer)(nil) +var ( + _ BlockTimer = (*noopBlkTimer)(nil) + + preFundedKeys = secp256k1.TestKeys() +) type noopBlkTimer struct{} func (*noopBlkTimer) ResetBlockTimer() {} -var preFundedKeys = secp256k1.TestKeys() - // shows that valid tx is not added to mempool if this would exceed its maximum // size func TestBlockBuilderMaxMempoolSizeHandling(t *testing.T) { @@ -119,9 +121,6 @@ func TestProposalTxsInMempool(t *testing.T) { proposalTxs, err := createTestProposalTxs(2) require.NoError(err) - // txs should not be already there - require.False(mpool.HasStakerTx()) - for i, tx := range proposalTxs { require.False(mpool.Has(tx.ID())) @@ -129,20 +128,12 @@ func TestProposalTxsInMempool(t *testing.T) { require.NoError(mpool.Add(tx)) // we can get it - require.True(mpool.HasStakerTx()) require.True(mpool.Has(tx.ID())) retrieved := mpool.Get(tx.ID()) require.NotNil(retrieved) require.Equal(tx, retrieved) - { - // we can peek it - peeked := mpool.PeekStakerTx() - require.NotNil(peeked) - require.Equal(tx, peeked) - } - { // we can peek it peeked := mpool.PeekTxs(math.MaxInt) @@ -222,17 +213,10 @@ func createTestProposalTxs(count int) ([]*txs.Tx, error) { now := time.Now() proposalTxs := make([]*txs.Tx, 0, count) for i := 0; i < count; i++ { - utx := &txs.AddValidatorTx{ - BaseTx: txs.BaseTx{}, - Validator: txs.Validator{ - Start: uint64(now.Add(time.Duration(count-i) * time.Second).Unix()), - }, - StakeOuts: nil, - RewardsOwner: &secp256k1fx.OutputOwners{}, - DelegationShares: 100, - } - - tx, err := txs.NewSigned(utx, txs.Codec, nil) + tx, err := generateAddValidatorTx( + uint64(now.Add(time.Duration(count-i)*time.Second).Unix()), // startTime + 0, // endTime + ) if err != nil { return nil, err } @@ -240,3 +224,42 @@ func createTestProposalTxs(count int) ([]*txs.Tx, error) { } return proposalTxs, nil } + +func generateAddValidatorTx(startTime uint64, endTime uint64) (*txs.Tx, error) { + utx := &txs.AddValidatorTx{ + BaseTx: txs.BaseTx{}, + Validator: txs.Validator{ + NodeID: ids.GenerateTestNodeID(), + Start: startTime, + End: endTime, + }, + StakeOuts: nil, + RewardsOwner: &secp256k1fx.OutputOwners{}, + DelegationShares: 100, + } + + return txs.NewSigned(utx, txs.Codec, nil) +} + +func TestDropExpiredStakerTxs(t *testing.T) { + require := require.New(t) + + registerer := prometheus.NewRegistry() + mempool, err := New("mempool", registerer, &noopBlkTimer{}) + require.NoError(err) + + tx1, err := generateAddValidatorTx(10, 20) + require.NoError(err) + require.NoError(mempool.Add(tx1)) + + tx2, err := generateAddValidatorTx(8, 20) + require.NoError(err) + require.NoError(mempool.Add(tx2)) + + tx3, err := generateAddValidatorTx(15, 20) + require.NoError(err) + require.NoError(mempool.Add(tx3)) + + minStartTime := time.Unix(9, 0) + require.Len(mempool.DropExpiredStakerTxs(minStartTime), 1) +} diff --git a/vms/platformvm/txs/mempool/mock_mempool.go b/vms/platformvm/txs/mempool/mock_mempool.go index a4baccd405e9..8f8c90eb2d07 100644 --- a/vms/platformvm/txs/mempool/mock_mempool.go +++ b/vms/platformvm/txs/mempool/mock_mempool.go @@ -9,6 +9,7 @@ package mempool import ( reflect "reflect" + time "time" ids "github.com/ava-labs/avalanchego/ids" txs "github.com/ava-labs/avalanchego/vms/platformvm/txs" @@ -64,6 +65,20 @@ func (mr *MockMempoolMockRecorder) DisableAdding() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisableAdding", reflect.TypeOf((*MockMempool)(nil).DisableAdding)) } +// DropExpiredStakerTxs mocks base method. +func (m *MockMempool) DropExpiredStakerTxs(arg0 time.Time) []ids.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DropExpiredStakerTxs", arg0) + ret0, _ := ret[0].([]ids.ID) + return ret0 +} + +// DropExpiredStakerTxs indicates an expected call of DropExpiredStakerTxs. +func (mr *MockMempoolMockRecorder) DropExpiredStakerTxs(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DropExpiredStakerTxs", reflect.TypeOf((*MockMempool)(nil).DropExpiredStakerTxs), arg0) +} + // EnableAdding mocks base method. func (m *MockMempool) EnableAdding() { m.ctrl.T.Helper() @@ -118,20 +133,6 @@ func (mr *MockMempoolMockRecorder) Has(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockMempool)(nil).Has), arg0) } -// HasStakerTx mocks base method. -func (m *MockMempool) HasStakerTx() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HasStakerTx") - ret0, _ := ret[0].(bool) - return ret0 -} - -// HasStakerTx indicates an expected call of HasStakerTx. -func (mr *MockMempoolMockRecorder) HasStakerTx() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasStakerTx", reflect.TypeOf((*MockMempool)(nil).HasStakerTx)) -} - // HasTxs mocks base method. func (m *MockMempool) HasTxs() bool { m.ctrl.T.Helper() @@ -158,20 +159,6 @@ func (mr *MockMempoolMockRecorder) MarkDropped(arg0, arg1 interface{}) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarkDropped", reflect.TypeOf((*MockMempool)(nil).MarkDropped), arg0, arg1) } -// PeekStakerTx mocks base method. -func (m *MockMempool) PeekStakerTx() *txs.Tx { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PeekStakerTx") - ret0, _ := ret[0].(*txs.Tx) - return ret0 -} - -// PeekStakerTx indicates an expected call of PeekStakerTx. -func (mr *MockMempoolMockRecorder) PeekStakerTx() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeekStakerTx", reflect.TypeOf((*MockMempool)(nil).PeekStakerTx)) -} - // PeekTxs mocks base method. func (m *MockMempool) PeekTxs(arg0 int) []*txs.Tx { m.ctrl.T.Helper() diff --git a/vms/platformvm/txs/mempool/remover.go b/vms/platformvm/txs/mempool/remover.go deleted file mode 100644 index b21071b16465..000000000000 --- a/vms/platformvm/txs/mempool/remover.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package mempool - -import "github.com/ava-labs/avalanchego/vms/platformvm/txs" - -var _ txs.Visitor = (*remover)(nil) - -type remover struct { - m *mempool - tx *txs.Tx -} - -func (r *remover) AddValidatorTx(*txs.AddValidatorTx) error { - r.m.removeStakerTx(r.tx) - return nil -} - -func (r *remover) AddSubnetValidatorTx(*txs.AddSubnetValidatorTx) error { - r.m.removeStakerTx(r.tx) - return nil -} - -func (r *remover) AddDelegatorTx(*txs.AddDelegatorTx) error { - r.m.removeStakerTx(r.tx) - return nil -} - -func (r *remover) RemoveSubnetValidatorTx(*txs.RemoveSubnetValidatorTx) error { - r.m.removeDecisionTxs([]*txs.Tx{r.tx}) - return nil -} - -func (r *remover) CreateChainTx(*txs.CreateChainTx) error { - r.m.removeDecisionTxs([]*txs.Tx{r.tx}) - return nil -} - -func (r *remover) CreateSubnetTx(*txs.CreateSubnetTx) error { - r.m.removeDecisionTxs([]*txs.Tx{r.tx}) - return nil -} - -func (r *remover) ImportTx(*txs.ImportTx) error { - r.m.removeDecisionTxs([]*txs.Tx{r.tx}) - return nil -} - -func (r *remover) ExportTx(*txs.ExportTx) error { - r.m.removeDecisionTxs([]*txs.Tx{r.tx}) - return nil -} - -func (r *remover) TransformSubnetTx(*txs.TransformSubnetTx) error { - r.m.removeDecisionTxs([]*txs.Tx{r.tx}) - return nil -} - -func (r *remover) TransferSubnetOwnershipTx(*txs.TransferSubnetOwnershipTx) error { - r.m.removeDecisionTxs([]*txs.Tx{r.tx}) - return nil -} - -func (r *remover) BaseTx(*txs.BaseTx) error { - r.m.removeDecisionTxs([]*txs.Tx{r.tx}) - return nil -} - -func (r *remover) AddPermissionlessValidatorTx(*txs.AddPermissionlessValidatorTx) error { - r.m.removeStakerTx(r.tx) - return nil -} - -func (r *remover) AddPermissionlessDelegatorTx(*txs.AddPermissionlessDelegatorTx) error { - r.m.removeStakerTx(r.tx) - return nil -} - -func (*remover) AdvanceTimeTx(*txs.AdvanceTimeTx) error { - // this tx is never in mempool - return nil -} - -func (*remover) RewardValidatorTx(*txs.RewardValidatorTx) error { - // this tx is never in mempool - return nil -} diff --git a/vms/platformvm/txs/txheap/by_age.go b/vms/platformvm/txs/txheap/by_age.go deleted file mode 100644 index be888c437a0f..000000000000 --- a/vms/platformvm/txs/txheap/by_age.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package txheap - -import ( - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/heap" -) - -func NewByAge() Heap { - return &txHeap{ - heap: heap.NewMap[ids.ID, heapTx](func(a, b heapTx) bool { - return a.age < b.age - }), - } -} diff --git a/vms/platformvm/txs/txheap/by_end_time.go b/vms/platformvm/txs/txheap/by_end_time.go index ba144448919d..2499ce971bc9 100644 --- a/vms/platformvm/txs/txheap/by_end_time.go +++ b/vms/platformvm/txs/txheap/by_end_time.go @@ -13,6 +13,12 @@ import ( var _ TimedHeap = (*byEndTime)(nil) +type TimedHeap interface { + Heap + + Timestamp() time.Time +} + type byEndTime struct { txHeap } diff --git a/vms/platformvm/txs/txheap/by_start_time.go b/vms/platformvm/txs/txheap/by_start_time.go deleted file mode 100644 index f19c28d76436..000000000000 --- a/vms/platformvm/txs/txheap/by_start_time.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package txheap - -import ( - "time" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/heap" - "github.com/ava-labs/avalanchego/vms/platformvm/txs" -) - -var _ TimedHeap = (*byStartTime)(nil) - -type TimedHeap interface { - Heap - - Timestamp() time.Time -} - -type byStartTime struct { - txHeap -} - -func NewByStartTime() TimedHeap { - return &byStartTime{ - txHeap: txHeap{ - heap: heap.NewMap[ids.ID, heapTx](func(a, b heapTx) bool { - aTime := a.tx.Unsigned.(txs.Staker).StartTime() - bTime := b.tx.Unsigned.(txs.Staker).StartTime() - return aTime.Before(bTime) - }), - }, - } -} - -func (h *byStartTime) Timestamp() time.Time { - return h.Peek().Unsigned.(txs.Staker).StartTime() -} diff --git a/vms/platformvm/txs/txheap/by_start_time_test.go b/vms/platformvm/txs/txheap/by_start_time_test.go deleted file mode 100644 index e00d42076015..000000000000 --- a/vms/platformvm/txs/txheap/by_start_time_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package txheap - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/vms/platformvm/txs" - "github.com/ava-labs/avalanchego/vms/secp256k1fx" -) - -func TestByStartTime(t *testing.T) { - require := require.New(t) - - txHeap := NewByStartTime() - - baseTime := time.Now() - - utx0 := &txs.AddValidatorTx{ - Validator: txs.Validator{ - NodeID: ids.BuildTestNodeID([]byte{0}), - Start: uint64(baseTime.Unix()) + 1, - End: uint64(baseTime.Unix()) + 1, - }, - RewardsOwner: &secp256k1fx.OutputOwners{}, - } - tx0 := &txs.Tx{Unsigned: utx0} - require.NoError(tx0.Initialize(txs.Codec)) - - utx1 := &txs.AddValidatorTx{ - Validator: txs.Validator{ - NodeID: ids.BuildTestNodeID([]byte{1}), - Start: uint64(baseTime.Unix()) + 2, - End: uint64(baseTime.Unix()) + 2, - }, - RewardsOwner: &secp256k1fx.OutputOwners{}, - } - tx1 := &txs.Tx{Unsigned: utx1} - require.NoError(tx1.Initialize(txs.Codec)) - - utx2 := &txs.AddValidatorTx{ - Validator: txs.Validator{ - NodeID: ids.BuildTestNodeID([]byte{1}), - Start: uint64(baseTime.Unix()) + 3, - End: uint64(baseTime.Unix()) + 3, - }, - RewardsOwner: &secp256k1fx.OutputOwners{}, - } - tx2 := &txs.Tx{Unsigned: utx2} - require.NoError(tx2.Initialize(txs.Codec)) - - txHeap.Add(tx2) - require.Equal(utx2.EndTime(), txHeap.Timestamp()) - - txHeap.Add(tx1) - require.Equal(utx1.EndTime(), txHeap.Timestamp()) - - txHeap.Add(tx0) - require.Equal(utx0.EndTime(), txHeap.Timestamp()) - require.Equal(tx0, txHeap.Peek()) -}