-
Notifications
You must be signed in to change notification settings - Fork 50
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 0.x] Add ProtocolStateVersionUpgrade
service event
#411
Changes from all commits
72994c4
f21ab6c
b3026e8
c8b8e1a
c28ccd3
f59efe4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,10 @@ | |
/// The contract itself can be used to query the current version and the next upcoming version. | ||
pub contract NodeVersionBeacon { | ||
|
||
/// ========================= | ||
/// Execution State Versioning | ||
/// ========================= | ||
|
||
/// Struct representing software version as Semantic Version | ||
/// along with helper functions | ||
/// For reference, see https://semver.org/ | ||
|
@@ -134,9 +138,10 @@ pub contract NodeVersionBeacon { | |
) | ||
} | ||
|
||
/// Event emitted when the version table is updated. | ||
/// It contains the current version and all the upcoming versions | ||
/// sorted by block height. | ||
/// 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. | ||
pub event VersionBeacon( | ||
|
@@ -280,6 +285,13 @@ pub 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. | ||
pub 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. | ||
|
@@ -291,6 +303,8 @@ pub contract NodeVersionBeacon { | |
pub fun heartbeat() { | ||
self.checkFirstUpcomingBoundary() | ||
|
||
self.emitProtocolStateVersionUpgradeEventIfNeeded() | ||
|
||
if (!NodeVersionBeacon.emitEventOnNextHeartbeat) { | ||
return | ||
} | ||
|
@@ -336,6 +350,17 @@ pub 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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't look like it from looking at the other code, but I just want to confirm that there is no way that this optional can be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty sure it cannot be nil, because of the if pendingUpgrade == nil {
return
} |
||
activeView: pendingUpgrade!.activeView) | ||
} | ||
} | ||
|
||
/// getCurrentVersionBoundaries returns the current version boundaries. | ||
|
@@ -495,6 +520,47 @@ pub 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`. | ||
pub struct ViewActivatedVersion { | ||
pub let version: UInt64 | ||
pub 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`. | ||
pub 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.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. | ||
pub fun peekPendingProtocolStateVersionUpgrade(): ViewActivatedVersion? { | ||
return self.account.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.save<ViewActivatedVersion>(upgrade, to: /storage/PendingProtocolStateVersionUpgrade) | ||
} | ||
|
||
init(versionUpdateFreezePeriod: UInt64) { | ||
self.AdminStoragePath = /storage/NodeVersionBeaconAdmin | ||
self.HeartbeatStoragePath = /storage/NodeVersionBeaconHeartbeat | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to confirm my understanding:
The reason we don't just emit the event here is that the service events are only observed from the service transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly. The idea was to be as restrictive as possible for what qualifies as a service event, because they are so security-sensitive, at the cost of convenience in this kind of case.