diff --git a/packages/ca/constants.go b/packages/ca/constants.go index d995e27dfd9c2db0851c9cbfa15eb070c12d8a2d..2b31816a61193fb2b4d63799ea4350d228d72aa0 100644 --- a/packages/ca/constants.go +++ b/packages/ca/constants.go @@ -1,6 +1,8 @@ package ca const ( - MAX_STATEMENT_TIMEOUT = uint64(5000) - MAX_NEIGHBOR_COUNT = 8 + MAX_STATEMENT_TIMEOUT = uint64(5000) + MAX_NEIGHBOR_COUNT = 8 + MAX_PENDING_HEARTBEATS = 10 + MAX_MISSING_HEARTBEATS = 10 ) diff --git a/packages/ca/errors.go b/packages/ca/errors.go index 2fbec995bde3bf9e63639a6ad28a7029b9b30d55..86fa236cf80ecaa26c5280f280441b9fd4f795c0 100644 --- a/packages/ca/errors.go +++ b/packages/ca/errors.go @@ -5,6 +5,7 @@ import ( ) var ( + ErrInternalError = errors.New("internal error") ErrMalformedHeartbeat = errors.New("malformed heartbeat") ErrUnknownNeighbor = errors.New("unknown neighbor") ErrTooManyNeighbors = errors.New("too many neighbors") diff --git a/packages/ca/neighbor_manager.go b/packages/ca/neighbor_manager.go index 900a905dc267f59d9b8f3098a7f78bc8ff1cfe2e..d5b77118f866000b2e5f7988e9d89b4cd6822152 100644 --- a/packages/ca/neighbor_manager.go +++ b/packages/ca/neighbor_manager.go @@ -5,6 +5,8 @@ import ( "sort" "strconv" + "github.com/iotaledger/goshimmer/packages/typeutils" + "github.com/iotaledger/goshimmer/packages/events" "github.com/iotaledger/goshimmer/packages/ca/heartbeat" @@ -15,7 +17,7 @@ import ( type NeighborManager struct { Events NeighborManagerEvents options *NeighborManagerOptions - lastAppliedHeartbeat *heartbeat.Heartbeat + lastReceivedHeartbeat *heartbeat.Heartbeat missingHeartbeats map[string]bool pendingHeartbeats map[string]*heartbeat.Heartbeat heartbeats map[string]*heartbeat.Heartbeat @@ -41,7 +43,7 @@ func (neighborManager *NeighborManager) Reset() { neighborManager.neighborChains = make(map[string]*StatementChain) } -func (neighborManager *NeighborManager) ApplyHeartbeat(heartbeat *heartbeat.Heartbeat) (err errors.IdentifiableError) { +func (neighborManager *NeighborManager) storeHeartbeat(heartbeat *heartbeat.Heartbeat) (err errors.IdentifiableError) { // region check if heartbeat is "syntactically correct" //////////////////////////////////////////////////////////// mainStatement := heartbeat.GetMainStatement() @@ -61,12 +63,48 @@ func (neighborManager *NeighborManager) ApplyHeartbeat(heartbeat *heartbeat.Hear previousHeartbeatHash := mainStatement.GetPreviousStatementHash() if len(previousHeartbeatHash) == 0 { neighborManager.Reset() - } else if neighborManager.lastAppliedHeartbeat != nil && !bytes.Equal(neighborManager.lastAppliedHeartbeat.GetMainStatement().GetHash(), previousHeartbeatHash) { + } else if neighborManager.lastReceivedHeartbeat != nil { + lastMainStatement := neighborManager.lastReceivedHeartbeat.GetMainStatement() + previousHeartbeatHashString := typeutils.BytesToString(previousHeartbeatHash) + if lastMainStatement != nil && !bytes.Equal(lastMainStatement.GetHash(), previousHeartbeatHash) { + if len(neighborManager.pendingHeartbeats) >= MAX_PENDING_HEARTBEATS || len(neighborManager.missingHeartbeats) >= MAX_MISSING_HEARTBEATS { + neighborManager.Reset() + } else if _, exists := neighborManager.heartbeats[previousHeartbeatHashString]; !exists { + neighborManager.missingHeartbeats[previousHeartbeatHashString] = true + } + } + } + heartbeatHash := typeutils.BytesToString(mainStatement.GetHash()) + + if neighborManager.lastReceivedHeartbeat == nil || mainStatement.GetTime() > neighborManager.lastReceivedHeartbeat.GetMainStatement().GetTime() { + neighborManager.lastReceivedHeartbeat = heartbeat } + neighborManager.heartbeats[heartbeatHash] = heartbeat + neighborManager.pendingHeartbeats[heartbeatHash] = heartbeat + delete(neighborManager.missingHeartbeats, heartbeatHash) + // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////// + return +} + +func (neighborManager *NeighborManager) applyPendingHeartbeats() (err errors.IdentifiableError) { + if len(neighborManager.missingHeartbeats) == 0 && len(neighborManager.pendingHeartbeats) >= 1 { + // cycle through heartbeats and apply them one by one + } + + return +} + +func (neighborManager *NeighborManager) ApplyHeartbeat(heartbeat *heartbeat.Heartbeat) (err errors.IdentifiableError) { + if storeErr := neighborManager.storeHeartbeat(heartbeat); storeErr != nil { + err = storeErr + + return + } + // region mark idle neighbors ////////////////////////////////////////////////////////////////////////////////////// existingNeighbors := make(map[string]*StatementChain)