2025-12-18 18:23:09 +01:00
|
|
|
## Logos Storage
|
2022-05-19 16:28:53 -06:00
|
|
|
## Copyright (c) 2021 Status Research & Development GmbH
|
|
|
|
|
## Licensed under either of
|
|
|
|
|
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
|
|
|
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
|
|
|
## at your option.
|
|
|
|
|
## This file may not be copied, modified, or distributed except according to
|
|
|
|
|
## those terms.
|
|
|
|
|
|
2021-04-12 11:43:54 +02:00
|
|
|
import std/sequtils
|
2021-04-26 17:11:11 +02:00
|
|
|
import std/tables
|
2023-11-14 13:02:17 +01:00
|
|
|
import std/sets
|
2022-11-15 09:46:21 -06:00
|
|
|
|
2021-04-12 11:43:54 +02:00
|
|
|
import pkg/libp2p
|
|
|
|
|
import pkg/chronos
|
2021-04-14 16:07:49 +02:00
|
|
|
import pkg/nitro
|
2021-04-12 11:43:54 +02:00
|
|
|
import pkg/questionable
|
2022-05-18 20:29:15 -06:00
|
|
|
|
2022-05-19 16:28:53 -06:00
|
|
|
import ../protobuf/blockexc
|
|
|
|
|
import ../protobuf/payments
|
|
|
|
|
import ../protobuf/presence
|
2021-04-12 11:43:54 +02:00
|
|
|
|
2023-11-14 13:02:17 +01:00
|
|
|
import ../../blocktype
|
feat: create logging proxy (#663)
* implement a logging proxy
The logging proxy:
- prevents the need to import chronicles (as well as export except toJson),
- prevents the need to override `writeValue` or use or import nim-json-seralization elsewhere in the codebase, allowing for sole use of utils/json for de/serialization,
- and handles json formatting correctly in chronicles json sinks
* Rename logging -> logutils to avoid ambiguity with common names
* clean up
* add setProperty for JsonRecord, remove nim-json-serialization conflict
* Allow specifying textlines and json format separately
Not specifying a LogFormat will apply the formatting to both textlines and json sinks.
Specifying a LogFormat will apply the formatting to only that sink.
* remove unneeded usages of std/json
We only need to import utils/json instead of std/json
* move serialization from rest/json to utils/json so it can be shared
* fix NoColors ambiguity
Was causing unit tests to fail on Windows.
* Remove nre usage to fix Windows error
Windows was erroring with `could not load: pcre64.dll`. Instead of fixing that error, remove the pcre usage :)
* Add logutils module doc
* Shorten logutils.formatIt for `NBytes`
Both json and textlines formatIt were not needed, and could be combined into one formatIt
* remove debug integration test config
debug output and logformat of json for integration test logs
* Use ## module doc to support docgen
* bump nim-poseidon2 to export fromBytes
Before the changes in this branch, fromBytes was likely being resolved by nim-stew, or other dependency. With the changes in this branch, that dependency was removed and fromBytes could no longer be resolved. By exporting fromBytes from nim-poseidon, the correct resolution is now happening.
* fixes to get compiling after rebasing master
* Add support for Result types being logged using formatIt
2024-01-23 18:35:03 +11:00
|
|
|
import ../../logutils
|
2023-11-14 13:02:17 +01:00
|
|
|
|
2021-08-30 13:25:20 -06:00
|
|
|
export payments, nitro
|
2021-04-14 16:07:49 +02:00
|
|
|
|
2025-11-13 07:47:02 +02:00
|
|
|
const
|
|
|
|
|
MinRefreshInterval = 1.seconds
|
|
|
|
|
MaxRefreshBackoff = 36 # 36 seconds
|
|
|
|
|
MaxWantListBatchSize* = 1024 # Maximum blocks to send per WantList message
|
|
|
|
|
|
2021-08-30 13:25:20 -06:00
|
|
|
type BlockExcPeerCtx* = ref object of RootObj
|
2023-03-10 08:02:54 +01:00
|
|
|
id*: PeerId
|
2023-12-22 06:04:01 -06:00
|
|
|
blocks*: Table[BlockAddress, Presence] # remote peer have list including price
|
2025-11-13 07:47:02 +02:00
|
|
|
wantedBlocks*: HashSet[BlockAddress] # blocks that the peer wants
|
2023-12-22 06:04:01 -06:00
|
|
|
exchanged*: int # times peer has exchanged with us
|
2025-11-13 07:47:02 +02:00
|
|
|
refreshInProgress*: bool # indicates if a refresh is in progress
|
|
|
|
|
lastRefresh*: Moment # last time we refreshed our knowledge of the blocks this peer has
|
|
|
|
|
refreshBackoff*: int = 1 # backoff factor for refresh requests
|
2023-12-22 06:04:01 -06:00
|
|
|
account*: ?Account # ethereum account of this peer
|
|
|
|
|
paymentChannel*: ?ChannelId # payment channel id
|
2025-11-13 07:47:02 +02:00
|
|
|
blocksSent*: HashSet[BlockAddress] # blocks sent to peer
|
|
|
|
|
blocksRequested*: HashSet[BlockAddress] # pending block requests to this peer
|
|
|
|
|
lastExchange*: Moment # last time peer has sent us a block
|
|
|
|
|
activityTimeout*: Duration
|
|
|
|
|
lastSentWants*: HashSet[BlockAddress]
|
|
|
|
|
# track what wantList we last sent for delta updates
|
|
|
|
|
|
|
|
|
|
proc isKnowledgeStale*(self: BlockExcPeerCtx): bool =
|
|
|
|
|
let staleness =
|
|
|
|
|
self.lastRefresh + self.refreshBackoff * MinRefreshInterval < Moment.now()
|
|
|
|
|
|
|
|
|
|
if staleness and self.refreshInProgress:
|
|
|
|
|
trace "Cleaning up refresh state", peer = self.id
|
|
|
|
|
self.refreshInProgress = false
|
|
|
|
|
self.refreshBackoff = 1
|
|
|
|
|
|
|
|
|
|
staleness
|
|
|
|
|
|
|
|
|
|
proc isBlockSent*(self: BlockExcPeerCtx, address: BlockAddress): bool =
|
|
|
|
|
address in self.blocksSent
|
|
|
|
|
|
|
|
|
|
proc markBlockAsSent*(self: BlockExcPeerCtx, address: BlockAddress) =
|
|
|
|
|
self.blocksSent.incl(address)
|
|
|
|
|
|
|
|
|
|
proc markBlockAsNotSent*(self: BlockExcPeerCtx, address: BlockAddress) =
|
|
|
|
|
self.blocksSent.excl(address)
|
|
|
|
|
|
|
|
|
|
proc refreshRequested*(self: BlockExcPeerCtx) =
|
|
|
|
|
trace "Refresh requested for peer", peer = self.id, backoff = self.refreshBackoff
|
|
|
|
|
self.refreshInProgress = true
|
|
|
|
|
self.lastRefresh = Moment.now()
|
2021-04-12 11:43:54 +02:00
|
|
|
|
2025-11-13 07:47:02 +02:00
|
|
|
proc refreshReplied*(self: BlockExcPeerCtx) =
|
|
|
|
|
self.refreshInProgress = false
|
|
|
|
|
self.lastRefresh = Moment.now()
|
|
|
|
|
self.refreshBackoff = min(self.refreshBackoff * 2, MaxRefreshBackoff)
|
2021-05-10 14:08:40 +02:00
|
|
|
|
2025-11-13 07:47:02 +02:00
|
|
|
proc havesUpdated(self: BlockExcPeerCtx) =
|
|
|
|
|
self.refreshBackoff = 1
|
2023-11-14 13:02:17 +01:00
|
|
|
|
2025-11-13 07:47:02 +02:00
|
|
|
proc wantsUpdated*(self: BlockExcPeerCtx) =
|
|
|
|
|
self.refreshBackoff = 1
|
|
|
|
|
|
|
|
|
|
proc peerHave*(self: BlockExcPeerCtx): HashSet[BlockAddress] =
|
|
|
|
|
# XXX: this is ugly an inefficient, but since those will typically
|
|
|
|
|
# be used in "joins", it's better to pay the price here and have
|
|
|
|
|
# a linear join than to not do it and have a quadratic join.
|
|
|
|
|
toHashSet(self.blocks.keys.toSeq)
|
2023-11-14 13:02:17 +01:00
|
|
|
|
|
|
|
|
proc contains*(self: BlockExcPeerCtx, address: BlockAddress): bool =
|
|
|
|
|
address in self.blocks
|
2021-04-12 11:43:54 +02:00
|
|
|
|
2022-11-15 09:46:21 -06:00
|
|
|
func setPresence*(self: BlockExcPeerCtx, presence: Presence) =
|
2025-11-13 07:47:02 +02:00
|
|
|
if presence.address notin self.blocks:
|
|
|
|
|
self.havesUpdated()
|
|
|
|
|
|
2023-11-14 13:02:17 +01:00
|
|
|
self.blocks[presence.address] = presence
|
2021-04-12 11:43:54 +02:00
|
|
|
|
2023-11-14 13:02:17 +01:00
|
|
|
func cleanPresence*(self: BlockExcPeerCtx, addresses: seq[BlockAddress]) =
|
|
|
|
|
for a in addresses:
|
|
|
|
|
self.blocks.del(a)
|
2021-04-26 17:11:11 +02:00
|
|
|
|
2023-11-14 13:02:17 +01:00
|
|
|
func cleanPresence*(self: BlockExcPeerCtx, address: BlockAddress) =
|
|
|
|
|
self.cleanPresence(@[address])
|
2021-05-10 13:47:15 +02:00
|
|
|
|
2023-11-14 13:02:17 +01:00
|
|
|
func price*(self: BlockExcPeerCtx, addresses: seq[BlockAddress]): UInt256 =
|
2022-11-15 09:46:21 -06:00
|
|
|
var price = 0.u256
|
2023-11-14 13:02:17 +01:00
|
|
|
for a in addresses:
|
|
|
|
|
self.blocks.withValue(a, precense):
|
2022-11-15 09:46:21 -06:00
|
|
|
price += precense[].price
|
|
|
|
|
|
|
|
|
|
price
|
2025-11-13 07:47:02 +02:00
|
|
|
|
|
|
|
|
proc blockRequestScheduled*(self: BlockExcPeerCtx, address: BlockAddress) =
|
|
|
|
|
## Adds a block the set of blocks that have been requested to this peer
|
|
|
|
|
## (its request schedule).
|
|
|
|
|
if self.blocksRequested.len == 0:
|
|
|
|
|
self.lastExchange = Moment.now()
|
|
|
|
|
self.blocksRequested.incl(address)
|
|
|
|
|
|
|
|
|
|
proc blockRequestCancelled*(self: BlockExcPeerCtx, address: BlockAddress) =
|
|
|
|
|
## Removes a block from the set of blocks that have been requested to this peer
|
|
|
|
|
## (its request schedule).
|
|
|
|
|
self.blocksRequested.excl(address)
|
|
|
|
|
|
|
|
|
|
proc blockReceived*(self: BlockExcPeerCtx, address: BlockAddress): bool =
|
|
|
|
|
let wasRequested = address in self.blocksRequested
|
|
|
|
|
self.blocksRequested.excl(address)
|
|
|
|
|
self.lastExchange = Moment.now()
|
|
|
|
|
wasRequested
|
|
|
|
|
|
|
|
|
|
proc activityTimer*(
|
|
|
|
|
self: BlockExcPeerCtx
|
|
|
|
|
): Future[void] {.async: (raises: [CancelledError]).} =
|
|
|
|
|
## This is called by the block exchange when a block is scheduled for this peer.
|
|
|
|
|
## If the peer sends no blocks for a while, it is considered inactive/uncooperative
|
|
|
|
|
## and the peer is dropped. Note that ANY block that the peer sends will reset this
|
|
|
|
|
## timer for all blocks.
|
|
|
|
|
##
|
|
|
|
|
while true:
|
|
|
|
|
let idleTime = Moment.now() - self.lastExchange
|
|
|
|
|
if idleTime > self.activityTimeout:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
await sleepAsync(self.activityTimeout - idleTime)
|