WorkMode.sol (3058B)
1 pragma solidity ^0.8.0; 2 3 // SPDX-License-Identifier: GPL-3.0-or-later 4 // File-Version: 1 5 6 contract WorkMode { 7 8 uint256 public startOfTimes; 9 uint32 public periodDuration; 10 mapping(address => uint32 ) public startPeriod; // 0 = not yet active, 1 = (before) start of times, 2 = first period after start of times 11 mapping(address => uint8[] ) public mode; // modes 1=idle, 2=active, 4=experimental 12 13 event ParticipantAdded(address indexed origin, uint32 startPeriod); 14 event LogAdded(address indexed origin, uint32 indexed period, uint8 mode); 15 16 constructor(uint32 _periodDuration, uint256 _startOfTimes) { 17 if (_startOfTimes == 0) { 18 startOfTimes = block.timestamp; 19 } else { 20 startOfTimes = _startOfTimes; 21 } 22 periodDuration = _periodDuration; 23 } 24 25 // Get the current internal period from the current block timestamp. 26 function getPeriodInternal() private view returns (uint32) { 27 uint256 delta; 28 uint32 period; 29 30 delta = block.timestamp - startOfTimes; 31 period = (uint32(delta) / periodDuration) + 2; 32 33 return period; 34 } 35 36 // Get the current zero-indexed period from the current block timetamp. 37 function getPeriod() public view returns (uint32) { 38 uint32 period; 39 40 period = getPeriodInternal(); 41 42 return period - 1; 43 } 44 45 // Get the zero-indexed start period for the participant. 46 function startPeriodFor(address _participant) public view returns (uint32) { 47 uint32 period; 48 49 period = startPeriod[_participant] - 1; 50 51 return period; 52 } 53 54 // Get the last internal period a participant added a mode. 55 function lastPeriodForInternal(address _participant) private view returns (uint32) { 56 uint256 idx; 57 uint32 originStartPeriod; 58 59 idx = mode[_participant].length; 60 if (idx == 0) { 61 return 1; 62 } 63 64 originStartPeriod = startPeriod[_participant]; 65 return originStartPeriod + uint32(idx); 66 } 67 68 // Get the last zero-indexed period a participant added a mode. 69 function lastPeriodFor(address _participant) public view returns (uint32) { 70 uint32 period; 71 72 period = lastPeriodForInternal(_participant); 73 74 return period - 1; 75 } 76 77 // Set the period to the initial value for an active participant 78 function checkInit() private { 79 uint32 nowPeriod; 80 81 if (mode[tx.origin].length == 0) { 82 startPeriod[tx.origin] = 1; 83 nowPeriod = getPeriod(); 84 emit ParticipantAdded(tx.origin, nowPeriod); 85 } 86 } 87 88 // Register a new mode. 89 // 90 // The period registering for must be explicit, and the mode must be for the next period after the last that was registered. 91 function set(uint32 _registerPeriod, uint8 _registerMode) public returns (bool) { 92 uint32 lastPeriod; 93 uint32 registerPeriodInternal; 94 95 // Activate the participant if not yet active. 96 checkInit(); 97 98 lastPeriod = lastPeriodForInternal(tx.origin); 99 registerPeriodInternal = _registerPeriod + 1; 100 if (registerPeriodInternal <= lastPeriod) { 101 return false; 102 } 103 104 if (registerPeriodInternal - lastPeriod > 1) { 105 revert("period skipped"); 106 } 107 108 mode[tx.origin].push(_registerMode); 109 emit LogAdded(tx.origin, _registerPeriod, _registerMode); 110 111 return true; 112 } 113 }