Skip to content

Commit

Permalink
Merge pull request #179 from skalenetwork/enhancement/SKALE-2359-storing
Browse files Browse the repository at this point in the history
Enhancement/skale 2359 storing
  • Loading branch information
DimaStebaev authored Apr 24, 2020
2 parents 81ca961 + 6604ed5 commit 79ce7c5
Show file tree
Hide file tree
Showing 10 changed files with 536 additions and 368 deletions.
324 changes: 36 additions & 288 deletions contracts/delegation/DelegationController.sol

Large diffs are not rendered by default.

281 changes: 281 additions & 0 deletions contracts/delegation/PartialDifferences.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
/*
PartialDifferences.sol - SKALE Manager
Copyright (C) 2018-Present SKALE Labs
@author Dmytro Stebaiev
SKALE Manager is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SKALE Manager is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity 0.5.16;

import "../utils/MathUtils.sol";
import "../utils/FractionUtils.sol";


library PartialDifferences {
using SafeMath for uint;
using MathUtils for uint;

struct Sequence {
// month => diff
mapping (uint => uint) addDiff;
// month => diff
mapping (uint => uint) subtractDiff;
// month => value
mapping (uint => uint) value;

uint firstUnprocessedMonth;
uint lastChangedMonth;
}

struct Value {
// month => diff
mapping (uint => uint) addDiff;
// month => diff
mapping (uint => uint) subtractDiff;

uint value;
uint firstUnprocessedMonth;
uint lastChangedMonth;
}

// functions for sequence

function add(Sequence storage sequence, uint diff, uint month) internal {
require(sequence.firstUnprocessedMonth <= month, "Cannot add to the past");
if (sequence.firstUnprocessedMonth == 0) {
sequence.firstUnprocessedMonth = month;
}
sequence.addDiff[month] = sequence.addDiff[month].add(diff);
if (sequence.lastChangedMonth != month) {
sequence.lastChangedMonth = month;
}
}

function subtract(Sequence storage sequence, uint diff, uint month) internal {
require(sequence.firstUnprocessedMonth <= month, "Cannot subtract from the past");
if (sequence.firstUnprocessedMonth == 0) {
sequence.firstUnprocessedMonth = month;
}
sequence.subtractDiff[month] = sequence.subtractDiff[month].add(diff);
if (sequence.lastChangedMonth != month) {
sequence.lastChangedMonth = month;
}
}

function getAndUpdateValue(Sequence storage sequence, uint month) internal returns (uint) {
if (sequence.firstUnprocessedMonth == 0) {
return 0;
}

if (sequence.firstUnprocessedMonth <= month) {
for (uint i = sequence.firstUnprocessedMonth; i <= month; ++i) {
uint nextValue = sequence.value[i - 1].add(sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]);
if (sequence.value[i] != nextValue) {
sequence.value[i] = nextValue;
}
if (sequence.addDiff[i] > 0) {
delete sequence.addDiff[i];
}
if (sequence.subtractDiff[i] > 0) {
delete sequence.subtractDiff[i];
}
}
sequence.firstUnprocessedMonth = month.add(1);
}

return sequence.value[month];
}

function reduce(
Sequence storage sequence,
FractionUtils.Fraction memory reducingCoefficient,
uint month) internal
{
require(month.add(1) >= sequence.firstUnprocessedMonth, "Can't reduce value in the past");
require(reducingCoefficient.numerator <= reducingCoefficient.denominator, "Increasing of values is not implemented");
if (sequence.firstUnprocessedMonth == 0) {
return;
}
uint value = getAndUpdateValue(sequence, month);
if (value.approximatelyEqual(0)) {
return;
}

sequence.value[month] = sequence.value[month].mul(reducingCoefficient.numerator).div(reducingCoefficient.denominator);

for (uint i = month.add(1); i <= sequence.lastChangedMonth; ++i) {
sequence.subtractDiff[i] = sequence.subtractDiff[i].mul(reducingCoefficient.numerator).div(reducingCoefficient.denominator);
}
}

// functions for value

function add(Value storage sequence, uint diff, uint month) internal {
require(sequence.firstUnprocessedMonth <= month, "Cannot add to the past");
if (sequence.firstUnprocessedMonth == 0) {
sequence.firstUnprocessedMonth = month;
sequence.lastChangedMonth = month;
}
if (month > sequence.lastChangedMonth) {
sequence.lastChangedMonth = month;
}

if (month >= sequence.firstUnprocessedMonth) {
sequence.addDiff[month] = sequence.addDiff[month].add(diff);
} else {
sequence.value = sequence.value.add(diff);
}
}

function subtract(Value storage sequence, uint diff, uint month) internal {
require(sequence.firstUnprocessedMonth <= month.add(1), "Cannot subtract from the past");
if (sequence.firstUnprocessedMonth == 0) {
sequence.firstUnprocessedMonth = month;
sequence.lastChangedMonth = month;
}
if (month > sequence.lastChangedMonth) {
sequence.lastChangedMonth = month;
}

if (month >= sequence.firstUnprocessedMonth) {
sequence.subtractDiff[month] = sequence.subtractDiff[month].add(diff);
} else {
sequence.value = sequence.value.boundedSub(diff);
}
}

function getAndUpdateValue(Value storage sequence, uint month) internal returns (uint) {
require(month.add(1) >= sequence.firstUnprocessedMonth, "Cannot calculate value in the past");
if (sequence.firstUnprocessedMonth == 0) {
return 0;
}

if (sequence.firstUnprocessedMonth <= month) {
for (uint i = sequence.firstUnprocessedMonth; i <= month; ++i) {
uint newValue = sequence.value.add(sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]);
if (sequence.value != newValue) {
sequence.value = newValue;
}
if (sequence.addDiff[i] > 0) {
delete sequence.addDiff[i];
}
if (sequence.subtractDiff[i] > 0) {
delete sequence.subtractDiff[i];
}
}
sequence.firstUnprocessedMonth = month.add(1);
}

return sequence.value;
}

function reduce(Value storage sequence, uint amount, uint month) internal returns (FractionUtils.Fraction memory) {
require(month.add(1) >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past");
if (sequence.firstUnprocessedMonth == 0) {
return FractionUtils.createFraction(0);
}
uint value = getAndUpdateValue(sequence, month);
if (value.approximatelyEqual(0)) {
return FractionUtils.createFraction(0);
}

uint _amount = amount;
if (value < amount) {
_amount = value;
}

FractionUtils.Fraction memory reducingCoefficient = FractionUtils.createFraction(value.boundedSub(_amount), value);
reduce(sequence, reducingCoefficient, month);
return reducingCoefficient;
}

function reduce(Value storage sequence, FractionUtils.Fraction memory reducingCoefficient, uint month) internal {
reduce(
sequence,
sequence,
reducingCoefficient,
month,
false);
}

function reduce(
Value storage sequence,
Value storage sumSequence,
FractionUtils.Fraction memory reducingCoefficient,
uint month) internal
{
reduce(
sequence,
sumSequence,
reducingCoefficient,
month,
true);
}

function reduce(
Value storage sequence,
Value storage sumSequence,
FractionUtils.Fraction memory reducingCoefficient,
uint month,
bool hasSumSequence) internal
{
require(month.add(1) >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past");
if (hasSumSequence) {
require(month.add(1) >= sumSequence.firstUnprocessedMonth, "Cannot reduce value in the past");
}
require(reducingCoefficient.numerator <= reducingCoefficient.denominator, "Increasing of values is not implemented");
if (sequence.firstUnprocessedMonth == 0) {
return;
}
uint value = getAndUpdateValue(sequence, month);
if (value.approximatelyEqual(0)) {
return;
}

uint newValue = sequence.value.mul(reducingCoefficient.numerator).div(reducingCoefficient.denominator);
if (hasSumSequence) {
subtract(sumSequence, sequence.value.boundedSub(newValue), month);
}
sequence.value = newValue;

for (uint i = month.add(1); i <= sequence.lastChangedMonth; ++i) {
uint newDiff = sequence.subtractDiff[i].mul(reducingCoefficient.numerator).div(reducingCoefficient.denominator);
if (hasSumSequence) {
sumSequence.subtractDiff[i] = sumSequence.subtractDiff[i].boundedSub(sequence.subtractDiff[i].boundedSub(newDiff));
}
sequence.subtractDiff[i] = newDiff;
}
}

function clear(Value storage sequence) internal {
for (uint i = sequence.firstUnprocessedMonth; i <= sequence.lastChangedMonth; ++i) {
if (sequence.addDiff[i] > 0) {
delete sequence.addDiff[i];
}
if (sequence.subtractDiff[i] > 0) {
delete sequence.subtractDiff[i];
}
}
if (sequence.value > 0) {
delete sequence.value;
}
if (sequence.firstUnprocessedMonth > 0) {
delete sequence.firstUnprocessedMonth;
}
if (sequence.lastChangedMonth > 0) {
delete sequence.lastChangedMonth;
}
}
}
Loading

0 comments on commit 79ce7c5

Please sign in to comment.