Manager
Git Source (opens in a new tab)
Manages node lifecycle (registration, activation, deactivation)
Allows anyone to register to become an active node
Allows registered nodes to become active after a cooldown
seconds waiting period
Allows any node to deactivate itself and return to an inactive state
Exposes an onlyActiveNode()
modifier used to restrict functions to being called by only active nodes
Restricts addresses to 1 of 3 states: Inactive
, Registered
, Active
State Variables
cooldown
Cooldown period, in seconds, before a node with NodeStatus.Registered
can call activateNode()
type(uint32) is sufficient but we are not packing variables so control plane costs are higher because we need to cast the 32-bit type into the 256-bit type anyways. Thus, we use type(uint256).
uint256 public constant cooldown = 1 hours;
nodeInfo
Node address => node information
mapping(address => NodeInfo) public nodeInfo;
Functions
onlyActiveNode
Allow only callers that are active nodes
modifier onlyActiveNode();
registerNode
Allows registering a node for activation
First-step of two-step process (followed by activateNode()
)
Can call on behalf of other nodes as a proxy registerer
Node must have NodeStatus.Inactive
to begin registration
function registerNode(address node) external;
Parameters
Name | Type | Description |
---|---|---|
node | address | node address to register |
activateNode
Allows activating a registered node after cooldown
has elapsed
Second-step of two-step process (preceeded by registerNode()
)
Must be called by node accepting a pending registration (msg.sender == node
)
Must be called at least cooldown
seconds after registerNode()
function activateNode() external;
deactivateNode
Allows deactivating a node
Can be called to set the status of any node back to NodeStatus.Inactive
with no cooldown
Must be called by the node deactivating itself (msg.sender == node
)
function deactivateNode() external;
Events
NodeRegistered
Emitted when a node moves from NodeStatus.Inactive
to NodeStatus.Registered
It's actually slightly more expensive (~6 gas) to emit the uint32 given the explicit conversion needed but this is necessary to have better readability and uniformity across the type (not casting in event)
event NodeRegistered(address indexed node, address indexed registerer, uint32 cooldownStart);
NodeActivated
Emitted when a node moves from NodeStatus.Registered
to NodeStatus.Active
event NodeActivated(address indexed node);
NodeDeactivated
Emitted when a node moves from any status to NodeStatus.Inactive
event NodeDeactivated(address indexed node);
Errors
NodeNotActive
Thrown if attempting to call function that requires a node to have status NodeStatus.Active
Only used by modifier(onlyActiveNode)
4-byte signature: 0x8741cbb8
error NodeNotActive();
NodeNotRegisterable
Thrown by registerNode()
if attempting to register node with status that is not NodeStatus.Inactive
4-byte signature: 0x5acfd518
error NodeNotRegisterable(address node, NodeStatus status);
CooldownActive
Thrown by activateNode()
if cooldown
has not elapsed since node was registered
Like NodeRegistered
, slightly more expensive to use uint32 over uint256 (~6 gas) but better readability
4-byte signature: 0xc84b5bdd
error CooldownActive(uint32 cooldownStart);
NodeNotActivateable
Thrown by activateNode()
if attempting to active node with status that is not NodeStatus.Registered
4-byte signature: 0x33daa7f9
error NodeNotActivateable(NodeStatus status);
Structs
NodeInfo
Packed information about a node (status, cooldown start)
Cheaper to use a struct to store status
+ cooldownStart
rather than SSTORE 2 independent mappings
Technically, could bitshift pack uint40 of data into single uint256 but readability penalty not worth it
Tightly-packed (well under 32-byte slot): [uint8, uint32] = 40 bits = 5 bytes
struct NodeInfo {
/// @notice Node status
NodeStatus status;
/// @notice Cooldown start timestamp in seconds
/// @dev Default initializes to `0`; no cooldown active to start
/// @dev Equal to `0` if `status != NodeStatus.Registered`, else equal to cooldown start time
/// @dev Is modified by `registerNode()` to initiate `cooldown` holding period
/// @dev uint32 allows for a timestamp up to year ~2106, likely far beyond lifecycle of this contract
uint32 cooldownStart;
}
Enums
NodeStatus
Possible node statuses
Enums in Solidity are unsigned integers capped at 256 members, so Inactive is the 0-initialized default
Inactive (0): Default status is inactive; no status
Registered (1): Node has registered to become active, initiating a period of cooldown
Active (2): Node is active, able to fulfill subscriptions, and is part of modifier(onlyActiveNode)
enum NodeStatus {
Inactive,
Registered,
Active
}