mirror of
https://github.com/Rucknium/xmrpeers.git
synced 2025-01-31 06:45:53 +00:00
Add newborn.nodes() function
This commit is contained in:
parent
9313206163
commit
dad70df027
4 changed files with 194 additions and 2 deletions
|
@ -25,7 +25,9 @@ Imports:
|
||||||
parallelly,
|
parallelly,
|
||||||
future,
|
future,
|
||||||
future.apply,
|
future.apply,
|
||||||
qs
|
qs,
|
||||||
|
RCurl,
|
||||||
|
RJSONIO
|
||||||
Suggests:
|
Suggests:
|
||||||
archive,
|
archive,
|
||||||
testthat (>= 3.0.0),
|
testthat (>= 3.0.0),
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
export("ping.peers")
|
export("ping.peers")
|
||||||
export("get.p2p.log")
|
export("get.p2p.log")
|
||||||
export("compress.log")
|
export("compress.log")
|
||||||
|
export("newborn.nodes")
|
||||||
importFrom("utils", "read.csv", "untar", "installed.packages")
|
importFrom("utils", "read.csv", "untar", "installed.packages")
|
||||||
importFrom("stats", "complete.cases")
|
importFrom("stats", "complete.cases", "quantile")
|
||||||
|
|
136
R/newborn.R
Normal file
136
R/newborn.R
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
|
||||||
|
|
||||||
|
#' Print likely newborn nodes to the console
|
||||||
|
#'
|
||||||
|
#' @description When a node connects to our own node, it could be a newborn
|
||||||
|
#' node that is syncing from the genesis block. `newborn.nodes` queries the
|
||||||
|
#' local Monero node about node connections with a `get_peers` call and prints
|
||||||
|
#' information about likely newborn nodes to the console. The unrestricted RPC
|
||||||
|
#' port must be reachable by R. This function is an infinite loop. `ctrl + c`
|
||||||
|
#' to interrupt the function and print all IP addresses of likely newborn nodes
|
||||||
|
#' recorded so far. Each peer will only be printed once during a specific run of
|
||||||
|
#' `newborn.nodes`, even if the node disconnects and reconnects later.
|
||||||
|
#'
|
||||||
|
#' @param unrestricted.rpc.url URL and port of the monerod unrestricted RPC.
|
||||||
|
#' Default is `http://127.0.0.1:18081`
|
||||||
|
#' @param poll.time How often, in seconds, to check for a newborn node
|
||||||
|
#' connection. Default is 30 seconds.
|
||||||
|
#' @param sync.height.lag Criteria to consider a node as "newborn". Nodes that
|
||||||
|
#' have a height greater than current network height minus `sync.height.lag`
|
||||||
|
#' will not be considered a newborn node. Default is 3 months.
|
||||||
|
#' @param avg_upload.limit Criteria to consider a node as "newborn". The
|
||||||
|
#' `avg_upload` from the `get_peers` call must be greater than or equal to
|
||||||
|
#' `avg_upload.limit` OR `current_upload` must be greater than or equal to
|
||||||
|
#' `current_upload.limit` to consider the node as "newborn". Default is 10 for
|
||||||
|
#' both limits. Sometimes a node gets stuck at a low height, so it isn't
|
||||||
|
#' actually new or syncing. This criteria makes sure that the peer is actually
|
||||||
|
#' actively syncing data.
|
||||||
|
#' @param current_upload.limit Criteria to consider a node as "newborn".
|
||||||
|
#'
|
||||||
|
#' @return
|
||||||
|
#' NULL (invisible)
|
||||||
|
#' @export
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' newborn.nodes()
|
||||||
|
#' }
|
||||||
|
|
||||||
|
newborn.nodes <- function(unrestricted.rpc.url = "http://127.0.0.1:18081",
|
||||||
|
poll.time = 30, sync.height.lag = 30 * 24 * 90, avg_upload.limit = 10,
|
||||||
|
current_upload.limit = 10) {
|
||||||
|
|
||||||
|
json.post <- RJSONIO::toJSON(
|
||||||
|
list(
|
||||||
|
jsonrpc = "2.0",
|
||||||
|
id = "0",
|
||||||
|
method = "get_connections",
|
||||||
|
params = ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
already.seen.newborn.address <- c()
|
||||||
|
already.seen.newborn.peer_id <- c()
|
||||||
|
|
||||||
|
on.exit({
|
||||||
|
session.duration <- Sys.time() - session.start.time
|
||||||
|
cat(paste0(format(Sys.time(), "%Y-%m-%d %T"),
|
||||||
|
" ", length(already.seen.newborn.address),
|
||||||
|
" likely newborn nodes seen during this session that lasted ",
|
||||||
|
round(session.duration, 1), " ", units(session.duration),
|
||||||
|
": \n",
|
||||||
|
paste0(already.seen.newborn.address, collapse = " "), "\n"))
|
||||||
|
})
|
||||||
|
|
||||||
|
session.start.time <- Sys.time()
|
||||||
|
|
||||||
|
cat(paste0(format(session.start.time, "%Y-%m-%d %T"), " Start polling monerod for newborn nodes...\n"))
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
|
||||||
|
peers <- RJSONIO::fromJSON(
|
||||||
|
RCurl::postForm(paste0(unrestricted.rpc.url, "/json_rpc"),
|
||||||
|
.opts = list(
|
||||||
|
userpwd = "",
|
||||||
|
postfields = json.post,
|
||||||
|
httpheader = c('Content-Type' = 'application/json', Accept = 'application/json')
|
||||||
|
)
|
||||||
|
), asText = TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
if(length(peers$result$connections) == 0 ) {
|
||||||
|
cat("Unexpected results from node's RPC response. Check that monerod's unrestricted RPC port is at ",
|
||||||
|
unrestricted.rpc.url, "\n")
|
||||||
|
Sys.sleep(poll.time)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
peers <- peers$result$connections
|
||||||
|
|
||||||
|
peer.heights <- sapply(peers, FUN = function(x) {x$height})
|
||||||
|
peer.address <- sapply(peers, FUN = function(x) {x$address})
|
||||||
|
peer.peer_id <- sapply(peers, FUN = function(x) {x$peer_id})
|
||||||
|
peer.avg_upload <- sapply(peers, FUN = function(x) {x$avg_upload})
|
||||||
|
peer.current_upload <- sapply(peers, FUN = function(x) {x$current_upload})
|
||||||
|
|
||||||
|
consensus.height <- floor(quantile(peer.heights, prob = 0.9))
|
||||||
|
|
||||||
|
new.nodes <- which(
|
||||||
|
peer.heights > 1 &
|
||||||
|
(peer.heights <= consensus.height - sync.height.lag) &
|
||||||
|
(! peer.address %in% already.seen.newborn.address) &
|
||||||
|
(! peer.peer_id %in% already.seen.newborn.peer_id) &
|
||||||
|
(peer.avg_upload > avg_upload.limit | peer.current_upload > current_upload.limit)
|
||||||
|
)
|
||||||
|
|
||||||
|
for (i in new.nodes) {
|
||||||
|
|
||||||
|
cat(
|
||||||
|
paste0(format(Sys.time(), "%Y-%m-%d %T"), " ",
|
||||||
|
"Likely newborn node: ",
|
||||||
|
formatC(peers[[i]]$address, width = 21), ", ",
|
||||||
|
# "Peer ID: ", peers[[i]]$peer_id, ", ",
|
||||||
|
# "Connection ID: ", peers[[i]]$connection_id, ", ",
|
||||||
|
"Height: ",
|
||||||
|
formatC(peers[[i]]$height, width = 7, format = "d"), "/", consensus.height, ", ",
|
||||||
|
ifelse(peers[[i]]$pruning_seed > 0, " Pruned", "Unpruned"), ", ",
|
||||||
|
ifelse(peers[[i]]$incoming, "Incoming connection", "Outgoing connection"), ", ",
|
||||||
|
"avg_upload: ", formatC(peers[[i]]$avg_upload, width = 4),
|
||||||
|
# ", ", "current_upload: ", formatC(peers[[i]]$current_upload, width = 4),
|
||||||
|
# ", ", "send_count: ", formatC(peers[[i]]$send_count, width = 8, format = "d"),
|
||||||
|
"\n"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
already.seen.newborn.address <- c(already.seen.newborn.address, peers[[i]]$address)
|
||||||
|
already.seen.newborn.peer_id <- c(already.seen.newborn.peer_id, peers[[i]]$peer_id)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Sys.sleep(poll.time)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return(invisible(NULL))
|
||||||
|
|
||||||
|
}
|
53
man/newborn.nodes.Rd
Normal file
53
man/newborn.nodes.Rd
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/newborn.R
|
||||||
|
\name{newborn.nodes}
|
||||||
|
\alias{newborn.nodes}
|
||||||
|
\title{Print likely newborn nodes to the console}
|
||||||
|
\usage{
|
||||||
|
newborn.nodes(
|
||||||
|
unrestricted.rpc.url = "http://127.0.0.1:18081",
|
||||||
|
poll.time = 30,
|
||||||
|
sync.height.lag = 30 * 24 * 90,
|
||||||
|
avg_upload.limit = 10,
|
||||||
|
current_upload.limit = 10
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{unrestricted.rpc.url}{URL and port of the monerod unrestricted RPC.
|
||||||
|
Default is \verb{http://127.0.0.1:18081}}
|
||||||
|
|
||||||
|
\item{poll.time}{How often, in seconds, to check for a newborn node
|
||||||
|
connection. Default is 30 seconds.}
|
||||||
|
|
||||||
|
\item{sync.height.lag}{Criteria to consider a node as "newborn". Nodes that
|
||||||
|
have a height greater than current network height minus \code{sync.height.lag}
|
||||||
|
will not be considered a newborn node. Default is 3 months.}
|
||||||
|
|
||||||
|
\item{avg_upload.limit}{Criteria to consider a node as "newborn". The
|
||||||
|
\code{avg_upload} from the \code{get_peers} call must be greater than or equal to
|
||||||
|
\code{avg_upload.limit} OR \code{current_upload} must be greater than or equal to
|
||||||
|
\code{current_upload.limit} to consider the node as "newborn". Default is 10 for
|
||||||
|
both limits. Sometimes a node gets stuck at a low height, so it isn't
|
||||||
|
actually new or syncing. This criteria makes sure that the peer is actually
|
||||||
|
actively syncing data.}
|
||||||
|
|
||||||
|
\item{current_upload.limit}{Criteria to consider a node as "newborn".}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
NULL (invisible)
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
When a node connects to our own node, it could be a newborn
|
||||||
|
node that is syncing from the genesis block. \code{newborn.nodes} queries the
|
||||||
|
local Monero node about node connections with a \code{get_peers} call and prints
|
||||||
|
information about likely newborn nodes to the console. The unrestricted RPC
|
||||||
|
port must be reachable by R. This function is an infinite loop. \code{ctrl + c}
|
||||||
|
to interrupt the function and print all IP addresses of likely newborn nodes
|
||||||
|
recorded so far. Each peer will only be printed once during a specific run of
|
||||||
|
\code{newborn.nodes}, even if the node disconnects and reconnects later.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
newborn.nodes()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue