Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cadence 1.0] Add ProtocolStateVersionUpgrade service event #419

74 changes: 70 additions & 4 deletions contracts/NodeVersionBeacon.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
/// The contract itself can be used to query the current version and the next upcoming version.
access(all) contract NodeVersionBeacon {

/// =========================
/// Execution State Versioning
/// =========================

/// Struct representing software version as Semantic Version
/// along with helper functions
/// For reference, see https://semver.org/
Expand Down Expand Up @@ -134,10 +138,11 @@ access(all) contract NodeVersionBeacon {
)
}

/// Event emitted when the version table is updated.
/// It contains the current version and all the upcoming versions
/// sorted by block height.
/// The sequence increases by one each time an event is emitted.
/// A service event emitted when the version table is updated.
/// The version is the software version which must be used for executing a height range of blocks.
/// The version pertains to Execution and Verification Nodes.
/// The table contains the current version and all the upcoming versions sorted by block height.
/// The sequence increases by one each time an event is emitted.
/// It can be used to verify no events were missed.
access(all) event VersionBeacon(
versionBoundaries: [VersionBoundary],
Expand Down Expand Up @@ -280,6 +285,13 @@ access(all) contract NodeVersionBeacon {

emit NodeVersionBoundaryFreezePeriodChanged(freezePeriod: newFreezePeriod)
}

/// Adds a pending protocol state version upgrade, which will be emitted
/// as a service event during the next heartbeat.
access(all) fun setPendingProtocolStateVersionUpgrade(newProtocolVersion: UInt64, activeView: UInt64) {
let pendingUpgrade = NodeVersionBeacon.ViewActivatedVersion(version: newProtocolVersion, activeView: activeView)
NodeVersionBeacon.storePendingProtocolStateVersionUpgrade(upgrade: pendingUpgrade)
}
}

/// Heartbeat resource that emits the version beacon event and keeps track of upcoming versions.
Expand All @@ -291,6 +303,8 @@ access(all) contract NodeVersionBeacon {
access(all) fun heartbeat() {
self.checkFirstUpcomingBoundary()

self.emitProtocolStateVersionUpgradeEventIfNeeded()

if (!NodeVersionBeacon.emitEventOnNextHeartbeat) {
return
}
Expand Down Expand Up @@ -336,6 +350,17 @@ access(all) contract NodeVersionBeacon {
// If we passed a boundary re-emit the VersionBeacon event
NodeVersionBeacon.emitEventOnNextHeartbeat = true
}

/// Emit a ProtocolStateVersionUpgrade event, if a pending upgrade is in storage.
access(self) fun emitProtocolStateVersionUpgradeEventIfNeeded() {
let pendingUpgrade = NodeVersionBeacon.popPendingProtocolStateVersionUpgrade()
if pendingUpgrade == nil {
return
}
emit NodeVersionBeacon.ProtocolStateVersionUpgrade(
newProtocolVersion: pendingUpgrade!.version,
activeView: pendingUpgrade!.activeView)
jordanschalm marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// getCurrentVersionBoundaries returns the current version boundaries.
Expand Down Expand Up @@ -495,6 +520,47 @@ access(all) contract NodeVersionBeacon {
return self.versionBoundaryBlockList[0]
}

/// =========================
/// Protocol State Versioning
/// =========================

/// ViewActivatedVersion stores a version and a view. It indicates a version upgrade
/// so that `version` will become active at view `activeView`.
access(all) struct ViewActivatedVersion {
access(all) let version: UInt64
access(all) let activeView: UInt64

init(version: UInt64, activeView: UInt64) {
self.version = version
self.activeView = activeView
}
}

/// A service event which is emitted to indicate that the Protocol State version is being upgraded.
/// This acts as a signal to begin using the upgraded Protocol State version
/// after this service event is sealed, and after view `activeView` is entered.
/// Nodes running a software version which does not support `newProtocolVersion`
/// will stop processing new blocks when they reach view `activeAtView`.
access(all) event ProtocolStateVersionUpgrade(newProtocolVersion: UInt64, activeView: UInt64)

/// Removes the pending ProtocolStateVersionUpgrade from storage and returns it.
/// If no ProtocolStateVersionUpgrade was in storage, returns nil.
access(contract) fun popPendingProtocolStateVersionUpgrade(): ViewActivatedVersion? {
return self.account.storage.load<ViewActivatedVersion>(from: /storage/PendingProtocolStateVersionUpgrade)
}

/// Reads the pending ProtocolStateVersionUpgrade from storage, without removing it, and returns it.
/// If no ProtocolStateVersionUpgrade was in storage, returns nil.
access(all) fun peekPendingProtocolStateVersionUpgrade(): ViewActivatedVersion? {
return self.account.storage.copy<ViewActivatedVersion>(from: /storage/PendingProtocolStateVersionUpgrade)
}

/// Stores the pending ProtocolStateVersionUpgrade to storage.
/// No ProtocolStateVersionUpgrade may already be stored, otherwise the transaction will revert.
access(contract) fun storePendingProtocolStateVersionUpgrade(upgrade: ViewActivatedVersion) {
self.account.storage.save<ViewActivatedVersion>(upgrade, to: /storage/PendingProtocolStateVersionUpgrade)
jordanschalm marked this conversation as resolved.
Show resolved Hide resolved
}

init(versionUpdateFreezePeriod: UInt64) {
self.AdminStoragePath = /storage/NodeVersionBeaconAdmin
self.HeartbeatStoragePath = /storage/NodeVersionBeaconHeartbeat
Expand Down
Loading
Loading