diff --git a/pkg/core/weight/value.go b/pkg/core/weight/value.go index 2bcb0706d..a251fa581 100644 --- a/pkg/core/weight/value.go +++ b/pkg/core/weight/value.go @@ -13,6 +13,9 @@ type Value struct { // validatorsWeight is the second tier which tracks weight in a non-cumulative manner (BFT style). validatorsWeight int64 + // attestorsWeight is the third tier which tracks weight in a non-cumulative manner (BFT style). + attestorsWeight int64 + // acceptanceState is the final tier which determines the decision of the spender. acceptanceState acceptance.State } @@ -55,6 +58,18 @@ func (v Value) SetValidatorsWeight(weight int64) Value { return v } +// AttestorsWeight returns the weight of the validators. +func (v Value) AttestorsWeight() int64 { + return v.attestorsWeight +} + +// SetAttestorsWeight sets the weight of the attestors and returns the new Value. +func (v Value) SetAttestorsWeight(weight int64) Value { + v.attestorsWeight = weight + + return v +} + // AcceptanceState returns the acceptance state of the Value. func (v Value) AcceptanceState() acceptance.State { return v.acceptanceState diff --git a/pkg/core/weight/weight.go b/pkg/core/weight/weight.go index 0fb43fd9f..d0f21f3f5 100644 --- a/pkg/core/weight/weight.go +++ b/pkg/core/weight/weight.go @@ -17,6 +17,9 @@ type Weight struct { // Voters is the set of voters contributing to the weight Voters ds.Set[account.SeatIndex] + // Attestors is the set of attestors contributing to the weight. + Attestors ds.Set[account.SeatIndex] + // value is the current weight Value. value Value @@ -27,8 +30,9 @@ type Weight struct { // New creates a new Weight instance. func New() *Weight { w := &Weight{ - Voters: ds.NewSet[account.SeatIndex](), - OnUpdate: event.New1[Value](), + Voters: ds.NewSet[account.SeatIndex](), + Attestors: ds.NewSet[account.SeatIndex](), + OnUpdate: event.New1[Value](), } return w @@ -103,6 +107,41 @@ func (w *Weight) DeleteVoter(seat account.SeatIndex) *Weight { return w } +// AddAttestor adds the given voter to the list of Attestors, updates the weight and returns the Weight (for chaining). +func (w *Weight) AddAttestor(seat account.SeatIndex) *Weight { + if added := w.Attestors.Add(seat); added { + if newValue, valueUpdated := w.updateAttestorsWeight(); valueUpdated { + w.OnUpdate.Trigger(newValue) + } + } + + return w +} + +// DeleteAttestor removes the given voter from the list of Attestors, updates the weight and returns the Weight (for chaining). +func (w *Weight) DeleteAttestor(seat account.SeatIndex) *Weight { + if deleted := w.Attestors.Delete(seat); deleted { + if newValue, valueUpdated := w.updateAttestorsWeight(); valueUpdated { + w.OnUpdate.Trigger(newValue) + } + } + + return w +} + +// ResetAttestors removes all voters from the list of Attestors, updates the weight and returns the Weight (for chaining). +func (w *Weight) ResetAttestors() *Weight { + if w.Attestors.Size() >= 1 { + w.Attestors.Clear() + + if newValue, valueUpdated := w.updateAttestorsWeight(); valueUpdated { + w.OnUpdate.Trigger(newValue) + } + } + + return w +} + func (w *Weight) updateValidatorsWeight() (Value, bool) { w.mutex.Lock() defer w.mutex.Unlock() @@ -117,6 +156,20 @@ func (w *Weight) updateValidatorsWeight() (Value, bool) { return w.value, false } +func (w *Weight) updateAttestorsWeight() (Value, bool) { + w.mutex.Lock() + defer w.mutex.Unlock() + + newAttestorsWeight := int64(w.Attestors.Size()) + if w.value.AttestorsWeight() != newAttestorsWeight { + w.value = w.value.SetAttestorsWeight(newAttestorsWeight) + + return w.value, true + } + + return w.value, false +} + // AcceptanceState returns the acceptance state of the weight. func (w *Weight) AcceptanceState() acceptance.State { w.mutex.RLock() diff --git a/pkg/protocol/chains.go b/pkg/protocol/chains.go index d0cecca08..def67869d 100644 --- a/pkg/protocol/chains.go +++ b/pkg/protocol/chains.go @@ -213,15 +213,15 @@ func attachEngineLogs(instance *engine.Engine) func() { }).Unhook, events.SeatManager.OnlineCommitteeSeatAdded.Hook(func(seat account.SeatIndex, accountID iotago.AccountID) { - instance.LogTrace("SybilProtection.OnlineCommitteeSeatAdded", "seat", seat, "accountID", accountID) + instance.LogInfo("SybilProtection.OnlineCommitteeSeatAdded", "seat", seat, "accountID", accountID) }).Unhook, events.SeatManager.OnlineCommitteeSeatRemoved.Hook(func(seat account.SeatIndex) { - instance.LogTrace("SybilProtection.OnlineCommitteeSeatRemoved", "seat", seat) + instance.LogInfo("SybilProtection.OnlineCommitteeSeatRemoved", "seat", seat) }).Unhook, events.SybilProtection.CommitteeSelected.Hook(func(committee *account.SeatedAccounts, epoch iotago.EpochIndex) { - instance.LogTrace("SybilProtection.CommitteeSelected", "epoch", epoch, "committee", committee.IDs()) + instance.LogInfo("SybilProtection.CommitteeSelected", "epoch", epoch, "committee", committee.IDs()) }).Unhook, events.SpendDAG.SpenderCreated.Hook(func(conflictID iotago.TransactionID) { diff --git a/pkg/protocol/engine/mempool/spenddag/spenddagv1/spender.go b/pkg/protocol/engine/mempool/spenddag/spenddagv1/spender.go index fc432b021..ea91565fa 100644 --- a/pkg/protocol/engine/mempool/spenddag/spenddagv1/spender.go +++ b/pkg/protocol/engine/mempool/spenddag/spenddagv1/spender.go @@ -113,13 +113,13 @@ func NewSpender[SpenderID, ResourceID spenddag.IDType, VoteRank spenddag.VoteRan c.preferredInstead = c c.unhookAcceptanceMonitoring = c.Weight.OnUpdate.Hook(func(value weight.Value) { - if value.AcceptanceState().IsPending() && value.ValidatorsWeight() >= c.acceptanceThreshold() { + if threshold := c.acceptanceThreshold(); value.AcceptanceState().IsPending() && value.ValidatorsWeight() >= threshold && value.AttestorsWeight() >= threshold { c.setAcceptanceState(acceptance.Accepted) } }).Unhook // in case the initial weight is enough to accept the spend, accept it immediately - if threshold := c.acceptanceThreshold(); initialWeight.Value().ValidatorsWeight() >= threshold { + if threshold := c.acceptanceThreshold(); initialWeight.AcceptanceState().IsPending() && initialWeight.Value().ValidatorsWeight() >= threshold && initialWeight.Value().AttestorsWeight() >= threshold { c.setAcceptanceState(acceptance.Accepted) } @@ -219,6 +219,17 @@ func (c *Spender[SpenderID, ResourceID, VoteRank]) ApplyVote(vote *vote.Vote[Vot // update the latest vote c.LatestVotes.Set(vote.Voter, vote) + // track attestors when we reach the acceptance threshold + if c.Weight.Value().ValidatorsWeight() >= c.acceptanceThreshold() { + if vote.IsLiked() { + c.Weight.AddAttestor(vote.Voter) + } else { + c.Weight.DeleteAttestor(vote.Voter) + } + } else { + c.Weight.ResetAttestors() + } + // abort if the vote does not change the opinion of the validator if exists && latestVote.IsLiked() == vote.IsLiked() { return diff --git a/pkg/protocol/engine/mempool/spenddag/tests/tests.go b/pkg/protocol/engine/mempool/spenddag/tests/tests.go index cfe6ce0b7..db1d56997 100644 --- a/pkg/protocol/engine/mempool/spenddag/tests/tests.go +++ b/pkg/protocol/engine/mempool/spenddag/tests/tests.go @@ -117,7 +117,9 @@ func CreateSpendWithoutMembers(t *testing.T, tf *Framework) { require.NoError(t, tf.CastVotes("nodeID1", 1, "spender1")) require.NoError(t, tf.CastVotes("nodeID2", 1, "spender1")) require.NoError(t, tf.CastVotes("nodeID3", 1, "spender1")) - + require.NoError(t, tf.CastVotes("nodeID1", 2, "spender1")) + require.NoError(t, tf.CastVotes("nodeID2", 2, "spender1")) + require.NoError(t, tf.CastVotes("nodeID3", 2, "spender1")) tf.Assert.LikedInstead([]string{"spender1"}) tf.Assert.Accepted("spender1") } @@ -188,6 +190,9 @@ func SpendAcceptance(t *testing.T, tf *Framework) { require.NoError(t, tf.CastVotes("nodeID2", 1, "spender4")) require.NoError(t, tf.CastVotes("nodeID3", 1, "spender4")) + require.NoError(t, tf.CastVotes("nodeID1", 2, "spender4")) + require.NoError(t, tf.CastVotes("nodeID2", 2, "spender4")) + require.NoError(t, tf.CastVotes("nodeID3", 2, "spender4")) tf.Assert.LikedInstead([]string{"spender1"}) tf.Assert.LikedInstead([]string{"spender2"}, "spender1") tf.Assert.LikedInstead([]string{"spender3"}, "spender4") @@ -224,6 +229,10 @@ func CastVotes(t *testing.T, tf *Framework) { require.NoError(t, tf.CastVotes("nodeID1", 1, "spender2")) require.NoError(t, tf.CastVotes("nodeID2", 1, "spender2")) require.NoError(t, tf.CastVotes("nodeID3", 1, "spender2")) + require.NoError(t, tf.CastVotes("nodeID4", 2, "spender2")) + require.NoError(t, tf.CastVotes("nodeID2", 2, "spender2")) + require.NoError(t, tf.CastVotes("nodeID3", 2, "spender2")) + tf.Assert.LikedInstead([]string{"spender1"}, "spender2") tf.Assert.Accepted("spender2") @@ -317,6 +326,9 @@ func CastVotesAcceptance(t *testing.T, tf *Framework) { require.NoError(t, tf.CastVotes("nodeID1", 1, "spender3")) require.NoError(t, tf.CastVotes("nodeID2", 1, "spender3")) require.NoError(t, tf.CastVotes("nodeID3", 1, "spender3")) + require.NoError(t, tf.CastVotes("nodeID4", 2, "spender3")) + require.NoError(t, tf.CastVotes("nodeID2", 2, "spender3")) + require.NoError(t, tf.CastVotes("nodeID3", 2, "spender3")) tf.Assert.LikedInstead([]string{"spender1"}) tf.Assert.Accepted("spender1") tf.Assert.Rejected("spender2") @@ -410,6 +422,9 @@ func EvictAcceptedSpender(t *testing.T, tf *Framework) { require.NoError(t, tf.CastVotes("nodeID1", 1, "spender2")) require.NoError(t, tf.CastVotes("nodeID2", 1, "spender2")) require.NoError(t, tf.CastVotes("nodeID3", 1, "spender2")) + require.NoError(t, tf.CastVotes("nodeID1", 2, "spender2")) + require.NoError(t, tf.CastVotes("nodeID2", 2, "spender2")) + require.NoError(t, tf.CastVotes("nodeID3", 2, "spender2")) tf.Assert.LikedInstead([]string{"spender1"}, "spender2") tf.Assert.Accepted("spender2") @@ -478,6 +493,9 @@ func EvictRejectedSpender(t *testing.T, tf *Framework) { require.NoError(t, tf.CastVotes("nodeID1", 1, "spender2")) require.NoError(t, tf.CastVotes("nodeID2", 1, "spender2")) require.NoError(t, tf.CastVotes("nodeID3", 1, "spender2")) + require.NoError(t, tf.CastVotes("nodeID1", 2, "spender2")) + require.NoError(t, tf.CastVotes("nodeID2", 2, "spender2")) + require.NoError(t, tf.CastVotes("nodeID3", 2, "spender2")) tf.Assert.LikedInstead([]string{"spender1"}, "spender2") tf.Assert.Rejected("spender1") diff --git a/pkg/protocol/engine/mempool/v1/mempool.go b/pkg/protocol/engine/mempool/v1/mempool.go index dc0a4458f..c87aee4c3 100644 --- a/pkg/protocol/engine/mempool/v1/mempool.go +++ b/pkg/protocol/engine/mempool/v1/mempool.go @@ -121,7 +121,6 @@ func (m *MemPool[VoteRank]) AttachSignedTransaction(signedTransaction mempool.Si if isNewTransaction { m.transactionAttached.Trigger(storedSignedTransaction.transactionMetadata) - m.solidifyInputs(storedSignedTransaction.transactionMetadata) } } diff --git a/pkg/tests/booker_test.go b/pkg/tests/booker_test.go index 333fb3e4c..57f396580 100644 --- a/pkg/tests/booker_test.go +++ b/pkg/tests/booker_test.go @@ -201,6 +201,8 @@ func Test_DoubleSpend(t *testing.T) { { ts.IssueValidationBlockWithHeaderOptions("block6", node2, mock.WithStrongParents(ts.BlockIDs("block3", "block4")...), mock.WithShallowLikeParents(ts.BlockID("block2"))) ts.IssueValidationBlockWithHeaderOptions("block7", node1, mock.WithStrongParents(ts.BlockIDs("block6")...)) + ts.IssueValidationBlockWithHeaderOptions("block8", node2, mock.WithStrongParents(ts.BlockIDs("block7")...)) + ts.IssueValidationBlockWithHeaderOptions("block9", node1, mock.WithStrongParents(ts.BlockIDs("block8")...)) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("block6"): {"tx2"}, @@ -223,7 +225,7 @@ func Test_MultipleAttachments(t *testing.T) { blocksConflicts := make(map[*blocks.Block][]string) - // Create a transaction and issue it from both nodes, so that the conflict is accepted, but no attachment is included yet. + // Create a transaction and issue it from both nodes, so that the spend is accepted, but no attachment is included yet. { tx1 := wallet.CreateBasicOutputsEquallyFromInput("tx1", 2, "Genesis:0") @@ -234,17 +236,23 @@ func Test_MultipleAttachments(t *testing.T) { ts.IssueValidationBlockWithHeaderOptions("B.1.1", nodeB, mock.WithStrongParents(ts.BlockID("B.1"))) nodeA.Wait() - ts.IssueValidationBlockWithHeaderOptions("A.2", nodeA, mock.WithStrongParents(ts.BlockID("B.1.1"))) - ts.IssueValidationBlockWithHeaderOptions("B.2", nodeB, mock.WithStrongParents(ts.BlockID("A.1.1"))) + ts.IssueValidationBlockWithHeaderOptions("A.2.1", nodeA, mock.WithStrongParents(ts.BlockID("B.1.1"))) + ts.IssueValidationBlockWithHeaderOptions("B.2.1", nodeB, mock.WithStrongParents(ts.BlockID("A.1.1"))) + + // Cast more votes to accept the transaction. + ts.IssueValidationBlockWithHeaderOptions("A.2.2", nodeA, mock.WithStrongParents(ts.BlockID("A.1"))) + ts.IssueValidationBlockWithHeaderOptions("B.2.2", nodeB, mock.WithStrongParents(ts.BlockID("B.1"))) + ts.IssueValidationBlockWithHeaderOptions("A.3.2", nodeA, mock.WithStrongParents(ts.BlockID("B.2.2"))) + ts.IssueValidationBlockWithHeaderOptions("B.3.2", nodeB, mock.WithStrongParents(ts.BlockID("A.2.2"))) ts.AssertBlocksInCachePreAccepted(ts.Blocks("A.1", "B.1"), true, ts.Nodes()...) ts.AssertBlocksInCacheAccepted(ts.Blocks("A.1", "B.1"), false, ts.Nodes()...) ts.AssertBlocksInCacheConflicts(lo.MergeMaps(blocksConflicts, map[*blocks.Block][]string{ - ts.Block("A.1"): {"tx1"}, - ts.Block("B.1"): {"tx1"}, - ts.Block("A.2"): {"tx1"}, - ts.Block("B.2"): {"tx1"}, + ts.Block("A.1"): {"tx1"}, + ts.Block("B.1"): {"tx1"}, + ts.Block("A.2.1"): {"tx1"}, + ts.Block("B.2.1"): {"tx1"}, }), ts.Nodes()...) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ wallet.Transaction("tx1"): {"tx1"}, @@ -262,13 +270,19 @@ func Test_MultipleAttachments(t *testing.T) { ts.IssueValidationBlockWithHeaderOptions("B.3", nodeB, mock.WithStrongParents(ts.BlockID("A.3.1"))) ts.IssueValidationBlockWithHeaderOptions("A.4", nodeA, mock.WithStrongParents(ts.BlockID("B.3"))) + // Issue attestor votes. + ts.IssueValidationBlockWithHeaderOptions("B.4", nodeB, mock.WithStrongParents(ts.BlockID("A.3"))) + ts.IssueValidationBlockWithHeaderOptions("A.5", nodeA, mock.WithStrongParents(ts.BlockID("B.4"))) + ts.AssertBlocksInCachePreAccepted(ts.Blocks("A.3"), true, ts.Nodes()...) - ts.IssueValidationBlockWithHeaderOptions("B.4", nodeB, mock.WithStrongParents(ts.BlockIDs("B.3", "A.4")...)) - ts.IssueValidationBlockWithHeaderOptions("A.5", nodeA, mock.WithStrongParents(ts.BlockIDs("B.3", "A.4")...)) + ts.IssueValidationBlockWithHeaderOptions("B.5", nodeB, mock.WithStrongParents(ts.BlockIDs("B.3", "A.4")...)) + ts.IssueValidationBlockWithHeaderOptions("A.6", nodeA, mock.WithStrongParents(ts.BlockIDs("B.3", "A.4")...)) + ts.IssueValidationBlockWithHeaderOptions("B.6", nodeB, mock.WithStrongParents(ts.BlockIDs("B.3", "A.4")...)) + ts.IssueValidationBlockWithHeaderOptions("A.7", nodeA, mock.WithStrongParents(ts.BlockIDs("B.3", "A.4")...)) - ts.AssertBlocksInCachePreAccepted(ts.Blocks("B.3", "A.4"), true, ts.Nodes()...) - ts.AssertBlocksInCachePreAccepted(ts.Blocks("B.4", "A.5"), false, ts.Nodes()...) + ts.AssertBlocksInCachePreAccepted(ts.Blocks("B.3", "A.4", "B.4"), true, ts.Nodes()...) + ts.AssertBlocksInCachePreAccepted(ts.Blocks("A.5", "B.5", "A.6", "B.6", "A.7"), false, ts.Nodes()...) ts.AssertBlocksInCacheAccepted(ts.Blocks("A.3"), true, ts.Nodes()...) ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx1", "tx2"), true, ts.Nodes()...) @@ -278,8 +292,12 @@ func Test_MultipleAttachments(t *testing.T) { ts.Block("A.3"): {"tx2"}, ts.Block("B.3"): {"tx2"}, ts.Block("A.4"): {"tx2"}, - ts.Block("A.5"): {}, - ts.Block("B.4"): {}, + ts.Block("A.5"): {"tx2"}, + ts.Block("A.6"): {}, + ts.Block("B.4"): {"tx2"}, + ts.Block("B.5"): {"tx2"}, + ts.Block("A.7"): {}, + ts.Block("B.6"): {}, }), ts.Nodes()...) ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ wallet.Transaction("tx1"): {"tx1"}, @@ -290,13 +308,13 @@ func Test_MultipleAttachments(t *testing.T) { // Issue a block that includes tx1, and make sure that tx2 is accepted as well as a consequence. { - ts.IssueValidationBlockWithHeaderOptions("A.6", nodeA, mock.WithStrongParents(ts.BlockIDs("A.2", "B.2")...)) - ts.IssueValidationBlockWithHeaderOptions("B.5", nodeB, mock.WithStrongParents(ts.BlockIDs("A.2", "B.2")...)) + ts.IssueValidationBlockWithHeaderOptions("A.6", nodeA, mock.WithStrongParents(ts.BlockIDs("A.2.1", "B.2.1")...)) + ts.IssueValidationBlockWithHeaderOptions("B.5", nodeB, mock.WithStrongParents(ts.BlockIDs("A.2.1", "B.2.1")...)) ts.IssueValidationBlockWithHeaderOptions("A.7", nodeA, mock.WithStrongParents(ts.BlockIDs("A.6", "B.5")...)) ts.IssueValidationBlockWithHeaderOptions("B.6", nodeB, mock.WithStrongParents(ts.BlockIDs("A.6", "B.5")...)) - ts.AssertBlocksInCachePreAccepted(ts.Blocks("A.2", "B.2", "A.6", "B.5"), true, ts.Nodes()...) + ts.AssertBlocksInCachePreAccepted(ts.Blocks("A.2.1", "B.2.1", "A.6", "B.5"), true, ts.Nodes()...) ts.AssertBlocksInCacheAccepted(ts.Blocks("A.1", "B.1"), true, ts.Nodes()...) ts.AssertBlocksInCachePreAccepted(ts.Blocks("A.7", "B.6"), false, ts.Nodes()...) @@ -396,6 +414,8 @@ func Test_SpendRejectedCommittedRace(t *testing.T) { { ts.IssueValidationBlockWithHeaderOptions("block2.3", node2, mock.WithSlotCommitment(genesisCommitment), mock.WithStrongParents(ts.BlockIDs("block2.2")...)) ts.IssueValidationBlockWithHeaderOptions("block2.4", node1, mock.WithSlotCommitment(genesisCommitment), mock.WithStrongParents(ts.BlockIDs("block2.3")...)) + ts.IssueValidationBlockWithHeaderOptions("block2.5", node2, mock.WithSlotCommitment(genesisCommitment), mock.WithStrongParents(ts.BlockIDs("block2.4")...)) + ts.IssueValidationBlockWithHeaderOptions("block2.6", node1, mock.WithSlotCommitment(genesisCommitment), mock.WithStrongParents(ts.BlockIDs("block2.5")...)) ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ ts.Block("block2.3"): {"tx2"}, diff --git a/pkg/tests/combined_account_transition_test.go b/pkg/tests/combined_account_transition_test.go index 5717b6f37..b5d99192c 100644 --- a/pkg/tests/combined_account_transition_test.go +++ b/pkg/tests/combined_account_transition_test.go @@ -42,6 +42,8 @@ func Test_AccountStateTransition(t *testing.T) { ts.IssueValidationBlockWithHeaderOptions("vblock0", node2, mock.WithStrongParents(ts.BlockID("block0"))) ts.IssueValidationBlockWithHeaderOptions("vblock1", node1, mock.WithStrongParents(ts.BlockID("vblock0"))) ts.IssueValidationBlockWithHeaderOptions("vblock2", node2, mock.WithStrongParents(ts.BlockID("vblock1"))) + ts.IssueValidationBlockWithHeaderOptions("vblock3", node1, mock.WithStrongParents(ts.BlockID("vblock2"))) + ts.IssueValidationBlockWithHeaderOptions("vblock4", node2, mock.WithStrongParents(ts.BlockID("vblock3"))) ts.AssertTransactionsInCacheAccepted(wallet.Transactions("TX1"), true, node1, node2) } @@ -200,16 +202,18 @@ func sendFunds(ts *testsuite.TestSuite) { // send funds from defaultWallet to secondWallet tx := wallet.SendFundsToWallet("TX5", secondWallet, "TX1:2") - ts.IssueBasicBlockWithOptions("block4", wallet, tx) + ts.IssueBasicBlockWithOptions("block5", wallet, tx) ts.AssertTransactionsExist(wallet.Transactions("TX5"), true, node1) ts.AssertTransactionsInCacheBooked(wallet.Transactions("TX5"), true, node1) // Issue some more blocks to make transaction accepted { - ts.IssueValidationBlockWithHeaderOptions("vblock9", node2, mock.WithStrongParents(ts.BlockID("block4"))) - ts.IssueValidationBlockWithHeaderOptions("vblock10", node1, mock.WithStrongParents(ts.BlockID("vblock9"))) - ts.IssueValidationBlockWithHeaderOptions("vblock11", node2, mock.WithStrongParents(ts.BlockID("vblock10"))) + ts.IssueValidationBlockWithHeaderOptions("vblock12", node2, mock.WithStrongParents(ts.BlockID("block5"))) + ts.IssueValidationBlockWithHeaderOptions("vblock13", node1, mock.WithStrongParents(ts.BlockID("vblock12"))) + ts.IssueValidationBlockWithHeaderOptions("vblock14", node2, mock.WithStrongParents(ts.BlockID("vblock13"))) + ts.IssueValidationBlockWithHeaderOptions("vblock15", node1, mock.WithStrongParents(ts.BlockID("vblock14"))) + ts.IssueValidationBlockWithHeaderOptions("vblock16", node2, mock.WithStrongParents(ts.BlockID("vblock15"))) ts.AssertTransactionsInCacheAccepted(wallet.Transactions("TX5"), true, node1, node2) } @@ -226,13 +230,15 @@ func allotManaTo(ts *testsuite.TestSuite, to iotago.AccountID) { Mana: iotago.Mana(1000), }}, "TX1:3") commitment := node1.Protocol.Engines.Main.Get().Storage.Settings().LatestCommitment().Commitment() - ts.IssueBasicBlockWithOptions("block5", wallet, tx6, mock.WithSlotCommitment(commitment)) + ts.IssueBasicBlockWithOptions("block6", wallet, tx6, mock.WithSlotCommitment(commitment)) // Issue some more blocks to make transaction accepted { - ts.IssueValidationBlockWithHeaderOptions("vblock6", node2, mock.WithStrongParents(ts.BlockID("block5"))) - ts.IssueValidationBlockWithHeaderOptions("vblock7", node1, mock.WithStrongParents(ts.BlockID("vblock6"))) - ts.IssueValidationBlockWithHeaderOptions("vblock8", node2, mock.WithStrongParents(ts.BlockID("vblock7"))) + ts.IssueValidationBlockWithHeaderOptions("vblock7", node2, mock.WithStrongParents(ts.BlockID("block6"))) + ts.IssueValidationBlockWithHeaderOptions("vblock8", node1, mock.WithStrongParents(ts.BlockID("vblock7"))) + ts.IssueValidationBlockWithHeaderOptions("vblock9", node2, mock.WithStrongParents(ts.BlockID("vblock8"))) + ts.IssueValidationBlockWithHeaderOptions("vblock10", node1, mock.WithStrongParents(ts.BlockID("vblock9"))) + ts.IssueValidationBlockWithHeaderOptions("vblock11", node2, mock.WithStrongParents(ts.BlockID("vblock10"))) ts.AssertTransactionsInCacheAccepted(wallet.Transactions("TX6"), true, node1, node2) } @@ -245,16 +251,18 @@ func createNativetoken(ts *testsuite.TestSuite) { node2 := ts.Node("node2") tx := wallet.CreateNativeTokenFromInput("TX7", "TX5:0", "TX4:0", 5_000_000, 10_000_000_000) - ts.IssueBasicBlockWithOptions("block6", wallet, tx) + ts.IssueBasicBlockWithOptions("block17", wallet, tx) ts.AssertTransactionsExist(wallet.Transactions("TX7"), true, node1) ts.AssertTransactionsInCacheBooked(wallet.Transactions("TX7"), true, node1) // Issue some more blocks to make transaction accepted { - ts.IssueValidationBlockWithHeaderOptions("vblock12", node2, mock.WithStrongParents(ts.BlockID("block6"))) - ts.IssueValidationBlockWithHeaderOptions("vblock13", node1, mock.WithStrongParents(ts.BlockID("vblock12"))) - ts.IssueValidationBlockWithHeaderOptions("vblock14", node2, mock.WithStrongParents(ts.BlockID("vblock13"))) + ts.IssueValidationBlockWithHeaderOptions("vblock18", node2, mock.WithStrongParents(ts.BlockID("block17"))) + ts.IssueValidationBlockWithHeaderOptions("vblock19", node1, mock.WithStrongParents(ts.BlockID("vblock18"))) + ts.IssueValidationBlockWithHeaderOptions("vblock20", node2, mock.WithStrongParents(ts.BlockID("vblock19"))) + ts.IssueValidationBlockWithHeaderOptions("vblock21", node1, mock.WithStrongParents(ts.BlockID("vblock20"))) + ts.IssueValidationBlockWithHeaderOptions("vblock22", node2, mock.WithStrongParents(ts.BlockID("vblock21"))) ts.AssertTransactionsInCacheAccepted(wallet.Transactions("TX7"), true, node1, node2) } diff --git a/pkg/tests/loss_of_acceptance_test.go b/pkg/tests/loss_of_acceptance_test.go index d6515045b..aa91469f0 100644 --- a/pkg/tests/loss_of_acceptance_test.go +++ b/pkg/tests/loss_of_acceptance_test.go @@ -314,10 +314,9 @@ func TestLossOfAcceptanceWithoutRestart(t *testing.T) { node2 := ts.AddNode("node2") ts.Run(true, nil) - // Issue up to slot 10, committing slot 8. { - ts.IssueBlocksAtSlots("", []iotago.SlotIndex{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 3, "Genesis", ts.Nodes(), true, true) + ts.IssueBlocksAtSlots("", []iotago.SlotIndex{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 4, "Genesis", ts.Nodes(), true, true) ts.AssertBlocksInCacheAccepted(ts.BlocksWithPrefix("10.0"), true, ts.Nodes()...) ts.AssertEqualStoredCommitmentAtIndex(8, ts.Nodes()...) @@ -340,7 +339,7 @@ func TestLossOfAcceptanceWithoutRestart(t *testing.T) { // Need to issue to slot 22 so that all other nodes can warp sync up to slot 19 and then commit slot 20 themselves. { - ts.IssueBlocksAtSlots("", []iotago.SlotIndex{21, 22}, 2, "block0", mock.Nodes(node0), true, false) + ts.IssueBlocksAtSlots("", []iotago.SlotIndex{21, 22}, 4, "block0", mock.Nodes(node0), true, false) ts.AssertEqualStoredCommitmentAtIndex(20, ts.Nodes()...) ts.AssertLatestCommitmentSlotIndex(20, ts.Nodes()...) @@ -350,9 +349,9 @@ func TestLossOfAcceptanceWithoutRestart(t *testing.T) { { // Since already issued, but not accepted blocks in slot 9 and 10 are be orphaned, we need to make sure that // the already issued transactions in the testsuite are not used again. - ts.SetAutomaticTransactionIssuingCounters(node2.Partition, 28) + ts.SetAutomaticTransactionIssuingCounters(node2.Partition, 37) - ts.IssueBlocksAtSlots("", []iotago.SlotIndex{23, 24, 25}, 3, "22.1", ts.Nodes(), true, false) + ts.IssueBlocksAtSlots("", []iotago.SlotIndex{23, 24, 25}, 4, "22.3", ts.Nodes(), true, false) ts.AssertBlocksInCacheAccepted(ts.BlocksWithPrefix("25.0"), true, ts.Nodes()...) ts.AssertEqualStoredCommitmentAtIndex(23, ts.Nodes()...) @@ -366,7 +365,7 @@ func TestLossOfAcceptanceWithoutRestart(t *testing.T) { ts.AssertStorageCommitmentTransactions(9, expectedTransactions(ts.BlocksWithPrefix("9")), ts.Nodes()...) ts.AssertStorageCommitmentBlocks(10, map[iotago.CommitmentID]iotago.BlockIDs{ - lo.PanicOnErr(node1.Protocol.Engines.Main.Get().Storage.Commitments().Load(7)).ID(): ts.BlockIDsWithPrefix("10.0"), // only the first blocks row in slot 10 was accepted + lo.PanicOnErr(node1.Protocol.Engines.Main.Get().Storage.Commitments().Load(7)).ID(): append(ts.BlockIDsWithPrefix("10.0"), ts.BlockIDsWithPrefix("10.1")...), // only the first blocks row in slot 10 was accepted }, ts.Nodes()...) ts.AssertStorageCommitmentTransactions(10, expectedTransactions(ts.BlocksWithPrefix("10.0")), ts.Nodes()...) diff --git a/pkg/tests/mempool_invalid_signatures_test.go b/pkg/tests/mempool_invalid_signatures_test.go index f01d5117c..e372150c5 100644 --- a/pkg/tests/mempool_invalid_signatures_test.go +++ b/pkg/tests/mempool_invalid_signatures_test.go @@ -62,7 +62,7 @@ func Test_MempoolInvalidSignatures(t *testing.T) { require.NoError(t, err) // Accept block2 and block3. - ts.IssueBlocksAtSlots("accept-block3", []iotago.SlotIndex{block3.ID().Slot()}, 2, "block3", ts.Nodes(), false, true) + ts.IssueBlocksAtSlots("accept-block3", []iotago.SlotIndex{block3.ID().Slot()}, 4, "block3", ts.Nodes(), false, true) // Ensure that the valid attachment exists and got accepted, // while the invalid attachment did not override the previous valid attachment.