From 56a188be7c9d89064d74d28b5c82b982620bc75f Mon Sep 17 00:00:00 2001 From: Artur Albov Date: Thu, 24 Jan 2019 12:21:45 +0700 Subject: [PATCH] #179 Change Bandwidth Price to Average for 24h Sliding Window. Notes fixes --- app/app.go | 6 ++-- x/bandwidth/keeper.go | 6 +++- x/bandwidth/meter.go | 71 +++++++++++++++++++------------------- x/bandwidth/types/meter.go | 6 ++-- 4 files changed, 48 insertions(+), 41 deletions(-) diff --git a/app/app.go b/app/app.go index 9d466e7a..b77610c3 100644 --- a/app/app.go +++ b/app/app.go @@ -309,7 +309,7 @@ func (app *CyberdApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) { if err == nil { - txCost := app.bandwidthMeter.GetTxCost(ctx, tx) + txCost := app.bandwidthMeter.GetPricedTxCost(tx) accBw := app.bandwidthMeter.GetCurrentAccBandwidth(ctx, acc) if !accBw.HasEnoughRemained(txCost) { @@ -342,7 +342,7 @@ func (app *CyberdApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { if err == nil { - txCost := app.bandwidthMeter.GetTxCost(ctx, tx) + txCost := app.bandwidthMeter.GetPricedTxCost(tx) accBw := app.bandwidthMeter.GetCurrentAccBandwidth(ctx, acc) if !accBw.HasEnoughRemained(txCost) { @@ -351,7 +351,7 @@ func (app *CyberdApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { resp := app.BaseApp.DeliverTx(txBytes) app.bandwidthMeter.ConsumeAccBandwidth(ctx, accBw, txCost) - app.bandwidthMeter.AddToBlockBandwidth(uint64(txCost)) + app.bandwidthMeter.AddToBlockBandwidth(app.bandwidthMeter.GetTxCost(tx)) return abci.ResponseDeliverTx{ Code: uint32(resp.Code), diff --git a/x/bandwidth/keeper.go b/x/bandwidth/keeper.go index 5670b614..2e3a45e9 100644 --- a/x/bandwidth/keeper.go +++ b/x/bandwidth/keeper.go @@ -59,7 +59,11 @@ func (bk BaseBlockSpentBandwidthKeeper) SetBlockSpentBandwidth(ctx sdk.Context, func (bk BaseBlockSpentBandwidthKeeper) GetValuesForPeriod(ctx sdk.Context, period int64) map[uint64]uint64 { startKey := make([]byte, 8) - binary.LittleEndian.PutUint64(startKey, uint64(ctx.BlockHeight()-period+1)) + windowStart := ctx.BlockHeight() - period + 1 + if windowStart < 0 { // check needed cause it will be casted to uint and can cause overflow + windowStart = 0 + } + binary.LittleEndian.PutUint64(startKey, uint64(windowStart)) endKey := make([]byte, 8) binary.LittleEndian.PutUint64(endKey, uint64(ctx.BlockHeight())) diff --git a/x/bandwidth/meter.go b/x/bandwidth/meter.go index 73009864..bf08b604 100644 --- a/x/bandwidth/meter.go +++ b/x/bandwidth/meter.go @@ -8,7 +8,7 @@ import ( "math" ) -var _ types.BandwidthMeter = BaseBandwidthMeter{} +var _ types.BandwidthMeter = &BaseBandwidthMeter{} type BaseBandwidthMeter struct { // data providers @@ -22,50 +22,47 @@ type BaseBandwidthMeter struct { msgCost types.MsgBandwidthCost // price adjustment fields - curBlockSpentBandwidth *uint64 //resets every block - currentCreditPrice *float64 + curBlockSpentBandwidth uint64 //resets every block + currentCreditPrice float64 bandwidthSpent map[uint64]uint64 // bandwidth spent by blocks - totalSpentForSlidingWindow *uint64 + totalSpentForSlidingWindow uint64 } func NewBaseMeter( mainKeeper store.MainKeeper, ak auth.AccountKeeper, sp types.AccStakeProvider, bwKeeper types.Keeper, msgCost types.MsgBandwidthCost, blockBandwidthKeeper types.BlockSpentBandwidthKeeper, -) BaseBandwidthMeter { +) *BaseBandwidthMeter { - return BaseBandwidthMeter{ + return &BaseBandwidthMeter{ mainKeeper: mainKeeper, blockBandwidthKeeper: blockBandwidthKeeper, accKeeper: ak, stakeProvider: sp, bwKeeper: bwKeeper, msgCost: msgCost, - curBlockSpentBandwidth: new(uint64), - currentCreditPrice: new(float64), - totalSpentForSlidingWindow: new(uint64), bandwidthSpent: make(map[uint64]uint64), } } -func (m BaseBandwidthMeter) Load(ctx sdk.Context) { - *m.totalSpentForSlidingWindow = 0 - for blockNum, spentBandwidth := range m.blockBandwidthKeeper.GetValuesForPeriod(ctx, SlidingWindowSize) { - m.bandwidthSpent[blockNum] = spentBandwidth - *m.totalSpentForSlidingWindow += spentBandwidth +func (m *BaseBandwidthMeter) Load(ctx sdk.Context) { + m.totalSpentForSlidingWindow = 0 + m.bandwidthSpent = m.blockBandwidthKeeper.GetValuesForPeriod(ctx, SlidingWindowSize) + for _, spentBandwidth := range m.bandwidthSpent { + m.totalSpentForSlidingWindow += spentBandwidth } - *m.currentCreditPrice = math.Float64frombits(m.mainKeeper.GetBandwidthPrice(ctx, BaseCreditPrice)) - *m.curBlockSpentBandwidth = 0 + m.currentCreditPrice = math.Float64frombits(m.mainKeeper.GetBandwidthPrice(ctx, BaseCreditPrice)) + m.curBlockSpentBandwidth = 0 } -func (m BaseBandwidthMeter) AddToBlockBandwidth(value uint64) { +func (m *BaseBandwidthMeter) AddToBlockBandwidth(value int64) { // we have to divide by price here to get base price value - *m.curBlockSpentBandwidth += uint64(float64(value) / *m.currentCreditPrice) + m.curBlockSpentBandwidth += uint64(float64(value) / m.currentCreditPrice) } // Here we move bandwidth window: // Remove first block of window and add new block to window end -func (m BaseBandwidthMeter) CommitBlockBandwidth(ctx sdk.Context) { - *m.totalSpentForSlidingWindow += *m.curBlockSpentBandwidth +func (m *BaseBandwidthMeter) CommitBlockBandwidth(ctx sdk.Context) { + m.totalSpentForSlidingWindow += m.curBlockSpentBandwidth newWindowEnd := ctx.BlockHeight() windowStart := newWindowEnd - SlidingWindowSize @@ -74,47 +71,51 @@ func (m BaseBandwidthMeter) CommitBlockBandwidth(ctx sdk.Context) { } windowStartValue, exists := m.bandwidthSpent[uint64(windowStart)] if exists { - *m.totalSpentForSlidingWindow -= windowStartValue + m.totalSpentForSlidingWindow -= windowStartValue delete(m.bandwidthSpent, uint64(windowStart)) } - m.blockBandwidthKeeper.SetBlockSpentBandwidth(ctx, uint64(ctx.BlockHeight()), *m.curBlockSpentBandwidth) - m.bandwidthSpent[uint64(newWindowEnd)] = *m.curBlockSpentBandwidth - *m.curBlockSpentBandwidth = 0 + m.blockBandwidthKeeper.SetBlockSpentBandwidth(ctx, uint64(ctx.BlockHeight()), m.curBlockSpentBandwidth) + m.bandwidthSpent[uint64(newWindowEnd)] = m.curBlockSpentBandwidth + m.curBlockSpentBandwidth = 0 } -func (m BaseBandwidthMeter) AdjustPrice(ctx sdk.Context) { +func (m *BaseBandwidthMeter) AdjustPrice(ctx sdk.Context) { - newPrice := float64(*m.totalSpentForSlidingWindow) / float64(ShouldBeSpentPerSlidingWindow) + newPrice := float64(m.totalSpentForSlidingWindow) / float64(ShouldBeSpentPerSlidingWindow) if newPrice < 0.01*BaseCreditPrice { newPrice = 0.01 * BaseCreditPrice } - *m.currentCreditPrice = newPrice + m.currentCreditPrice = newPrice m.mainKeeper.StoreBandwidthPrice(ctx, math.Float64bits(newPrice)) } -func (m BaseBandwidthMeter) GetTxCost(ctx sdk.Context, tx sdk.Tx) int64 { +func (m *BaseBandwidthMeter) GetTxCost(tx sdk.Tx) int64 { bandwidthForTx := TxCost for _, msg := range tx.GetMsgs() { bandwidthForTx = bandwidthForTx + m.msgCost(msg) } - return int64(float64(bandwidthForTx) * *m.currentCreditPrice) + return bandwidthForTx } -func (m BaseBandwidthMeter) GetAccMaxBandwidth(ctx sdk.Context, addr sdk.AccAddress) int64 { +func (m *BaseBandwidthMeter) GetPricedTxCost(tx sdk.Tx) int64 { + return int64(float64(m.GetTxCost(tx)) * m.currentCreditPrice) +} + +func (m *BaseBandwidthMeter) GetAccMaxBandwidth(ctx sdk.Context, addr sdk.AccAddress) int64 { accStakePercentage := m.stakeProvider.GetAccStakePercentage(ctx, addr) return int64(accStakePercentage * float64(DesirableNetworkBandwidthForRecoveryPeriod)) } -func (m BaseBandwidthMeter) GetCurrentAccBandwidth(ctx sdk.Context, address sdk.AccAddress) types.AcсBandwidth { +func (m *BaseBandwidthMeter) GetCurrentAccBandwidth(ctx sdk.Context, address sdk.AccAddress) types.AcсBandwidth { accBw := m.bwKeeper.GetAccBandwidth(ctx, address) accMaxBw := m.GetAccMaxBandwidth(ctx, address) accBw.UpdateMax(accMaxBw, ctx.BlockHeight(), RecoveryPeriod) return accBw } -func (m BaseBandwidthMeter) UpdateAccMaxBandwidth(ctx sdk.Context, address sdk.AccAddress) { +func (m *BaseBandwidthMeter) UpdateAccMaxBandwidth(ctx sdk.Context, address sdk.AccAddress) { bw := m.GetCurrentAccBandwidth(ctx, address) m.bwKeeper.SetAccBandwidth(ctx, bw) } @@ -127,13 +128,13 @@ func (m BaseBandwidthMeter) UpdateAccMaxBandwidth(ctx sdk.Context, address sdk.A // bw := getCurrentBw(addr) // bwCost := deliverTx(tx) // consumeBw(bw, bwCost) -func (m BaseBandwidthMeter) ConsumeAccBandwidth(ctx sdk.Context, bw types.AcсBandwidth, amt int64) { +func (m *BaseBandwidthMeter) ConsumeAccBandwidth(ctx sdk.Context, bw types.AcсBandwidth, amt int64) { bw.Consume(amt) m.bwKeeper.SetAccBandwidth(ctx, bw) bw = m.GetCurrentAccBandwidth(ctx, bw.Address) m.bwKeeper.SetAccBandwidth(ctx, bw) } -func (m BaseBandwidthMeter) GetCurrentCreditPrice() float64 { - return *m.currentCreditPrice +func (m *BaseBandwidthMeter) GetCurrentCreditPrice() float64 { + return m.currentCreditPrice } diff --git a/x/bandwidth/types/meter.go b/x/bandwidth/types/meter.go index ed979c01..98ca46ed 100644 --- a/x/bandwidth/types/meter.go +++ b/x/bandwidth/types/meter.go @@ -18,7 +18,7 @@ type BandwidthMeter interface { // load current bandwidth state after restart Load(ctx sdk.Context) // add value to consumed bandwidth for current block - AddToBlockBandwidth(value uint64) + AddToBlockBandwidth(value int64) // adjust price based on 24h loading AdjustPrice(ctx sdk.Context) // get current bandwidth price @@ -32,7 +32,9 @@ type BandwidthMeter interface { // Returns acc max bandwidth GetAccMaxBandwidth(ctx sdk.Context, address sdk.AccAddress) int64 // Returns tx bandwidth cost - GetTxCost(ctx sdk.Context, tx sdk.Tx) int64 + GetTxCost(tx sdk.Tx) int64 + // Return tx bandwidth cost considering the price + GetPricedTxCost(tx sdk.Tx) int64 // // Performs bw consumption for given acc // To get right number, should be called after tx delivery with bw state obtained prior delivery