diff --git a/packages/refactored/old/ledgerstate_test_SetBranchConfirmed.png b/packages/refactored/ledger/img/ledgerstate_test_SetBranchConfirmed.png similarity index 100% rename from packages/refactored/old/ledgerstate_test_SetBranchConfirmed.png rename to packages/refactored/ledger/img/ledgerstate_test_SetBranchConfirmed.png diff --git a/packages/refactored/ledger/ledger_test.go b/packages/refactored/ledger/ledger_test.go index d85c962b98..9964ddb1a9 100644 --- a/packages/refactored/ledger/ledger_test.go +++ b/packages/refactored/ledger/ledger_test.go @@ -4,6 +4,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/iotaledger/goshimmer/packages/refactored/branchdag" ) func TestLedger(t *testing.T) { @@ -118,3 +121,257 @@ func TestLedger(t *testing.T) { }) } } + +// See scenario at img/ledgerstate_test_SetBranchConfirmed.png +func TestLedger_SetBranchConfirmed(t *testing.T) { + testFramework := NewTestFramework() + + // Step 1: Bottom Layer + testFramework.CreateTransaction("G", 3, "Genesis") + testFramework.CreateTransaction("TXA", 1, "G.0") + testFramework.CreateTransaction("TXB", 1, "G.0") + testFramework.CreateTransaction("TXC", 1, "G.1") + testFramework.CreateTransaction("TXD", 1, "G.1") + testFramework.CreateTransaction("TXH", 1, "G.2") + testFramework.CreateTransaction("TXI", 1, "G.2") + // Step 2: Middle Layer + testFramework.CreateTransaction("TXE", 1, "TXA.0", "TXC.0") + // Step 3: Top Layer + testFramework.CreateTransaction("TXF", 1, "TXE.0") + // Step 4: Top Layer + testFramework.CreateTransaction("TXG", 1, "TXE.0") + // Step 5: TopTop Layer + testFramework.CreateTransaction("TXL", 1, "TXG.0", "TXH.0") + // Step 6: TopTopTOP Layer + testFramework.CreateTransaction("TXM", 1, "TXL.0") + + // Mark A as Confirmed + { + for _, txAlias := range []string{"G", "TXA", "TXB", "TXC", "TXD", "TXH", "TXI"} { + assert.NoError(t, testFramework.IssueTransaction(txAlias)) + } + require.True(t, testFramework.Ledger.BranchDAG.SetBranchConfirmed(testFramework.Transaction("TXA").ID())) + + testFramework.AssertBranchIDs(t, map[string][]string{ + "G": {"MasterBranch"}, + "TXA": {"TXA"}, + "TXB": {"TXB"}, + "TXC": {"TXC"}, + "TXD": {"TXD"}, + "TXH": {"TXH"}, + "TXI": {"TXI"}, + }) + + testFramework.AssertBranchDAG(t, map[string][]string{ + "TXA": {"MasterBranch"}, + "TXB": {"MasterBranch"}, + "TXC": {"MasterBranch"}, + "TXD": {"MasterBranch"}, + "TXH": {"MasterBranch"}, + "TXI": {"MasterBranch"}, + }) + + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXA"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXB"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXC"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXD"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXH"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXI"))) + } + + // When creating the middle layer the new transaction E should be booked only under its Pending parent C + { + assert.NoError(t, testFramework.IssueTransaction("TXE")) + + testFramework.AssertBranchIDs(t, map[string][]string{ + "G": {"MasterBranch"}, + "TXA": {"TXA"}, + "TXB": {"TXB"}, + "TXC": {"TXC"}, + "TXD": {"TXD"}, + "TXH": {"TXH"}, + "TXI": {"TXI"}, + "TXE": {"TXC"}, + }) + + testFramework.AssertBranchDAG(t, map[string][]string{ + "TXA": {"MasterBranch"}, + "TXB": {"MasterBranch"}, + "TXC": {"MasterBranch"}, + "TXD": {"MasterBranch"}, + "TXH": {"MasterBranch"}, + "TXI": {"MasterBranch"}, + }) + + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXA"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXB"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXC"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXD"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXH"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXI"))) + } + + // When creating the first transaction (F) of top layer it should be booked under the Pending parent C + { + for _, txAlias := range []string{"TXF"} { + assert.NoError(t, testFramework.IssueTransaction(txAlias)) + } + + testFramework.AssertBranchIDs(t, map[string][]string{ + "G": {"MasterBranch"}, + "TXA": {"TXA"}, + "TXB": {"TXB"}, + "TXC": {"TXC"}, + "TXD": {"TXD"}, + "TXH": {"TXH"}, + "TXI": {"TXI"}, + // Branches F & G are spawned by the fork of G + "TXF": {"TXC"}, + }) + + testFramework.AssertBranchDAG(t, map[string][]string{ + "TXA": {"MasterBranch"}, + "TXB": {"MasterBranch"}, + "TXC": {"MasterBranch"}, + "TXD": {"MasterBranch"}, + "TXH": {"MasterBranch"}, + "TXI": {"MasterBranch"}, + }) + + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXA"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXB"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXC"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXD"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXH"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXI"))) + } + + // When creating the conflicting TX (G) of the top layer branches F & G are spawned by the fork of G + { + for _, txAlias := range []string{"TXG"} { + assert.NoError(t, testFramework.IssueTransaction(txAlias)) + } + + testFramework.AssertBranchIDs(t, map[string][]string{ + "G": {"MasterBranch"}, + "TXA": {"TXA"}, + "TXB": {"TXB"}, + "TXC": {"TXC"}, + "TXD": {"TXD"}, + "TXH": {"TXH"}, + "TXI": {"TXI"}, + // Branches F & G are spawned by the fork of G + "TXF": {"TXF"}, + "TXG": {"TXG"}, + }) + + testFramework.AssertBranchDAG(t, map[string][]string{ + "TXA": {"MasterBranch"}, + "TXB": {"MasterBranch"}, + "TXC": {"MasterBranch"}, + "TXD": {"MasterBranch"}, + "TXH": {"MasterBranch"}, + "TXI": {"MasterBranch"}, + "TXF": {"TXC"}, + "TXG": {"TXC"}, + }) + + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXA"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXB"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXC"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXD"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXH"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXI"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXF"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXG"))) + } + + require.True(t, testFramework.Ledger.BranchDAG.SetBranchConfirmed(testFramework.Transaction("TXD").ID())) + + // TX L combines a child (G) of a Rejected branch (C) and a pending branch H, resulting in (G,H) + { + for _, txAlias := range []string{"TXL"} { + assert.NoError(t, testFramework.IssueTransaction(txAlias)) + } + + testFramework.AssertBranchIDs(t, map[string][]string{ + "G": {"MasterBranch"}, + "TXA": {"TXA"}, + "TXB": {"TXB"}, + "TXC": {"TXC"}, + "TXD": {"TXD"}, + "TXH": {"TXH"}, + "TXI": {"TXI"}, + // Branches F & G are spawned by the fork of G + "TXF": {"TXF"}, + "TXG": {"TXG"}, + "TXL": {"TXG", "TXH"}, + }) + + testFramework.AssertBranchDAG(t, map[string][]string{ + "TXA": {"MasterBranch"}, + "TXB": {"MasterBranch"}, + "TXC": {"MasterBranch"}, + "TXD": {"MasterBranch"}, + "TXH": {"MasterBranch"}, + "TXI": {"MasterBranch"}, + "TXF": {"TXC"}, + "TXG": {"TXC"}, + }) + + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXA"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXB"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXC"))) + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXD"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXH"))) + assert.Equal(t, branchdag.Pending, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXI"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXF"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXG"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXG", "TXH"))) + } + + require.True(t, testFramework.Ledger.BranchDAG.SetBranchConfirmed(testFramework.Transaction("TXH").ID())) + + // The new TX M should be now booked under G, as branch H confirmed, just G because we don't propagate H further. + { + for _, txAlias := range []string{"TXM"} { + assert.NoError(t, testFramework.IssueTransaction(txAlias)) + } + + testFramework.AssertBranchIDs(t, map[string][]string{ + "G": {"MasterBranch"}, + "TXA": {"TXA"}, + "TXB": {"TXB"}, + "TXC": {"TXC"}, + "TXD": {"TXD"}, + "TXH": {"TXH"}, + "TXI": {"TXI"}, + // Branches F & G are spawned by the fork of G + "TXF": {"TXF"}, + "TXG": {"TXG"}, + "TXL": {"TXG", "TXH"}, + "TXM": {"TXG"}, + }) + + testFramework.AssertBranchDAG(t, map[string][]string{ + "TXA": {"MasterBranch"}, + "TXB": {"MasterBranch"}, + "TXC": {"MasterBranch"}, + "TXD": {"MasterBranch"}, + "TXH": {"MasterBranch"}, + "TXI": {"MasterBranch"}, + "TXF": {"TXC"}, + "TXG": {"TXC"}, + }) + + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXA"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXB"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXC"))) + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXD"))) + assert.Equal(t, branchdag.Confirmed, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXH"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXI"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXF"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXG"))) + assert.Equal(t, branchdag.Rejected, testFramework.Ledger.BranchDAG.InclusionState(testFramework.TransactionIDs("TXG", "TXH"))) + } +}