# TellorMesosphere Tellor Mesosphere provides layer 2 oracle services for the Tellor Fellowship. It works by allowing a whitelisted set of addresses to submit values. Once a `quorum` of values is submitted within the `timeLimit` and with a range below the `maximumDeviation` from the previous median, a new median value is generated. ## Setup When deploying the Mesosphere, one must choose a `quorum`, a `timeLimit`, and a `maximumDeviation`. The quorum is the minimum number of valid reporter values needed to generate a new median value. The timeLimit is the maximum age a value can be to be considered for generating a new median value. The maximumDeviation determines the maximum range a set of values can have to be used for a new median. A maximumDeviation of `2000` for example means that the range cannot be greater than 20% of the previous median. If this limit is exceeded, the value furthest from the previous median is removed. After deployment, the deployer address is set as the admin. More admins can be added using the `addAdmin` function. The admin must add reporters using the `addReporter` function. Once the number of reporters added reaches quorum, new median values can start to be generated. ## Submit Value Function The `submitValue` function is used by reporters to submit new values. The function first saves the value and timestamp to `latestValues` and `latestTimestamps`, respectively. The `_getNewMedian` internal function is then called to determine whether certain conditions are met and then, if so, calculate the new median. The `_getNewMedian` function creates an empty memory array, `_validReports`. It then iterates through the latest timestamps from each reporter. If a timestamp is less than `timeLimit` seconds old, its corresponding value is added to `_validReports`. After all latest timestamps are iterated through, the function checks whether the number of valid reports has reached quorum. If not, `_getNewMedian` returns `false`. If quorum has been reached, we move on to sorting the `_validReports` array. After the `_validReports` array has been sorted, the difference between the last value and the first value is taken to find the range. If the range times 10000 divided by the most recent median is greater than `maximumDeviation`, it is determined whether `quorum` would still be reached if we removed a value. If not, `_getNewMedian` returns `false`. Otherwise, we then determine whether the minimum value or the maximum value is further from the last median value. The reporter whose value is further has their corresponding `latestTimestamps` set to zero so that it will no longer be considered valid for generating a new median. Then the `_getNewMedian` function starts again from the beginning. If the `maximumDeviation` is not exceeded, a new `_median` is found from the sorted array’s middle value (or the average of the middle two values if `_numberOfValidReports` is an even number). The `_getNewMedian` function then returns `(true, _median, _oldestTimestamp, _numberOfValidReports)`. Once the `submitValue` function gets a response from the `_getNewMedian` function, it either stops there if `_ifRetrieve` is `false`, or otherwise moves on to saving the new median value. If `_ifRetrieve` is `true`, the function then determines whether to push a new value or overwrite the last value. If the `_oldestTimestamp` used to determine the new median equals the oldest timestamp from the last value, and the number of valid reports from the last value is less than the total number of reporters, then the last value is overwritten. The `values` mapping for the last timestamp is set to `0` and the `timestamps` mapping’s last value is reset to the current `block.timestamp`. If the above conditions are not met, the current `block.timestamp` is pushed to the `timestamps` mapping=>array and `oldestTimestampFromLatestBlock` is set to equal`_oldestTimestamp`. Finally, the new median is saved to the `values` mapping at the current `block.timestamp`, and `numberReportersFromLatestBlock` is set to equal `_numberOfValidReports`. ## Get Current Value Function The `getCurrentValue` function can be called by anyone to retrieve the current value for a given `requestId`. This function first determines the total number of values that have been submitted. It then decides whether to return the most recent value or the second to last value. If the quantity of valid reports that generated the last value is less than minimum(total number of reporters, 5), and the oldest timestamp used to generate the last value is less than `timeLimit` seconds old, this function returns the second to last value. Otherwise it returns the last value. This means that after a new median is generated and the oldest timestamp used to generate that median is more than `timeLimit` seconds old, the `getCurrentValue` function will return that latest median value. It also means that if the number of reporters is less than or equal to 5 and all reporters contribute to generating the last median value, `getCurrentValue` will immediately return that last median. Alternatively, if the number of reporters is greater than 5, only 5 valid reporter values are needed to immediately return the last median value. The justification for including these conditions in the `getCurrentValue` function is that it gives a chance for more reporters to help generate a median value. If quorum is 3 and the total number of reporters is 5, it only takes 3 reporters' values to push a new median to the `values` mapping. If however a fourth and fifth reporter submit values before the `timeLimit` expires, we should consider the median of 5 values to be better than the median of 3 values. ## Roles _Admin_ - admin can add admins and add/remove reporters. The deployer address is set as admin on deployment _Reporter_ - Reporters can submit data using the `submitValue` function ## Storage - `values` mapping requestId => timestamp => value - `timestamps` mapping requestId => timestamps array - `reporters` mapping reporterIndex => reporterAddress - `reporterIndices` mapping reporterAddress => reporterIndex - `latestValues` mapping requestId => reporterIndex => latestValue - Tracks most recent value from each reporter for each requestId - `latestTimestamps` mapping requestId => reporterIndex => latestTimestamp - Tracks most recent timestamp from each reporter for each requestId - `oldestTimestampFromLatestBlock` mapping requestId => oldestTimestamp - `numberReportersFromLatestBlock` mapping requestId => number of valid reports for last value