diff --git a/packages/mana/balance.go b/packages/mana/balance.go index ebb9c4e5d42ad8afd3bd01bf9ff8234f91c3642f..1c407ff90c536e2246c39124fb6b77e2929c86da 100644 --- a/packages/mana/balance.go +++ b/packages/mana/balance.go @@ -5,18 +5,18 @@ import ( ) type Balance struct { - calculator *Calculator - currentBalance uint64 - lastErosion uint64 - roundingErrorInLastErosion float64 + calculator *Calculator + currentBalance uint64 + lastErosion uint64 + accumulatedRoundingError float64 } func NewBalance(calculator *Calculator) *Balance { return &Balance{ - calculator: calculator, - currentBalance: 0, - lastErosion: 0, - roundingErrorInLastErosion: 0, + calculator: calculator, + currentBalance: 0, + lastErosion: 0, + accumulatedRoundingError: 0, } } @@ -25,23 +25,33 @@ func (balance *Balance) GetValue() uint64 { } func (balance *Balance) AddTransfer(movedCoins uint64, receivedTime uint64, spentTime uint64) { - gainedMana, _ := balance.calculator.GenerateMana(movedCoins, spentTime-receivedTime) - - if spentTime >= balance.lastErosion { - balance.Erode(spentTime) - } else { - fmt.Println("empty") - // revert old actions - // apply new - // replay old + gainedMana, roundingError := balance.calculator.GenerateMana(movedCoins, spentTime-receivedTime) + + if balance.currentBalance != 0 { + if spentTime >= balance.lastErosion { + balance.Erode(spentTime) + } else { + fmt.Println("empty") + // revert old actions + // apply new + // replay old + } } balance.currentBalance += gainedMana + balance.accumulatedRoundingError += roundingError + balance.lastErosion = spentTime + + fmt.Println("GENERATE: ", spentTime-receivedTime, movedCoins, gainedMana) } func (balance *Balance) Erode(erosionTime uint64) { if balance.lastErosion <= erosionTime { - balance.currentBalance, _ = balance.calculator.ErodeMana(balance.currentBalance, erosionTime-balance.lastErosion) + erodedMana, _ := balance.calculator.ErodeMana(balance.currentBalance, erosionTime-balance.lastErosion) + + fmt.Println("ERODE: ", erosionTime-balance.lastErosion, balance.currentBalance, erodedMana) + + balance.currentBalance = erodedMana } else { fmt.Println("empty") // revert old erosions diff --git a/packages/mana/balance_test.go b/packages/mana/balance_test.go new file mode 100644 index 0000000000000000000000000000000000000000..233458983ac1baa1fa5194d09b9c52fd58f14490 --- /dev/null +++ b/packages/mana/balance_test.go @@ -0,0 +1,20 @@ +package mana + +import ( + "fmt" + "testing" +) + +func TestBalance_AddTransfer(t *testing.T) { + calculator := NewCalculator(500, 0.1) + + balance1 := NewBalance(calculator) + balance1.AddTransfer(1000, 0, 500) + balance1.AddTransfer(1000, 500, 1000) + balance1.AddTransfer(1000, 1000, 1700) + fmt.Println(balance1.GetValue()) + + balance2 := NewBalance(calculator) + balance2.AddTransfer(1000, 0, 1700) + fmt.Println(balance2.GetValue()) +} diff --git a/packages/mana/calculator.go b/packages/mana/calculator.go index d1ff397f51616f1101e2b1ce2ebd37fde8ec6084..46aa3c53046a68f3c28d5caaebe6bd09fdc77170 100644 --- a/packages/mana/calculator.go +++ b/packages/mana/calculator.go @@ -7,7 +7,7 @@ import ( // A calculator that can be used to calculate the changes of mana due to erosion or mana generation. type Calculator struct { decayInterval float64 - decayRate float64 + decayFactor float64 options *CalculatorOptions tokenSupplyScalefactor float64 } @@ -17,13 +17,13 @@ func NewCalculator(decayInterval float64, decayRate float64, optionalOptions ... return &Calculator{ // store key settings decayInterval: decayInterval, - decayRate: decayRate, // configure optional parameters options: DEFAULT_OPTIONS.Override(optionalOptions...), // derive important factors ... // ... make mana reach exactly the token supply as it's max value (n coins => n mana) + decayFactor: 1 - decayRate, tokenSupplyScalefactor: decayRate / (1 - decayRate), } } @@ -31,9 +31,7 @@ func NewCalculator(decayInterval float64, decayRate float64, optionalOptions ... // Returns the amount of mana that was generated by holding the given amount of coins for the given time. func (calculator *Calculator) GenerateMana(coins uint64, heldTime uint64) (result uint64, roundingError float64) { // calculate results - relativeDecayTime := float64(heldTime) / float64(calculator.decayInterval) - erosionFactor := (1 - math.Pow(1-calculator.decayRate, float64(relativeDecayTime+1)) - calculator.decayRate) / calculator.decayRate - gainedMana := float64(coins) * calculator.options.ManaScaleFactor * calculator.tokenSupplyScalefactor * erosionFactor + gainedMana := float64(coins) * calculator.options.ManaScaleFactor * (1 - math.Pow(calculator.decayFactor, float64(heldTime)/calculator.decayInterval)) // assign rounded results & determine roundingErrors result = uint64(math.Round(gainedMana)) @@ -52,8 +50,7 @@ func (calculator *Calculator) ErodeMana(mana uint64, decayTime uint64) (result u } // calculate results - growthFactor := math.Log(1-calculator.decayRate) / float64(calculator.decayInterval) - erodedMana := float64(mana) * math.Pow(math.E, growthFactor*float64(decayTime)) + erodedMana := float64(mana) * math.Pow(calculator.decayFactor, float64(decayTime)/calculator.decayInterval) // assign rounded results & determine roundingErrors result = uint64(math.Round(erodedMana))