From be304989943d30fbcb0ba46e13c54949745621a4 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:04:37 +0100 Subject: [PATCH 1/3] Ignore basic blocks from validators when applying approval weight. --- pkg/protocol/engine/ledger/ledger/ledger.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/protocol/engine/ledger/ledger/ledger.go b/pkg/protocol/engine/ledger/ledger/ledger.go index 0b9207f36..d1dc83685 100644 --- a/pkg/protocol/engine/ledger/ledger/ledger.go +++ b/pkg/protocol/engine/ledger/ledger/ledger.go @@ -749,6 +749,10 @@ func (l *Ledger) resolveState(stateRef mempool.StateReference) *promise.Promise[ } func (l *Ledger) blockPreAccepted(block *blocks.Block) { + if _, isValidationBlock := block.ValidationBlock(); !isValidationBlock { + return + } + voteRank := ledger.NewBlockVoteRank(block.ID(), block.ProtocolBlock().Header.IssuingTime) committee, exists := l.sybilProtection.SeatManager().CommitteeInSlot(block.ID().Slot()) From 813b33e45cc91ad985c0902d6125194d90e14ff6 Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Tue, 14 Nov 2023 15:09:19 +0100 Subject: [PATCH 2/3] Implement test to make sure that basic blocks don't carry any weight. --- pkg/tests/booker_test.go | 89 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/pkg/tests/booker_test.go b/pkg/tests/booker_test.go index 9608d8f57..04685668b 100644 --- a/pkg/tests/booker_test.go +++ b/pkg/tests/booker_test.go @@ -48,6 +48,95 @@ func Test_IssuingTransactionsOutOfOrder(t *testing.T) { }, node1) } +func Test_WeightPropagation(t *testing.T) { + ts := testsuite.NewTestSuite(t) + defer ts.Shutdown() + + node1 := ts.AddValidatorNode("node1") + node2 := ts.AddValidatorNode("node2") + + wallet := ts.AddGenesisWallet("default", node1) + + ts.Run(true, map[string][]options.Option[protocol.Protocol]{}) + + ts.AssertSybilProtectionCommittee(0, []iotago.AccountID{ + node1.Validator.AccountID, + node2.Validator.AccountID, + }, ts.Nodes()...) + + // Create and issue double spends + { + tx1 := wallet.CreateBasicOutputsEquallyFromInputs("tx1", 1, "Genesis:0") + tx2 := wallet.CreateBasicOutputsEquallyFromInputs("tx2", 1, "Genesis:0") + + ts.IssuePayloadWithOptions("block1", wallet, tx1, mock.WithStrongParents(ts.BlockID("Genesis"))) + ts.IssuePayloadWithOptions("block2", wallet, tx2, mock.WithStrongParents(ts.BlockID("Genesis"))) + + ts.AssertTransactionsExist(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCacheBooked(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ + ts.Block("block1"): {"tx1"}, + ts.Block("block2"): {"tx2"}, + }, node1, node2) + + ts.AssertTransactionInCacheConflicts(map[*iotago.Transaction][]string{ + wallet.Transaction("tx2"): {"tx2"}, + wallet.Transaction("tx1"): {"tx1"}, + }, node1, node2) + } + + // Issue some more blocks and assert that conflicts are propagated to blocks. + { + + ts.IssuePayloadWithOptions("block3-basic", ts.Wallet("node1"), &iotago.TaggedData{}, mock.WithStrongParents(ts.BlockID("block1"))) + ts.IssuePayloadWithOptions("block4-basic", ts.Wallet("node2"), &iotago.TaggedData{}, mock.WithStrongParents(ts.BlockID("block2"))) + + ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ + ts.Block("block3-basic"): {"tx1"}, + ts.Block("block4-basic"): {"tx2"}, + }, node1, node2) + ts.AssertConflictsInCacheAcceptanceState([]string{"tx1", "tx2"}, acceptance.Pending, ts.Nodes()...) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) + } + + // Issue valid blocks that should resolve the conflict, but basic blocks don't carry any weight.. + { + ts.IssuePayloadWithOptions("block5-basic", ts.Wallet("node1"), &iotago.TaggedData{}, mock.WithStrongParents(ts.BlockIDs("block4-basic")...), mock.WithShallowLikeParents(ts.BlockID("block2"))) + ts.IssuePayloadWithOptions("block6-basic", ts.Wallet("node2"), &iotago.TaggedData{}, mock.WithStrongParents(ts.BlockIDs("block5-basic")...)) + + ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ + ts.Block("block6-basic"): {"tx2"}, + }, ts.Nodes()...) + + // Make sure that neither approval (conflict weight), + // nor witness (block weight) was not propagated using basic blocks and caused acceptance. + ts.AssertConflictsInCacheAcceptanceState([]string{"tx1", "tx2"}, acceptance.Pending, ts.Nodes()...) + ts.AssertTransactionsInCacheAccepted(wallet.Transactions("tx2"), false, node1, node2) + ts.AssertTransactionsInCacheRejected(wallet.Transactions("tx1"), false, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) + ts.AssertBlocksInCacheAccepted(ts.Blocks("block3-basic", "block4-basic", "block5-basic", "block6-basic"), false, ts.Nodes()...) + ts.AssertBlocksInCachePreAccepted(ts.Blocks("block3-basic", "block4-basic", "block5-basic", "block6-basic"), false, ts.Nodes()...) + } + + // Issue validator blocks that are subjectively invalid, but accept the basic blocks. Make sure that the pre-accepted basic blocks do not apply witness weight. + { + ts.IssueValidationBlock("block8", node1, mock.WithStrongParents(ts.BlockIDs("block3-basic", "block6-basic")...)) + ts.IssueValidationBlock("block9", node2, mock.WithStrongParents(ts.BlockID("block8"))) + ts.IssueValidationBlock("block10", node1, mock.WithStrongParents(ts.BlockID("block9"))) + + ts.AssertBlocksInCacheConflicts(map[*blocks.Block][]string{ + ts.Block("block8"): {"tx1", "tx2"}, + ts.Block("block9"): {"tx1", "tx2"}, + ts.Block("block10"): {"tx1", "tx2"}, + }, node1, node2) + + ts.AssertBlocksInCachePreAccepted(ts.Blocks("block3-basic", "block4-basic", "block5-basic", "block6-basic"), true, node1, node2) + ts.AssertBlocksInCacheAccepted(ts.Blocks("block3-basic", "block4-basic", "block5-basic", "block6-basic"), true, node1, node2) + ts.AssertTransactionsInCachePending(wallet.Transactions("tx1", "tx2"), true, node1, node2) + } +} + func Test_DoubleSpend(t *testing.T) { ts := testsuite.NewTestSuite(t) defer ts.Shutdown() From b204639bb343d8dd0cfbc79ceed722935857664d Mon Sep 17 00:00:00 2001 From: Piotr Macek <4007944+piotrm50@users.noreply.github.com> Date: Tue, 14 Nov 2023 15:11:50 +0100 Subject: [PATCH 3/3] Improve comment --- pkg/tests/booker_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/tests/booker_test.go b/pkg/tests/booker_test.go index 04685668b..b1b35d572 100644 --- a/pkg/tests/booker_test.go +++ b/pkg/tests/booker_test.go @@ -119,7 +119,9 @@ func Test_WeightPropagation(t *testing.T) { ts.AssertBlocksInCachePreAccepted(ts.Blocks("block3-basic", "block4-basic", "block5-basic", "block6-basic"), false, ts.Nodes()...) } - // Issue validator blocks that are subjectively invalid, but accept the basic blocks. Make sure that the pre-accepted basic blocks do not apply witness weight. + // Issue validator blocks that are subjectively invalid, but accept the basic blocks. + // Make sure that the pre-accepted basic blocks do not apply approval weight - the conflicts should remain unresolved. + // If basic blocks carry approval or witness weight, then the test will fail. { ts.IssueValidationBlock("block8", node1, mock.WithStrongParents(ts.BlockIDs("block3-basic", "block6-basic")...)) ts.IssueValidationBlock("block9", node2, mock.WithStrongParents(ts.BlockID("block8")))