Last active
November 8, 2018 15:57
-
-
Save resilience-me/75cf3df0d7276e8e6b669a77e90cd99a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
contract MazeHashFunction { | |
function generateRandomNumber(uint _treasureMap) view internal returns (uint) { | |
bytes memory randomNumber = new bytes(32); | |
bytes memory treasureMapInBytes = toBytes(_treasureMap); | |
uint8 nextByteInTreasureMap = uint8(treasureMapInBytes[31]); | |
uint8 pointerToNextPosition = nextByteInTreasureMap; | |
for(uint i = 31; i >0; i--) { | |
uint nextHashInLabyrinth = uint(blockhash(block.number - 1 - pointerToNextPosition)); | |
bytes memory blockHashToBytes = toBytes(nextHashInLabyrinth); | |
uint8 byteFromBlockhash = uint8(blockHashToBytes[i]); | |
nextByteInTreasureMap = uint8(treasureMapInBytes[i]); | |
uint8 nextRandomNumber = nextByteInTreasureMap ^ byteFromBlockhash; | |
randomNumber[i] = bytes1(nextRandomNumber); | |
pointerToNextPosition = nextRandomNumber; | |
} | |
return toUint(randomNumber); | |
} | |
function toBytes(uint256 x) pure internal returns (bytes b) { | |
b = new bytes(32); | |
assembly { mstore(add(b, 32), x) } | |
} | |
function toUint(bytes x) pure internal returns (uint b) { | |
assembly { | |
b := mload(add(x, 0x20)) | |
} | |
} | |
} | |
contract PseudonymPairs is MazeHashFunction { | |
enum State { interlude, pseudonymEvent, eventFinished, endOfPeriod } | |
uint[4] timeperiods; | |
mapping(uint => uint) randomHourMechanism; | |
uint randomHour; // The exact hour of the event cycles by random over 24 hours | |
uint genesisTimestamp = 1545523200; // Saturday 22 December 2018 00:00:00, pseudonym events | |
// scheduled to random hour between 00:00 and 23:59 on saturdays | |
function setRandomHour() internal { | |
entropy = generateRandomNumber(entropy); | |
uint stepIn24HourCycle = eventCounter % 24; | |
uint randomNumber = entropy % (24 - stepIn24HourCycle); | |
uint randomClockstroke = stepIn24HourCycle + randomNumber; | |
randomHourMechanism[randomClockstroke] = randomHourMechanism[stepIn24HourCycle]; // Update the index that is used for cycling through random hours | |
randomHour = randomClockstroke; | |
timeperiods[2] = 28 days - randomHour; | |
timeperiods[1] = 28 days - randomHour - 20 minutes; | |
} | |
modifier atTime(State _inState, State _nextState) { | |
require(now > getTime(_inState)); | |
require(now < getTime(_nextState)); | |
_; | |
} | |
function getTime(State _state) view returns (uint) { | |
return genesisTimestamp + (timeperiods[3] * eventCounter) + timeperiods[uint(_state)]; | |
} | |
modifier incrementEventCounter { | |
if(now > getTime(State.endOfPeriod)) eventCounter++; | |
_; | |
} | |
constructor() { | |
genesisTimestamp = now; | |
timeperiods[3] = 28 days; // 13 events per year, 364 day year. The pseudonym event is on a saturday, always | |
timeperiods[2] = 28 days - randomHour; // This varies with randomHour, adjusted every new pseudonym month | |
timeperiods[1] = 28 days - randomHour - 20 minutes; // The pseudonym event lasts 20 minutes | |
timeperiods[0] = 0; | |
} | |
function register(uint _nym) internal atTime(State.interlude, State.pseudonymEvent) { } | |
mapping(uint => uint) evenNumbersIndex; // The pair that a given pseudonymID maps to, list is shuffled with each new person who invokes sortMe() | |
mapping(uint => uint) unevenNumbersIndex; // The index is split over even and uneven numbers, to map to pairs of two people | |
mapping(address => uint) pseudonymID; | |
mapping(uint => address) pseudonymIndex; | |
uint totalSorted; | |
uint totalPairs; | |
mapping(uint => uint) virtualBorder; // immigrantID mapped to evenNumbers, hitch-hikes on a registered person, and the shuffling on their end | |
mapping(address => uint) immigrantID; | |
mapping(uint => address) immigrantIndex; | |
uint totalImmigrants; | |
uint entropy; | |
function sortMe() atTime(State.interlude, State.pseudonymEvent) { | |
require(pseudonymID[msg.sender] == 0); | |
totalSorted++; | |
pseudonymID[msg.sender] = totalSorted; | |
pseudonymIndex[totalSorted] = msg.sender; | |
entropy = generateRandomNumber(entropy); | |
// Map even and uneven numbers in separate indices, each integer representing a pair with two people | |
if(totalSorted % 2 == 0) { | |
uint randomNumber = 1 + (entropy % totalPairs); | |
evenNumbersIndex[randomNumber] = totalPairs; | |
evenNumbersIndex[totalPairs] = randomNumber; | |
totalPairs++; | |
} | |
if(totalSorted % 2 == 1) { | |
uint randomNumber = 1 + (entropy % totalPairs); | |
unevenNumbersIndex[randomNumber] = totalPairs; | |
unevenNumbersIndex[totalPairs] = randomNumber; | |
} | |
} | |
function optIn() atTime(State.interlude, State.pseudonymEvent) { | |
require(totalPairs >= 1); | |
require(totalPairs > totalImmigrants); | |
require(immigrantID[msg.sender] == 0); | |
require(borderToken.balanceOf[msg.sender] >= 1); | |
borderToken.balanceOf[msg.sender]--; | |
totalImmigrants++; | |
immigrantID[msg.sender] = totalImmigrants; | |
immigrantIndex[totalImmigrants] = msg.sender; | |
entropy = generateRandomNumber(entropy); | |
uint randomNumber = 1 + (entropy % (totalPairs - totalImmigrants)); | |
uint randomPair = totalImmigrants + randomNumber; // Mapped to evenNumbers, hitch-hikes on a registered person, and the shuffling on their end | |
// Prune the list with randomPair, adding the pair from the beginning to its position | |
if(virtualBorder[randomPair] == 0) virtualBorder[randomPair] = randomPair; | |
if(virtualBorder[totalImmigrants] == 0) virtualBorder[totalImmigrants] = totalImmigrants; | |
uint indexedPosition = virtualBorder[randomPair]; | |
virtualBorder[indexedPosition] = virtualBorder[totalImmigrants]; | |
// Assign the person to randomPair | |
virtualBorder[totalImmigrants] = randomPair; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment