balance.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. // Copyright 2019 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package server
  17. import (
  18. "errors"
  19. "math"
  20. "sync"
  21. "time"
  22. "github.com/ethereum/go-ethereum/common/mclock"
  23. "github.com/ethereum/go-ethereum/les/utils"
  24. "github.com/ethereum/go-ethereum/p2p/enode"
  25. "github.com/ethereum/go-ethereum/p2p/nodestate"
  26. )
  27. var errBalanceOverflow = errors.New("balance overflow")
  28. const maxBalance = math.MaxInt64 // maximum allowed balance value
  29. const (
  30. balanceCallbackUpdate = iota // called when priority drops below the last minimum estimate
  31. balanceCallbackZero // called when priority drops to zero (positive balance exhausted)
  32. balanceCallbackCount // total number of balance callbacks
  33. )
  34. // PriceFactors determine the pricing policy (may apply either to positive or
  35. // negative balances which may have different factors).
  36. // - TimeFactor is cost unit per nanosecond of connection time
  37. // - CapacityFactor is cost unit per nanosecond of connection time per 1000000 capacity
  38. // - RequestFactor is cost unit per request "realCost" unit
  39. type PriceFactors struct {
  40. TimeFactor, CapacityFactor, RequestFactor float64
  41. }
  42. // timePrice returns the price of connection per nanosecond at the given capacity
  43. func (p PriceFactors) timePrice(cap uint64) float64 {
  44. return p.TimeFactor + float64(cap)*p.CapacityFactor/1000000
  45. }
  46. // NodeBalance keeps track of the positive and negative balances of a connected
  47. // client and calculates actual and projected future priority values.
  48. // Implements nodePriority interface.
  49. type NodeBalance struct {
  50. bt *BalanceTracker
  51. lock sync.RWMutex
  52. node *enode.Node
  53. connAddress string
  54. active bool
  55. priority bool
  56. capacity uint64
  57. balance balance
  58. posFactor, negFactor PriceFactors
  59. sumReqCost uint64
  60. lastUpdate, nextUpdate, initTime mclock.AbsTime
  61. updateEvent mclock.Timer
  62. // since only a limited and fixed number of callbacks are needed, they are
  63. // stored in a fixed size array ordered by priority threshold.
  64. callbacks [balanceCallbackCount]balanceCallback
  65. // callbackIndex maps balanceCallback constants to callbacks array indexes (-1 if not active)
  66. callbackIndex [balanceCallbackCount]int
  67. callbackCount int // number of active callbacks
  68. }
  69. // balance represents a pair of positive and negative balances
  70. type balance struct {
  71. pos, neg utils.ExpiredValue
  72. }
  73. // balanceCallback represents a single callback that is activated when client priority
  74. // reaches the given threshold
  75. type balanceCallback struct {
  76. id int
  77. threshold int64
  78. callback func()
  79. }
  80. // GetBalance returns the current positive and negative balance.
  81. func (n *NodeBalance) GetBalance() (uint64, uint64) {
  82. n.lock.Lock()
  83. defer n.lock.Unlock()
  84. now := n.bt.clock.Now()
  85. n.updateBalance(now)
  86. return n.balance.pos.Value(n.bt.posExp.LogOffset(now)), n.balance.neg.Value(n.bt.negExp.LogOffset(now))
  87. }
  88. // GetRawBalance returns the current positive and negative balance
  89. // but in the raw(expired value) format.
  90. func (n *NodeBalance) GetRawBalance() (utils.ExpiredValue, utils.ExpiredValue) {
  91. n.lock.Lock()
  92. defer n.lock.Unlock()
  93. now := n.bt.clock.Now()
  94. n.updateBalance(now)
  95. return n.balance.pos, n.balance.neg
  96. }
  97. // AddBalance adds the given amount to the positive balance and returns the balance
  98. // before and after the operation. Exceeding maxBalance results in an error (balance is
  99. // unchanged) while adding a negative amount higher than the current balance results in
  100. // zero balance.
  101. func (n *NodeBalance) AddBalance(amount int64) (uint64, uint64, error) {
  102. var (
  103. err error
  104. old, new uint64
  105. )
  106. n.bt.ns.Operation(func() {
  107. var (
  108. callbacks []func()
  109. setPriority bool
  110. )
  111. n.bt.updateTotalBalance(n, func() bool {
  112. now := n.bt.clock.Now()
  113. n.updateBalance(now)
  114. // Ensure the given amount is valid to apply.
  115. offset := n.bt.posExp.LogOffset(now)
  116. old = n.balance.pos.Value(offset)
  117. if amount > 0 && (amount > maxBalance || old > maxBalance-uint64(amount)) {
  118. err = errBalanceOverflow
  119. return false
  120. }
  121. // Update the total positive balance counter.
  122. n.balance.pos.Add(amount, offset)
  123. callbacks = n.checkCallbacks(now)
  124. setPriority = n.checkPriorityStatus()
  125. new = n.balance.pos.Value(offset)
  126. n.storeBalance(true, false)
  127. return true
  128. })
  129. for _, cb := range callbacks {
  130. cb()
  131. }
  132. if setPriority {
  133. n.bt.ns.SetStateSub(n.node, n.bt.PriorityFlag, nodestate.Flags{}, 0)
  134. }
  135. n.signalPriorityUpdate()
  136. })
  137. if err != nil {
  138. return old, old, err
  139. }
  140. return old, new, nil
  141. }
  142. // SetBalance sets the positive and negative balance to the given values
  143. func (n *NodeBalance) SetBalance(pos, neg uint64) error {
  144. if pos > maxBalance || neg > maxBalance {
  145. return errBalanceOverflow
  146. }
  147. n.bt.ns.Operation(func() {
  148. var (
  149. callbacks []func()
  150. setPriority bool
  151. )
  152. n.bt.updateTotalBalance(n, func() bool {
  153. now := n.bt.clock.Now()
  154. n.updateBalance(now)
  155. var pb, nb utils.ExpiredValue
  156. pb.Add(int64(pos), n.bt.posExp.LogOffset(now))
  157. nb.Add(int64(neg), n.bt.negExp.LogOffset(now))
  158. n.balance.pos = pb
  159. n.balance.neg = nb
  160. callbacks = n.checkCallbacks(now)
  161. setPriority = n.checkPriorityStatus()
  162. n.storeBalance(true, true)
  163. return true
  164. })
  165. for _, cb := range callbacks {
  166. cb()
  167. }
  168. if setPriority {
  169. n.bt.ns.SetStateSub(n.node, n.bt.PriorityFlag, nodestate.Flags{}, 0)
  170. }
  171. n.signalPriorityUpdate()
  172. })
  173. return nil
  174. }
  175. // RequestServed should be called after serving a request for the given peer
  176. func (n *NodeBalance) RequestServed(cost uint64) uint64 {
  177. n.lock.Lock()
  178. var callbacks []func()
  179. defer func() {
  180. n.lock.Unlock()
  181. if callbacks != nil {
  182. n.bt.ns.Operation(func() {
  183. for _, cb := range callbacks {
  184. cb()
  185. }
  186. })
  187. }
  188. }()
  189. now := n.bt.clock.Now()
  190. n.updateBalance(now)
  191. fcost := float64(cost)
  192. posExp := n.bt.posExp.LogOffset(now)
  193. var check bool
  194. if !n.balance.pos.IsZero() {
  195. if n.posFactor.RequestFactor != 0 {
  196. c := -int64(fcost * n.posFactor.RequestFactor)
  197. cc := n.balance.pos.Add(c, posExp)
  198. if c == cc {
  199. fcost = 0
  200. } else {
  201. fcost *= 1 - float64(cc)/float64(c)
  202. }
  203. check = true
  204. } else {
  205. fcost = 0
  206. }
  207. }
  208. if fcost > 0 {
  209. if n.negFactor.RequestFactor != 0 {
  210. n.balance.neg.Add(int64(fcost*n.negFactor.RequestFactor), n.bt.negExp.LogOffset(now))
  211. check = true
  212. }
  213. }
  214. if check {
  215. callbacks = n.checkCallbacks(now)
  216. }
  217. n.sumReqCost += cost
  218. return n.balance.pos.Value(posExp)
  219. }
  220. // Priority returns the actual priority based on the current balance
  221. func (n *NodeBalance) Priority(now mclock.AbsTime, capacity uint64) int64 {
  222. n.lock.Lock()
  223. defer n.lock.Unlock()
  224. n.updateBalance(now)
  225. return n.balanceToPriority(n.balance, capacity)
  226. }
  227. // EstMinPriority gives a lower estimate for the priority at a given time in the future.
  228. // An average request cost per time is assumed that is twice the average cost per time
  229. // in the current session.
  230. // If update is true then a priority callback is added that turns UpdateFlag on and off
  231. // in case the priority goes below the estimated minimum.
  232. func (n *NodeBalance) EstMinPriority(at mclock.AbsTime, capacity uint64, update bool) int64 {
  233. n.lock.Lock()
  234. defer n.lock.Unlock()
  235. var avgReqCost float64
  236. dt := time.Duration(n.lastUpdate - n.initTime)
  237. if dt > time.Second {
  238. avgReqCost = float64(n.sumReqCost) * 2 / float64(dt)
  239. }
  240. pri := n.balanceToPriority(n.reducedBalance(at, capacity, avgReqCost), capacity)
  241. if update {
  242. n.addCallback(balanceCallbackUpdate, pri, n.signalPriorityUpdate)
  243. }
  244. return pri
  245. }
  246. // PosBalanceMissing calculates the missing amount of positive balance in order to
  247. // connect at targetCapacity, stay connected for the given amount of time and then
  248. // still have a priority of targetPriority
  249. func (n *NodeBalance) PosBalanceMissing(targetPriority int64, targetCapacity uint64, after time.Duration) uint64 {
  250. n.lock.Lock()
  251. defer n.lock.Unlock()
  252. now := n.bt.clock.Now()
  253. if targetPriority < 0 {
  254. timePrice := n.negFactor.timePrice(targetCapacity)
  255. timeCost := uint64(float64(after) * timePrice)
  256. negBalance := n.balance.neg.Value(n.bt.negExp.LogOffset(now))
  257. if timeCost+negBalance < uint64(-targetPriority) {
  258. return 0
  259. }
  260. if uint64(-targetPriority) > negBalance && timePrice > 1e-100 {
  261. if negTime := time.Duration(float64(uint64(-targetPriority)-negBalance) / timePrice); negTime < after {
  262. after -= negTime
  263. } else {
  264. after = 0
  265. }
  266. }
  267. targetPriority = 0
  268. }
  269. timePrice := n.posFactor.timePrice(targetCapacity)
  270. posRequired := uint64(float64(targetPriority)*float64(targetCapacity)+float64(after)*timePrice) + 1
  271. if posRequired >= maxBalance {
  272. return math.MaxUint64 // target not reachable
  273. }
  274. posBalance := n.balance.pos.Value(n.bt.posExp.LogOffset(now))
  275. if posRequired > posBalance {
  276. return posRequired - posBalance
  277. }
  278. return 0
  279. }
  280. // SetPriceFactors sets the price factors. TimeFactor is the price of a nanosecond of
  281. // connection while RequestFactor is the price of a request cost unit.
  282. func (n *NodeBalance) SetPriceFactors(posFactor, negFactor PriceFactors) {
  283. n.lock.Lock()
  284. now := n.bt.clock.Now()
  285. n.updateBalance(now)
  286. n.posFactor, n.negFactor = posFactor, negFactor
  287. callbacks := n.checkCallbacks(now)
  288. n.lock.Unlock()
  289. if callbacks != nil {
  290. n.bt.ns.Operation(func() {
  291. for _, cb := range callbacks {
  292. cb()
  293. }
  294. })
  295. }
  296. }
  297. // GetPriceFactors returns the price factors
  298. func (n *NodeBalance) GetPriceFactors() (posFactor, negFactor PriceFactors) {
  299. n.lock.Lock()
  300. defer n.lock.Unlock()
  301. return n.posFactor, n.negFactor
  302. }
  303. // activate starts time/capacity cost deduction.
  304. func (n *NodeBalance) activate() {
  305. n.bt.updateTotalBalance(n, func() bool {
  306. if n.active {
  307. return false
  308. }
  309. n.active = true
  310. n.lastUpdate = n.bt.clock.Now()
  311. return true
  312. })
  313. }
  314. // deactivate stops time/capacity cost deduction and saves the balances in the database
  315. func (n *NodeBalance) deactivate() {
  316. n.bt.updateTotalBalance(n, func() bool {
  317. if !n.active {
  318. return false
  319. }
  320. n.updateBalance(n.bt.clock.Now())
  321. if n.updateEvent != nil {
  322. n.updateEvent.Stop()
  323. n.updateEvent = nil
  324. }
  325. n.storeBalance(true, true)
  326. n.active = false
  327. return true
  328. })
  329. }
  330. // updateBalance updates balance based on the time factor
  331. func (n *NodeBalance) updateBalance(now mclock.AbsTime) {
  332. if n.active && now > n.lastUpdate {
  333. n.balance = n.reducedBalance(now, n.capacity, 0)
  334. n.lastUpdate = now
  335. }
  336. }
  337. // storeBalance stores the positive and/or negative balance of the node in the database
  338. func (n *NodeBalance) storeBalance(pos, neg bool) {
  339. if pos {
  340. n.bt.storeBalance(n.node.ID().Bytes(), false, n.balance.pos)
  341. }
  342. if neg {
  343. n.bt.storeBalance([]byte(n.connAddress), true, n.balance.neg)
  344. }
  345. }
  346. // addCallback sets up a one-time callback to be called when priority reaches
  347. // the threshold. If it has already reached the threshold the callback is called
  348. // immediately.
  349. // Note: should be called while n.lock is held
  350. // Note 2: the callback function runs inside a NodeStateMachine operation
  351. func (n *NodeBalance) addCallback(id int, threshold int64, callback func()) {
  352. n.removeCallback(id)
  353. idx := 0
  354. for idx < n.callbackCount && threshold > n.callbacks[idx].threshold {
  355. idx++
  356. }
  357. for i := n.callbackCount - 1; i >= idx; i-- {
  358. n.callbackIndex[n.callbacks[i].id]++
  359. n.callbacks[i+1] = n.callbacks[i]
  360. }
  361. n.callbackCount++
  362. n.callbackIndex[id] = idx
  363. n.callbacks[idx] = balanceCallback{id, threshold, callback}
  364. now := n.bt.clock.Now()
  365. n.updateBalance(now)
  366. n.scheduleCheck(now)
  367. }
  368. // removeCallback removes the given callback and returns true if it was active
  369. // Note: should be called while n.lock is held
  370. func (n *NodeBalance) removeCallback(id int) bool {
  371. idx := n.callbackIndex[id]
  372. if idx == -1 {
  373. return false
  374. }
  375. n.callbackIndex[id] = -1
  376. for i := idx; i < n.callbackCount-1; i++ {
  377. n.callbackIndex[n.callbacks[i+1].id]--
  378. n.callbacks[i] = n.callbacks[i+1]
  379. }
  380. n.callbackCount--
  381. return true
  382. }
  383. // checkCallbacks checks whether the threshold of any of the active callbacks
  384. // have been reached and returns triggered callbacks.
  385. // Note: checkCallbacks assumes that the balance has been recently updated.
  386. func (n *NodeBalance) checkCallbacks(now mclock.AbsTime) (callbacks []func()) {
  387. if n.callbackCount == 0 || n.capacity == 0 {
  388. return
  389. }
  390. pri := n.balanceToPriority(n.balance, n.capacity)
  391. for n.callbackCount != 0 && n.callbacks[n.callbackCount-1].threshold >= pri {
  392. n.callbackCount--
  393. n.callbackIndex[n.callbacks[n.callbackCount].id] = -1
  394. callbacks = append(callbacks, n.callbacks[n.callbackCount].callback)
  395. }
  396. n.scheduleCheck(now)
  397. return
  398. }
  399. // scheduleCheck sets up or updates a scheduled event to ensure that it will be called
  400. // again just after the next threshold has been reached.
  401. func (n *NodeBalance) scheduleCheck(now mclock.AbsTime) {
  402. if n.callbackCount != 0 {
  403. d, ok := n.timeUntil(n.callbacks[n.callbackCount-1].threshold)
  404. if !ok {
  405. n.nextUpdate = 0
  406. n.updateAfter(0)
  407. return
  408. }
  409. if n.nextUpdate == 0 || n.nextUpdate > now+mclock.AbsTime(d) {
  410. if d > time.Second {
  411. // Note: if the scheduled update is not in the very near future then we
  412. // schedule the update a bit earlier. This way we do need to update a few
  413. // extra times but don't need to reschedule every time a processed request
  414. // brings the expected firing time a little bit closer.
  415. d = ((d - time.Second) * 7 / 8) + time.Second
  416. }
  417. n.nextUpdate = now + mclock.AbsTime(d)
  418. n.updateAfter(d)
  419. }
  420. } else {
  421. n.nextUpdate = 0
  422. n.updateAfter(0)
  423. }
  424. }
  425. // updateAfter schedules a balance update and callback check in the future
  426. func (n *NodeBalance) updateAfter(dt time.Duration) {
  427. if n.updateEvent == nil || n.updateEvent.Stop() {
  428. if dt == 0 {
  429. n.updateEvent = nil
  430. } else {
  431. n.updateEvent = n.bt.clock.AfterFunc(dt, func() {
  432. var callbacks []func()
  433. n.lock.Lock()
  434. if n.callbackCount != 0 {
  435. now := n.bt.clock.Now()
  436. n.updateBalance(now)
  437. callbacks = n.checkCallbacks(now)
  438. }
  439. n.lock.Unlock()
  440. if callbacks != nil {
  441. n.bt.ns.Operation(func() {
  442. for _, cb := range callbacks {
  443. cb()
  444. }
  445. })
  446. }
  447. })
  448. }
  449. }
  450. }
  451. // balanceExhausted should be called when the positive balance is exhausted (priority goes to zero/negative)
  452. // Note: this function should run inside a NodeStateMachine operation
  453. func (n *NodeBalance) balanceExhausted() {
  454. n.lock.Lock()
  455. n.storeBalance(true, false)
  456. n.priority = false
  457. n.lock.Unlock()
  458. n.bt.ns.SetStateSub(n.node, nodestate.Flags{}, n.bt.PriorityFlag, 0)
  459. }
  460. // checkPriorityStatus checks whether the node has gained priority status and sets the priority
  461. // callback and flag if necessary. It assumes that the balance has been recently updated.
  462. // Note that the priority flag has to be set by the caller after the mutex has been released.
  463. func (n *NodeBalance) checkPriorityStatus() bool {
  464. if !n.priority && !n.balance.pos.IsZero() {
  465. n.priority = true
  466. n.addCallback(balanceCallbackZero, 0, func() { n.balanceExhausted() })
  467. return true
  468. }
  469. return false
  470. }
  471. // signalPriorityUpdate signals that the priority fell below the previous minimum estimate
  472. // Note: this function should run inside a NodeStateMachine operation
  473. func (n *NodeBalance) signalPriorityUpdate() {
  474. n.bt.ns.SetStateSub(n.node, n.bt.UpdateFlag, nodestate.Flags{}, 0)
  475. n.bt.ns.SetStateSub(n.node, nodestate.Flags{}, n.bt.UpdateFlag, 0)
  476. }
  477. // setCapacity updates the capacity value used for priority calculation
  478. // Note: capacity should never be zero
  479. // Note 2: this function should run inside a NodeStateMachine operation
  480. func (n *NodeBalance) setCapacity(capacity uint64) {
  481. n.lock.Lock()
  482. now := n.bt.clock.Now()
  483. n.updateBalance(now)
  484. n.capacity = capacity
  485. callbacks := n.checkCallbacks(now)
  486. n.lock.Unlock()
  487. for _, cb := range callbacks {
  488. cb()
  489. }
  490. }
  491. // balanceToPriority converts a balance to a priority value. Lower priority means
  492. // first to disconnect. Positive balance translates to positive priority. If positive
  493. // balance is zero then negative balance translates to a negative priority.
  494. func (n *NodeBalance) balanceToPriority(b balance, capacity uint64) int64 {
  495. if !b.pos.IsZero() {
  496. return int64(b.pos.Value(n.bt.posExp.LogOffset(n.bt.clock.Now())) / capacity)
  497. }
  498. return -int64(b.neg.Value(n.bt.negExp.LogOffset(n.bt.clock.Now())))
  499. }
  500. // reducedBalance estimates the reduced balance at a given time in the fututre based
  501. // on the current balance, the time factor and an estimated average request cost per time ratio
  502. func (n *NodeBalance) reducedBalance(at mclock.AbsTime, capacity uint64, avgReqCost float64) balance {
  503. dt := float64(at - n.lastUpdate)
  504. b := n.balance
  505. if !b.pos.IsZero() {
  506. factor := n.posFactor.timePrice(capacity) + n.posFactor.RequestFactor*avgReqCost
  507. diff := -int64(dt * factor)
  508. dd := b.pos.Add(diff, n.bt.posExp.LogOffset(at))
  509. if dd == diff {
  510. dt = 0
  511. } else {
  512. dt += float64(dd) / factor
  513. }
  514. }
  515. if dt > 0 {
  516. factor := n.negFactor.timePrice(capacity) + n.negFactor.RequestFactor*avgReqCost
  517. b.neg.Add(int64(dt*factor), n.bt.negExp.LogOffset(at))
  518. }
  519. return b
  520. }
  521. // timeUntil calculates the remaining time needed to reach a given priority level
  522. // assuming that no requests are processed until then. If the given level is never
  523. // reached then (0, false) is returned.
  524. // Note: the function assumes that the balance has been recently updated and
  525. // calculates the time starting from the last update.
  526. func (n *NodeBalance) timeUntil(priority int64) (time.Duration, bool) {
  527. now := n.bt.clock.Now()
  528. var dt float64
  529. if !n.balance.pos.IsZero() {
  530. posBalance := n.balance.pos.Value(n.bt.posExp.LogOffset(now))
  531. timePrice := n.posFactor.timePrice(n.capacity)
  532. if timePrice < 1e-100 {
  533. return 0, false
  534. }
  535. if priority > 0 {
  536. newBalance := uint64(priority) * n.capacity
  537. if newBalance > posBalance {
  538. return 0, false
  539. }
  540. dt = float64(posBalance-newBalance) / timePrice
  541. return time.Duration(dt), true
  542. }
  543. dt = float64(posBalance) / timePrice
  544. } else {
  545. if priority > 0 {
  546. return 0, false
  547. }
  548. }
  549. // if we have a positive balance then dt equals the time needed to get it to zero
  550. negBalance := n.balance.neg.Value(n.bt.negExp.LogOffset(now))
  551. timePrice := n.negFactor.timePrice(n.capacity)
  552. if uint64(-priority) > negBalance {
  553. if timePrice < 1e-100 {
  554. return 0, false
  555. }
  556. dt += float64(uint64(-priority)-negBalance) / timePrice
  557. }
  558. return time.Duration(dt), true
  559. }