Skip to content

Commit

Permalink
Merge pull request #515 from iotaledger/feat/only-validator-blocks-ca…
Browse files Browse the repository at this point in the history
…rry-weight

Ignore basic blocks from validators when applying approval weight.
  • Loading branch information
piotrm50 authored Nov 14, 2023
2 parents 631e5bc + b204639 commit ea175ab
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
4 changes: 4 additions & 0 deletions pkg/protocol/engine/ledger/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,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())
Expand Down
91 changes: 91 additions & 0 deletions pkg/tests/booker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,97 @@ 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 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")))
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()
Expand Down

0 comments on commit ea175ab

Please sign in to comment.