Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions app/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,6 @@ func (dag *Dag) AddEdge(fromIndex DagNodeID, toIndex DagNodeID) *DagEdge {
// It will also register the new node with AccessOpsMap so that future nodes that amy be dependent on this one can properly identify the dependency.
func (dag *Dag) AddNodeBuildDependency(messageIndex int, txIndex int, accessOp acltypes.AccessOperation) {
dagNode := dag.AddNode(messageIndex, txIndex, accessOp)
// if in TxIndexMap, make an edge from the previous node index
if lastTxNodeID, ok := dag.TxIndexMap[txIndex]; ok {
// TODO: we actually don't necessarily need these edges, but keeping for now so we can first determine that cycles can't be missed if we remove these
// add an edge between access ops in a transaction
dag.AddEdge(lastTxNodeID, dagNode.NodeID)
}
// update tx index map
dag.TxIndexMap[txIndex] = dagNode.NodeID

Expand Down Expand Up @@ -205,6 +199,8 @@ func (dag *Dag) BuildCompletionSignalMaps() (
completionSignalingMap map[int]MessageCompletionSignalMapping,
blockingSignalsMap map[int]MessageCompletionSignalMapping,
) {
completionSignalingMap = make(map[int]MessageCompletionSignalMapping)
blockingSignalsMap = make(map[int]MessageCompletionSignalMapping)
// go through every node
for _, node := range dag.NodeMap {
// for each node, assign its completion signaling, and also assign blocking signals for the destination nodes
Expand All @@ -214,11 +210,23 @@ func (dag *Dag) BuildCompletionSignalMaps() (
if maybeCompletionSignal != nil {
completionSignal := *maybeCompletionSignal

// add it to the right blocking signal in the right txindex
toNode := dag.NodeMap[edge.ToNodeID]
if _, exists := blockingSignalsMap[toNode.TxIndex]; !exists {
blockingSignalsMap[toNode.TxIndex] = make(MessageCompletionSignalMapping)
}
if _, exists := blockingSignalsMap[toNode.TxIndex][toNode.MessageIndex]; !exists {
blockingSignalsMap[toNode.TxIndex][toNode.MessageIndex] = make(map[acltypes.AccessOperation][]CompletionSignal)
}
// add it to the right blocking signal in the right txindex
prevBlockSignalMapping := blockingSignalsMap[toNode.TxIndex][toNode.MessageIndex][completionSignal.BlockedAccessOperation]
blockingSignalsMap[toNode.TxIndex][toNode.MessageIndex][completionSignal.BlockedAccessOperation] = append(prevBlockSignalMapping, completionSignal)

if _, exists := completionSignalingMap[node.TxIndex]; !exists {
completionSignalingMap[node.TxIndex] = make(MessageCompletionSignalMapping)
}
if _, exists := completionSignalingMap[node.TxIndex][node.MessageIndex]; !exists {
completionSignalingMap[node.TxIndex][node.MessageIndex] = make(map[acltypes.AccessOperation][]CompletionSignal)
}
// add it to the completion signal for the tx index
prevCompletionSignalMapping := completionSignalingMap[node.TxIndex][node.MessageIndex][completionSignal.CompletionAccessOperation]
completionSignalingMap[node.TxIndex][node.MessageIndex][completionSignal.CompletionAccessOperation] = append(prevCompletionSignalMapping, completionSignal)
Expand All @@ -227,7 +235,7 @@ func (dag *Dag) BuildCompletionSignalMaps() (
}
}
}
return
return completionSignalingMap, blockingSignalsMap
}

var ErrCycleInDAG = fmt.Errorf("cycle detected in DAG")
107 changes: 74 additions & 33 deletions app/graph_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package app_test

import (
"sort"
"testing"

acltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol"
Expand Down Expand Up @@ -48,63 +49,103 @@ func TestCreateGraph(t *testing.T) {
IdentifierTemplate: "ResourceB",
}

dag.AddNodeBuildDependency(1, 1, writeAccessA) // node id 0
dag.AddNodeBuildDependency(1, 1, readAccessB) // node id 1
dag.AddNodeBuildDependency(1, 1, commitAccessOp) // node id 2
dag.AddNodeBuildDependency(1, 2, readAccessA) // node id 3
dag.AddNodeBuildDependency(1, 2, readAccessB) // node id 4
dag.AddNodeBuildDependency(1, 2, commitAccessOp) // node id 5
dag.AddNodeBuildDependency(1, 3, readAccessB) // node id 6
dag.AddNodeBuildDependency(1, 3, readAccessA) // node id 7
dag.AddNodeBuildDependency(1, 3, commitAccessOp) // node id 8
dag.AddNodeBuildDependency(1, 4, writeAccessB) // node id 9
dag.AddNodeBuildDependency(1, 4, commitAccessOp) // node id 10
dag.AddNodeBuildDependency(0, 0, writeAccessA) // node id 0
dag.AddNodeBuildDependency(0, 0, readAccessB) // node id 1
dag.AddNodeBuildDependency(0, 0, commitAccessOp) // node id 2
dag.AddNodeBuildDependency(0, 1, readAccessA) // node id 3
dag.AddNodeBuildDependency(0, 1, readAccessB) // node id 4
dag.AddNodeBuildDependency(0, 1, commitAccessOp) // node id 5
dag.AddNodeBuildDependency(0, 2, readAccessB) // node id 6
dag.AddNodeBuildDependency(0, 2, readAccessA) // node id 7
dag.AddNodeBuildDependency(0, 2, commitAccessOp) // node id 8
dag.AddNodeBuildDependency(0, 3, writeAccessB) // node id 9
dag.AddNodeBuildDependency(0, 3, commitAccessOp) // node id 10

require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[0])
require.Equal(
t,
[]app.DagEdge{{0, 1}},
dag.EdgesMap[0],
)
require.Equal(
t,
[]app.DagEdge{{1, 2}, {1, 9}},
[]app.DagEdge{{1, 9}},
dag.EdgesMap[1],
)
require.Equal(
t,
[]app.DagEdge{{2, 3}, {2, 7}},
dag.EdgesMap[2],
)
require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[3])
require.Equal(
t,
[]app.DagEdge{{3, 4}},
dag.EdgesMap[3],
)
require.Equal(
t,
[]app.DagEdge{{4, 5}, {4, 9}},
[]app.DagEdge{{4, 9}},
dag.EdgesMap[4],
)
require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[5])
require.Equal(
t,
[]app.DagEdge{{6, 7}, {6, 9}},
[]app.DagEdge{{6, 9}},
dag.EdgesMap[6],
)
require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[7])
require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[8])
require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[9])
require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[10])

// assert dag is acyclic
acyclic := graph.Acyclic(dag)
require.True(t, acyclic)

// test completion signals
completionSignalsMap, blockingSignalsMap := dag.BuildCompletionSignalMaps()

channel0 := completionSignalsMap[0][0][commitAccessOp][0].Channel
channel1 := completionSignalsMap[0][0][commitAccessOp][1].Channel
channel2 := completionSignalsMap[1][0][readAccessB][0].Channel
channel3 := completionSignalsMap[0][0][readAccessB][0].Channel
channel4 := completionSignalsMap[2][0][readAccessB][0].Channel

signal0 := app.CompletionSignal{2, 3, commitAccessOp, readAccessA, channel0}
signal1 := app.CompletionSignal{2, 7, commitAccessOp, readAccessA, channel1}
signal2 := app.CompletionSignal{4, 9, readAccessB, writeAccessB, channel2}
signal3 := app.CompletionSignal{1, 9, readAccessB, writeAccessB, channel3}
signal4 := app.CompletionSignal{6, 9, readAccessB, writeAccessB, channel4}

require.Equal(
t,
[]app.DagEdge{{7, 8}},
dag.EdgesMap[7],
[]app.CompletionSignal{signal0, signal1},
completionSignalsMap[0][0][commitAccessOp],
)
require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[8])
require.Equal(
t,
[]app.DagEdge{{9, 10}},
dag.EdgesMap[9],
[]app.CompletionSignal{signal0},
blockingSignalsMap[1][0][readAccessA],
)
require.Equal(
t,
[]app.CompletionSignal{signal1},
blockingSignalsMap[2][0][readAccessA],
)
require.Equal(t, []app.DagEdge(nil), dag.EdgesMap[10])

// assert dag is acyclic
acyclic := graph.Acyclic(dag)
require.True(t, acyclic)
require.Equal(
t,
[]app.CompletionSignal{signal2},
completionSignalsMap[1][0][readAccessB],
)
require.Equal(
t,
[]app.CompletionSignal{signal3},
completionSignalsMap[0][0][readAccessB],
)
require.Equal(
t,
[]app.CompletionSignal{signal4},
completionSignalsMap[2][0][readAccessB],
)
slice := blockingSignalsMap[3][0][writeAccessB]
sort.SliceStable(slice, func(p, q int) bool {
return slice[p].FromNodeID < slice[q].FromNodeID
})
require.Equal(
t,
[]app.CompletionSignal{signal3, signal2, signal4},
slice,
)
}