diff --git a/README.md b/README.md
index 2fe3a7adfc3..474af5a521f 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,30 @@
![alt text](https://github.com/zerocurrencycoin/Zero/blob/master/art/zero%203d%20mountain.png?raw=true)
-[ZERO](https://zerocurrency.io) - [Ny-Alesund:2.0.4](https://github.com/zerocurrencycoin/Zero/releases/tag/v2.0.4)
+[ZERO](https://zerocurrency.io) - [Cosmos:3.0.0](https://github.com/zerocurrencycoin/Zero/releases/tag/v3.0.0)
||FAST|| ||DECENTRALISED|| ||ANONYMOUS|| ||SECURE|| ||ASIC RESISTANT|| - LAUNCE DATE: 2017-02-19
GENESIS BLOCK - 19th Feb 2017 11:26:40 - 068cbb5db6bc11be5b93479ea4df41fa7e012e92ca8603c315f9b1a2202205c6
-Download the latest version here - [ZERO - Latest Version - Ny-Alesund:2.0.4](https://github.com/zerocurrencycoin/Zero/releases/tag/v2.0.4)
+Download the latest version here - [ZERO - Latest Version - Cosmos:3.0.0](https://github.com/zerocurrencycoin/Zero/releases/tag/v3.0.0)
------------------------------------------
❓ What is ZERO?
--------------
-[ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v2.0.4) is a revolutionary cryptocurrency and transaction platform based on Zcash.
+[ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v3.0.0) is a revolutionary cryptocurrency and transaction platform based on Zcash.
-[ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v2.0.4) offers total payment confidentiality, while still maintaining a decentralised network using a public blockchain.
+[ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v3.0.0) offers total payment confidentiality, while still maintaining a decentralised network using a public blockchain.
-[ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v2.0.4) combines Bitcoin’s security with Zcash’s anonymity and privacy.
+[ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v3.0.0) combines Bitcoin’s security with Zcash’s anonymity and privacy.
-[ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v2.0.4) stands out from the competition as a fully working product that has already
+[ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v3.0.0) stands out from the competition as a fully working product that has already
implemented a set of special features not found in any other cryptocurrency.
Our main focus as a team and community is to remain as transparent as we can possibly be and to maintain an interactive relationship with everyone involved. We are fully open about the project, listening to all suggestions from investors, miners and supporters.
-This software is the [ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v2.0.4) node. It downloads and stores the entire history of ZERO's transactions, about 1.2GB at this point.
+This software is the [ZERO](https://github.com/zerocurrencycoin/Zero/releases/tag/v3.0.0) node. It downloads and stores the entire history of ZERO's transactions, about 1.2GB at this point.
Depending on the speed of your computer and network connection, the synchronization process could take several hours.
------------------------------------------
@@ -122,7 +122,7 @@ See important security warnings on the
📒 Deprecation Policy
------------------
-Disabledeprecation flag has been removed. Old nodes will automatically be shut down and must be upgraded upon reaching the deprecation block height, which will occur approximately 32 weeks (7/1/2019) from the release of v2.0.4.
+Disabledeprecation flag has been removed. Old nodes will automatically be shut down and must be upgraded upon reaching the deprecation block height, which will occur approximately 32 weeks (7/1/2019) from the release of v3.0.0.
🔧 Building
diff --git a/configure.ac b/configure.ac
index 105decc9253..f2efdce0614 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
-define(_CLIENT_VERSION_MAJOR, 2)
+define(_CLIENT_VERSION_MAJOR, 3)
define(_CLIENT_VERSION_MINOR, 0)
-define(_CLIENT_VERSION_REVISION, 4)
+define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_BUILD, 50)
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
diff --git a/doc/man/zero-cli.1 b/doc/man/zero-cli.1
index 196a047ead8..a0892e8107e 100644
--- a/doc/man/zero-cli.1
+++ b/doc/man/zero-cli.1
@@ -3,7 +3,7 @@
.SH NAME
zero-cli \- manual page for zero-cli v2.0.1
.SH DESCRIPTION
-Zcash RPC client version v2.0.4
+Zcash RPC client version v3.0.0
.PP
In order to ensure you are adequately protecting your privacy when using Zcash,
please see .
diff --git a/doc/man/zero-tx.1 b/doc/man/zero-tx.1
index cc34c452bcb..fb7a8e018e8 100644
--- a/doc/man/zero-tx.1
+++ b/doc/man/zero-tx.1
@@ -3,7 +3,7 @@
.SH NAME
zero-tx \- manual page for zero-tx v2.0.1
.SH DESCRIPTION
-Zcash zcash\-tx utility version v2.0.4
+Zcash zcash\-tx utility version v3.0.0
.SS "Usage:"
.TP
zcash\-tx [options] [commands]
diff --git a/doc/man/zerod.1 b/doc/man/zerod.1
index 6f91e69d27a..cdd23162bcd 100644
--- a/doc/man/zerod.1
+++ b/doc/man/zerod.1
@@ -3,7 +3,7 @@
.SH NAME
zerod \- manual page for zerod v2.0.1
.SH DESCRIPTION
-Zcash Daemon version v2.0.4
+Zcash Daemon version v3.0.0
.PP
In order to ensure you are adequately protecting your privacy when using Zcash,
please see .
diff --git a/src/Makefile.am b/src/Makefile.am
index 36598ca7e36..948ac95f957 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -121,6 +121,7 @@ LIBZCASH_H = \
BITCOIN_CORE_H = \
addressindex.h \
spentindex.h \
+ zeronode/activezeronode.h \
addrman.h \
alert.h \
amount.h \
@@ -166,6 +167,12 @@ BITCOIN_CORE_H = \
dbwrapper.h \
limitedmap.h \
main.h \
+ zeronode/zeronode.h \
+ zeronode/payments.h \
+ zeronode/budget.h \
+ zeronode/zeronode-sync.h \
+ zeronode/zeronodeman.h \
+ zeronode/zeronodeconfig.h \
memusage.h \
merkleblock.h \
metrics.h \
@@ -174,6 +181,7 @@ BITCOIN_CORE_H = \
net.h \
netbase.h \
noui.h \
+ zeronode/obfuscation.h \
policy/fees.h \
pow.h \
prevector.h \
@@ -195,12 +203,15 @@ BITCOIN_CORE_H = \
script/sign.h \
script/standard.h \
serialize.h \
+ zeronode/spork.h \
+ zeronode/sporkdb.h \
streams.h \
support/allocators/secure.h \
support/allocators/zeroafterfree.h \
support/cleanse.h \
support/events.h \
support/pagelocker.h \
+ zeronode/swifttx.h \
sync.h \
threadsafety.h \
timedata.h \
@@ -276,7 +287,11 @@ libbitcoin_server_a_SOURCES = \
rpc/net.cpp \
rpc/rawtransaction.cpp \
rpc/server.cpp \
+ rpc/zeronode.cpp \
+ rpc/zeronode-budget.cpp \
+ rpc/spork.cpp \
script/sigcache.cpp \
+ zeronode/sporkdb.cpp \
timedata.cpp \
torcontrol.cpp \
txdb.cpp \
@@ -307,6 +322,10 @@ endif
libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
+ zeronode/activezeronode.cpp \
+ zeronode/obfuscation.cpp \
+ utiltest.cpp \
+ utiltest.h \
zcbenchmarks.cpp \
zcbenchmarks.h \
wallet/asyncrpcoperation_mergetoaddress.cpp \
@@ -315,6 +334,13 @@ libbitcoin_wallet_a_SOURCES = \
wallet/crypter.cpp \
wallet/db.cpp \
wallet/paymentdisclosure.cpp \
+ zeronode/swifttx.cpp \
+ zeronode/zeronode.cpp \
+ zeronode/budget.cpp \
+ zeronode/payments.cpp \
+ zeronode/zeronode-sync.cpp \
+ zeronode/zeronodeconfig.cpp \
+ zeronode/zeronodeman.cpp \
wallet/paymentdisclosuredb.cpp \
wallet/rpcdisclosure.cpp \
wallet/rpcdump.cpp \
@@ -387,6 +413,8 @@ libbitcoin_common_a_SOURCES = \
script/script_error.cpp \
script/sign.cpp \
script/standard.cpp \
+ zeronode/spork.cpp \
+ zeronode/sporkdb.cpp \
transaction_builder.cpp \
utiltest.cpp \
$(BITCOIN_CORE_H) \
diff --git a/src/bitcoin-cli-res.rc b/src/bitcoin-cli-res.rc
index ea0a759d731..49671159cef 100644
--- a/src/bitcoin-cli-res.rc
+++ b/src/bitcoin-cli-res.rc
@@ -16,8 +16,8 @@ BEGIN
BEGIN
BLOCK "040904E4" // U.S. English - multilingual (hex)
BEGIN
- VALUE "CompanyName", "Zcash"
- VALUE "FileDescription", "zero-cli (JSON-RPC client for Zcash)"
+ VALUE "CompanyName", "Zero"
+ VALUE "FileDescription", "zero-cli (JSON-RPC client for Zero)"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "zero-cli"
VALUE "LegalCopyright", COPYRIGHT_STR
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index cdfcf656dd3..a383887a61b 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -77,10 +77,10 @@ static int AppInitRPC(int argc, char* argv[])
//
ParseParameters(argc, argv);
if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) {
- std::string strUsage = _("Zcash RPC client version") + " " + FormatFullVersion() + "\n" + PrivacyInfo();
+ std::string strUsage = _("Zero RPC client version") + " " + FormatFullVersion() + "\n" + PrivacyInfo();
if (!mapArgs.count("-version")) {
strUsage += "\n" + _("Usage:") + "\n" +
- " zero-cli [options] [params] " + _("Send command to Zcash") + "\n" +
+ " zero-cli [options] [params] " + _("Send command to Zero") + "\n" +
" zero-cli [options] help " + _("List commands") + "\n" +
" zero-cli [options] help " + _("Get help for a command") + "\n";
diff --git a/src/bitcoin-tx-res.rc b/src/bitcoin-tx-res.rc
index d8daac85044..08a3ba0923b 100644
--- a/src/bitcoin-tx-res.rc
+++ b/src/bitcoin-tx-res.rc
@@ -16,8 +16,8 @@ BEGIN
BEGIN
BLOCK "040904E4" // U.S. English - multilingual (hex)
BEGIN
- VALUE "CompanyName", "Zcash"
- VALUE "FileDescription", "zero-tx (CLI Zcash transaction editor utility)"
+ VALUE "CompanyName", "Zero"
+ VALUE "FileDescription", "zero-tx (CLI Zero transaction editor utility)"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "zero-tx"
VALUE "LegalCopyright", COPYRIGHT_STR
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 20059764c2c..e69ae7114be 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -48,10 +48,10 @@ static int AppInitRawTx(int argc, char* argv[])
if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
{
// First part of help message is specific to this utility
- std::string strUsage = _("Zcash zero-tx utility version") + " " + FormatFullVersion() + "\n\n" +
+ std::string strUsage = _("Zero zero-tx utility version") + " " + FormatFullVersion() + "\n\n" +
_("Usage:") + "\n" +
- " zero-tx [options] [commands] " + _("Update hex-encoded zcash transaction") + "\n" +
- " zero-tx [options] -create [commands] " + _("Create hex-encoded zcash transaction") + "\n" +
+ " zero-tx [options] [commands] " + _("Update hex-encoded zero transaction") + "\n" +
+ " zero-tx [options] -create [commands] " + _("Create hex-encoded zero transaction") + "\n" +
"\n";
fprintf(stdout, "%s", strUsage.c_str());
diff --git a/src/bitcoind-res.rc b/src/bitcoind-res.rc
index f8f7acea2cc..43e5719edcb 100644
--- a/src/bitcoind-res.rc
+++ b/src/bitcoind-res.rc
@@ -16,8 +16,8 @@ BEGIN
BEGIN
BLOCK "040904E4" // U.S. English - multilingual (hex)
BEGIN
- VALUE "CompanyName", "Zcash"
- VALUE "FileDescription", "zerod (Zcash node with a JSON-RPC server)"
+ VALUE "CompanyName", "Zero"
+ VALUE "FileDescription", "zerod (Zero node with a JSON-RPC server)"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "zerod"
VALUE "LegalCopyright", COPYRIGHT_STR
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 8863fc1f034..0d1a55d77eb 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -7,6 +7,7 @@
#include "rpc/server.h"
#include "init.h"
#include "main.h"
+#include "zeronode/zeronodeconfig.h"
#include "noui.h"
#include "scheduler.h"
#include "util.h"
@@ -72,7 +73,7 @@ bool AppInit(int argc, char* argv[])
// Process help and version before taking care about datadir
if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version"))
{
- std::string strUsage = _("Zcash Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n" + PrivacyInfo();
+ std::string strUsage = _("Zero Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n" + PrivacyInfo();
if (mapArgs.count("-version"))
{
@@ -81,7 +82,7 @@ bool AppInit(int argc, char* argv[])
else
{
strUsage += "\n" + _("Usage:") + "\n" +
- " zerod [options] " + _("Start Zcash Daemon") + "\n";
+ " zerod [options] " + _("Start Zero Daemon") + "\n";
strUsage += "\n" + HelpMessage(HMM_BITCOIND);
}
@@ -111,7 +112,7 @@ bool AppInit(int argc, char* argv[])
"\n"
"You can look at the example configuration file for suggestions of default\n"
"options that you may want to change. It should be in one of these locations,\n"
- "depending on how you installed Zcash:\n") +
+ "depending on how you installed Zero:\n") +
_("- Source code: %s\n"
"- .deb package: %s\n")).c_str(),
GetConfigFile().string().c_str(),
@@ -128,10 +129,19 @@ bool AppInit(int argc, char* argv[])
return false;
}
+ //Start Zeronode
+ // parse zeronode.conf
+ std::string strErr;
+ if (!zeronodeConfig.read(strErr)) {
+ fprintf(stderr, "Error reading zeronode configuration file: %s\n", strErr.c_str());
+ return false;
+ }
+ //End Zeronode
+
// Command-line RPC
bool fCommandLine = false;
for (int i = 1; i < argc; i++)
- if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "zcash:"))
+ if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "zero:"))
fCommandLine = true;
if (fCommandLine)
@@ -143,7 +153,7 @@ bool AppInit(int argc, char* argv[])
fDaemon = GetBoolArg("-daemon", false);
if (fDaemon)
{
- fprintf(stdout, "Zcash server starting\n");
+ fprintf(stdout, "Zero server starting\n");
// Daemonize
pid_t pid = fork();
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 3a5af3bc264..958b36a136f 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -82,7 +82,7 @@ class CMainParams : public CChainParams {
CMainParams() {
strNetworkID = "main";
strCurrencyUnits = "ZER";
- bip44CoinType = 133; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md
+ bip44CoinType = 323; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md
consensus.fCoinbaseMustBeProtected = true;
consensus.nFeeStartBlockHeight = 412300;
consensus.nSubsidyHalvingInterval = 800000;
@@ -106,7 +106,9 @@ class CMainParams : public CChainParams {
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 492850;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 492850;
-
+ consensus.vUpgrades[Consensus::UPGRADE_COSMOS].nProtocolVersion = 170008;
+ consensus.vUpgrades[Consensus::UPGRADE_COSMOS].nActivationHeight = 620450;
+
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
@@ -126,6 +128,13 @@ class CMainParams : public CChainParams {
nEquihashN = N;
nEquihashK = K;
+ //Start Zeronode
+ nZeronodeCountDrift = 0;
+ strSporkKey = "0477f4d5094e70c26bf998ba0d0e06af8c31b399c5b794895da2158dac086260353c50eaf477e7c5ec6b87349fc63bacdd56f0ffe4dcc112dca71d8335cd1ad2c1";
+ strZeronodeDummyAddress = "t1TLNF3seMZennWmmxik8r1PVEKj5zudgRw";
+ nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee
+ //End Zeronode
+
genesis = CreateGenesisBlock(
1487500000,
uint256S("4c697665206c6f6e6720616e642070726f7370657221014592005a64336e336b"),
@@ -140,11 +149,16 @@ class CMainParams : public CChainParams {
vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
vSeeds.clear();
+ vSeeds.push_back(CDNSSeedData("zerocurrency0", "seed0.zerocurrency.io"));
vSeeds.push_back(CDNSSeedData("zerocurrency1", "seed1.zerocurrency.io"));
vSeeds.push_back(CDNSSeedData("zerocurrency2", "seed2.zerocurrency.io"));
vSeeds.push_back(CDNSSeedData("zerocurrency3", "seed3.zerocurrency.io"));
vSeeds.push_back(CDNSSeedData("zerocurrency4", "seed4.zerocurrency.io"));
vSeeds.push_back(CDNSSeedData("zerocurrency5", "seed5.zerocurrency.io"));
+ vSeeds.push_back(CDNSSeedData("zerocurrency6", "seed6.zerocurrency.io"));
+ vSeeds.push_back(CDNSSeedData("zerocurrency7", "seed7.zerocurrency.io"));
+ vSeeds.push_back(CDNSSeedData("zerocurrency8", "seed8.zerocurrency.io"));
+ vSeeds.push_back(CDNSSeedData("zerocurrency9", "seed9.zerocurrency.io"));
// guarantees the first 2 characters, when base58 encoded, are "t1"
base58Prefixes[PUBKEY_ADDRESS] = {0x1C,0xB8};
@@ -175,10 +189,19 @@ class CMainParams : public CChainParams {
checkpointData = (CCheckpointData) {
boost::assign::map_list_of
- ( 0, consensus.hashGenesisBlock),
- genesis.nTime,
- 0,
- 0
+ ( 0, consensus.hashGenesisBlock)
+ ( 60000, uint256S("0x00002ae1f476c997f3800d6c7fc733efaa0fc6172d91075724a60a9fd42dcf3a"))
+ ( 140000, uint256S("0x00000eb02cca5b05f4be1ee4016790e5b1a3817eb12b1aba605024602665ce7e"))
+ ( 200000, uint256S("0x0000090d945b23a43b757d57f8f396ac748861f22bf1d8914cba440fd59a5c43"))
+ ( 300000, uint256S("0x000001e0b15c1f74af391c39bcb2d61ea879238b53ba738a45303cccd84c2c3f"))
+ ( 400000, uint256S("0x000001ebcc62c257dd00d70bb7fbc210580875e8dbc9f1f9c9aafdb4dc1d8a4e"))
+ ( 500000, uint256S("0x000000c642fda400a464c50dcf310e65efa2627799b9b0c378524205ba2307b7"))
+ ( 550000, uint256S("0x000003cb1f3c128819bdf84632fd31058014542af64eea8959d5139fc26c21cd")),
+ 1553590617, // * UNIX timestamp of last checkpoint block
+ 1067556, // * total number of transactions between genesis and last checkpoint
+ // (the tx=... number in the SetBestChain debug.log lines)
+ 1118 // * estimated number of transactions per day after checkpoint
+ // total number of tx / (checkpoint block height / (24 * 24))
};
// Founders reward script expects a vector of 2-of-3 multisig addresses
@@ -232,6 +255,8 @@ class CTestNetParams : public CChainParams {
consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 50;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 50;
+ consensus.vUpgrades[Consensus::UPGRADE_COSMOS].nProtocolVersion = 170008;
+ consensus.vUpgrades[Consensus::UPGRADE_COSMOS].nActivationHeight =47925;
// The best chain should have at least this much work.
@@ -250,6 +275,13 @@ class CTestNetParams : public CChainParams {
nEquihashN = N;
nEquihashK = K;
+ //Start Zeronode
+ nZeronodeCountDrift = 0;
+ strSporkKey = "04f249a25f6708898afead4e01fc726269ffbdcbbecad7f675ed2470f68571e57ac32bde7111781e476b0c0256cc5e7b71cc5fd56fcffbfb1ead0cb6fe89d91303";
+ strZeronodeDummyAddress = "tmWuQ8Yh3pHDa8MingmN8ECPRBxo2n8uZRs";
+ nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee
+ //End Zeronode
+
genesis = CreateGenesisBlock(
1542244402,
uint256S("0000000000000000000000000000000000000000000000000000000000000007"),
@@ -370,6 +402,9 @@ class CRegTestParams : public CChainParams {
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007;
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
+ consensus.vUpgrades[Consensus::UPGRADE_COSMOS].nProtocolVersion = 170008;
+ consensus.vUpgrades[Consensus::UPGRADE_COSMOS].nActivationHeight =
+ Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
// The best chain should have at least this much work.
@@ -388,6 +423,13 @@ class CRegTestParams : public CChainParams {
nEquihashN = N;
nEquihashK = K;
+ //Start Zeronode
+ nZeronodeCountDrift = 0;
+ strSporkKey = "045da9271f5d9df405d9e83c7c7e62e9c831cc85c51ffaa6b515c4f9c845dec4bf256460003f26ba9d394a17cb57e6759fe231eca75b801c20bccd19cbe4b7942d";
+ strZeronodeDummyAddress = "s1eQnJdoWDhKhxDrX8ev3aFjb1J6ZwXCxUT";
+ nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee
+ //End Zeronode
+
genesis = CreateGenesisBlock(
1531037936,
uint256S("0000000000000000000000000000000000000000000000000000000000000001"),
diff --git a/src/chainparams.h b/src/chainparams.h
index ce5c1d6a179..25adae3aea1 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -98,6 +98,17 @@ class CChainParams
const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; }
const std::vector& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }
+
+ /** Start Zeronode **/
+ /** The zeronode count that we will allow the see-saw reward payments to be off by */
+ int ZeronodeCountDrift() const { return nZeronodeCountDrift; }
+ std::string SporkKey() const { return strSporkKey; }
+ std::string ZeronodeDummyAddress() const { return strZeronodeDummyAddress; }
+ /** Headers first syncing is disabled */
+ bool HeadersFirstSyncingActive() const { return fHeadersFirstSyncingActive; };
+ int64_t Budget_Fee_Confirmations() const { return nBudget_Fee_Confirmations; }
+ /**End Zeronode **/
+
/** Return the founder's reward address and script for a given block height */
std::string GetFoundersRewardAddressAtHeight(int height) const;
CScript GetFoundersRewardScriptAtHeight(int height) const;
@@ -128,6 +139,15 @@ class CChainParams
bool fRequireStandard = false;
bool fMineBlocksOnDemand = false;
bool fTestnetToBeDeprecatedFieldRPC = false;
+
+ /** Start Zeronode **/
+ int nZeronodeCountDrift;
+ std::string strSporkKey;
+ bool fHeadersFirstSyncingActive;
+ std::string strZeronodeDummyAddress;
+ int64_t nBudget_Fee_Confirmations;
+ /** Start Zeronode **/
+
CCheckpointData checkpointData;
std::vector vFoundersRewardAddress;
diff --git a/src/clientversion.cpp b/src/clientversion.cpp
index 79b85431873..20be7ee31c0 100644
--- a/src/clientversion.cpp
+++ b/src/clientversion.cpp
@@ -19,7 +19,7 @@
* for both bitcoind and bitcoin-core, to make it harder for attackers to
* target servers or GUI users specifically.
*/
-const std::string CLIENT_NAME("Ny-Alesund");
+const std::string CLIENT_NAME("Cosmos");
/**
* Client version number
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index ddd2397f884..0846e38bc64 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -25,6 +25,7 @@ static const unsigned int MAX_BLOCK_SIGOPS = 40000;
/** The maximum size of a transaction (network rule) */
static const unsigned int MAX_TX_SIZE_BEFORE_SAPLING = 100000;
static const unsigned int MAX_TX_SIZE_AFTER_SAPLING = MAX_BLOCK_SIZE;
+static const unsigned int MAX_TX_SIZE_COSMOS = 200000;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 720;
/** The minimum value which is invalid for expiry height, used by CTransaction and CMutableTransaction */
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 24390f7085c..ccb4a9e957d 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -26,6 +26,7 @@ enum UpgradeIndex {
UPGRADE_TESTDUMMY,
UPGRADE_OVERWINTER,
UPGRADE_SAPLING,
+ UPGRADE_COSMOS,
// NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp
MAX_NETWORK_UPGRADES
};
diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp
index 3e5cac4d37b..49151bbd676 100644
--- a/src/consensus/upgrades.cpp
+++ b/src/consensus/upgrades.cpp
@@ -22,12 +22,17 @@ const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = {
{
/*.nBranchId =*/ 0x6f76727a,
/*.strName =*/ "Overwinter",
- /*.strInfo =*/ "See https://z.cash/upgrade/overwinter.html for details.",
+ /*.strInfo =*/ "Overwinter Upgrade",
},
{
/*.nBranchId =*/ 0x7361707a,
/*.strName =*/ "Sapling",
- /*.strInfo =*/ "See https://z.cash/upgrade/sapling.html for details.",
+ /*.strInfo =*/ "Sapling Upgrade.",
+ },
+ {
+ /*.nBranchId =*/ 0x7361707a,
+ /*.strName =*/ "Cosmos",
+ /*.strInfo =*/ "Cosmos Upgrade.",
}
};
diff --git a/src/deprecation.h b/src/deprecation.h
index 0d946cd8ec7..8cffc956507 100644
--- a/src/deprecation.h
+++ b/src/deprecation.h
@@ -8,7 +8,7 @@
// Deprecation policy:
// * Shut down 26 weeks' worth of blocks after the estimated release block height.
// * A warning is shown during the 4 weeks' worth of blocks prior to shut down.
-static const int APPROX_RELEASE_HEIGHT = 458500;
+static const int APPROX_RELEASE_HEIGHT = 593110;
static const int WEEKS_UNTIL_DEPRECATION = 32;
//Fixing zero day size
static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 30);
diff --git a/src/init.cpp b/src/init.cpp
index e21067adaa3..c2acea5a0ca 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -9,6 +9,7 @@
#include "init.h"
#include "crypto/common.h"
+#include "zeronode/activezeronode.h"
#include "addrman.h"
#include "amount.h"
#include "checkpoints.h"
@@ -22,6 +23,10 @@
#include "key_io.h"
#endif
#include "main.h"
+#include "zeronode/budget.h"
+#include "zeronode/payments.h"
+#include "zeronode/zeronodeconfig.h"
+#include "zeronode/zeronodeman.h"
#include "metrics.h"
#include "miner.h"
#include "net.h"
@@ -29,6 +34,8 @@
#include "rpc/register.h"
#include "script/standard.h"
#include "script/sigcache.h"
+#include "zeronode/spork.h"
+#include "zeronode/sporkdb.h"
#include "scheduler.h"
#include "txdb.h"
#include "torcontrol.h"
@@ -208,6 +215,9 @@ void Shutdown()
#endif
StopNode();
StopTorControl();
+ DumpZeronodes();
+ DumpBudgets();
+ DumpZeronodePayments();
UnregisterNodeSignals(GetNodeSignals());
if (fFeeEstimatesInitialized)
@@ -234,6 +244,8 @@ void Shutdown()
pcoinsdbview = NULL;
delete pblocktree;
pblocktree = NULL;
+ delete pSporkDB;
+ pSporkDB = NULL;
}
#ifdef ENABLE_WALLET
if (pwalletMain)
@@ -487,6 +499,13 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
+ strUsage += HelpMessageGroup(_("Zeronode options:"));
+ strUsage += HelpMessageOpt("-zeronode=", strprintf(_("Enable the client to act as a zeronode (0-1, default: %u)"), 0));
+ strUsage += HelpMessageOpt("-znconf=", strprintf(_("Specify zeronode configuration file (default: %s)"), "zeronode.conf"));
+ strUsage += HelpMessageOpt("-znconflock=", strprintf(_("Lock zeronodes from zeronode configuration file (default: %u)"), 1));
+ strUsage += HelpMessageOpt("-zeronodeprivkey=", _("Set the zeronode private key"));
+ strUsage += HelpMessageOpt("-zeronodeaddr=", strprintf(_("Set external address:port to get to this zeronode (example: %s)"), "128.127.106.235:60020"));
+ strUsage += HelpMessageOpt("-budgetvotemode=", _("Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto)"));
strUsage += HelpMessageGroup(_("Node relay options:"));
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), 1));
strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
@@ -538,6 +557,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-metricsrefreshtime", strprintf(_("Number of seconds between metrics refreshes (default: %u if running in a console, %u otherwise)"), 1, 600));
}
+ strUsage += HelpMessageOpt("-sporkkey=", _("Enable spork administration functionality with the appropriate private key."));
+
return strUsage;
}
@@ -701,9 +722,9 @@ static void ZC_LoadParams(
boost::filesystem::exists(sprout_groth16)
)) {
uiInterface.ThreadSafeMessageBox(strprintf(
- _("Cannot find the Zcash network parameters in the following directory:\n"
+ _("Cannot find the Zero network parameters in the following directory:\n"
"%s\n"
- "Please run 'zcash-fetch-params' or './zcutil/fetch-params.sh' and then restart."),
+ "Please run 'zero-fetch-params' or './zcutil/fetch-params.sh' and then restart."),
ZC_GetParamsDir()),
"", CClientUIInterface::MSG_ERROR);
StartShutdown();
@@ -854,7 +875,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fLogIPs = GetBoolArg("-logips", false);
LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
- LogPrintf("Zcash version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
+ LogPrintf("Zero version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
@@ -1153,7 +1174,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Sanity check
if (!InitSanityCheck())
- return InitError(_("Initialization sanity check failed. Zcash is shutting down."));
+ return InitError(_("Initialization sanity check failed. Zero is shutting down."));
std::string strDataDir = GetDataDir().string();
#ifdef ENABLE_WALLET
@@ -1169,9 +1190,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
try {
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock())
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Zcash is probably already running."), strDataDir));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Zero is probably already running."), strDataDir));
} catch(const boost::interprocess::interprocess_exception& e) {
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Zcash is probably already running.") + " %s.", strDataDir, e.what()));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Zero is probably already running.") + " %s.", strDataDir, e.what()));
}
#ifndef WIN32
@@ -1201,6 +1222,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
threadGroup.create_thread(&ThreadScriptCheck);
}
+ if (mapArgs.count("-sporkkey")) // spork priv key
+ {
+ if (!sporkManager.SetPrivKey(GetArg("-sporkkey", "")))
+ return InitError(_("Unable to sign spork message, wrong key?"));
+ }
+
// Start the lightweight task scheduler thread
CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
threadGroup.create_thread(boost::bind(&TraceThread, "scheduler", serviceLoop));
@@ -1221,7 +1248,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
libsnark::inhibit_profiling_info = true;
libsnark::inhibit_profiling_counters = true;
- // Initialize Zcash circuit parameters
+ // Initialize Zero circuit parameters
ZC_LoadParams(chainparams);
if (GetBoolArg("-savesproutr1cs", false)) {
@@ -1462,7 +1489,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
bool fReset = fReindex;
std::string strLoadError;
- uiInterface.InitMessage(_("Loading block index..."));
+
nStart = GetTimeMillis();
do {
@@ -1472,7 +1499,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
delete pcoinsdbview;
delete pcoinscatcher;
delete pblocktree;
+ delete pSporkDB;
+ pSporkDB = new CSporkDB(0, false, false);
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
@@ -1485,6 +1514,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
CleanupBlockRevFiles();
}
+ uiInterface.InitMessage(_("Loading sporks..."));
+ LoadSporksFromDB();
+
+ uiInterface.InitMessage(_("Loading block index..."));
if (!LoadBlockIndex()) {
strLoadError = _("Error loading block database");
break;
@@ -1624,7 +1657,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
- strErrors << _("Wallet needed to be rewritten: restart Zcash to complete") << "\n";
+ strErrors << _("Wallet needed to be rewritten: restart Zero to complete") << "\n";
LogPrintf("%s", strErrors.str());
return InitError(strErrors.str());
}
@@ -1731,10 +1764,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#ifdef ENABLE_MINING
#ifndef ENABLE_WALLET
if (GetBoolArg("-minetolocalwallet", false)) {
- return InitError(_("Zcash was not built with wallet support. Set -minetolocalwallet=0 to use -mineraddress, or rebuild Zcash with wallet support."));
+ return InitError(_("Zero was not built with wallet support. Set -minetolocalwallet=0 to use -mineraddress, or rebuild Zero with wallet support."));
}
if (GetArg("-mineraddress", "").empty() && GetBoolArg("-gen", false)) {
- return InitError(_("Zcash was not built with wallet support. Set -mineraddress, or rebuild Zcash with wallet support."));
+ return InitError(_("Zero was not built with wallet support. Set -mineraddress, or rebuild Zero with wallet support."));
}
#endif // !ENABLE_WALLET
@@ -1807,6 +1840,148 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
MilliSleep(10);
}
+
+ // ********************************************************* Step 10a: setup Zeronode
+
+
+ uiInterface.InitMessage(_("Loading zeronode cache..."));
+
+ CZeronodeDB zndb;
+ CZeronodeDB::ReadResult readResult = zndb.Read(znodeman);
+ if (readResult == CZeronodeDB::FileError)
+ LogPrintf("Missing zeronode cache file - zncache.dat, will try to recreate\n");
+ else if (readResult != CZeronodeDB::Ok) {
+ LogPrintf("Error reading zncache.dat: ");
+ if (readResult == CZeronodeDB::IncorrectFormat)
+ LogPrintf("magic is ok but data has invalid format, will try to recreate\n");
+ else
+ LogPrintf("file format is unknown or invalid, please fix it manually\n");
+ }
+
+ uiInterface.InitMessage(_("Loading budget cache..."));
+
+ CBudgetDB budgetdb;
+ CBudgetDB::ReadResult readResult2 = budgetdb.Read(budget);
+
+ if (readResult2 == CBudgetDB::FileError)
+ LogPrintf("Missing budget cache - budget.dat, will try to recreate\n");
+ else if (readResult2 != CBudgetDB::Ok) {
+ LogPrintf("Error reading budget.dat: ");
+ if (readResult2 == CBudgetDB::IncorrectFormat)
+ LogPrintf("magic is ok but data has invalid format, will try to recreate\n");
+ else
+ LogPrintf("file format is unknown or invalid, please fix it manually\n");
+ }
+
+ //flag our cached items so we send them to our peers
+ budget.ResetSync();
+ budget.ClearSeen();
+
+
+ uiInterface.InitMessage(_("Loading zeronode payment cache..."));
+
+ CZeronodePaymentDB znpayments;
+ CZeronodePaymentDB::ReadResult readResult3 = znpayments.Read(zeronodePayments);
+
+ if (readResult3 == CZeronodePaymentDB::FileError)
+ LogPrintf("Missing zeronode payment cache - znpayments.dat, will try to recreate\n");
+ else if (readResult3 != CZeronodePaymentDB::Ok) {
+ LogPrintf("Error reading znpayments.dat: ");
+ if (readResult3 == CZeronodePaymentDB::IncorrectFormat)
+ LogPrintf("magic is ok but data has invalid format, will try to recreate\n");
+ else
+ LogPrintf("file format is unknown or invalid, please fix it manually\n");
+ }
+
+ fZeroNode = GetBoolArg("-zeronode", false);
+
+ if ((fZeroNode || zeronodeConfig.getCount() > -1) && fTxIndex == false) {
+ return InitError("Enabling Zeronode support requires turning on transaction indexing."
+ "Please add txindex=1 to your configuration and start with -reindex");
+ }
+
+ if (fZeroNode) {
+ LogPrintf("IS MASTER NODE\n");
+ strZeroNodeAddr = GetArg("-zeronodeaddr", "");
+
+ LogPrintf(" addr %s\n", strZeroNodeAddr.c_str());
+
+ if (!strZeroNodeAddr.empty()) {
+ CService addrTest = CService(strZeroNodeAddr);
+ if (!addrTest.IsValid()) {
+ return InitError("Invalid -zeronodeaddr address: " + strZeroNodeAddr);
+ }
+ }
+
+ strZeroNodePrivKey = GetArg("-zeronodeprivkey", "");
+ if (!strZeroNodePrivKey.empty()) {
+ std::string errorMessage;
+
+ CKey key;
+ CPubKey pubkey;
+
+ if (!obfuScationSigner.SetKey(strZeroNodePrivKey, errorMessage, key, pubkey)) {
+ return InitError(_("Invalid zeronodeprivkey. Please see documenation."));
+ }
+
+ activeZeronode.pubKeyZeronode = pubkey;
+
+ } else {
+ return InitError(_("You must specify a zeronodeprivkey in the configuration. Please see documentation for help."));
+ }
+ }
+
+ //get the mode of budget voting for this zeronode
+ strBudgetMode = GetArg("-budgetvotemode", "auto");
+
+ if (GetBoolArg("-znconflock", true) && pwalletMain) {
+ LOCK(pwalletMain->cs_wallet);
+ LogPrintf("Locking Zeronodes:\n");
+ uint256 znTxHash;
+ BOOST_FOREACH (CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+ LogPrintf(" %s %s\n", zne.getTxHash(), zne.getOutputIndex());
+ znTxHash.SetHex(zne.getTxHash());
+ COutPoint outpoint = COutPoint(znTxHash, boost::lexical_cast(zne.getOutputIndex()));
+ pwalletMain->LockCoin(outpoint);
+ }
+ }
+
+ //lite mode disables all Zeronode and Obfuscation related functionality
+ fLiteMode = GetBoolArg("-litemode", false);
+ if (fZeroNode && fLiteMode) {
+ return InitError("You can not start a zeronode in litemode");
+ }
+
+ fEnableSwiftTX = GetBoolArg("-enableswifttx", fEnableSwiftTX);
+ nSwiftTXDepth = GetArg("-swifttxdepth", nSwiftTXDepth);
+ nSwiftTXDepth = std::min(std::max(nSwiftTXDepth, 0), 60);
+
+ LogPrintf("fLiteMode %d\n", fLiteMode);
+ LogPrintf("nSwiftTXDepth %d\n", nSwiftTXDepth);
+ LogPrintf("Budget Mode %s\n", strBudgetMode.c_str());
+
+ /* Denominations
+
+ A note about convertability. Within Obfuscation pools, each denomination
+ is convertable to another.
+
+ For example:
+ 1XLR+1000 == (.1XLR+100)*10
+ 10XLR+10000 == (1XLR+1000)*10
+ */
+ obfuScationDenominations.push_back((10000 * COIN) + 10000000);
+ obfuScationDenominations.push_back((1000 * COIN) + 1000000);
+ obfuScationDenominations.push_back((100 * COIN) + 100000);
+ obfuScationDenominations.push_back((10 * COIN) + 10000);
+ obfuScationDenominations.push_back((1 * COIN) + 1000);
+ obfuScationDenominations.push_back((.1 * COIN) + 100);
+ /* Disabled till we need them
+ obfuScationDenominations.push_back( (.01 * COIN)+10 );
+ obfuScationDenominations.push_back( (.001 * COIN)+1 );
+ */
+
+ threadGroup.create_thread(boost::bind(&ThreadCheckObfuScationPool));
+
// ********************************************************* Step 11: start node
if (!CheckDiskSpace())
diff --git a/src/main.cpp b/src/main.cpp
index e293994e70a..66aee65de06 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -17,10 +17,17 @@
#include "consensus/validation.h"
#include "deprecation.h"
#include "init.h"
+#include "zeronode/budget.h"
+#include "zeronode/payments.h"
+#include "zeronode/zeronodeman.h"
#include "merkleblock.h"
#include "metrics.h"
#include "net.h"
+#include "zeronode/obfuscation.h"
#include "pow.h"
+#include "zeronode/spork.h"
+#include "zeronode/sporkdb.h"
+#include "zeronode/swifttx.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
@@ -96,6 +103,7 @@ struct COrphanTx {
};
map mapOrphanTransactions GUARDED_BY(cs_main);;
map > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);;
+map mapRejectedBlocks GUARDED_BY(cs_main);;
void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
@@ -108,7 +116,7 @@ static void CheckBlockIndex();
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
-const string strMessageMagic = "Zcash Signed Message:\n";
+const string strMessageMagic = "Zero Signed Message:\n";
// Internal stuff
namespace {
@@ -566,6 +574,7 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
CCoinsViewCache *pcoinsTip = NULL;
CBlockTreeDB *pblocktree = NULL;
+CSporkDB* pSporkDB = NULL;
//////////////////////////////////////////////////////////////////////////////
//
@@ -878,6 +887,59 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
return nSigOps;
}
+int GetInputAge(CTxIn& vin)
+{
+ CCoinsView viewDummy;
+ CCoinsViewCache view(&viewDummy);
+ {
+ LOCK(mempool.cs);
+ CCoinsViewMemPool viewMempool(pcoinsTip, mempool);
+ view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
+
+ const CCoins* coins = view.AccessCoins(vin.prevout.hash);
+
+ if (coins) {
+ if (coins->nHeight < 0) return 0;
+ return (chainActive.Tip()->nHeight + 1) - coins->nHeight;
+ } else
+ return -1;
+ }
+}
+
+int GetInputAgeIX(uint256 nTXHash, CTxIn& vin)
+{
+ int sigs = 0;
+ int nResult = GetInputAge(vin);
+ if (nResult < 0) nResult = 0;
+
+ if (nResult < 6) {
+ std::map::iterator i = mapTxLocks.find(nTXHash);
+ if (i != mapTxLocks.end()) {
+ sigs = (*i).second.CountSignatures();
+ }
+ if (sigs >= SWIFTTX_SIGNATURES_REQUIRED) {
+ return nSwiftTXDepth + nResult;
+ }
+ }
+
+ return -1;
+}
+
+int GetIXConfirmations(uint256 nTXHash)
+{
+ int sigs = 0;
+
+ std::map::iterator i = mapTxLocks.find(nTXHash);
+ if (i != mapTxLocks.end()) {
+ sigs = (*i).second.CountSignatures();
+ }
+ if (sigs >= SWIFTTX_SIGNATURES_REQUIRED) {
+ return nSwiftTXDepth;
+ }
+
+ return 0;
+}
+
/**
* Check a transaction contextually against a set of consensus rules valid at a given block height.
*
@@ -896,6 +958,7 @@ bool ContextualCheckTransaction(
{
bool overwinterActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
bool saplingActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING);
+ bool cosmosActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_COSMOS);
bool isSprout = !overwinterActive;
// If Sprout rules apply, reject transactions which are intended for Overwinter and beyond
@@ -976,6 +1039,14 @@ bool ContextualCheckTransaction(
REJECT_INVALID, "bad-txns-oversize");
}
+ if (cosmosActive) {
+ // Size limits
+ BOOST_STATIC_ASSERT(MAX_BLOCK_SIZE > MAX_TX_SIZE_COSMOS); // sanity
+ if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_TX_SIZE_COSMOS)
+ return state.DoS(100, error("ContextualCheckTransaction(): size limits failed"),
+ REJECT_INVALID, "bad-txns-oversize");
+ }
+
uint256 dataToBeSigned;
if (!tx.vjoinsplit.empty() ||
@@ -1147,6 +1218,7 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
// Size limits
BOOST_STATIC_ASSERT(MAX_BLOCK_SIZE >= MAX_TX_SIZE_AFTER_SAPLING); // sanity
BOOST_STATIC_ASSERT(MAX_TX_SIZE_AFTER_SAPLING > MAX_TX_SIZE_BEFORE_SAPLING); // sanity
+ BOOST_STATIC_ASSERT(MAX_TX_SIZE_COSMOS > MAX_TX_SIZE_BEFORE_SAPLING); // sanity
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_TX_SIZE_AFTER_SAPLING)
return state.DoS(100, error("CheckTransaction(): size limits failed"),
REJECT_INVALID, "bad-txns-oversize");
@@ -1615,6 +1687,206 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return true;
}
+bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee)
+{
+ AssertLockHeld(cs_main);
+ if (pfMissingInputs)
+ *pfMissingInputs = false;
+
+ auto verifier = libzcash::ProofVerifier::Disabled();
+ if (!CheckTransaction(tx, state, verifier))
+ return error("AcceptableInputs: : CheckTransaction failed");
+
+ // Coinbase is only valid in a block, not as a loose transaction
+ if (tx.IsCoinBase())
+ return state.DoS(100, error("AcceptableInputs: : coinbase as individual tx"),
+ REJECT_INVALID, "coinbase");
+
+ // Rather not work on nonstandard transactions (unless -testnet/-regtest)
+ string reason;
+ // for any real tx this will be checked on AcceptToMemoryPool anyway
+ // if (Params().RequireStandard() && !IsStandardTx(tx, reason))
+ // return state.DoS(0,
+ // error("AcceptableInputs : nonstandard transaction: %s", reason),
+ // REJECT_NONSTANDARD, reason);
+
+ // is it already in the memory pool?
+ uint256 hash = tx.GetHash();
+ if (pool.exists(hash))
+ return false;
+
+ // ----------- instantX transaction scanning -----------
+
+ BOOST_FOREACH(const CTxIn& in, tx.vin){
+ if(mapLockedInputs.count(in.prevout)){
+ if(mapLockedInputs[in.prevout] != tx.GetHash()){
+ return state.DoS(0,
+ error("AcceptableInputs : conflicts with existing transaction lock: %s", reason),
+ REJECT_INVALID, "tx-lock-conflict");
+ }
+ }
+ }
+
+ // Check for conflicts with in-memory transactions
+ {
+ LOCK(pool.cs); // protect pool.mapNextTx
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ COutPoint outpoint = tx.vin[i].prevout;
+ if (pool.mapNextTx.count(outpoint))
+ {
+ // Disable replacement feature for now
+ return false;
+ }
+ }
+ }
+
+
+ {
+ CCoinsView dummy;
+ CCoinsViewCache view(&dummy);
+
+ CAmount nValueIn = 0;
+ {
+ LOCK(pool.cs);
+ CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
+ view.SetBackend(viewMemPool);
+
+ // do we already have it?
+ if (view.HaveCoins(hash))
+ return false;
+
+ // do all inputs exist?
+ // Note that this does not check for the presence of actual outputs (see the next check for that),
+ // only helps filling in pfMissingInputs (to determine missing vs spent).
+ for (const CTxIn txin : tx.vin) {
+ if (!view.HaveCoins(txin.prevout.hash)) {
+ if (pfMissingInputs)
+ *pfMissingInputs = true;
+ return false;
+ }
+
+ // // check for invalid/fraudulent inputs
+ // if (!ValidOutPoint(txin.prevout, chainActive.Height())) {
+ // return state.Invalid(error("%s : tried to spend invalid input %s in tx %s", __func__, txin.prevout.ToString(),
+ // tx.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-inputs");
+ // }
+ }
+
+ // are the actual inputs available?
+ if (!view.HaveInputs(tx))
+ return state.Invalid(error("AcceptableInputs : inputs already spent"),
+ REJECT_DUPLICATE, "bad-txns-inputs-spent");
+
+ // Bring the best block into scope
+ view.GetBestBlock();
+
+ nValueIn = view.GetValueIn(tx);
+
+ // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
+ view.SetBackend(dummy);
+ }
+
+ // Check for non-standard pay-to-script-hash in inputs
+ // for any real tx this will be checked on AcceptToMemoryPool anyway
+ // if (Params().RequireStandard() && !AreInputsStandard(tx, view))
+ // return error("AcceptableInputs: : nonstandard transaction input");
+
+ // Check that the transaction doesn't have an excessive number of
+ // sigops, making it impossible to mine. Since the coinbase transaction
+ // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
+ // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
+ // merely non-standard transaction.
+ unsigned int nSigOps = GetLegacySigOpCount(tx);
+ unsigned int nMaxSigOps = MAX_STANDARD_TX_SIGOPS;
+ nSigOps += GetP2SHSigOpCount(tx, view);
+ if (nSigOps > nMaxSigOps)
+ return state.DoS(0,
+ error("AcceptableInputs : too many sigops %s, %d > %d",
+ hash.ToString(), nSigOps, nMaxSigOps),
+ REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
+
+ CAmount nValueOut = tx.GetValueOut();
+ CAmount nFees = nValueIn-nValueOut;
+ double dPriority = view.GetPriority(tx, chainActive.Height());
+
+ // Keep track of transactions that spend a coinbase, which we re-scan
+ // during reorgs to ensure COINBASE_MATURITY is still met.
+ bool fSpendsCoinbase = false;
+ BOOST_FOREACH(const CTxIn &txin, tx.vin) {
+ const CCoins *coins = view.AccessCoins(txin.prevout.hash);
+ if (coins->IsCoinBase()) {
+ fSpendsCoinbase = true;
+ break;
+ }
+ }
+
+ // Grab the branch ID we expect this transaction to commit to. We don't
+ // yet know if it does, but if the entry gets added to the mempool, then
+ // it has passed ContextualCheckInputs and therefore this is correct.
+ auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
+
+ CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx), fSpendsCoinbase, consensusBranchId);
+ unsigned int nSize = entry.GetTxSize();
+
+ // Don't accept it if it can't get into a block
+ // Accept a tx if it contains joinsplits and has at least the default fee specified by z_sendmany.
+ if (tx.vjoinsplit.size() > 0 && nFees >= ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE) {
+ // In future we will we have more accurate and dynamic computation of fees for tx with joinsplits.
+ } else {
+ CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
+ if (fLimitFree && nFees < txMinFee)
+ return state.DoS(0, error("AcceptableInputs : not enough fees %s, %d < %d",
+ hash.ToString(), nFees, txMinFee),
+ REJECT_INSUFFICIENTFEE, "insufficient fee");
+
+ // Require that free transactions have sufficient priority to be mined in the next block.
+ if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
+ return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
+ }
+
+ // Continuously rate-limit free (really, very-low-fee) transactions
+ // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
+ // be annoying or make others' transactions take longer to confirm.
+ if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize))
+ {
+ static CCriticalSection csFreeLimiter;
+ static double dFreeCount;
+ static int64_t nLastTime;
+ int64_t nNow = GetTime();
+
+ LOCK(csFreeLimiter);
+
+ // Use an exponentially decaying ~10-minute window:
+ dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
+ nLastTime = nNow;
+ // -limitfreerelay unit is thousand-bytes-per-minute
+ // At default rate it would take over a month to fill 1GB
+ if (dFreeCount >= GetArg("-limitfreerelay", 30) * 10 * 1000)
+ return state.DoS(0, error("AcceptableInputs : free transaction rejected by rate limiter"),
+ REJECT_INSUFFICIENTFEE, "rate limited free transaction");
+ LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
+ dFreeCount += nSize;
+ }
+ }
+
+ if (fRejectInsaneFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
+ return error("AcceptableInputs: : insane fees %s, %d > %d",
+ hash.ToString(),
+ nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
+
+ // Check against previous transactions
+ // This is done last to help prevent CPU exhaustion denial-of-service attacks.
+ PrecomputedTransactionData txdata(tx);
+ if (!ContextualCheckInputs(tx, state, view, false, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
+ return error("AcceptableInputs: : ConnectInputs failed %s", hash.ToString());
+ }
+
+ // SyncWithWallets(tx, NULL);
+
+ return true;
+}
+
bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector > &hashes)
{
if (!fTimestampIndex)
@@ -1808,6 +2080,25 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
return nSubsidy;
}
+int64_t GetZeronodePayment(int nHeight, int64_t blockValue, int nZeronodeCount)
+{
+ int64_t ret = blockValue * 20 / 100; //default: 20%
+ if (IsSporkActive(SPORK_7_ZERONODE_PAYMENT_ENABLED)) {
+ if (IsSporkActive(SPORK_6_ZERONODE_FULL_PAYMENT_ENABLED)) {
+ if(nHeight >= Params().GetConsensus().nSubsidyHalvingInterval * 1) ret = blockValue * 25 / 100;
+ if(nHeight >= Params().GetConsensus().nSubsidyHalvingInterval * 2) ret = blockValue * 30 / 100;
+ if(nHeight >= Params().GetConsensus().nSubsidyHalvingInterval * 3) ret = blockValue * 35 / 100;
+ if(nHeight >= Params().GetConsensus().nSubsidyHalvingInterval * 4) ret = blockValue * 40 / 100;
+ } else {
+ ret = 100000;
+ }
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
bool IsInitialBlockDownload()
{
const CChainParams& chainParams = Params();
@@ -1834,8 +2125,8 @@ bool IsInitialBlockDownload()
return false;
}
-static bool fLargeWorkForkFound = false;
-static bool fLargeWorkInvalidChainFound = false;
+bool fLargeWorkForkFound = false;
+bool fLargeWorkInvalidChainFound = false;
static CBlockIndex *pindexBestForkTip = NULL;
static CBlockIndex *pindexBestForkBase = NULL;
@@ -3226,6 +3517,19 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
return true;
}
+bool DisconnectBlocksAndReprocess(int blocks)
+{
+ LOCK(cs_main);
+
+ CValidationState state;
+
+ LogPrintf("DisconnectBlocksAndReprocess: Got command to replay %d blocks\n", blocks);
+ for (int i = 0; i <= blocks; i++)
+ DisconnectTip(state);
+
+ return true;
+}
+
/**
* Return the tip of the chain with the most work in it, that isn't
* known to be invalid (it's however far from certain to be valid).
@@ -3772,6 +4076,9 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW)
{
+
+ bool cosmosActive = NetworkUpgradeActive(chainActive.Height()+1, Params().GetConsensus(), Consensus::UPGRADE_COSMOS);
+
// Check block version
if (block.nVersion < MIN_BLOCK_VERSION)
return state.DoS(100, error("CheckBlockHeader(): block version too low"),
@@ -3788,10 +4095,13 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
REJECT_INVALID, "high-hash");
// Check timestamp
- if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
+ if (!cosmosActive && block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),
REJECT_INVALID, "time-too-new");
+ if (cosmosActive && block.GetBlockTime() > GetAdjustedTime() + 10 * 60)
+ return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),
+ REJECT_INVALID, "time-too-new");
return true;
}
@@ -3840,6 +4150,58 @@ bool CheckBlock(const CBlock& block, CValidationState& state,
return state.DoS(100, error("CheckBlock(): more than one coinbase"),
REJECT_INVALID, "bad-cb-multiple");
+ // ----------- swiftTX transaction scanning -----------
+ if (IsSporkActive(SPORK_3_SWIFTTX_BLOCK_FILTERING)) {
+ BOOST_FOREACH (const CTransaction& tx, block.vtx) {
+ if (!tx.IsCoinBase()) {
+ //only reject blocks when it's based on complete consensus
+ BOOST_FOREACH (const CTxIn& in, tx.vin) {
+ if (mapLockedInputs.count(in.prevout)) {
+ if (mapLockedInputs[in.prevout] != tx.GetHash()) {
+ mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime()));
+ LogPrintf("CheckBlock() : found conflicting transaction with transaction lock %s %s\n", mapLockedInputs[in.prevout].ToString(), tx.GetHash().ToString());
+ return state.DoS(0, error("CheckBlock() : found conflicting transaction with transaction lock"),
+ REJECT_INVALID, "conflicting-tx-ix");
+ }
+ }
+ }
+ }
+ }
+ } else {
+ LogPrintf("CheckBlock() : skipping transaction locking checks\n");
+ }
+
+
+ // zeronode payments / budgets
+ CBlockIndex* pindexPrev = chainActive.Tip();
+ int nHeight = 0;
+ if (pindexPrev != NULL) {
+ if (pindexPrev->GetBlockHash() == block.hashPrevBlock) {
+ nHeight = pindexPrev->nHeight + 1;
+ } else { //out of order
+ BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
+ if (mi != mapBlockIndex.end() && (*mi).second)
+ nHeight = (*mi).second->nHeight + 1;
+ }
+
+ // Zero
+ // It is entierly possible that we don't have enough data and this could fail
+ // (i.e. the block could indeed be valid). Store the block for later consideration
+ // but issue an initial reject message.
+ // The case also exists that the sending peer could not have enough data to see
+ // that this block is invalid, so don't issue an outright ban.
+ if (nHeight != 0 && !IsInitialBlockDownload()) {
+ if (!IsBlockPayeeValid(block, nHeight)) {
+ mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime()));
+ return state.DoS(0, error("CheckBlock() : Couldn't find zeronode/budget payment"),
+ REJECT_INVALID, "bad-cb-payee");
+ }
+ } else {
+ if (fDebug)
+ LogPrintf("CheckBlock(): Zeronode payment check skipped on sync - skipping IsBlockPayeeValid()\n");
+ }
+ }
+
// Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state, verifier))
@@ -4106,6 +4468,12 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool
if (!ActivateBestChain(state, pblock))
return error("%s: ActivateBestChain failed", __func__);
+ if (!fLiteMode) {
+ if (zeronodeSync.RequestedZeronodeAssets > ZERONODE_SYNC_LIST) {
+ zeronodePayments.ProcessBlock(GetHeight() + 10);
+ budget.NewBlock();
+ }
+ }
return true;
}
@@ -5207,6 +5575,51 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
}
case MSG_BLOCK:
return mapBlockIndex.count(inv.hash);
+ case MSG_TXLOCK_REQUEST:
+ return mapTxLockReq.count(inv.hash) ||
+ mapTxLockReqRejected.count(inv.hash);
+ case MSG_TXLOCK_VOTE:
+ return mapTxLockVote.count(inv.hash);
+ case MSG_SPORK:
+ return mapSporks.count(inv.hash);
+ case MSG_ZERONODE_WINNER:
+ if (zeronodePayments.mapZeronodePayeeVotes.count(inv.hash)) {
+ zeronodeSync.AddedZeronodeWinner(inv.hash);
+ return true;
+ }
+ return false;
+ case MSG_BUDGET_VOTE:
+ if (budget.mapSeenZeronodeBudgetVotes.count(inv.hash)) {
+ zeronodeSync.AddedBudgetItem(inv.hash);
+ return true;
+ }
+ return false;
+ case MSG_BUDGET_PROPOSAL:
+ if (budget.mapSeenZeronodeBudgetProposals.count(inv.hash)) {
+ zeronodeSync.AddedBudgetItem(inv.hash);
+ return true;
+ }
+ return false;
+ case MSG_BUDGET_FINALIZED_VOTE:
+ if (budget.mapSeenFinalizedBudgetVotes.count(inv.hash)) {
+ zeronodeSync.AddedBudgetItem(inv.hash);
+ return true;
+ }
+ return false;
+ case MSG_BUDGET_FINALIZED:
+ if (budget.mapSeenFinalizedBudgets.count(inv.hash)) {
+ zeronodeSync.AddedBudgetItem(inv.hash);
+ return true;
+ }
+ return false;
+ case MSG_ZERONODE_ANNOUNCE:
+ if (znodeman.mapSeenZeronodeBroadcast.count(inv.hash)) {
+ zeronodeSync.AddedZeronodeList(inv.hash);
+ return true;
+ }
+ return false;
+ case MSG_ZERONODE_PING:
+ return znodeman.mapSeenZeronodePing.count(inv.hash);
}
// Don't know what it is, just say we already got one
return true;
@@ -5331,6 +5744,101 @@ void static ProcessGetData(CNode* pfrom)
}
}
}
+ if (!pushed && inv.type == MSG_TXLOCK_VOTE) {
+ if (mapTxLockVote.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << mapTxLockVote[inv.hash];
+ pfrom->PushMessage("txlvote", ss);
+ pushed = true;
+ }
+ }
+ if (!pushed && inv.type == MSG_TXLOCK_REQUEST) {
+ if (mapTxLockReq.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << mapTxLockReq[inv.hash];
+ pfrom->PushMessage("ix", ss);
+ pushed = true;
+ }
+ }
+ if (!pushed && inv.type == MSG_SPORK) {
+ if (mapSporks.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << mapSporks[inv.hash];
+ pfrom->PushMessage("spork", ss);
+ pushed = true;
+ }
+ }
+ if (!pushed && inv.type == MSG_ZERONODE_WINNER) {
+ if (zeronodePayments.mapZeronodePayeeVotes.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << zeronodePayments.mapZeronodePayeeVotes[inv.hash];
+ pfrom->PushMessage("znw", ss);
+ pushed = true;
+ }
+ }
+ if (!pushed && inv.type == MSG_BUDGET_VOTE) {
+ if (budget.mapSeenZeronodeBudgetVotes.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << budget.mapSeenZeronodeBudgetVotes[inv.hash];
+ pfrom->PushMessage("mvote", ss);
+ pushed = true;
+ }
+ }
+
+ if (!pushed && inv.type == MSG_BUDGET_PROPOSAL) {
+ if (budget.mapSeenZeronodeBudgetProposals.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << budget.mapSeenZeronodeBudgetProposals[inv.hash];
+ pfrom->PushMessage("zprop", ss);
+ pushed = true;
+ }
+ }
+
+ if (!pushed && inv.type == MSG_BUDGET_FINALIZED_VOTE) {
+ if (budget.mapSeenFinalizedBudgetVotes.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << budget.mapSeenFinalizedBudgetVotes[inv.hash];
+ pfrom->PushMessage("fbvote", ss);
+ pushed = true;
+ }
+ }
+
+ if (!pushed && inv.type == MSG_BUDGET_FINALIZED) {
+ if (budget.mapSeenFinalizedBudgets.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << budget.mapSeenFinalizedBudgets[inv.hash];
+ pfrom->PushMessage("fbs", ss);
+ pushed = true;
+ }
+ }
+
+ if (!pushed && inv.type == MSG_ZERONODE_ANNOUNCE) {
+ if (znodeman.mapSeenZeronodeBroadcast.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << znodeman.mapSeenZeronodeBroadcast[inv.hash];
+ pfrom->PushMessage("znb", ss);
+ pushed = true;
+ }
+ }
+
+ if (!pushed && inv.type == MSG_ZERONODE_PING) {
+ if (znodeman.mapSeenZeronodePing.count(inv.hash)) {
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss.reserve(1000);
+ ss << znodeman.mapSeenZeronodePing[inv.hash];
+ pfrom->PushMessage("znp", ss);
+ pushed = true;
+ }
+ }
if (!pushed) {
vNotFound.push_back(inv);
@@ -6258,6 +6766,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else {
// Ignore unknown commands for extensibility
+ znodeman.ProcessMessage(pfrom, strCommand, vRecv);
+ budget.ProcessMessage(pfrom, strCommand, vRecv);
+ zeronodePayments.ProcessMessageZeronodePayments(pfrom, strCommand, vRecv);
+ ProcessMessageSwiftTX(pfrom, strCommand, vRecv);
+ ProcessSpork(pfrom, strCommand, vRecv);
+ zeronodeSync.ProcessMessage(pfrom, strCommand, vRecv);
LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id);
}
@@ -6266,6 +6780,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
+// Note: whenever a protocol update is needed toggle between both implementations (comment out the formerly active one)
+// so we can leave the existing clients untouched (old SPORK will stay on so they don't see even older clients).
+// Those old clients won't react to the changes of the other (new) SPORK because at the time of their implementation
+// it was the one which was commented out
+int ActiveProtocol()
+{
+ return MIN_PEER_PROTO_VERSION_ENFORCEMENT;
+}
+
// requires LOCK(cs_vRecvMsg)
bool ProcessMessages(CNode* pfrom)
{
diff --git a/src/main.h b/src/main.h
index 369b812bf3b..6ada503401a 100644
--- a/src/main.h
+++ b/src/main.h
@@ -41,6 +41,7 @@
class CBlockIndex;
class CBlockTreeDB;
+class CSporkDB;
class CBloomFilter;
class CInv;
class CScriptCheck;
@@ -139,12 +140,17 @@ extern bool fTxIndex;
extern bool fIsBareMultisigStd;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
+
+extern bool fLargeWorkForkFound;
+extern bool fLargeWorkInvalidChainFound;
+
// TODO: remove this flag by structuring our code such that
// it is unneeded for testing
extern bool fCoinbaseEnforcedProtectionEnabled;
extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
extern bool fAlerts;
+extern std::map mapRejectedBlocks;
extern int64_t nMaxTipAge;
/** Best header we've seen so far (used for getheaders queries' starting points). */
@@ -226,6 +232,9 @@ bool IsInitialBlockDownload();
std::string GetWarnings(const std::string& strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
+
+bool DisconnectBlocksAndReprocess(int blocks);
+
/** Find the best known block, and make it the tip of the block chain */
bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL);
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
@@ -246,7 +255,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
* @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned
*/
void FindFilesToPrune(std::set& setFilesToPrune);
-
+int64_t GetZeronodePayment(int nHeight, int64_t blockValue, int nZeronodeCount = 0);
/**
* Actually unlink the specified files
*/
@@ -262,11 +271,16 @@ void Misbehaving(NodeId nodeid, int howmuch);
void FlushStateToDisk();
/** Prune block files and flush state to disk. */
void PruneAndFlush();
-
+/** See whether the protocol update is enforced for connected nodes */
+int ActiveProtocol();
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectAbsurdFee=false);
-
+bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee = false);
+int GetInputAge(CTxIn& vin);
+int GetInputAgeIX(uint256 nTXHash, CTxIn& vin);
+bool GetCoinAge(const CTransaction& tx, unsigned int nTxTime, uint64_t& nCoinAge);
+int GetIXConfirmations(uint256 nTXHash);
struct CNodeStateStats {
int nMisbehavior;
@@ -799,6 +813,9 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
* of problems. Note that in any case, coins may be modified. */
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
+/** Reprocess a number of blocks to try and get on the correct chain again **/
+bool DisconnectBlocksAndReprocess(int blocks);
+
/** Apply the effects of this block (with given index) on the UTXO set represented by coins */
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
@@ -917,6 +934,8 @@ extern CCoinsViewCache *pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */
extern CBlockTreeDB *pblocktree;
+/** Global variable that points to the spork database (protected by cs_main) */
+extern CSporkDB* pSporkDB;
/**
* Return the spend height, which is one more than the inputs.GetBestBlock().
* While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
diff --git a/src/miner.cpp b/src/miner.cpp
index d501ab9e7ef..9cfe1acc918 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -20,6 +20,7 @@
#include "key_io.h"
#include "main.h"
#include "metrics.h"
+#include "zeronode/zeronode-sync.h"
#include "net.h"
#include "pow.h"
#include "primitives/transaction.h"
@@ -32,6 +33,12 @@
#include "sodium.h"
+#ifdef ENABLE_WALLET
+#include "wallet/wallet.h"
+#endif
+#include "zeronode/payments.h"
+#include "zeronode/spork.h"
+
#include
#include
#ifdef ENABLE_MINING
@@ -402,22 +409,17 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1);
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
- txNew.vout[0].nValue = GetBlockSubsidy(nHeight, chainparams.GetConsensus());
+
// Set to 0 so expiry height does not apply to coinbase txs
txNew.nExpiryHeight = 0;
- if ((nHeight >= chainparams.GetConsensus().nFeeStartBlockHeight) && (nHeight <= chainparams.GetConsensus().GetLastFoundersRewardBlockHeight())) {
- // Founders reward is 20% of the block subsidy
- auto vFoundersReward = txNew.vout[0].nValue * 0.075;
- // Take some reward away from us
- txNew.vout[0].nValue -= vFoundersReward;
+ // Zeronode and general budget payments
+ FillBlockPayee(txNew, nFees, pblock->txoutFounders, pblock->txoutZeronode);
- // And give it to the founders
- txNew.vout.push_back(CTxOut(vFoundersReward, chainparams.GetFoundersRewardScriptAtHeight(nHeight)));
- }
+ // Make payee
+ pblock->payee = txNew.vout[txNew.vout.size() - 1].scriptPubKey;
// Add fees
- txNew.vout[0].nValue += nFees;
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
pblock->vtx[0] = txNew;
diff --git a/src/net.cpp b/src/net.cpp
index f0f7dc8ab60..1ca38e9d11a 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -353,16 +353,16 @@ CNode* FindNode(const CService& addr)
return NULL;
}
-CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
+CNode* ConnectNode(CAddress addrConnect, const char* pszDest, bool obfuScationMaster)
{
if (pszDest == NULL) {
- if (IsLocal(addrConnect))
+ if (IsLocal(addrConnect) && !obfuScationMaster)
return NULL;
// Look for an existing connection
CNode* pnode = FindNode((CService)addrConnect);
- if (pnode)
- {
+ if (pnode) {
+ pnode->fObfuScationMaster = obfuScationMaster;
pnode->AddRef();
return pnode;
}
@@ -397,6 +397,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
}
pnode->nTimeConnected = GetTime();
+ if (obfuScationMaster) pnode->fObfuScationMaster = true;
return pnode;
} else if (!proxyConnectionFailed) {
@@ -731,7 +732,6 @@ class CNodeRef {
{
if (this != &other) {
LOCK(cs_vNodes);
-
_pnode->Release();
_pnode = other._pnode;
_pnode->AddRef();
@@ -1892,6 +1892,30 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
}
}
+void RelayTransactionLockReq(const CTransaction& tx, bool relayToAll)
+{
+ CInv inv(MSG_TXLOCK_REQUEST, tx.GetHash());
+
+ //broadcast the new lock
+ LOCK(cs_vNodes);
+ BOOST_FOREACH (CNode* pnode, vNodes) {
+ if (!relayToAll && !pnode->fRelayTxes)
+ continue;
+
+ pnode->PushMessage("ix", tx);
+ }
+}
+
+void RelayInv(CInv& inv)
+{
+ LOCK(cs_vNodes);
+ BOOST_FOREACH (CNode* pnode, vNodes){
+ if((pnode->nServices==NODE_BLOOM_WITHOUT_MN) && inv.IsZeroNodeType())continue;
+ if (pnode->nVersion >= ActiveProtocol())
+ pnode->PushInventory(inv);
+ }
+}
+
void CNode::RecordBytesRecv(uint64_t bytes)
{
LOCK(cs_totalBytesRecv);
diff --git a/src/net.h b/src/net.h
index b5e365b356b..a159ae77e38 100644
--- a/src/net.h
+++ b/src/net.h
@@ -71,7 +71,7 @@ CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
-CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
+CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL, bool obfuScationMaster=false);
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
@@ -281,6 +281,12 @@ class CNode
// b) the peer may tell us in its version message that we should not relay tx invs
// until it has initialized its bloom filter.
bool fRelayTxes;
+ // Should be 'true' only if we connected to this node to actually mix funds.
+ // In this case node will be released automatically via CZeronodeMan::ProcessZeronodeConnections().
+ // Connecting to verify connectability/status or connecting for sending/relaying single message
+ // (even if it's relative to mixing e.g. for blinding) should NOT set this to 'true'.
+ // For such cases node should be released manually (preferably right after corresponding code).
+ bool fObfuScationMaster;
bool fSentAddr;
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
@@ -294,6 +300,8 @@ class CNode
static std::map setBanned;
static CCriticalSection cs_setBanned;
+ std::vector vecRequestsFulfilled; //keep track of what client has asked for
+
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
static std::vector vWhitelistedRange;
@@ -352,7 +360,7 @@ class CNode
int GetRefCount()
{
- assert(nRefCount >= 0);
+ //assert(nRefCount >= 0);
return nRefCount;
}
@@ -598,6 +606,58 @@ class CNode
}
}
+ template
+ void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9, const T10& a10, const T11& a11)
+ {
+ try {
+ BeginMessage(pszCommand);
+ ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10 << a11;
+ EndMessage();
+ } catch (...) {
+ AbortMessage();
+ throw;
+ }
+ }
+
+ template
+ void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9, const T10& a10, const T11& a11, const T12& a12)
+ {
+ try {
+ BeginMessage(pszCommand);
+ ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10 << a11 << a12;
+ EndMessage();
+ } catch (...) {
+ AbortMessage();
+ throw;
+ }
+ }
+
+ bool HasFulfilledRequest(std::string strRequest)
+ {
+ BOOST_FOREACH (std::string& type, vecRequestsFulfilled) {
+ if (type == strRequest) return true;
+ }
+ return false;
+ }
+
+ void ClearFulfilledRequest(std::string strRequest)
+ {
+ std::vector::iterator it = vecRequestsFulfilled.begin();
+ while (it != vecRequestsFulfilled.end()) {
+ if ((*it) == strRequest) {
+ vecRequestsFulfilled.erase(it);
+ return;
+ }
+ ++it;
+ }
+ }
+
+ void FulfilledRequest(std::string strRequest)
+ {
+ if (HasFulfilledRequest(strRequest)) return;
+ vecRequestsFulfilled.push_back(strRequest);
+ }
+
void CloseSocketDisconnect();
// Denial-of-service detection/prevention
@@ -641,6 +701,8 @@ class CNode
class CTransaction;
void RelayTransaction(const CTransaction& tx);
void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
+void RelayTransactionLockReq(const CTransaction& tx, bool relayToAll = false);
+void RelayInv(CInv& inv);
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 489d54711ef..750ae37749f 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -84,8 +84,13 @@ class CBlock : public CBlockHeader
std::vector vtx;
// memory only
+ mutable CScript payee;
mutable std::vector vMerkleTree;
+ // memory only for blocktemplate - Zeronode updates
+ mutable CTxOut txoutFounders;
+ mutable CTxOut txoutZeronode;
+
CBlock()
{
SetNull();
@@ -109,7 +114,10 @@ class CBlock : public CBlockHeader
{
CBlockHeader::SetNull();
vtx.clear();
+ payee = CScript();
vMerkleTree.clear();
+ txoutFounders = CTxOut();
+ txoutZeronode = CTxOut();
}
CBlockHeader GetBlockHeader() const
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index e6c88003af6..819cbd76ed4 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -144,6 +144,11 @@ uint256 JSDescription::h_sig(ZCJoinSplit& params, const uint256& joinSplitPubKey
return params.h_sig(randomSeed, nullifiers, joinSplitPubKey);
}
+std::string COutPoint::ToStringShort() const
+{
+ return strprintf("%s-%u", hash.ToString().substr(0,64), n);
+}
+
std::string COutPoint::ToString() const
{
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
@@ -154,6 +159,11 @@ std::string SaplingOutPoint::ToString() const
return strprintf("SaplingOutPoint(%s, %u)", hash.ToString().substr(0, 10), n);
}
+uint256 COutPoint::GetHash()
+{
+ return Hash(BEGIN(hash), END(hash), BEGIN(n), END(n));
+}
+
CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
{
prevout = prevoutIn;
@@ -214,6 +224,47 @@ uint256 CMutableTransaction::GetHash() const
return SerializeHash(*this);
}
+std::string CMutableTransaction::ToString() const
+{
+ std::string str;
+ if (!fOverwintered) {
+ str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
+ GetHash().ToString().substr(0,10),
+ nVersion,
+ vin.size(),
+ vout.size(),
+ nLockTime);
+ } else if (nVersion >= SAPLING_MIN_TX_VERSION) {
+ str += strprintf("CTransaction(hash=%s, ver=%d, fOverwintered=%d, nVersionGroupId=%08x, vin.size=%u, vout.size=%u, nLockTime=%u, nExpiryHeight=%u, valueBalance=%u, vShieldedSpend.size=%u, vShieldedOutput.size=%u)\n",
+ GetHash().ToString().substr(0,10),
+ nVersion,
+ fOverwintered,
+ nVersionGroupId,
+ vin.size(),
+ vout.size(),
+ nLockTime,
+ nExpiryHeight,
+ valueBalance,
+ vShieldedSpend.size(),
+ vShieldedOutput.size());
+ } else if (nVersion >= 3) {
+ str += strprintf("CTransaction(hash=%s, ver=%d, fOverwintered=%d, nVersionGroupId=%08x, vin.size=%u, vout.size=%u, nLockTime=%u, nExpiryHeight=%u)\n",
+ GetHash().ToString().substr(0,10),
+ nVersion,
+ fOverwintered,
+ nVersionGroupId,
+ vin.size(),
+ vout.size(),
+ nLockTime,
+ nExpiryHeight);
+ }
+ for (unsigned int i = 0; i < vin.size(); i++)
+ str += " " + vin[i].ToString() + "\n";
+ for (unsigned int i = 0; i < vout.size(); i++)
+ str += " " + vout[i].ToString() + "\n";
+ return str;
+}
+
void CTransaction::UpdateHash() const
{
*const_cast(&hash) = SerializeHash(*this);
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index e39a24fa7a1..940388c32d8 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -351,7 +351,9 @@ class COutPoint : public BaseOutPoint
public:
COutPoint() : BaseOutPoint() {};
COutPoint(uint256 hashIn, uint32_t nIn) : BaseOutPoint(hashIn, nIn) {};
+ std::string ToStringShort() const;
std::string ToString() const;
+ uint256 GetHash();
};
/** An outpoint - a combination of a transaction hash and an index n into its sapling
@@ -360,7 +362,7 @@ class SaplingOutPoint : public BaseOutPoint
{
public:
SaplingOutPoint() : BaseOutPoint() {};
- SaplingOutPoint(uint256 hashIn, uint32_t nIn) : BaseOutPoint(hashIn, nIn) {};
+ SaplingOutPoint(uint256 hashIn, uint32_t nIn) : BaseOutPoint(hashIn, nIn) {};
std::string ToString() const;
};
@@ -374,6 +376,7 @@ class CTxIn
COutPoint prevout;
CScript scriptSig;
uint32_t nSequence;
+ CScript prevPubKey;
CTxIn()
{
@@ -778,6 +781,18 @@ struct CMutableTransaction
* fly, as opposed to GetHash() in CTransaction, which uses a cached result.
*/
uint256 GetHash() const;
+
+ std::string ToString() const;
+
+ friend bool operator==(const CMutableTransaction& a, const CMutableTransaction& b)
+ {
+ return a.GetHash() == b.GetHash();
+ }
+
+ friend bool operator!=(const CMutableTransaction& a, const CMutableTransaction& b)
+ {
+ return !(a == b);
+ }
};
#endif // BITCOIN_PRIMITIVES_TRANSACTION_H
diff --git a/src/protocol.cpp b/src/protocol.cpp
index dd855aa33aa..e0c5b2f1fc0 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -17,7 +17,19 @@ static const char* ppszTypeName[] =
"ERROR",
"tx",
"block",
- "filtered block"
+ "filtered block",
+ "tx lock request",
+ "tx lock vote",
+ "spork",
+ "zn winner",
+ "zn scan error",
+ "zn budget vote",
+ "zn budget proposal",
+ "zn budget finalized",
+ "zn budget finalized vote",
+ "zn quorum",
+ "zn announce",
+ "zn ping"
};
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)
@@ -129,6 +141,10 @@ bool CInv::IsKnownType() const
return (type >= 1 && type < (int)ARRAYLEN(ppszTypeName));
}
+bool CInv::IsZeroNodeType() const{
+ return (type >= 6);
+}
+
const char* CInv::GetCommand() const
{
if (!IsKnownType())
diff --git a/src/protocol.h b/src/protocol.h
index d908191ccbc..9e7f321e247 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -76,6 +76,10 @@ enum {
// but no longer do as of protocol version 170004 (= NO_BLOOM_VERSION)
NODE_BLOOM = (1 << 2),
+ // NODE_BLOOM_WITHOUT_MN means the node has the same features as NODE_BLOOM with the only difference
+ // that the node doens't want to receive master nodes messages. (the 1<<3 was not picked as constant because on bitcoin 0.14 is witness and we want that update here )
+ NODE_BLOOM_WITHOUT_MN = (1 << 4),
+
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
// bitcoin-development mailing list. Remember that service bits are just
@@ -139,6 +143,7 @@ class CInv
friend bool operator<(const CInv& a, const CInv& b);
bool IsKnownType() const;
+ bool IsZeroNodeType() const;
const char* GetCommand() const;
std::string ToString() const;
@@ -154,6 +159,18 @@ enum {
// Nodes may always request a MSG_FILTERED_BLOCK in a getdata, however,
// MSG_FILTERED_BLOCK should not appear in any invs except as a part of getdata.
MSG_FILTERED_BLOCK,
+ MSG_TXLOCK_REQUEST,
+ MSG_TXLOCK_VOTE,
+ MSG_SPORK,
+ MSG_ZERONODE_WINNER,
+ MSG_ZERONODE_SCANNING_ERROR,
+ MSG_BUDGET_VOTE,
+ MSG_BUDGET_PROPOSAL,
+ MSG_BUDGET_FINALIZED,
+ MSG_BUDGET_FINALIZED_VOTE,
+ MSG_ZERONODE_QUORUM,
+ MSG_ZERONODE_ANNOUNCE,
+ MSG_ZERONODE_PING
};
#endif // BITCOIN_PROTOCOL_H
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index cc035cf74fe..b77cfdbe57a 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -24,6 +24,7 @@ class CRPCConvertParam
static const CRPCConvertParam vRPCConvertParams[] =
{
{ "getalldata", 0},
+ { "getalldata", 1},
{ "stop", 0 },
{ "setmocktime", 0 },
{ "getaddednodeinfo", 0 },
@@ -140,7 +141,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "z_importkey", 2 },
{ "z_importviewingkey", 2 },
{ "z_getpaymentdisclosure", 1},
- { "z_getpaymentdisclosure", 2}
+ { "z_getpaymentdisclosure", 2},
+ { "spork", 1},
+ { "spork", 2},
};
class CRPCConvertTable
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index abbd67cd136..45502541f09 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -12,6 +12,7 @@
#include "crypto/equihash.h"
#endif
#include "init.h"
+#include "key_io.h"
#include "main.h"
#include "metrics.h"
#include "miner.h"
@@ -21,6 +22,7 @@
#include "txmempool.h"
#include "util.h"
#include "validationinterface.h"
+#include "zeronode/spork.h"
#include
@@ -459,6 +461,20 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
" \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
" \"bits\" : \"xxx\", (string) compressed target of next block\n"
" \"height\" : n (numeric) The height of the next block\n"
+ " \"votes\" : [\n (array) show vote candidates\n"
+ " { ... } (json object) vote candidate\n"
+ " ,...\n"
+ " ],\n"
+ " \"coinbase_required_outputs\" : [\n (array) required coinbase transactions\n"
+ " {\n"
+ " \"payee\" : \"xxxx\", (string) required payee for the next block\n"
+ " \"payee_amount\" : \"xxxx\", (numeric) required amount to pay\n"
+ " \"type\" : \"xxxx\" (string) payee type, devfee, utilitynode, etc...\n"
+ " }\n"
+ " \"payee\" : \"xxx\", (string) required zeronode payee for the next block\n"
+ " \"payee_amount\" : n, (numeric) required amount to pay\n"
+ " \"zeronode_payments\" : true|false, (boolean) true, if zeronode payments are enabled\n"
+ " \"enforce_zeronode_payments\" : true|false (boolean) true, if zeronode payments are enforced\n"
"}\n"
"\nExamples:\n"
@@ -532,7 +548,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
if (vNodes.empty())
- throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Zcash is not connected!");
+ throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "ZERO is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "ZERO is downloading blocks...");
@@ -663,9 +679,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (tx.IsCoinBase()) {
// Show founders' reward if it is required
- if (pblock->vtx[0].vout.size() > 1) {
+ if (pblock->txoutFounders != CTxOut()) {
// Correct this if GetBlockTemplate changes the order
- entry.push_back(Pair("foundersreward", (int64_t)tx.vout[1].nValue));
+ entry.push_back(Pair("foundersreward", (int64_t)pblock->txoutFounders.nValue));
}
entry.push_back(Pair("required", true));
txCoinbase = entry;
@@ -687,6 +703,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
aMutable.push_back("prevblock");
}
+ UniValue aVotes(UniValue::VARR);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("capabilities", aCaps));
result.push_back(Pair("version", pblock->nVersion));
@@ -710,6 +727,43 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
result.push_back(Pair("curtime", pblock->GetBlockTime()));
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
+ result.push_back(Pair("votes", aVotes));
+
+ //List of all required coinbase transactions
+ UniValue requiredCoinbaseArr(UniValue::VARR);
+ if (pblock->txoutFounders != CTxOut()) {
+ UniValue rqCoinbase(UniValue::VOBJ);
+ CTxDestination dest;
+ ExtractDestination(pblock->txoutFounders.scriptPubKey, dest);
+ rqCoinbase.push_back(Pair("payee", EncodeDestination(dest)));
+ rqCoinbase.push_back(Pair("script", HexStr(pblock->txoutFounders.scriptPubKey.begin(), pblock->txoutFounders.scriptPubKey.end())));
+ rqCoinbase.push_back(Pair("amount", pblock->txoutFounders.nValue));
+ rqCoinbase.push_back(Pair("type", "foundersreward"));
+ rqCoinbase.push_back(Pair("enforced", true));
+ requiredCoinbaseArr.push_back(rqCoinbase);
+ }
+
+ if(pblock->txoutZeronode != CTxOut()) {
+ UniValue rqCoinbase(UniValue::VOBJ);
+ CTxDestination dest;
+ ExtractDestination(pblock->txoutZeronode.scriptPubKey, dest);
+ rqCoinbase.push_back(Pair("payee", EncodeDestination(dest)));
+ rqCoinbase.push_back(Pair("script", HexStr(pblock->txoutZeronode.scriptPubKey.begin(), pblock->txoutZeronode.scriptPubKey.end())));
+ rqCoinbase.push_back(Pair("amount", pblock->txoutZeronode.nValue));
+ rqCoinbase.push_back(Pair("type", "zeronode"));
+ rqCoinbase.push_back(Pair("enforced", IsSporkActive(SPORK_8_ZERONODE_PAYMENT_ENFORCEMENT)));
+ requiredCoinbaseArr.push_back(rqCoinbase);
+ // Legacy Masternode blocktemplate
+ result.push_back(Pair("payee", EncodeDestination(dest)));
+ result.push_back(Pair("payee_amount", pblock->txoutZeronode.nValue));
+ } else {
+ // Legacy Masternode blocktemplate
+ result.push_back(Pair("payee", ""));
+ result.push_back(Pair("payee_amount", ""));
+ }
+ result.push_back(Pair("masternode_payments", IsSporkActive(SPORK_7_ZERONODE_PAYMENT_ENABLED)));
+ result.push_back(Pair("enforce_masternode_payments", IsSporkActive(SPORK_8_ZERONODE_PAYMENT_ENFORCEMENT)));
+ result.push_back(Pair("coinbase_required_outputs",requiredCoinbaseArr));
return result;
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 7ab678f6769..a918bcef9d6 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -90,8 +90,7 @@ UniValue getalldata(const UniValue& params, bool fHelp)
int nMinDepth = 1;
CAmount nBalance = getBalanceTaddr("", nMinDepth, true);
CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, true);
- //CAmount nLockedCoin = pwalletMain->GetLockedCoins();
- CAmount nLockedCoin = 0;
+ CAmount nLockedCoin = pwalletMain->GetLockedCoins();
CAmount nTotalBalance = nBalance + nPrivateBalance + nLockedCoin;
@@ -115,73 +114,99 @@ UniValue getalldata(const UniValue& params, bool fHelp)
if (params.size() > 0 && (params[0].get_int() == 1 || params[0].get_int() == 0))
{
- for (const std::pair& item : pwalletMain->mapAddressBook) {
+ BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, pwalletMain->mapAddressBook)
+ {
UniValue addr(UniValue::VOBJ);
const CTxDestination& dest = item.first;
+
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
- const std::string& strAccount = item.second.name;
+
+ const string& strName = item.second.name;
nBalance = getBalanceTaddr(EncodeDestination(dest), nMinDepth, false);
+
addr.push_back(Pair("amount", ValueFromAmount(nBalance)));
addr.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
addrlist.push_back(Pair(EncodeDestination(dest), addr));
}
//address grouping
- LOCK2(cs_main, pwalletMain->cs_wallet);
- map balances = pwalletMain->GetAddressBalances();
- BOOST_FOREACH(set grouping, pwalletMain->GetAddressGroupings())
{
- BOOST_FOREACH(CTxDestination address, grouping)
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
+ map balances = pwalletMain->GetAddressBalances();
+ BOOST_FOREACH(set grouping, pwalletMain->GetAddressGroupings())
{
- UniValue addr(UniValue::VOBJ);
- const string& strName = EncodeDestination(address);
- std::cout << "Address " << strName << "\n";
- if(addrlist.exists(strName))
- continue;
- isminetype mine = pwalletMain ? IsMine(*pwalletMain, address) : ISMINE_NO;
- nBalance = getBalanceTaddr(strName, nMinDepth, false);
- addr.push_back(Pair("amount", ValueFromAmount(nBalance)));
- addr.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
- addrlist.push_back(Pair(strName, addr));
+ BOOST_FOREACH(CTxDestination address, grouping)
+ {
+ UniValue addr(UniValue::VOBJ);
+ const string& strName = EncodeDestination(address);
+ if(addrlist.exists(strName))
+ continue;
+ isminetype mine = pwalletMain ? IsMine(*pwalletMain, address) : ISMINE_NO;
+
+ nBalance = getBalanceTaddr(strName, nMinDepth, false);
+
+ addr.push_back(Pair("amount", ValueFromAmount(nBalance)));
+ addr.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
+ addrlist.push_back(Pair(strName, addr));
+ }
}
}
- //get all z address - Sprout
- std::set addressSprout;
- pwalletMain->GetSproutPaymentAddresses(addressSprout);
- for (auto addr : addressSprout ) {
- if (pwalletMain->HaveSproutSpendingKey(addr)) {
- UniValue address(UniValue::VOBJ);
- const string& strName = EncodePaymentAddress(addr);
- nBalance = getBalanceZaddr(strName, nMinDepth, false);
- address.push_back(Pair("amount", ValueFromAmount(nBalance)));
- address.push_back(Pair("ismine", true));
- addrlist.push_back(Pair(strName, address));
+ //get all z address
+ {
+ std::set addresses;
+ pwalletMain->GetSproutPaymentAddresses(addresses);
+ for (auto addr : addresses) {
+ if (pwalletMain->HaveSproutSpendingKey(addr)) {
+ UniValue address(UniValue::VOBJ);
+ const string& strName = EncodePaymentAddress(addr);
+ nBalance = getBalanceZaddr(strName, nMinDepth, false);
+ address.push_back(Pair("amount", ValueFromAmount(nBalance)));
+ address.push_back(Pair("ismine", true));
+ addrlist.push_back(Pair(strName, address));
+ }
+ else
+ {
+ UniValue address(UniValue::VOBJ);
+ const string& strName = EncodePaymentAddress(addr);
+ nBalance = getBalanceZaddr(strName, nMinDepth, false);
+ address.push_back(Pair("amount", ValueFromAmount(nBalance)));
+ address.push_back(Pair("ismine", false));
+ addrlist.push_back(Pair(strName, address));
+ }
}
}
-
- //get all z address - Sapling
- std::set addressSapling;
- pwalletMain->GetSaplingPaymentAddresses(addressSapling);
- for (auto addr : addressSapling ) {
- libzcash::SaplingIncomingViewingKey ivk;
- libzcash::SaplingFullViewingKey fvk;
- if (pwalletMain->GetSaplingIncomingViewingKey(addr, ivk) &&
- pwalletMain->GetSaplingFullViewingKey(ivk, fvk) &&
- pwalletMain->HaveSaplingSpendingKey(fvk)) {
- UniValue address(UniValue::VOBJ);
- const string& strName = EncodePaymentAddress(addr);
- nBalance = getBalanceZaddr(strName, nMinDepth, false);
- address.push_back(Pair("amount", ValueFromAmount(nBalance)));
- address.push_back(Pair("ismine", true));
- addrlist.push_back(Pair(strName, address));
+ {
+ std::set addresses;
+ pwalletMain->GetSaplingPaymentAddresses(addresses);
+ libzcash::SaplingIncomingViewingKey ivk;
+ libzcash::SaplingFullViewingKey fvk;
+ for (auto addr : addresses) {
+ if (pwalletMain->GetSaplingIncomingViewingKey(addr, ivk) &&
+ pwalletMain->GetSaplingFullViewingKey(ivk, fvk)) {
+ if(pwalletMain->HaveSaplingSpendingKey(fvk)) {
+ UniValue address(UniValue::VOBJ);
+ const string& strName = EncodePaymentAddress(addr);
+ nBalance = getBalanceZaddr(strName, nMinDepth, false);
+ address.push_back(Pair("amount", ValueFromAmount(nBalance)));
+ address.push_back(Pair("ismine", true));
+ addrlist.push_back(Pair(strName, address));
+ }
+ else
+ {
+ UniValue address(UniValue::VOBJ);
+ const string& strName = EncodePaymentAddress(addr);
+ nBalance = getBalanceZaddr(strName, nMinDepth, false);
+ address.push_back(Pair("amount", ValueFromAmount(nBalance)));
+ address.push_back(Pair("ismine", false));
+ addrlist.push_back(Pair(strName, address));
+ }
+ }
}
}
-
}
-
-
addressbalance.push_back(addrlist);
returnObj.push_back(Pair("addressbalance", addressbalance));
@@ -211,6 +236,14 @@ UniValue getalldata(const UniValue& params, bool fHelp)
{
day = 30;
}
+ else if(params[1].get_int() == 4)
+ {
+ day = 90;
+ }
+ else if(params[1].get_int() == 5)
+ {
+ day = 365;
+ }
}
std::list acentries;
@@ -225,7 +258,11 @@ UniValue getalldata(const UniValue& params, bool fHelp)
CAccountingEntry *const pacentry = (*it).second.second;
if (pacentry != 0)
AcentryToJSON(*pacentry, strAccount, trans);
- if (pwtx->nTimeReceived <= (t - (day * 60 * 60 * 24))) break;
+ int confirms = pwtx->GetDepthInMainChain();
+ if(confirms > 0)
+ {
+ if (mapBlockIndex[pwtx->hashBlock]->GetBlockTime() <= (t - (day * 60 * 60 * 24)) && (int)trans.size() >= nCount) break;
+ }
}
vector arrTmp = trans.getValues();
diff --git a/src/rpc/register.h b/src/rpc/register.h
index 01aa58a25d8..6aa1d1e23d5 100644
--- a/src/rpc/register.h
+++ b/src/rpc/register.h
@@ -19,6 +19,12 @@ void RegisterMiscRPCCommands(CRPCTable &tableRPC);
void RegisterMiningRPCCommands(CRPCTable &tableRPC);
/** Register raw transaction RPC commands */
void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
+/**Register Zeronode Commands */
+void RegisterZeronodeRPCCommands(CRPCTable &tableRPC);
+/**Register Budget Commands */
+void RegisterBudgetRPCCommands(CRPCTable &tableRPC);
+/** Register Spork RPC commands */
+void RegisterSporkRPCCommands(CRPCTable &tableRPC);
static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC)
{
@@ -27,6 +33,9 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC)
RegisterMiscRPCCommands(tableRPC);
RegisterMiningRPCCommands(tableRPC);
RegisterRawTransactionRPCCommands(tableRPC);
+ RegisterZeronodeRPCCommands(tableRPC);
+ //RegisterBudgetRPCCommands(tableRPC); //Disabled for now
+ RegisterSporkRPCCommands(tableRPC);
}
#endif
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 0dd1db51d3c..638648259c0 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -245,11 +245,11 @@ UniValue stop(const UniValue& params, bool fHelp)
if (fHelp || params.size() > 1)
throw runtime_error(
"stop\n"
- "\nStop Zcash server.");
+ "\nStop Zero server.");
// Event loop will exit after current HTTP requests have been handled, so
// this reply will get back to the client.
StartShutdown();
- return "Zcash server stopping";
+ return "Zero server stopping";
}
/**
diff --git a/src/rpc/spork.cpp b/src/rpc/spork.cpp
new file mode 100644
index 00000000000..05d5ac442ff
--- /dev/null
+++ b/src/rpc/spork.cpp
@@ -0,0 +1,120 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2019 The Zero developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "init.h"
+#include "key_io.h"
+#include "main.h"
+#include "rpc/server.h"
+#include "zeronode/spork.h"
+
+#include
+
+#include
+
+using namespace std;
+
+UniValue spork(const UniValue& params, bool fHelp)
+{
+ if (params.size() == 1 && params[0].get_str() == "show") {
+ UniValue ret(UniValue::VOBJ);
+ for (int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++) {
+ if (sporkManager.GetSporkNameByID(nSporkID) != "Unknown")
+ ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), GetSporkValue(nSporkID)));
+ }
+ return ret;
+ } else if (params.size() == 1 && params[0].get_str() == "active") {
+ UniValue ret(UniValue::VOBJ);
+ for (int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++) {
+ if (sporkManager.GetSporkNameByID(nSporkID) != "Unknown")
+ ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), IsSporkActive(nSporkID)));
+ }
+ return ret;
+ } else if (params.size() == 2) {
+ int nSporkID = sporkManager.GetSporkIDByName(params[0].get_str());
+ if (nSporkID == -1) {
+ return "Invalid spork name";
+ }
+
+ // SPORK VALUE
+ int64_t nValue = params[1].get_int64();
+
+ //broadcast new spork
+ if (sporkManager.UpdateSpork(nSporkID, nValue)) {
+ return "success";
+ } else {
+ return "failure";
+ }
+ }
+
+ throw runtime_error(
+ "spork \"name\" ( value )\n"
+ "\nReturn spork values or their active state.\n"
+
+ "\nArguments:\n"
+ "1. \"name\" (string, required) \"show\" to show values, \"active\" to show active state.\n"
+ " When set up as a spork signer, the name of the spork can be used to update it's value.\n"
+ "2. value (numeric, required when updating a spork) The new value for the spork.\n"
+
+ "\nResult (show):\n"
+ "{\n"
+ " \"spork_name\": nnn (key/value) Key is the spork name, value is it's current value.\n"
+ " ,...\n"
+ "}\n"
+
+ "\nResult (active):\n"
+ "{\n"
+ " \"spork_name\": true|false (key/value) Key is the spork name, value is a boolean for it's active state.\n"
+ " ,...\n"
+ "}\n"
+
+ "\nResult (name):\n"
+ " \"success|failure\" (string) Wither or not the update succeeded.\n"
+
+ "\nExamples:\n" +
+ HelpExampleCli("spork", "show") + HelpExampleRpc("spork", "show"));
+}
+
+UniValue createsporkkeys(const UniValue& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 0))
+ throw runtime_error(
+ "createsporkkeys\n"
+ "\nCreate a set of private and public keys used for sporks\n"
+
+ "\nResult:\n"
+ "\"pubkey\" (string) Spork public key\n"
+ "\"privkey\" (string) Spork private key\n"
+
+ "\nExamples:\n" +
+ HelpExampleCli("createsporkkeys", "") + HelpExampleRpc("createsporkkeys", ""));
+
+ CKey secret;
+ secret.MakeNewKey(false);
+
+ CPubKey pubKey = secret.GetPubKey();
+
+ std::string str;
+ for (int i = 0; i < pubKey.size(); i++) {
+ str += pubKey[i];
+ }
+
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("pubkey", HexStr(str)));
+ ret.push_back(Pair("privkey", EncodeSecret(secret)));
+ return ret;
+}
+
+static const CRPCCommand commands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ { "spork", "spork", &spork, false},
+ /** Not shown in help menu */
+ { "hidden", "createsporkkeys", &createsporkkeys, false},
+};
+void RegisterSporkRPCCommands(CRPCTable &tableRPC)
+{
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+}
diff --git a/src/rpc/zeronode-budget.cpp b/src/rpc/zeronode-budget.cpp
new file mode 100644
index 00000000000..9af5a570abf
--- /dev/null
+++ b/src/rpc/zeronode-budget.cpp
@@ -0,0 +1,1066 @@
+// Copyright (c) 2014-2015 The Dash Developers
+// Copyright (c) 2015-2017 The PIVX developers
+// Copyright (c) 2017-2018 The Zero developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "zeronode/activezeronode.h"
+#include "db.h"
+#include "init.h"
+#include "main.h"
+#include "zeronode/budget.h"
+#include "zeronode/payments.h"
+#include "zeronode/zeronodeconfig.h"
+#include "zeronode/zeronodeman.h"
+#include "rpc/server.h"
+#include "utilmoneystr.h"
+
+#include
+
+using namespace std;
+
+void budgetToJSON(CBudgetProposal* pbudgetProposal, UniValue& bObj)
+{
+ CTxDestination address1;
+ ExtractDestination(pbudgetProposal->GetPayee(), address1);
+
+ bObj.push_back(Pair("Name", pbudgetProposal->GetName()));
+ bObj.push_back(Pair("URL", pbudgetProposal->GetURL()));
+ bObj.push_back(Pair("Hash", pbudgetProposal->GetHash().ToString()));
+ bObj.push_back(Pair("FeeHash", pbudgetProposal->nFeeTXHash.ToString()));
+ bObj.push_back(Pair("BlockStart", (int64_t)pbudgetProposal->GetBlockStart()));
+ bObj.push_back(Pair("BlockEnd", (int64_t)pbudgetProposal->GetBlockEnd()));
+ bObj.push_back(Pair("TotalPaymentCount", (int64_t)pbudgetProposal->GetTotalPaymentCount()));
+ bObj.push_back(Pair("RemainingPaymentCount", (int64_t)pbudgetProposal->GetRemainingPaymentCount()));
+ bObj.push_back(Pair("PaymentAddress", EncodeDestination(address1)));
+ bObj.push_back(Pair("Ratio", pbudgetProposal->GetRatio()));
+ bObj.push_back(Pair("Yeas", (int64_t)pbudgetProposal->GetYeas()));
+ bObj.push_back(Pair("Nays", (int64_t)pbudgetProposal->GetNays()));
+ bObj.push_back(Pair("Abstains", (int64_t)pbudgetProposal->GetAbstains()));
+ bObj.push_back(Pair("TotalPayment", ValueFromAmount(pbudgetProposal->GetAmount() * pbudgetProposal->GetTotalPaymentCount())));
+ bObj.push_back(Pair("MonthlyPayment", ValueFromAmount(pbudgetProposal->GetAmount())));
+ bObj.push_back(Pair("IsEstablished", pbudgetProposal->IsEstablished()));
+
+ std::string strError = "";
+ bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(strError)));
+ bObj.push_back(Pair("IsValidReason", strError.c_str()));
+ bObj.push_back(Pair("fValid", pbudgetProposal->fValid));
+}
+
+
+
+UniValue preparebudget(const UniValue& params, bool fHelp)
+{
+ int nBlockMin = 0;
+ CBlockIndex* pindexPrev = chainActive.Tip();
+
+ if (fHelp || params.size() != 6)
+ throw runtime_error(
+ "preparebudget \"proposal-name\" \"url\" payment-count block-start \"zero-address\" monthy-payment\n"
+ "\nPrepare proposal for network by signing and creating tx\n"
+
+ "\nArguments:\n"
+ "1. \"proposal-name\": (string, required) Desired proposal name (20 character limit)\n"
+ "2. \"url\": (string, required) URL of proposal details (64 character limit)\n"
+ "3. payment-count: (numeric, required) Total number of monthly payments\n"
+ "4. block-start: (numeric, required) Starting super block height\n"
+ "5. \"zero-address\": (string, required) Zero address to send payments to\n"
+ "6. monthly-payment: (numeric, required) Monthly payment amount\n"
+
+ "\nResult:\n"
+ "\"xxxx\" (string) proposal fee hash (if successful) or error message (if failed)\n"
+ "\nExamples:\n" +
+ HelpExampleCli("preparebudget", "\"test-proposal\" \"https://forum.zero.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500") +
+ HelpExampleRpc("preparebudget", "\"test-proposal\" \"https://forum.zero.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500"));
+
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+
+ std::string strProposalName = SanitizeString(params[0].get_str());
+ if (strProposalName.size() > 20)
+ throw runtime_error("Invalid proposal name, limit of 20 characters.");
+
+ std::string strURL = SanitizeString(params[1].get_str());
+ if (strURL.size() > 64)
+ throw runtime_error("Invalid url, limit of 64 characters.");
+
+ int nPaymentCount = params[2].get_int();
+ if (nPaymentCount < 1)
+ throw runtime_error("Invalid payment count, must be more than zero.");
+
+ // Start must be in the next budget cycle
+ if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks();
+
+ int nBlockStart = params[3].get_int();
+ if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) {
+ int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks();
+ throw runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext));
+ }
+
+ int nBlockEnd = nBlockStart + GetBudgetPaymentCycleBlocks() * nPaymentCount; // End must be AFTER current cycle
+
+ if (nBlockStart < nBlockMin)
+ throw runtime_error("Invalid block start, must be more than current height.");
+
+ if (nBlockEnd < pindexPrev->nHeight)
+ throw runtime_error("Invalid ending block, starting block + (payment_cycle*payments) must be more than current height.");
+
+ CTxDestination address = DecodeDestination(params[4].get_str());
+ if (!IsValidDestination(address))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zero address");
+
+ // Parse Zero address
+ CScript scriptPubKey = GetScriptForDestination(address);
+ CAmount nAmount = AmountFromValue(params[5]);
+
+ //*************************************************************************
+
+ // create transaction 15 minutes into the future, to allow for confirmation time
+ CBudgetProposalBroadcast budgetProposalBroadcast(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, uint256());
+
+ std::string strError = "";
+ if (!budgetProposalBroadcast.IsValid(strError, false))
+ throw runtime_error("Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError);
+
+ bool useIX = false; //true;
+ // if (params.size() > 7) {
+ // if(params[7].get_str() != "false" && params[7].get_str() != "true")
+ // return "Invalid use_ix, must be true or false";
+ // useIX = params[7].get_str() == "true" ? true : false;
+ // }
+
+ CWalletTx wtx;
+ if (!pwalletMain->GetBudgetSystemCollateralTX(wtx, budgetProposalBroadcast.GetHash(), useIX)) {
+ throw runtime_error("Error making collateral transaction for proposal. Please check your wallet balance.");
+ }
+
+ // make our change address
+ CReserveKey reservekey(pwalletMain);
+ //send the tx to the network
+ pwalletMain->CommitTransaction(wtx, reservekey, useIX ? "ix" : "tx");
+
+ return wtx.GetHash().ToString();
+}
+
+UniValue submitbudget(const UniValue& params, bool fHelp)
+{
+ int nBlockMin = 0;
+ CBlockIndex* pindexPrev = chainActive.Tip();
+
+ if (fHelp || params.size() != 7)
+ throw runtime_error(
+ "submitbudget \"proposal-name\" \"url\" payment-count block-start \"zero-address\" monthy-payment \"fee-tx\"\n"
+ "\nSubmit proposal to the network\n"
+
+ "\nArguments:\n"
+ "1. \"proposal-name\": (string, required) Desired proposal name (20 character limit)\n"
+ "2. \"url\": (string, required) URL of proposal details (64 character limit)\n"
+ "3. payment-count: (numeric, required) Total number of monthly payments\n"
+ "4. block-start: (numeric, required) Starting super block height\n"
+ "5. \"zero-address\": (string, required) Zero address to send payments to\n"
+ "6. monthly-payment: (numeric, required) Monthly payment amount\n"
+ "7. \"fee-tx\": (string, required) Transaction hash from preparebudget command\n"
+
+ "\nResult:\n"
+ "\"xxxx\" (string) proposal hash (if successful) or error message (if failed)\n"
+ "\nExamples:\n" +
+ HelpExampleCli("submitbudget", "\"test-proposal\" \"https://forum.zero.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500") +
+ HelpExampleRpc("submitbudget", "\"test-proposal\" \"https://forum.zero.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500"));
+
+ // Check these inputs the same way we check the vote commands:
+ // **********************************************************
+
+ std::string strProposalName = SanitizeString(params[0].get_str());
+ if (strProposalName.size() > 20)
+ throw runtime_error("Invalid proposal name, limit of 20 characters.");
+
+ std::string strURL = SanitizeString(params[1].get_str());
+ if (strURL.size() > 64)
+ throw runtime_error("Invalid url, limit of 64 characters.");
+
+ int nPaymentCount = params[2].get_int();
+ if (nPaymentCount < 1)
+ throw runtime_error("Invalid payment count, must be more than zero.");
+
+ // Start must be in the next budget cycle
+ if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks();
+
+ int nBlockStart = params[3].get_int();
+ if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) {
+ int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks();
+ throw runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext));
+ }
+
+ int nBlockEnd = nBlockStart + (GetBudgetPaymentCycleBlocks() * nPaymentCount); // End must be AFTER current cycle
+
+ if (nBlockStart < nBlockMin)
+ throw runtime_error("Invalid block start, must be more than current height.");
+
+ if (nBlockEnd < pindexPrev->nHeight)
+ throw runtime_error("Invalid ending block, starting block + (payment_cycle*payments) must be more than current height.");
+
+ CTxDestination address = DecodeDestination(params[4].get_str());
+ if (!IsValidDestination(address))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zero address");
+
+ // Parse Zero address
+ CScript scriptPubKey = GetScriptForDestination(address);
+ CAmount nAmount = AmountFromValue(params[5]);
+ uint256 hash = ParseHashV(params[6], "parameter 1");
+
+ //create the proposal incase we're the first to make it
+ CBudgetProposalBroadcast budgetProposalBroadcast(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, hash);
+
+ std::string strError = "";
+ int nConf = 0;
+ if (!IsBudgetCollateralValid(hash, budgetProposalBroadcast.GetHash(), strError, budgetProposalBroadcast.nTime, nConf)) {
+ throw runtime_error("Proposal FeeTX is not valid - " + hash.ToString() + " - " + strError);
+ }
+
+ if (!zeronodeSync.IsBlockchainSynced()) {
+ throw runtime_error("Must wait for client to sync with zeronode network. Try again in a minute or so.");
+ }
+
+ // if(!budgetProposalBroadcast.IsValid(strError)){
+ // return "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError;
+ // }
+
+ budget.mapSeenZeronodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast));
+ budgetProposalBroadcast.Relay();
+ if(budget.AddProposal(budgetProposalBroadcast)) {
+ return budgetProposalBroadcast.GetHash().ToString();
+ }
+ throw runtime_error("Invalid proposal, see debug.log for details.");
+}
+
+UniValue znbudgetvote(const UniValue& params, bool fHelp)
+{
+ std::string strCommand;
+ if (params.size() >= 1) {
+ strCommand = params[0].get_str();
+
+ // Backwards compatibility with legacy `znbudget` command
+ if (strCommand == "vote") strCommand = "local";
+ if (strCommand == "vote-many") strCommand = "many";
+ if (strCommand == "vote-alias") strCommand = "alias";
+ }
+
+ if (fHelp || (params.size() == 3 && (strCommand != "local" && strCommand != "many")) || (params.size() == 4 && strCommand != "alias") ||
+ params.size() > 4 || params.size() < 3)
+ throw runtime_error(
+ "znbudgetvote \"local|many|alias\" \"votehash\" \"yes|no\" ( \"alias\" )\n"
+ "\nVote on a budget proposal\n"
+
+ "\nArguments:\n"
+ "1. \"mode\" (string, required) The voting mode. 'local' for voting directly from a zeronode, 'many' for voting with a MN controller and casting the same vote for each MN, 'alias' for voting with a MN controller and casting a vote for a single MN\n"
+ "2. \"votehash\" (string, required) The vote hash for the proposal\n"
+ "3. \"votecast\" (string, required) Your vote. 'yes' to vote for the proposal, 'no' to vote against\n"
+ "4. \"alias\" (string, required for 'alias' mode) The MN alias to cast a vote for.\n"
+
+ "\nResult:\n"
+ "{\n"
+ " \"overall\": \"xxxx\", (string) The overall status message for the vote cast\n"
+ " \"detail\": [\n"
+ " {\n"
+ " \"node\": \"xxxx\", (string) 'local' or the MN alias\n"
+ " \"result\": \"xxxx\", (string) Either 'Success' or 'Failed'\n"
+ " \"error\": \"xxxx\", (string) Error message, if vote failed\n"
+ " }\n"
+ " ,...\n"
+ " ]\n"
+ "}\n"
+
+ "\nExamples:\n" +
+ HelpExampleCli("znbudgetvote", "\"local\" \"ed2f83cedee59a91406f5f47ec4d60bf5a7f9ee6293913c82976bd2d3a658041\" \"yes\"") +
+ HelpExampleRpc("znbudgetvote", "\"local\" \"ed2f83cedee59a91406f5f47ec4d60bf5a7f9ee6293913c82976bd2d3a658041\" \"yes\""));
+
+ uint256 hash = ParseHashV(params[1], "parameter 1");
+ std::string strVote = params[2].get_str();
+
+ if (strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
+ int nVote = VOTE_ABSTAIN;
+ if (strVote == "yes") nVote = VOTE_YES;
+ if (strVote == "no") nVote = VOTE_NO;
+
+ int success = 0;
+ int failed = 0;
+
+ UniValue resultsObj(UniValue::VARR);
+
+ if (strCommand == "local") {
+ CPubKey pubKeyZeronode;
+ CKey keyZeronode;
+ std::string errorMessage;
+
+ UniValue statusObj(UniValue::VOBJ);
+
+ while (true) {
+ if (!obfuScationSigner.SetKey(strZeroNodePrivKey, errorMessage, keyZeronode, pubKeyZeronode)) {
+ failed++;
+ statusObj.push_back(Pair("node", "local"));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Zeronode signing error, could not set key correctly: " + errorMessage));
+ resultsObj.push_back(statusObj);
+ break;
+ }
+
+ CZeronode* pzn = znodeman.Find(activeZeronode.vin);
+ if (pzn == NULL) {
+ failed++;
+ statusObj.push_back(Pair("node", "local"));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Failure to find zeronode in list : " + activeZeronode.vin.ToString()));
+ resultsObj.push_back(statusObj);
+ break;
+ }
+
+ CBudgetVote vote(activeZeronode.vin, hash, nVote);
+ if (!vote.Sign(keyZeronode, pubKeyZeronode)) {
+ failed++;
+ statusObj.push_back(Pair("node", "local"));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Failure to sign."));
+ resultsObj.push_back(statusObj);
+ break;
+ }
+
+ std::string strError = "";
+ if (budget.UpdateProposal(vote, NULL, strError)) {
+ success++;
+ budget.mapSeenZeronodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
+ vote.Relay();
+ statusObj.push_back(Pair("node", "local"));
+ statusObj.push_back(Pair("result", "success"));
+ statusObj.push_back(Pair("error", ""));
+ } else {
+ failed++;
+ statusObj.push_back(Pair("node", "local"));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Error voting : " + strError));
+ }
+ resultsObj.push_back(statusObj);
+ break;
+ }
+
+ UniValue returnObj(UniValue::VOBJ);
+ returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed)));
+ returnObj.push_back(Pair("detail", resultsObj));
+
+ return returnObj;
+ }
+
+ if (strCommand == "many") {
+ BOOST_FOREACH (CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+ std::string errorMessage;
+ std::vector vchZeroNodeSignature;
+ std::string strZeroNodeSignMessage;
+
+ CPubKey pubKeyCollateralAddress;
+ CKey keyCollateralAddress;
+ CPubKey pubKeyZeronode;
+ CKey keyZeronode;
+
+ UniValue statusObj(UniValue::VOBJ);
+
+ if (!obfuScationSigner.SetKey(zne.getPrivKey(), errorMessage, keyZeronode, pubKeyZeronode)) {
+ failed++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Zeronode signing error, could not set key correctly: " + errorMessage));
+ resultsObj.push_back(statusObj);
+ continue;
+ }
+
+ CZeronode* pzn = znodeman.Find(pubKeyZeronode);
+ if (pzn == NULL) {
+ failed++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Can't find zeronode by pubkey"));
+ resultsObj.push_back(statusObj);
+ continue;
+ }
+
+ CBudgetVote vote(pzn->vin, hash, nVote);
+ if (!vote.Sign(keyZeronode, pubKeyZeronode)) {
+ failed++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Failure to sign."));
+ resultsObj.push_back(statusObj);
+ continue;
+ }
+
+ std::string strError = "";
+ if (budget.UpdateProposal(vote, NULL, strError)) {
+ budget.mapSeenZeronodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
+ vote.Relay();
+ success++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "success"));
+ statusObj.push_back(Pair("error", ""));
+ } else {
+ failed++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", strError.c_str()));
+ }
+
+ resultsObj.push_back(statusObj);
+ }
+
+ UniValue returnObj(UniValue::VOBJ);
+ returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed)));
+ returnObj.push_back(Pair("detail", resultsObj));
+
+ return returnObj;
+ }
+
+ if (strCommand == "alias") {
+ std::string strAlias = params[3].get_str();
+ std::vector znEntries;
+ znEntries = zeronodeConfig.getEntries();
+
+ BOOST_FOREACH(CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+
+ if( strAlias != zne.getAlias()) continue;
+
+ std::string errorMessage;
+ std::vector vchZeroNodeSignature;
+ std::string strZeroNodeSignMessage;
+
+ CPubKey pubKeyCollateralAddress;
+ CKey keyCollateralAddress;
+ CPubKey pubKeyZeronode;
+ CKey keyZeronode;
+
+ UniValue statusObj(UniValue::VOBJ);
+
+ if(!obfuScationSigner.SetKey(zne.getPrivKey(), errorMessage, keyZeronode, pubKeyZeronode)){
+ failed++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Zeronode signing error, could not set key correctly: " + errorMessage));
+ resultsObj.push_back(statusObj);
+ continue;
+ }
+
+ CZeronode* pzn = znodeman.Find(pubKeyZeronode);
+ if(pzn == NULL)
+ {
+ failed++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Can't find zeronode by pubkey"));
+ resultsObj.push_back(statusObj);
+ continue;
+ }
+
+ CBudgetVote vote(pzn->vin, hash, nVote);
+ if(!vote.Sign(keyZeronode, pubKeyZeronode)){
+ failed++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "Failure to sign."));
+ resultsObj.push_back(statusObj);
+ continue;
+ }
+
+ std::string strError = "";
+ if(budget.UpdateProposal(vote, NULL, strError)) {
+ budget.mapSeenZeronodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
+ vote.Relay();
+ success++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "success"));
+ statusObj.push_back(Pair("error", ""));
+ } else {
+ failed++;
+ statusObj.push_back(Pair("node", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", strError.c_str()));
+ }
+
+ resultsObj.push_back(statusObj);
+ }
+
+ UniValue returnObj(UniValue::VOBJ);
+ returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed)));
+ returnObj.push_back(Pair("detail", resultsObj));
+
+ return returnObj;
+ }
+
+ return NullUniValue;
+}
+
+UniValue getbudgetvotes(const UniValue& params, bool fHelp)
+{
+ if (params.size() != 1)
+ throw runtime_error(
+ "getbudgetvotes \"proposal-name\"\n"
+ "\nPrint vote information for a budget proposal\n"
+
+ "\nArguments:\n"
+ "1. \"proposal-name\": (string, required) Name of the proposal\n"
+
+ "\nResult:\n"
+ "[\n"
+ " {\n"
+ " \"znId\": \"xxxx\", (string) Hash of the zeronode's collateral transaction\n"
+ " \"nHash\": \"xxxx\", (string) Hash of the vote\n"
+ " \"Vote\": \"YES|NO\", (string) Vote cast ('YES' or 'NO')\n"
+ " \"nTime\": xxxx, (numeric) Time in seconds since epoch the vote was cast\n"
+ " \"fValid\": true|false, (boolean) 'true' if the vote is valid, 'false' otherwise\n"
+ " }\n"
+ " ,...\n"
+ "]\n"
+ "\nExamples:\n" +
+ HelpExampleCli("getbudgetvotes", "\"test-proposal\"") + HelpExampleRpc("getbudgetvotes", "\"test-proposal\""));
+
+ std::string strProposalName = SanitizeString(params[0].get_str());
+
+ UniValue ret(UniValue::VARR);
+
+ CBudgetProposal* pbudgetProposal = budget.FindProposal(strProposalName);
+
+ if (pbudgetProposal == NULL) throw runtime_error("Unknown proposal name");
+
+ std::map::iterator it = pbudgetProposal->mapVotes.begin();
+ while (it != pbudgetProposal->mapVotes.end()) {
+ UniValue bObj(UniValue::VOBJ);
+ bObj.push_back(Pair("znId", (*it).second.vin.prevout.hash.ToString()));
+ bObj.push_back(Pair("nHash", (*it).first.ToString().c_str()));
+ bObj.push_back(Pair("Vote", (*it).second.GetVoteString()));
+ bObj.push_back(Pair("nTime", (int64_t)(*it).second.nTime));
+ bObj.push_back(Pair("fValid", (*it).second.fValid));
+
+ ret.push_back(bObj);
+
+ it++;
+ }
+
+ return ret;
+}
+
+UniValue getnextsuperblock(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getnextsuperblock\n"
+ "\nPrint the next super block height\n"
+
+ "\nResult:\n"
+ "n (numeric) Block height of the next super block\n"
+ "\nExamples:\n" +
+ HelpExampleCli("getnextsuperblock", "") + HelpExampleRpc("getnextsuperblock", ""));
+
+ CBlockIndex* pindexPrev = chainActive.Tip();
+ if (!pindexPrev) return "unknown";
+
+ int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks();
+ return nNext;
+}
+
+UniValue getbudgetprojection(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getbudgetprojection\n"
+ "\nShow the projection of which proposals will be paid the next cycle\n"
+
+ "\nResult:\n"
+ "[\n"
+ " {\n"
+ " \"Name\": \"xxxx\", (string) Proposal Name\n"
+ " \"URL\": \"xxxx\", (string) Proposal URL\n"
+ " \"Hash\": \"xxxx\", (string) Proposal vote hash\n"
+ " \"FeeHash\": \"xxxx\", (string) Proposal fee hash\n"
+ " \"BlockStart\": n, (numeric) Proposal starting block\n"
+ " \"BlockEnd\": n, (numeric) Proposal ending block\n"
+ " \"TotalPaymentCount\": n, (numeric) Number of payments\n"
+ " \"RemainingPaymentCount\": n, (numeric) Number of remaining payments\n"
+ " \"PaymentAddress\": \"xxxx\", (string) Zero address of payment\n"
+ " \"Ratio\": x.xxx, (numeric) Ratio of yeas vs nays\n"
+ " \"Yeas\": n, (numeric) Number of yea votes\n"
+ " \"Nays\": n, (numeric) Number of nay votes\n"
+ " \"Abstains\": n, (numeric) Number of abstains\n"
+ " \"TotalPayment\": xxx.xxx, (numeric) Total payment amount\n"
+ " \"MonthlyPayment\": xxx.xxx, (numeric) Monthly payment amount\n"
+ " \"IsEstablished\": true|false, (boolean) Established (true) or (false)\n"
+ " \"IsValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
+ " \"IsValidReason\": \"xxxx\", (string) Error message, if any\n"
+ " \"fValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
+ " \"Alloted\": xxx.xxx, (numeric) Amount alloted in current period\n"
+ " \"TotalBudgetAlloted\": xxx.xxx (numeric) Total alloted\n"
+ " }\n"
+ " ,...\n"
+ "]\n"
+ "\nExamples:\n" +
+ HelpExampleCli("getbudgetprojection", "") + HelpExampleRpc("getbudgetprojection", ""));
+
+ UniValue ret(UniValue::VARR);
+ UniValue resultObj(UniValue::VOBJ);
+ CAmount nTotalAllotted = 0;
+
+ std::vector winningProps = budget.GetBudget();
+ BOOST_FOREACH (CBudgetProposal* pbudgetProposal, winningProps) {
+ nTotalAllotted += pbudgetProposal->GetAllotted();
+
+ //CTxDestination address1;
+ //ExtractDestination(pbudgetProposal->GetPayee(), address1);
+ //CTxDestination address2 = DecodeDestination(address1);
+
+ UniValue bObj(UniValue::VOBJ);
+ budgetToJSON(pbudgetProposal, bObj);
+ bObj.push_back(Pair("Alloted", ValueFromAmount(pbudgetProposal->GetAllotted())));
+ bObj.push_back(Pair("TotalBudgetAlloted", ValueFromAmount(nTotalAllotted)));
+
+ ret.push_back(bObj);
+ }
+
+ return ret;
+}
+
+UniValue getbudgetinfo(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "getbudgetinfo ( \"proposal\" )\n"
+ "\nShow current zeronode budgets\n"
+
+ "\nArguments:\n"
+ "1. \"proposal\" (string, optional) Proposal name\n"
+
+ "\nResult:\n"
+ "[\n"
+ " {\n"
+ " \"Name\": \"xxxx\", (string) Proposal Name\n"
+ " \"URL\": \"xxxx\", (string) Proposal URL\n"
+ " \"Hash\": \"xxxx\", (string) Proposal vote hash\n"
+ " \"FeeHash\": \"xxxx\", (string) Proposal fee hash\n"
+ " \"BlockStart\": n, (numeric) Proposal starting block\n"
+ " \"BlockEnd\": n, (numeric) Proposal ending block\n"
+ " \"TotalPaymentCount\": n, (numeric) Number of payments\n"
+ " \"RemainingPaymentCount\": n, (numeric) Number of remaining payments\n"
+ " \"PaymentAddress\": \"xxxx\", (string) Zero address of payment\n"
+ " \"Ratio\": x.xxx, (numeric) Ratio of yeas vs nays\n"
+ " \"Yeas\": n, (numeric) Number of yea votes\n"
+ " \"Nays\": n, (numeric) Number of nay votes\n"
+ " \"Abstains\": n, (numeric) Number of abstains\n"
+ " \"TotalPayment\": xxx.xxx, (numeric) Total payment amount\n"
+ " \"MonthlyPayment\": xxx.xxx, (numeric) Monthly payment amount\n"
+ " \"IsEstablished\": true|false, (boolean) Established (true) or (false)\n"
+ " \"IsValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
+ " \"IsValidReason\": \"xxxx\", (string) Error message, if any\n"
+ " \"fValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
+ " }\n"
+ " ,...\n"
+ "]\n"
+ "\nExamples:\n" +
+ HelpExampleCli("getbudgetprojection", "") + HelpExampleRpc("getbudgetprojection", ""));
+
+ UniValue ret(UniValue::VARR);
+
+ std::string strShow = "valid";
+ if (params.size() == 1) {
+ std::string strProposalName = SanitizeString(params[0].get_str());
+ CBudgetProposal* pbudgetProposal = budget.FindProposal(strProposalName);
+ if (pbudgetProposal == NULL) throw runtime_error("Unknown proposal name");
+ UniValue bObj(UniValue::VOBJ);
+ budgetToJSON(pbudgetProposal, bObj);
+ ret.push_back(bObj);
+ return ret;
+ }
+
+ std::vector winningProps = budget.GetAllProposals();
+ BOOST_FOREACH (CBudgetProposal* pbudgetProposal, winningProps) {
+ if (strShow == "valid" && !pbudgetProposal->fValid) continue;
+
+ UniValue bObj(UniValue::VOBJ);
+ budgetToJSON(pbudgetProposal, bObj);
+
+ ret.push_back(bObj);
+ }
+
+ return ret;
+}
+
+UniValue znbudgetrawvote(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 6)
+ throw runtime_error(
+ "znbudgetrawvote \"zeronode-tx-hash\" zeronode-tx-index \"proposal-hash\" yes|no time \"vote-sig\"\n"
+ "\nCompile and relay a proposal vote with provided external signature instead of signing vote internally\n"
+
+ "\nArguments:\n"
+ "1. \"zeronode-tx-hash\" (string, required) Transaction hash for the zeronode\n"
+ "2. zeronode-tx-index (numeric, required) Output index for the zeronode\n"
+ "3. \"proposal-hash\" (string, required) Proposal vote hash\n"
+ "4. yes|no (boolean, required) Vote to cast\n"
+ "5. time (numeric, required) Time since epoch in seconds\n"
+ "6. \"vote-sig\" (string, required) External signature\n"
+
+ "\nResult:\n"
+ "\"status\" (string) Vote status or error message\n"
+ "\nExamples:\n" +
+ HelpExampleCli("znbudgetrawvote", "") + HelpExampleRpc("znbudgetrawvote", ""));
+
+ uint256 hashMnTx = ParseHashV(params[0], "zn tx hash");
+ int nMnTxIndex = params[1].get_int();
+ CTxIn vin = CTxIn(hashMnTx, nMnTxIndex);
+
+ uint256 hashProposal = ParseHashV(params[2], "Proposal hash");
+ std::string strVote = params[3].get_str();
+
+ if (strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
+ int nVote = VOTE_ABSTAIN;
+ if (strVote == "yes") nVote = VOTE_YES;
+ if (strVote == "no") nVote = VOTE_NO;
+
+ int64_t nTime = params[4].get_int64();
+ std::string strSig = params[5].get_str();
+ bool fInvalid = false;
+ vector vchSig = DecodeBase64(strSig.c_str(), &fInvalid);
+
+ if (fInvalid)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
+
+ CZeronode* pzn = znodeman.Find(vin);
+ if (pzn == NULL) {
+ return "Failure to find zeronode in list : " + vin.ToString();
+ }
+
+ CBudgetVote vote(vin, hashProposal, nVote);
+ vote.nTime = nTime;
+ vote.vchSig = vchSig;
+
+ if (!vote.SignatureValid(true)) {
+ return "Failure to verify signature.";
+ }
+
+ std::string strError = "";
+ if (budget.UpdateProposal(vote, NULL, strError)) {
+ budget.mapSeenZeronodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
+ vote.Relay();
+ return "Voted successfully";
+ } else {
+ return "Error voting : " + strError;
+ }
+}
+
+UniValue znfinalbudget(const UniValue& params, bool fHelp)
+{
+ string strCommand;
+ if (params.size() >= 1)
+ strCommand = params[0].get_str();
+
+ if (fHelp ||
+ (strCommand != "suggest" && strCommand != "vote-many" && strCommand != "vote" && strCommand != "show" && strCommand != "getvotes"))
+ throw runtime_error(
+ "znfinalbudget \"command\"... ( \"passphrase\" )\n"
+ "Vote or show current budgets\n"
+ "\nAvailable commands:\n"
+ " vote-many - Vote on a finalized budget\n"
+ " vote - Vote on a finalized budget\n"
+ " show - Show existing finalized budgets\n"
+ " getvotes - Get vote information for each finalized budget\n");
+
+ if (strCommand == "vote-many") {
+ if (params.size() != 2)
+ throw runtime_error("Correct usage is 'znfinalbudget vote-many BUDGET_HASH'");
+
+ std::string strHash = params[1].get_str();
+ uint256 hash(uint256S(strHash));
+
+ int success = 0;
+ int failed = 0;
+
+ UniValue resultsObj(UniValue::VOBJ);
+
+ BOOST_FOREACH (CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+ std::string errorMessage;
+ std::vector vchZeroNodeSignature;
+ std::string strZeroNodeSignMessage;
+
+ CPubKey pubKeyCollateralAddress;
+ CKey keyCollateralAddress;
+ CPubKey pubKeyZeronode;
+ CKey keyZeronode;
+
+ UniValue statusObj(UniValue::VOBJ);
+
+ if (!obfuScationSigner.SetKey(zne.getPrivKey(), errorMessage, keyZeronode, pubKeyZeronode)) {
+ failed++;
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("errorMessage", "Zeronode signing error, could not set key correctly: " + errorMessage));
+ resultsObj.push_back(Pair(zne.getAlias(), statusObj));
+ continue;
+ }
+
+ CZeronode* pzn = znodeman.Find(pubKeyZeronode);
+ if (pzn == NULL) {
+ failed++;
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("errorMessage", "Can't find zeronode by pubkey"));
+ resultsObj.push_back(Pair(zne.getAlias(), statusObj));
+ continue;
+ }
+
+
+ CFinalizedBudgetVote vote(pzn->vin, hash);
+ if (!vote.Sign(keyZeronode, pubKeyZeronode)) {
+ failed++;
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("errorMessage", "Failure to sign."));
+ resultsObj.push_back(Pair(zne.getAlias(), statusObj));
+ continue;
+ }
+
+ std::string strError = "";
+ if (budget.UpdateFinalizedBudget(vote, NULL, strError)) {
+ budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote));
+ vote.Relay();
+ success++;
+ statusObj.push_back(Pair("result", "success"));
+ } else {
+ failed++;
+ statusObj.push_back(Pair("result", strError.c_str()));
+ }
+
+ resultsObj.push_back(Pair(zne.getAlias(), statusObj));
+ }
+
+ UniValue returnObj(UniValue::VOBJ);
+ returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed)));
+ returnObj.push_back(Pair("detail", resultsObj));
+
+ return returnObj;
+ }
+
+ if (strCommand == "vote") {
+ if (params.size() != 2)
+ throw runtime_error("Correct usage is 'znfinalbudget vote BUDGET_HASH'");
+
+ std::string strHash = params[1].get_str();
+ uint256 hash;
+ hash = ArithToUint256(arith_uint256(strHash));
+
+ CPubKey pubKeyZeronode;
+ CKey keyZeronode;
+ std::string errorMessage;
+
+ if (!obfuScationSigner.SetKey(strZeroNodePrivKey, errorMessage, keyZeronode, pubKeyZeronode))
+ return "Error upon calling SetKey";
+
+ CZeronode* pzn = znodeman.Find(activeZeronode.vin);
+ if (pzn == NULL) {
+ return "Failure to find zeronode in list : " + activeZeronode.vin.ToString();
+ }
+
+ CFinalizedBudgetVote vote(activeZeronode.vin, hash);
+ if (!vote.Sign(keyZeronode, pubKeyZeronode)) {
+ return "Failure to sign.";
+ }
+
+ std::string strError = "";
+ if (budget.UpdateFinalizedBudget(vote, NULL, strError)) {
+ budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote));
+ vote.Relay();
+ return "success";
+ } else {
+ return "Error voting : " + strError;
+ }
+ }
+
+ if (strCommand == "show") {
+ UniValue resultObj(UniValue::VOBJ);
+
+ std::vector winningFbs = budget.GetFinalizedBudgets();
+ BOOST_FOREACH (CFinalizedBudget* finalizedBudget, winningFbs) {
+ UniValue bObj(UniValue::VOBJ);
+ bObj.push_back(Pair("FeeTX", finalizedBudget->nFeeTXHash.ToString()));
+ bObj.push_back(Pair("Hash", finalizedBudget->GetHash().ToString()));
+ bObj.push_back(Pair("BlockStart", (int64_t)finalizedBudget->GetBlockStart()));
+ bObj.push_back(Pair("BlockEnd", (int64_t)finalizedBudget->GetBlockEnd()));
+ bObj.push_back(Pair("Proposals", finalizedBudget->GetProposals()));
+ bObj.push_back(Pair("VoteCount", (int64_t)finalizedBudget->GetVoteCount()));
+ bObj.push_back(Pair("Status", finalizedBudget->GetStatus()));
+
+ std::string strError = "";
+ bObj.push_back(Pair("IsValid", finalizedBudget->IsValid(strError)));
+ bObj.push_back(Pair("IsValidReason", strError.c_str()));
+
+ resultObj.push_back(Pair(finalizedBudget->GetName(), bObj));
+ }
+
+ return resultObj;
+ }
+
+ if (strCommand == "getvotes") {
+ if (params.size() != 2)
+ throw runtime_error("Correct usage is 'znbudget getvotes budget-hash'");
+
+ std::string strHash = params[1].get_str();
+ uint256 hash;
+ hash = ArithToUint256(arith_uint256(strHash));
+
+ UniValue obj(UniValue::VOBJ);
+
+ CFinalizedBudget* pfinalBudget = budget.FindFinalizedBudget(hash);
+
+ if (pfinalBudget == NULL) return "Unknown budget hash";
+
+ std::map::iterator it = pfinalBudget->mapVotes.begin();
+ while (it != pfinalBudget->mapVotes.end()) {
+ UniValue bObj(UniValue::VOBJ);
+ bObj.push_back(Pair("nHash", (*it).first.ToString().c_str()));
+ bObj.push_back(Pair("nTime", (int64_t)(*it).second.nTime));
+ bObj.push_back(Pair("fValid", (*it).second.fValid));
+
+ obj.push_back(Pair((*it).second.vin.prevout.ToStringShort(), bObj));
+
+ it++;
+ }
+
+ return obj;
+ }
+
+ return NullUniValue;
+}
+
+UniValue checkbudgets(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "checkbudgets\n"
+ "\nInitiates a buddget check cycle manually\n"
+ "\nExamples:\n" +
+ HelpExampleCli("checkbudgets", "") + HelpExampleRpc("checkbudgets", ""));
+
+ budget.CheckAndRemove();
+
+ return NullUniValue;
+}
+
+
+// This command is retained for backwards compatibility, but is depreciated.
+// Future removal of this command is planned to keep things clean.
+UniValue znbudget(const UniValue& params, bool fHelp)
+{
+ string strCommand;
+ if (params.size() >= 1)
+ strCommand = params[0].get_str();
+
+ if (fHelp ||
+ (strCommand != "vote-alias" && strCommand != "vote-many" && strCommand != "prepare" && strCommand != "submit" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo" && strCommand != "show" && strCommand != "projection" && strCommand != "check" && strCommand != "nextblock"))
+ throw runtime_error(
+ "znbudget \"command\"... ( \"passphrase\" )\n"
+ "\nVote or show current budgets\n"
+ "This command is depreciated, please see individual command documentation for future reference\n\n"
+
+ "\nAvailable commands:\n"
+ " prepare - Prepare proposal for network by signing and creating tx\n"
+ " submit - Submit proposal for network\n"
+ " vote-many - Vote on a Zero initiative\n"
+ " vote-alias - Vote on a Zero initiative\n"
+ " vote - Vote on a Zero initiative/budget\n"
+ " getvotes - Show current zeronode budgets\n"
+ " getinfo - Show current zeronode budgets\n"
+ " show - Show all budgets\n"
+ " projection - Show the projection of which proposals will be paid the next cycle\n"
+ " check - Scan proposals and remove invalid\n"
+ " nextblock - Get next superblock for budget system\n");
+
+ if (strCommand == "nextblock") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getnextsuperblock(newParams, fHelp);
+ }
+
+ if (strCommand == "prepare") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return preparebudget(newParams, fHelp);
+ }
+
+ if (strCommand == "submit") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return submitbudget(newParams, fHelp);
+ }
+
+ if (strCommand == "vote" || strCommand == "vote-many" || strCommand == "vote-alias") {
+ if (strCommand == "vote-alias")
+ throw runtime_error(
+ "vote-alias is not supported with this command\n"
+ "Please use znbudgetvote instead.\n"
+ );
+ return znbudgetvote(params, fHelp);
+ }
+
+ if (strCommand == "projection") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getbudgetprojection(newParams, fHelp);
+ }
+
+ if (strCommand == "show" || strCommand == "getinfo") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getbudgetinfo(newParams, fHelp);
+ }
+
+ if (strCommand == "getvotes") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getbudgetvotes(newParams, fHelp);
+ }
+
+ if (strCommand == "check") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return checkbudgets(newParams, fHelp);
+ }
+
+ return NullUniValue;
+}
+
+
+
+static const CRPCCommand commands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ { "zeronode-budget", "znbudget", &znbudget, true },
+ { "zeronode-budget", "preparebudget", &preparebudget, true },
+ { "zeronode-budget", "submitbudget", &submitbudget, true },
+ { "zeronode-budget", "znbudgetvote", &znbudgetvote, true },
+ { "zeronode-budget", "getbudgetvotes", &getbudgetvotes, true },
+ { "zeronode-budget", "getnextsuperblock", &getnextsuperblock, true },
+ { "zeronode-budget", "getbudgetprojection", &getbudgetprojection, true },
+ { "zeronode-budget", "getbudgetinfo", &getbudgetinfo, true },
+ { "zeronode-budget", "znbudgetrawvote", &znbudgetrawvote, true },
+ { "zeronode-budget", "znfinalbudget", &znfinalbudget, true },
+ { "zeronode-budget", "znbudgetvote", &znbudgetvote, true },
+ { "zeronode-budget", "checkbudgets", &checkbudgets, true },
+};
+
+void RegisterBudgetRPCCommands(CRPCTable &tableRPC)
+{
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+}
diff --git a/src/rpc/zeronode.cpp b/src/rpc/zeronode.cpp
new file mode 100644
index 00000000000..98ffb7cf559
--- /dev/null
+++ b/src/rpc/zeronode.cpp
@@ -0,0 +1,1006 @@
+// Copyright (c) 2009-2012 The Bitcoin developers
+// Copyright (c) 2015-2017 The PIVX developers
+// Copyright (c) 2017-2018 The Zero developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "zeronode/activezeronode.h"
+#include "db.h"
+#include "init.h"
+#include "main.h"
+#include "zeronode/budget.h"
+#include "zeronode/payments.h"
+#include "zeronode/zeronodeconfig.h"
+#include "zeronode/zeronodeman.h"
+#include "zeronode/zeronode-sync.h"
+#include "rpc/server.h"
+#include "utilmoneystr.h"
+
+#include
+
+#include
+
+UniValue listzeronodes(const UniValue& params, bool fHelp)
+{
+ std::string strFilter = "";
+
+ if (params.size() == 1) strFilter = params[0].get_str();
+
+ if (fHelp || (params.size() > 1))
+ throw runtime_error(
+ "listzeronodes ( \"filter\" )\n"
+ "\nGet a ranked list of zeronodes\n"
+
+ "\nArguments:\n"
+ "1. \"filter\" (string, optional) Filter search text. Partial match by txhash, status, or addr.\n"
+
+ "\nResult:\n"
+ "[\n"
+ " {\n"
+ " \"rank\": n, (numeric) Zeronode Rank (or 0 if not enabled)\n"
+ " \"txhash\": \"hash\", (string) Collateral transaction hash\n"
+ " \"outidx\": n, (numeric) Collateral transaction output index\n"
+ " \"status\": s, (string) Status (ENABLED/EXPIRED/REMOVE/etc)\n"
+ " \"addr\": \"addr\", (string) Zeronode Zero address\n"
+ " \"version\": v, (numeric) Zeronode protocol version\n"
+ " \"lastseen\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last seen\n"
+ " \"activetime\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) zeronode has been active\n"
+ " \"lastpaid\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) zeronode was last paid\n"
+ " }\n"
+ " ,...\n"
+ "]\n"
+ "\nExamples:\n" +
+ HelpExampleCli("zeronodelist", "") + HelpExampleRpc("zeronodelist", ""));
+
+ UniValue ret(UniValue::VARR);
+ int nHeight;
+ {
+ LOCK(cs_main);
+ CBlockIndex* pindex = chainActive.Tip();
+ if(!pindex) return 0;
+ nHeight = pindex->nHeight;
+ }
+ std::vector > vZeronodeRanks = znodeman.GetZeronodeRanks(nHeight);
+ BOOST_FOREACH (PAIRTYPE(int, CZeronode) & s, vZeronodeRanks) {
+ UniValue obj(UniValue::VOBJ);
+ std::string strVin = s.second.vin.prevout.ToStringShort();
+ std::string strTxHash = s.second.vin.prevout.hash.ToString();
+ uint32_t oIdx = s.second.vin.prevout.n;
+
+ CZeronode* zn = znodeman.Find(s.second.vin);
+
+ if (zn != NULL) {
+ if (strFilter != "" && strTxHash.find(strFilter) == string::npos &&
+ zn->Status().find(strFilter) == string::npos &&
+ EncodeDestination(zn->pubKeyCollateralAddress.GetID()).find(strFilter) == string::npos) continue;
+
+ std::string strStatus = zn->Status();
+ std::string strHost;
+ int port;
+ SplitHostPort(zn->addr.ToString(), port, strHost);
+ CNetAddr node = CNetAddr(strHost, false);
+ std::string strNetwork = GetNetworkName(node.GetNetwork());
+
+ obj.push_back(Pair("rank", (strStatus == "ENABLED" ? s.first : 0)));
+ obj.push_back(Pair("network", strNetwork));
+ obj.push_back(Pair("ip", strHost));
+ obj.push_back(Pair("txhash", strTxHash));
+ obj.push_back(Pair("outidx", (uint64_t)oIdx));
+ obj.push_back(Pair("status", strStatus));
+ obj.push_back(Pair("addr", EncodeDestination(zn->pubKeyCollateralAddress.GetID())));
+ obj.push_back(Pair("version", zn->protocolVersion));
+ obj.push_back(Pair("lastseen", (int64_t)zn->lastPing.sigTime));
+ obj.push_back(Pair("activetime", (int64_t)(zn->lastPing.sigTime - zn->sigTime)));
+ obj.push_back(Pair("lastpaid", (int64_t)zn->GetLastPaid()));
+
+ ret.push_back(obj);
+ }
+ }
+
+ return ret;
+}
+
+UniValue startalias(const UniValue& params, bool fHelp)
+{
+ LogPrintf("params.size(): %d", params.size());
+ if (fHelp || (params.size() != 1))
+ throw runtime_error(
+ "startalias \"aliasname\"\n"
+ "\nAttempts to start an alias\n"
+
+ "\nArguments:\n"
+ "1. \"aliasname\" (string, required) alias name\n"
+
+ "\nExamples:\n" +
+ HelpExampleCli("startalias", "\"zn1\"") + HelpExampleRpc("startalias", ""));
+ if (!zeronodeSync.IsSynced())
+ {
+ UniValue obj(UniValue::VOBJ);
+ std::string error = "Zeronode is not synced, please wait. Current status: " + zeronodeSync.GetSyncStatus();
+ obj.push_back(Pair("result", error));
+ return obj;
+ }
+
+ std::string strAlias = params[0].get_str();
+ bool fSuccess = false;
+ BOOST_FOREACH (CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+ if (zne.getAlias() == strAlias) {
+ std::string strError;
+ CZeronodeBroadcast znb;
+
+ fSuccess = CZeronodeBroadcast::Create(zne.getIp(), zne.getPrivKey(), zne.getTxHash(), zne.getOutputIndex(), strError, znb);
+
+ if (fSuccess) {
+ znodeman.UpdateZeronodeList(znb);
+ znb.Relay();
+ }
+ break;
+ }
+ }
+ if (fSuccess) {
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("result", "Successfully started alias"));
+ return obj;
+ } else {
+ throw runtime_error("Failed to start alias\n");
+ }
+}
+
+UniValue zeronodeconnect(const UniValue& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 1))
+ throw runtime_error(
+ "zeronodeconnect \"address\"\n"
+ "\nAttempts to connect to specified zeronode address\n"
+
+ "\nArguments:\n"
+ "1. \"address\" (string, required) IP or net address to connect to\n"
+
+ "\nExamples:\n" +
+ HelpExampleCli("zeronodeconnect", "\"192.168.0.6:23821\"") + HelpExampleRpc("zeronodeconnect", "\"192.168.0.6:23821\""));
+
+ std::string strAddress = params[0].get_str();
+
+ CService addr = CService(strAddress);
+
+ CNode* pnode = ConnectNode((CAddress)addr, NULL, false);
+ if (pnode) {
+ pnode->Release();
+ return NullUniValue;
+ } else {
+ throw runtime_error("error connecting\n");
+ }
+}
+
+UniValue getzeronodecount (const UniValue& params, bool fHelp)
+{
+ if (fHelp || (params.size() > 0))
+ throw runtime_error(
+ "getzeronodecount\n"
+ "\nGet zeronode count values\n"
+
+ "\nResult:\n"
+ "{\n"
+ " \"total\": n, (numeric) Total zeronodes\n"
+ " \"stable\": n, (numeric) Stable count\n"
+ " \"obfcompat\": n, (numeric) Obfuscation Compatible\n"
+ " \"enabled\": n, (numeric) Enabled zeronodes\n"
+ " \"inqueue\": n (numeric) Zeronodes in queue\n"
+ "}\n"
+ "\nExamples:\n" +
+ HelpExampleCli("getzeronodecount", "") + HelpExampleRpc("getzeronodecount", ""));
+
+ UniValue obj(UniValue::VOBJ);
+ int nCount = 0;
+ int ipv4 = 0, ipv6 = 0, onion = 0;
+
+ if (chainActive.Tip())
+ znodeman.GetNextZeronodeInQueueForPayment(chainActive.Tip()->nHeight, true, nCount);
+
+ znodeman.CountNetworks(ActiveProtocol(), ipv4, ipv6, onion);
+
+ obj.push_back(Pair("total", znodeman.size()));
+ obj.push_back(Pair("stable", znodeman.stable_size()));
+ obj.push_back(Pair("obfcompat", znodeman.CountEnabled(ActiveProtocol())));
+ obj.push_back(Pair("enabled", znodeman.CountEnabled()));
+ obj.push_back(Pair("inqueue", nCount));
+ obj.push_back(Pair("ipv4", ipv4));
+ obj.push_back(Pair("ipv6", ipv6));
+ obj.push_back(Pair("onion", onion));
+
+ return obj;
+}
+
+UniValue zeronodecurrent (const UniValue& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 0))
+ throw runtime_error(
+ "zeronodecurrent\n"
+ "\nGet current zeronode winner\n"
+
+ "\nResult:\n"
+ "{\n"
+ " \"protocol\": xxxx, (numeric) Protocol version\n"
+ " \"txhash\": \"xxxx\", (string) Collateral transaction hash\n"
+ " \"pubkey\": \"xxxx\", (string) MN Public key\n"
+ " \"lastseen\": xxx, (numeric) Time since epoch of last seen\n"
+ " \"activeseconds\": xxx, (numeric) Seconds MN has been active\n"
+ "}\n"
+ "\nExamples:\n" +
+ HelpExampleCli("zeronodecurrent", "") + HelpExampleRpc("zeronodecurrent", ""));
+
+ CZeronode* winner = znodeman.GetCurrentZeroNode(1);
+ if (winner) {
+ UniValue obj(UniValue::VOBJ);
+
+ obj.push_back(Pair("protocol", (int64_t)winner->protocolVersion));
+ obj.push_back(Pair("txhash", winner->vin.prevout.hash.ToString()));
+ obj.push_back(Pair("pubkey", EncodeDestination(winner->pubKeyCollateralAddress.GetID())));
+ obj.push_back(Pair("lastseen", (winner->lastPing == CZeronodePing()) ? winner->sigTime : (int64_t)winner->lastPing.sigTime));
+ obj.push_back(Pair("activeseconds", (winner->lastPing == CZeronodePing()) ? 0 : (int64_t)(winner->lastPing.sigTime - winner->sigTime)));
+ return obj;
+ }
+
+ throw runtime_error("unknown");
+}
+
+UniValue zeronodedebug (const UniValue& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 0))
+ throw runtime_error(
+ "zeronodedebug\n"
+ "\nPrint zeronode status\n"
+
+ "\nResult:\n"
+ "\"status\" (string) Zeronode status message\n"
+ "\nExamples:\n" +
+ HelpExampleCli("zeronodedebug", "") + HelpExampleRpc("zeronodedebug", ""));
+
+ if (activeZeronode.status != ACTIVE_ZERONODE_INITIAL || !zeronodeSync.IsSynced())
+ return activeZeronode.GetStatus();
+
+ CTxIn vin = CTxIn();
+ CPubKey pubkey;
+ CKey key;
+ if (!activeZeronode.GetZeroNodeVin(vin, pubkey, key))
+ throw runtime_error("Missing zeronode input, please look at the documentation for instructions on zeronode creation\n");
+ else
+ return activeZeronode.GetStatus();
+}
+
+UniValue startzeronode (const UniValue& params, bool fHelp)
+{
+ std::string strCommand;
+ if (params.size() >= 1) {
+ strCommand = params[0].get_str();
+
+ // Backwards compatibility with legacy 'zeronode' super-command forwarder
+ if (strCommand == "start") strCommand = "local";
+ if (strCommand == "start-alias") strCommand = "alias";
+ if (strCommand == "start-all") strCommand = "all";
+ if (strCommand == "start-many") strCommand = "many";
+ if (strCommand == "start-missing") strCommand = "missing";
+ if (strCommand == "start-disabled") strCommand = "disabled";
+ }
+
+ if (fHelp || params.size() < 2 || params.size() > 3 ||
+ (params.size() == 2 && (strCommand != "local" && strCommand != "all" && strCommand != "many" && strCommand != "missing" && strCommand != "disabled")) ||
+ (params.size() == 3 && strCommand != "alias"))
+ throw runtime_error(
+ "startzeronode \"local|all|many|missing|disabled|alias\" lockwallet ( \"alias\" )\n"
+ "\nAttempts to start one or more zeronode(s)\n"
+
+ "\nArguments:\n"
+ "1. set (string, required) Specify which set of zeronode(s) to start.\n"
+ "2. lockwallet (boolean, required) Lock wallet after completion.\n"
+ "3. alias (string) Zeronode alias. Required if using 'alias' as the set.\n"
+
+ "\nResult: (for 'local' set):\n"
+ "\"status\" (string) Zeronode status message\n"
+
+ "\nResult: (for other sets):\n"
+ "{\n"
+ " \"overall\": \"xxxx\", (string) Overall status message\n"
+ " \"detail\": [\n"
+ " {\n"
+ " \"node\": \"xxxx\", (string) Node name or alias\n"
+ " \"result\": \"xxxx\", (string) 'success' or 'failed'\n"
+ " \"error\": \"xxxx\" (string) Error message, if failed\n"
+ " }\n"
+ " ,...\n"
+ " ]\n"
+ "}\n"
+ "\nExamples:\n" +
+ HelpExampleCli("startzeronode", "\"alias\" \"0\" \"my_zn\"") + HelpExampleRpc("startzeronode", "\"alias\" \"0\" \"my_zn\""));
+
+ if (!zeronodeSync.IsSynced())
+ {
+ UniValue resultsObj(UniValue::VARR);
+ int successful = 0;
+ int failed = 0;
+ BOOST_FOREACH (CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+ UniValue statusObj(UniValue::VOBJ);
+ statusObj.push_back(Pair("alias", zne.getAlias()));
+ statusObj.push_back(Pair("result", "failed"));
+
+ failed++;
+ {
+ std::string error = "Zeronode is not synced, please wait. Current status: " + zeronodeSync.GetSyncStatus();
+ statusObj.push_back(Pair("error", error));
+ }
+ resultsObj.push_back(statusObj);
+ }
+
+ UniValue returnObj(UniValue::VOBJ);
+ returnObj.push_back(Pair("overall", strprintf("Successfully started %d zeronodes, failed to start %d, total %d", successful, failed, successful + failed)));
+ returnObj.push_back(Pair("detail", resultsObj));
+
+ return returnObj;
+ }
+
+ bool fLock = (params[1].get_str() == "true" ? true : false);
+
+ if (strCommand == "local") {
+ if (!fZeroNode) throw runtime_error("you must set zeronode=1 in the configuration\n");
+
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+
+ if (activeZeronode.status != ACTIVE_ZERONODE_STARTED) {
+ activeZeronode.status = ACTIVE_ZERONODE_INITIAL; // TODO: consider better way
+ activeZeronode.ManageStatus();
+ if (fLock)
+ pwalletMain->Lock();
+ }
+
+ return activeZeronode.GetStatus();
+ }
+
+ if (strCommand == "all" || strCommand == "many" || strCommand == "missing" || strCommand == "disabled") {
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+
+ if ((strCommand == "missing" || strCommand == "disabled") &&
+ (zeronodeSync.RequestedZeronodeAssets <= ZERONODE_SYNC_LIST ||
+ zeronodeSync.RequestedZeronodeAssets == ZERONODE_SYNC_FAILED)) {
+ throw runtime_error("You can't use this command until zeronode list is synced\n");
+ }
+
+ std::vector znEntries;
+ znEntries = zeronodeConfig.getEntries();
+
+ int successful = 0;
+ int failed = 0;
+
+ UniValue resultsObj(UniValue::VARR);
+
+ BOOST_FOREACH (CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+ std::string errorMessage;
+ int nIndex;
+ if(!zne.castOutputIndex(nIndex))
+ continue;
+ CTxIn vin = CTxIn(uint256S(zne.getTxHash()), uint32_t(nIndex));
+ CZeronode* pzn = znodeman.Find(vin);
+
+ if (pzn != NULL) {
+ if (strCommand == "missing") continue;
+ if (strCommand == "disabled" && pzn->IsEnabled()) continue;
+ }
+
+ bool result = activeZeronode.Register(zne.getIp(), zne.getPrivKey(), zne.getTxHash(), zne.getOutputIndex(), errorMessage);
+
+ UniValue statusObj(UniValue::VOBJ);
+ statusObj.push_back(Pair("alias", zne.getAlias()));
+ statusObj.push_back(Pair("result", result ? "success" : "failed"));
+
+ if (result) {
+ successful++;
+ statusObj.push_back(Pair("error", ""));
+ } else {
+ failed++;
+ statusObj.push_back(Pair("error", errorMessage));
+ }
+
+ resultsObj.push_back(statusObj);
+ }
+ if (fLock)
+ pwalletMain->Lock();
+
+ UniValue returnObj(UniValue::VOBJ);
+ returnObj.push_back(Pair("overall", strprintf("Successfully started %d zeronodes, failed to start %d, total %d", successful, failed, successful + failed)));
+ returnObj.push_back(Pair("detail", resultsObj));
+
+ return returnObj;
+ }
+
+ if (strCommand == "alias") {
+ std::string alias = params[2].get_str();
+
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+
+ bool found = false;
+ int successful = 0;
+ int failed = 0;
+
+ UniValue resultsObj(UniValue::VARR);
+ UniValue statusObj(UniValue::VOBJ);
+ statusObj.push_back(Pair("alias", alias));
+
+ BOOST_FOREACH (CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+ if (zne.getAlias() == alias) {
+ found = true;
+ std::string errorMessage;
+
+ bool result = activeZeronode.Register(zne.getIp(), zne.getPrivKey(), zne.getTxHash(), zne.getOutputIndex(), errorMessage);
+
+ statusObj.push_back(Pair("result", result ? "successful" : "failed"));
+
+ if (result) {
+ successful++;
+ statusObj.push_back(Pair("error", ""));
+ } else {
+ failed++;
+ statusObj.push_back(Pair("error", errorMessage));
+ }
+ break;
+ }
+ }
+
+ if (!found) {
+ failed++;
+ statusObj.push_back(Pair("result", "failed"));
+ statusObj.push_back(Pair("error", "could not find alias in config. Verify with list-conf."));
+ }
+
+ resultsObj.push_back(statusObj);
+
+ if (fLock)
+ pwalletMain->Lock();
+
+ UniValue returnObj(UniValue::VOBJ);
+ returnObj.push_back(Pair("overall", strprintf("Successfully started %d zeronodes, failed to start %d, total %d", successful, failed, successful + failed)));
+ returnObj.push_back(Pair("detail", resultsObj));
+
+ return returnObj;
+ }
+ return NullUniValue;
+}
+
+UniValue createzeronodekey (const UniValue& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 0))
+ throw runtime_error(
+ "createzeronodekey\n"
+ "\nCreate a new zeronode private key\n"
+
+ "\nResult:\n"
+ "\"key\" (string) Zeronode private key\n"
+ "\nExamples:\n" +
+ HelpExampleCli("createzeronodekey", "") + HelpExampleRpc("createzeronodekey", ""));
+
+ CKey secret;
+ secret.MakeNewKey(false);
+
+ return EncodeSecret(secret);
+}
+
+UniValue getzeronodeoutputs (const UniValue& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 0))
+ throw runtime_error(
+ "getzeronodeoutputs\n"
+ "\nPrint all zeronode transaction outputs\n"
+
+ "\nResult:\n"
+ "[\n"
+ " {\n"
+ " \"txhash\": \"xxxx\", (string) output transaction hash\n"
+ " \"outputidx\": n (numeric) output index number\n"
+ " }\n"
+ " ,...\n"
+ "]\n"
+
+ "\nExamples:\n" +
+ HelpExampleCli("getzeronodeoutputs", "") + HelpExampleRpc("getzeronodeoutputs", ""));
+
+ // Find possible candidates
+ vector possibleCoins = activeZeronode.SelectCoinsZeronode();
+
+ UniValue ret(UniValue::VARR);
+ BOOST_FOREACH (COutput& out, possibleCoins) {
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("txhash", out.tx->GetHash().ToString()));
+ obj.push_back(Pair("outputidx", out.i));
+ ret.push_back(obj);
+ }
+
+ return ret;
+}
+
+UniValue listzeronodeconf (const UniValue& params, bool fHelp)
+{
+ std::string strFilter = "";
+
+ if (params.size() == 1) strFilter = params[0].get_str();
+
+ if (fHelp || (params.size() > 1))
+ throw runtime_error(
+ "listzeronodeconf ( \"filter\" )\n"
+ "\nPrint zeronode.conf in JSON format\n"
+
+ "\nArguments:\n"
+ "1. \"filter\" (string, optional) Filter search text. Partial match on alias, address, txHash, or status.\n"
+
+ "\nResult:\n"
+ "[\n"
+ " {\n"
+ " \"alias\": \"xxxx\", (string) zeronode alias\n"
+ " \"address\": \"xxxx\", (string) zeronode IP address\n"
+ " \"privateKey\": \"xxxx\", (string) zeronode private key\n"
+ " \"txHash\": \"xxxx\", (string) transaction hash\n"
+ " \"outputIndex\": n, (numeric) transaction output index\n"
+ " \"status\": \"xxxx\" (string) zeronode status\n"
+ " }\n"
+ " ,...\n"
+ "]\n"
+
+ "\nExamples:\n" +
+ HelpExampleCli("listzeronodeconf", "") + HelpExampleRpc("listzeronodeconf", ""));
+
+ std::vector znEntries;
+ znEntries = zeronodeConfig.getEntries();
+
+ UniValue ret(UniValue::VARR);
+
+ BOOST_FOREACH (CZeronodeConfig::CZeronodeEntry zne, zeronodeConfig.getEntries()) {
+ int nIndex;
+ if(!zne.castOutputIndex(nIndex))
+ continue;
+ CTxIn vin = CTxIn(uint256S(zne.getTxHash()), uint32_t(nIndex));
+ CZeronode* pzn = znodeman.Find(vin);
+
+ std::string strStatus = pzn ? pzn->Status() : "MISSING";
+
+ if (strFilter != "" && zne.getAlias().find(strFilter) == string::npos &&
+ zne.getIp().find(strFilter) == string::npos &&
+ zne.getTxHash().find(strFilter) == string::npos &&
+ strStatus.find(strFilter) == string::npos) continue;
+
+ UniValue znObj(UniValue::VARR);
+ znObj.push_back(Pair("alias", zne.getAlias()));
+ znObj.push_back(Pair("address", zne.getIp()));
+ znObj.push_back(Pair("privateKey", zne.getPrivKey()));
+ znObj.push_back(Pair("txHash", zne.getTxHash()));
+ znObj.push_back(Pair("outputIndex", zne.getOutputIndex()));
+ znObj.push_back(Pair("status", strStatus));
+ ret.push_back(znObj);
+ }
+
+ return ret;
+}
+
+UniValue getzeronodestatus (const UniValue& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 0))
+ throw runtime_error(
+ "getzeronodestatus\n"
+ "\nPrint zeronode status\n"
+
+ "\nResult:\n"
+ "{\n"
+ " \"txhash\": \"xxxx\", (string) Collateral transaction hash\n"
+ " \"outputidx\": n, (numeric) Collateral transaction output index number\n"
+ " \"netaddr\": \"xxxx\", (string) Zeronode network address\n"
+ " \"addr\": \"xxxx\", (string) Zero address for zeronode payments\n"
+ " \"status\": \"xxxx\", (string) Zeronode status\n"
+ " \"message\": \"xxxx\" (string) Zeronode status message\n"
+ "}\n"
+
+ "\nExamples:\n" +
+ HelpExampleCli("getzeronodestatus", "") + HelpExampleRpc("getzeronodestatus", ""));
+
+ if (!fZeroNode) throw runtime_error("This is not a zeronode");
+
+ CZeronode* pzn = znodeman.Find(activeZeronode.vin);
+
+ if (pzn) {
+ UniValue znObj(UniValue::VARR);
+ znObj.push_back(Pair("txhash", activeZeronode.vin.prevout.hash.ToString()));
+ znObj.push_back(Pair("outputidx", (uint64_t)activeZeronode.vin.prevout.n));
+ znObj.push_back(Pair("netaddr", activeZeronode.service.ToString()));
+ znObj.push_back(Pair("addr", EncodeDestination(pzn->pubKeyCollateralAddress.GetID())));
+ znObj.push_back(Pair("status", activeZeronode.status));
+ znObj.push_back(Pair("message", activeZeronode.GetStatus()));
+ return znObj;
+ }
+ throw runtime_error("Zeronode not found in the list of available zeronodes. Current status: "
+ + activeZeronode.GetStatus());
+}
+
+UniValue getzeronodewinners (const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() > 3)
+ throw runtime_error(
+ "getzeronodewinners ( blocks \"filter\" )\n"
+ "\nPrint the zeronode winners for the last n blocks\n"
+
+ "\nArguments:\n"
+ "1. blocks (numeric, optional) Number of previous blocks to show (default: 10)\n"
+ "2. filter (string, optional) Search filter matching MN address\n"
+
+ "\nResult (single winner):\n"
+ "[\n"
+ " {\n"
+ " \"nHeight\": n, (numeric) block height\n"
+ " \"winner\": {\n"
+ " \"address\": \"xxxx\", (string) Zero MN Address\n"
+ " \"nVotes\": n, (numeric) Number of votes for winner\n"
+ " }\n"
+ " }\n"
+ " ,...\n"
+ "]\n"
+
+ "\nResult (multiple winners):\n"
+ "[\n"
+ " {\n"
+ " \"nHeight\": n, (numeric) block height\n"
+ " \"winner\": [\n"
+ " {\n"
+ " \"address\": \"xxxx\", (string) Zero MN Address\n"
+ " \"nVotes\": n, (numeric) Number of votes for winner\n"
+ " }\n"
+ " ,...\n"
+ " ]\n"
+ " }\n"
+ " ,...\n"
+ "]\n"
+ "\nExamples:\n" +
+ HelpExampleCli("getzeronodewinners", "") + HelpExampleRpc("getzeronodewinners", ""));
+
+ int nHeight;
+ {
+ LOCK(cs_main);
+ CBlockIndex* pindex = chainActive.Tip();
+ if(!pindex) return 0;
+ nHeight = pindex->nHeight;
+ }
+
+ int nLast = 10;
+ std::string strFilter = "";
+
+ if (params.size() >= 1)
+ nLast = atoi(params[0].get_str());
+
+ if (params.size() == 2)
+ strFilter = params[1].get_str();
+
+ UniValue ret(UniValue::VARR);
+
+ for (int i = nHeight - nLast; i < nHeight + 20; i++) {
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("nHeight", i));
+
+ std::string strPayment = GetRequiredPaymentsString(i);
+ if (strFilter != "" && strPayment.find(strFilter) == std::string::npos) continue;
+
+ if (strPayment.find(',') != std::string::npos) {
+ UniValue winner(UniValue::VARR);
+ boost::char_separator sep(",");
+ boost::tokenizer< boost::char_separator > tokens(strPayment, sep);
+ BOOST_FOREACH (const string& t, tokens) {
+ UniValue addr(UniValue::VOBJ);
+ std::size_t pos = t.find(":");
+ std::string strAddress = t.substr(0,pos);
+ uint64_t nVotes = atoi(t.substr(pos+1));
+ addr.push_back(Pair("address", strAddress));
+ addr.push_back(Pair("nVotes", nVotes));
+ winner.push_back(addr);
+ }
+ obj.push_back(Pair("winner", winner));
+ } else if (strPayment.find("Unknown") == std::string::npos) {
+ UniValue winner(UniValue::VOBJ);
+ std::size_t pos = strPayment.find(":");
+ std::string strAddress = strPayment.substr(0,pos);
+ uint64_t nVotes = atoi(strPayment.substr(pos+1));
+ winner.push_back(Pair("address", strAddress));
+ winner.push_back(Pair("nVotes", nVotes));
+ obj.push_back(Pair("winner", winner));
+ } else {
+ UniValue winner(UniValue::VOBJ);
+ winner.push_back(Pair("address", strPayment));
+ winner.push_back(Pair("nVotes", 0));
+ obj.push_back(Pair("winner", winner));
+ }
+
+ ret.push_back(obj);
+ }
+
+ return ret;
+}
+
+UniValue getzeronodescores (const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "getzeronodescores ( blocks )\n"
+ "\nPrint list of winning zeronode by score\n"
+
+ "\nArguments:\n"
+ "1. blocks (numeric, optional) Show the last n blocks (default 10)\n"
+
+ "\nResult:\n"
+ "{\n"
+ " xxxx: \"xxxx\" (numeric : string) Block height : Zeronode hash\n"
+ " ,...\n"
+ "}\n"
+ "\nExamples:\n" +
+ HelpExampleCli("getzeronodescores", "") + HelpExampleRpc("getzeronodescores", ""));
+
+ int nLast = 10;
+
+ if (params.size() == 1) {
+ try {
+ nLast = std::stoi(params[0].get_str());
+ } catch (const boost::bad_lexical_cast &) {
+ throw runtime_error("Exception on param 2");
+ }
+ }
+ UniValue obj(UniValue::VOBJ);
+
+ int nHeight = chainActive.Tip()->nHeight - nLast;
+
+ uint256 blockHash;
+ if(!GetBlockHash(blockHash, nHeight - 100)) {
+ return NullUniValue;
+ }
+
+ std::vector vZeronodes = znodeman.GetFullZeronodeVector();
+ for (int height = nHeight; height < chainActive.Tip()->nHeight + 20; height++) {
+ arith_uint256 nHigh = 0;
+ CZeronode* pBestZeronode = NULL;
+ BOOST_FOREACH (CZeronode& zn, vZeronodes) {
+ arith_uint256 n = zn.CalculateScore(blockHash);
+ if (n > nHigh) {
+ nHigh = n;
+ pBestZeronode = &zn;
+ }
+ }
+ if (pBestZeronode)
+ obj.push_back(Pair(strprintf("%d", height), pBestZeronode->vin.prevout.hash.ToString().c_str()));
+ }
+
+ return obj;
+}
+
+UniValue znsync(const UniValue& params, bool fHelp)
+{
+ std::string strMode;
+ if (params.size() == 1)
+ strMode = params[0].get_str();
+
+ if (fHelp || params.size() != 1 || (strMode != "status" && strMode != "reset")) {
+ throw runtime_error(
+ "znsync \"status|reset\"\n"
+ "\nReturns the sync status or resets sync.\n"
+
+ "\nArguments:\n"
+ "1. \"mode\" (string, required) either 'status' or 'reset'\n"
+
+ "\nResult ('status' mode):\n"
+ "{\n"
+ " \"IsBlockchainSynced\": true|false, (boolean) 'true' if blockchain is synced\n"
+ " \"lastZeronodeList\": xxxx, (numeric) Timestamp of last MN list message\n"
+ " \"lastZeronodeWinner\": xxxx, (numeric) Timestamp of last MN winner message\n"
+ " \"lastBudgetItem\": xxxx, (numeric) Timestamp of last MN budget message\n"
+ " \"lastFailure\": xxxx, (numeric) Timestamp of last failed sync\n"
+ " \"nCountFailures\": n, (numeric) Number of failed syncs (total)\n"
+ " \"sumZeronodeList\": n, (numeric) Number of MN list messages (total)\n"
+ " \"sumZeronodeWinner\": n, (numeric) Number of MN winner messages (total)\n"
+ " \"sumBudgetItemProp\": n, (numeric) Number of MN budget messages (total)\n"
+ " \"sumBudgetItemFin\": n, (numeric) Number of MN budget finalization messages (total)\n"
+ " \"countZeronodeList\": n, (numeric) Number of MN list messages (local)\n"
+ " \"countZeronodeWinner\": n, (numeric) Number of MN winner messages (local)\n"
+ " \"countBudgetItemProp\": n, (numeric) Number of MN budget messages (local)\n"
+ " \"countBudgetItemFin\": n, (numeric) Number of MN budget finalization messages (local)\n"
+ " \"RequestedZeronodeAssets\": n, (numeric) Status code of last sync phase\n"
+ " \"RequestedZeronodeAttempt\": n, (numeric) Status code of last sync attempt\n"
+ "}\n"
+
+ "\nResult ('reset' mode):\n"
+ "\"status\" (string) 'success'\n"
+ "\nExamples:\n" +
+ HelpExampleCli("znsync", "\"status\"") + HelpExampleRpc("znsync", "\"status\""));
+ }
+
+ if (strMode == "status") {
+ UniValue obj(UniValue::VOBJ);
+
+ obj.push_back(Pair("IsBlockchainSynced", zeronodeSync.IsBlockchainSynced()));
+ obj.push_back(Pair("lastZeronodeList", zeronodeSync.lastZeronodeList));
+ obj.push_back(Pair("lastZeronodeWinner", zeronodeSync.lastZeronodeWinner));
+ obj.push_back(Pair("lastBudgetItem", zeronodeSync.lastBudgetItem));
+ obj.push_back(Pair("lastFailure", zeronodeSync.lastFailure));
+ obj.push_back(Pair("nCountFailures", zeronodeSync.nCountFailures));
+ obj.push_back(Pair("sumZeronodeList", zeronodeSync.sumZeronodeList));
+ obj.push_back(Pair("sumZeronodeWinner", zeronodeSync.sumZeronodeWinner));
+ obj.push_back(Pair("sumBudgetItemProp", zeronodeSync.sumBudgetItemProp));
+ obj.push_back(Pair("sumBudgetItemFin", zeronodeSync.sumBudgetItemFin));
+ obj.push_back(Pair("countZeronodeList", zeronodeSync.countZeronodeList));
+ obj.push_back(Pair("countZeronodeWinner", zeronodeSync.countZeronodeWinner));
+ obj.push_back(Pair("countBudgetItemProp", zeronodeSync.countBudgetItemProp));
+ obj.push_back(Pair("countBudgetItemFin", zeronodeSync.countBudgetItemFin));
+ obj.push_back(Pair("RequestedZeronodeAssets", zeronodeSync.RequestedZeronodeAssets));
+ obj.push_back(Pair("RequestedZeronodeAttempt", zeronodeSync.RequestedZeronodeAttempt));
+
+ return obj;
+ }
+
+ if (strMode == "reset") {
+ zeronodeSync.Reset();
+ return "success";
+ }
+ return "failure";
+}
+
+// This command is retained for backwards compatibility, but is depreciated.
+// Future removal of this command is planned to keep things clean.
+UniValue zeronode(const UniValue& params, bool fHelp)
+{
+ string strCommand;
+ if (params.size() >= 1)
+ strCommand = params[0].get_str();
+
+ if (fHelp ||
+ (strCommand != "start" && strCommand != "start-alias" && strCommand != "start-many" && strCommand != "start-all" && strCommand != "start-missing" &&
+ strCommand != "start-disabled" && strCommand != "list" && strCommand != "list-conf" && strCommand != "count" && strCommand != "enforce" &&
+ strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect" &&
+ strCommand != "outputs" && strCommand != "status" && strCommand != "calcscore"))
+ throw runtime_error(
+ "zeronode \"command\"...\n"
+ "\nSet of commands to execute zeronode related actions\n"
+ "This command is depreciated, please see individual command documentation for future reference\n\n"
+
+ "\nArguments:\n"
+ "1. \"command\" (string or set of strings, required) The command to execute\n"
+
+ "\nAvailable commands:\n"
+ " count - Print count information of all known zeronodes\n"
+ " connect - Attempts to connect to specified zeronode address\n"
+ " current - Print info on current zeronode winner\n"
+ " debug - Print zeronode status\n"
+ " genkey - Generate new zeronodeprivkey\n"
+ " outputs - Print zeronode compatible outputs\n"
+ " start - Start zeronode configured in zero.conf\n"
+ " start-alias - Start single zeronode by assigned alias configured in zeronode.conf\n"
+ " start- - Start zeronodes configured in zeronode.conf (: 'all', 'missing', 'disabled')\n"
+ " status - Print zeronode status information\n"
+ " list - Print list of all known zeronodes (see zeronodelist for more info)\n"
+ " list-conf - Print zeronode.conf in JSON format\n"
+ " winners - Print list of zeronode winners\n"
+ " calcscore - Print list of winning zeronode by score\n");
+
+ if (strCommand == "list") {
+ UniValue newParams(UniValue::VARR);
+
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+
+ return listzeronodes(newParams, fHelp);
+ }
+
+ if (strCommand == "connect") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return zeronodeconnect(newParams, fHelp);
+ }
+
+ if (strCommand == "count") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getzeronodecount(newParams, fHelp);
+ }
+
+ if (strCommand == "current") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return zeronodecurrent(newParams, fHelp);
+ }
+
+ if (strCommand == "debug") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return zeronodedebug(newParams, fHelp);
+ }
+
+ if (strCommand == "start" || strCommand == "start-alias" || strCommand == "start-many" || strCommand == "start-all" || strCommand == "start-missing" || strCommand == "start-disabled") {
+ return startzeronode(params, fHelp);
+ }
+
+ if (strCommand == "genkey") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return createzeronodekey(newParams, fHelp);
+ }
+
+ if (strCommand == "list-conf") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return listzeronodeconf(newParams, fHelp);
+ }
+
+ if (strCommand == "outputs") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getzeronodeoutputs(newParams, fHelp);
+ }
+
+ if (strCommand == "status") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getzeronodestatus(newParams, fHelp);
+ }
+
+ if (strCommand == "winners") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getzeronodewinners(newParams, fHelp);
+ }
+
+ if (strCommand == "calcscore") {
+ UniValue newParams(UniValue::VARR);
+ for (unsigned int i = 1; i < params.size(); i++) {
+ newParams.push_back(params[i]);
+ }
+ return getzeronodescores(newParams, fHelp);
+ }
+
+ return NullUniValue;
+}
+
+static const CRPCCommand commands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ /* MN features */
+ {"zeronode", "getzeronodecount", &getzeronodecount, true},
+ {"zeronode", "zeronodeconnect", &zeronodeconnect, true},
+ {"zeronode", "zeronodecurrent", &zeronodecurrent, true},
+ {"zeronode", "zeronodedebug", &zeronodedebug, true},
+ {"zeronode", "createzeronodekey", &createzeronodekey, true},
+ {"zeronode", "getzeronodeoutputs", &getzeronodeoutputs, true},
+ {"zeronode", "startzeronode", &startzeronode, true},
+ {"zeronode", "startalias", &startalias, true},
+ {"zeronode", "getzeronodestatus", &getzeronodestatus, true},
+ {"zeronode", "listzeronodes", &listzeronodes, true},
+ {"zeronode", "listzeronodeconf", &listzeronodeconf, true},
+ {"zeronode", "getzeronodewinners", &getzeronodewinners, true},
+ {"zeronode", "getzeronodescores", &getzeronodescores, true},
+ {"zeronode", "zeronode", &zeronode, true},
+ {"zeronode", "znsync", &znsync, true},
+
+};
+
+void RegisterZeronodeRPCCommands(CRPCTable &tableRPC)
+{
+ for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
+ tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+}
diff --git a/src/rpcserver.h b/src/rpcserver.h
deleted file mode 100644
index 5691fa14da8..00000000000
--- a/src/rpcserver.h
+++ /dev/null
@@ -1,317 +0,0 @@
-// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_RPCSERVER_H
-#define BITCOIN_RPCSERVER_H
-
-#include "amount.h"
-#include "rpcprotocol.h"
-#include "uint256.h"
-
-#include
-#include