mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
les: track balance instead of totalAmount
This commit is contained in:
parent
b10612d685
commit
9ee4bc94c3
1 changed files with 106 additions and 43 deletions
111
les/api.go
111
les/api.go
|
|
@ -40,10 +40,13 @@ var (
|
||||||
errUnknownBenchmarkType = errors.New("unknown benchmark type")
|
errUnknownBenchmarkType = errors.New("unknown benchmark type")
|
||||||
errMultiple = errors.New("multiple errors")
|
errMultiple = errors.New("multiple errors")
|
||||||
errClientNotConnected = errors.New("client is not connected")
|
errClientNotConnected = errors.New("client is not connected")
|
||||||
|
errBalanceOverflow = errors.New("balance overflow")
|
||||||
|
|
||||||
dropCapacityDelay = time.Second // delay applied to decreasing capacity changes
|
dropCapacityDelay = time.Second // delay applied to decreasing capacity changes
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const maxBalance = 18000000000000000000
|
||||||
|
|
||||||
// PrivateLightServerAPI provides an API to access the LES light server.
|
// PrivateLightServerAPI provides an API to access the LES light server.
|
||||||
type PrivateLightServerAPI struct {
|
type PrivateLightServerAPI struct {
|
||||||
server *LesServer
|
server *LesServer
|
||||||
|
|
@ -108,6 +111,18 @@ func (api *PrivateLightServerAPI) SetClientParams(ids []enode.ID, tags []string,
|
||||||
} else {
|
} else {
|
||||||
err = errInvalidValue
|
err = errInvalidValue
|
||||||
}
|
}
|
||||||
|
case "pricing/balance":
|
||||||
|
if val, ok := value.(float64); ok {
|
||||||
|
client.priceTracker.setBalance(val, false)
|
||||||
|
} else {
|
||||||
|
err = errInvalidValue
|
||||||
|
}
|
||||||
|
case "pricing/addBalance":
|
||||||
|
if val, ok := value.(float64); ok {
|
||||||
|
client.priceTracker.setBalance(val, true)
|
||||||
|
} else {
|
||||||
|
err = errInvalidValue
|
||||||
|
}
|
||||||
case "pricing/timeFactor":
|
case "pricing/timeFactor":
|
||||||
if val, ok := value.(float64); ok && val >= 0 {
|
if val, ok := value.(float64); ok && val >= 0 {
|
||||||
client.timeFactor = val / 1000000000
|
client.timeFactor = val / 1000000000
|
||||||
|
|
@ -460,7 +475,7 @@ func (v *priorityClientPool) clientInfo(c *priorityClientInfo) map[string]interf
|
||||||
tags = append(tags, tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
clientInfo["userTags"] = tags
|
clientInfo["userTags"] = tags
|
||||||
clientInfo["pricing/totalAmount"] = c.priceTracker.getTotalAmount()
|
clientInfo["pricing/balance"] = c.priceTracker.getBalance()
|
||||||
return clientInfo
|
return clientInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,7 +556,7 @@ func (v *priorityClientPool) priceUpdate(client *priorityClientInfo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setPriceUpdate schedules a price update when the total price reaches the given limit.
|
// setPriceUpdate schedules a price update when the balance reaches the given limit.
|
||||||
// If periodic is false then the limit is interpreted as an absolute value while if true
|
// If periodic is false then the limit is interpreted as an absolute value while if true
|
||||||
// it is relative to the current totalAmount value or the its value at the last future update.
|
// it is relative to the current totalAmount value or the its value at the last future update.
|
||||||
func (v *priorityClientPool) setPriceUpdate(client *priorityClientInfo, value uint64, periodic bool) {
|
func (v *priorityClientPool) setPriceUpdate(client *priorityClientInfo, value uint64, periodic bool) {
|
||||||
|
|
@ -551,7 +566,7 @@ func (v *priorityClientPool) setPriceUpdate(client *priorityClientInfo, value ui
|
||||||
}
|
}
|
||||||
if periodic {
|
if periodic {
|
||||||
client.priceUpdatePeriod = value
|
client.priceUpdatePeriod = value
|
||||||
value += client.priceTracker.getTotalAmount()
|
value = client.priceTracker.getBalance() - value
|
||||||
} else {
|
} else {
|
||||||
client.priceUpdatePeriod = 0
|
client.priceUpdatePeriod = 0
|
||||||
}
|
}
|
||||||
|
|
@ -748,8 +763,8 @@ func (v *priorityClientPool) updatePriceFactors(c *priorityClientInfo) {
|
||||||
// price threshold has been reached.
|
// price threshold has been reached.
|
||||||
type priceTracker struct {
|
type priceTracker struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
totalAmount, callbackThreshold uint64
|
balance, lastBalance, callbackThreshold uint64
|
||||||
callback func()
|
zeroCallback, userCallback func()
|
||||||
timeFactor, requestFactor float64
|
timeFactor, requestFactor float64
|
||||||
lastUpdate, nextUpdate mclock.AbsTime
|
lastUpdate, nextUpdate mclock.AbsTime
|
||||||
updateTimer *time.Timer
|
updateTimer *time.Timer
|
||||||
|
|
@ -759,24 +774,27 @@ type priceTracker struct {
|
||||||
// the next scheduled update if necessary
|
// the next scheduled update if necessary
|
||||||
func (pt *priceTracker) update() {
|
func (pt *priceTracker) update() {
|
||||||
now := mclock.Now()
|
now := mclock.Now()
|
||||||
if pt.lastUpdate != 0 {
|
if pt.lastBalance != 0 && pt.lastUpdate != 0 {
|
||||||
dt := now - pt.lastUpdate
|
dt := now - pt.lastUpdate
|
||||||
if dt > 0 {
|
if dt > 0 {
|
||||||
pt.totalAmount += uint64(pt.timeFactor * float64(dt))
|
amount := uint64(pt.timeFactor * float64(dt))
|
||||||
|
if pt.balance > amount {
|
||||||
|
pt.balance -= amount
|
||||||
|
} else {
|
||||||
|
pt.balance = 0
|
||||||
|
go pt.zeroCallback()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pt.lastUpdate = now
|
pt.lastUpdate = now
|
||||||
if pt.callbackThreshold == 0 || pt.callback == nil {
|
if pt.userCallback != nil && pt.balance <= pt.callbackThreshold {
|
||||||
pt.nextUpdate = 0
|
callback := pt.userCallback
|
||||||
pt.updateAfter(0)
|
pt.userCallback = nil
|
||||||
} else {
|
|
||||||
if pt.totalAmount >= pt.callbackThreshold {
|
|
||||||
pt.callbackThreshold = 0
|
pt.callbackThreshold = 0
|
||||||
pt.nextUpdate = 0
|
go callback()
|
||||||
go pt.callback()
|
}
|
||||||
} else {
|
if pt.balance != 0 && pt.timeFactor > 1e-100 {
|
||||||
if pt.timeFactor > 1e-100 {
|
dt := float64(pt.balance-pt.callbackThreshold) / pt.timeFactor
|
||||||
dt := float64(pt.callbackThreshold-pt.totalAmount) / pt.timeFactor
|
|
||||||
if dt > 1e15 {
|
if dt > 1e15 {
|
||||||
dt = 1e15
|
dt = 1e15
|
||||||
}
|
}
|
||||||
|
|
@ -792,8 +810,7 @@ func (pt *priceTracker) update() {
|
||||||
pt.nextUpdate = 0
|
pt.nextUpdate = 0
|
||||||
pt.updateAfter(0)
|
pt.updateAfter(0)
|
||||||
}
|
}
|
||||||
}
|
pt.lastBalance = pt.balance
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateAfter schedules an update in the future
|
// updateAfter schedules an update in the future
|
||||||
|
|
@ -820,18 +837,64 @@ func (pt *priceTracker) requestCost(cost uint64) {
|
||||||
defer pt.lock.Unlock()
|
defer pt.lock.Unlock()
|
||||||
|
|
||||||
if pt.requestFactor != 0 {
|
if pt.requestFactor != 0 {
|
||||||
pt.totalAmount += uint64(float64(cost) * pt.requestFactor)
|
c := uint64(float64(cost) * pt.requestFactor)
|
||||||
|
if pt.balance > c {
|
||||||
|
pt.balance -= c
|
||||||
|
} else {
|
||||||
|
pt.balance = 0
|
||||||
|
}
|
||||||
pt.update()
|
pt.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTotalAmount returns the current total cost accumulated.
|
// getBalance returns the current balance
|
||||||
func (pt *priceTracker) getTotalAmount() uint64 {
|
func (pt *priceTracker) getBalance() uint64 {
|
||||||
pt.lock.Lock()
|
pt.lock.Lock()
|
||||||
defer pt.lock.Unlock()
|
defer pt.lock.Unlock()
|
||||||
|
|
||||||
pt.update()
|
pt.update()
|
||||||
return pt.totalAmount
|
return pt.balance
|
||||||
|
}
|
||||||
|
|
||||||
|
// setBalance sets the balance to the given value or adds the value to it
|
||||||
|
// Note: it also performs float to int conversion and overflow check. Adding a negative
|
||||||
|
// value bigger than the current balance does not yield an error, just sets the balance
|
||||||
|
// to zero and revokes priority status. User balance alert may also be triggered.
|
||||||
|
func (pt *priceTracker) setBalance(value float64, add bool) error {
|
||||||
|
pt.lock.Lock()
|
||||||
|
defer pt.lock.Unlock()
|
||||||
|
|
||||||
|
pt.update()
|
||||||
|
neg := false
|
||||||
|
if value < 0 {
|
||||||
|
neg = true
|
||||||
|
value = -value
|
||||||
|
}
|
||||||
|
if value > maxBalance {
|
||||||
|
return errBalanceOverflow
|
||||||
|
}
|
||||||
|
v := uint64(value)
|
||||||
|
if add {
|
||||||
|
if neg {
|
||||||
|
if v < pt.balance {
|
||||||
|
pt.balance -= v
|
||||||
|
} else {
|
||||||
|
pt.balance = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if maxBalance-v < pt.balance {
|
||||||
|
return errBalanceOverflow
|
||||||
|
}
|
||||||
|
pt.balance += v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if neg {
|
||||||
|
return errBalanceOverflow
|
||||||
|
}
|
||||||
|
pt.balance = v
|
||||||
|
}
|
||||||
|
pt.update()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setFactors sets the price factors. timeFactor is the price of a nanosecond of
|
// setFactors sets the price factors. timeFactor is the price of a nanosecond of
|
||||||
|
|
@ -853,7 +916,7 @@ func (pt *priceTracker) setCallback(threshold uint64, callback func()) {
|
||||||
defer pt.lock.Unlock()
|
defer pt.lock.Unlock()
|
||||||
|
|
||||||
pt.callbackThreshold = threshold
|
pt.callbackThreshold = threshold
|
||||||
pt.callback = callback
|
pt.userCallback = callback
|
||||||
pt.update()
|
pt.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue