commit a3ccb8511fc60e8a015bce8da6a351764d4e463b
Author: nolash <dev@holbrook.no>
Date: Sun, 9 Jan 2022 11:35:52 +0000
Initial commit
Diffstat:
A | solidity/WorkMode.sol | | | 113 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 113 insertions(+), 0 deletions(-)
diff --git a/solidity/WorkMode.sol b/solidity/WorkMode.sol
@@ -0,0 +1,113 @@
+pragma solidity ^0.8.0;
+
+// SPDX-License-Identifier: GPL-3.0-or-later
+// File-Version: 1
+
+contract WorkMode {
+
+ uint256 public startOfTimes;
+ uint32 public periodDuration;
+ mapping(address => uint32 ) public startPeriod; // 0 = not yet active, 1 = (before) start of times, 2 = first period after start of times
+ mapping(address => uint8[] ) public mode; // modes 1=idle, 2=active, 4=experimental
+
+ event ParticipantAdded(address indexed origin, uint32 startPeriod);
+ event LogAdded(address indexed origin, uint32 indexed period, uint8 mode);
+
+ constructor(uint32 _periodDuration, uint256 _startOfTimes) {
+ if (_startOfTimes == 0) {
+ startOfTimes = block.timestamp;
+ } else {
+ startOfTimes = _startOfTimes;
+ }
+ periodDuration = _periodDuration;
+ }
+
+ // Get the current internal period from the current block timestamp.
+ function getPeriodInternal() private view returns (uint32) {
+ uint256 delta;
+ uint32 period;
+
+ delta = block.timestamp - startOfTimes;
+ period = (uint32(delta) / periodDuration) + 2;
+
+ return period;
+ }
+
+ // Get the current zero-indexed period from the current block timetamp.
+ function getPeriod() public view returns (uint32) {
+ uint32 period;
+
+ period = getPeriodInternal();
+
+ return period - 1;
+ }
+
+ // Get the zero-indexed start period for the participant.
+ function startPeriodFor(address _participant) public view returns (uint32) {
+ uint32 period;
+
+ period = startPeriod[_participant] - 1;
+
+ return period;
+ }
+
+ // Get the last internal period a participant added a mode.
+ function lastPeriodForInternal(address _participant) private view returns (uint32) {
+ uint256 idx;
+ uint32 originStartPeriod;
+
+ idx = mode[_participant].length;
+ if (idx == 0) {
+ return 1;
+ }
+
+ originStartPeriod = startPeriod[_participant];
+ return originStartPeriod + uint32(idx);
+ }
+
+ // Get the last zero-indexed period a participant added a mode.
+ function lastPeriodFor(address _participant) public view returns (uint32) {
+ uint32 period;
+
+ period = lastPeriodForInternal(_participant);
+
+ return period - 1;
+ }
+
+ // Set the period to the initial value for an active participant
+ function checkInit() private {
+ uint32 nowPeriod;
+
+ if (mode[tx.origin].length == 0) {
+ startPeriod[tx.origin] = 1;
+ nowPeriod = getPeriod();
+ emit ParticipantAdded(tx.origin, nowPeriod);
+ }
+ }
+
+ // Register a new mode.
+ //
+ // The period registering for must be explicit, and the mode must be for the next period after the last that was registered.
+ function set(uint32 _registerPeriod, uint8 _registerMode) public returns (bool) {
+ uint32 lastPeriod;
+ uint32 registerPeriodInternal;
+
+ // Activate the participant if not yet active.
+ checkInit();
+
+ lastPeriod = lastPeriodForInternal(tx.origin);
+ registerPeriodInternal = _registerPeriod + 1;
+ if (registerPeriodInternal <= lastPeriod) {
+ return false;
+ }
+
+ if (registerPeriodInternal - lastPeriod > 1) {
+ revert("period skipped");
+ }
+
+ mode[tx.origin].push(_registerMode);
+ emit LogAdded(tx.origin, _registerPeriod, _registerMode);
+
+ return true;
+ }
+}