Merge remote-tracking branch 'upstream/master' into feature/3722-feature_flags
This commit is contained in:
commit
041d363232
File diff suppressed because it is too large
Load Diff
12
Cargo.toml
12
Cargo.toml
|
@ -33,10 +33,18 @@ tracing = "0.1"
|
|||
tracing-core = "0.1"
|
||||
tracing-appender = "0.1"
|
||||
zcash_history = "0.2"
|
||||
zcash_primitives = "0.4"
|
||||
zcash_proofs = "0.4"
|
||||
zcash_primitives = "0.5"
|
||||
zcash_proofs = "0.5"
|
||||
ed25519-zebra = "2.0.0"
|
||||
|
||||
# Metrics
|
||||
hyper = { version = "=0.14.2", default-features = false, features = ["server", "tcp", "http1"] }
|
||||
ipnet = "2"
|
||||
metrics = "0.14.2"
|
||||
metrics-exporter-prometheus = "0.3"
|
||||
thiserror = "1"
|
||||
tokio = { version = "1.0", features = ["rt", "net", "time", "macros"] }
|
||||
|
||||
# Temporary workaround for https://github.com/myrrlyn/funty/issues/3
|
||||
funty = "=1.1.0"
|
||||
|
||||
|
|
|
@ -124,14 +124,24 @@ Files: src/crypto/ctaes/*
|
|||
Copyright: Copyright (c) 2016 Pieter Wuille
|
||||
License: Expat
|
||||
|
||||
Files: src/rust/include/rust/map.h
|
||||
Copyright: Copyright (c) 2012 William Swanson
|
||||
License: Expat-with-advertising-clause
|
||||
|
||||
Files: src/rust/include/rust/VA_OPT.hpp
|
||||
Copyright: Copyright (c) 2019 Will Wray
|
||||
License: Boost-Software-License-1.0
|
||||
|
||||
Files: src/rust/include/tracing.h
|
||||
src/rust/src/tracing_ffi.rs
|
||||
Copyright: Copyright (c) 2020 Jack Grigg
|
||||
License: Expat
|
||||
|
||||
Files: src/rust/include/tracing/map.h
|
||||
Copyright: Copyright (c) 2012 William Swanson
|
||||
License: Expat-with-advertising-clause
|
||||
Files: src/rust/src/metrics_ffi/prometheus.rs
|
||||
Copyright:
|
||||
2020-2021 The contributors to the metrics project
|
||||
2021 Jack Grigg
|
||||
License: Expat
|
||||
|
||||
Files: src/secp256k1/*
|
||||
Copyright: Copyright (c) 2013 Pieter Wuille
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
scrape_configs:
|
||||
- job_name: 'zcashd'
|
||||
scrape_interval: 500ms
|
||||
metrics_path: '/'
|
||||
static_configs:
|
||||
- targets: ['127.0.0.1:9969']
|
|
@ -1,12 +1,12 @@
|
|||
package=native_rust
|
||||
$(package)_version=1.49.0
|
||||
$(package)_version=1.51.0
|
||||
$(package)_download_path=https://static.rust-lang.org/dist
|
||||
$(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz
|
||||
$(package)_sha256_hash_linux=8b14446df82f3707d69cf58fed92f18e0bff91621c62baf89288ef70e3e92981
|
||||
$(package)_sha256_hash_linux=9e125977aa13f012a68fdc6663629c685745091ae244f0587dd55ea4e3a3e42f
|
||||
$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz
|
||||
$(package)_sha256_hash_darwin=fe3e248bc4b0ee0a2595693687ad845c8a8bda824a56c9321520bcca02433716
|
||||
$(package)_sha256_hash_darwin=765212098a415996b767d1e372ce266caf94027402b269fec33291fffc085ca4
|
||||
$(package)_file_name_freebsd=rust-$($(package)_version)-x86_64-unknown-freebsd.tar.gz
|
||||
$(package)_sha256_hash_freebsd=dced98577e834f511cae8e58290539ad6b8dd40ae512e90d1371f650961bd930
|
||||
$(package)_sha256_hash_freebsd=d764ab80889460caca86cda7b7ca2ced80544bb477634adc8cade0e27f4f663b
|
||||
|
||||
# Mapping from GCC canonical hosts to Rust targets
|
||||
# If a mapping is not present, we assume they are identical, unless $host_os is
|
||||
|
@ -15,9 +15,9 @@ $(package)_rust_target_x86_64-pc-linux-gnu=x86_64-unknown-linux-gnu
|
|||
$(package)_rust_target_x86_64-w64-mingw32=x86_64-pc-windows-gnu
|
||||
|
||||
# Mapping from Rust targets to SHA-256 hashes
|
||||
$(package)_rust_std_sha256_hash_aarch64-unknown-linux-gnu=c58bd4f0738ff662f70e35c19bfa6b8eb12ad54b0fbdce32ee3e50186c04a969
|
||||
$(package)_rust_std_sha256_hash_x86_64-apple-darwin=c4389a8534b8da3ae3570646d68fea9a25268b17ed138867e31d4517312759af
|
||||
$(package)_rust_std_sha256_hash_x86_64-pc-windows-gnu=61275ed8bb8350e58e619a99104b8ba9a4bdd715b2ce03e20cb33f5b19e84a9c
|
||||
$(package)_rust_std_sha256_hash_aarch64-unknown-linux-gnu=a6ed4abe59dfaf2119e2803f67fd8aef757a622ae3ac9a040946af2b02f4c269
|
||||
$(package)_rust_std_sha256_hash_x86_64-apple-darwin=2856bc46d3624ae2658897c15388c0c353bea916963a2fc5991c23b920d5678c
|
||||
$(package)_rust_std_sha256_hash_x86_64-pc-windows-gnu=55f871bdaf361a26280ca5396297cc7c67237cd86d4ebfe3cbdf9fac14ce0327
|
||||
|
||||
define rust_target
|
||||
$(if $($(1)_rust_target_$(2)),$($(1)_rust_target_$(2)),$(if $(findstring darwin,$(3)),x86_64-apple-darwin,$(if $(findstring freebsd,$(3)),x86_64-unknown-freebsd,$(2))))
|
||||
|
@ -47,12 +47,12 @@ define $(package)_extract_cmds
|
|||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
bash ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(build_prefix) --disable-ldconfig && \
|
||||
bash ./install.sh --without=rust-docs --destdir=$($(package)_staging_dir) --prefix=$(build_prefix) --disable-ldconfig && \
|
||||
../$(canonical_host)/install.sh --destdir=$($(package)_staging_dir) --prefix=$(build_prefix) --disable-ldconfig
|
||||
endef
|
||||
else
|
||||
|
||||
define $(package)_stage_cmds
|
||||
bash ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(build_prefix) --disable-ldconfig
|
||||
bash ./install.sh --without=rust-docs --destdir=$($(package)_staging_dir) --prefix=$(build_prefix) --disable-ldconfig
|
||||
endef
|
||||
endif
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# The zcashd Book
|
||||
|
||||
[zcashd](README.md)
|
||||
- [User Documentation](user.md)
|
||||
- [Metrics](user/metrics.md)
|
||||
- [Design](design.md)
|
||||
- [Chain state](design/chain-state.md)
|
||||
- ["Coins" view](design/coins-view.md)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# User Documentation
|
||||
|
||||
This section contains user documentation specific to `zcashd`.
|
||||
|
||||
See [here](https://zcash.readthedocs.io/) for more general Zcash documentation, as well as
|
||||
installation instructions for `zcashd`.
|
|
@ -0,0 +1,84 @@
|
|||
# zcashd metrics
|
||||
|
||||
## Metrics UI
|
||||
|
||||
This is the user interface that `zcashd` displays by default when run. It
|
||||
displays a small selection of interesting metrics, but is not intended for
|
||||
programmatic consumption.
|
||||
|
||||
## RPC methods
|
||||
|
||||
`zcashd` provides the following JSON-RPC methods that expose node metrics:
|
||||
|
||||
- Chain:
|
||||
- `getblockchaininfo`: Various state info regarding block chain processing.
|
||||
- `gettxoutsetinfo`: Statistics about the unspent transparent transaction output set.
|
||||
- `getmempoolinfo`: Details on the active state of the TX memory pool.
|
||||
- P2P network:
|
||||
- `getnetworkinfo`: Various state info regarding P2P networking.
|
||||
- `getpeerinfo`: Data about each connected network node.
|
||||
- `getdeprecationinfo`: The current node version and deprecation block height.
|
||||
- Miscellaneous
|
||||
- `getmemoryinfo`: Information about memory usage.
|
||||
- `getmininginfo`: Mining-related information.
|
||||
- `getinfo` (deprecated): A small subset of the above metrics.
|
||||
|
||||
You can see what each method provides with `zcash-cli help METHOD_NAME`.
|
||||
|
||||
## Prometheus support
|
||||
|
||||
`zcashd` can optionally expose an HTTP server that acts as a Prometheus scrape
|
||||
endpoint. The server will respond to `GET` requests on any request path.
|
||||
|
||||
To enable the endpoint, add `-prometheusport=<port>` to your `zcashd`
|
||||
configuration (either in `zcash.conf` or on the command line). After
|
||||
restarting `zcashd` you can then test the endpoint by querying it:
|
||||
|
||||
```
|
||||
$ curl http://127.0.0.1:<port>
|
||||
# TYPE zcash_net_out_messages counter
|
||||
zcash_net_out_messages 181
|
||||
|
||||
# TYPE zcash_net_in_bytes_total counter
|
||||
zcash_net_in_bytes_total 3701998
|
||||
|
||||
# TYPE zcash_net_in_messages counter
|
||||
zcash_net_in_messages 184
|
||||
|
||||
# TYPE zcashd_build_info counter
|
||||
zcashd_build_info{version="v4.2.0"} 1
|
||||
|
||||
# TYPE zcash_chain_verified_block_total counter
|
||||
zcash_chain_verified_block_total 162
|
||||
...
|
||||
```
|
||||
|
||||
By default, access is restricted to localhost. This can be expanded with
|
||||
`-metricsallowip=<ip>`, which can specify IPs or subnets. Note that HTTPS is not
|
||||
supported, and therefore connections to the endpoint are not encrypted or
|
||||
authenticated. Access to the endpoint should be assumed to compromise the
|
||||
privacy of node operations, by the provided metrics and/or by timing side
|
||||
channels. Non-localhost access is **strongly discouraged** if the node has a
|
||||
wallet holding live funds.
|
||||
|
||||
### Example metrics collection with Docker
|
||||
|
||||
The example instructions below were tested on Windows 10 using Docker Desktop
|
||||
with the WSL 2 backend:
|
||||
|
||||
```
|
||||
# Create a storage volume for Grafana (once)
|
||||
docker volume create grafana-storage
|
||||
|
||||
# Create a storage volume for Prometheus (once)
|
||||
docker volume create prometheus-storage
|
||||
|
||||
# Run Prometheus
|
||||
# You will need to modify ~/contrib/metrics/prometheus.yaml to match the
|
||||
# endpoint configured with -prometheusmetrics (and possibly also for your Docker
|
||||
# network setup).
|
||||
docker run --detach -p 9090:9090 --volume prometheus-storage:/prometheus --volume ~/contrib/metrics/prometheus.yaml:/etc/prometheus/prometheus.yml prom/prometheus
|
||||
|
||||
# Run Grafana
|
||||
docker run --detach -p 3030:3030 --env GF_SERVER_HTTP_PORT=3030 --volume grafana-storage:/var/lib/grafana grafana/grafana
|
||||
```
|
|
@ -36,3 +36,20 @@ blocks and transactions to fewer nodes.
|
|||
Reducing the maximum connected nodes to a minimum could be desirable if traffic
|
||||
limits are tiny. Keep in mind that bitcoin's trustless model works best if you are
|
||||
connected to a handful of nodes.
|
||||
|
||||
## 4. Turn off transaction relay (`-blocksonly`)
|
||||
|
||||
Forwarding transactions to peers increases the P2P traffic. To only sync blocks
|
||||
with other peers, you can disable transaction relay.
|
||||
|
||||
Be reminded of the effects of this setting.
|
||||
|
||||
- Fee estimation will no longer work.
|
||||
- It sets the flag "-walletbroadcast" to be "0", only if it is currently unset.
|
||||
Doing so disables the automatic broadcasting of transactions from wallet. Not
|
||||
relaying other's transactions could hurt your privacy if used while a wallet
|
||||
is loaded or if you use the node to broadcast transactions.
|
||||
- If a peer is whitelisted and "-whitelistforcerelay" is set to "1" (which will
|
||||
also set "whitelistrelay" to "1"), we will still receive and relay their transactions.
|
||||
- It makes block propagation slower because compact block relay can only be
|
||||
used when transaction relay is enabled.
|
||||
|
|
|
@ -4,3 +4,25 @@ release-notes at release time)
|
|||
Notable changes
|
||||
===============
|
||||
|
||||
Prometheus metrics
|
||||
------------------
|
||||
|
||||
`zcashd` can now be configured to optionally expose an HTTP server that acts as
|
||||
a Prometheus scrape endpoint. The server will respond to `GET` requests on any
|
||||
request path.
|
||||
|
||||
To enable the endpoint, add `-prometheusport=<port>` to your `zcashd`
|
||||
configuration (either in `zcash.conf` or on the command line). After
|
||||
restarting `zcashd` you can then test the endpoint by querying it with e.g.
|
||||
`curl http://127.0.0.1:<port>`.
|
||||
|
||||
By default, access is restricted to localhost. This can be expanded with
|
||||
`-metricsallowip=<ip>`, which can specify IPs or subnets. Note that HTTPS is not
|
||||
supported, and therefore connections to the endpoint are not encrypted or
|
||||
authenticated. Access to the endpoint should be assumed to compromise the
|
||||
privacy of node operations, by the provided metrics and/or by timing side
|
||||
channels. Non-localhost access is **strongly discouraged** if the node has a
|
||||
wallet holding live funds.
|
||||
|
||||
The specific metrics names may change in subsequent releases, in particular to
|
||||
improve interoperability with `zebrad`.
|
||||
|
|
|
@ -27,6 +27,3 @@ native_b2 1.75.0 2021-03-01
|
|||
|
||||
# Google Test 1.10.0 requires adding CMake to the depends system.
|
||||
googletest 1.10.0 2021-03-01
|
||||
|
||||
# We will likely switch to the 1.51.0 release when it is out.
|
||||
native_rust 1.50.0 2021-07-01
|
||||
|
|
|
@ -205,7 +205,7 @@ class GithubTagReleaseLister:
|
|||
|
||||
class BerkeleyDbReleaseLister:
|
||||
def known_releases(self):
|
||||
url = "https://www.oracle.com/technetwork/products/berkeleydb/downloads/index-082944.html"
|
||||
url = "https://www.oracle.com/database/technologies/related/berkeleydb-downloads.html"
|
||||
r = requests.get(url)
|
||||
if r.status_code != 200:
|
||||
raise RuntimeError("Request to Berkeley DB download directory failed.")
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.49.0
|
||||
1.51.0
|
||||
|
|
|
@ -355,13 +355,6 @@ public:
|
|||
"t3PSn5TbMMAEw7Eu36DYctFezRzpX1hzf3M", /* main-index: 45*/
|
||||
"t3R3Y5vnBLrEn8L6wFjPjBLnxSUQsKnmFpv", /* main-index: 46*/
|
||||
"t3Pcm737EsVkGTbhsu2NekKtJeG92mvYyoN", /* main-index: 47*/
|
||||
// "t3PZ9PPcLzgL57XRSG5ND4WNBC9UTFb8DXv", /* main-index: 48*/
|
||||
// "t3L1WgcyQ95vtpSgjHfgANHyVYvffJZ9iGb", /* main-index: 49*/
|
||||
// "t3JtoXqsv3FuS7SznYCd5pZJGU9di15mdd7", /* main-index: 50*/
|
||||
// "t3hLJHrHs3ytDgExxr1mD8DYSrk1TowGV25", /* main-index: 51*/
|
||||
// "t3fmYHU2DnVaQgPhDs6TMFVmyC3qbWEWgXN", /* main-index: 52*/
|
||||
// "t3T4WmAp6nrLkJ24iPpGeCe1fSWTPv47ASG", /* main-index: 53*/
|
||||
// "t3fP6GrDM4QVwdjFhmCxGNbe7jXXXSDQ5dv", /* main-index: 54*/
|
||||
};
|
||||
|
||||
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight(0));
|
||||
|
|
|
@ -119,7 +119,7 @@ public:
|
|||
void Run()
|
||||
{
|
||||
ThreadCounter count(*this);
|
||||
while (running) {
|
||||
while (true) {
|
||||
std::unique_ptr<WorkItem> i;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(cs);
|
||||
|
|
63
src/init.cpp
63
src/init.cpp
|
@ -64,6 +64,8 @@
|
|||
#include "zmq/zmqnotificationinterface.h"
|
||||
#endif
|
||||
|
||||
#include <rust/metrics.h>
|
||||
|
||||
#include "librustzcash.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -329,6 +331,8 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||
strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS));
|
||||
strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
|
||||
strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
|
||||
if (showDebug)
|
||||
strUsage += HelpMessageOpt("-blocksonly", strprintf(_("Whether to reject transactions from network peers. Automatic broadcast and rebroadcast of any transactions from inbound peers is disabled, unless '-whitelistforcerelay' is '1', in which case whitelisted peers' transactions will be relayed. RPC transactions are not affected. (default: %u)"), DEFAULT_BLOCKSONLY));
|
||||
strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), DEFAULT_CHECKBLOCKS));
|
||||
strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL));
|
||||
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
|
||||
|
@ -396,6 +400,8 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
|
||||
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
|
||||
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
|
||||
strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted inbound peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY));
|
||||
strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted inbound peers even they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
|
||||
strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
|
@ -410,6 +416,15 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||
strUsage += HelpMessageOpt("-zmqpubrawtx=<address>", _("Enable publish raw transaction in <address>"));
|
||||
#endif
|
||||
|
||||
strUsage += HelpMessageGroup(_("Monitoring options:"));
|
||||
strUsage += HelpMessageOpt("-metricsallowip=<ip>", _("Allow metrics connections from specified source. "
|
||||
"Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). "
|
||||
"This option can be specified multiple times. (default: only localhost)"));
|
||||
strUsage += HelpMessageOpt("-metricsbind=<addr>", _("Bind to given address to listen for metrics connections. (default: bind to all interfaces)"));
|
||||
strUsage += HelpMessageOpt("-prometheusport=<port>", _("Expose node metrics in the Prometheus exposition format. "
|
||||
"An HTTP listener will be started on <port>, which responds to GET requests on any request path. "
|
||||
"Use -metricsallowip and -metricsbind to control access."));
|
||||
|
||||
strUsage += HelpMessageGroup(_("Debugging/Testing options:"));
|
||||
if (showDebug)
|
||||
{
|
||||
|
@ -798,6 +813,22 @@ void InitParameterInteraction()
|
|||
if (SoftSetBoolArg("-rescan", true))
|
||||
LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
|
||||
}
|
||||
|
||||
// disable walletbroadcast and whitelistrelay in blocksonly mode
|
||||
if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
|
||||
if (SoftSetBoolArg("-whitelistrelay", false))
|
||||
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__);
|
||||
#ifdef ENABLE_WALLET
|
||||
if (SoftSetBoolArg("-walletbroadcast", false))
|
||||
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.
|
||||
if (GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
|
||||
if (SoftSetBoolArg("-whitelistrelay", true))
|
||||
LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void InitLogging()
|
||||
|
@ -911,6 +942,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
// ********************************************************* Step 2: parameter interactions
|
||||
const CChainParams& chainparams = Params();
|
||||
|
||||
// also see: InitParameterInteraction()
|
||||
|
||||
// Set this early so that experimental features are correctly enabled/disabled
|
||||
auto err = InitExperimentalMode();
|
||||
if (err) {
|
||||
|
@ -927,7 +960,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Make sure enough file descriptors are available
|
||||
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
|
||||
int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
|
||||
|
@ -1221,6 +1254,34 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
// Count uptime
|
||||
MarkStartTime();
|
||||
|
||||
int prometheusPort = GetArg("-prometheusport", -1);
|
||||
if (prometheusPort > 0) {
|
||||
const std::vector<std::string>& vAllow = mapMultiArgs["-metricsallowip"];
|
||||
std::vector<const char*> vAllowCstr;
|
||||
for (const std::string& strAllow : vAllow) {
|
||||
vAllowCstr.push_back(strAllow.c_str());
|
||||
}
|
||||
|
||||
std::string metricsBind = GetArg("-metricsbind", "");
|
||||
const char* metricsBindCstr = nullptr;
|
||||
if (!metricsBind.empty()) {
|
||||
metricsBindCstr = metricsBind.c_str();
|
||||
}
|
||||
|
||||
// Start up the metrics runtime. This spins off a Rust thread that runs
|
||||
// the Prometheus exporter. We just let this thread die at process end.
|
||||
LogPrintf("metrics thread start");
|
||||
if (!metrics_run(metricsBindCstr, vAllowCstr.data(), vAllowCstr.size(), prometheusPort)) {
|
||||
return InitError(strprintf(_("Failed to start Prometheus metrics exporter")));
|
||||
}
|
||||
}
|
||||
|
||||
// Expose binary metadata to metrics, using a single time series with value 1.
|
||||
// https://www.robustperception.io/exposing-the-software-version-to-prometheus
|
||||
MetricsIncrementCounter(
|
||||
"zcashd.build.info",
|
||||
"version", CLIENT_BUILD.c_str());
|
||||
|
||||
if ((chainparams.NetworkIDString() != "regtest") &&
|
||||
GetBoolArg("-showmetrics", isatty(STDOUT_FILENO)) &&
|
||||
!fPrintToConsole && !GetBoolArg("-daemon", false)) {
|
||||
|
|
|
@ -18,6 +18,7 @@ bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) con
|
|||
{
|
||||
CKey key;
|
||||
if (!GetKey(address, key)) {
|
||||
LOCK(cs_KeyStore);
|
||||
WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
|
||||
if (it != mapWatchKeys.end()) {
|
||||
vchPubKeyOut = it->second;
|
||||
|
|
208
src/main.cpp
208
src/main.cpp
|
@ -46,6 +46,7 @@
|
|||
#include <boost/thread.hpp>
|
||||
|
||||
#include <rust/ed25519.h>
|
||||
#include <rust/metrics.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -64,7 +65,7 @@ CCriticalSection cs_main;
|
|||
BlockMap mapBlockIndex;
|
||||
CChain chainActive;
|
||||
CBlockIndex *pindexBestHeader = NULL;
|
||||
static int64_t nTimeBestReceived = 0;
|
||||
static std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block
|
||||
CWaitableCriticalSection csBestBlock;
|
||||
CConditionVariable cvBlockChange;
|
||||
int nScriptCheckThreads = 0;
|
||||
|
@ -361,7 +362,7 @@ int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consens
|
|||
void InitializeNode(NodeId nodeid, const CNode *pnode) {
|
||||
LOCK(cs_main);
|
||||
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
|
||||
state.name = pnode->addrName;
|
||||
state.name = pnode->GetAddrName();
|
||||
state.address = pnode->addr;
|
||||
}
|
||||
|
||||
|
@ -1737,6 +1738,10 @@ bool AcceptToMemoryPool(
|
|||
}
|
||||
|
||||
pool.EnsureSizeLimit();
|
||||
|
||||
MetricsGauge("zcash.mempool.size.transactions", mempool.size());
|
||||
MetricsGauge("zcash.mempool.size.bytes", mempool.GetTotalTxSize());
|
||||
MetricsGauge("zcash.mempool.usage.bytes", mempool.DynamicMemoryUsage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3256,6 +3261,85 @@ void PruneAndFlush() {
|
|||
FlushStateToDisk(Params(), state, FLUSH_STATE_NONE);
|
||||
}
|
||||
|
||||
struct PoolMetrics {
|
||||
std::optional<size_t> created;
|
||||
std::optional<size_t> spent;
|
||||
std::optional<size_t> unspent;
|
||||
std::optional<CAmount> value;
|
||||
|
||||
static PoolMetrics Sprout(CBlockIndex *pindex, CCoinsViewCache *view) {
|
||||
PoolMetrics stats;
|
||||
stats.value = pindex->nChainSproutValue;
|
||||
|
||||
// RewindBlockIndex calls DisconnectTip in a way that can potentially cause a
|
||||
// Sprout tree to not exist (the rewind_index RPC test reliably triggers this).
|
||||
// We only need to access the tree during disconnection for metrics purposes, and
|
||||
// we will never encounter this rewind situation on either mainnet or testnet, so
|
||||
// if we can't access the Sprout tree we default to zero.
|
||||
SproutMerkleTree sproutTree;
|
||||
if (view->GetSproutAnchorAt(pindex->hashFinalSproutRoot, sproutTree)) {
|
||||
stats.created = sproutTree.size();
|
||||
} else {
|
||||
stats.created = 0;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
static PoolMetrics Sapling(CBlockIndex *pindex, CCoinsViewCache *view) {
|
||||
PoolMetrics stats;
|
||||
stats.value = pindex->nChainSaplingValue;
|
||||
|
||||
// Before Sapling activation, the Sapling commitment set is empty.
|
||||
SaplingMerkleTree saplingTree;
|
||||
if (view->GetSaplingAnchorAt(pindex->hashFinalSaplingRoot, saplingTree)) {
|
||||
stats.created = saplingTree.size();
|
||||
} else {
|
||||
stats.created = 0;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
static PoolMetrics Transparent(CBlockIndex *pindex, CCoinsViewCache *view) {
|
||||
PoolMetrics stats;
|
||||
// TODO: Collect transparent pool value.
|
||||
|
||||
// TODO: Figure out a way to efficiently collect UTXO set metrics
|
||||
// (view->GetStats() is too slow to call during block verification).
|
||||
|
||||
return stats;
|
||||
}
|
||||
};
|
||||
|
||||
#define RenderPoolMetrics(poolName, poolMetrics) \
|
||||
do { \
|
||||
if (poolMetrics.created) { \
|
||||
MetricsStaticGauge( \
|
||||
"zcash.pool.notes.created", \
|
||||
poolMetrics.created.value(), \
|
||||
"name", poolName); \
|
||||
} \
|
||||
if (poolMetrics.spent) { \
|
||||
MetricsStaticGauge( \
|
||||
"zcash.pool.notes.spent", \
|
||||
poolMetrics.spent.value(), \
|
||||
"name", poolName); \
|
||||
} \
|
||||
if (poolMetrics.unspent) { \
|
||||
MetricsStaticGauge( \
|
||||
"zcash.pool.notes.unspent", \
|
||||
poolMetrics.unspent.value(), \
|
||||
"name", poolName); \
|
||||
} \
|
||||
if (poolMetrics.value) { \
|
||||
MetricsStaticGauge( \
|
||||
"zcash.pool.value.zatoshis", \
|
||||
poolMetrics.value.value(), \
|
||||
"name", poolName); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Update chainActive and related internal data structures. */
|
||||
void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
|
||||
chainActive.SetTip(pindexNew);
|
||||
|
@ -3283,6 +3367,15 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
|
|||
"progress", progress.c_str(),
|
||||
"cache", cache.c_str());
|
||||
|
||||
auto sproutPool = PoolMetrics::Sprout(pindexNew, pcoinsTip);
|
||||
auto saplingPool = PoolMetrics::Sapling(pindexNew, pcoinsTip);
|
||||
auto transparentPool = PoolMetrics::Transparent(pindexNew, pcoinsTip);
|
||||
|
||||
MetricsGauge("zcash.chain.verified.block.height", pindexNew->nHeight);
|
||||
RenderPoolMetrics("sprout", sproutPool);
|
||||
RenderPoolMetrics("sapling", saplingPool);
|
||||
RenderPoolMetrics("transparent", transparentPool);
|
||||
|
||||
cvBlockChange.notify_all();
|
||||
}
|
||||
|
||||
|
@ -3414,6 +3507,8 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
|
|||
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
|
||||
LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
|
||||
LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);
|
||||
MetricsIncrementCounter("zcash.chain.verified.block.total");
|
||||
MetricsHistogram("zcash.chain.verified.block.seconds", (nTime6 - nTime1) * 0.000001);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3633,12 +3728,13 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
|
|||
*/
|
||||
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock)
|
||||
{
|
||||
CBlockIndex *pindexNewTip = NULL;
|
||||
CBlockIndex *pindexMostWork = NULL;
|
||||
CBlockIndex *pindexNewTip = NULL;
|
||||
do {
|
||||
boost::this_thread::interruption_point();
|
||||
|
||||
bool fInitialDownload;
|
||||
int nNewHeight;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
pindexMostWork = FindMostWorkChain();
|
||||
|
@ -3652,6 +3748,7 @@ bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams,
|
|||
|
||||
pindexNewTip = chainActive.Tip();
|
||||
fInitialDownload = IsInitialBlockDownload(chainparams.GetConsensus());
|
||||
nNewHeight = chainActive.Height();
|
||||
}
|
||||
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
|
||||
|
||||
|
@ -3667,13 +3764,13 @@ bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams,
|
|||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (CNode* pnode : vNodes)
|
||||
if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
|
||||
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
|
||||
pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip));
|
||||
}
|
||||
// Notify external listeners about the new tip.
|
||||
GetMainSignals().UpdatedBlockTip(pindexNewTip);
|
||||
}
|
||||
} while(pindexMostWork != chainActive.Tip());
|
||||
} while (pindexNewTip != pindexMostWork);
|
||||
CheckBlockIndex(chainparams.GetConsensus());
|
||||
|
||||
// Write changes periodically to disk, after relay.
|
||||
|
@ -5542,10 +5639,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
|||
pfrom->PushMessage("block", block);
|
||||
else // MSG_FILTERED_BLOCK)
|
||||
{
|
||||
LOCK(pfrom->cs_filter);
|
||||
if (pfrom->pfilter)
|
||||
bool send = false;
|
||||
CMerkleBlock merkleBlock;
|
||||
{
|
||||
CMerkleBlock merkleBlock(block, *pfrom->pfilter);
|
||||
LOCK(pfrom->cs_filter);
|
||||
if (pfrom->pfilter) {
|
||||
send = true;
|
||||
merkleBlock = CMerkleBlock(block, *pfrom->pfilter);
|
||||
}
|
||||
}
|
||||
if (send) {
|
||||
pfrom->PushMessage("merkleblock", merkleBlock);
|
||||
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
|
||||
// This avoids hurting performance by pointlessly requiring a round-trip
|
||||
|
@ -5651,6 +5754,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
if (pfrom->nVersion != 0)
|
||||
{
|
||||
pfrom->PushMessage("reject", strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 1);
|
||||
return false;
|
||||
}
|
||||
|
@ -5659,7 +5763,11 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
CAddress addrMe;
|
||||
CAddress addrFrom;
|
||||
uint64_t nNonce = 1;
|
||||
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
|
||||
std::string strSubVer;
|
||||
std::string cleanSubVer;
|
||||
uint64_t nServices;
|
||||
vRecv >> pfrom->nVersion >> nServices >> nTime >> addrMe;
|
||||
pfrom->nServices = nServices;
|
||||
if (pfrom->nVersion < MIN_PEER_PROTO_VERSION)
|
||||
{
|
||||
// disconnect from peers older than this proto version
|
||||
|
@ -5692,11 +5800,14 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
if (!vRecv.empty())
|
||||
vRecv >> addrFrom >> nNonce;
|
||||
if (!vRecv.empty()) {
|
||||
vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
|
||||
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer, SAFE_CHARS_SUBVERSION);
|
||||
vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);
|
||||
cleanSubVer = SanitizeString(strSubVer, SAFE_CHARS_SUBVERSION);
|
||||
}
|
||||
if (!vRecv.empty()) {
|
||||
int nStartingHeight;
|
||||
vRecv >> nStartingHeight;
|
||||
pfrom->nStartingHeight = nStartingHeight;
|
||||
}
|
||||
if (!vRecv.empty())
|
||||
vRecv >> pfrom->nStartingHeight;
|
||||
if (!vRecv.empty())
|
||||
vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
|
||||
else
|
||||
|
@ -5710,7 +5821,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
return true;
|
||||
}
|
||||
|
||||
pfrom->addrLocal = addrMe;
|
||||
pfrom->SetAddrLocal(addrMe);
|
||||
if (pfrom->fInbound && addrMe.IsRoutable())
|
||||
{
|
||||
SeenLocal(addrMe);
|
||||
|
@ -5720,10 +5831,18 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
if (pfrom->fInbound)
|
||||
pfrom->PushVersion();
|
||||
|
||||
{
|
||||
LOCK(pfrom->cs_SubVer);
|
||||
pfrom->strSubVer = strSubVer;
|
||||
pfrom->cleanSubVer = cleanSubVer;
|
||||
}
|
||||
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
|
||||
|
||||
// Potentially mark this peer as a preferred download peer.
|
||||
UpdatePreferredDownload(pfrom, State(pfrom->GetId()));
|
||||
{
|
||||
LOCK(cs_main);
|
||||
UpdatePreferredDownload(pfrom, State(pfrom->GetId()));
|
||||
}
|
||||
|
||||
// Change version
|
||||
pfrom->PushMessage("verack");
|
||||
|
@ -5741,7 +5860,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
|
||||
pfrom->PushAddress(addr, insecure_rand);
|
||||
} else if (IsPeerAddrLocalGood(pfrom)) {
|
||||
addr.SetIP(pfrom->addrLocal);
|
||||
addr.SetIP(addrMe);
|
||||
LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
|
||||
pfrom->PushAddress(addr, insecure_rand);
|
||||
}
|
||||
|
@ -5776,7 +5895,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
remoteAddr = ", peeraddr=" + pfrom->addr.ToString();
|
||||
|
||||
LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n",
|
||||
pfrom->cleanSubVer, pfrom->nVersion,
|
||||
cleanSubVer, pfrom->nVersion,
|
||||
pfrom->nStartingHeight, addrMe.ToString(), pfrom->id,
|
||||
remoteAddr);
|
||||
|
||||
|
@ -5787,6 +5906,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
else if (pfrom->nVersion == 0)
|
||||
{
|
||||
// Must have a version message before anything else
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 1);
|
||||
return false;
|
||||
}
|
||||
|
@ -5834,6 +5954,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
return true;
|
||||
if (vAddr.size() > 1000)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
return error("message addr size() = %u", vAddr.size());
|
||||
}
|
||||
|
@ -5893,10 +6014,17 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
vRecv >> vInv;
|
||||
if (vInv.size() > MAX_INV_SZ)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
return error("message inv size() = %u", vInv.size());
|
||||
}
|
||||
|
||||
bool fBlocksOnly = GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
|
||||
|
||||
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
|
||||
if (pfrom->fWhitelisted && GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
|
||||
fBlocksOnly = false;
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
std::vector<CInv> vToFetch;
|
||||
|
@ -5934,8 +6062,12 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
}
|
||||
LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
|
||||
}
|
||||
} else {
|
||||
if (!fAlreadyHave && !IsInitialBlockDownload(chainparams.GetConsensus()))
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fBlocksOnly)
|
||||
LogPrint("net", "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->id);
|
||||
else if (!fAlreadyHave && !IsInitialBlockDownload(chainparams.GetConsensus()))
|
||||
pfrom->AskFor(inv);
|
||||
}
|
||||
|
||||
|
@ -5959,6 +6091,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
vRecv >> vInv;
|
||||
if (vInv.size() > MAX_INV_SZ)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
return error("message getdata size() = %u", vInv.size());
|
||||
}
|
||||
|
@ -6062,6 +6195,14 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
|
||||
else if (strCommand == "tx" && !IsInitialBlockDownload(chainparams.GetConsensus()))
|
||||
{
|
||||
// Stop processing the transaction early if
|
||||
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
|
||||
if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
|
||||
{
|
||||
LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id);
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<uint256> vWorkQueue;
|
||||
vector<uint256> vEraseQueue;
|
||||
CTransaction tx;
|
||||
|
@ -6160,7 +6301,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
assert(recentRejects);
|
||||
recentRejects->insert(tx.GetHash());
|
||||
|
||||
if (pfrom->fWhitelisted) {
|
||||
if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
|
||||
// Always relay transactions received from whitelisted peers, even
|
||||
// if they were already in the mempool or rejected from it due
|
||||
// to policy, allowing the node to function as a gateway for
|
||||
|
@ -6200,6 +6341,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
|
||||
unsigned int nCount = ReadCompactSize(vRecv);
|
||||
if (nCount > MAX_HEADERS_RESULTS) {
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
return error("headers message size = %u", nCount);
|
||||
}
|
||||
|
@ -6397,7 +6539,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
if (pingUsecTime > 0) {
|
||||
// Successful ping time measurement, replace previous
|
||||
pfrom->nPingUsecTime = pingUsecTime;
|
||||
pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime);
|
||||
pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime);
|
||||
} else {
|
||||
// This should never happen
|
||||
sProblem = "Timing mishap";
|
||||
|
@ -6460,6 +6602,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
// This isn't a Misbehaving(100) (immediate ban) because the
|
||||
// peer might be an older or different implementation with
|
||||
// a different signature key, etc.
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 10);
|
||||
}
|
||||
}
|
||||
|
@ -6471,6 +6614,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
strCommand == "filteradd"))
|
||||
{
|
||||
if (pfrom->nVersion >= NO_BLOOM_VERSION) {
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return false;
|
||||
} else if (GetBoolArg("-enforcenodebloom", DEFAULT_ENFORCENODEBLOOM)) {
|
||||
|
@ -6486,16 +6630,19 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
vRecv >> filter;
|
||||
|
||||
if (!filter.IsWithinSizeConstraints())
|
||||
{
|
||||
// There is no excuse for sending a too-large filter
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOCK(pfrom->cs_filter);
|
||||
delete pfrom->pfilter;
|
||||
pfrom->pfilter = new CBloomFilter(filter);
|
||||
pfrom->pfilter->UpdateEmptyFull();
|
||||
pfrom->fRelayTxes = true;
|
||||
}
|
||||
pfrom->fRelayTxes = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -6506,15 +6653,20 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
|
|||
|
||||
// Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
|
||||
// and thus, the maximum size any matched object can have) in a filteradd message
|
||||
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE)
|
||||
{
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
bool bad = false;
|
||||
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
|
||||
bad = true;
|
||||
} else {
|
||||
LOCK(pfrom->cs_filter);
|
||||
if (pfrom->pfilter)
|
||||
if (pfrom->pfilter) {
|
||||
pfrom->pfilter->insert(vData);
|
||||
else
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
} else {
|
||||
bad = true;
|
||||
}
|
||||
}
|
||||
if (bad) {
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,10 @@ struct CNodeStateStats;
|
|||
static const bool DEFAULT_ALERTS = true;
|
||||
/** Maximum reorg length we will accept before we shut down and alert the user. */
|
||||
static const unsigned int MAX_REORG_LENGTH = COINBASE_MATURITY - 1;
|
||||
/** Default for DEFAULT_WHITELISTRELAY. */
|
||||
static const bool DEFAULT_WHITELISTRELAY = true;
|
||||
/** Default for DEFAULT_WHITELISTFORCERELAY. */
|
||||
static const bool DEFAULT_WHITELISTFORCERELAY = true;
|
||||
/** Default for -minrelaytxfee, minimum relay fee for transactions */
|
||||
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 100;
|
||||
//! -maxtxfee default
|
||||
|
|
188
src/net.cpp
188
src/net.cpp
|
@ -31,6 +31,8 @@
|
|||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <rust/metrics.h>
|
||||
|
||||
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
|
||||
#define DUMP_ADDRESSES_INTERVAL 900
|
||||
|
||||
|
@ -190,8 +192,9 @@ int GetnScore(const CService& addr)
|
|||
// Is our peer's addrLocal potentially useful as an external IP source?
|
||||
bool IsPeerAddrLocalGood(CNode *pnode)
|
||||
{
|
||||
return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() &&
|
||||
!IsLimited(pnode->addrLocal.GetNetwork());
|
||||
CService addrLocal = pnode->GetAddrLocal();
|
||||
return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() &&
|
||||
!IsLimited(addrLocal.GetNetwork());
|
||||
}
|
||||
|
||||
// pushes our own address to a peer
|
||||
|
@ -206,7 +209,7 @@ void AdvertizeLocal(CNode *pnode)
|
|||
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
|
||||
GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
|
||||
{
|
||||
addrLocal.SetIP(pnode->addrLocal);
|
||||
addrLocal.SetIP(pnode->GetAddrLocal());
|
||||
}
|
||||
if (addrLocal.IsRoutable())
|
||||
{
|
||||
|
@ -348,9 +351,11 @@ CNode* FindNode(const CSubNet& subNet)
|
|||
CNode* FindNode(const std::string& addrName)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (CNode* pnode : vNodes)
|
||||
if (pnode->addrName == addrName)
|
||||
for (CNode* pnode : vNodes) {
|
||||
if (pnode->GetAddrName() == addrName) {
|
||||
return (pnode);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -370,6 +375,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
|
|||
return NULL;
|
||||
|
||||
// Look for an existing connection
|
||||
LOCK(cs_vNodes);
|
||||
CNode* pnode = FindNode((CService)addrConnect);
|
||||
if (pnode)
|
||||
{
|
||||
|
@ -406,8 +412,6 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
|
|||
vNodes.push_back(pnode);
|
||||
}
|
||||
|
||||
pnode->nTimeConnected = GetTime();
|
||||
|
||||
return pnode;
|
||||
} else if (!proxyConnectionFailed) {
|
||||
// If connecting to the node failed, and failure is not caused by a problem connecting to
|
||||
|
@ -441,10 +445,12 @@ static void DumpBanlist()
|
|||
void CNode::CloseSocketDisconnect()
|
||||
{
|
||||
fDisconnect = true;
|
||||
if (hSocket != INVALID_SOCKET)
|
||||
{
|
||||
LogPrint("net", "disconnecting peer=%d\n", id);
|
||||
CloseSocket(hSocket);
|
||||
LOCK(cs_hSocket);
|
||||
if (hSocket != INVALID_SOCKET) {
|
||||
LogPrint("net", "disconnecting peer=%d\n", id);
|
||||
CloseSocket(hSocket);
|
||||
}
|
||||
}
|
||||
|
||||
// in case this fails, we'll empty the recv buffer when the CNode is deleted
|
||||
|
@ -466,7 +472,7 @@ void CNode::PushVersion()
|
|||
else
|
||||
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
|
||||
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
|
||||
nLocalHostNonce, strSubVersion, nBestHeight, true);
|
||||
nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY));
|
||||
}
|
||||
|
||||
|
||||
|
@ -634,21 +640,61 @@ void CNode::AddWhitelistedRange(const CSubNet &subnet) {
|
|||
vWhitelistedRange.push_back(subnet);
|
||||
}
|
||||
|
||||
|
||||
std::string CNode::GetAddrName() const {
|
||||
LOCK(cs_addrName);
|
||||
return addrName;
|
||||
}
|
||||
|
||||
void CNode::MaybeSetAddrName(const std::string& addrNameIn) {
|
||||
LOCK(cs_addrName);
|
||||
if (addrName.empty()) {
|
||||
addrName = addrNameIn;
|
||||
}
|
||||
}
|
||||
|
||||
CService CNode::GetAddrLocal() const {
|
||||
LOCK(cs_addrLocal);
|
||||
return addrLocal;
|
||||
}
|
||||
|
||||
void CNode::SetAddrLocal(const CService& addrLocalIn) {
|
||||
LOCK(cs_addrLocal);
|
||||
if (addrLocal.IsValid()) {
|
||||
error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString());
|
||||
} else {
|
||||
addrLocal = addrLocalIn;
|
||||
}
|
||||
}
|
||||
|
||||
void CNode::copyStats(CNodeStats &stats)
|
||||
{
|
||||
stats.nodeid = this->GetId();
|
||||
stats.nServices = nServices;
|
||||
{
|
||||
LOCK(cs_filter);
|
||||
stats.fRelayTxes = fRelayTxes;
|
||||
}
|
||||
stats.nLastSend = nLastSend;
|
||||
stats.nLastRecv = nLastRecv;
|
||||
stats.nTimeConnected = nTimeConnected;
|
||||
stats.nTimeOffset = nTimeOffset;
|
||||
stats.addrName = addrName;
|
||||
stats.addrName = GetAddrName();
|
||||
stats.nVersion = nVersion;
|
||||
stats.cleanSubVer = cleanSubVer;
|
||||
{
|
||||
LOCK(cs_SubVer);
|
||||
stats.cleanSubVer = cleanSubVer;
|
||||
}
|
||||
stats.fInbound = fInbound;
|
||||
stats.nStartingHeight = nStartingHeight;
|
||||
stats.nSendBytes = nSendBytes;
|
||||
stats.nRecvBytes = nRecvBytes;
|
||||
{
|
||||
LOCK(cs_vSend);
|
||||
stats.nSendBytes = nSendBytes;
|
||||
}
|
||||
{
|
||||
LOCK(cs_vRecv);
|
||||
stats.nRecvBytes = nRecvBytes;
|
||||
}
|
||||
stats.fWhitelisted = fWhitelisted;
|
||||
|
||||
// It is common for nodes with good ping times to suddenly become lagged,
|
||||
|
@ -667,7 +713,8 @@ void CNode::copyStats(CNodeStats &stats)
|
|||
stats.dPingWait = (((double)nPingUsecWait) / 1e6);
|
||||
|
||||
// Leave string empty if addrLocal invalid (not filled in yet)
|
||||
stats.addrLocal = addrLocal.IsValid() ? addrLocal.ToString() : "";
|
||||
CService addrLocalUnlocked = GetAddrLocal();
|
||||
stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : "";
|
||||
}
|
||||
|
||||
// requires LOCK(cs_vRecvMsg)
|
||||
|
@ -702,6 +749,11 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
|
|||
|
||||
if (msg.complete()) {
|
||||
msg.nTime = GetTimeMicros();
|
||||
std::string strCommand = SanitizeString(msg.hdr.GetCommand());
|
||||
MetricsIncrementCounter("zcash.net.in.messages", "command", strCommand.c_str());
|
||||
MetricsCounter(
|
||||
"zcash.net.in.bytes", msg.hdr.nMessageSize,
|
||||
"command", strCommand.c_str());
|
||||
messageHandlerCondition.notify_one();
|
||||
}
|
||||
}
|
||||
|
@ -772,10 +824,19 @@ void SocketSendData(CNode *pnode)
|
|||
while (it != pnode->vSendMsg.end()) {
|
||||
const CSerializeData &data = *it;
|
||||
assert(data.size() > pnode->nSendOffset);
|
||||
int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
int nBytes = 0;
|
||||
{
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
break;
|
||||
nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
}
|
||||
if (nBytes > 0) {
|
||||
pnode->nLastSend = GetTime();
|
||||
pnode->nSendBytes += nBytes;
|
||||
{
|
||||
LOCK(pnode->cs_vSend);
|
||||
pnode->nSendBytes += nBytes;
|
||||
}
|
||||
pnode->nSendOffset += nBytes;
|
||||
pnode->RecordBytesSent(nBytes);
|
||||
if (pnode->nSendOffset == data.size()) {
|
||||
|
@ -1104,6 +1165,7 @@ void ThreadSocketHandler()
|
|||
}
|
||||
if (vNodesSize != nPrevNodeCount) {
|
||||
nPrevNodeCount = vNodesSize;
|
||||
MetricsGauge("zcash.net.peers", nPrevNodeCount);
|
||||
uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
|
||||
}
|
||||
|
||||
|
@ -1133,12 +1195,6 @@ void ThreadSocketHandler()
|
|||
LOCK(cs_vNodes);
|
||||
for (CNode* pnode : vNodes)
|
||||
{
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
FD_SET(pnode->hSocket, &fdsetError);
|
||||
hSocketMax = max(hSocketMax, pnode->hSocket);
|
||||
have_fds = true;
|
||||
|
||||
// Implement the following logic:
|
||||
// * If there is data to send, select() for sending data. As this only
|
||||
// happens when optimistic write failed, we choose to first drain the
|
||||
|
@ -1154,19 +1210,35 @@ void ThreadSocketHandler()
|
|||
// * We send some data.
|
||||
// * We wait for data to be received (and disconnect after timeout).
|
||||
// * We process a message in the buffer (message handler thread).
|
||||
|
||||
bool select_send;
|
||||
{
|
||||
TRY_LOCK(pnode->cs_vSend, lockSend);
|
||||
if (lockSend && !pnode->vSendMsg.empty()) {
|
||||
FD_SET(pnode->hSocket, &fdsetSend);
|
||||
continue;
|
||||
}
|
||||
select_send = lockSend && !pnode->vSendMsg.empty();
|
||||
}
|
||||
|
||||
bool select_recv;
|
||||
{
|
||||
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
|
||||
if (lockRecv && (
|
||||
select_recv = lockRecv && (
|
||||
pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() ||
|
||||
pnode->GetTotalRecvSize() <= ReceiveFloodSize()))
|
||||
FD_SET(pnode->hSocket, &fdsetRecv);
|
||||
pnode->GetTotalRecvSize() <= ReceiveFloodSize());
|
||||
}
|
||||
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
|
||||
FD_SET(pnode->hSocket, &fdsetError);
|
||||
hSocketMax = max(hSocketMax, pnode->hSocket);
|
||||
have_fds = true;
|
||||
|
||||
if (select_send) {
|
||||
FD_SET(pnode->hSocket, &fdsetSend);
|
||||
continue;
|
||||
}
|
||||
if (select_recv) {
|
||||
FD_SET(pnode->hSocket, &fdsetRecv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1219,9 +1291,18 @@ void ThreadSocketHandler()
|
|||
//
|
||||
// Receive
|
||||
//
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
|
||||
bool recvSet = false;
|
||||
bool sendSet = false;
|
||||
bool errorSet = false;
|
||||
{
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv);
|
||||
sendSet = FD_ISSET(pnode->hSocket, &fdsetSend);
|
||||
errorSet = FD_ISSET(pnode->hSocket, &fdsetError);
|
||||
}
|
||||
if (recvSet || errorSet)
|
||||
{
|
||||
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
|
||||
if (lockRecv)
|
||||
|
@ -1229,13 +1310,22 @@ void ThreadSocketHandler()
|
|||
{
|
||||
// typical socket buffer is 8K-64K
|
||||
char pchBuf[0x10000];
|
||||
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
||||
int nBytes = 0;
|
||||
{
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
||||
}
|
||||
if (nBytes > 0)
|
||||
{
|
||||
if (!pnode->ReceiveMsgBytes(pchBuf, nBytes))
|
||||
pnode->CloseSocketDisconnect();
|
||||
pnode->nLastRecv = GetTime();
|
||||
pnode->nRecvBytes += nBytes;
|
||||
{
|
||||
LOCK(pnode->cs_vRecv);
|
||||
pnode->nRecvBytes += nBytes;
|
||||
}
|
||||
pnode->RecordBytesRecv(nBytes);
|
||||
}
|
||||
else if (nBytes == 0)
|
||||
|
@ -1263,9 +1353,7 @@ void ThreadSocketHandler()
|
|||
//
|
||||
// Send
|
||||
//
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
if (FD_ISSET(pnode->hSocket, &fdsetSend))
|
||||
if (sendSet)
|
||||
{
|
||||
TRY_LOCK(pnode->cs_vSend, lockSend);
|
||||
if (lockSend)
|
||||
|
@ -1922,9 +2010,11 @@ public:
|
|||
~CNetCleanup()
|
||||
{
|
||||
// Close sockets
|
||||
for (CNode* pnode : vNodes)
|
||||
for (CNode* pnode : vNodes) {
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket != INVALID_SOCKET)
|
||||
CloseSocket(pnode->hSocket);
|
||||
}
|
||||
for (ListenSocket& hListenSocket : vhListenSocket)
|
||||
if (hListenSocket.socket != INVALID_SOCKET)
|
||||
if (!CloseSocket(hListenSocket.socket))
|
||||
|
@ -2001,12 +2091,14 @@ void CNode::RecordBytesRecv(uint64_t bytes)
|
|||
{
|
||||
LOCK(cs_totalBytesRecv);
|
||||
nTotalBytesRecv += bytes;
|
||||
MetricsCounter("zcash.net.in.bytes.total", bytes);
|
||||
}
|
||||
|
||||
void CNode::RecordBytesSent(uint64_t bytes)
|
||||
{
|
||||
LOCK(cs_totalBytesSent);
|
||||
nTotalBytesSent += bytes;
|
||||
MetricsCounter("zcash.net.out.bytes.total", bytes);
|
||||
|
||||
uint64_t now = GetTime();
|
||||
if (nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now)
|
||||
|
@ -2147,6 +2239,7 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX
|
|||
|
||||
CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
|
||||
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
|
||||
nTimeConnected(GetTime()),
|
||||
addr(addrIn),
|
||||
nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)),
|
||||
addrKnown(5000, 0.001),
|
||||
|
@ -2159,7 +2252,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
|
|||
nLastRecv = 0;
|
||||
nSendBytes = 0;
|
||||
nRecvBytes = 0;
|
||||
nTimeConnected = GetTime();
|
||||
nTimeOffset = 0;
|
||||
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
|
||||
nVersion = 0;
|
||||
|
@ -2218,11 +2310,11 @@ CNode::~CNode()
|
|||
void CNode::ReloadTracingSpan()
|
||||
{
|
||||
if (fLogIPs) {
|
||||
span = TracingSpanFields("info", "net", "Peer",
|
||||
span = TracingSpan("info", "net", "Peer",
|
||||
"id", idStr.c_str(),
|
||||
"addr", addrName.c_str());
|
||||
} else {
|
||||
span = TracingSpanFields("info", "net", "Peer",
|
||||
span = TracingSpan("info", "net", "Peer",
|
||||
"id", idStr.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -2265,13 +2357,16 @@ void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSen
|
|||
{
|
||||
ENTER_CRITICAL_SECTION(cs_vSend);
|
||||
assert(ssSend.size() == 0);
|
||||
assert(strSendCommand.empty());
|
||||
ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0);
|
||||
LogPrint("net", "sending: %s ", SanitizeString(pszCommand));
|
||||
strSendCommand = SanitizeString(pszCommand);
|
||||
LogPrint("net", "sending: %s ", strSendCommand);
|
||||
}
|
||||
|
||||
void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
|
||||
{
|
||||
ssSend.clear();
|
||||
strSendCommand.clear();
|
||||
|
||||
LEAVE_CRITICAL_SECTION(cs_vSend);
|
||||
|
||||
|
@ -2280,6 +2375,7 @@ void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
|
|||
|
||||
void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
|
||||
{
|
||||
MetricsIncrementCounter("zcash.net.out.messages", "command", strSendCommand.c_str());
|
||||
// The -*messagestest options are intentionally not documented in the help message,
|
||||
// since they are only used during development to debug the networking code and are
|
||||
// not intended for end-users.
|
||||
|
@ -2313,6 +2409,10 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
|
|||
std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData());
|
||||
ssSend.GetAndClear(*it);
|
||||
nSendSize += (*it).size();
|
||||
MetricsCounter(
|
||||
"zcash.net.out.bytes", (*it).size(),
|
||||
"command", strSendCommand.c_str());
|
||||
strSendCommand.clear();
|
||||
|
||||
// If write queue empty, attempt "optimistic write"
|
||||
if (it == vSendMsg.begin())
|
||||
|
|
48
src/net.h
48
src/net.h
|
@ -63,6 +63,8 @@ static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
|
|||
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
|
||||
/** The default for -maxuploadtarget. 0 = Unlimited */
|
||||
static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0;
|
||||
/** Default for blocks only*/
|
||||
static const bool DEFAULT_BLOCKSONLY = false;
|
||||
/**
|
||||
* The period before a network upgrade activates, where connections to upgrading peers are preferred (in blocks).
|
||||
* This was three days for upgrades up to and including Blossom, and is 1.5 days from Heartwood onward.
|
||||
|
@ -189,6 +191,7 @@ class CNodeStats
|
|||
public:
|
||||
NodeId nodeid;
|
||||
uint64_t nServices;
|
||||
bool fRelayTxes;
|
||||
int64_t nLastSend;
|
||||
int64_t nLastRecv;
|
||||
int64_t nTimeConnected;
|
||||
|
@ -253,14 +256,17 @@ class CNode
|
|||
{
|
||||
public:
|
||||
// socket
|
||||
uint64_t nServices;
|
||||
std::atomic<uint64_t> nServices;
|
||||
SOCKET hSocket;
|
||||
CDataStream ssSend;
|
||||
std::string strSendCommand; // Current command being assembled in ssSend
|
||||
size_t nSendSize; // total size of all vSendMsg entries
|
||||
size_t nSendOffset; // offset inside the first vSendMsg already sent
|
||||
uint64_t nSendBytes;
|
||||
std::deque<CSerializeData> vSendMsg;
|
||||
CCriticalSection cs_vSend;
|
||||
CCriticalSection cs_hSocket;
|
||||
CCriticalSection cs_vRecv;
|
||||
|
||||
std::deque<CInv> vRecvGetData;
|
||||
std::deque<CNetMessage> vRecvMsg;
|
||||
|
@ -268,19 +274,18 @@ public:
|
|||
uint64_t nRecvBytes;
|
||||
int nRecvVersion;
|
||||
|
||||
int64_t nLastSend;
|
||||
int64_t nLastRecv;
|
||||
int64_t nTimeConnected;
|
||||
int64_t nTimeOffset;
|
||||
std::atomic<int64_t> nLastSend;
|
||||
std::atomic<int64_t> nLastRecv;
|
||||
const int64_t nTimeConnected;
|
||||
std::atomic<int64_t> nTimeOffset;
|
||||
const CAddress addr;
|
||||
std::string addrName;
|
||||
CService addrLocal;
|
||||
int nVersion;
|
||||
// strSubVer is whatever byte array we read from the wire. However, this field is intended
|
||||
// to be printed out, displayed to humans in various forms and so on. So we sanitize it and
|
||||
// store the sanitized version in cleanSubVer. The original should be used when dealing with
|
||||
// the network or wire types and the cleaned string used when displayed or logged.
|
||||
std::string strSubVer, cleanSubVer;
|
||||
CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer
|
||||
bool fWhitelisted; // This peer can bypass DoS banning.
|
||||
bool fOneShot;
|
||||
bool fClient;
|
||||
|
@ -291,14 +296,14 @@ public:
|
|||
// We use fRelayTxes for two purposes -
|
||||
// a) it allows us to not relay tx invs before receiving the peer's version message
|
||||
// b) the peer may tell us in its version message that we should not relay tx invs
|
||||
// until it has initialized its bloom filter.
|
||||
// unless it loads a bloom filter.
|
||||
bool fRelayTxes;
|
||||
bool fSentAddr;
|
||||
CSemaphoreGrant grantOutbound;
|
||||
CCriticalSection cs_filter;
|
||||
CBloomFilter* pfilter;
|
||||
int nRefCount;
|
||||
NodeId id;
|
||||
std::atomic<int> nRefCount;
|
||||
|
||||
const uint64_t nKeyedNetGroup;
|
||||
|
||||
|
@ -324,7 +329,7 @@ protected:
|
|||
|
||||
public:
|
||||
uint256 hashContinue;
|
||||
int nStartingHeight;
|
||||
std::atomic<int> nStartingHeight;
|
||||
|
||||
// flood relay
|
||||
std::vector<CAddress> vAddrToSend;
|
||||
|
@ -341,15 +346,15 @@ public:
|
|||
|
||||
// Ping time measurement:
|
||||
// The pong reply we're expecting, or 0 if no pong expected.
|
||||
uint64_t nPingNonceSent;
|
||||
std::atomic<uint64_t> nPingNonceSent;
|
||||
// Time (in usec) the last ping was sent, or 0 if no ping was ever sent.
|
||||
int64_t nPingUsecStart;
|
||||
std::atomic<int64_t> nPingUsecStart;
|
||||
// Last measured round-trip time.
|
||||
int64_t nPingUsecTime;
|
||||
std::atomic<int64_t> nPingUsecTime;
|
||||
// Best measured round-trip time.
|
||||
int64_t nMinPingUsecTime;
|
||||
std::atomic<int64_t> nMinPingUsecTime;
|
||||
// Whether a ping is requested.
|
||||
bool fPingQueued;
|
||||
std::atomic<bool> fPingQueued;
|
||||
|
||||
CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
|
||||
~CNode();
|
||||
|
@ -372,6 +377,12 @@ private:
|
|||
|
||||
static uint64_t CalculateKeyedNetGroup(const CAddress& ad);
|
||||
|
||||
|
||||
mutable CCriticalSection cs_addrName;
|
||||
std::string addrName;
|
||||
|
||||
CService addrLocal;
|
||||
mutable CCriticalSection cs_addrLocal;
|
||||
public:
|
||||
|
||||
// Regenerate the span for this CNode. This re-queries the log filter to see
|
||||
|
@ -408,6 +419,10 @@ public:
|
|||
msg.SetVersion(nVersionIn);
|
||||
}
|
||||
|
||||
CService GetAddrLocal() const;
|
||||
//! May not be called more than once
|
||||
void SetAddrLocal(const CService& addrLocalIn);
|
||||
|
||||
CNode* AddRef()
|
||||
{
|
||||
nRefCount++;
|
||||
|
@ -696,6 +711,9 @@ public:
|
|||
//!response the time in seconds left in the current max outbound cycle
|
||||
// in case of no limit, it will always respond with 0
|
||||
static uint64_t GetMaxOutboundTimeLeftInCycle();
|
||||
std::string GetAddrName() const;
|
||||
//! Sets the addrName only if it was not previously set
|
||||
void MaybeSetAddrName(const std::string& addrNameIn);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -68,9 +68,8 @@ static void CopyNodeStats(std::vector<CNodeStats>& vstats)
|
|||
LOCK(cs_vNodes);
|
||||
vstats.reserve(vNodes.size());
|
||||
for (CNode* pnode : vNodes) {
|
||||
CNodeStats stats;
|
||||
pnode->copyStats(stats);
|
||||
vstats.push_back(stats);
|
||||
vstats.emplace_back();
|
||||
pnode->copyStats(vstats.back());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,6 +86,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
|
|||
" \"addr\":\"host:port\", (string) The IP address and port of the peer\n"
|
||||
" \"addrlocal\":\"ip:port\", (string) local address\n"
|
||||
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
|
||||
" \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\n"
|
||||
" \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
|
||||
" \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n"
|
||||
" \"bytessent\": n, (numeric) The total bytes sent\n"
|
||||
|
@ -130,6 +130,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
|
|||
if (!(stats.addrLocal.empty()))
|
||||
obj.pushKV("addrlocal", stats.addrLocal);
|
||||
obj.pushKV("services", strprintf("%016x", stats.nServices));
|
||||
obj.pushKV("relaytxes", stats.fRelayTxes);
|
||||
obj.pushKV("lastsend", stats.nLastSend);
|
||||
obj.pushKV("lastrecv", stats.nLastRecv);
|
||||
obj.pushKV("bytessent", stats.nSendBytes);
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
// Copyright (c) 2019 Will Wray https://keybase.io/willwray
|
||||
// Copyright (c) 2020 The Zcash developers
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Repo: https://github.com/willwray/VA_OPT
|
||||
|
||||
#ifndef ZCASH_RUST_INCLUDE_RUST_VA_OPT_H
|
||||
#define ZCASH_RUST_INCLUDE_RUST_VA_OPT_H
|
||||
|
||||
/*
|
||||
VA_OPT.hpp
|
||||
==========
|
||||
|
||||
Preprocessor utilities for testing emptiness of macro arguments
|
||||
and for conditional expansion based on the emptiness of ARGS.
|
||||
|
||||
VA_OPT_SUPPORT(?)
|
||||
1 if __VA_OPT__ support is detected else 0 (see platform note).
|
||||
|
||||
C++20's __VA_OPT__ finally provides a reliable test for empty ARGS.
|
||||
The following macros use __VA_OPT__, if detected, otherwise they
|
||||
provide 'polyfill' fallbacks (though with some failing edge cases).
|
||||
|
||||
IS_EMPTY(...)
|
||||
1 if the ... ARGS is empty else 0.
|
||||
|
||||
IFN(...)
|
||||
If ... ARGS are not empty then a trailing 'paren expression' (X)
|
||||
is deparenthesized to X else the trailing (X) term is consumed.
|
||||
E.g. IFN()(N) vanishes, while IFN(NotEmpty)(N) -> N
|
||||
|
||||
In other words, IFN(ARGS) is like __VA_OPT__, but with explicit
|
||||
(ARGS) in place of an implicit __VA_ARGS__ check.
|
||||
|
||||
IFE(...)
|
||||
If ... ARGS is empty expand trailing 'paren expression' (X) to X
|
||||
else if ARGS are not empty consume the trailing paren expression.
|
||||
E.g. IFE(NotEmpty)(E) vanishes, while IFE()(E) -> E
|
||||
|
||||
IFNE(...)(N,E...)
|
||||
If ... ARGS are not empty expands to N else expands to E...
|
||||
E.g. IFNE(ARG)(X,()) is equivalent to IFN(ARG)(X)IFE(ARG)(())
|
||||
both put back a terminating () removed by the outer macro call.
|
||||
|
||||
Without VA_OPT_SUPPORT these 'emptiness' macros are not perfect;
|
||||
IS_EMPTY, IFN, IFE, IFNE may cause a compile error ('too few args')
|
||||
if the argument is a function-like macro name that expects ARG(s).
|
||||
|
||||
IBP(...)
|
||||
IS_BEGIN_PARENS macro to test if an argument is parenthesised:
|
||||
1 if ... ARGS begins with a 'paren expression' else 0.
|
||||
|
||||
Platform note: Current Sept 2019 __VA_OPT__ support:
|
||||
-------------
|
||||
Clang -std=c++2a enables it. GCC has it enabled without -std=c++2a
|
||||
but warns "__VA_OPT__ is not available until C++2a" if another -std
|
||||
flag is supplied along with -pedantic (dont know how to supress it).
|
||||
MSVC TBD
|
||||
|
||||
Credits
|
||||
-------
|
||||
Props to pre-pro pioneers, particularly Paul Mensonides.
|
||||
The 'emptiness' methods are adapted from BOOST_VMD_IS_EMPTY which,
|
||||
. in turn, depends on BOOST Preprocessor's BOOST_PP_IS_BEGIN_PARENS
|
||||
(adapted and exposed here as IBP 'Is Begin Parens'):
|
||||
www.boost.org/doc/libs/1_71_0/libs/vmd
|
||||
www.boost.org/doc/libs/1_71_0/libs/preprocessor
|
||||
*/
|
||||
|
||||
#define VA_ARG1(A0,A1,...) A1
|
||||
// VA_EMPTY works only if __VA_OPT__ is supported, else always -> 1
|
||||
#define VA_EMPTY(...) VA_ARG1(__VA_OPT__(,)0,1,)
|
||||
|
||||
// VA_OPT_SUPPORT helper macro for __VA_OPT__ feature detection.
|
||||
// Adapted from https://stackoverflow.com/a/48045656/7443483
|
||||
// Use as #if VA_OPT_SUPPORT(?)
|
||||
#define VA_OPT_SUPPORT ! VA_EMPTY
|
||||
|
||||
#if VA_OPT_SUPPORT(?)
|
||||
|
||||
# define IS_EMPTY(...) VA_EMPTY(__VA_ARGS__)
|
||||
# define IFN(...) VA_EAT __VA_OPT__(()VA_IDENT)
|
||||
# define IFE(...) VA_IDENT __VA_OPT__(()VA_EAT)
|
||||
# define IFNE(...) VA_ARGTAIL __VA_OPT__((,)VA_ARG0)
|
||||
|
||||
#else
|
||||
|
||||
# define IS_EMPTY(...) IFP(IBP(__VA_ARGS__))(IE_GEN_0,IE_IBP)(__VA_ARGS__)
|
||||
# define IFN(...) IFP(IBP(__VA_ARGS__))(GEN_IDENT,EAT_OR_IDENT)(__VA_ARGS__)
|
||||
# define IFE(...) IFP(IBP(__VA_ARGS__))(GEN_EAT,IDENT_OR_EAT)(__VA_ARGS__)
|
||||
# define IFNE(...) IFP(IBP(__VA_ARGS__))(GEN_ARGTAIL,ARG0_OR_TAIL)(__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#define VA_EAT(...)
|
||||
#define VA_IDENT(...) __VA_ARGS__
|
||||
#define VA_ARG0_(A0,...) A0
|
||||
#define VA_ARG0(...) VA_ARG0_(__VA_ARGS__)
|
||||
#define VA_ARGTAIL_(A0,...) __VA_ARGS__
|
||||
#define VA_ARGTAIL(...) VA_ARGTAIL_(__VA_ARGS__)
|
||||
|
||||
// IFP helper macros to test IBP for IFN and IS_EMPTY
|
||||
#define IFP_0(T,...) __VA_ARGS__
|
||||
#define IFP_1(T,...) T
|
||||
|
||||
#define IFP_CAT(A,...) A##__VA_ARGS__
|
||||
#define IFP(BP) IFP_CAT(IFP_,BP)
|
||||
|
||||
// IS_BEGIN_PAREN helper macros adapted from BOOST VMD
|
||||
#define IBP_CAT_(A,...) A##__VA_ARGS__
|
||||
#define IBP_CAT(A,...) IBP_CAT_(A,__VA_ARGS__)
|
||||
|
||||
#define IBP_ARG0_(A,...) A
|
||||
#define IBP_ARG0(...) IBP_ARG0_(__VA_ARGS__)
|
||||
|
||||
#define IBP_IS_ARGS(...) 1
|
||||
|
||||
#define IBP_1 1,
|
||||
#define IBP_IBP_IS_ARGS 0,
|
||||
|
||||
// IBP IS_BEGIN_PAREN returns 1 or 0 if ... ARGS is parenthesised
|
||||
#define IBP(...) IBP_ARG0(IBP_CAT(IBP_, IBP_IS_ARGS __VA_ARGS__))
|
||||
|
||||
// IFN, IFE, IFNE and IF_EMPTY helpers without __VA_OPT__ support
|
||||
#if ! VA_OPT_SUPPORT(?)
|
||||
|
||||
# define IBP_(T,...) IBP_ARG0(IBP_CAT(IF##T##_, IBP_IS_ARGS __VA_ARGS__))
|
||||
|
||||
// IS_EMPTY helper macros, depend on IBP
|
||||
# define IE_REDUCE_IBP(...) ()
|
||||
# define IE_GEN_0(...) 0
|
||||
# define IE_IBP(...) IBP(IE_REDUCE_IBP __VA_ARGS__ ())
|
||||
|
||||
# define GEN_IDENT(...) VA_IDENT
|
||||
# define GEN_EAT(...) VA_EAT
|
||||
# define GEN_ARGTAIL(...) VA_ARGTAIL
|
||||
# define GEN_ARG0(...) VA_ARG0
|
||||
|
||||
// IFN, IFE, IFNE helper macros
|
||||
# define EAT_OR_IDENT(...) IBP_(N,IE_REDUCE_IBP __VA_ARGS__ ())
|
||||
# define IFN_1 VA_EAT,
|
||||
# define IFN_IBP_IS_ARGS VA_IDENT,
|
||||
|
||||
# define IDENT_OR_EAT(...) IBP_(E,IE_REDUCE_IBP __VA_ARGS__ ())
|
||||
# define IFE_1 VA_IDENT,
|
||||
# define IFE_IBP_IS_ARGS VA_EAT,
|
||||
|
||||
# define ARG0_OR_TAIL(...) IBP_(NE,IE_REDUCE_IBP __VA_ARGS__ ())
|
||||
# define IFNE_1 VA_ARGTAIL,
|
||||
# define IFNE_IBP_IS_ARGS VA_ARG0,
|
||||
|
||||
#endif // IFN and IF_EMPTY defs
|
||||
|
||||
#endif // ZCASH_RUST_INCLUDE_RUST_VA_OPT_H
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2020 Jack Grigg
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#ifndef ZCASH_RUST_INCLUDE_RUST_HELPERS_H
|
||||
#define ZCASH_RUST_INCLUDE_RUST_HELPERS_H
|
||||
|
||||
#include "rust/map.h"
|
||||
#include "rust/VA_OPT.hpp"
|
||||
|
||||
//
|
||||
// Helper macros
|
||||
//
|
||||
|
||||
#define MAP_PAIR_LIST0(f, x, y, peek, ...) f(x, y) MAP_LIST_NEXT(peek, MAP_PAIR_LIST1)(f, peek, __VA_ARGS__)
|
||||
#define MAP_PAIR_LIST1(f, x, y, peek, ...) f(x, y) MAP_LIST_NEXT(peek, MAP_PAIR_LIST0)(f, peek, __VA_ARGS__)
|
||||
|
||||
/// Applies the function macro `f` to each pair of the remaining parameters and
|
||||
/// inserts commas between the results.
|
||||
#define MAP_PAIR_LIST(f, ...) EVAL(MAP_PAIR_LIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
|
||||
|
||||
#define T_FIELD_NAME(x, y) x
|
||||
#define T_FIELD_VALUE(x, y) y
|
||||
|
||||
#define T_FIELD_NAMES(...) IFN(__VA_ARGS__)(MAP_PAIR_LIST(T_FIELD_NAME, __VA_ARGS__))
|
||||
#define T_FIELD_VALUES(...) IFN(__VA_ARGS__)(MAP_PAIR_LIST(T_FIELD_VALUE, __VA_ARGS__))
|
||||
|
||||
#define T_DOUBLEESCAPE(a) #a
|
||||
#define T_ESCAPEQUOTE(a) T_DOUBLEESCAPE(a)
|
||||
|
||||
// Computes the length of the given array. This is COUNT_OF from Chromium.
|
||||
#define T_ARRLEN(x) ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
|
||||
|
||||
#endif // ZCASH_RUST_INCLUDE_RUST_HELPERS_H
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012 William Swanson
|
||||
* Copyright (C) 2020 The Zcash developers
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -26,8 +27,8 @@
|
|||
* prior written authorization from the authors.
|
||||
*/
|
||||
|
||||
#ifndef ZCASH_RUST_INCLUDE_TRACING_MAP_H
|
||||
#define ZCASH_RUST_INCLUDE_TRACING_MAP_H
|
||||
#ifndef ZCASH_RUST_INCLUDE_RUST_MAP_H
|
||||
#define ZCASH_RUST_INCLUDE_RUST_MAP_H
|
||||
|
||||
#define EVAL0(...) __VA_ARGS__
|
||||
#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
|
||||
|
@ -67,4 +68,4 @@
|
|||
*/
|
||||
#define MAP_LIST(f, ...) EVAL(MAP_LIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
|
||||
|
||||
#endif // ZCASH_RUST_INCLUDE_TRACING_MAP_H
|
||||
#endif // ZCASH_RUST_INCLUDE_RUST_MAP_H
|
|
@ -0,0 +1,314 @@
|
|||
// Copyright (c) 2020 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#ifndef ZCASH_RUST_INCLUDE_RUST_METRICS_H
|
||||
#define ZCASH_RUST_INCLUDE_RUST_METRICS_H
|
||||
|
||||
#include "rust/helpers.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Initializes the metrics runtime and runs the Prometheus exporter in a new
|
||||
/// thread.
|
||||
///
|
||||
/// bind_address is an IP address to bind to, or empty to use the default.
|
||||
///
|
||||
/// Returns false on any error.
|
||||
bool metrics_run(
|
||||
const char* bind_address,
|
||||
const char* const* allow_ips,
|
||||
size_t allow_ips_len,
|
||||
uint16_t prometheus_port);
|
||||
|
||||
struct MetricsCallsite;
|
||||
typedef struct MetricsCallsite MetricsCallsite;
|
||||
|
||||
struct MetricsKey;
|
||||
typedef struct MetricsKey MetricsKey;
|
||||
|
||||
/// Creates a metrics callsite.
|
||||
///
|
||||
/// This API supports labels that MUST have static values. For non-static label
|
||||
/// values, use `metrics_key`.
|
||||
///
|
||||
/// You should usually call one of the helper macros such as `MetricsCounter`
|
||||
/// instead of calling this directly.
|
||||
///
|
||||
/// This MUST ONLY be called to assign a `static MetricsCallsite*`, and all
|
||||
/// string arguments MUST be static `const char*` constants, and MUST be valid
|
||||
/// UTF-8.
|
||||
MetricsCallsite* metrics_callsite(
|
||||
const char* name,
|
||||
const char* const* label_names,
|
||||
const char* const* label_values,
|
||||
size_t labels_len);
|
||||
|
||||
/// Creates a metrics key.
|
||||
///
|
||||
/// This API supports labels that may not have static values, and is intended
|
||||
/// to be called for each metrics callsite invocation. As such, it returns null
|
||||
/// if a metrics recorder is not installed, to save on construction costs.
|
||||
///
|
||||
/// You should usually call one of the helper macros such as `MetricsCounter`
|
||||
/// instead of calling this directly.
|
||||
///
|
||||
/// API requirements:
|
||||
/// - label_names and label_values, if not null, MUST be the same length.
|
||||
/// - All string arguments MUST be valid UTF-8.
|
||||
MetricsKey* metrics_key(
|
||||
const char* name,
|
||||
const char* const* label_names,
|
||||
const char* const* label_values,
|
||||
size_t labels_len);
|
||||
|
||||
/// Increments a counter.
|
||||
///
|
||||
/// Counters represent a single monotonic value, which means the value can only
|
||||
/// be incremented, not decremented, and always starts out with an initial value
|
||||
/// of zero.
|
||||
void metrics_static_increment_counter(const MetricsCallsite* callsite, uint64_t value);
|
||||
|
||||
/// Increments a counter.
|
||||
///
|
||||
/// Counters represent a single monotonic value, which means the value can only
|
||||
/// be incremented, not decremented, and always starts out with an initial value
|
||||
/// of zero.
|
||||
void metrics_increment_counter(MetricsKey* key, uint64_t value);
|
||||
|
||||
/// Updates a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
void metrics_static_update_gauge(const MetricsCallsite* callsite, double value);
|
||||
|
||||
/// Updates a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
void metrics_update_gauge(MetricsKey* callsite, double value);
|
||||
|
||||
/// Increments a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
void metrics_static_increment_gauge(const MetricsCallsite* callsite, double value);
|
||||
|
||||
/// Increments a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
void metrics_increment_gauge(MetricsKey* callsite, double value);
|
||||
|
||||
/// Decrements a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
void metrics_static_decrement_gauge(const MetricsCallsite* callsite, double value);
|
||||
|
||||
/// Decrements a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
void metrics_decrement_gauge(MetricsKey* callsite, double value);
|
||||
|
||||
/// Records a histogram.
|
||||
///
|
||||
/// Histograms measure the distribution of values for a given set of
|
||||
/// measurements, and start with no initial values.
|
||||
void metrics_static_record_histogram(const MetricsCallsite* callsite, double value);
|
||||
|
||||
/// Records a histogram.
|
||||
///
|
||||
/// Histograms measure the distribution of values for a given set of
|
||||
/// measurements, and start with no initial values.
|
||||
void metrics_record_histogram(MetricsKey* callsite, double value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Helper macros
|
||||
//
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Constructs a metrics callsite.
|
||||
//
|
||||
// The 'static constexpr' hack ensures that all arguments are compile-time
|
||||
// constants with static storage duration. The output of this macro MUST be
|
||||
// stored as a static MetricsCallsite*.
|
||||
#define M_CALLSITE(name, label_names, label_values) ([&] { \
|
||||
static constexpr const char* _m_name = name; \
|
||||
static constexpr const char* const* _m_label_names = \
|
||||
label_names; \
|
||||
static constexpr const char* const* _m_label_values = \
|
||||
label_values; \
|
||||
return metrics_callsite( \
|
||||
_m_name, _m_label_names, _m_label_values, \
|
||||
T_ARRLEN(label_names)); \
|
||||
}())
|
||||
#else
|
||||
// Constructs a metrics callsite.
|
||||
//
|
||||
// All arguments MUST be static constants, and the output of this macro MUST be
|
||||
// stored as a static MetricsCallsite*.
|
||||
#define M_CALLSITE(name, label_names, label_values) \
|
||||
metrics_callsite(name, label_names, label_values, T_ARRLEN(label_names))
|
||||
#endif
|
||||
|
||||
// Constructs a metrics key.
|
||||
#define M_KEY(name, labels, values) \
|
||||
metrics_key( \
|
||||
name, \
|
||||
labels, \
|
||||
values, \
|
||||
T_ARRLEN(labels))
|
||||
|
||||
//
|
||||
// Metrics
|
||||
//
|
||||
|
||||
/// Increments a counter.
|
||||
///
|
||||
/// Counters represent a single monotonic value, which means the value can only
|
||||
/// be incremented, not decremented, and always starts out with an initial value
|
||||
/// of zero.
|
||||
///
|
||||
/// name MUST be a static constant, and all strings MUST be valid UTF-8.
|
||||
#define MetricsCounter(name, value, ...) \
|
||||
do { \
|
||||
IFE(__VA_ARGS__) \
|
||||
(static constexpr const char* const EMPTY[] = {}; \
|
||||
static MetricsCallsite* CALLSITE = \
|
||||
M_CALLSITE(name, EMPTY, EMPTY); \
|
||||
metrics_static_increment_counter(CALLSITE, value);) \
|
||||
IFN(__VA_ARGS__)(const char* M_LABELS[] = \
|
||||
{T_FIELD_NAMES(__VA_ARGS__)}; \
|
||||
const char* M_VALUES[] = \
|
||||
{T_FIELD_VALUES(__VA_ARGS__)}; \
|
||||
MetricsKey* KEY = \
|
||||
M_KEY(name, M_LABELS, M_VALUES); \
|
||||
metrics_increment_counter(KEY, value);) \
|
||||
} while (0)
|
||||
|
||||
/// Increments a counter by one.
|
||||
///
|
||||
/// Counters represent a single monotonic value, which means the value can only
|
||||
/// be incremented, not decremented, and always starts out with an initial value
|
||||
/// of zero.
|
||||
///
|
||||
/// name MUST be a static constant, and all strings MUST be valid UTF-8.
|
||||
#define MetricsIncrementCounter(name, ...) MetricsCounter(name, 1, __VA_ARGS__)
|
||||
|
||||
/// Updates a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
///
|
||||
/// name MUST be a static constant, and all strings MUST be valid UTF-8.
|
||||
#define MetricsGauge(name, value, ...) \
|
||||
do { \
|
||||
IFE(__VA_ARGS__) \
|
||||
(static constexpr const char* const EMPTY[] = {}; \
|
||||
static MetricsCallsite* CALLSITE = \
|
||||
M_CALLSITE(name, EMPTY, EMPTY); \
|
||||
metrics_static_update_gauge(CALLSITE, value);) \
|
||||
IFN(__VA_ARGS__)(const char* M_LABELS[] = \
|
||||
{T_FIELD_NAMES(__VA_ARGS__)}; \
|
||||
const char* M_VALUES[] = \
|
||||
{T_FIELD_VALUES(__VA_ARGS__)}; \
|
||||
MetricsKey* KEY = \
|
||||
M_KEY(name, M_LABELS, M_VALUES); \
|
||||
metrics_update_gauge(KEY, value);) \
|
||||
} while (0)
|
||||
|
||||
/// Updates a gauge with optional static labels.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
///
|
||||
/// name MUST be a static constant, and all strings MUST be valid UTF-8.
|
||||
#define MetricsStaticGauge(name, value, ...) \
|
||||
do { \
|
||||
static constexpr const char* M_LABELS[] = \
|
||||
{T_FIELD_NAMES(__VA_ARGS__)}; \
|
||||
static constexpr const char* M_VALUES[] = \
|
||||
{T_FIELD_VALUES(__VA_ARGS__)}; \
|
||||
static MetricsCallsite* CALLSITE = \
|
||||
M_CALLSITE(name, M_LABELS, M_VALUES); \
|
||||
metrics_static_update_gauge(CALLSITE, value); \
|
||||
} while (0)
|
||||
|
||||
/// Increments a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
///
|
||||
/// name MUST be a static constant, and all strings MUST be valid UTF-8.
|
||||
#define MetricsIncrementGauge(name, value, ...) \
|
||||
do { \
|
||||
IFE(__VA_ARGS__) \
|
||||
(static constexpr const char* const EMPTY[] = {}; \
|
||||
static MetricsCallsite* CALLSITE = \
|
||||
M_CALLSITE(name, EMPTY, EMPTY); \
|
||||
metrics_static_increment_gauge(CALLSITE, value);) \
|
||||
IFN(__VA_ARGS__)(const char* M_LABELS[] = \
|
||||
{T_FIELD_NAMES(__VA_ARGS__)}; \
|
||||
const char* M_VALUES[] = \
|
||||
{T_FIELD_VALUES(__VA_ARGS__)}; \
|
||||
MetricsKey* KEY = \
|
||||
M_KEY(name, M_LABELS, M_VALUES); \
|
||||
metrics_increment_gauge(KEY, value);) \
|
||||
} while (0)
|
||||
|
||||
/// Decrements a gauge.
|
||||
///
|
||||
/// Gauges represent a single value that can go up or down over time, and always
|
||||
/// starts out with an initial value of zero.
|
||||
///
|
||||
/// name MUST be a static constant, and all strings MUST be valid UTF-8.
|
||||
#define MetricsDecrementGauge(name, value, ...) \
|
||||
do { \
|
||||
IFE(__VA_ARGS__) \
|
||||
(static constexpr const char* const EMPTY[] = {}; \
|
||||
static MetricsCallsite* CALLSITE = \
|
||||
M_CALLSITE(name, EMPTY, EMPTY); \
|
||||
metrics_static_decrement_gauge(CALLSITE, value);) \
|
||||
IFN(__VA_ARGS__)(const char* M_LABELS[] = \
|
||||
{T_FIELD_NAMES(__VA_ARGS__)}; \
|
||||
const char* M_VALUES[] = \
|
||||
{T_FIELD_VALUES(__VA_ARGS__)}; \
|
||||
MetricsKey* KEY = \
|
||||
M_KEY(name, M_LABELS, M_VALUES); \
|
||||
metrics_decrement_gauge(KEY, value);) \
|
||||
} while (0)
|
||||
|
||||
/// Records a histogram.
|
||||
///
|
||||
/// Histograms measure the distribution of values for a given set of
|
||||
/// measurements, and start with no initial values.
|
||||
///
|
||||
/// name MUST be a static constant, and all strings MUST be valid UTF-8.
|
||||
#define MetricsHistogram(name, value, ...) \
|
||||
do { \
|
||||
IFE(__VA_ARGS__) \
|
||||
(static constexpr const char* const EMPTY[] = {}; \
|
||||
static MetricsCallsite* CALLSITE = \
|
||||
M_CALLSITE(name, EMPTY, EMPTY); \
|
||||
metrics_static_record_histogram(CALLSITE, value);) \
|
||||
IFN(__VA_ARGS__)(const char* M_LABELS[] = \
|
||||
{T_FIELD_NAMES(__VA_ARGS__)}; \
|
||||
const char* M_VALUES[] = \
|
||||
{T_FIELD_VALUES(__VA_ARGS__)}; \
|
||||
MetricsKey* KEY = \
|
||||
M_KEY(name, M_LABELS, M_VALUES); \
|
||||
metrics_record_histogram(KEY, value);) \
|
||||
} while (0)
|
||||
|
||||
#endif // ZCASH_RUST_INCLUDE_RUST_METRICS_H
|
|
@ -5,8 +5,8 @@
|
|||
#ifndef ZCASH_RUST_INCLUDE_TRACING_H
|
||||
#define ZCASH_RUST_INCLUDE_TRACING_H
|
||||
|
||||
#include "rust/helpers.h"
|
||||
#include "rust/types.h"
|
||||
#include "tracing/map.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
@ -107,25 +107,6 @@ void tracing_log(
|
|||
// Helper macros
|
||||
//
|
||||
|
||||
#define MAP_PAIR_LIST0(f, x, y, peek, ...) f(x, y) MAP_LIST_NEXT(peek, MAP_PAIR_LIST1)(f, peek, __VA_ARGS__)
|
||||
#define MAP_PAIR_LIST1(f, x, y, peek, ...) f(x, y) MAP_LIST_NEXT(peek, MAP_PAIR_LIST0)(f, peek, __VA_ARGS__)
|
||||
|
||||
/// Applies the function macro `f` to each pair of the remaining parameters and
|
||||
/// inserts commas between the results.
|
||||
#define MAP_PAIR_LIST(f, ...) EVAL(MAP_PAIR_LIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
|
||||
|
||||
#define T_FIELD_NAME(x, y) x
|
||||
#define T_FIELD_VALUE(x, y) y
|
||||
|
||||
#define T_FIELD_NAMES(...) MAP_PAIR_LIST(T_FIELD_NAME, __VA_ARGS__)
|
||||
#define T_FIELD_VALUES(...) MAP_PAIR_LIST(T_FIELD_VALUE, __VA_ARGS__)
|
||||
|
||||
#define T_DOUBLEESCAPE(a) #a
|
||||
#define T_ESCAPEQUOTE(a) T_DOUBLEESCAPE(a)
|
||||
|
||||
// Computes the length of the given array. This is COUNT_OF from Chromium.
|
||||
#define T_ARRLEN(x) ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Constructs a tracing callsite.
|
||||
//
|
||||
|
@ -251,22 +232,6 @@ public:
|
|||
};
|
||||
} // namespace tracing
|
||||
|
||||
/// Expands to a `tracing::Span` object which is used to record a span.
|
||||
/// The `Span::Enter` method on that object records that the span has been
|
||||
/// entered, and returns a RAII guard object, which will exit the span when
|
||||
/// dropped.
|
||||
///
|
||||
/// level, target, and name MUST be static constants, and MUST be valid UTF-8
|
||||
/// strings.
|
||||
#define TracingSpan(level, target, name) ([&] { \
|
||||
static constexpr const char* const FIELDS[] = {}; \
|
||||
const char* T_VALUES[] = {}; \
|
||||
static TracingCallsite* CALLSITE = \
|
||||
T_CALLSITE(name, target, level, FIELDS, true); \
|
||||
return tracing::Span( \
|
||||
CALLSITE, T_VALUES, T_ARRLEN(T_VALUES)); \
|
||||
}())
|
||||
|
||||
/// Expands to a `tracing::Span` object which is used to record a span.
|
||||
/// The `Span::Enter` method on that object records that the span has been
|
||||
/// entered, and returns a RAII guard object, which will exit the span when
|
||||
|
@ -276,15 +241,15 @@ public:
|
|||
///
|
||||
/// level, target, name, and all keys MUST be static constants, and MUST be
|
||||
/// valid UTF-8 strings.
|
||||
#define TracingSpanFields(level, target, name, ...) ([&] { \
|
||||
static constexpr const char* const FIELDS[] = \
|
||||
{T_FIELD_NAMES(__VA_ARGS__)}; \
|
||||
const char* T_VALUES[] = \
|
||||
{T_FIELD_VALUES(__VA_ARGS__)}; \
|
||||
static TracingCallsite* CALLSITE = \
|
||||
T_CALLSITE(name, target, level, FIELDS, true); \
|
||||
return tracing::Span( \
|
||||
CALLSITE, T_VALUES, T_ARRLEN(T_VALUES)); \
|
||||
#define TracingSpan(level, target, name, ...) ([&] { \
|
||||
static constexpr const char* const FIELDS[] = \
|
||||
{T_FIELD_NAMES(__VA_ARGS__)}; \
|
||||
const char* T_VALUES[] = \
|
||||
{T_FIELD_VALUES(__VA_ARGS__)}; \
|
||||
static TracingCallsite* CALLSITE = \
|
||||
T_CALLSITE(name, target, level, FIELDS, true); \
|
||||
return tracing::Span( \
|
||||
CALLSITE, T_VALUES, T_ARRLEN(T_VALUES)); \
|
||||
}())
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
use libc::{c_char, c_double};
|
||||
use metrics::{try_recorder, GaugeValue, Key, KeyData, Label};
|
||||
use metrics_exporter_prometheus::PrometheusBuilder;
|
||||
use std::ffi::CStr;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use tracing::error;
|
||||
|
||||
mod prometheus;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_run(
|
||||
bind_address: *const c_char,
|
||||
allow_ips: *const *const c_char,
|
||||
allow_ips_len: usize,
|
||||
prometheus_port: u16,
|
||||
) -> bool {
|
||||
// Parse any allowed IPs.
|
||||
let allow_ips = unsafe { slice::from_raw_parts(allow_ips, allow_ips_len) };
|
||||
let mut allow_ips: Vec<ipnet::IpNet> = match allow_ips
|
||||
.iter()
|
||||
.map(|&p| unsafe { CStr::from_ptr(p) })
|
||||
.map(|s| {
|
||||
s.to_str().ok().and_then(|s| {
|
||||
s.parse()
|
||||
.map_err(|e| {
|
||||
error!("Invalid -metricsallowip argument '{}': {}", s, e);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
{
|
||||
Some(ips) => ips,
|
||||
None => {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// We always allow localhost.
|
||||
allow_ips.extend(&["127.0.0.0/8".parse().unwrap(), "::1/128".parse().unwrap()]);
|
||||
|
||||
// Parse the address to bind to.
|
||||
let bind_address = SocketAddr::new(
|
||||
if allow_ips.is_empty() {
|
||||
// Default to loopback if not allowing external IPs.
|
||||
"127.0.0.1".parse::<IpAddr>().unwrap()
|
||||
} else if bind_address.is_null() {
|
||||
// No specific bind address specified, bind to any.
|
||||
"0.0.0.0".parse::<IpAddr>().unwrap()
|
||||
} else {
|
||||
match unsafe { CStr::from_ptr(bind_address) }
|
||||
.to_str()
|
||||
.ok()
|
||||
.and_then(|s| s.parse::<IpAddr>().ok())
|
||||
{
|
||||
Some(addr) => addr,
|
||||
None => {
|
||||
error!("Invalid -metricsbind argument");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
prometheus_port,
|
||||
);
|
||||
|
||||
prometheus::install(bind_address, PrometheusBuilder::new(), allow_ips).is_ok()
|
||||
}
|
||||
|
||||
pub struct FfiCallsite {
|
||||
key_data: KeyData,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_callsite(
|
||||
name: *const c_char,
|
||||
label_names: *const *const c_char,
|
||||
label_values: *const *const c_char,
|
||||
labels_len: usize,
|
||||
) -> *mut FfiCallsite {
|
||||
let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
|
||||
let labels = unsafe { slice::from_raw_parts(label_names, labels_len) };
|
||||
let values = unsafe { slice::from_raw_parts(label_values, labels_len) };
|
||||
|
||||
let stringify = |s: &[_]| {
|
||||
s.iter()
|
||||
.map(|&p| unsafe { CStr::from_ptr(p) })
|
||||
.map(|cs| cs.to_string_lossy().into_owned())
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let labels = stringify(labels);
|
||||
let values = stringify(values);
|
||||
|
||||
let labels: Vec<_> = labels
|
||||
.into_iter()
|
||||
.zip(values.into_iter())
|
||||
.map(|(name, value)| Label::new(name, value))
|
||||
.collect();
|
||||
|
||||
Box::into_raw(Box::new(FfiCallsite {
|
||||
key_data: KeyData::from_parts(name, labels),
|
||||
}))
|
||||
}
|
||||
|
||||
pub struct FfiKey {
|
||||
inner: Key,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_key(
|
||||
name: *const c_char,
|
||||
label_names: *const *const c_char,
|
||||
label_values: *const *const c_char,
|
||||
labels_len: usize,
|
||||
) -> *mut FfiKey {
|
||||
if try_recorder().is_none() {
|
||||
// No recorder is currently installed, so don't genenerate a key. We check for
|
||||
// null inside each API that consumes an FfiKey, just in case a recorder was
|
||||
// installed in a racy way.
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
|
||||
let labels = unsafe { slice::from_raw_parts(label_names, labels_len) };
|
||||
let values = unsafe { slice::from_raw_parts(label_values, labels_len) };
|
||||
|
||||
let stringify = |s: &[_]| {
|
||||
s.iter()
|
||||
.map(|&p| unsafe { CStr::from_ptr(p) })
|
||||
.map(|cs| cs.to_string_lossy().into_owned())
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let labels = stringify(labels);
|
||||
let values = stringify(values);
|
||||
|
||||
let labels: Vec<_> = labels
|
||||
.into_iter()
|
||||
.zip(values.into_iter())
|
||||
.map(|(name, value)| Label::new(name, value))
|
||||
.collect();
|
||||
|
||||
Box::into_raw(Box::new(FfiKey {
|
||||
inner: Key::Owned(KeyData::from_parts(name, labels)),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_static_increment_counter(callsite: *const FfiCallsite, value: u64) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
let callsite = unsafe { callsite.as_ref().unwrap() };
|
||||
recorder.increment_counter(Key::Borrowed(&callsite.key_data), value);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_increment_counter(key: *mut FfiKey, value: u64) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
if !key.is_null() {
|
||||
let key = unsafe { Box::from_raw(key) };
|
||||
recorder.increment_counter(key.inner, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_static_update_gauge(callsite: *const FfiCallsite, value: c_double) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
let callsite = unsafe { callsite.as_ref().unwrap() };
|
||||
recorder.update_gauge(
|
||||
Key::Borrowed(&callsite.key_data),
|
||||
GaugeValue::Absolute(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_update_gauge(key: *mut FfiKey, value: c_double) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
if !key.is_null() {
|
||||
let key = unsafe { Box::from_raw(key) };
|
||||
recorder.update_gauge(key.inner, GaugeValue::Absolute(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_static_increment_gauge(callsite: *const FfiCallsite, value: c_double) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
let callsite = unsafe { callsite.as_ref().unwrap() };
|
||||
recorder.update_gauge(
|
||||
Key::Borrowed(&callsite.key_data),
|
||||
GaugeValue::Increment(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_increment_gauge(key: *mut FfiKey, value: c_double) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
if !key.is_null() {
|
||||
let key = unsafe { Box::from_raw(key) };
|
||||
recorder.update_gauge(key.inner, GaugeValue::Increment(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_static_decrement_gauge(callsite: *const FfiCallsite, value: c_double) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
let callsite = unsafe { callsite.as_ref().unwrap() };
|
||||
recorder.update_gauge(
|
||||
Key::Borrowed(&callsite.key_data),
|
||||
GaugeValue::Decrement(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_decrement_gauge(key: *mut FfiKey, value: c_double) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
if !key.is_null() {
|
||||
let key = unsafe { Box::from_raw(key) };
|
||||
recorder.update_gauge(key.inner, GaugeValue::Decrement(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_static_record_histogram(callsite: *const FfiCallsite, value: c_double) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
let callsite = unsafe { callsite.as_ref().unwrap() };
|
||||
recorder.record_histogram(Key::Borrowed(&callsite.key_data), value);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn metrics_record_histogram(key: *mut FfiKey, value: c_double) {
|
||||
if let Some(recorder) = try_recorder() {
|
||||
if !key.is_null() {
|
||||
let key = unsafe { Box::from_raw(key) };
|
||||
recorder.record_histogram(key.inner, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
// This is mostly code copied from metrics_exporter_prometheus. The copied portions are
|
||||
// licensed under the same terms as the zcash codebase (reproduced below from
|
||||
// https://github.com/metrics-rs/metrics/blob/main/metrics-exporter-prometheus/LICENSE):
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
use hyper::{
|
||||
server::{conn::AddrStream, Server},
|
||||
service::{make_service_fn, service_fn},
|
||||
{Body, Error as HyperError, Response, StatusCode},
|
||||
};
|
||||
use metrics::SetRecorderError;
|
||||
use metrics_exporter_prometheus::{PrometheusBuilder, PrometheusRecorder};
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::thread;
|
||||
use thiserror::Error as ThisError;
|
||||
use tokio::{pin, runtime, select};
|
||||
|
||||
/// Errors that could occur while installing a Prometheus recorder/exporter.
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum InstallError {
|
||||
/// Creating the networking event loop did not succeed.
|
||||
#[error("failed to spawn Tokio runtime for endpoint: {0}")]
|
||||
Io(#[from] io::Error),
|
||||
|
||||
/// Binding/listening to the given address did not succeed.
|
||||
#[error("failed to bind to given listen address: {0}")]
|
||||
Hyper(#[from] HyperError),
|
||||
|
||||
/// Installing the recorder did not succeed.
|
||||
#[error("failed to install exporter as global recorder: {0}")]
|
||||
Recorder(#[from] SetRecorderError),
|
||||
}
|
||||
|
||||
/// A copy of `PrometheusBuilder::build_with_exporter` that adds support for an IP address
|
||||
/// or subnet allowlist.
|
||||
pub(super) fn build(
|
||||
bind_address: SocketAddr,
|
||||
builder: PrometheusBuilder,
|
||||
allow_ips: Vec<ipnet::IpNet>,
|
||||
) -> Result<
|
||||
(
|
||||
PrometheusRecorder,
|
||||
impl Future<Output = Result<(), HyperError>> + Send + 'static,
|
||||
),
|
||||
InstallError,
|
||||
> {
|
||||
let recorder = builder.build();
|
||||
let handle = recorder.handle();
|
||||
|
||||
let server = Server::try_bind(&bind_address)?;
|
||||
|
||||
let exporter = async move {
|
||||
let make_svc = make_service_fn(move |socket: &AddrStream| {
|
||||
let remote_addr = socket.remote_addr().ip();
|
||||
let allowed = allow_ips.iter().any(|subnet| subnet.contains(&remote_addr));
|
||||
let handle = handle.clone();
|
||||
|
||||
async move {
|
||||
Ok::<_, HyperError>(service_fn(move |_| {
|
||||
let handle = handle.clone();
|
||||
|
||||
async move {
|
||||
if allowed {
|
||||
let output = handle.render();
|
||||
Ok(Response::new(Body::from(output)))
|
||||
} else {
|
||||
Response::builder()
|
||||
.status(StatusCode::FORBIDDEN)
|
||||
.body(Body::empty())
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
server.serve(make_svc).await
|
||||
};
|
||||
|
||||
Ok((recorder, exporter))
|
||||
}
|
||||
|
||||
/// A copy of `PrometheusBuilder::install` that adds support for an IP address or subnet
|
||||
/// allowlist.
|
||||
pub(super) fn install(
|
||||
bind_address: SocketAddr,
|
||||
builder: PrometheusBuilder,
|
||||
allow_ips: Vec<ipnet::IpNet>,
|
||||
) -> Result<(), InstallError> {
|
||||
let runtime = runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()?;
|
||||
|
||||
let (recorder, exporter) = {
|
||||
let _guard = runtime.enter();
|
||||
build(bind_address, builder, allow_ips)?
|
||||
};
|
||||
metrics::set_boxed_recorder(Box::new(recorder))?;
|
||||
|
||||
thread::Builder::new()
|
||||
.name("zcash-prometheus".to_string())
|
||||
.spawn(move || {
|
||||
runtime.block_on(async move {
|
||||
pin!(exporter);
|
||||
loop {
|
||||
select! {
|
||||
_ = &mut exporter => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -63,6 +63,7 @@ use zcash_history::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree}
|
|||
|
||||
mod blake2b;
|
||||
mod ed25519;
|
||||
mod metrics_ffi;
|
||||
mod tracing_ffi;
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -145,19 +146,18 @@ pub extern "C" fn librustzcash_init_zksnark_params(
|
|||
);
|
||||
|
||||
// Load params
|
||||
let (spend_params, spend_vk, output_params, output_vk, sprout_vk) =
|
||||
load_parameters(spend_path, output_path, sprout_path);
|
||||
let params = load_parameters(spend_path, output_path, sprout_path);
|
||||
|
||||
// Caller is responsible for calling this function once, so
|
||||
// these global mutations are safe.
|
||||
unsafe {
|
||||
SAPLING_SPEND_PARAMS = Some(spend_params);
|
||||
SAPLING_OUTPUT_PARAMS = Some(output_params);
|
||||
SAPLING_SPEND_PARAMS = Some(params.spend_params);
|
||||
SAPLING_OUTPUT_PARAMS = Some(params.output_params);
|
||||
SPROUT_GROTH16_PARAMS_PATH = sprout_path.map(|p| p.to_owned());
|
||||
|
||||
SAPLING_SPEND_VK = Some(spend_vk);
|
||||
SAPLING_OUTPUT_VK = Some(output_vk);
|
||||
SPROUT_GROTH16_VK = sprout_vk;
|
||||
SAPLING_SPEND_VK = Some(params.spend_vk);
|
||||
SAPLING_OUTPUT_VK = Some(params.output_vk);
|
||||
SPROUT_GROTH16_VK = params.sprout_vk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,7 +386,7 @@ pub extern "C" fn librustzcash_sapling_compute_nf(
|
|||
let vk = ViewingKey { ak, nk };
|
||||
let nf = note.nf(&vk, position);
|
||||
let result = unsafe { &mut *result };
|
||||
result.copy_from_slice(&nf);
|
||||
result.copy_from_slice(&nf.0);
|
||||
|
||||
true
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ fn test_key_agreement() {
|
|||
|
||||
// Grab ivk from our viewing key in serialized form
|
||||
let ivk = vk.ivk();
|
||||
let ivk_serialized = ivk.to_bytes();
|
||||
let ivk_serialized = ivk.to_repr();
|
||||
|
||||
// Create random esk
|
||||
let mut esk = [0u8; 32];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use group::GroupEncoding;
|
||||
use zcash_primitives::{
|
||||
constants::SPENDING_KEY_GENERATOR,
|
||||
primitives::{Diversifier, ProofGenerationKey, Rseed},
|
||||
primitives::{Diversifier, Nullifier, ProofGenerationKey, Rseed},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -27,7 +27,7 @@ fn key_components() {
|
|||
note_cm: [u8; 32],
|
||||
note_pos: u64,
|
||||
note_nf: [u8; 32],
|
||||
};
|
||||
}
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py
|
||||
let test_vectors = vec![
|
||||
|
@ -674,7 +674,7 @@ fn key_components() {
|
|||
assert_eq!(&nk, &tv.nk);
|
||||
}
|
||||
|
||||
assert_eq!(&fvk.ivk().to_bytes(), &tv.ivk);
|
||||
assert_eq!(&fvk.ivk().to_repr(), &tv.ivk);
|
||||
{
|
||||
let mut ivk = [0u8; 32];
|
||||
librustzcash_crh_ivk(&tv.ak, &tv.nk, &mut ivk);
|
||||
|
@ -698,6 +698,6 @@ fn key_components() {
|
|||
.unwrap();
|
||||
assert_eq!(¬e.cmu().to_bytes(), &tv.note_cm);
|
||||
|
||||
assert_eq!(note.nf(&fvk, tv.note_pos), tv.note_nf);
|
||||
assert_eq!(note.nf(&fvk, tv.note_pos), Nullifier(tv.note_nf));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ fn sapling_generators() {
|
|||
wprb: [u8; 32],
|
||||
vcvb: [u8; 32],
|
||||
vcrb: [u8; 32],
|
||||
};
|
||||
}
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_generators.py
|
||||
let sapling_generators = SaplingGenerators {
|
||||
|
|
|
@ -19,7 +19,7 @@ fn notes() {
|
|||
note_cm: [u8; 32],
|
||||
note_pos: u64,
|
||||
note_nf: [u8; 32],
|
||||
};
|
||||
}
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py
|
||||
let test_vectors = vec![
|
||||
|
|
|
@ -14,7 +14,7 @@ fn redjubjub_signatures() {
|
|||
m: [u8; 32],
|
||||
sig: [u8; 64],
|
||||
rsig: [u8; 64],
|
||||
};
|
||||
}
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_signatures.py
|
||||
let test_vectors = vec![
|
||||
|
|
|
@ -69,6 +69,7 @@ void CScheduler::serviceQueue()
|
|||
}
|
||||
}
|
||||
--nThreadsServicingQueue;
|
||||
newTaskScheduled.notify_one();
|
||||
}
|
||||
|
||||
void CScheduler::stop(bool drain)
|
||||
|
|
55
src/sync.cpp
55
src/sync.cpp
|
@ -55,11 +55,24 @@ private:
|
|||
};
|
||||
|
||||
typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
|
||||
typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
|
||||
typedef std::set<std::pair<void*, void*> > InvLockOrders;
|
||||
|
||||
static boost::mutex dd_mutex;
|
||||
static std::map<std::pair<void*, void*>, LockStack> lockorders;
|
||||
static boost::thread_specific_ptr<LockStack> lockstack;
|
||||
struct LockData {
|
||||
// Very ugly hack: as the global constructs and destructors run single
|
||||
// threaded, we use this boolean to know whether LockData still exists,
|
||||
// as DeleteLock can get called by global CCriticalSection destructors
|
||||
// after LockData disappears.
|
||||
bool available;
|
||||
LockData() : available(true) {}
|
||||
~LockData() { available = false; }
|
||||
|
||||
LockOrders lockorders;
|
||||
InvLockOrders invlockorders;
|
||||
boost::mutex dd_mutex;
|
||||
} static lockdata;
|
||||
|
||||
boost::thread_specific_ptr<LockStack> lockstack;
|
||||
|
||||
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
|
||||
{
|
||||
|
@ -116,7 +129,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
|
|||
if (lockstack.get() == NULL)
|
||||
lockstack.reset(new LockStack);
|
||||
|
||||
dd_mutex.lock();
|
||||
boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
|
||||
|
||||
(*lockstack).push_back(std::make_pair(c, locklocation));
|
||||
|
||||
|
@ -126,23 +139,21 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
|
|||
break;
|
||||
|
||||
std::pair<void*, void*> p1 = std::make_pair(i.first, c);
|
||||
if (lockorders.count(p1))
|
||||
if (lockdata.lockorders.count(p1))
|
||||
continue;
|
||||
lockorders[p1] = (*lockstack);
|
||||
lockdata.lockorders[p1] = (*lockstack);
|
||||
|
||||
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
|
||||
if (lockorders.count(p2))
|
||||
potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
|
||||
lockdata.invlockorders.insert(p2);
|
||||
if (lockdata.lockorders.count(p2))
|
||||
potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
|
||||
}
|
||||
}
|
||||
dd_mutex.unlock();
|
||||
}
|
||||
|
||||
static void pop_lock()
|
||||
{
|
||||
dd_mutex.lock();
|
||||
(*lockstack).pop_back();
|
||||
dd_mutex.unlock();
|
||||
}
|
||||
|
||||
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
|
||||
|
@ -172,4 +183,26 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
|
|||
abort();
|
||||
}
|
||||
|
||||
void DeleteLock(void* cs)
|
||||
{
|
||||
if (!lockdata.available) {
|
||||
// We're already shutting down.
|
||||
return;
|
||||
}
|
||||
boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
|
||||
std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
|
||||
LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
|
||||
while (it != lockdata.lockorders.end() && it->first.first == cs) {
|
||||
std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
|
||||
lockdata.invlockorders.erase(invitem);
|
||||
lockdata.lockorders.erase(it++);
|
||||
}
|
||||
InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
|
||||
while (invit != lockdata.invlockorders.end() && invit->first == cs) {
|
||||
std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
|
||||
lockdata.lockorders.erase(invinvitem);
|
||||
lockdata.invlockorders.erase(invit++);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DEBUG_LOCKORDER */
|
||||
|
|
38
src/sync.h
38
src/sync.h
|
@ -71,30 +71,39 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapped boost mutex: supports recursive locking, but no waiting
|
||||
* TODO: We should move away from using the recursive lock by default.
|
||||
*/
|
||||
typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection;
|
||||
|
||||
/** Wrapped boost mutex: supports waiting but not recursive locking */
|
||||
typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
|
||||
|
||||
/** Just a typedef for boost::condition_variable, can be wrapped later if desired */
|
||||
typedef boost::condition_variable CConditionVariable;
|
||||
|
||||
#ifdef DEBUG_LOCKORDER
|
||||
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
|
||||
void LeaveCritical();
|
||||
std::string LocksHeld();
|
||||
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
|
||||
void DeleteLock(void* cs);
|
||||
#else
|
||||
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
|
||||
void static inline LeaveCritical() {}
|
||||
void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
|
||||
void static inline DeleteLock(void* cs) {}
|
||||
#endif
|
||||
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
|
||||
|
||||
/**
|
||||
* Wrapped boost mutex: supports recursive locking, but no waiting
|
||||
* TODO: We should move away from using the recursive lock by default.
|
||||
*/
|
||||
class CCriticalSection : public AnnotatedMixin<boost::recursive_mutex>
|
||||
{
|
||||
public:
|
||||
~CCriticalSection() {
|
||||
DeleteLock((void*)this);
|
||||
}
|
||||
};
|
||||
|
||||
typedef CCriticalSection CDynamicCriticalSection;
|
||||
/** Wrapped boost mutex: supports waiting but not recursive locking */
|
||||
typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
|
||||
|
||||
/** Just a typedef for boost::condition_variable, can be wrapped later if desired */
|
||||
typedef boost::condition_variable CConditionVariable;
|
||||
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
|
||||
#endif
|
||||
|
@ -162,7 +171,10 @@ public:
|
|||
|
||||
typedef CMutexLock<CCriticalSection> CCriticalBlock;
|
||||
|
||||
#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
|
||||
#define PASTE(x, y) x ## y
|
||||
#define PASTE2(x, y) PASTE(x, y)
|
||||
|
||||
#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
|
||||
#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
|
||||
#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
|
||||
|
||||
|
|
45
src/util.cpp
45
src/util.cpp
|
@ -87,6 +87,7 @@ using namespace std;
|
|||
const char * const BITCOIN_CONF_FILENAME = "zcash.conf";
|
||||
const char * const BITCOIN_PID_FILENAME = "zcashd.pid";
|
||||
|
||||
CCriticalSection cs_args;
|
||||
map<string, string> mapArgs;
|
||||
map<string, vector<string> > mapMultiArgs;
|
||||
bool fDebug = false;
|
||||
|
@ -113,6 +114,7 @@ static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
|
|||
|
||||
void ParseParameters(int argc, const char* const argv[])
|
||||
{
|
||||
LOCK(cs_args);
|
||||
mapArgs.clear();
|
||||
mapMultiArgs.clear();
|
||||
|
||||
|
@ -148,6 +150,7 @@ void ParseParameters(int argc, const char* const argv[])
|
|||
|
||||
std::string GetArg(const std::string& strArg, const std::string& strDefault)
|
||||
{
|
||||
LOCK(cs_args);
|
||||
if (mapArgs.count(strArg))
|
||||
return mapArgs[strArg];
|
||||
return strDefault;
|
||||
|
@ -155,6 +158,7 @@ std::string GetArg(const std::string& strArg, const std::string& strDefault)
|
|||
|
||||
int64_t GetArg(const std::string& strArg, int64_t nDefault)
|
||||
{
|
||||
LOCK(cs_args);
|
||||
if (mapArgs.count(strArg))
|
||||
return atoi64(mapArgs[strArg]);
|
||||
return nDefault;
|
||||
|
@ -162,6 +166,7 @@ int64_t GetArg(const std::string& strArg, int64_t nDefault)
|
|||
|
||||
bool GetBoolArg(const std::string& strArg, bool fDefault)
|
||||
{
|
||||
LOCK(cs_args);
|
||||
if (mapArgs.count(strArg))
|
||||
return InterpretBool(mapArgs[strArg]);
|
||||
return fDefault;
|
||||
|
@ -169,6 +174,7 @@ bool GetBoolArg(const std::string& strArg, bool fDefault)
|
|||
|
||||
bool SoftSetArg(const std::string& strArg, const std::string& strValue)
|
||||
{
|
||||
LOCK(cs_args);
|
||||
if (mapArgs.count(strArg))
|
||||
return false;
|
||||
mapArgs[strArg] = strValue;
|
||||
|
@ -286,7 +292,7 @@ static fs::path ZC_GetDefaultBaseParamsDir()
|
|||
|
||||
const fs::path &ZC_GetParamsDir()
|
||||
{
|
||||
LOCK(csPathCached); // Reuse the same lock as upstream.
|
||||
LOCK2(cs_args, csPathCached);
|
||||
|
||||
fs::path &path = zc_paramsPathCached;
|
||||
|
||||
|
@ -313,6 +319,7 @@ const fs::path &ZC_GetParamsDir()
|
|||
const fs::path GetExportDir()
|
||||
{
|
||||
fs::path path;
|
||||
LOCK(cs_args);
|
||||
if (mapArgs.count("-exportdir")) {
|
||||
path = fs::system_complete(mapArgs["-exportdir"]);
|
||||
if (fs::exists(path) && !fs::is_directory(path)) {
|
||||
|
@ -328,8 +335,7 @@ const fs::path GetExportDir()
|
|||
|
||||
const fs::path &GetDataDir(bool fNetSpecific)
|
||||
{
|
||||
|
||||
LOCK(csPathCached);
|
||||
LOCK2(cs_args, csPathCached);
|
||||
|
||||
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
|
||||
|
||||
|
@ -357,6 +363,7 @@ const fs::path &GetDataDir(bool fNetSpecific)
|
|||
|
||||
void ClearDatadirCache()
|
||||
{
|
||||
LOCK(csPathCached);
|
||||
pathCached = fs::path();
|
||||
pathCachedNetSpecific = fs::path();
|
||||
}
|
||||
|
@ -389,6 +396,7 @@ void ReadConfigFile(const std::string& confPath,
|
|||
"externalip",
|
||||
"fundingstream",
|
||||
"loadblock",
|
||||
"metricsallowip",
|
||||
"nuparams",
|
||||
"onlynet",
|
||||
"rpcallowip",
|
||||
|
@ -401,23 +409,26 @@ void ReadConfigFile(const std::string& confPath,
|
|||
};
|
||||
set<string> unique_options;
|
||||
|
||||
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
|
||||
{
|
||||
string strKey = string("-") + it->string_key;
|
||||
string strValue = it->value[0];
|
||||
|
||||
if (find(allowed_duplicates.begin(), allowed_duplicates.end(), it->string_key) == allowed_duplicates.end())
|
||||
LOCK(cs_args);
|
||||
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
|
||||
{
|
||||
if (!unique_options.insert(strKey).second) {
|
||||
throw std::runtime_error(strprintf("Option '%s' is duplicated, which is not allowed.", strKey));
|
||||
}
|
||||
}
|
||||
string strKey = string("-") + it->string_key;
|
||||
string strValue = it->value[0];
|
||||
|
||||
InterpretNegativeSetting(strKey, strValue);
|
||||
// Don't overwrite existing settings so command line settings override zcash.conf
|
||||
if (mapSettingsRet.count(strKey) == 0)
|
||||
mapSettingsRet[strKey] = strValue;
|
||||
mapMultiSettingsRet[strKey].push_back(strValue);
|
||||
if (find(allowed_duplicates.begin(), allowed_duplicates.end(), it->string_key) == allowed_duplicates.end())
|
||||
{
|
||||
if (!unique_options.insert(strKey).second) {
|
||||
throw std::runtime_error(strprintf("Option '%s' is duplicated, which is not allowed.", strKey));
|
||||
}
|
||||
}
|
||||
|
||||
InterpretNegativeSetting(strKey, strValue);
|
||||
// Don't overwrite existing settings so command line settings override zcash.conf
|
||||
if (mapSettingsRet.count(strKey) == 0)
|
||||
mapSettingsRet[strKey] = strValue;
|
||||
mapMultiSettingsRet[strKey].push_back(strValue);
|
||||
}
|
||||
}
|
||||
// If datadir is changed in .conf file:
|
||||
ClearDatadirCache();
|
||||
|
|
|
@ -50,8 +50,9 @@ void MilliSleep(int64_t n)
|
|||
|
||||
std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
|
||||
{
|
||||
static std::locale classic(std::locale::classic());
|
||||
// std::locale takes ownership of the pointer
|
||||
std::locale loc(std::locale::classic(), new boost::posix_time::time_facet(pszFormat));
|
||||
std::locale loc(classic, new boost::posix_time::time_facet(pszFormat));
|
||||
std::stringstream ss;
|
||||
ss.imbue(loc);
|
||||
ss << boost::posix_time::from_time_t(nTime);
|
||||
|
|
|
@ -24,9 +24,6 @@
|
|||
using namespace std;
|
||||
|
||||
|
||||
unsigned int nWalletDBUpdated;
|
||||
|
||||
|
||||
//
|
||||
// CDB
|
||||
//
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
|
||||
static const bool DEFAULT_WALLET_PRIVDB = true;
|
||||
|
||||
extern unsigned int nWalletDBUpdated;
|
||||
|
||||
class CDBEnv
|
||||
{
|
||||
private:
|
||||
|
|
|
@ -4835,7 +4835,7 @@ bool CWallet::InitLoadWallet(bool clearWitnessCaches)
|
|||
walletInstance->ScanForWalletTransactions(pindexRescan, true);
|
||||
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
|
||||
walletInstance->SetBestChain(chainActive.GetLocator());
|
||||
nWalletDBUpdated++;
|
||||
CWalletDB::IncrementUpdateCounter();
|
||||
|
||||
// Restore wallet transaction metadata after -zapwallettxes=1
|
||||
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
|
||||
|
|
|
@ -20,18 +20,21 @@
|
|||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <atomic>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static uint64_t nAccountingEntryNumber = 0;
|
||||
|
||||
static std::atomic<unsigned int> nWalletDBUpdateCounter;
|
||||
|
||||
//
|
||||
// CWalletDB
|
||||
//
|
||||
|
||||
bool CWalletDB::WriteName(const string& strAddress, const string& strName)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(make_pair(string("name"), strAddress), strName);
|
||||
}
|
||||
|
||||
|
@ -39,37 +42,37 @@ bool CWalletDB::EraseName(const string& strAddress)
|
|||
{
|
||||
// This should only be used for sending addresses, never for receiving addresses,
|
||||
// receiving addresses must always have an address book entry if they're not change return.
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Erase(make_pair(string("name"), strAddress));
|
||||
}
|
||||
|
||||
bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(make_pair(string("purpose"), strAddress), strPurpose);
|
||||
}
|
||||
|
||||
bool CWalletDB::ErasePurpose(const string& strPurpose)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Erase(make_pair(string("purpose"), strPurpose));
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("tx"), hash), wtx);
|
||||
}
|
||||
|
||||
bool CWalletDB::EraseTx(uint256 hash)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Erase(std::make_pair(std::string("tx"), hash));
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
|
||||
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
|
||||
keyMeta, false))
|
||||
|
@ -89,7 +92,7 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
|
|||
const CKeyMetadata &keyMeta)
|
||||
{
|
||||
const bool fEraseUnencryptedKey = true;
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
|
||||
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
|
||||
keyMeta))
|
||||
|
@ -111,7 +114,7 @@ bool CWalletDB::WriteCryptedZKey(const libzcash::SproutPaymentAddress & addr,
|
|||
const CKeyMetadata &keyMeta)
|
||||
{
|
||||
const bool fEraseUnencryptedKey = true;
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
|
||||
if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta))
|
||||
return false;
|
||||
|
@ -131,7 +134,7 @@ bool CWalletDB::WriteCryptedSaplingZKey(
|
|||
const CKeyMetadata &keyMeta)
|
||||
{
|
||||
const bool fEraseUnencryptedKey = true;
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
auto ivk = extfvk.fvk.in_viewing_key();
|
||||
|
||||
if (!Write(std::make_pair(std::string("sapzkeymeta"), ivk), keyMeta))
|
||||
|
@ -149,13 +152,13 @@ bool CWalletDB::WriteCryptedSaplingZKey(
|
|||
|
||||
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteZKey(const libzcash::SproutPaymentAddress& addr, const libzcash::SproutSpendingKey& key, const CKeyMetadata &keyMeta)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
|
||||
if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta))
|
||||
return false;
|
||||
|
@ -167,7 +170,7 @@ bool CWalletDB::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk,
|
|||
const libzcash::SaplingExtendedSpendingKey &key,
|
||||
const CKeyMetadata &keyMeta)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
|
||||
if (!Write(std::make_pair(std::string("sapzkeymeta"), ivk), keyMeta))
|
||||
return false;
|
||||
|
@ -179,58 +182,58 @@ bool CWalletDB::WriteSaplingPaymentAddress(
|
|||
const libzcash::SaplingPaymentAddress &addr,
|
||||
const libzcash::SaplingIncomingViewingKey &ivk)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
|
||||
return Write(std::make_pair(std::string("sapzaddr"), addr), ivk, false);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteSproutViewingKey(const libzcash::SproutViewingKey &vk)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("vkey"), vk), '1');
|
||||
}
|
||||
|
||||
bool CWalletDB::EraseSproutViewingKey(const libzcash::SproutViewingKey &vk)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Erase(std::make_pair(std::string("vkey"), vk));
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteSaplingExtendedFullViewingKey(
|
||||
const libzcash::SaplingExtendedFullViewingKey &extfvk)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("sapextfvk"), extfvk), '1');
|
||||
}
|
||||
|
||||
bool CWalletDB::EraseSaplingExtendedFullViewingKey(
|
||||
const libzcash::SaplingExtendedFullViewingKey &extfvk)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Erase(std::make_pair(std::string("sapextfvk"), extfvk));
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteWatchOnly(const CScript &dest)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
|
||||
}
|
||||
|
||||
bool CWalletDB::EraseWatchOnly(const CScript &dest)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::string("bestblock"), locator);
|
||||
}
|
||||
|
||||
|
@ -241,19 +244,19 @@ bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
|
|||
|
||||
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::string("orderposnext"), nOrderPosNext);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::string("defaultkey"), vchPubKey);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteWitnessCacheSize(int64_t nWitnessCacheSize)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::string("witnesscachesize"), nWitnessCacheSize);
|
||||
}
|
||||
|
||||
|
@ -264,13 +267,13 @@ bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
|
|||
|
||||
bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("pool"), nPool), keypool);
|
||||
}
|
||||
|
||||
bool CWalletDB::ErasePool(int64_t nPool)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Erase(std::make_pair(std::string("pool"), nPool));
|
||||
}
|
||||
|
||||
|
@ -904,8 +907,8 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||
bool fNoncriticalErrors = false;
|
||||
DBErrors result = DB_LOAD_OK;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
try {
|
||||
LOCK(pwallet->cs_wallet);
|
||||
int nMinVersion = 0;
|
||||
if (Read((string)"minversion", nMinVersion))
|
||||
{
|
||||
|
@ -1105,20 +1108,20 @@ void ThreadFlushWalletDB(const string& strFile)
|
|||
if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET))
|
||||
return;
|
||||
|
||||
unsigned int nLastSeen = nWalletDBUpdated;
|
||||
unsigned int nLastFlushed = nWalletDBUpdated;
|
||||
unsigned int nLastSeen = CWalletDB::GetUpdateCounter();
|
||||
unsigned int nLastFlushed = CWalletDB::GetUpdateCounter();
|
||||
int64_t nLastWalletUpdate = GetTime();
|
||||
while (true)
|
||||
{
|
||||
MilliSleep(500);
|
||||
|
||||
if (nLastSeen != nWalletDBUpdated)
|
||||
if (nLastSeen != CWalletDB::GetUpdateCounter())
|
||||
{
|
||||
nLastSeen = nWalletDBUpdated;
|
||||
nLastSeen = CWalletDB::GetUpdateCounter();
|
||||
nLastWalletUpdate = GetTime();
|
||||
}
|
||||
|
||||
if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
|
||||
if (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2)
|
||||
{
|
||||
TRY_LOCK(bitdb.cs_db,lockDb);
|
||||
if (lockDb)
|
||||
|
@ -1139,7 +1142,7 @@ void ThreadFlushWalletDB(const string& strFile)
|
|||
if (mi != bitdb.mapFileUseCount.end())
|
||||
{
|
||||
LogPrint("db", "Flushing %s\n", strFile);
|
||||
nLastFlushed = nWalletDBUpdated;
|
||||
nLastFlushed = CWalletDB::GetUpdateCounter();
|
||||
int64_t nStart = GetTimeMillis();
|
||||
|
||||
// Flush wallet file so it's self contained
|
||||
|
@ -1282,31 +1285,41 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename)
|
|||
|
||||
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
|
||||
}
|
||||
|
||||
bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
|
||||
}
|
||||
|
||||
|
||||
bool CWalletDB::WriteHDSeed(const HDSeed& seed)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("hdseed"), seed.Fingerprint()), seed.RawSeed());
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& vchCryptedSecret)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::make_pair(std::string("chdseed"), seedFp), vchCryptedSecret);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteHDChain(const CHDChain& chain)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
nWalletDBUpdateCounter++;
|
||||
return Write(std::string("hdchain"), chain);
|
||||
}
|
||||
|
||||
void CWalletDB::IncrementUpdateCounter()
|
||||
{
|
||||
nWalletDBUpdateCounter++;
|
||||
}
|
||||
|
||||
unsigned int CWalletDB::GetUpdateCounter()
|
||||
{
|
||||
return nWalletDBUpdateCounter;
|
||||
}
|
||||
|
|
|
@ -203,6 +203,8 @@ public:
|
|||
bool WriteSaplingExtendedFullViewingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk);
|
||||
bool EraseSaplingExtendedFullViewingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk);
|
||||
|
||||
static void IncrementUpdateCounter();
|
||||
static unsigned int GetUpdateCounter();
|
||||
private:
|
||||
CWalletDB(const CWalletDB&);
|
||||
void operator=(const CWalletDB&);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/sh
|
||||
|
||||
export LC_ALL=C
|
||||
set -eu -o pipefail
|
||||
set -eu
|
||||
set +x
|
||||
|
||||
function cmd_pref() {
|
||||
if type -p "$2" > /dev/null; then
|
||||
cmd_pref() {
|
||||
if command -v "$2" >/dev/null; then
|
||||
eval "$1=$2"
|
||||
else
|
||||
eval "$1=$3"
|
||||
|
@ -13,7 +13,7 @@ function cmd_pref() {
|
|||
}
|
||||
|
||||
# If a g-prefixed version of the command exists, use it preferentially.
|
||||
function gprefix() {
|
||||
gprefix() {
|
||||
cmd_pref "$1" "g$2" "$2"
|
||||
}
|
||||
|
||||
|
@ -22,21 +22,21 @@ cd "$(dirname "$("$READLINK" -f "$0")")/.."
|
|||
|
||||
# Allow user overrides to $MAKE. Typical usage for users who need it:
|
||||
# MAKE=gmake ./zcutil/build.sh -j$(nproc)
|
||||
if [[ -z "${MAKE-}" ]]; then
|
||||
if [ -z "${MAKE-}" ]; then
|
||||
MAKE=make
|
||||
fi
|
||||
|
||||
# Allow overrides to $BUILD and $HOST for porters. Most users will not need it.
|
||||
# BUILD=i686-pc-linux-gnu ./zcutil/build.sh
|
||||
if [[ -z "${BUILD-}" ]]; then
|
||||
if [ -z "${BUILD-}" ]; then
|
||||
BUILD="$(./depends/config.guess)"
|
||||
fi
|
||||
if [[ -z "${HOST-}" ]]; then
|
||||
if [ -z "${HOST-}" ]; then
|
||||
HOST="$BUILD"
|
||||
fi
|
||||
|
||||
# Allow users to set arbitrary compile flags. Most users will not need this.
|
||||
if [[ -z "${CONFIGURE_FLAGS-}" ]]; then
|
||||
if [ -z "${CONFIGURE_FLAGS-}" ]; then
|
||||
CONFIGURE_FLAGS=""
|
||||
fi
|
||||
|
||||
|
@ -69,13 +69,13 @@ set -x
|
|||
eval "$MAKE" --version
|
||||
as --version
|
||||
|
||||
ENABLE_DEBUG_REGEX='^(.*\s)?--enable-debug(\s.*)?$'
|
||||
if [[ "$CONFIGURE_FLAGS" =~ $ENABLE_DEBUG_REGEX ]]
|
||||
then
|
||||
case "$CONFIGURE_FLAGS" in
|
||||
(*"--enable-debug"*)
|
||||
DEBUG=1
|
||||
else
|
||||
;;
|
||||
(*)
|
||||
DEBUG=
|
||||
fi
|
||||
;;esac
|
||||
|
||||
HOST="$HOST" BUILD="$BUILD" "$MAKE" "$@" -C ./depends/ DEBUG="$DEBUG"
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/sh
|
||||
|
||||
export LC_ALL=C
|
||||
set -eu
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
uname_S=$(uname -s 2>/dev/null || echo not)
|
||||
|
||||
if [ "$uname_S" = "Darwin" ]; then
|
||||
PARAMS_DIR="$HOME/Library/Application Support/ZcashParams"
|
||||
else
|
||||
PARAMS_DIR="$HOME/.zcash-params"
|
||||
|
@ -19,7 +21,7 @@ DOWNLOAD_URL="https://download.z.cash/downloads"
|
|||
IPFS_HASH="/ipfs/QmXRHVGLQBiKwvNq7c2vPxAKz1zRVmMYbmt7G5TQss7tY7"
|
||||
|
||||
SHA256CMD="$(command -v sha256sum || echo shasum)"
|
||||
SHA256ARGS="$(command -v sha256sum >/dev/null || echo '-a 256')"
|
||||
SHA256ARGS="$(command -v sha256sum >/dev/null || echo \"-a 256\")"
|
||||
|
||||
WGETCMD="$(command -v wget || echo '')"
|
||||
IPFSCMD="$(command -v ipfs || echo '')"
|
||||
|
@ -30,64 +32,57 @@ ZC_DISABLE_WGET="${ZC_DISABLE_WGET:-}"
|
|||
ZC_DISABLE_IPFS="${ZC_DISABLE_IPFS:-}"
|
||||
ZC_DISABLE_CURL="${ZC_DISABLE_CURL:-}"
|
||||
|
||||
function fetch_wget {
|
||||
LOCKFILE=/tmp/fetch_params.lock
|
||||
|
||||
fetch_wget() {
|
||||
if [ -z "$WGETCMD" ] || ! [ -z "$ZC_DISABLE_WGET" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local filename="$1"
|
||||
local dlname="$2"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Retrieving (wget): $DOWNLOAD_URL/$filename
|
||||
Retrieving (wget): $DOWNLOAD_URL/$1
|
||||
EOF
|
||||
|
||||
wget \
|
||||
--progress=dot:giga \
|
||||
--output-document="$dlname" \
|
||||
--output-document="$2" \
|
||||
--continue \
|
||||
--retry-connrefused --waitretry=3 --timeout=30 \
|
||||
"$DOWNLOAD_URL/$filename"
|
||||
"$DOWNLOAD_URL/$1"
|
||||
}
|
||||
|
||||
function fetch_ipfs {
|
||||
fetch_ipfs() {
|
||||
if [ -z "$IPFSCMD" ] || ! [ -z "$ZC_DISABLE_IPFS" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local filename="$1"
|
||||
local dlname="$2"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Retrieving (ipfs): $IPFS_HASH/$filename
|
||||
Retrieving (ipfs): $IPFS_HASH/$1
|
||||
EOF
|
||||
|
||||
ipfs get --output "$dlname" "$IPFS_HASH/$filename"
|
||||
ipfs get --output "$2" "$IPFS_HASH/$1"
|
||||
}
|
||||
|
||||
function fetch_curl {
|
||||
fetch_curl() {
|
||||
if [ -z "$CURLCMD" ] || ! [ -z "$ZC_DISABLE_CURL" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local filename="$1"
|
||||
local dlname="$2"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Retrieving (curl): $DOWNLOAD_URL/$filename
|
||||
Retrieving (curl): $DOWNLOAD_URL/$1
|
||||
EOF
|
||||
|
||||
curl \
|
||||
--output "$dlname" \
|
||||
--output "$2" \
|
||||
-# -L -C - \
|
||||
"$DOWNLOAD_URL/$filename"
|
||||
"$DOWNLOAD_URL/$1"
|
||||
|
||||
}
|
||||
|
||||
function fetch_failure {
|
||||
fetch_failure() {
|
||||
cat >&2 <<EOF
|
||||
|
||||
Failed to fetch the Zcash zkSNARK parameters!
|
||||
|
@ -101,11 +96,13 @@ EOF
|
|||
exit 1
|
||||
}
|
||||
|
||||
function fetch_params {
|
||||
local filename="$1"
|
||||
local output="$2"
|
||||
local dlname="${output}.dl"
|
||||
local expectedhash="$3"
|
||||
fetch_params() {
|
||||
# We only set these variables inside this function,
|
||||
# and unset them at the end of the function.
|
||||
filename="$1"
|
||||
output="$2"
|
||||
dlname="${output}.dl"
|
||||
expectedhash="$3"
|
||||
|
||||
if ! [ -f "$output" ]
|
||||
then
|
||||
|
@ -143,33 +140,37 @@ EOF
|
|||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
unset -v filename
|
||||
unset -v output
|
||||
unset -v dlname
|
||||
unset -v expectedhash
|
||||
}
|
||||
|
||||
# Use flock to prevent parallel execution.
|
||||
function lock() {
|
||||
local lockfile=/tmp/fetch_params.lock
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
if shlock -f ${lockfile} -p $$; then
|
||||
lock() {
|
||||
if [ "$uname_S" = "Darwin" ]; then
|
||||
if shlock -f ${LOCKFILE} -p $$; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# create lock file
|
||||
eval "exec 200>$lockfile"
|
||||
eval "exec 9>$LOCKFILE"
|
||||
# acquire the lock
|
||||
flock -n 200 \
|
||||
flock -n 9 \
|
||||
&& return 0 \
|
||||
|| return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function exit_locked_error {
|
||||
exit_locked_error() {
|
||||
echo "Only one instance of fetch-params.sh can be run at a time." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function main() {
|
||||
main() {
|
||||
|
||||
lock fetch-params.sh \
|
||||
|| exit_locked_error
|
||||
|
@ -232,5 +233,5 @@ then
|
|||
fi
|
||||
|
||||
main
|
||||
rm -f /tmp/fetch_params.lock
|
||||
rm -f $LOCKFILE
|
||||
exit 0
|
||||
|
|
Loading…
Reference in New Issue