Skip to content

Commit

Permalink
Feat: more cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
hmoog committed Mar 5, 2023
1 parent 7a3a86d commit 59d641b
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 30 deletions.
47 changes: 39 additions & 8 deletions packages/protocol/engine/clock/anchoredtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (
"github.com/iotaledger/hive.go/runtime/event"
)

// AnchoredTime is a time value that is anchored to a specific point in time but that advances with the real-time.
// AnchoredTime is a time value that advances with the system clock but that is anchored to a specific point in time.
type AnchoredTime struct {
OnUpdate *event.Event1[time.Time]
OnAnchorUpdated *event.Event1[time.Time]

anchor time.Time
updateTime time.Time
Expand All @@ -18,7 +18,7 @@ type AnchoredTime struct {

func NewAnchoredTime() *AnchoredTime {
return &AnchoredTime{
OnUpdate: event.New1[time.Time](),
OnAnchorUpdated: event.New1[time.Time](),
}
}

Expand All @@ -40,12 +40,43 @@ func (c *AnchoredTime) Set(newTime time.Time) (updated bool) {
c.mutex.Lock()
defer c.mutex.Unlock()

if updated = newTime.Unix() > c.anchor.Unix(); updated {
c.anchor = newTime
c.updateTime = time.Now()
if newTime.Before(c.anchor) {
return false
}

c.updateTime = time.Now()
c.anchor = newTime

c.OnAnchorUpdated.Trigger(c.anchor)

return true
}

// Advance advances the time monotonically if the given time is after the current time.
func (c *AnchoredTime) Advance(newTime time.Time) (updated bool) {
c.mutex.Lock()
defer c.mutex.Unlock()

if newTime.Before(c.anchor) {
return false
}

c.updateTime = c.advancedUpdateTime(newTime)
c.anchor = newTime

c.OnAnchorUpdated.Trigger(c.anchor)

return true
}

// advancedUpdateTime determines the new update time that is in sync with the monotonic clock.
func (c *AnchoredTime) advancedUpdateTime(newTime time.Time) time.Time {
diff := time.Since(c.updateTime)

c.OnUpdate.Trigger(c.anchor)
// if the new time lags behind the monotonic time, we adjust the time to prevent the clock from going backwards.
if lag := newTime.Sub(c.anchor.Add(diff)); lag < 0 {
diff += lag
}

return
return c.updateTime.Add(diff)
}
10 changes: 5 additions & 5 deletions packages/protocol/engine/clock/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (

// Events is a collection of events that can be triggered by the Clock.
type Events struct {
// AcceptanceTimeUpdated is an Event for callbacks of the type func(newTime, now time.Time).
// AcceptanceTimeUpdated is triggered when the Acceptance Tangle Time advances.
AcceptanceTimeUpdated *event.Event1[time.Time]

// AcceptanceTimeUpdated is triggered when a Acceptance Tangle Time advances.
ConfirmedTimeUpdated *event.Event1[time.Time]
// ConfirmationTimeUpdated is triggered when the Confirmation Tangle Time advances.
ConfirmationTimeUpdated *event.Event1[time.Time]

// LinkableCollection is a generic trait that allows to link multiple collections of events together.
event.Group[Events, *Events]
Expand All @@ -21,7 +21,7 @@ type Events struct {
// NewEvents contains the constructor of the Events object (it is generated by a generic factory).
var NewEvents = event.CreateGroupConstructor(func() (newEvents *Events) {
return &Events{
ConfirmedTimeUpdated: event.New1[time.Time](),
AcceptanceTimeUpdated: event.New1[time.Time](),
ConfirmationTimeUpdated: event.New1[time.Time](),
AcceptanceTimeUpdated: event.New1[time.Time](),
}
})
53 changes: 41 additions & 12 deletions packages/protocol/engine/clock/module/clock.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package module

import (
"time"

"github.com/iotaledger/goshimmer/packages/core/module"
"github.com/iotaledger/goshimmer/packages/protocol/engine"
"github.com/iotaledger/goshimmer/packages/protocol/engine/clock"
"github.com/iotaledger/goshimmer/packages/protocol/engine/consensus/blockgadget"
"github.com/iotaledger/hive.go/core/slot"
"github.com/iotaledger/hive.go/lo"
"github.com/iotaledger/hive.go/runtime/event"
"github.com/iotaledger/hive.go/runtime/options"
)

// Clock is a component that provides different notions of time for the Engine.
type Clock struct {
// engine contains a reference to the Engine.
engine *engine.Engine

// acceptanceTime is a notion of time that is anchored to the latest accepted block.
acceptanceTime *clock.AnchoredTime

Expand All @@ -26,25 +32,18 @@ type Clock struct {
func Provide(opts ...options.Option[Clock]) module.Provider[*engine.Engine, clock.Clock] {
return module.Provide(func(e *engine.Engine) clock.Clock {
return options.Apply(&Clock{
engine: e,
acceptanceTime: clock.NewAnchoredTime(),
confirmationTime: clock.NewAnchoredTime(),
}, opts, func(c *Clock) {
e.HookConstructed(func() {
e.Events.Clock.AcceptanceTimeUpdated.LinkTo(c.acceptanceTime.OnUpdate)
e.Events.Clock.ConfirmedTimeUpdated.LinkTo(c.confirmationTime.OnUpdate)
c.setupEvents(event.WithWorkerPool(e.Workers.CreatePool("Clock", 1)))

e.LedgerState.HookInitialized(func() {
c.acceptanceTime.Set(e.SlotTimeProvider.EndTime(e.Storage.Settings.LatestCommitment().Index()))
c.confirmationTime.Set(e.SlotTimeProvider.EndTime(e.Storage.Settings.LatestCommitment().Index()))
c.setInitialTime(e.SlotTimeProvider.EndTime(e.Storage.Settings.LatestCommitment().Index()))

c.TriggerInitialized()
})

async := event.WithWorkerPool(e.Workers.CreatePool("ClockPlugin", 1))

c.HookStopped(e.Events.Consensus.BlockGadget.BlockAccepted.Hook(func(block *blockgadget.Block) { c.acceptanceTime.Set(block.IssuingTime()) }, async).Unhook)
c.HookStopped(e.Events.Consensus.BlockGadget.BlockConfirmed.Hook(func(block *blockgadget.Block) { c.confirmationTime.Set(block.IssuingTime()) }, async).Unhook)
c.HookStopped(e.Events.Consensus.SlotGadget.SlotConfirmed.Hook(func(index slot.Index) { c.confirmationTime.Set(e.SlotTimeProvider.EndTime(index)) }, async).Unhook)
})

e.HookStopped(c.TriggerStopped)
Expand All @@ -62,5 +61,35 @@ func (c *Clock) ConfirmationTime() *clock.AnchoredTime {
return c.confirmationTime
}

// code contract (make sure the type implements all required methods).
var _ clock.Clock = &Clock{}
// setInitialTime initializes the time values of the Clock.
func (c *Clock) setInitialTime(now time.Time) {
c.acceptanceTime.Set(now)
c.confirmationTime.Set(now)
}

// setupEvents connects the Clock to the Engine events.
func (c *Clock) setupEvents(workerPool event.Option) {
c.engine.Events.Clock.AcceptanceTimeUpdated.LinkTo(c.acceptanceTime.OnAnchorUpdated)
c.engine.Events.Clock.ConfirmationTimeUpdated.LinkTo(c.confirmationTime.OnAnchorUpdated)

c.HookStopped(lo.Batch(
c.engine.Events.Consensus.BlockGadget.BlockAccepted.Hook(c.onBlockAccepted, workerPool).Unhook,
c.engine.Events.Consensus.BlockGadget.BlockConfirmed.Hook(c.onBlockConfirmed, workerPool).Unhook,
c.engine.Events.Consensus.SlotGadget.SlotConfirmed.Hook(c.onSlotConfirmed, workerPool).Unhook,
))
}

// onBlockAccepted is called when a block is accepted.
func (c *Clock) onBlockAccepted(block *blockgadget.Block) {
c.acceptanceTime.Advance(block.IssuingTime())
}

// onBlockConfirmed is called when a block is confirmed.
func (c *Clock) onBlockConfirmed(block *blockgadget.Block) {
c.confirmationTime.Advance(block.IssuingTime())
}

// onSlotConfirmed is called when a slot is confirmed.
func (c *Clock) onSlotConfirmed(index slot.Index) {
c.confirmationTime.Advance(c.engine.SlotTimeProvider.EndTime(index))
}
4 changes: 1 addition & 3 deletions packages/protocol/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,7 @@ func (e *Engine) initNotarizationManager() {
}, event.WithWorkerPool(wpBlocks))

// Slots are committed whenever ATT advances, start committing only when bootstrapped.
e.Events.Clock.AcceptanceTimeUpdated.Hook(func(newTime time.Time) {
e.NotarizationManager.SetAcceptanceTime(newTime)
}, event.WithWorkerPool(wpCommitments))
e.Events.Clock.AcceptanceTimeUpdated.Hook(e.NotarizationManager.SetAcceptanceTime, event.WithWorkerPool(wpCommitments))
}

func (e *Engine) initEvictionState() {
Expand Down
4 changes: 2 additions & 2 deletions packages/protocol/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/iotaledger/goshimmer/packages/protocol/congestioncontrol/icca/scheduler"
"github.com/iotaledger/goshimmer/packages/protocol/engine"
"github.com/iotaledger/goshimmer/packages/protocol/engine/clock"
"github.com/iotaledger/goshimmer/packages/protocol/engine/clock/module"
clockModule "github.com/iotaledger/goshimmer/packages/protocol/engine/clock/module"
"github.com/iotaledger/goshimmer/packages/protocol/engine/consensus/blockgadget"
"github.com/iotaledger/goshimmer/packages/protocol/engine/notarization"
"github.com/iotaledger/goshimmer/packages/protocol/engine/sybilprotection"
Expand Down Expand Up @@ -78,7 +78,7 @@ func New(workers *workerpool.Group, dispatcher network.Endpoint, opts ...options
Events: NewEvents(),
Workers: workers,
dispatcher: dispatcher,
optsClockProvider: module.Provide(),
optsClockProvider: clockModule.Provide(),
optsSybilProtectionProvider: dpos.NewProvider(),
optsThroughputQuotaProvider: mana1.NewProvider(),

Expand Down

0 comments on commit 59d641b

Please sign in to comment.